はじめに
IERAE CTF 2024に参加しました。6問解いて878ポイント66位でした。
環境
Fedora GNU/Linux
Welcome(122pt)
discordにjoinしてFLAGゲット。
IERAE{An_incredibly_interesting_flag}
OMG(123pt)
ブラウザの履歴を書き換えるウェブページ。
Let's press the browser back button 33 times. / 戻るボタンを33回押そう!
説明文のとおり33回戻るボタンをクリックしてFLAGゲット。
IERAE{Tr3ndy_4ds.LOL}
derangement(149pt)
deramgementしたものから15桁の文字列を推測する問題。
derangementの仕方を見ると、
def is_derangement(perm, original):
return all(p != o for p, o in zip(perm, original))
とあり、オリジナルと一致しない組み合わせを返している。
桁ごとに、何度derangementしても出てこない文字がオリジナルの文字になりそう。
#include <stdio.h>
int main(void) {
char str[16][16];
char d[16];
char list[16] = "!\"'()*<[15gOsSy"; //これが出てくる文字
for (int i = 0; i < 15; i++) {
for (int j = 0; j < 16; j++) {
str[i][j] = list[j];
}
}
for (; scanf("%s", &d) != -1; ) {
for (int i = 0; i < 15; i++) {
for (int j = 0; j < 16; j++) {
if (str[i][j] == d[i])
str[i][j]='\0';
}
}
}
// 候補を出力
for (int i = 0; i < 15; i++) {
for (int j = 0; j < 16; j++) {
if (str[i][j])
printf("%d:%c\n", i, str[i][j]);
}
}
}
出力は以下。
0:g
1:1
2:y
3:"
4:(
5:s
6:O
7:<
8:5
9:)
10:[
11:*
12:!
13:'
14:S
15桁の文字列は以下と分かった。※実行時ごとに異なる
g1y"(sO<5)[*!'S
プログラムに入力してFLAGゲット。
IERAE{th3r35_n0_5uch_th!ng_45_p3rf3ct_3ncrypt!0n}
Assignment
バイナリが渡された。
とりあえずobjdump -d
してみる。
0x1cの位置に0x33を代入、0x1の位置に0x45を代入、・・・としてフラグ文字列を作っていそう。
$ objdump -d chal
...省略...
0000000000001149 <main>:
1149: 55 push %rbp
114a: 48 89 e5 mov %rsp,%rbp
114d: 48 83 ec 10 sub $0x10,%rsp
1151: 89 7d fc mov %edi,-0x4(%rbp)
1154: 48 89 75 f0 mov %rsi,-0x10(%rbp)
1158: c6 05 fd 2e 00 00 33 movb $0x33,0x2efd(%rip) # 405c <flag+0x1c>
115f: c6 05 db 2e 00 00 45 movb $0x45,0x2edb(%rip) # 4041 <flag+0x1>
1166: c6 05 d5 2e 00 00 52 movb $0x52,0x2ed5(%rip) # 4042 <flag+0x2>
116d: c6 05 e0 2e 00 00 72 movb $0x72,0x2ee0(%rip) # 4054 <flag+0x14>
1174: c6 05 df 2e 00 00 61 movb $0x61,0x2edf(%rip) # 405a <flag+0x1a>
117b: c6 05 c8 2e 00 00 5f movb $0x5f,0x2ec8(%rip) # 404a <flag+0xa>
1182: c6 05 d7 2e 00 00 7d movb $0x7d,0x2ed7(%rip) # 4060 <flag+0x20>
1189: c6 05 b9 2e 00 00 65 movb $0x65,0x2eb9(%rip) # 4049 <flag+0x9>
1190: c6 05 bf 2e 00 00 6e movb $0x6e,0x2ebf(%rip) # 4056 <flag+0x16>
1197: c6 05 b3 2e 00 00 5f movb $0x5f,0x2eb3(%rip) # 4051 <flag+0x11>
119e: c6 05 a1 2e 00 00 73 movb $0x73,0x2ea1(%rip) # 4046 <flag+0x6>
11a5: c6 05 9b 2e 00 00 30 movb $0x30,0x2e9b(%rip) # 4047 <flag+0x7>
11ac: c6 05 9c 2e 00 00 30 movb $0x30,0x2e9c(%rip) # 404f <flag+0xf>
11b3: c6 05 96 2e 00 00 6d movb $0x6d,0x2e96(%rip) # 4050 <flag+0x10>
11ba: c6 05 94 2e 00 00 31 movb $0x31,0x2e94(%rip) # 4055 <flag+0x15>
11c1: c6 05 90 2e 00 00 5f movb $0x5f,0x2e90(%rip) # 4058 <flag+0x18>
11c8: c6 05 7d 2e 00 00 34 movb $0x34,0x2e7d(%rip) # 404c <flag+0xc>
11cf: c6 05 83 2e 00 00 35 movb $0x35,0x2e83(%rip) # 4059 <flag+0x19>
11d6: c6 05 82 2e 00 00 63 movb $0x63,0x2e82(%rip) # 405f <flag+0x1f>
11dd: c6 05 5f 2e 00 00 41 movb $0x41,0x2e5f(%rip) # 4043 <flag+0x3>
11e4: c6 05 55 2e 00 00 49 movb $0x49,0x2e55(%rip) # 4040 <flag>
11eb: c6 05 6b 2e 00 00 35 movb $0x35,0x2e6b(%rip) # 405d <flag+0x1d>
11f2: c6 05 59 2e 00 00 73 movb $0x73,0x2e59(%rip) # 4052 <flag+0x12>
11f9: c6 05 53 2e 00 00 74 movb $0x74,0x2e53(%rip) # 4053 <flag+0x13>
1200: c6 05 44 2e 00 00 72 movb $0x72,0x2e44(%rip) # 404b <flag+0xb>
1207: c6 05 3a 2e 00 00 6d movb $0x6d,0x2e3a(%rip) # 4048 <flag+0x8>
120e: c6 05 30 2e 00 00 7b movb $0x7b,0x2e30(%rip) # 4045 <flag+0x5>
1215: c6 05 28 2e 00 00 45 movb $0x45,0x2e28(%rip) # 4044 <flag+0x4>
121c: c6 05 38 2e 00 00 39 movb $0x39,0x2e38(%rip) # 405b <flag+0x1b>
1223: c6 05 34 2e 00 00 34 movb $0x34,0x2e34(%rip) # 405e <flag+0x1e>
122a: c6 05 26 2e 00 00 67 movb $0x67,0x2e26(%rip) # 4057 <flag+0x17>
1231: c6 05 15 2e 00 00 6e movb $0x6e,0x2e15(%rip) # 404d <flag+0xd>
1238: c6 05 0f 2e 00 00 64 movb $0x64,0x2e0f(%rip) # 404e <flag+0xe>
123f: 83 7d fc 01 cmpl $0x1,-0x4(%rbp)
1243: 7e 30 jle 1275 <main+0x12c>
1245: 48 8b 45 f0 mov -0x10(%rbp),%rax
1249: 48 83 c0 08 add $0x8,%rax
124d: 48 8b 00 mov (%rax),%rax
1250: 48 89 c6 mov %rax,%rsi
1253: 48 8d 05 e6 2d 00 00 lea 0x2de6(%rip),%rax # 4040 <flag>
125a: 48 89 c7 mov %rax,%rdi
125d: e8 de fd ff ff call 1040 <strcmp@plt>
FLAG文字列を作成するプログラムを作成した。
#include <stdio.h>
int main(void) {
int str[100] = {0};
int c, offset;
for (; scanf("%x %x", &c, &offset) != -1; ) {
str[offset] = c;
}
for (int i = 0; i < 100; i++) {
printf("%c", str[i]);
}
}
入力は以下。ディスアセンブル結果から値とoffsetを抽出した。
33 1c
45 1
52 2
...
FLAGゲット。
IERAE{s0me_r4nd0m_str1ng_5a9354c}
Weak PRNG
メルセンヌ・ツイスタで作った数字を、それ以降の出力から予測する問題。
以下記事を参考に作成。
xs1 = [ # プログラムの出力を624個並べた
1053714421,
2234018411,
2819543536,
254786992,
...
500837242,
56794293,
3564297824,
]
mt_state = [untemper(x) for x in xs1]
prev_mt_state = get_prev_state(mt_state)
random.setstate((3, tuple(prev_mt_state + [0]), None))
predicted = [random.getrandbits(32) for _ in range(N)]
print(predicted[-1]) # これが欲しい数字
数字を入力してFLAGゲット。
Luz Da Lua
luacファイルが渡された。unluacでデコンパイルしてみた。
$ java -jar unluac_2023_12_24.jar LuzDaLua.luac
luaでは~=は否定の条件式なので、条件式が成り立たない文字を探していけばよさそう。
io.write("Input > ")
input = io.read("*l")
if 28 ~= string.len(input) then
elseif string.byte(input, 1) ~ 232 ~= 161 then
elseif 43 ~= string.byte(input, 2) ~ 110 then
elseif string.byte(input, 3) ~ 178 ~= 224 then
elseif string.byte(input, 4) ~ 172 ~= 237 then
elseif string.byte(input, 5) ~ 212 ~= 145 then
elseif 98 ~= string.byte(input, 6) ~ 25 then
elseif 121 ~= string.byte(input, 7) ~ 53 then
elseif 74 ~= string.byte(input, 8) ~ 63 then
elseif string.byte(input, 9) ~ 135 ~= 230 then
elseif 3 ~= string.byte(input, 10) ~ 92 then
elseif 23 ~= string.byte(input, 11) ~ 38 then
elseif string.byte(input, 12) ~ 250 ~= 137 then
elseif 135 ~= string.byte(input, 13) ~ 216 then
elseif 86 ~= string.byte(input, 14) ~ 5 then
elseif 117 ~= string.byte(input, 15) ~ 69 then
elseif string.byte(input, 16) ~ 226 ~= 189 then
elseif string.byte(input, 17) ~ 137 ~= 186 then
elseif string.byte(input, 18) ~ 148 ~= 240 then
elseif 53 ~= string.byte(input, 19) ~ 64 then
elseif string.byte(input, 20) ~ 130 ~= 225 then
elseif string.byte(input, 21) ~ 241 ~= 197 then
elseif string.byte(input, 22) ~ 151 ~= 227 then
elseif 250 ~= string.byte(input, 23) ~ 203 then
elseif string.byte(input, 24) ~ 179 ~= 220 then
elseif string.byte(input, 25) ~ 216 ~= 182 then
elseif 4 ~= string.byte(input, 26) ~ 101 then
elseif 130 ~= string.byte(input, 27) ~ 238 then
elseif 64 ~= string.byte(input, 28) ~ 61 then
else
print("Correct")
goto lbl_305
end
print("Wrong")
::lbl_305::
luaでプログラムを作成。io.write()だと改行なしで出力できる。
io.write(string.char(232 ~ 161))
io.write(string.char(43 ~ 110))
io.write(string.char(178 ~ 224))
io.write(string.char(172 ~ 237))
io.write(string.char(212 ~ 145))
io.write(string.char(98 ~ 25))
io.write(string.char(121 ~ 53))
io.write(string.char(74 ~ 63))
io.write(string.char(135 ~ 230))
io.write(string.char(3 ~ 92))
io.write(string.char(23 ~ 38))
io.write(string.char(250 ~ 137))
io.write(string.char(135 ~ 216))
io.write(string.char(86 ~ 5))
io.write(string.char(117 ~ 69))
io.write(string.char(226 ~ 189))
io.write(string.char(137 ~ 186))
io.write(string.char(148 ~ 240))
io.write(string.char(53 ~ 64))
io.write(string.char(130 ~ 225))
io.write(string.char(241 ~ 197))
io.write(string.char(151 ~ 227))
io.write(string.char(250 ~ 203))
io.write(string.char(179 ~ 220))
io.write(string.char(216 ~ 182))
io.write(string.char(4 ~ 101))
io.write(string.char(130 ~ 238))
io.write(string.char(64 ~ 61))
FLAGゲット。
IERAE{Lua_1s_S0_3duc4t1onal}
感想
楽しかったです。
web系とpwn系の問題をもっと解けるようになりたいと思いました。