evilsocket / opensnitch

OpenSnitch is a GNU/Linux interactive application firewall inspired by Little Snitch.
GNU General Public License v3.0
10.74k stars 498 forks source link

Application path manipulation #12

Closed jvoisin closed 7 years ago

jvoisin commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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

anonym commented 7 years ago

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 commented 7 years ago

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

jvoisin commented 7 years ago

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

ckuethe commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago
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 commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

"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 commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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

Yes I do :)

anonym commented 7 years ago

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

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 commented 7 years ago

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

anonym commented 7 years ago

Simone Margaritelli:

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

While this is an improvement, I think there are some remaining problems, some fixable, some not. A fixable issue is that you also have to intercept sys_execveat calls since they too can modify argv. But an unfixable, fundamental limitation of this approach is that processes started before ProcMon (and, hence, opensnitch) can still spoof their command-lines and get away with it.

So, for a safe solution I believe we need a kernel-level fix. :/

jvoisin commented 7 years ago

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

evilsocket commented 7 years ago

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

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

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 commented 7 years ago
  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 commented 7 years ago

Nooooo IRC no please XD

jvoisin commented 7 years ago

Then whatever fits :D

evilsocket commented 7 years ago

@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 commented 7 years ago

First.last@gmail

evilsocket commented 7 years ago

@ckuethe no such info on your profile man :)

ckuethe commented 7 years ago

there is now :)

evilsocket commented 7 years ago

sent ;)

anonym commented 7 years ago

Simone Margaritelli:

@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.

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.

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.

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.

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 "").

  1. 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?

Personally I find issue/ticket/bug trackers the ideal place for development discussion. :)

evilsocket commented 7 years ago

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 commented 7 years ago

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

evilsocket commented 7 years ago

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