チーム名numeron/ユーザ名numeronで参加。5問解いて693点取得し、224人中86位だった。
もともと参加の予定はなかったのであまり時間は取れなかったが、とっつきやすい問題も多く楽しめた。
OMG
戻るボタンを連打したら出てきた。
IERAE{Tr3ndy_4ds.LOL}
assignment
ghidraで解析すると、flag文字列が書いてある部分が見つかったが、文字の順番が入れ替わっている。手作業で並び替えるのも面倒なので、Cでsolver(と言っていいのか?)を書いた。
#include <stdio.h> int main() { char flag[40]; // 適当な大きさ flag[28] = 0x33; flag[1] = 0x45; flag[2] = 0x52; flag[20] = 0x72; flag[26] = 0x61; flag[10] = 0x5f; flag[32] = 0x7d; flag[9] = 0x65; flag[22] = 0x6e; flag[17] = 0x5f; flag[6] = 0x73; flag[7] = 0x30; flag[15] = 0x30; flag[16] = 0x6d; flag[21] = 0x31; flag[24] = 0x5f; flag[12] = 0x34; flag[25] = 0x35; flag[31] = 99; flag[3] = 0x41; flag[0] = 0x49; flag[29] = 0x35; flag[18] = 0x73; flag[19] = 0x74; flag[11] = 0x72; flag[8] = 0x6d; flag[5] = 0x7b; flag[4] = 0x45; flag[27] = 0x39; flag[30] = 0x34; flag[23] = 0x67; flag[13] = 0x6e; flag[14] = 100; printf("%s\n", flag); }
IERAE{s0me_r4nd0m_str1ng_5a9354c}
derangement
15文字の適当な文字列magic_word
を当てる問題。ヒントを聞くと、magic_word
の各文字の配置をランダムにした文字列が手に入る。このヒントは、もとのmagic_word
の配置と全く重ならないように作られている(任意のnについて、ヒントのn文字目はmagic_word
のn文字目と一致しない)ため、これを手がかりにしてmagic_word
を推測していく。
注意点として、配布プログラムのwhile connection_count < 300:
にもあるように、ヒント問い合わせと回答送信は合わせて300回までしか行えない。そこで、最初に298回*1ヒントを聞いておき、それらを手がかりに回答するという手順でsolverを作成した。
以下がsolverのコードである。
from pwn import * LENGTH = 15 def post_answer(io, answer: str): io.recvuntil(b"> ") io.sendline(b"2") io.recvuntil(b"> ") io.sendline(answer) io.interactive() def ask_hint(io) -> str: io.recvuntil(b"> ") io.sendline(b"1") io.recvuntil(b"hint: ") return io.recv(LENGTH).decode() def main(): io = remote("104.199.135.28", 55555) hints: list[str] = [ask_hint(io) for i in range(298)] char_set = hints[0] answer: str = "" for i in range(15): chars_left: str = char_set for h in hints: chars_left = chars_left.replace(h[i], "") if len(chars_left) == 1: answer += chars_left[0] break print(i, answer) print(answer) post_answer(io, answer) if __name__ == "__main__": main()
solverの実行結果を以下に示す。
[x] Opening connection to 104.199.135.28 on port 55555 [x] Opening connection to 104.199.135.28 on port 55555: Trying 104.199.135.28 [+] Opening connection to 104.199.135.28 on port 55555: Done 0 ( 1 (t 2 (tq 3 (tq1 4 (tq1) 5 (tq1)P 6 (tq1)Pf 7 (tq1)Pf+ 8 (tq1)Pf+r 9 (tq1)Pf+rp 10 (tq1)Pf+rp^ 11 (tq1)Pf+rp^d 12 (tq1)Pf+rp^dG 13 (tq1)Pf+rp^dG, 14 (tq1)Pf+rp^dG,/ (tq1)Pf+rp^dG,/ [*] Switching to interactive mode Congrats! IERAE{th3r35_n0_5uch_th!ng_45_p3rf3ct_3ncrypt!0n} Connection limit reached. Exiting... [*] Got EOF while reading in interactive
IERAE{th3r35_n0_5uch_th!ng_45_p3rf3ct_3ncrypt!0n}
Luz Da Lua
Luaのデコンパイラがあったので使う。 https://luadec.metaworm.site
-- filename: @/mnt/LuzDaLua.lua -- version: lua54 -- line: [0, 0] id: 0 io.write("Input > ") input = io.read("*l") if string.len(input) ~= 28 then goto label_301 elseif string.byte(input, 1) ~ 232 ~= 161 then goto label_301 elseif string.byte(input, 2) ~ 110 ~= 43 then goto label_301 elseif string.byte(input, 3) ~ 178 ~= 224 then goto label_301 elseif string.byte(input, 4) ~ 172 ~= 237 then goto label_301 elseif string.byte(input, 5) ~ 212 ~= 145 then goto label_301 elseif string.byte(input, 6) ~ 25 ~= 98 then goto label_301 elseif string.byte(input, 7) ~ 53 ~= 121 then goto label_301 elseif string.byte(input, 8) ~ 63 ~= 74 then goto label_301 elseif string.byte(input, 9) ~ 135 ~= 230 then goto label_301 elseif string.byte(input, 10) ~ 92 ~= 3 then goto label_301 elseif string.byte(input, 11) ~ 38 ~= 23 then goto label_301 elseif string.byte(input, 12) ~ 250 ~= 137 then goto label_301 elseif string.byte(input, 13) ~ 216 ~= 135 then goto label_301 elseif string.byte(input, 14) ~ 5 ~= 86 then goto label_301 elseif string.byte(input, 15) ~ 69 ~= 117 then goto label_301 elseif string.byte(input, 16) ~ 226 ~= 189 then goto label_301 elseif string.byte(input, 17) ~ 137 ~= 186 then goto label_301 elseif string.byte(input, 18) ~ 148 ~= 240 then goto label_301 elseif string.byte(input, 19) ~ 64 ~= 53 then goto label_301 elseif string.byte(input, 20) ~ 130 ~= 225 then goto label_301 elseif string.byte(input, 21) ~ 241 ~= 197 then goto label_301 elseif string.byte(input, 22) ~ 151 ~= 227 then goto label_301 elseif string.byte(input, 23) ~ 203 ~= 250 then goto label_301 elseif string.byte(input, 24) ~ 179 ~= 220 then goto label_301 elseif string.byte(input, 25) ~ 216 ~= 182 then goto label_301 elseif string.byte(input, 26) ~ 101 ~= 4 then goto label_301 elseif string.byte(input, 27) ~ 238 ~= 130 then goto label_301 elseif string.byte(input, 28) ~ 61 ~= 64 then goto label_301 else print("Correct") end -- warn: not visited block [59] -- block#59: -- _ENV.print("Wrong")
ここで~
はXOR演算、~=
は等しくないことを示す比較演算子である。
入力とflagを(XOR演算を挟みつつ)1文字ずつ比較しているので、この逆演算をすればよい。
pythonで適当にsolverを書いた。
chars: list[int] = [232^161, 110^43, 178^224, 172^237, 212^145, 25^98, 53^121, 63^74, 135^230, 92^3, 38^23, 250^137, 216^135, 5^86, 69^117, 226^189, 137^186, 148^240, 64^53, 130^225, 241^197, 151^227, 203^250, 179^220, 216^182, 101^4, 238^130, 61^64] flag: str = "".join([chr(c) for c in chars]) print(flag)
これを実行するとflagが得られる。
IERAE{Lua_1s_S0_3duc4t1onal}
*1:別に299回以下なら何回でもOKだと思うが念の為回数に余裕をもたせた