Write-up
처음 접속을 하면 아래의 코드가 주어진다. 코드를 해석해보면 key와 random을 xor연산하여 0xdeadbeef 와 값이 동일하면 플래그가 출력되도록 되어있다.
random@pwnable:~$ ls
flag random random.c
random@pwnable:~$ cat random.c
#include <stdio.h>
int main(){
unsigned int random;
random = rand(); // random value!
unsigned int key=0;
scanf("%d", &key);
if( (key ^ random) == 0xdeadbeef ){ // key random이랑 xor 연산
printf("Good!\n");
system("/bin/cat flag");
return 0;
}
printf("Wrong, maybe you should try 2^32 cases.\n");
return 0;
}
이제 디컴파일을 하여 코드를 확인해보자. DWORD PTR [rbp-0x4],eax에 랜덤값을 생성하여 변수에 삽입하는 것을 알 수 있다.
(gdb) set disassembly-flavor intel
(gdb) disas main
Dump of assembler code for function main:
0x00000000004005f4 <+0>: push rbp
0x00000000004005f5 <+1>: mov rbp,rsp
0x00000000004005f8 <+4>: sub rsp,0x10
0x00000000004005fc <+8>: mov eax,0x0
0x0000000000400601 <+13>: call 0x400500 <rand@plt>
0x0000000000400606 <+18>: mov DWORD PTR [rbp-0x4],eax
0x0000000000400609 <+21>: mov DWORD PTR [rbp-0x8],0x0
0x0000000000400610 <+28>: mov eax,0x400760
0x0000000000400615 <+33>: lea rdx,[rbp-0x8]
0x0000000000400619 <+37>: mov rsi,rdx
0x000000000040061c <+40>: mov rdi,rax
0x000000000040061f <+43>: mov eax,0x0
0x0000000000400624 <+48>: call 0x4004f0 <__isoc99_scanf@plt>
0x0000000000400629 <+53>: mov eax,DWORD PTR [rbp-0x8]
0x000000000040062c <+56>: xor eax,DWORD PTR [rbp-0x4]
0x000000000040062f <+59>: cmp eax,0xdeadbeef
0x0000000000400634 <+64>: jne 0x400656 <main+98>
0x0000000000400636 <+66>: mov edi,0x400763
0x000000000040063b <+71>: call 0x4004c0 <puts@plt>
0x0000000000400640 <+76>: mov edi,0x400769
0x0000000000400645 <+81>: mov eax,0x0
0x000000000040064a <+86>: call 0x4004d0 <system@plt>
0x000000000040064f <+91>: mov eax,0x0
0x0000000000400654 <+96>: jmp 0x400665 <main+113>
0x0000000000400656 <+98>: mov edi,0x400778
0x000000000040065b <+103>: call 0x4004c0 <puts@plt>
0x0000000000400660 <+108>: mov eax,0x0
0x0000000000400665 <+113>: leave
0x0000000000400666 <+114>: ret
End of assembler dump.
해당 지점에서 bp를 잡고 할당된 값을 보면 0x6b8b4567 값이 고정되서 들어가는 것을 알 수 있다. 즉 0x6b8b4567과 0xdeadbeef를 xor연산하여 대입하면 flag를 획득할 수 있다는 것이다.
(gdb) b *main+18
Breakpoint 1 at 0x400606
(gdb) r
Starting program: /home/random/random
Breakpoint 1, 0x0000000000400606 in main ()
(gdb) info register $eax
eax 0x6b8b4567 1804289383
이를 기반으로 아래 코드를 작성하여 flag를 획득 할 수 있었다.
from pwn import *
rand = 0x6b8b4567
deadbeef = 0xdeadbeef
payload = str(deadbeef ^ rand)
s = ssh('random','pwnable.kr',password='guest',port=2222)
p = s.process('./random')
p.sendline(payload)
p.interactive()
python3 ./pwnable.kr_random.py
[+] Connecting to pwnable.kr on port 2222: Done
[*] passcode@pwnable.kr:
Distro Ubuntu 16.04
OS: linux
Arch: amd64
Version: 4.4.179
ASLR: Enabled
[+] Starting remote process bytearray(b'./random') on pwnable.kr: pid 59043
[*] Switching to interactive mode
Good!
Mommy, I thought libc random is unpredictable...