IERAE CTF 2024 Writeup

# はじめに
IERAE CTF 2024に参加しました。6問解いて878ポイント66位でした。

https://ierae-ctf.com/

# 環境
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の仕方を見ると、

```python
def is_derangement(perm, original):
    return all(p != o for p, o in zip(perm, original))
```

とあり、オリジナルと一致しない組み合わせを返している。
桁ごとに、何度derangementしても出てこない文字がオリジナルの文字になりそう。

```c
#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]);
		}
	}
}
```

出力は以下。
```text
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を代入、・・・としてフラグ文字列を作っていそう。

```console
$ objdump -d chal
```
```text
...省略...
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文字列を作成するプログラムを作成した。

```c
#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を抽出した。

```text
33 1c
45 1
52 2
...
```

FLAGゲット。
```IERAE{s0me_r4nd0m_str1ng_5a9354c}```

# Weak PRNG
メルセンヌ・ツイスタで作った数字を、それ以降の出力から予測する問題。
以下記事を参考に作成。

https://zenn.dev/hk_ilohas/articles/mersenne-twister-previous-state

```python
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でデコンパイルしてみた。

https://sourceforge.net/projects/unluac/

```console
$ java -jar unluac_2023_12_24.jar LuzDaLua.luac 
```

luaでは~=は否定の条件式なので、条件式が成り立たない文字を探していけばよさそう。

```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()だと改行なしで出力できる。

```lua
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系の問題をもっと解けるようになりたいと思いました。