본문 바로가기
포너블(pwnable)/CTF(pwnable.kr)

[Toddler's Bottle] lotto 문제풀이

by LIZ0904 2021. 5. 7.
반응형

lotto

오늘의 문제는 lotto다. 난 로또 1등 당첨되고 싶은데 이 문제를 풀면 당첨될 수 있을까?

 

ssh 주소 접속

ssh 주소로 들어간 뒤, ls 명령을 통해 안의 내용을 확인해보았다. 뭐 지금까지 했던 대로 lotto.c의 코드를 이해한 뒤, lotto 실행파일을 통해 flag 파일을 확인할 수 있겠지...

 

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

cat lotto.c 명령을 이용해 lotto.c 파일의 내용을 확인해보았다. play(), help(), main() 크게 3가지의 함수로 이루어져 있다. 중요시 여겨 봐야 하는 것은 당연히 play 함수다.

 

//play 함수의 일부분

    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");
	}

play함수 중에서 유심히 봐야하는 부분은 이 부분이다. char 형태로 lotto 배열 6개를 받아오고 있고, 여기에는 1~45까지의 숫자가 들어갈 수 있다.

 

아스키코드값으로 1~45까지의 10진수 중에서 키보드로 입력값을 전달할 수 있는 것은, 33(!)~45(-)까지 있다.

그 다음 중첩 for문을 보면, 총 36번의 루프를 돈다. 즉, lotto 배열의 값 중 하나만 맞으면 match가 6이 되면서 flag를 출력할 수 있다는 말이다. 만약 submit=123456이라면, lotto=111111이라도 match가 6이 되어 flag가 출력된다는 의미다.

 

하지만 lotto가 int형이 아닌 char형이기 때문에, 만약 숫자 1을 입력하면 문자 '1'로 인식해 아스키코드 값인 49로 인식이 된다. 때문에 아스키코드표를 참고해 45이하인 수를 입력해줘야한다. 만약 lotto값으로 !!!!!!을 입력해주면, 33 33 33 33 33 33 으로 인식되고, submit에 33이라는 숫자가 있을 때까지 계속 입력해주면 된다.

 

flag 출력

나는 ,,,,,,(44 44 44 44 44 44)를 입력해주었는데, 여러번 입력해보다 보니 flag가 출력됐다!

성공~~

 

 

flag: sorry mom... I FORGOT to check duplicate numbers... :(

 

 

반응형

댓글