Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

prevent escaping lshell using sudo_noexec #122

Closed
lberra opened this issue Feb 4, 2016 · 18 comments
Closed

prevent escaping lshell using sudo_noexec #122

lberra opened this issue Feb 4, 2016 · 18 comments
Labels

Comments

@lberra
Copy link
Contributor

lberra commented Feb 4, 2016

at the moment it is possible to escape lshell if an allowed command can execute an arbitrary non allowed one:
example:
find ~ -name .lhistory -exec bash \;
(yes default config disallows ";" but it can be enabled)
i prevented this by creating an alias:
aliases : {'find':'LD_PRELOAD=/usr/lib/sudo/sudo_noexec.so find'}
but it would be cool having an option for this

path_noxec: '/path/to/noexec.so'
allowed_noexec: ['find', 'vi' ]

which would preload the noexec library to the restricted program

@ghantoos
Copy link
Owner

ghantoos commented Feb 4, 2016

👍 Amazing idea!! Thank you for sharing this! I've been wanting to work on adding noexec to prevent such commands to use the shell escape, but never thought of it this way.

I will work on it to integrate it. I'll keep you posted.

@ghantoos
Copy link
Owner

ghantoos commented Feb 6, 2016

I am going to use the LD_PRELOAD for all the allowed commands, regardless of the fact that they allow shell escapes (e.g. vim, find) or not. I have a first patch that seems functional. I will commit it soon, it would be great if you could test it out.

@ghantoos
Copy link
Owner

ghantoos commented Feb 6, 2016

I have tested the patch on Debian and CentOS. It would be great if you could test it too.

@lberra
Copy link
Contributor Author

lberra commented Feb 6, 2016

i am sorry but this is easily bypassed:
echo a && find . -name .lhistory -exec bash ;
would become
LD_PRELOAD=/usr/libexec/sudo_noexec.so echo a && find . -name .lhistory -exec bash ;
which would set the noexec to echo, but not on find
setting LD_PRELOAD before subprocess.call wont work, since we have shell=True
i tried a different approach, autocreating aliases
also i made the path to the shlib configurable if not autodetected
see #123

@ghantoos
Copy link
Owner

ghantoos commented Feb 6, 2016

Nice again @lberra ! I will take a look at your PR. Ideally, I would like to avoid adding a new variable. Some administrator might not know which command allows shell-escapes, and miss them.

I'm looking into forcing the LD_PRELOAD as a global environment variable. This would make it available for all the commands on a command line. More to follow soon. :)

@lberra
Copy link
Contributor Author

lberra commented Feb 6, 2016

if you want to set it global do something like

if os.path.isfile(noexec):
return 'export LD_PRELOAD=%s;' % noexec

remember that setting it globally will break shell scripts

we could invert the settings, making allowed run commands through noexec and allowed_exec bypass the restriction putting a big fat warning

@ghantoos
Copy link
Owner

ghantoos commented Feb 6, 2016

I have tested the following, and it seems to work:

    retcode = subprocess.call("%s" % cmd,
                              env={'LD_PRELOAD':ld_preload},
                              shell=True)

I'll commit it in a minute, if you still have some time to test it out. :)

ghantoos pushed a commit that referenced this issue Feb 6, 2016
This commit adds the possibility to prevent shell escapes by using
the sudo_noexec.so shared-object.

If sudo(8) is installed and sudo_noexec.so is available, it will be
loaded before running every command, preventing it from running
further commands itself.
@ghantoos
Copy link
Owner

ghantoos commented Feb 6, 2016

@lberra I have forced the git push, to overwrite master, you might need to re-clone. Sorry for that.

@ghantoos ghantoos reopened this Feb 6, 2016
@ghantoos ghantoos reopened this Feb 6, 2016
@ghantoos
Copy link
Owner

ghantoos commented Feb 6, 2016

I'm not totally awake, lot's of --force. :)

@ghantoos
Copy link
Owner

ghantoos commented Feb 6, 2016

we could invert the settings, making allowed run commands through noexec and allowed_exec
bypass the restriction putting a big fat warning

I wonder if it should be allowed at all. Wouldn't that just reopen the door for escapes? In which scenario do you think it would be helpful?

@lberra
Copy link
Contributor Author

lberra commented Feb 6, 2016

setting LD_PRELOAD breaks shell scripts that execute external commands
i could find useful creating some custom shell script and allowing the user to run it
(in this case i could just reset LD_PRELOAD inside the script)
it may also break other things:
man comes to mind

@ghantoos
Copy link
Owner

ghantoos commented Feb 6, 2016

On Feb 6, 2016 14:43, "lberra" notifications@github.com wrote:

setting LD_PRELOAD breaks shell scripts that execute external commands
i could find useful creating some custom shell script and allowing the
user to run it
(in this case i could just reset LD_PRELOAD inside the script)
it may also break other things:
man comes to mind

Very true. I went too fast on a solution. I will revert my changes, and
rethink the solution. As I see it, it will be a mix of your suggestion and
mine: two types of allowed commands (exec and no exec), no aliases but env
variable setting the LD_PRELOAD. With the warning you suggested. Also, I
might reuse your list of sudo_noexec.so, it's quite generic.

@ghantoos
Copy link
Owner

ghantoos commented Feb 8, 2016

Here is the plan. I prefer having the default command list to use "allowed" (instead of "allowed_noexec" in your PR). This will prevent from breaking the configuration with previous versions of lshell.

Instead, I will be adding another variable to explicitly allow commands to use exec (e.g. shell scripts). Otherwise, it seems that you alias solution is the best way to achieve want you have described.

To sum up, I will be integrating your PR, and working on top of it to introduce aliases for allowed commands, and a new variable called "allowed_shell_escape" for the exception list.

@ghantoos
Copy link
Owner

Thank you so much for your help on this @lberra !! This is very much appreciated!

@lmarkov
Copy link

lmarkov commented Mar 15, 2016

Hello,
I updated may configuration to new version 0.9.18 and I have problems with this new check. I have many custom scripts that can't be executed because of this restrictions. Can you suggest me how to bypass this check or allow access for the scripts without to put every one in the list of the configuration file?

@ghantoos
Copy link
Owner

@lmarkov there is currently no way to bypass the script without adding them to the allowed_shell_escape variable.

There is actually a tiny bug preventing you from bypassing the standard noexec path. I will correct this now. If you clone the latest code, you will be able to set another path_noexec, for example on my Debian: path_noexec : '/lib/x86_64-linux-gnu/libc.so.6'.

I will add the possibility to disable this, with a big security warning.

@lmarkov
Copy link

lmarkov commented Mar 16, 2016

I commented all lines in def set_noexec(self): in file checkconfig.py. I think that this is solution for so far.

ghantoos pushed a commit that referenced this issue Mar 16, 2016
- this feature has been initialy requested in #122
- corrects the typo in --path_noexec flag
@ghantoos
Copy link
Owner

@lmarkov I have just comited the possibility to disable the LD_PRELOAD by setting the value of path_noexec to ''. See d9e7eea and #133.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants