Skip to content

Commit a41e8cd

Browse files
committed
Merge branch 'master' of github.com:HackTricks-wiki/hacktricks
2 parents 0cab913 + ab4f84a commit a41e8cd

4 files changed

Lines changed: 269 additions & 35 deletions

File tree

src/linux-hardening/linux-environment-variables.md

Lines changed: 138 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ cat /proc/$$/environ
4141
cat /proc/`python -c "import os; print(os.getppid())"`/environ
4242
```
4343

44+
The contents of `/proc/*/environ` are **NUL-separated**, so these variants are usually easier to read:
45+
46+
```bash
47+
tr '\0' '\n' </proc/$$/environ | sort -u
48+
tr '\0' '\n' </proc/<PID>/environ | sort -u
49+
```
50+
51+
If you are looking for **credentials** or **interesting service configuration** inside inherited environments, also check [Linux Post Exploitation](linux-post-exploitation/README.md).
52+
4453
## Common variables
4554

4655
From: [https://geek-university.com/linux/common-environment-variables/](https://geek-university.com/linux/common-environment-variables/)
@@ -65,25 +74,27 @@ From: [https://geek-university.com/linux/common-environment-variables/](https://
6574

6675
## Interesting variables for hacking
6776

77+
Not every variable is equally useful. From an offensive perspective, prioritize variables that change **search paths**, **startup files**, **dynamic linker behavior**, or **audit/logging**.
78+
6879
### **HISTFILESIZE**
6980

70-
Change the **value of this variable to 0**, so when you **end your session** the **history file** (\~/.bash_history) **will be deleted**.
81+
Change the **value of this variable to 0**, so when you **end your session** the **history file** (\~/.bash_history) will be **truncated to 0 lines**.
7182

7283
```bash
7384
export HISTFILESIZE=0
7485
```
7586

7687
### **HISTSIZE**
7788

78-
Change the **value of this variable to 0**, so when you **end your session** any command will be added to the **history file** (\~/.bash_history).
89+
Change the **value of this variable to 0**, so commands are **not kept in the in-memory history** and won't be written back to the **history file** (\~/.bash_history).
7990

8091
```bash
8192
export HISTSIZE=0
82-
8393
```
94+
8495
### **HISTCONTROL**
8596

86-
If the **value of this variable is set to ignorespace or ignoreboth** any command prepend it with an extra space will not be saved in the history.
97+
If the **value of this variable is set to `ignorespace` or `ignoreboth`**, any command prepended with an extra space will not be saved in the history.
8798

8899
```bash
89100
export HISTCONTROL=ignorespace
@@ -94,6 +105,15 @@ $ echo "to save or"
94105
$ echo "not to save"
95106
```
96107

108+
### **HISTFILE**
109+
110+
Point the **history file** to **`/dev/null`** or unset it completely. This is usually more reliable than only changing the history size.
111+
112+
```bash
113+
export HISTFILE=/dev/null
114+
unset HISTFILE
115+
```
116+
97117
### http_proxy & https_proxy
98118

99119
The processes will use the **proxy** declared here to connect to internet through **http or https**.
@@ -117,13 +137,121 @@ Both lowercase and uppercase variants may be used depending on the tool (`http_p
117137

118138
### SSL_CERT_FILE & SSL_CERT_DIR
119139

120-
The processes will trust the certificates indicated in **these env variables**.
140+
The processes will trust the certificates indicated in **these env variables**. This is useful to make tools such as **`curl`**, **`git`**, Python HTTP clients, or package managers trust a CA controlled by the attacker (for example, to make an interception proxy look legitimate).
121141

122142
```bash
123143
export SSL_CERT_FILE=/path/to/ca-bundle.pem
124144
export SSL_CERT_DIR=/path/to/ca-certificates
125145
```
126146

147+
### **PATH**
148+
149+
If a privileged wrapper/script executes commands **without absolute paths**, the **first attacker-controlled directory** in `PATH` wins. This is the primitive behind many **PATH hijacks** in `sudo`, cron jobs, shell wrappers, and custom SUID helpers. Look for `env_keep+=PATH`, weak `secure_path`, or wrappers that call `tar`, `service`, `cp`, `python`, etc. by name.
150+
151+
```bash
152+
mkdir -p /dev/shm/bin
153+
cat > /dev/shm/bin/tar <<'EOF'
154+
#!/bin/sh
155+
echo '[+] PATH hijack reached' >&2
156+
id
157+
EOF
158+
chmod +x /dev/shm/bin/tar
159+
PATH=/dev/shm/bin:$PATH vulnerable-wrapper
160+
```
161+
162+
For full privilege-escalation chains abusing `PATH`, check [Linux Privilege Escalation](privilege-escalation/README.md).
163+
164+
### **HOME & XDG_CONFIG_HOME**
165+
166+
`HOME` is not only a directory reference: many tools automatically load **dotfiles**, **plugins**, and **per-user configuration** from `$HOME` or `$XDG_CONFIG_HOME`. If a privileged workflow preserves these values, **config injection** may be easier than binary hijacking.
167+
168+
```bash
169+
export HOME=/dev/shm/fakehome
170+
export XDG_CONFIG_HOME=/dev/shm/fakehome/.config
171+
mkdir -p "$XDG_CONFIG_HOME"
172+
```
173+
174+
Interesting targets include `.gitconfig`, `.wgetrc`, `.curlrc`, `.inputrc`, `.pythonrc.py`, and tool-specific files such as `.terraformrc`.
175+
176+
### **LD_PRELOAD, LD_LIBRARY_PATH & LD_AUDIT**
177+
178+
These variables influence the **dynamic linker**:
179+
180+
- `LD_PRELOAD`: force extra shared objects to be loaded first.
181+
- `LD_LIBRARY_PATH`: prepend library search directories.
182+
- `LD_AUDIT`: load auditor libraries that observe library loading and symbol resolution.
183+
184+
They are extremely valuable for **hooking**, **instrumentation**, and **privilege escalation** if a privileged command preserves them. In **secure-execution** mode (`AT_SECURE`, e.g. setuid/setgid/capabilities), the loader strips or restricts many of these variables. However, parser bugs in that early loader stage are still high-impact because they run **before** the target program.
185+
186+
```bash
187+
env | grep -E '^LD_'
188+
ldso=$(ls /lib64/ld-linux-*.so.* /lib/*-linux-gnu/ld-linux-*.so.* 2>/dev/null | head -n1)
189+
"$ldso" --list-diagnostics /bin/true | head
190+
"$ldso" --list-tunables /bin/true | head
191+
```
192+
193+
### **GLIBC_TUNABLES**
194+
195+
`GLIBC_TUNABLES` changes early glibc behavior (for example, allocator tunables) and is very handy in exploit labs. It also matters from a security perspective because the **dynamic loader parses it very early**. The 2023 **Looney Tunables** bug was a good reminder that a single environment variable parsed in the loader can become a **local privilege-escalation primitive** against SUID programs.
196+
197+
```bash
198+
GLIBC_TUNABLES=glibc.malloc.tcache_count=0 ./binary
199+
```
200+
201+
### **BASH_ENV & ENV**
202+
203+
If **Bash** is started **non-interactively**, it checks `BASH_ENV` and sources that file before running the target script. When Bash is invoked as `sh`, or in POSIX-style interactive mode, `ENV` may also be consulted. This is a classic way to turn a shell wrapper into code execution if the environment is attacker-controlled.
204+
205+
```bash
206+
cat > /tmp/pre.sh <<'EOF'
207+
echo '[+] sourced before the target script'
208+
EOF
209+
BASH_ENV=/tmp/pre.sh bash -c 'echo target'
210+
```
211+
212+
Bash itself disables these startup files when the **real/effective IDs differ** unless `-p` is used, so the exact behavior depends on how the wrapper invokes the shell.
213+
214+
### **PYTHONPATH, PYTHONHOME, PYTHONSTARTUP & PYTHONINSPECT**
215+
216+
These variables change how Python starts:
217+
218+
- `PYTHONPATH`: prepend import search paths.
219+
- `PYTHONHOME`: relocate the standard library tree.
220+
- `PYTHONSTARTUP`: execute a file before the interactive prompt.
221+
- `PYTHONINSPECT=1`: drop into interactive mode after a script finishes.
222+
223+
They are useful against maintenance scripts, debuggers, shells, and wrappers that call Python with a controllable environment. `python -E` and `python -I` ignore all `PYTHON*` variables.
224+
225+
```bash
226+
mkdir -p /tmp/pylib
227+
printf 'print("owned from PYTHONPATH")\n' > /tmp/pylib/htmod.py
228+
PYTHONPATH=/tmp/pylib python3 -c 'import htmod'
229+
PYTHONPATH=/tmp/pylib python3 -I -c 'import htmod' # ignored in isolated mode
230+
```
231+
232+
### **PERL5OPT & PERL5LIB**
233+
234+
Perl has equally useful startup variables:
235+
236+
- `PERL5LIB`: prepend library directories.
237+
- `PERL5OPT`: inject switches as if they were on every `perl` command line.
238+
239+
This can force **automatic module loading** or change interpreter behavior before the target script does anything interesting. Perl ignores these variables in **taint / setuid / setgid** contexts, but they still matter a lot for normal root-run wrappers, CI jobs, installers, and custom sudoers rules.
240+
241+
```bash
242+
mkdir -p /tmp/perllib
243+
cat > /tmp/perllib/HT.pm <<'EOF'
244+
package HT;
245+
BEGIN { print "PERL5OPT_TRIGGERED\n" }
246+
1;
247+
EOF
248+
PERL5LIB=/tmp/perllib PERL5OPT=-MHT perl -e 'print "target\n"'
249+
```
250+
251+
The same idea appears in other runtimes (`RUBYOPT`, `NODE_OPTIONS`, etc.): whenever an interpreter is launched by a privileged wrapper, look for env vars that modify **module loading** or **startup behavior**.
252+
253+
From a post-exploitation perspective, also remember that inherited environments often contain **credentials**, **proxy settings**, **service tokens**, or **cloud keys**. Check [Linux Post Exploitation](linux-post-exploitation/README.md) for `/proc/<PID>/environ` and `systemd` `Environment=` hunting.
254+
127255
### PS1
128256

129257
Change how your prompt looks.
@@ -146,6 +274,11 @@ One background job, one stopped and last command didn't finish correctly:
146274

147275
![](<../images/image (715).png>)
148276

277+
## References
278+
279+
- [GNU Bash Manual - Bash Startup Files](https://www.gnu.org/software/bash/manual/html_node/Bash-Startup-Files.html)
280+
- [ld.so(8) - Linux manual page](https://man7.org/linux/man-pages/man8/ld.so.8.html)
281+
149282
{{#include ../banners/hacktricks-training.md}}
150283

151284

0 commit comments

Comments
 (0)