ret2text
首先checksec,查看保护
开启了NX保护,IDA查看程序
很明显存在栈溢出漏洞,继续查看程序,发现有一处调用shell
想要程序调用system函数,需要input==secretcode,而secretcode每次都是随机的,所以只能通过栈溢出,让main函数的返回值为调用system函数的地方,查看该函数所在的位置
0x0804863A,接下来是找到函数返回的地址,并将其覆盖
0xffffd338-0xffffd2cc = 108,于是构造payload
1 | from pwn import * |
例题:jarvisOJ level0
ret2shellcode
首先checksec
32位程序,没有开启任何保护,IDA查看程序
有栈溢出,例外,strncpy()函数将gets的内容写入buf2中。于是攻击思路如下:
1 | 将shellcode写入buf2中,然后利用栈溢出将函数返回地址覆盖为buf2的地址。例外有一点需要注意的是,shellcode长度不能超过0x64,buf2部分可写可执行 |
查看buf2的地址
可以看到buffer位于.bss段的0x0804A080处,接下来查看此处地址的权限
vmmap查看内存,0xa080+0x64=0xa0c4,有可写可读可执行权限。于是构造payload
1 | from pwn import * |
例题:jarvisOJ level1
ret2syscall
首先checksec
开启NX,IDA查看程序
没有系统函数和shellcode,但是依然有栈溢出,这时候可以利用系统调用。下面介绍几个相关知识:
执行系统调用的指令是 int 0x80
系统调用获取shell的函数是 execve(“/bin/sh”,NULL,NULL)
对应的寄存器的值(对于32位程序)
1 | 系统调用号,即 eax 应该为 0xb |
给寄存器赋值要利用到pop,因此需要ROPgadget
查找可存储寄存器的代码
1 | ROPgadget --binary rop --only 'pop|ret' | grep 'eax' |
查找字符串
1 | ROPgadget --binary rop --string "/bin/sh" |
查找有int 0x80的地址
1 | ROPgadget --binary rop --only 'int' |
还有一点需要注意的是:ret操作会执行一次pop并作为跳转地址
首先找eax
选取如下
1 | 0x080bb196 : pop eax ; ret |
再找ebx
选取如下,一举三得
1 | 0x0806eb90 : pop edx ; pop ecx ; pop ebx ; ret |
查找”/bin/sh”
查找int 0x80
编写脚本如下:
1 | from pwn import * |
ret2libc
ret2libc1
首先checksec
32位程序,NX开启。IDA查看程序
存在栈溢出漏洞,Get shell最直接的方法就是:
1 | 改写程序返回地址为so库中system函数的地址,同时布置好栈,将参数“/bin/sh\x00”放在’返回地址往后两个单位内存地址’处即可 |
查看system函数和”/bin/sh”的地址
编写脚本
1 | from pwn import * |
例题:jarvisOJ level2
ret2libc2
首先checksec
32位程序,开启了NX。IDA查看程序
有栈溢出,并且有system函数和gets函数,攻击思路:
1 | 利用gets函数向.bss段中写入“/bin/sh”,再调用系统函数执行system("/bin/sh") |
gdb查看system函数和gets函数在plt表中的位置
找一个buf来存储写入的”/bin/sh”
再找一个gadget连接gets和buf2,即ebx
编写脚本
1 | from pwn import * |
该方法同样适用于ret2libc1
1 | from pwn import * |
ret2libc3
首先checksec
32位程序,NX开启。IDA查看
有栈溢出,无system函数。下面介绍两个知识点:
1、system 函数属于 libc,而 libc.so 动态链接库中的函数之间相对偏移是固定的,也就是说要找基地址。举个例子:
1 | puts真实地址-puts偏移地址 = system真实地址-system偏移地址 = 基地址 |
2、那么如何得到 libc 中的某个函数的地址呢?我们一般常用的方法是采用 got 表泄露,即输出某个函数对应的 got 表项的内容。当然,由于 libc 的延迟绑定机制,我们需要泄漏已经执行过的函数的地址,已经执行过的话就会在got表生存下来。同时可以根据got表项找到对应的libc.so,从而确定函数偏移。举个例子:
1 | 利用puts函数泄露puts函数的got表,因为puts函数在gets之前使用过。 |
利用puts的got表项找对应的libc.so有两种方法:
2、https://github.com/lieanu/LibcSearcher
objdump看一下got表有哪些
因为PIE是关闭的,所以可以直接去puts出got表中puts的内容,并且返回到面函数
1 | from pwn import * |
然后根据got表中puts的内容找到相应的libc
这样就可以求出libc的基地址,system的地址和“/bin/sh”的地址
1 | libc_base = puts_addr - libc.symbols['puts'] |
但是这样有个小问题,第二次调用main函数的时候,esp和ebp的相对偏移发生了变化,payload应为
1 | payload = 'a'*112 + p32(system_addr) + p32(elf.symbols['main']) + p32(binsh_addr) |
利用cyclic来判断
于是编写脚本
1 | from pwn import * |