#
noxCTF-TheNameCalculator
##
漏洞分析
在终端运行文件,提示输入姓名,随便输入之后输出字符串,看样子输入不是很让出题人满意。。。
IDA反编译之后F5一键转成C代码,根据命名找到secretFunc,发现里面有格式化字符串漏洞,即printf里面将用户输入作为其参数。看调用这个函数的位置,似乎没法转成C代码,直接看汇编,大概看出来先给了提示字符串,之后输出,再调用read函数从用户输入中读取最多32个字节,可以看到存储输入的数组的起始位置为ebp-0x2c,而最后跳转逻辑比较的是ebp-0x10处的内容与0X06A4B825的大小,因此只要让输入的28-32这四个字节与之相同即可进入secretFunc。
继续看secretFunc,这次read上限是27字节,还是蛮有限,联想起上次给了大概40个字节还是不能用pwn自己的函数来构造,这个长度估计也只能用%k$hn或者%k$n。这里的一个小障碍是输入的字符给按字节异或处理了一下,原始输入的结果基本不能用了,因此要想想办法逆回去
异或其实按照它的异或方式处理一次,在程序中就可以还原回去,相当于A xor B xor B -> A xor 0 = A。道理都懂,但是对于编程很菜的我来说还是有点难度,把输入的字符串当成一排滑槽,下面有个0x5F7B4153向右滑,第一个字节和0x53异或,第二个字节和0x53和0x41异或,第三个字节和0x53和0x41和0x7B异或,之后的字节一直到倒数第四个都是和四个字节异或,同理倒数第三个和0x5F、0x7B、0x5F异或,倒数第二个和倒数两个字节异或(小端顺序中的高位),最后一个字节和倒数第一个字节异或。为了编程方便,我统一都写满27字节。
最后最关键的是printf任意写地址要修改哪里,之前做过的覆盖return addr的例子在这里不好使了,因为这次开启了ASLR,本来经过观察有个地址和返回地址所在栈地址的差总是0x14,但是泄露这个地址发现它总是在变化,而我们只有一次使用printf的机会,因此这条路就没了。剩下的只有是通过覆盖got表地址的方式,看到这里有个exit还不错,本来有return了,彷佛是刻意留的函数。但是这个if条件怎么能满足呢,GDB断点调试一下,发现这竟然是exit的地址,因此修改了exit地址之后恰好可以满足条件,调用exit@got从而进入super函数拿到flag。
##
寻找格式化字符串偏移
先用AAAA+’%p’*11+’a’的方式,发现没有0x41414141,说明偏移比较靠后,还是gdb.attach()实时调一下,断点下在printf,先find 0x41414141,得到的地址用fmtarg和格式化字符串比较一下,得到参数地址与格式化字符串的地址为13,这里是相对函数的偏移,因此相对于格式化字符串的偏移是12
##
exp
综合之前的信息,我们需要得到exit@got,然后用superFunc的地址覆盖,IDA可以看到函数相对地址是0x596,加上0x08048000的装载基地址,其实际地址为0x08048596,而exit@got的值为0x0804a024,只有后面四个字节不同,因此使用hn的方式覆写双字节,0x8596-4 = 34194,最后的输入为p32(exit_addr)+’%34194c%12$hn’+padding