分析
这题题目已经在暗示用int数据的overflow了,不过不急,先分析一下。
保护
基本没啥保护,也挺好,适合不用搞太多花里胡哨的泄露,只需理解这题想告诉你的知识。
后门函数
看到有一个what is this函数,正是我们要的cat flag函数。
main函数
login函数
main函数里需要的操作很简单,只需输入一个1就欧克。然后到login函数看看有啥。
check_passwd函数
看到有两个输入点,似乎可以存在栈溢出。但是想都不用想check_passwd肯定不会让你这么轻松溢出的。更别提这个函数给buf这个变量足足分配了512个字节,而我们输入0x199还离着远着呢。只能在看看check函数了。
可能的破绽
不用说,一看strlen和strcpy就知道,这题考点肯定就在这了。
仔细看看s就是我们之前输入的buf,被作为参数传进来了。可以看到s会先通过一个检查,程序只允许长度大于3且小于等于8的密码,只有这样才会执行strcpy函数,将我们的s复制到dest里面,在栈上看到dest距离我们要覆盖的ret地址很近,如果我们能够绕过刚才strlen的限制,毫无疑问我们可以覆盖到这个地址进行栈溢出。(刚刚输入的buf可是足足有0x199个字节。)
还有一个值得关注的点,unsigned __int8 v3
v3被定义为了一个无符号短整型。其中__int8的意思是只占8bit位,也就是1个字节,这一点在栈上看的更清晰,var_9的位置从-9开始到-8。
那现在的问题就是如何绕过程序的strlen函数的长度检查。这个程序在C语言的层面无懈可击,但是我一直认为做pwn就是要从汇编层面找漏洞,从而对C语言或其他程序进行降维打击。
可能的突破口
我们有两个可能的突破口
1.用\x00来作为字符串的结尾绕过strlen的检查,但是问题在于能绕过strlen,strcpy也会被骗过,这种方法我没成功,但我感觉是有可能的,大家感兴趣可以试试。
2.通过输入一个很大的长度让v3溢出,从而让v3只存下一个大数字最后的低几位,从而使v3范围在3到8直接,绕过if的判断。
gdb看汇编
话不多说,看看gdb里的情况。
这里我输入的密码是aaaabaaa。而cmp和jbe指令就对应着判断v3是否小于等于3,cmp和ja指令就判断v3是否大于8,可以看到如果判定失败,都会跳转到同一个位置,很明显我们就会失去我们需要的strcpy。(这里cmp和jbe和ja指令如果不熟悉建议去搜一下,很快就会明白了。
而这里的重点在于他的比较是用al的值来比较的,而al是ax的低八位,而ax是eax的低八位(如果这是64位程序,eax还是rax的低八位)
确定思路
那么很明显,al只是一个有8bit位的很小的数。这就和刚才的v3对应上了。我们知道2^8是256,由于v3是无符号数,所以v3的范围从0到255.那么这里绕过判断的思路就很明确了,我们应该先输入256个字节的垃圾数据填满v3,而后在输入3到8个字节的数据,这样就可以绕过判断了。
exp编写
问题一
但是我们这样输入在执行strcpy之后栈上会填满我们的垃圾数据,而我们ret的地址也会发生这样尴尬的事。
假设我们的payload如图,很明显我们的back_door地址永远也不会覆盖到他该在栈上的地址!会发生这种搞笑的事。
不过这个问题还算好解决,我们计算好距离,把back_door地址插入在一堆的a里面就好。
问题二
不过这里我们看到一个尴尬的事,eax保存strlen函数返回值,而现在eax是0x18,想都不用想肯定只读了0x14个a和back_door地址。
在python的DEBUG界面很清晰看到我们的back_door地址后还跟了四个字节的0,如何解决这个问题呢,我的方法很暴力。上exp!
看看exp
from pwn import *
context(
terminal = ['tmux','splitw','-h'],
os = "linux",
#arch = "amd64",
arch = "i386",
log_level="debug"
)
#elf = ELF("./over_flow")
io = process("./over_flow")
#io = remote("61.147.171.105",58664)
def debug():
gdb.attach(io)
pause()
debug()
#########################################################################################################################
back_door = 0xaaaabaaa0804868B#我直接用aaaabaaa改掉那几个讨厌的0,让strlen函数继续读下去。
payload = b'A'*(0x18)+p64(back_door)+b''*(0xe4)
io.sendlineafter(b"Your choice:",b'1')
io.sendlineafter(b"Please input your username:\n",b'DBG')
io.sendlineafter(b"Please input your passwd:\n",payload)
io.interactive()
#103<总长度<=108
实际运行效果如下。
可以看到成功运行,拿下!
标签:door,函数,int,back,CTfpwn,v3,io,overflow,strlen From: https://blog.51cto.com/u_16356440/8666848