[pwnable.kr] lotto - 2 pt

2018. 5. 10. 22:38


lotto다 로또!

이번에는 토끼처럼 생긴 카드에 적혀잇다. 문제를 보자



로또 프로그램을 숙제로 만들었는데 한번 플레이해보겠냐는것 같다.



보면 알겠지만 lotto파일에 setuid가 걸려있고, 읽을 수 있는 파일은 lotto.c밖에 없다.

내용을 한번 보자.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
 
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;
}
 
 
cs


이렇게 돌아가는 소스코드이다. /dev/urandom 을 이용하여 0~45의 값을 가지는 6바이트의 랜덤값을 가져오고

사용자에게 6바이트를 입력받아 비교한 후 6개의 값이 같다면 /bin/cat flag를 실행하여 플래그를 출력해준다.


처음에는 urandom에 취약점이 있는가 싶었지만...

사용자한테 입력받은 값과 랜덤6바이트를 비교하는 과정에서 취약점이 있었다.


1
2
3
4
5
6
7
8
9
    // 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++;
            }
        }
    }
cs


위에 보면 알겠지만 2중 for문을 사용하고 있는데, lotto[i]를 고정해두고 submit의 모든 값과 비교해서 1개라도 일치하면 match값을 증가시킨다.

이렇게 할 경우 만약 submit에 같은 값만 들어있을 경우 lotto[i]와 submit[j] 중 일치하는 값이 하나만 존재하여도 match의 값은 6으로 바로 증가할 수 잇을 것이다.


그러므로 submit의 값 6개를 모두 같은 값(0~45)을 입력하고 랜덤한 lotto값 6바이트중에 우리가 입력한 값이 포함된다면 플래그를 얻을 수 있을 것이다.



아스키코드표를 보면 32~45까지는 표현할 수 있는 아스키값이므로 임의로 '!'=33을 선택하여

성공할 때까지 프로그램을 돌려보기로 하였다.



잉? 한번에 성공해서 당황했다. 적어도 6/46이니까 7~8정도 돌릴줄 알았는데....ㅋㅋ 


운이 좋았다... 진짜 로또였으면 대박이였을텐데.... 큭;

어쨋든 클리어..ㅋㅋ


'Wargame > Pwnable.kr' 카테고리의 다른 글

[pwnable.kr] flag - 7 pt  (0) 2018.05.14
[pwnable.kr] input - 4 pt  (0) 2018.05.10
[pwnable.kr] bof- 5 pt  (0) 2018.05.09
[pwnable.kr] collision - 3 pt  (0) 2018.05.02
[pwnable.kr] blackjack - 1 pt  (0) 2018.05.01

+ Recent posts