pwnable.kr (lotto)

c0wb3ll ㅣ 2020. 12. 22. 16:01

pwnable.kr (lotto)

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

로또 프로그램 소스코드이다.

unsigned char submit[6];    //global

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

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

unsigned char array로 선언된 submit에 우리가 입력한 로또 값이 들어간다.

    // 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);

로또 값은 /dev/urandom 이라는 난수생성기를 이용해 생성된다.

/dev/urandom을 이용해 난수를 생성하고 45값으로 나머지 연산을 하여 0~44의 값을 가지게 한다.

그 후 1을 더해 1~45의 값을 가지게 된다.

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

flag 획득 조건은 다음과 같다. match 값이 6이 되면 /bin/cat flag를 실행한다.

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

match 값이 증가하는 조건은 다음과 같다.

근데 조건이 무언가 이상하다.

만일 submit에 들어있는 값이 111111 이라면 이중 for문을 돌며 검사하는 과정에서

lotto[i]에 1이라는 값이 하나 있다면 match의 값이 6을 가지게 된다.

이 말은 6자리숫자를 모두 맞추는 것보다 6자리 중 한자리의 값을 맞추는 것이 더 쉽기 때문에 높은 확률로 로또에 당첨될 수 있다.

또한 변수들은 unsigned char 형으로 선언되어 있어서 ascii코드를 참고하여 1~45의 값들 중 하나를 선택해 입력하면 된다.