본문 바로가기

포너블

[pwnable.kr/포너블] random

random@pwnable:~$ ls
flag random random.c

우선 ls로 파일을 확인해 보면 3개가 나온다

flag: 정답 파일

random: 실행 파일

random.c: random의 소스 파일

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 ){
                printf("Good!\n");
                system("/bin/cat flag");
                return 0;
        }

        printf("Wrong, maybe you should try 2^32 cases.\n");
        return 0;
}
  1. unsigned int 변수 random에 rand() 함수를 이용한 난수를 넣는다.
  2. unsigned int 변수 key를 0으로 초기화 시킨 후, scanf로 입력을 받는다.
  3. key와 random의 xor 연산이 0xdeadbeef와 같다면 flag를 출력한다.
  4. 다르면 “Wrong, maybe you should try 2^32 cases.”를 출력한다.

이 문제는 rand함수의 문제점을 알고 있다면 풀 수 있다.

rand함수는 프로그램이 생성될 때 딱 값이 정해지기 때문에 프로그램을 여러번 실행시켜도 동일한 값이 나온다. (난수를 만들고 싶으면 srand함수로 seed를 바꿔 주면 됨)

따라서 random 변수에 값이 들어갔을 때 그 값을 확인한 후, xor 연산을 했을 때 0xdeadbeef 와 같게 하면 되는 것이다.

random 값을 어떻게 확인할지에 대해 구글링 해 본 결과, gdb를 이용하여 디버깅 할 수 있다는 것을 알게 되었다.

random값을 알기 위해서 코드를 천천히 디버깅 해 보았다.

gdb -q random으로 복잡한 문구들 없이 출력이 뜨게 한 후, disas main 명령어를 넣어 main 함수에서의 어셈블리어를 보자.

어셈블리어도 처음이고, gdb도 처음이고… 사실상 리눅스도 처음이라 이걸 보면서 어디서부터 손을 대야 할지 막막했다.

일단 대충 call이 호출하는 거니까 rand 함수를 호출하는 곳을 보면 되겠다! 라는 생각이 들었다.

따라서 rand로 값을 불러오는 부분에 breka point를 걸어 주면,

이처럼 break point에서 코드 실행이 중지된다.

ni로 다음 줄로 넘어가면 eax의 값을 rbp-0x4에 넣는 줄이 나온다.

여기서 random 변수값을 확인하려고 p/d, p/u 등등 여러 프린트 문을 실행해 보았지만… 안 된다는 문구만 보이고 변수값을 확인할 수 없었다

그래서 변수값이 들어가는 레지스터의 값을 보자! 라는 결론이 나왔다.

eax에 함수의 리턴값이 들어가고 그걸 rbp-0x4에 옮겨 주므로 rbp의 값을 확인해 보면

이렇게 무슨 랜덤 값이 나왔는지 확인할 수 있다.

xor연산을 반대로 계산한 후 입력해 주면 끝!


WORD: cpu의 기본 처리 단위인 16비트 (2bytes)

DWORD: 32비트 (4 bytes) // 레지스터가 e로 시작

QWORD: 64비트 (8 bytes) // 레지스터가 r로 시작함

file [문제파일] 명령어를 이용하면 파일의 비트를 알 수 있다.

함수 호출 규약

64bit에서 함수 인자값은 순서대로 레지스터에 저장된다.

  • linux

RDI → RSI → RDX → RCX → R8 → R9

  • window

RCX → RDX → R8 → R9 → stack → stack

따라서 scanf(”%d”, &a); 로 입력받을 때, %d는 RDI로, &a는 RSI에 저장된다. a의 값이 궁금하다면 RSI의 값을 확인하면 된다.

함수 인자값과는 별개로 함수의 리턴값은 ax에 저장된다. 위의 문제에서도 ax에 rand()의 리턴값이 들어가 있다는 것을 인지해야 풀 수 있다.

'포너블' 카테고리의 다른 글

[포너블/pwnable.kr] cmd2  (0) 2023.08.30
[포너블/pwnable.kr] cmd1  (0) 2023.08.30
[포너블/pwnable.kr] passcode  (0) 2023.08.30
[포너블/pwnable.kr] blackjack  (0) 2023.08.30
[pwnable.kr/포너블] bof  (0) 2023.07.30