xctf今年第一场分站赛的一题pwn题
前言
赛后想复现,一直鸽到现在,解出来还是挺高兴的把
分析
题目名字叫easy_unicorn
,看这名字就知道是和unicorn相关的,反编译题目给的程序(x86_sandbox
)后,可以看到程序load了同目录下的xctf_pwn.dump
,分配内存,然后映射内存地址,最后执行,但是直接拿ida反编译xctf_pwn.dump
是不行的,先放着
查看程序x86_sandbox
,我们可以看到x86_sandbox
有一个debug
和info
的选项,跑起来效果:
这个info选项给的消息很有用,我们对着它的输出来恢复下xctf_pwn.dump
写了个粗糙的脚本:
1 | f = open("./log.txt","rb") |
log.txt的内容:
1 |
|
这样我们就可以得到一个可以ida反编译的文件,但是跑不起来就是了,如果要跑起来,应该还需要进一步的修复,但是直接静态的看也能解
这逻辑基本能看的很清楚了,我们找到要我们输入passwd的地方,找到它生成code的算法,在反着解回去就行,生成code的算法:
逆推回去即可,输入password成功的话,程序会叫我们想不想要flag,输入y的话,程序会试图打开flag文件,但是会被syscall_hook劫持,返回-1的fd,所以不能输出flag:
但是我们可以看到,他打开的fd没有被关闭,接着再看其它的syscall_hook,发现我们只能用:read,write,open,close,newfstat,mmap,brk,exit
这些系统调用,所以考虑orw来拿flag
程序执行完询问你要不要flag就结束了,并没有什么可以拿来利用的地方,所以得继续找下漏洞
漏洞点
最终是在询问密码这里的地方发现了漏洞点:
1 | signed __int64 __fastcall sub_400DDE(__int64 a1, void *a2) |
跟进sub_401120
:
1 | _QWORD *__fastcall sub_401120(_QWORD *a1) |
那个++*a1
的地方就是漏洞所在,这个好像是虚函数表的指针,这个类的虚函数表指针指向0x401900
:
我们可以一直输入错误的密码32次,使其指向0x401920
,最后在输入正确密码后就不是问我们要不要flag,而是跳到那个shell
的函数,我们有一次任意call
的机会:
我的思路是:
- 既然程序给了栈的地址
printf("data ptr:%p\n", &buf);
这一句,那我们就调用read函数来做rop - 先
open("flag.txt",0)
,前面说过,fd并没有被关闭 - 接着
read(3,buf,0x80)
,最后write出来就好
最终exp:
1 | from pwn import * |
后记
这题花了挺长时间才复现出来的,比赛的时候肯定是没这没多时间解这个题目了