we37 发表于 2021-4-18 22:13

解析某网络教学平台登录时的明文加密方法并使用python实现代码复现

不知道标题说清楚了没(^_^)。
上学期考完试,因为成绩是一门一门的出来,经常都要去网络教学平台登录查看成绩出没出(那种不知道自己是否挂科的煎熬感),我嫌烦而且刚好学完爬虫,就想着看能不能写个脚本实现一键查成绩的功能,当时没有具体的学过前端代码,但因为有c的基础也算是能看出来一点,然后抓包解析,一顿瞎操作,明文具体怎么加密的没看懂,但是找到了加密完的密文和发送的url(嘿嘿),然后数据清洗,功能这不就实现了吗,然后,就没有然后了,功能都实现了,那还然后个屁。
但是最近我自己的网站因为是http明文传输,也不好加证书实现https,所以我就想,用户数据安全肯定得保证啊,得想办法搞一套加密方法回来,这样就又记起了我学校的这套当时没看懂的加密。
通过打断点,看代码解析完之后,我发现其实还蛮简单的。所以想将这个加密方法分享给大家。好了,废话说了这么多了(不是),直接上源码。
-----------------------------------------------------------------------------------------------
以下解析实属小白的我玩玩,有问题希望大神指出来(^_^)感激不尽。
本文适合有一点前端知识的同学阅读,大家加油学啊!!!!

https://static.52pojie.cn/static/image/hrline/4.gif
https://static.52pojie.cn/static/image/hrline/4.gif



form表单
<form id="loginForm" name="loginForm" action="/Logon.do?method=logon" method="post">

        <ul id="ul1" >

                <li class="box_bt"><img class="img-responsive" src="/css/images/user_icon.png"style="float:left;margin:8px 8px 0 0">用户登录</li>

                <li class="input-group input_li">

                          <span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span>

                          <input type="text" class="form-control" id="userAccount" name="userAccount" placeholder="请输入账号" value="123" autofocus>

                </li>

                <li class="input-group input_li">

                          <span class="input-group-addon" id="basic-addon1"><i class="glyphicon glyphicon-lock"></i></span>

                          <input type="password" class="form-control" id="userPassword" name="userPassword" placeholder="请输入密码" value="">

                </li>

                <li class="input_li">

                        <button type="button" class="btn btn-primary login_btn">登   录</button>

                </li>

        </ul>

        <input name="encoded" id="encoded" type="hidden" value=""/>

</form>



js代码

function login() {

        if($("#userAccount").val() == "") {

                $("#showMsg").text("请输入账号");

                $("#userAccount").focus();

                return false;

        }

        if($("#userPassword").val() == "") {

                $("#showMsg").text("请输入密码");

                $("#userPassword").focus();

                return false;

        }

       

               

                var strUrl = "/Logon.do?method=logon&flag=sess";

       



        $.ajax( {

                url:strUrl,

                type:"post",

                cache:false,

                dataType:"text",

                success:function(dataStr) {

                        if(dataStr=="no"){

                                return false;

                       }else{

                               var scode=dataStr.split("#");

                             var sxh=dataStr.split("#");

                             var code=document.getElementById("userAccount").value+"%%%"+document.getElementById("userPassword").value;

                               var encoded="";

                                for(var i=0;i<code.length;i++){

                                        if(i<20){

                                                encoded=encoded+code.substring(i,i+1)+scode.substring(0,parseInt(sxh.substring(i,i+1)));

                                          scode = scode.substring(parseInt(sxh.substring(i,i+1)),scode.length);

                                        }else{

                                          encoded=encoded+code.substring(i,code.length);

                                          i=code.length;

                                        }

                                }

                                document.getElementById("encoded").value=encoded;

                                if("logon"!="logonLdap"){

                                        document.getElementById("userPassword").value="";

                                }



                                document.getElementById("loginForm").submit();

                       }

                },

                error:function() {

                       alert("计算异常!");

                }

        });

}




form表单我过滤了一遍,将一些与本文无关的代码剔除。看着很简单,两个输入框,一个提交按钮,最下面还有个隐藏的输入框,不知道是干什么用的,不用纠结,后面肯定有用到,接着往下看。

js代码中,上面两个if判断都是做输入框非空处理的,不用关注,接着看有个strUrl,然后使用ajax异步提交了一个post请求,但是: 可以看到该请求体中没有data字段,也就是没有将我们的账号密码提交上去,说明提交还在后面,接着往下看,请求success之后,从服务器拿到了一个dataStr,然后做了一步判断,不用说,这里返回no的几率很小,所以不用管,接着看,到了下面,我们发现它将dataStr通过’#‘分开了,那么这里就有点疑问了,dataStr到底是个啥??不解决这个问题我们再往下看也没用。所以怎么办才能拿到dataStr呢?
   
       打断点

打断点可以说是一个基础而且十分有用的技能了,至少我写爬虫是经常需要打断点的。



通过打断点,我们可以看到dataStr很清晰的展现在我们面前,


        dataStr = "8321akd3k0013M7cQ0Dv1Y749315N3f2Sxy762W213#13122313321123323321"

        scode = "321akd3k0013M7cQ0Dv1Y749315N3f2Sxy762W213"

        sxh = "13122313321123323321"

        code = "123%%%123"    # code就是我们的账号+"%%%"+密码

       
看到这里,一些基本的变量已经知道了,强烈推荐大家自己试着解一下。

然后又定义了一个encoded,我们应该能猜到encoded应该是用来存放加密完之后的密文的。

接下来看for循环里的if体内,

        encoded=encoded+code.substring(i,i+1)+scode.substring(0,parseInt(sxh.substring(i,i+1)));
       

[*]substring ?? 没见过,没关系,百度一下,百度到结果是字符串截取,括号内是字符串下标,不包括后边的下标。
[*]parseInt ?? 没见过,没关系,百度一下,字符串转为数值类型。

-----------------------------------------------------------------------------------------
那么第一次for循环就清楚了:

code.substring(i, i + 1)   就是将code取第一个字符
scode.substring(0,parseInt(sxh.substring(i,i+1)))就是先取sxh的第一个字符,然后将他转成数值,再从scode中取到0-这个数字范围内的字符,在第一次循环中表现为scode.substring(0, 1) 也就是取scode的第一个字符。

接下来的这个语句:

        scode = scode.substring(parseInt(sxh.substring(i,i+1)),scode.length);
       
很简单的置换,将scode中“已经使用了的字符”进行删除。

那下面的else是什么意思啊?

        encoded=encoded+code.substring(i,code.length);
        i=code.length;
       
意思就是将code中大于20的之后的字符一口气全部加到encoded后面,然后直接退出for循环(即第二条语句的意思,换了一种写法,但是和break意思一样)

for循环完成之后有这样一条语句:

        document.getElementById("encoded").value=encoded;
       
奥,原来是将加密后的密文encoded赋值给form表单中的被隐藏的那个输入框啊,
       
        document.getElementById("userPassword").value="";

将密码框的文本清空,最后将form表单submit提交。
这就很好解释了在传输过程中如何保证数据安全,以及后端如何拿到密文。


这样整个过程就全部分析完成了。

接下来的python代码复现也是很好完成了,


scode = "321akd3k0013M7cQ0Dv1Y749315N3f2Sxy762W213"

sxh = "13122313321123323321"

account = input('账号:')

password = input('密码:')

encoded = ''

code = f'{account}%%%{password}'

for i in range(len(code)):

        if i < 20:

                // encoded=encoded+code.substring(i,i+1)+scode.substring(0,parseInt(sxh.substring(i,i+1)));

                encoded = encoded + code + scode)]

                // scode = scode.substring(parseInt(sxh.substring(i,i+1)),scode.length);

                scode = scode):]

        else:

                // encoded=encoded+code.substring(i,code.length);

                encoded = encoded + code

                break

data = {

        'userAccount': accouont,

        'encoded': encoded,

}

res = requests.post(url='...',data=data,headers=header)



好了,完成!(从这里也能看出我们python代码的简洁,python之禅)


但是仅仅这样就够了吗?
*****************
我们在分析ajax异步请求的时候,知道了异步请求会返回一个dataStr,既然不是本地变量,那肯定会根据后端的变化而变化,所以这个变量我们肯定是要单独请求一次的。
*****************
我们在程序前面添上:

        dataStr = request.post(url='/Logon.do?method=logon&flag=sess',headers=header).text

        scode = dataStr.split("#")

        sxh = dataStr.split("#")
       
这样差不多就完成了。
这应该算是一个非常简单的逆向,但是我还是蛮有收获的。
学习永无止境,人生苦短,我用python(嘻)

xfmiao 发表于 2021-4-18 22:31

厉害,分析的到位

z137465707 发表于 2021-4-18 23:07

强强强!!

zecore 发表于 2021-4-19 00:01

太厉害了,学习

taijizsf666 发表于 2021-4-19 07:52

楼主厉害,加油

Alexxxx 发表于 2021-4-19 09:30

学习学习!!!!

Amichen 发表于 2021-4-19 10:31

写的很详细,666666

dongse 发表于 2021-4-19 10:36

bwuaich 发表于 2021-4-19 11:25

分析详细;欢迎分析讨论交流,吾爱破解论坛有你更精彩
页: [1]
查看完整版本: 解析某网络教学平台登录时的明文加密方法并使用python实现代码复现