AdaptixC2 ๊ตฌ์„ฑ ์ถ”์ถœ ๋ฐ TTPs

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 ์ง€์›ํ•˜๊ธฐ

AdaptixC2๋Š” Windows x86/x64 beacons(EXE/DLL/service EXE/raw shellcode) ๋ฐ BOF๋ฅผ ์ง€์›ํ•˜๋Š” ๋ชจ๋“ˆ์‹์˜ ์˜คํ”ˆ์†Œ์Šค postโ€‘exploitation/C2 ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค. ์ด ํŽ˜์ด์ง€๋Š” ๋‹ค์Œ์„ ๋ฌธ์„œํ™”ํ•ฉ๋‹ˆ๋‹ค:

  • RC4โ€‘packed configuration์ด ์–ด๋–ป๊ฒŒ ํฌํ•จ๋˜์–ด ์žˆ๋Š”์ง€์™€ beacon์—์„œ ์ด๋ฅผ ์ถ”์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•
  • HTTP/SMB/TCP ๋ฆฌ์Šค๋„ˆ์— ๋Œ€ํ•œ ๋„คํŠธ์›Œํฌ/ํ”„๋กœํ•„ ์ง€ํ‘œ
  • ์‹ค์ œ ์‚ฌ๋ก€์—์„œ ๊ด€์ฐฐ๋œ ์ผ๋ฐ˜์ ์ธ loader ๋ฐ persistence TTPs์™€ ๊ด€๋ จ Windows technique ํŽ˜์ด์ง€๋กœ์˜ ๋งํฌ

Beacon ํ”„๋กœํ•„ ๋ฐ ํ•„๋“œ

AdaptixC2๋Š” ์„ธ ๊ฐ€์ง€ ์ฃผ์š” beacon ํƒ€์ž…์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค:

  • BEACON_HTTP: ์„œ๋ฒ„/ํฌํŠธ/SSL, method, URI, headers, userโ€‘agent ๋ฐ custom parameter name์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋Š” web C2
  • BEACON_SMB: namedโ€‘pipe ๊ธฐ๋ฐ˜์˜ peerโ€‘toโ€‘peer C2 (intranet)
  • BEACON_TCP: ์ง์ ‘ ์†Œ์ผ“ ๋ฐฉ์‹, ์„ ํƒ์ ์œผ๋กœ ํ”„๋กœํ† ์ฝœ ์‹œ์ž‘์„ ๋‚œ๋…ํ™”ํ•˜๊ธฐ ์œ„ํ•œ ์„ ํ–‰ ๋งˆ์ปค(prepended marker) ํฌํ•จ ๊ฐ€๋Šฅ

HTTP beacon ๊ตฌ์„ฑ(๋ณตํ˜ธํ™” ํ›„)์—์„œ ๊ด€์ฐฐ๋˜๋Š” ์ผ๋ฐ˜์ ์ธ ํ”„๋กœํ•„ ํ•„๋“œ:

  • agent_type (u32)
  • use_ssl (bool)
  • servers_count (u32), servers (array of strings), ports (array of u32)
  • http_method, uri, parameter, user_agent, http_headers (lengthโ€‘prefixed strings)
  • ans_pre_size (u32), ans_size (u32) โ€“ ์‘๋‹ต ํฌ๊ธฐ ํŒŒ์‹ฑ์— ์‚ฌ์šฉ
  • kill_date (u32), working_time (u32)
  • sleep_delay (u32), jitter_delay (u32)
  • listener_type (u32)
  • download_chunk_size (u32)

์˜ˆ์‹œ ๊ธฐ๋ณธ HTTP ํ”„๋กœํ•„ (beacon ๋นŒ๋“œ์—์„œ):

{
"agent_type": 3192652105,
"use_ssl": true,
"servers_count": 1,
"servers": ["172.16.196.1"],
"ports": [4443],
"http_method": "POST",
"uri": "/uri.php",
"parameter": "X-Beacon-Id",
"user_agent": "Mozilla/5.0 (Windows NT 6.2; rv:20.0) Gecko/20121202 Firefox/20.0",
"http_headers": "\r\n",
"ans_pre_size": 26,
"ans_size": 47,
"kill_date": 0,
"working_time": 0,
"sleep_delay": 2,
"jitter_delay": 0,
"listener_type": 0,
"download_chunk_size": 102400
}

๊ด€์ฐฐ๋œ ์•…์„ฑ HTTP ํ”„๋กœํ•„(์‹ค์ œ ๊ณต๊ฒฉ):

{
"agent_type": 3192652105,
"use_ssl": true,
"servers_count": 1,
"servers": ["tech-system[.]online"],
"ports": [443],
"http_method": "POST",
"uri": "/endpoint/api",
"parameter": "X-App-Id",
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.6167.160 Safari/537.36",
"http_headers": "\r\n",
"ans_pre_size": 26,
"ans_size": 47,
"kill_date": 0,
"working_time": 0,
"sleep_delay": 4,
"jitter_delay": 0,
"listener_type": 0,
"download_chunk_size": 102400
}

์•”ํ˜ธํ™”๋œ ๊ตฌ์„ฑ ํŒจํ‚น ๋ฐ ๋กœ๋“œ ๊ฒฝ๋กœ

์šด์˜์ž๊ฐ€ builder์—์„œ Create๋ฅผ ํด๋ฆญํ•˜๋ฉด, AdaptixC2๋Š” ์•”ํ˜ธํ™”๋œ ํ”„๋กœํŒŒ์ผ์„ beacon์˜ tail blob์œผ๋กœ ์ž„๋ฒ ๋“œํ•ฉ๋‹ˆ๋‹ค. ํ˜•์‹์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  • 4 ๋ฐ”์ดํŠธ: ๊ตฌ์„ฑ ํฌ๊ธฐ (uint32, littleโ€‘endian)
  • N ๋ฐ”์ดํŠธ: RC4โ€‘์•”ํ˜ธํ™”๋œ ๊ตฌ์„ฑ ๋ฐ์ดํ„ฐ
  • 16 ๋ฐ”์ดํŠธ: RC4 ํ‚ค

beacon loader๋Š” ๋์—์„œ 16โ€‘byte ํ‚ค๋ฅผ ๋ณต์‚ฌํ•˜๊ณ  Nโ€‘byte ๋ธ”๋ก์„ ์ œ์ž๋ฆฌ์—์„œ RC4๋กœ ๋ณตํ˜ธํ™”ํ•ฉ๋‹ˆ๋‹ค:

ULONG profileSize = packer->Unpack32();
this->encrypt_key = (PBYTE) MemAllocLocal(16);
memcpy(this->encrypt_key, packer->data() + 4 + profileSize, 16);
DecryptRC4(packer->data()+4, profileSize, this->encrypt_key, 16);

์‹ค๋ฌด์  ์‹œ์‚ฌ์ :

  • ์ „์ฒด ๊ตฌ์กฐ๋Š” ์ข…์ข… PE .rdata ์„น์…˜ ๋‚ด๋ถ€์— ์œ„์น˜ํ•ฉ๋‹ˆ๋‹ค.
  • ์ถ”์ถœ์€ ๊ฒฐ์ •์ ์ž…๋‹ˆ๋‹ค: size๋ฅผ ์ฝ๊ณ , ํ•ด๋‹น ํฌ๊ธฐ์˜ ciphertext๋ฅผ ์ฝ๊ณ , ๋ฐ”๋กœ ๋‹ค์Œ์— ์œ„์น˜ํ•œ 16โ€‘byte ํ‚ค๋ฅผ ์ฝ์€ ๋‹ค์Œ, RC4โ€‘decryptํ•ฉ๋‹ˆ๋‹ค.

๊ตฌ์„ฑ ์ถ”์ถœ ์›Œํฌํ”Œ๋กœ์šฐ (๋ฐฉ์–ด์ž)

beacon logic์„ ๋ชจ๋ฐฉํ•˜๋Š” extractor๋ฅผ ์ž‘์„ฑํ•˜์„ธ์š”:

  1. PE ๋‚ด๋ถ€์—์„œ blob์„ ์ฐพ์Šต๋‹ˆ๋‹ค (์ผ๋ฐ˜์ ์œผ๋กœ .rdata). ์‹ค์šฉ์ ์ธ ๋ฐฉ๋ฒ•์€ .rdata๋ฅผ ์Šค์บ”ํ•˜์—ฌ ํ•ฉ๋ฆฌ์ ์ธ [size|ciphertext|16โ€‘byte key] ๋ ˆ์ด์•„์›ƒ์„ ์ฐพ๊ณ  RC4๋ฅผ ์‹œ๋„ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  2. ์ฒ˜์Œ 4๋ฐ”์ดํŠธ๋ฅผ ์ฝ์Šต๋‹ˆ๋‹ค โ†’ size (uint32 LE).
  3. ๋‹ค์Œ N=size ๋ฐ”์ดํŠธ๋ฅผ ์ฝ์Šต๋‹ˆ๋‹ค โ†’ ciphertext.
  4. ๋งˆ์ง€๋ง‰ 16๋ฐ”์ดํŠธ๋ฅผ ์ฝ์Šต๋‹ˆ๋‹ค โ†’ RC4 key.
  5. ciphertext๋ฅผ RC4โ€‘decryptํ•œ ๋’ค, ํ‰๋ฌธ ํ”„๋กœํŒŒ์ผ์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํŒŒ์‹ฑํ•ฉ๋‹ˆ๋‹ค:
  • ์œ„์— ์–ธ๊ธ‰ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ u32/boolean scalars
  • ๊ธธ์ด ์ ‘๋‘ํ˜• ๋ฌธ์ž์—ด (u32 length ๋‹ค์Œ์— ๋ฐ”์ดํŠธ; ๋์˜ NUL์ด ์žˆ์„ ์ˆ˜ ์žˆ์Œ)
  • ๋ฐฐ์—ด: servers_count ๋‹ค์Œ์— ๊ทธ ์ˆ˜๋งŒํผ์˜ [string, u32 port] ์Œ์ด ์˜ต๋‹ˆ๋‹ค

์‚ฌ์ „ ์ถ”์ถœ๋œ blob์—์„œ ๋™์ž‘ํ•˜๋Š” ์ตœ์†Œํ•œ์˜ Python proofโ€‘ofโ€‘concept(standalone, ์™ธ๋ถ€ ์ข…์† ์—†์Œ):

import struct
from typing import List, Tuple

def rc4(key: bytes, data: bytes) -> bytes:
S = list(range(256))
j = 0
for i in range(256):
j = (j + S[i] + key[i % len(key)]) & 0xFF
S[i], S[j] = S[j], S[i]
i = j = 0
out = bytearray()
for b in data:
i = (i + 1) & 0xFF
j = (j + S[i]) & 0xFF
S[i], S[j] = S[j], S[i]
K = S[(S[i] + S[j]) & 0xFF]
out.append(b ^ K)
return bytes(out)

class P:
def __init__(self, buf: bytes):
self.b = buf; self.o = 0
def u32(self) -> int:
v = struct.unpack_from('<I', self.b, self.o)[0]; self.o += 4; return v
def u8(self) -> int:
v = self.b[self.o]; self.o += 1; return v
def s(self) -> str:
L = self.u32(); s = self.b[self.o:self.o+L]; self.o += L
return s[:-1].decode('utf-8','replace') if L and s[-1] == 0 else s.decode('utf-8','replace')

def parse_http_cfg(plain: bytes) -> dict:
p = P(plain)
cfg = {}
cfg['agent_type']    = p.u32()
cfg['use_ssl']       = bool(p.u8())
n                    = p.u32()
cfg['servers']       = []
cfg['ports']         = []
for _ in range(n):
cfg['servers'].append(p.s())
cfg['ports'].append(p.u32())
cfg['http_method']   = p.s()
cfg['uri']           = p.s()
cfg['parameter']     = p.s()
cfg['user_agent']    = p.s()
cfg['http_headers']  = p.s()
cfg['ans_pre_size']  = p.u32()
cfg['ans_size']      = p.u32() + cfg['ans_pre_size']
cfg['kill_date']     = p.u32()
cfg['working_time']  = p.u32()
cfg['sleep_delay']   = p.u32()
cfg['jitter_delay']  = p.u32()
cfg['listener_type'] = 0
cfg['download_chunk_size'] = 0x19000
return cfg

# Usage (when you have [size|ciphertext|key] bytes):
# blob = open('blob.bin','rb').read()
# size = struct.unpack_from('<I', blob, 0)[0]
# ct   = blob[4:4+size]
# key  = blob[4+size:4+size+16]
# pt   = rc4(key, ct)
# cfg  = parse_http_cfg(pt)

ํŒ:

  • ์ž๋™ํ™”ํ•  ๋•Œ, PE parser๋ฅผ ์‚ฌ์šฉํ•ด .rdata๋ฅผ ์ฝ๊ณ  ์Šฌ๋ผ์ด๋”ฉ ์œˆ๋„์šฐ๋ฅผ ์ ์šฉํ•˜์„ธ์š”: ๊ฐ ์˜คํ”„์…‹ o์— ๋Œ€ํ•ด size = u32(.rdata[o:o+4]), ct = .rdata[o+4:o+4+size], candidate key = next 16 bytes; RC4โ€‘decryptํ•˜๊ณ  ๋ฌธ์ž์—ด ํ•„๋“œ๊ฐ€ UTFโ€‘8๋กœ ๋””์ฝ”๋”ฉ๋˜๋Š”์ง€์™€ ๊ธธ์ด๊ฐ€ ํƒ€๋‹นํ•œ์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • ๋™์ผํ•œ lengthโ€‘prefixed ๊ทœ์•ฝ์„ ๋”ฐ๋ผ SMB/TCP ํ”„๋กœํŒŒ์ผ์„ ํŒŒ์‹ฑํ•˜์„ธ์š”.

๋„คํŠธ์›Œํฌ ์ง€๋ฌธํ™” ๋ฐ ํ—ŒํŒ…

HTTP

  • ์ผ๋ฐ˜์ : ์šด์˜์ž ์„ ํƒ URIs๋กœ POST(์˜ˆ: /uri.php, /endpoint/api)
  • beacon ID์— ์‚ฌ์šฉ๋˜๋Š” ์ปค์Šคํ…€ ํ—ค๋” ํŒŒ๋ผ๋ฏธํ„ฐ(์˜ˆ: Xโ€‘Beaconโ€‘Id, Xโ€‘Appโ€‘Id)
  • Firefox 20 ๋˜๋Š” ๋‹น์‹œ์˜ Chrome ๋นŒ๋“œ๋ฅผ ํ‰๋‚ด๋‚ด๋Š” Userโ€‘agents
  • sleep_delay/jitter_delay๋ฅผ ํ†ตํ•ด ๋ณด์ด๋Š” ํด๋ง ์ฃผ๊ธฐ

SMB/TCP

  • ์›น egress๊ฐ€ ์ œํ•œ๋œ ์ธํŠธ๋ผ๋„ท C2๋ฅผ ์œ„ํ•œ SMB namedโ€‘pipe ๋ฆฌ์Šค๋„ˆ
  • TCP beacons๋Š” ํ”„๋กœํ† ์ฝœ ์‹œ์ž‘์„ ์€ํํ•˜๊ธฐ ์œ„ํ•ด ํŠธ๋ž˜ํ”ฝ ์•ž์— ๋ช‡ ๋ฐ”์ดํŠธ๋ฅผ ๋ถ™์ผ ์ˆ˜ ์žˆ์Œ

์ธ์‹œ๋˜ํŠธ์—์„œ ๊ด€์ฐฐ๋œ Loader ๋ฐ persistence TTPs

๋ฉ”๋ชจ๋ฆฌ ๋‚ด PowerShell ๋กœ๋”

  • Base64/XOR ํŽ˜์ด๋กœ๋“œ ๋‹ค์šด๋กœ๋“œ (Invokeโ€‘RestMethod / WebClient)
  • unmanaged memory ํ• ๋‹น, shellcode ๋ณต์‚ฌ, VirtualProtect๋กœ ๋ณดํ˜ธ๋ฅผ 0x40 (PAGE_EXECUTE_READWRITE)์œผ๋กœ ๋ณ€๊ฒฝ
  • .NET ๋™์  ํ˜ธ์ถœ๋กœ ์‹คํ–‰: Marshal.GetDelegateForFunctionPointer + delegate.Invoke()

๋ฉ”๋ชจ๋ฆฌ ๋‚ด ์‹คํ–‰ ๋ฐ AMSI/ETW ๊ด€๋ จ ๊ณ ๋ ค์‚ฌํ•ญ์€ ๋‹ค์Œ ํŽ˜์ด์ง€๋ฅผ ํ™•์ธํ•˜์„ธ์š”:

Antivirus (AV) Bypass

๊ด€์ฐฐ๋œ ์ง€์†์„ฑ ๋ฉ”์ปค๋‹ˆ์ฆ˜

  • ๋กœ๊ทธ์˜จ ์‹œ ๋กœ๋”๋ฅผ ์žฌ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•œ Startup ํด๋”์˜ ๋ฐ”๋กœ๊ฐ€๊ธฐ(.lnk)
  • Registry Run ํ‚ค(HKCU/HKLM โ€ฆ\CurrentVersion\Run), ์ข…์ข… โ€œUpdaterโ€œ์ฒ˜๋Ÿผ ๋ฌดํ•ดํ•˜๊ฒŒ ๋“ค๋ฆฌ๋Š” ์ด๋ฆ„์œผ๋กœ loader.ps1์„ ์‹œ์ž‘
  • ์ทจ์•ฝํ•œ ํ”„๋กœ์„ธ์Šค๋ฅผ ๋Œ€์ƒ์œผ๋กœ %APPDATA%\Microsoft\Windows\Templates ์•„๋ž˜์— msimg32.dll์„ ๋‘ฌ์„œ ๋ฐœ์ƒํ•˜๋Š” DLL searchโ€‘order hijack

๊ธฐ์ˆ  ์‹ฌ์ธต ๋ถ„์„ ๋ฐ ์ ๊ฒ€:

Privilege Escalation with Autoruns

Dll Hijacking

ํ—ŒํŒ… ์•„์ด๋””์–ด

  • PowerShell์—์„œ ๋ฐœ์ƒํ•˜๋Š” RWโ†’RX ์ „ํ™˜: powershell.exe ๋‚ด๋ถ€์—์„œ VirtualProtect๋ฅผ ํ†ตํ•ด PAGE_EXECUTE_READWRITE
  • ๋™์  ํ˜ธ์ถœ ํŒจํ„ด (GetDelegateForFunctionPointer)
  • ์‚ฌ์šฉ์ž ๋˜๋Š” ๊ณต์šฉ Startup ํด๋”์˜ Startup .lnk
  • ์˜์‹ฌ์Šค๋Ÿฌ์šด Run ํ‚ค(์˜ˆ: โ€œUpdaterโ€) ๋ฐ update.ps1/loader.ps1 ๊ฐ™์€ ๋กœ๋” ์ด๋ฆ„
  • msimg32.dll์„ ํฌํ•จํ•˜๋Š” %APPDATA%\Microsoft\Windows\Templates ์•„๋ž˜์˜ ์‚ฌ์šฉ์ž ์“ฐ๊ธฐ ๊ฐ€๋Šฅํ•œ DLL ๊ฒฝ๋กœ

OpSec ํ•„๋“œ์— ๋Œ€ํ•œ ๋…ธํŠธ

  • KillDate: ์—์ด์ „ํŠธ๊ฐ€ ์Šค์Šค๋กœ ๋งŒ๋ฃŒ๋˜๋Š” ์‹œ์  ์ดํ›„์˜ ํƒ€์ž„์Šคํƒฌํ”„
  • WorkingTime: ์—์ด์ „ํŠธ๊ฐ€ ๋น„์ฆˆ๋‹ˆ์Šค ํ™œ๋™์— ์„ž์ด๋„๋ก ํ™œ์„ฑํ™”๋˜์–ด์•ผ ํ•˜๋Š” ์‹œ๊ฐ„๋Œ€

์ด ํ•„๋“œ๋“ค์€ ํด๋Ÿฌ์Šคํ„ฐ๋ง์— ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ๊ด€์ฐฐ๋œ ์กฐ์šฉํ•œ ๊ธฐ๊ฐ„์„ ์„ค๋ช…ํ•˜๋Š” ๋ฐ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

YARA ๋ฐ ์ •์  ๋‹จ์„œ

Unit 42๋Š” beacons(C/C++ ๋ฐ Go)์šฉ ๊ธฐ๋ณธ YARA์™€ loader APIโ€‘hashing ์ƒ์ˆ˜๋ฅผ ๊ณต๊ฐœํ–ˆ์Šต๋‹ˆ๋‹ค. PE .rdata ๋ ๊ทผ์ฒ˜์—์„œ [size|ciphertext|16โ€‘byteโ€‘key] ๋ ˆ์ด์•„์›ƒ๊ณผ ๊ธฐ๋ณธ HTTP ํ”„๋กœํŒŒ์ผ ๋ฌธ์ž์—ด์„ ์ฐพ๋Š” ๋ฃฐ๋กœ ๋ณด์™„ํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•˜์„ธ์š”.

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 ์ง€์›ํ•˜๊ธฐ