Pwnable.kr lotto 문제 풀이_ 정세인

CTF 중점 스터디

2019. 10. 27. 21:32

로또 프로그램을 만들었다고 한다.

 

lotto@prowl:~$ ls -l
total 24
-r--r----- 1 lotto_pwn root     55 Feb 18  2015 flag
-r-sr-x--- 1 lotto_pwn lotto 13081 Feb 18  2015 lotto
-r--r--r-- 1 root      root   1713 Feb 18  2015 lotto.c

 

c파일을 보자.

 

lotto@prowl:~$ cat lotto.c
#include 
#include 
#include 
#include 

unsigned char submit[6];

void play(){

        int i;
        printf("Submit your 6 lotto bytes : ");
        fflush(stdout);

        int r;
        r = read(0, submit, 6);

        printf("Lotto Start!\n");
        //sleep(1);

        // generate lotto numbers
        int fd = open("/dev/urandom", O_RDONLY);
        if(fd==-1){
                printf("error. tell admin\n");
                exit(-1);
        }
        unsigned char lotto[6];
        if(read(fd, lotto, 6) != 6){
                printf("error2. tell admin\n");
                exit(-1);
        }
        for(i=0; i<6; i++){
                lotto[i] = (lotto[i] % 45) + 1;         // 1 ~ 45
        }
        close(fd);

        // calculate lotto score
        int match = 0, j = 0;
        for(i=0; i<6; i++){
                for(j=0; j<6; j++){
                        if(lotto[i] == submit[j]){
                                match++;
                        }
                }
        }

        // win!
        if(match == 6){
                system("/bin/cat flag");
        }
        else{
                printf("bad luck...\n");
        }

}

void help(){
        printf("- nLotto Rule -\n");
        printf("nlotto is consisted with 6 random natural numbers less than 46\n");
        printf("your goal is to match lotto numbers as many as you can\n");
        printf("if you win lottery for *1st place*, you will get reward\n");
        printf("for more details, follow the link below\n");
        printf("http://www.nlotto.co.kr/counsel.do?method=playerGuide#buying_guide01\n\n");
        printf("mathematical chance to win this game is known to be 1/8145060.\n");
}

int main(int argc, char* argv[]){

        // menu
        unsigned int menu;

        while(1){

                printf("- Select Menu -\n");
                printf("1. Play Lotto\n");
                printf("2. Help\n");
                printf("3. Exit\n");

                scanf("%d", &menu);

                switch(menu){
                        case 1:
                                play();
                                break;
                        case 2:
                                help();
                                break;
                        case 3:
                                printf("bye\n");
                                return 0;
                        default:
                                printf("invalid menu\n");
                                break;
                }
        }
        return 0;
}

 

1,2,3번을 선택할 수 있고, 1번을 입력해서 play를 할 수 있다.

 

lotto@prowl:~$ ./lotto
- Select Menu -
1. Play Lotto
2. Help
3. Exit
1
Submit your 6 lotto bytes :

 

6바이트를 입력하라고 해서 1 6개를 넣어봤더니

 

Submit your 6 lotto bytes : 111111
Lotto Start!
bad luck...
- Select Menu -
1. Play Lotto
2. Help
3. Exit

 

lotto start! 라는 문구가 뜸과 동시에 bad luck을 출력하고 

무한 반복문을 통해서 다시 선택할 수 있게 해준다.

 


play함수를 처음부터 차근차근 보자

read함수의 fd번호가 0번 이므로 scanf 함수처럼 입력을 받는다.

입력받은 6바이트의 값을 submit이라는 배열변수에 저장한다.

 

lotto Start를 출력하고

 

/dev/urandom 이라는 장치파일을 open함수를 통해서 연다.

 

open함수의 반환값(fd에 들어가는 값)이 -1이 되면 error을 출력하고

프로그램을 종료한다.

 

에러가 뜨지 않는다면 lotto라는 6바이트 배열변수를 선언하고,

아까 open함수로 열었던 /dev/urandom 이라는 장치파일의 fd번호를

read함수에서 쓴다. urandom에서 만든 6바이트 난수를 lotto에다가

집어넣는다. read의 반환값은 저장되는 값의 바이트 수(lotto의 바이트 수)

이기 때문에 6이 아니라면 또 에러를 출력한다.

 

6번 반복하는 for문을 선언해서 lotto 배열변수의 인덱스 번호에 있는 

값들을 차례로 45로 나눈 나머지 값에 1을 더한 값을 저장한다.

 

submit 배열밴수의 인덱스번호에 있는 값들과

lotto 배열변수의 인덱스번호에 있는 값들이 같으면 match 값을

1 증가 시킨다. 두 배열변수를 0부터 5까지 총 6번 비교를 해서

6번이 같으면 match를 6으로 만들어준다.

 

따라서 match가 6이면 flag를 보여주는 것이고 

그 외의 경우는 bad luck을 출력한다.

 

분석을 겨우 했는데 문제를 풀려고 하니까

/dev/urandom 에서 생성된 난수가 무엇인지 모르면 절대 풀릴 수가 없는

문제인 것 같다. 그래서 '/dev/urandom 취약점' 등으로 검색해봤더니

자료가 많이 없었다. 답지를 볼까 1주일 정도 고민했다. 결국 답지를 봤다.

 


코드를 미흡하게 본 내 잘못이다. match를 ++시켜줄 때 6번이 아니고 36번을 반복하는 것이었다.

/dev/urandom 취약점 이라는 것과는 관련이 없었다. 비교하는 6개중에서 1개만 맞으면 총 match가 6번이 

올라가기 때문에 성공할 수 있다.

 

++++++

를 많이 입력해보니 성공했다.

'CTF 중점 스터디' 카테고리의 다른 글

N00bCTF - very ezzzzzz!! Write up  (0) 2019.11.03
ShadowCTF Magic Password 풀이  (0) 2019.11.01
N00bCTF - What is bof? Write up  (0) 2019.10.27
N00bCTF Where_is_flag 풀이  (0) 2019.10.27
pwnable.kr(Toddler's Bottle_blukat)_정세인  (2) 2019.10.20