[pwnable.kr] lotto(2 pts) :: Write-Up

두비니

·

2020. 7. 14. 01:20

 

Mommy! I made a lotto program for my homework.
do you want to play?

ssh lotto@pwnable.kr -p2222 (pw: guest)

 

 

 

lotto@pwnable:~$ nl lotto.c
     1	#include <stdio.h>
     2	#include <stdlib.h>
     3	#include <string.h>
     4	#include <fcntl.h>
       
     5	unsigned char submit[6];
       
     6	void play(){
     7		
     8		int i;
     9		printf("Submit your 6 lotto bytes : ");
    10		fflush(stdout);
       
    11		int r;
    12		r = read(0, submit, 6);
       
    13		printf("Lotto Start!\n");
    14		//sleep(1);
       
    15		// generate lotto numbers
    16		int fd = open("/dev/urandom", O_RDONLY);
    17		if(fd==-1){
    18			printf("error. tell admin\n");
    19			exit(-1);
    20		}
    21		unsigned char lotto[6];
    22		if(read(fd, lotto, 6) != 6){
    23			printf("error2. tell admin\n");
    24			exit(-1);
    25		}
    26		for(i=0; i<6; i++){
    27			lotto[i] = (lotto[i] % 45) + 1;		// 1 ~ 45
    28		}
    29		close(fd);
    30		
    31		// calculate lotto score
    32		int match = 0, j = 0;
    33		for(i=0; i<6; i++){
    34			for(j=0; j<6; j++){
    35				if(lotto[i] == submit[j]){
    36					match++;
    37				}
    38			}
    39		}
       
    40		// win!
    41		if(match == 6){
    42			system("/bin/cat flag");
    43		}
    44		else{
    45			printf("bad luck...\n");
    46		}
       
    47	}
       
    48	void help(){
    49		printf("- nLotto Rule -\n");
    50		printf("nlotto is consisted with 6 random natural numbers less than 46\n");
    51		printf("your goal is to match lotto numbers as many as you can\n");
    52		printf("if you win lottery for *1st place*, you will get reward\n");
    53		printf("for more details, follow the link below\n");
    54		printf("http://www.nlotto.co.kr/counsel.do?method=playerGuide#buying_guide01\n\n");
    55		printf("mathematical chance to win this game is known to be 1/8145060.\n");
    56	}
       
    57	int main(int argc, char* argv[]){
       
    58		// menu
    59		unsigned int menu;
       
    60		while(1){
       
    61			printf("- Select Menu -\n");
    62			printf("1. Play Lotto\n");
    63			printf("2. Help\n");
    64			printf("3. Exit\n");
       
    65			scanf("%d", &menu);
       
    66			switch(menu){
    67				case 1:
    68					play();
    69					break;
    70				case 2:
    71					help();
    72					break;
    73				case 3:
    74					printf("bye\n");
    75					return 0;
    76				default:
    77					printf("invalid menu\n");
    78					break;
    79			}
    80		}
    81		return 0;
    82	}
       

 

일단 코드의 전문이다. 보아하니 help와 main문 자체에서는 딱히 취약점이 없어서 play함수를 다시보자.

 

     6	void play(){
     7		
     8		int i;
     9		printf("Submit your 6 lotto bytes : ");
    10		fflush(stdout);

 

우선 나의 로또 6숫자를 입력받고, output stream을 비웁니다.

    11		int r;
    12		r = read(0, submit, 6);
       
    13		printf("Lotto Start!\n");
    14		//sleep(1);
       
    15		// generate lotto numbers
    16		int fd = open("/dev/urandom", O_RDONLY);
    17		if(fd==-1){
    18			printf("error. tell admin\n");
    19			exit(-1);
    20		}

 

그 다음 로또 번호를 랜덤생성해주고,

    21		unsigned char lotto[6];
    22		if(read(fd, lotto, 6) != 6){
    23			printf("error2. tell admin\n");
    24			exit(-1);
    25		}
    26		for(i=0; i<6; i++){
    27			lotto[i] = (lotto[i] % 45) + 1;		// 1 ~ 45
    28		}
    29		close(fd);
    30		

 

랜덤생성한 숫자를 45로 나눕니다. 범위가 1~45이기 때문이죠.

    31		// calculate lotto score
    32		int match = 0, j = 0;
    33		for(i=0; i<6; i++){
    34			for(j=0; j<6; j++){
    35				if(lotto[i] == submit[j]){			//vuln
    36					match++;
    37				}
    38			}
    39		}
       
    40		// win!
    41		if(match == 6){
    42			system("/bin/cat flag");
    43		}
    44		else{
    45			printf("bad luck...\n");
    46		}
       
    47	}

 

근데 여기서 취약점이 발생하게 됩니다. if문을 확인할때 무조건 앞에서부터 끝까지 무조건 확인합니다.

즉, 로또번호를 중복확인하지 않습니다.

예를들어 로또당첨번호가 123456이라면, 제가 222222를 입력해도 당첨이 된다는 것이죠.

 

 

그러면 그냥 1~45사이의 아스키값을 가지는 문자를 입력하면 되겠네요. 저는 !(느낌표) 사용하였고, 아스키 코드표 참고해서 되는값 아무거나해도 상관없습니다.

 

 

아무래도 random함수를 돌리다보니까 몇번 해야되네요