본문 바로가기

CTF_Write_UP/pwnable.kr

pwnable.kr : random 풀이

 

시작

안녕하세요 :D

오늘은 random을 풀어볼까 합니다.

순서대로 풀려고 했는데 많이 어렵네요ㅎ.. 쉬운 것 풀고 어려운 문제를 고민해보도록 하겠습니다.

시작해보죠!

root@goorm:/workspace/LCH_Server# ssh random@pwnable.kr -p2222

Write UP

random@ubuntu:~$ ./random
1234
Wrong, maybe you should try 2^32 cases.

random을 실행해보니 사용자의 입력을 기다립니다.

임의의 숫자를 넣어주니깐 틀렸으니깐 2^32번 시도해 보라고 하네요.

무리..겠죠? random.c를 확인해봅시다.

random@ubuntu:~$ cat random.c
#include 

int main(){
        unsigned int random;
        random = rand();        // random value!

        unsigned int key=0;
        scanf("%d", &key);

        if( (key ^ random) == 0xdeadbeef ){
                printf("Good!\n");
                system("/bin/cat flag");
                return 0;
        }

        printf("Wrong, maybe you should try 2^32 cases.\n");
        return 0;
}

rand()를 이용해 랜덤값을 random 변수에 넣어주고 있습니다.

사용자는 key에 입력을 하네요.

두 변수를 XOR한 값이 0xDEADBEEF이면 flag를 출력해 줍니다.

우리가 집중해서 봐야할 부분은 rand() 함수입니다.


rand()함수에 seed를 주지 않고 있습니다.

변칙적인 seed 값이 있다면 rand() 함수에서 매번 다른 값이 나오지만

이 코드에서는 rand()만 사용하고 있네요!

따라서 생성되는 랜덤값은 규칙적입니다.

gdb로 뜯어볼까요?

gdb-peda$ 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.

rand() 호출 직후인 main+18rbp-0x4 속에 rand()로 생성된 난수가 들어있겠죠?

break point를 걸고 달려봅시다.

gdb-peda$ x/x $rbp-0x4
0x7ffdbd7ca9ec: 0x6b8b4567

랜덤값이 들어가는 rbp-0x4 부분에 0x6b8b4567이란 값이 들어가있네요!

몇 번을 재실행해봐도 똑같은 값이 나옵니다. 변칙적인 seed를 주지 않기 때문이죠.

따라서 0x6b8b45670xdeadbeef 값을 XOR 해준다면 입력해주어야 할 key 값을 얻을 수 있겠네요.

random@ubuntu:~$ python -c 'print 0x6b8b4567 ^ 0xdeadbeef'
3039230856

key값으로 3039230856을 주면 되겠습니다.

random@ubuntu:~$ ./random
3039230856
Good!
Mommy, I thought libc random is unpredictable...

마무리

보통 rand() 함수 사용 시 seed로 현재 시간을 주죠?

seed가 없다면 rand() 역시 규칙적인 난수를 생성해줄 뿐입니다.

고생하셨습니다! 다음 문제에서 뵙겠습니다 :D

 

'CTF_Write_UP > pwnable.kr' 카테고리의 다른 글

pwnable.kr : mistake 풀이  (0) 2019.04.16
pwnable.kr : passcode 풀이  (0) 2019.04.14
pwnable.kr : bof 풀이  (0) 2019.04.13
pwnable.kr : col 풀이  (0) 2019.04.12
pwnable.kr : fd 풀이  (0) 2019.04.11