ProxyChains does not intercept Nmap connect() when the Nmap binary has Linux file capabilities
Description
I encountered an issue while using ProxyChains with Nmap through a Chisel SOCKS proxy during a penetration testing lab.
Nmap bypasses ProxyChains and attempts to connect directly to the internal target, even when explicitly using a TCP Connect scan (-sT) with host discovery disabled (-Pn).
After investigating with strace, I found that the behavior appears to be related to Linux file capabilities assigned to the Nmap executable.
Removing the file capabilities from the equation by using a capability-free copy of the same Nmap binary causes ProxyChains to work correctly.
Setup
The network path is:
Nmap
↓
ProxyChains
↓
SOCKS5 (127.0.0.1:1080)
↓
Chisel
↓
Internal Host
The SOCKS proxy itself is working correctly.
For example, Impacket's wmiexec.py successfully connects through the same ProxyChains configuration:
[proxychains] Strict chain ... 127.0.0.1:1080 ... <INTERNAL_IP>:445 ... OK
Expected Behavior
Running:
proxychains nmap -n -Pn -sT -p 445 <INTERNAL_IP>
should cause Nmap's TCP connect() calls to be intercepted by ProxyChains and forwarded through the SOCKS proxy:
Nmap
↓
ProxyChains
↓
127.0.0.1:1080
↓
<INTERNAL_IP>:445
Since -sT explicitly selects a TCP Connect scan, I expected the connection to go through ProxyChains.
Actual Behavior
When running Nmap through ProxyChains:
proxychains nmap -n -Pn -sT -p 445 <INTERNAL_IP>
no Strict chain connection messages appear.
Nmap also fails to use the SOCKS proxy.
Investigation
On this system, /usr/bin/nmap is a shell wrapper rather than the actual Nmap ELF executable.
returns:
/usr/bin/nmap: a sh script, ASCII text executable
The wrapper contains:
#!/usr/bin/env sh
set -e
if [ "$(id -u)" -eq 0 ] || [ "$1" = "--resume" ]; then
exec /usr/lib/nmap/nmap "$@"
else
exec /usr/lib/nmap/nmap --privileged "$@"
fi
Therefore, the actual Nmap executable is:
File capabilities
Checking the actual executable:
getcap /usr/lib/nmap/nmap
returns:
/usr/lib/nmap/nmap cap_net_bind_service,cap_net_admin,cap_net_raw=eip
The binary is not setuid:
returns:
strace Result
I then traced the connect() system calls while running the actual Nmap executable through ProxyChains:
strace -f -e trace=connect \
proxychains /usr/lib/nmap/nmap \
--unprivileged -n -Pn -sT -p 445 <INTERNAL_IP>
Instead of connecting to the SOCKS proxy at:
Nmap attempted to connect directly to:
This indicates that the connect() call was not being intercepted by ProxyChains.
Workaround / A-B Test
To test whether the file capabilities were involved, I copied the exact same Nmap executable:
cp /usr/lib/nmap/nmap /tmp/nmap-test
I verified that the copied executable did not have file capabilities:
No capabilities were returned.
I then ran the copied binary through ProxyChains:
proxychains /tmp/nmap-test \
--unprivileged -n -Pn -sT -p 445 <INTERNAL_IP>
ProxyChains immediately worked as expected:
[proxychains] Strict chain ... 127.0.0.1:1080 ... <INTERNAL_IP>:445 ... OK
The traffic was successfully routed through the Chisel SOCKS proxy.
Comparison
Original Nmap executable
/usr/lib/nmap/nmap
File capabilities:
cap_net_bind_service,cap_net_admin,cap_net_raw=eip
↓
ProxyChains
↓
connect(<INTERNAL_IP>:445)
↓
Direct connection
Capability-free copy
/tmp/nmap-test
No file capabilities
↓
ProxyChains
↓
connect(127.0.0.1:1080)
↓
SOCKS5 / Chisel
↓
<INTERNAL_IP>:445
Possible Cause
My current understanding is that this may be related to the interaction between Linux file capabilities, the dynamic linker's secure-execution mode, and ProxyChains' use of LD_PRELOAD.
ProxyChains relies on LD_PRELOAD to load its library and intercept networking functions such as connect().
When executing a binary with elevated file capabilities such as:
cap_net_admin
cap_net_raw
the dynamic linker may treat the executable as running in secure-execution mode and restrict or ignore LD_PRELOAD.
If that is what is happening here, the ProxyChains library would not be loaded into the Nmap process, explaining why Nmap's connect() calls go directly to the internal host.
This also appears consistent with the observations that:
- Other applications such as
wmiexec.py work through the same ProxyChains configuration.
- Nmap does not produce any ProxyChains
Strict chain connection messages.
strace shows Nmap connecting directly to the internal target.
- The exact same Nmap binary works through ProxyChains after being copied without its file capabilities.
Questions
Is this an expected limitation of ProxyChains when the target executable has Linux file capabilities?
If this behavior is expected due to LD_PRELOAD restrictions, would it be useful to document it?
This may be particularly confusing when using Nmap for network pivoting because nmap -sT -Pn would normally be expected to work through ProxyChains, while other TCP applications using the same SOCKS proxy work correctly.
ProxyChains does not intercept Nmap
connect()when the Nmap binary has Linux file capabilitiesDescription
I encountered an issue while using ProxyChains with Nmap through a Chisel SOCKS proxy during a penetration testing lab.
Nmap bypasses ProxyChains and attempts to connect directly to the internal target, even when explicitly using a TCP Connect scan (
-sT) with host discovery disabled (-Pn).After investigating with
strace, I found that the behavior appears to be related to Linux file capabilities assigned to the Nmap executable.Removing the file capabilities from the equation by using a capability-free copy of the same Nmap binary causes ProxyChains to work correctly.
Setup
The network path is:
The SOCKS proxy itself is working correctly.
For example, Impacket's
wmiexec.pysuccessfully connects through the same ProxyChains configuration:Expected Behavior
Running:
should cause Nmap's TCP
connect()calls to be intercepted by ProxyChains and forwarded through the SOCKS proxy:Since
-sTexplicitly selects a TCP Connect scan, I expected the connection to go through ProxyChains.Actual Behavior
When running Nmap through ProxyChains:
no
Strict chainconnection messages appear.Nmap also fails to use the SOCKS proxy.
Investigation
On this system,
/usr/bin/nmapis a shell wrapper rather than the actual Nmap ELF executable.returns:
The wrapper contains:
Therefore, the actual Nmap executable is:
File capabilities
Checking the actual executable:
returns:
The binary is not setuid:
returns:
straceResultI then traced the
connect()system calls while running the actual Nmap executable through ProxyChains:Instead of connecting to the SOCKS proxy at:
Nmap attempted to connect directly to:
This indicates that the
connect()call was not being intercepted by ProxyChains.Workaround / A-B Test
To test whether the file capabilities were involved, I copied the exact same Nmap executable:
I verified that the copied executable did not have file capabilities:
No capabilities were returned.
I then ran the copied binary through ProxyChains:
ProxyChains immediately worked as expected:
The traffic was successfully routed through the Chisel SOCKS proxy.
Comparison
Original Nmap executable
Capability-free copy
Possible Cause
My current understanding is that this may be related to the interaction between Linux file capabilities, the dynamic linker's secure-execution mode, and ProxyChains' use of
LD_PRELOAD.ProxyChains relies on
LD_PRELOADto load its library and intercept networking functions such asconnect().When executing a binary with elevated file capabilities such as:
the dynamic linker may treat the executable as running in secure-execution mode and restrict or ignore
LD_PRELOAD.If that is what is happening here, the ProxyChains library would not be loaded into the Nmap process, explaining why Nmap's
connect()calls go directly to the internal host.This also appears consistent with the observations that:
wmiexec.pywork through the same ProxyChains configuration.Strict chainconnection messages.straceshows Nmap connecting directly to the internal target.Questions
Is this an expected limitation of ProxyChains when the target executable has Linux file capabilities?
If this behavior is expected due to
LD_PRELOADrestrictions, would it be useful to document it?This may be particularly confusing when using Nmap for network pivoting because
nmap -sT -Pnwould normally be expected to work through ProxyChains, while other TCP applications using the same SOCKS proxy work correctly.