미역줄기의 이모저모

pwnable.kr lotto 풀이 본문

Hacking/포너블.kr 문제풀이

pwnable.kr lotto 풀이

미역줄기줄기 2024. 2. 1. 23:48
728x90

1. 문제확인

 

ssh lotto@pwnable.kr -p2222 로 접속!
 
 
 
 
 

2. 문제 분석

그리고 ls -l로 파일과 권한 확인!

lotto@pwnable:~$ ls -l
total 24
-r--r----- 1 lotto_pwn root 	55 Feb 18  2015 flag
-r-sr-x--- 1 lotto_pwn lotto 13081 Feb 18  2015 lotto
-r--r--r-- 1 root  	root   1713 Feb 18  2015 lotto.c

lotto_pwn을 가진 lotto를 통해 flag를 얻으면 되겠다! 그리고 -x니까 실행할 수 있겠네!
 
그전에 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;
}

실화냐
차분히 main부터 나눠서 보자
 

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

 
메뉴 선택하고 선택한 메뉴에 따라 play, help 함수가 호출되고 종료되는 것 말고는 별 다를거 없어 보인다.
 
 
그럼 이번엔 play함수를 보자

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

}

 
흠.. 일단 lotto값과 submit 값이 같으면 match가 1씩 증가 그렇게 match가 6이되면 flag가 나온다!
 
 
더 자세히 쪼개서 이해하자

 int i;
    printf("Submit your 6 lotto bytes : ");
    fflush(stdout);

 
정수 i 선언 했고,, 문자열 출력하고,, fflush(stdout)은 out stream을 비운다는 것이다.
 
 
 

int r;    
r = read(0, submit, 6);    
printf("Lotto Start!\n");

 
정수 r 선언 했고,, input strema으로부터 6글자를 받아서 char형 array submit에 저장한다
 
 
 

   // generate lotto numbers
    int fd = open("/dev/urandom", O_RDONLY);
    if(fd==-1){
   	 printf("error. tell admin\n");
   	 exit(-1);
    }

 
이건 그냥 /dev/urandom으로 난수를 생성하는 걸로 보인다.
fd를 얻지 못하면 에러 문장 출력
 
 
 

   unsigned char lotto[6];
    if(read(fd, lotto, 6) != 6){
   	 printf("error2. tell admin\n");
   	 exit(-1);
    }

 
char형 array lotto선언
앞서 구한 fd를 이용해서 /dev/ramdom의 난 6byte를 lotto에 넣는다.
read 실패하면 에러문장 출력
 
 
 

for(i=0; i<6; i++){
   	 lotto[i] = (lotto[i] % 45) + 1;   	 // 1 ~ 45
    }
    close(fd);

 
난수를 1~45로 조정해서 lotto에 넣어준다. 그리고 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++;
   		 }
   	 }
    }

 
lotto와 submit을 비교하는건데.. 같으면 match를 1씩 증가시킨다.
반복문을 잘 들여다 보면..
lotto가 123456이고 submit이 222222일때 6개가 모두 일치하는 상황이 생길 수 있다.
 
그러니까!
 
내가 어느 한 숫자를 중복으로 6개 입력하고 lotto의 6숫자 중에 내가 쓴 숫자만 있다면 당첨되는 것이다!
 
 
 

   // win!
    if(match == 6){
   	 system("/bin/cat flag");

 
그렇게 match가 6이 되면 flag 값이 읽힌다.
 
 
 
 
 

3. 문제 풀이

그러니까,
사용자의 입력(submit)의 중복을 체크하지 않아서 lotto에 당첨될 확률이 올라갔다.
 
그냥 될때까지 중복으로 아무거나 입력하자
근데! 입력할 때 int가 아니라 char형이기 때문에 1을 입력하면 '1'이 되어 10진수 값으로 49가 된다
 
45이하가 되는 문자를 아스키 코드표를 참고하여 쓰자!
 
나는 #으로 했다
 

될때까지 하면 된당
 

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

'Hacking > 포너블.kr 문제풀이' 카테고리의 다른 글

pwnable.kr passcode 풀이  (0) 2024.02.02
pwnable.kr cmd1 풀이  (1) 2024.02.02
pwnable.kr blackjack 풀이  (0) 2024.02.01
pwnable.kr shellshock 풀이  (0) 2024.02.01
pwnable.kr mistake 풀이  (0) 2024.02.01