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를 읽어보자.