masterwok/sohps
GitHub: masterwok/sohps
Stars: 1 | Forks: 0
# sohps: Shared Object Hijack Path Scanner
`sohps` is a security auditing tool designed to identify shared object hijack vulnerabilities in Linux ELF binaries and AppImage containers. By simulating the behavior of the Linux dynamic linker (`ld.so`), sohps maps how binaries resolve their shared object dependencies and uncovers vulnerabilities introduced by insecure search paths, writable directories, or misconfigured environments.
## Vulnerability Classes
`sohps` categorizes findings into several distinct attack vectors, providing researchers with immediate context for exploitation:
| Category | Description |
| :--- | :--- |
| **Implicit CWD** | Triggered by empty entries in `RPATH` or `RUNPATH` (e.g., a trailing colon). The linker falls back to the Current Working Directory, allowing an attacker to drop a malicious library. |
| **Environment Poisoning** | Triggered by insecure script wrappers (e.g., in AppImages) that blindly append to `LD_LIBRARY_PATH`. If the environment variable is unset, the trailing colon falls back to the CWD. |
| **$ORIGIN Hijack** | Vulnerabilities within directories resolved via the `$ORIGIN` macro. If the binary's directory or its relative neighbors are writable, the dependency tree can be hijacked. |
| **Writable Path** | Absolute search paths (system or user-defined) that are writable by the current user, allowing for direct replacement or tree recreation. |
| **Relative Path** | Hardcoded relative paths (e.g., `lib/`) that resolve against the CWD rather than the binary's location. |
| **Absolute Path** | Occurs when a `DT_NEEDED` entry contains a `/` (e.g., `/tmp/lib.so`). The linker bypasses all search paths and loads the file directly from the specified location. |
| **System Preload** | Checks for writable or missing `/etc/ld.so.preload` files, which can lead to system-wide hijacking of every executed process. |
## Capabilities
`sohps` simulates the following `ld.so` logic:
## Shortcomings & Limitations
While `sohps` is a powerful tool, users should be aware of its technical boundaries:
- **Static vs. Runtime**: `sohps` performs advanced static analysis of the ELF structure and filesystem permissions. It does not account for libraries loaded dynamically at runtime via `dlopen()`.
- **User-Space Perspective**: Permission checks are performed as the user running the tool. Findings may differ when run as a low-privileged user vs. root.
- **Kernel-Linker Variance**: While `sohps` mimics standard `glibc` behavior, custom or highly specialized linkers (like those in embedded systems or `musl`) may have subtle behavioral differences.
- **Environment Variables**: Outside of simulated flags like `--ld-path`, `sohps` does not automatically account for every possible environment variable that could influence `ld.so`.
## Installation & Building
`sohps` is written in Go and requires version 1.21 or later.
### Local Build
go build -o sohps ./cmd/sohps/main.go
### Cross-Platform Compilation
**Build for x86_64 Linux:**
GOOS=linux GOARCH=amd64 go build -o sohps_amd64 ./cmd/sohps/main.go
**Build for AArch64 (ARM64) Linux:**
GOOS=linux GOARCH=arm64 go build -o sohps_arm64 ./cmd/sohps/main.go
## Testing & Verification
### Running Unit Tests
The project includes a comprehensive suite of unit tests for all internal packages:
go test ./internal/... -v
### The `testenv` Sandbox
The `testenv/` directory contains a specialized research environment that generates intentionally vulnerable binaries. This allows researchers to verify the tool's detection logic against real-world scenarios.
1. **Build the Sandbox**:
cd testenv
make all
2. **Scan the Sandbox**:
./sohps --root /tmp/sohps_test testenv/bin
This will enumerate all 6 primary vulnerability classes, including **System Preload**, providing a clear benchmark for the tool's capabilities.
## Usage
# Scan a single binary
./sohps /usr/bin/clang-query
# Scan a directory recursively
./sohps /usr/local/bin
# Specify a custom system root (e.g. for firmware or rootfs analysis)
./sohps --root /mnt/rootfs /mnt/rootfs/bin
# Simulate an attacker-controlled LD_LIBRARY_PATH
./sohps --ld-path /tmp/evil /usr/bin/sudo
# Verbose scan (show safe targets) with no color for logging
./sohps -v -nc / > scan_report.txt
## Example
$ ./sohps testenv/bin
[*] Scanning testenv/bin...
[*] Found 14 ELF binaries. Starting analysis...
[*] testenv/bin/test_implicit_cwd
[!] Implicit CWD
Vulnerable Path : Empty Path (Implicit CWD)
Resolved Dir : Runtime Current Working Directory
Action : CWD HIJACK: Execute binary from an attacker-controlled writable directory containing a malicious payload.
Libraries (4) : libcustom.so, libcustom.so, libc.so.6, libc.so.6
[*] testenv/bin/test_colon_split
[!] Writable Path
Vulnerable Path : /tmp/sohps_test/one
Resolved Dir : /tmp/sohps_test/one/tls/aarch64/aarch64
Action : RECREATE: Writable parent (/tmp/sohps_test). Recreate full path and drop payload at: /tmp/sohps_test/one/tls/aarch64/aarch64/libcustom.so
Libraries (1) : libcustom.so
[!] Writable Path
Vulnerable Path : /tmp/sohps_test/two
Resolved Dir : /tmp/sohps_test/two/tls/aarch64/aarch64
Action : RECREATE: Writable parent (/tmp/sohps_test). Recreate full path and drop payload at: /tmp/sohps_test/two/tls/aarch64/aarch64/libcustom.so
Libraries (1) : libcustom.so
[!] Writable Path
Vulnerable Path : /tmp/sohps_test/one
Resolved Dir : /tmp/sohps_test/one/tls/aarch64/aarch64
Action : RECREATE: Writable parent (/tmp/sohps_test). Recreate full path and drop payload at: /tmp/sohps_test/one/tls/aarch64/aarch64/libc.so.6
Libraries (1) : libc.so.6
[!] Writable Path
Vulnerable Path : /tmp/sohps_test/two
Resolved Dir : /tmp/sohps_test/two/tls/aarch64/aarch64
Action : RECREATE: Writable parent (/tmp/sohps_test). Recreate full path and drop payload at: /tmp/sohps_test/two/tls/aarch64/aarch64/libc.so.6
Libraries (1) : libc.so.6
[*] testenv/bin/test_nodeflib
[!] Writable Path
Vulnerable Path : /tmp/sohps_test/nodeflib
Resolved Dir : /tmp/sohps_test/nodeflib/tls/aarch64/aarch64
Action : RECREATE: Writable parent (/tmp/sohps_test). Recreate full path and drop payload at: /tmp/sohps_test/nodeflib/tls/aarch64/aarch64/libcustom.so
Libraries (1) : libcustom.so
[!] Writable Path
Vulnerable Path : /tmp/sohps_test/nodeflib
Resolved Dir : /tmp/sohps_test/nodeflib/tls/aarch64/aarch64
Action : RECREATE: Writable parent (/tmp/sohps_test). Recreate full path and drop payload at: /tmp/sohps_test/nodeflib/tls/aarch64/aarch64/libc.so.6
Libraries (1) : libc.so.6
[*] testenv/bin/test_needed_abs
[!] Absolute Path
Vulnerable Path : Hardcoded Absolute Path
Resolved Dir : /tmp/sohps_test
Action : OVERWRITE: Delete existing library and replace with payload: rm /tmp/sohps_test/libcustom.so && mv payload.so /tmp/sohps_test/libcustom.so
Libraries (1) : /tmp/sohps_test/libcustom.so
[*] testenv/bin/test_missing_writable
[!] Writable Path
Vulnerable Path : /tmp/sohps_test/missing
Resolved Dir : /tmp/sohps_test/missing/tls/aarch64/aarch64
Action : RECREATE: Writable parent (/tmp/sohps_test/missing). Recreate full path and drop payload at: /tmp/sohps_test/missing/tls/aarch64/aarch64/libcustom.so
Libraries (1) : libcustom.so
[!] Writable Path
Vulnerable Path : /tmp/sohps_test/missing
Resolved Dir : /tmp/sohps_test/missing/tls/aarch64/aarch64
Action : RECREATE: Writable parent (/tmp/sohps_test/missing). Recreate full path and drop payload at: /tmp/sohps_test/missing/tls/aarch64/aarch64/libc.so.6
Libraries (1) : libc.so.6
[*] testenv/bin/test_relative
[!] Relative Path
Vulnerable Path : ./lib
Resolved Dir : /home/foo/dev/sohps/lib/tls/aarch64/aarch64
Action : RECREATE: Writable parent (/home/foo/dev/sohps). Recreate full path and drop payload at: /home/foo/dev/sohps/lib/tls/aarch64/aarch64/libcustom.so
Libraries (1) : libcustom.so
[!] Relative Path
Vulnerable Path : ./lib
Resolved Dir : /home/foo/dev/sohps/lib/tls/aarch64/aarch64
Action : RECREATE: Writable parent (/home/foo/dev/sohps). Recreate full path and drop payload at: /home/foo/dev/sohps/lib/tls/aarch64/aarch64/libc.so.6
Libraries (1) : libc.so.6
[*] testenv/bin/test_origin
[!] $ORIGIN Hijack
Vulnerable Path : $ORIGIN/../lib
Resolved Dir : /home/foo/dev/sohps/testenv/lib/tls/aarch64/aarch64
Action : RECREATE: Writable parent (/home/foo/dev/sohps/testenv). Recreate full path and drop payload at: /home/foo/dev/sohps/testenv/lib/tls/aarch64/aarch64/libcustom.so
Libraries (1) : libcustom.so
[!] $ORIGIN Hijack
Vulnerable Path : $ORIGIN/../lib
Resolved Dir : /home/foo/dev/sohps/testenv/lib/tls/aarch64/aarch64
Action : RECREATE: Writable parent (/home/foo/dev/sohps/testenv). Recreate full path and drop payload at: /home/foo/dev/sohps/testenv/lib/tls/aarch64/aarch64/libc.so.6
Libraries (1) : libc.so.6
[*] testenv/bin/test_rpath
[!] Writable Path
Vulnerable Path : /tmp/sohps_test/rpath
Resolved Dir : /tmp/sohps_test/rpath/tls/aarch64/aarch64
Action : RECREATE: Writable parent (/tmp/sohps_test). Recreate full path and drop payload at: /tmp/sohps_test/rpath/tls/aarch64/aarch64/libcustom.so
Libraries (1) : libcustom.so
[!] Writable Path
Vulnerable Path : /tmp/sohps_test/rpath
Resolved Dir : /tmp/sohps_test/rpath/tls/aarch64/aarch64
Action : RECREATE: Writable parent (/tmp/sohps_test). Recreate full path and drop payload at: /tmp/sohps_test/rpath/tls/aarch64/aarch64/libc.so.6
Libraries (1) : libc.so.6
[*] testenv/bin/test_appimage.AppImage
[!] Environment Poisoning
Vulnerable Path : Internal AppRun:1
Resolved Dir : Runtime Environment
Action : CWD HIJACK: Script poisons LD_LIBRARY_PATH when empty. Ensure it is unset, drop malicious library in CWD, and execute.
Libraries (2) : ld-linux-aarch64.so.1 (Proxy Required)
libc.so.6
[*] testenv/bin/test_trailing_colon
[!] Writable Path
Vulnerable Path : /tmp
Resolved Dir : /tmp/tls/aarch64/aarch64
Action : RECREATE: Writable parent (/tmp). Recreate full path and drop payload at: /tmp/tls/aarch64/aarch64/libc.so.6
Libraries (1) : libc.so.6
[!] Implicit CWD
Vulnerable Path : Empty Path (Implicit CWD)
Resolved Dir : Runtime Current Working Directory
Action : CWD HIJACK: Execute binary from an attacker-controlled writable directory containing a malicious payload.
Libraries (1) : libc.so.6
[*] testenv/bin/test_writable_file
[!] Writable Path
Vulnerable Path : /tmp/sohps_writable_file
Resolved Dir : /tmp/sohps_writable_file
Action : RECREATE: Rename writable parent (/tmp) and recreate path to drop payload: mv /tmp/sohps_writable_file && mkdir -p /tmp/sohps_writable_file
Libraries (1) : libcustom.so
[!] Writable Path
Vulnerable Path : /tmp/sohps_writable_file
Resolved Dir : /tmp/sohps_writable_file/tls/aarch64/aarch64
Action : RECREATE: Writable parent (/tmp). Recreate full path and drop payload at: /tmp/sohps_writable_file/tls/aarch64/aarch64/libc.so.6
Libraries (1) : libc.so.6
[*] testenv/bin/test_writable_path
[!] Writable Path
Vulnerable Path : /tmp/sohps_test
Resolved Dir : /tmp/sohps_test/tls/aarch64/aarch64
Action : RECREATE: Writable parent (/tmp/sohps_test). Recreate full path and drop payload at: /tmp/sohps_test/tls/aarch64/aarch64/libc.so.6
Libraries (1) : libc.so.6
[!] Writable Path
Vulnerable Path : /tmp/sohps_test
Resolved Dir : /tmp/sohps_test
Action : OVERWRITE: Delete existing library and replace with payload: rm /tmp/sohps_test/libcustom.so && mv payload.so /tmp/sohps_test/libcustom.so
Libraries (1) : libcustom.so
[*] testenv/bin/test_runpath
[!] Writable Path
Vulnerable Path : /tmp/sohps_test/runpath
Resolved Dir : /tmp/sohps_test/runpath/tls/aarch64/aarch64
Action : RECREATE: Writable parent (/tmp/sohps_test). Recreate full path and drop payload at: /tmp/sohps_test/runpath/tls/aarch64/aarch64/libcustom.so
Libraries (1) : libcustom.so
[!] Writable Path
Vulnerable Path : /tmp/sohps_test/runpath
Resolved Dir : /tmp/sohps_test/runpath/tls/aarch64/aarch64
Action : RECREATE: Writable parent (/tmp/sohps_test). Recreate full path and drop payload at: /tmp/sohps_test/runpath/tls/aarch64/aarch64/libc.so.6
Libraries (1) : libc.so.6
[*] Progress: [14/14] 100.0%
[*] Scan complete.
标签:EVTX分析