본문 바로가기

CTF_Write_UP/pwnable.kr

pwnable.kr : lotto 풀이

 

시작

안녕하세요!!

원래는 uaf를 풀어보려고 했는데 3시간 째 붙잡고 있다가 멘탈이 터졌어요!! 우와!!

그래서 스트레스 풀려고 만만한 lotto를 들고왔어요!!

들어가봐요!!

root@goorm:/workspace/LCH_Server# ssh lotto@pwnble.kr -p2222

Write UP

lotto.c의 내용을 먼저 볼까요?

lotto@ubuntu:~$ cat lotto.c
#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;
}

와 정말 꼴도 보기 싫게 기네요!!

read 함수에 fd 값을 0을 주어 charsubmit에 우리의 입력을 6 bytes 만큼 저장합니다.

다음으로 /dev/urandom이란 파일을 읽어서 charlotto 배열에 6 bytes 만큼 저장하네요.

그 후 각각 % 45 연산을 통해 1부터 45까지의 값을 넣어줍니다.

그리고 점수를 계산하고 match 값이 6이면 flag를 출력하는군요.

여기까지 왔을 때, 이상하다고 느낀 부분이 두 가지가 있습니다.

  1. int가 아닌 char 형태의 배열이다.

  2. 점수를 계산하는 부분이 이상하다.

1번 문제점은, 우리가 숫자 1을 입력해도 char형 배열 속엔 문자 '1'이 들어갑니다.

구글링을 통해 찾아보면 문자 '1'ASCII값은 81번이네요.

따라서 우리는 ASCII값이 1부터 45까지인 문자 중 하나를 넣어주어야 합니다.

키보드로 입력이 가능한 것은 몇 개 안되네요.

! " # $ % ^ ' ( ) * + , - . /가 전부입니다.

2번 문제점은, for문의 범위가 이상합니다.

저런 식으로 반복문을 돌리면, 6개 중 1개만 lotto 배열과 일치하면 match 카운트가 6이 되겠죠?

인덱스를 처음부터 끝까지 검사하기 때문입니다.

flag를 얻을 준비는 끝났습니다. 나머진 운에 맡겨야겠네요.

!를 사용해서 돌려보겠습니다.

lotto@ubuntu:~$ ./lotto

- Select Menu -
1. Play Lotto
2. Help
3. Exit
1
Submit your 6 lotto bytes : !!!!!!
Lotto Start!
bad luck...
- Select Menu -
1. Play Lotto
2. Help
3. Exit
1
Submit your 6 lotto bytes : !!!!!!
Lotto Start!
bad luck...
- Select Menu -
1. Play Lotto
2. Help
3. Exit
1
Submit your 6 lotto bytes : !!!!!!
Lotto Start!
bad luck...
- Select Menu -
1. Play Lotto
2. Help
3. Exit
1
Submit your 6 lotto bytes : !!!!!!
Lotto Start!
bad luck...
- Select Menu -
1. Play Lotto
2. Help
3. Exit
1
Submit your 6 lotto bytes : !!!!!!
Lotto Start!
sorry mom... I FORGOT to check duplicate numbers... :(

마무리

반복문의 범위를 생각하지 않아서 발생하는 문제였습니다.

char형 배열로 받은 것도 실수였구요.

lotto는 쉽게 풀 수 있었습니다ㅎㅎ..

문제는 uaf인데.. 저번에 passcode 풀 때 처럼 하루 종일 우울하네요!!! 머리 터질 것 같아요!!

다음 포스팅은 꼭 uaf로 오겠습니다.. 기다려주세요.. :)

 

'CTF_Write_UP > pwnable.kr' 카테고리의 다른 글

[pwnable.kr] unexploitable  (0) 2019.06.20
pwnable.kr : uaf 풀이  (0) 2019.04.18
pwnable.kr : shellshock 풀이  (0) 2019.04.16
pwnable.kr : mistake 풀이  (0) 2019.04.16
pwnable.kr : passcode 풀이  (0) 2019.04.14