미역줄기의 이모저모
pwnable.kr lotto 풀이 본문
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 |