pwnable.kr (random)

c0wb3ll ㅣ 2020. 12. 3. 18:35

pwnable.kr (random)

#include <stdio.h>

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;
}

문제 내용과 같이 if문을 통과하기 위해 random을 이용하여 값을 생성하고 입력받은 key와 xor하여 0xdeadbeef와 비교하는 문제이다.

 

딱히 눈으로 훑어보았을 때 별다른 취약점이 보이지 않았다....

 

그래서 일단 감으로는 무슨 함수인지 알고 있지만 정확히 모르는 함수들에 대해서 찾아보다가 운 좋게 rand()가 첫빠따에 걸려서 풀 수 있었다.

rand()

  • rand()가 하는일
    • 랜덤한 숫자를 반환한다.
    • 범위는 0 ~ RAND_MAX
      • <stdio.h>에 정의된 RAND_MAX는 32767이다.

여기까지는 별 이상이 없다.

 

다만 위 코드와 같이 rand()를 사용할 경우 큰 문제가 발생하는데 rand()는 프로그램 생성시 값이 고정되어 프로그램을 여러번 실행시켜도 같은 값을 돌려주게 된다.

 

그 말은 현재 rand()값은 정해져 있기 때문에 그냥 rand()로 반환된 값을 구하여 0xdeadbeef와 xor을 돌려주면 그 값이 key값이 된다.

 

실제로 진행해보도록 하자.

call rand 이후 eax에 들어있는 반환 값을 rbp-0x4에 넣는 것을 확인할 수 있다.

따라서 rbp-0x4가 rand()함수로 생성된 랜덤 값이 될 것이다.

 

또한 scanf()의 인자로는 rbp-0x8을 가져가기 때문에 rbp-0x8은 입력받는 key 값이 될 것이다.

 

결정적으로 cmp eax, 0xdeadbeef 문 바로 위에 xor 구문이 있다.

이 xor eax, DWORD PTR [rbp-0x4] 구문인데 이 때 eax에는 앞에 구문인

mov eax, DWORD PTR[rbp-0x8]에 의해 rbp-0x8의 주소 값이 들어가기 때문에 rbp-0x8은 입력받는 key값,

rbp-0x4는 rand()로 생성된 랜덤 값이라는 것을 확신할 수 있다.

 

rbp-0x4에는 0x6b8b4567이라는 값이 들어있다.

이 값을 0xdeadbeef와 xor하여 key값을 보내주면 될 것 같다.

from pwn import *

rand = 0x6b8b4567
dead = 0xdeadbeef

xor = str(rand ^ dead)

p = process('./random')

p.sendline(xor)

p.interactive()

다음과 같이 간이 flag를 생성시킨 뒤 익스 코드를 돌렸다.

성공적으로 flag를 읽어낸 것을 확인할 수 있다.

from pwn import *

rand = 0x6b8b4567
dead = 0xdeadbeef

xor = str(rand ^ dead)

# p = process('./random')

s = ssh('random', 'pwnable.kr', port=2222, password='guest')
p = s.process('/home/random/random')

p.sendline(xor)

p.interactive()

이제 ssh에 접속하여 flag를 읽어보자.