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

Application path manipulation #12

Closed
jvoisin opened this issue Apr 20, 2017 · 35 comments
Closed

Application path manipulation #12

jvoisin opened this issue Apr 20, 2017 · 35 comments

Comments

@jvoisin
Copy link

jvoisin commented Apr 20, 2017

Currently, opensnitch is using /proc/self/cmdline and /proc/self/comm, but they can easily be manipulated by a malicious application, and thus shouldn't be trusted.

@ckuethe
Copy link
Contributor

ckuethe commented Apr 20, 2017

That's my doing, so that I can get the name of the script being run by an interpreter. If you know of a better way to get that information I'm happy to change it.

@jvoisin
Copy link
Author

jvoisin commented Apr 20, 2017

I don't know either, sorry :/

Maybe a ghetto-mitigation would be to check that /proc/self/cmdline is starting with file /proc/self/exe?

@anonym
Copy link

anonym commented Apr 20, 2017

ckuethe wrote:

That's my doing, so that I can get the name of the script being run by an interpreter. If you know of a better way to get that information I'm happy to change it.

When I was posed with the same issue while working on onion-grater (note that this is not the upstream repo, which seems to not be publicly accessible at the moment, whatever) I could only find that AppArmor confined scripts have a safe way to make a PID to script path mapping. Of course, using that approach limits you to AppArmor confined scripts only, which was fine for my case, but clearly isn't for your. Any way, here's the code: https://github.com/Whonix/onion-grater/blob/master/usr/lib/onion-grater#L169

If you find a general purpose solution, I'm all ears! :)

jvoisin wrote:

Maybe a ghetto-mitigation would be to check that /proc/self/cmdline is starting with file /proc/self/exe?

I don't get how that changes anything. The application then just has to add that part in the beginning, followed by the application it wants to spoof (the "script"), right?

@jvoisin
Copy link
Author

jvoisin commented Apr 20, 2017

An application could spoof its script, but not its interepreter name; hence the term "ghetto-mitigation" :D

@anonym
Copy link

anonym commented Apr 20, 2017

Ah, now I got what you meant. But it still sucks! :) Using that trick, when you add an exception to opensnitch for a script s interpreted by an interpreter i, then all malicious scripts interpreted by i can spoof as script s and get the same exception. Hardly an improvement, imho.

@anonym
Copy link

anonym commented Apr 20, 2017

Also, /proc/self/exe is in the malicious script's control since there is such a thing as exec(). :)

@jvoisin
Copy link
Author

jvoisin commented Apr 20, 2017

exec() will destroy the process context completely (am I wrong?), what could an attacker do with this?

@ckuethe
Copy link
Contributor

ckuethe commented Apr 20, 2017

I'm not sure I'd ever whitelist an application entirely, especially not an interpreter.

exe may not even be found in comm or cmdline. Clearly it's hard to get a trustworthy snapshot of arguments, process name, etc. :(

$ ls -l /proc/1769/exe 
lrwxrwxrwx 1 ckuethe ckuethe 0 Apr 20 11:09 /proc/1769/exe -> /usr/bin/python2.7

Which is expected given the first line of the script:

#!/usr/bin/env python2.7

However ps says:

ckuethe   1769  0.4  0.4 733044 70888 ?        Sl   11:07   0:11 python2 /path/to/whateverscript

or

 1769 ?        00:00:10 whateverscript

@anonym
Copy link

anonym commented Apr 20, 2017

jvoisin wrote:

exec() will destroy the process context completely (am I wrong?), what could an attacker do with this?

My exec() remark was just a general reminder that /po,roc/self/exe can change when calling exec() which the attacker can do. It's not necessary to workaround your proposed mitigation.

Let's just make it clear that your mitigation won't work: so reading /proc/self/cmdline will read the data from the memory address of argv (speaking C). Try putting the following in your main() function and then check what /proc/self/cmdline becomes:

memcpy(argv[0], "/usr/bin/python3\0/path/to/trusted\0", 41);

I.e. you can set it however you like. Of course, to not overwrite important memory, call the program with atkeast 41 characters as the first argument. :)

So let's say we have an opensnitch exception for some path /path/to/trusted A local attacker can then run a Python script that writes /usr/bin/python\0/path/to/trusted\0 to os.ARGV (actually that doesn't work, but you can achieve the same with a simple C module that can be imported). Then the current opensnitch code will think that the script /path/to/trusted is running, and set that as the path in the Application class and hence the attacker's code will run with the exception made for /path/to/trusted. Furthermore /proc/self/exe will be /usr/bin/python (the attacker is running a Python script!), which is a prefix in the forged /proc/self/cmdline, so your mitigation is not effective. Ok?

@ckuethe
Copy link
Contributor

ckuethe commented Apr 20, 2017

ckuethe:/proc/25147$ cat comm 
/sbin/init
ckuethe:/proc/25147$ cat cmdline 
/sbin/initckuethe:/proc/25147$ ps -p 25147
  PID TTY          TIME CMD
25147 pts/4    00:00:08 /sbin/init
ckuethe:/proc/25147$ ps wwax | grep 25147
25147 pts/4    Sl+    0:08 /sbin/init
25917 pts/6    S+     0:00 grep --color=auto 25147

Which is actually /usr/bin/python2 /usr/local/bin/ptpython. the python setproctitle module makes such manipulation dead easy and we don't have a good countermeasure for it.

Non-malicious programs do this too. The MySQL client will censor its own argv in an attempt to reduce exposure of the password if you give it on the command line.

@anonym
Copy link

anonym commented Apr 20, 2017

ckuethe wrote:

I'm not sure I'd ever whitelist an application entirely [...]

I think full application granularity is the best we can except from average users. If that isn't your intended audience: fair enough! :)

[...] especially not an interpreter.

Of course! That's why you have this pid-to-script-path workaround in the Applications class in the first place. It's absolutely needed, and...

exe may not even be found in comm or cmdline. Clearly it's hard to get a trustworthy snapshot of arguments, process name, etc. :(

... it's unfortunate that the Linux kernel doesn't provide anything to help us. :/ It'd be great if Linux recorded argv each time ecec() is called, before the code has a chance to manipulate it (imagine /proc/self/cmdline.safe). That would be such a "trustworthy snapshot of arguments" you are talking about. In fact, this would probably be possible to implement in a kernel module right now. And eventually proposing it to be added into mainline Linux as an option since some people might want to keep it the old way, like MySQL users that like to pass critically sensitive information on the command line... *eyeroll*

Hm. This actually sounds like a great idea, or am I missing something obvious? If not, I believe it would offer us the perfect solution for opensnitch, onion-grater and other applications that use the application path of a running process as the basis for identifying what conceptual application is being executed.

@ckuethe
Copy link
Contributor

ckuethe commented Apr 20, 2017

I was just thinking about tossing together a quick kernel module to snapshot that information at exec() time.

Or maybe abuse apparmor by creating a profile to audit everything's command line arguments and not interfere with any other operation (unless overridden by a more specific policy)

@jvoisin
Copy link
Author

jvoisin commented Apr 21, 2017

A kernel module sounds like a great idea (and, surprisingly, the easiest way to go). It would be amazing to get it merged upstead.

Until this, I would recommend to stick with /proc/self/exe, that can't be modified (can it?).

@ckuethe
Copy link
Contributor

ckuethe commented Apr 21, 2017

I can look at making sure that exe, comm, and cmdline are all exposed to the UI, maybe with a tooltip to warn the user that a process can manipulate this information.

@jvoisin
Copy link
Author

jvoisin commented Apr 21, 2017

"Here are the process information, they might be wrong, it's up to you to trust them" doesn't sound like a good UX design to me :D

@anonym
Copy link

anonym commented Apr 21, 2017

ckuethe wrote:

I was just thinking about tossing together a quick kernel module to snapshot that information at exec() time.

Same here, it looks like the kernel hacking project I've been looking for for some time (i.e. something I feel motivated about). :)

Or maybe abuse apparmor by creating a profile to audit everything's command line arguments and not interfere with any other operation (unless overridden by a more specific policy)

When I was faced with this problem, that's what I did, i.e. I created "empty" profiles that

I can look at making sure that exe, comm, and cmdline are all exposed to the UI, maybe with a tooltip to warn the user that a process can manipulate this information.

I don't think this will change anything from the user's PoV. They still won't get any help to make the right decision, because the information they get cannot be trusted (except exe).

@anonym
Copy link

anonym commented Apr 21, 2017

jvoisin wrote:

A kernel module sounds like a great idea (and, surprisingly, the easiest way to go). It would be amazing to get it merged upstead.

I'll start looking into it now! This will be useful for onion-grater too. :)

Until this, I would recommend to stick with /proc/self/exe

You mean, to remove the workaround (based on comm and cmdline) for interpreted applications? If so I think I agree, even if that cripples opensnitch quite a bit. :/

that can't be modified (can it?).

I believe it is. I'm cloning Linux' Git right now, will have a look once it's done.

@jvoisin
Copy link
Author

jvoisin commented Apr 21, 2017

You mean, to remove the workaround (based on comm and cmdline) for interpreted applications?

Yes I do :)

@anonym
Copy link

anonym commented Apr 21, 2017

I had a look at the kernel module idea for a few hours today:

  • First, it seems entries to /proc/pid/ cannot be added via a module so it requires building a new kernel, but I definitely could be wrong.

  • Second, I played around with kprobes and it was easy to hook into a particular syscall (sys_execve), bit less easy to find the information we want. Well, it's easy to to find the path to the binary, but not the command line. Refactoring the crazy code used for /proc/pid/cmdline should make it possible.

Any way, it definitely seems like more work than I initially thought, so it's not clear if I'll have the time to work on this. :/

@evilsocket
Copy link
Owner

Guys ... IDEA! Maybe we can use ftrace kernel feature like they do in order to intercept calls to exec ? :)

@anonym
Copy link

anonym commented May 3, 2017 via email

@jvoisin
Copy link
Author

jvoisin commented May 3, 2017

I think that it's an acceptable trade-off.

@evilsocket
Copy link
Owner

evilsocket commented May 3, 2017

@fred-a-kemp, @jvoisin and @ckuethe IMHO even before that we'll need to:

Split the project into opensnitchd, opensnitch-ui and opensnitch-ruleman:

  • opensnitchd will be a C++ daemon, running as root with the main logic. It'll fix this.
  • opensnitch-ui python (?) UI running as normal user, getting the daemon messages. Will fix this
  • opensnitch-ruleman python (?) UI for rule editing.

Questions:

  1. What is the best IPC method in this case? I mean, if the daemon just creates a unix socket readable and writable by any user, any third party malicious software could access it and simply ACCEPT every packet ... dbus? No idea how it works honestly.

  2. What's the best way in your opinion to keep all the involved/interested developers in sync and let them communicate without using github issues? Mailing list? Slack? Pigeons?

@jvoisin
Copy link
Author

jvoisin commented May 3, 2017

  1. Check what Tor is doing, they're using a socket too iirc.
  2. I'm using irc myself, but I'm comfortable with pigeons too. Slack tends to eat all my RAM while needing a different tab per "Slack instance", please don't use it </3 For radare2, we're using irc, with a telegram bot for people who prefer something more eye-candy than irssi/weechat ;)

@evilsocket
Copy link
Owner

Nooooo IRC no please XD

@jvoisin
Copy link
Author

jvoisin commented May 3, 2017

Then whatever fits :D

@evilsocket
Copy link
Owner

@fred-a-kemp @ckuethe @jvoisin guys I just created a private Telegram channel for devs, where can I send you guys the invitation link?

@ckuethe
Copy link
Contributor

ckuethe commented May 3, 2017

First.last@gmail

@evilsocket
Copy link
Owner

@ckuethe no such info on your profile man :)

@ckuethe
Copy link
Contributor

ckuethe commented May 3, 2017

there is now :)

@evilsocket
Copy link
Owner

sent ;)

@anonym
Copy link

anonym commented May 4, 2017 via email

@evilsocket
Copy link
Owner

Sorry for the hate, but why C++? Sure, if you'll restrict yourself to some "safe" subset of C++, with a stack-first memory allocation approach, employing modern features like smart pointers to get memory safety if dynamic memory allocation is needed, etc. then I guess it is ok. That said, I do not really see what benefit we'd get from moving away from Python.

LOL What's wrong with you guys and C++? :D JK, dunno since handling the connections is not very performance centric maybe you're right, we can keep it in python.

BTW, I assume you intend to put the ProcMon functionality into the opensnitchd daemon. Since other projects might be interested in only the ProcMon bits you may want to split it into another daemon (perhaps openinformantd? :P), dedicated to keeping track of process information.

Why split it into two daemons? Maybe create a proper python library/module for reusability, but I'd rather have 1 daemon and 1 UI process.

Make the socket only accessible by members of the opensnitch group. If you go the DBus way you can define security policies with the same restrictions (see dbus-daemon(1), search for "").

Will take a look, tnx.

@adisbladis
Copy link
Contributor

@evilsocket Would you mind inviting me too? :) My email address is in my git commits Author field

@evilsocket
Copy link
Owner

@adisbladis sure! it's the one bound to your gpg key id I guess, right?

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

No branches or pull requests

5 participants