CISCN_2019_s_9
程序逻辑
查看保护
- 32位,无任何保护
伪代码
pwn函数
- fgets读取输入后直接输出
- 没有调用shellcode
hint函数
- jmp esp:跳转到esp执行
- esp存放指向栈顶的指针
- 跳转后会去执行栈中的指令
调试
main处打断点,run后发现直接调用pwn函数,单步进入
gdb ciscn_s_9
b main
r
s
此时函数栈帧状态如下
进入pwn函数,首先是当前栈底ebp压栈,更新ebp为当前栈顶esp,然后开辟一块0x28的栈空间
push ebp
mov ebp, esp
sub esp, 0x28
打印字符串,跳过即可
获取数据流输入,写入栈
lea eax, [ebp+s] ; 把ebp+s的地址给eax
push eax ; eax入栈
由于s被定义为-0x20,因此eax从ebp-0x20处(0x148)开始
构造一个’a’*0x20 + ‘b’*4的输入,发现’a’*0x20填满0x148~0x164,bbbb刚好覆盖ebp地址0x168
返回主函数
leave ; mov esp, ebp; pop ebp
ret ; pop eip
leave执行后栈帧如下
执行ret后,eip=0x804856f,回到返回地址,函数执行结束
hint函数
可以看到hint有一条跳转到esp的指令,由于栈上代码可执行,可以利用这个跳转到shellcode的位置
思路
在输入的时候可以把hint中的跳转指令的地址覆盖到0x16c即返回地址上,使得pwn函数在运行到ret时不会返回主函数,而是跳转到hint函数
ret到hint后会跳转到esp去执行我们的输入
由于pwn函数写入栈的位置为[ebp+s]也即0x168-0x20=0x148的位置,而我们当前的esp位置为0x170,因此需要把esp减去0x28使其能够刚好读到我们的输入
PWN
编写脚本
1 | from pwn import * |
- 可供shellcode的长度只有0x20 = 32个字节,因此不能用shellcraft.sh(),此处使用自己编写的shellcode
- \x90为NOP(空操作)指令,为了对齐到双字边界(4的偶数倍)
- shellcode.ljust(0x24, b”\x90)即为使用\x90(NOP指令)填充到0x168的位置,后面再接上0x8048554即jmp esp指令地址
执行效果
- 在0x0804854F打断点,发送payload后
可以看到此时return的地址已经被覆盖为hint中jmp esp的地址了,单步进入看到已经开始执行我们的shellcode
可以看到成功开启shell
完整代码执行效果如下