目标网址:https://user.wangxiao.cn/login?url=https%3A%2F%2Fwww.wangxiao.cn%2F
案例目标:网页账号密码模拟登录,获取对应的题库内容。

网页分析
问题复现,随便输入账号、验证码和密码,然后点击登录。

通过抓包查看请求内容。


从返回的结果可以看出,用于处理登录的数据包传输的password为加密格式,发送的是POST请求。
我们想要模拟这个登录请求,必须要做的一个事情就是分析该密码的加密逻辑,将自己登录传输的密码按照相同的加密逻辑进行加密,然后传输过去进行验证。
接下来开始分析其加密逻辑,点击启动器。前三个请求都是使用jquery发送。

我们直接从第四个开始分析,点进去,打上断点。

再次点击登录按钮,让其在断点处暂停。

从e中的url可以看出,这个时候请求的地址为/common/getTime。我们释放此次断点。

这个时候的url地址才是正常的。

查看发送的Ajax请求中的data值。

通过观察发现data的值是通过i赋值得到,在此处的密码已经被加密,我们需要往前找。

在此处可以知道i是通过e.data来赋值得到,并且e中的password已经的被加密的,而e是通过函数传输过来的,这个时候就需要往前找调用这个函数的地方,传输过来的e是什么,查看前一步操作。这个时候就需要借助右下角的调用堆栈。


在这个地方是通过zdAjax接口对其进行调用,并且传入接口中有两个参数,第一个是param其作用就是将加密的数据传输过去;第二个是一个箭头函数,其作用暂时不清楚。再次利用右下角的调用堆栈,回到之前的调用栈,搞清楚箭头函数传输过去是做了什么事情。

经过分析可以看到,这个箭头函数传输过来只在Ajax传输后对其进行了使用。
小结,zdAjax(param, res => {})作用为将param作为Ajax请求的参数发送到服务器的"/apis/" + param.url处,然后将服务器接收param参数后返回的数据,再传输作用再第二个箭头函数中。
再回到后一个调用栈,现在可以知道,e是通过该数据包中的param参数赋值得到,并且在这个地方param也是被加密的,继续向上找。

往上找发现param参数中的password是通过encryptFn(pwd + '' + ress.data)该方式对密码进行加密,此处pwd即为实际输入的未加密的密码,而param中已经被加密了,说明encryptFn即为加密方法。
其中ress.data的值为ress传输过来的,而经过前面的分析zdAjax接口的作用是将paramss作为参数发送到服务器中的某个url地址,然后将返回的数据传输给第二个箭头函数。
换句话说,ress的值为paramss发送给服务器后的响应值。再网上找paramss看看是什么。

可以看出,服务器接收参数的地址为/common/getTime,并且没有传输任何参数。
接下来看看加密方法encryptFn。

点击来就可以看到关键字setPublicKey

说明此处密码的加密方式就是RSA加密,并且公钥就再"xxxx"中。
PS:在分析网页的时候我们可以很明显的看到很多keepOurCookie12关键词,这说明该网址很有可能对网页的Cookie校验非常严格,可能调用JS对Cookie进行处理,这可能导致我们使用传统的session会话去保存登录状态无法解决登录问题。
现在加密方式和公钥都有了,顺利的话密码的加密问题应该已经可以解决。
除了账号和密码,在登录的时候还有一个验证码图片需要处理。查看验证码的请求方式。

图片的请求是使用的POST请求方式,
API地址为https://user.wangxiao.cn/apis//common/getImageCaptcha
接下来查看其返回的内容,点击预览。

可以看到图片的传输使用的是base64进行编码传输的。 我们可以将其获取下来,将其反向转化为字节后存储到本地即可看到正常图片内容。接下来可以人工识别或者调用第三方工具识别。
现在验证码和密码问题都已分析完成,开始进行代码编写。
代码编写
验证码识别
验证码识别问题相对简单点,我们先解决该问题。
直接请求API发现无法得到正常的图片数据。

给其增加常见的请求头。

从结果可以看到,加了常见的请求头参数仍然无法解决问题。
通过在其发送Ajax请求时可以看到,在发送Ajax请求时有一个很特殊的参数contentType也被传输过去了。

然后我们观察在请求头中也有这个参数,尝试把它加到请求头中进行访问。

这个时候发现能够得到JSON数据了,但是服务器的响应时间明显增加了,并且数据还是不对,显示未知错误。

这个时候时候通过观察cookie我们发现在其中有一个参数为sessionId值为1683532405248,这很有可能是一个与时间有关的参数,时间间隔太长导致请求失效了。
这个cookie是从哪里来的呢?我们关闭断点,直接刷新整个页面(注意:需要先清楚网页缓存),观察下在请求首页时候的cookie。

可以看到在请求首页的时候,响应头中有个Set-Cookie:sessionId=1683545006624; path=/参数,其中就有我们想要的sessionId,该参数的作用就是给后面的访问设置Cookie。
这个时候我们可以点击密码登录查看验证码数据包Cookie中的sessionId值看看是否一致。

通过比较可以发现确实是一致的。
所以要想请求到正确的图片数据,需要先请求首页让其设置Cookie后,再请求图片API。这个时候就需要使用到会话Session机制。

这个时候发现请求结果正常。使用base64对其进行解码存储到本地。


图片显示正常。有两种常见的方式对其进行识别:
- 人工识别后输入
- 调用第三方工具识别
在这里我们采用调用第三方工具的方式进行识别。
调用的是图鉴的API。在其官网有对应的调用示例,我们直接复制代码即可。
1 | import base64 |
其中:
uname:用户账号pwd:用户密码img:用户图片地址typeid:识别的图片种类,在官网可以查看,我们这里是数字和英文的组合即为3。

按照要求填入内容。

成功返回结果,验证码识别完成。
密码RSA加密
经过前面的分析,再进行密码加密的时候不是单纯的对密码加密,会加上一个ress.data这个参数是通过对服务器中的/common/getTime地址进行请求返回的结果。在抓包工具中也可以看到该数据包。

使用POST请求该数据包,同样在请求头中加上Content-Type。

结果返回正常。
筛选出get_time值,并为了后面代码编写,先定义好账号和密码(自己填写)。

拼接好待加密参数

经过前面的分析我们已经拿到RSA公钥,接下来使用RSA利用公钥对其进行加密,并将加密后的数据转化为Base64。
1 | MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDA5Zq6ZdH/RMSvC8WKhp5gj6Ue4Lqjo0Q2PnyGbSkTlYku0HtVzbh3S9F9oHbxeO55E8tEEQ5wj/+52VMLavcuwkDypG66N6c1z0Fo2HgxV3e0tqt1wyNtmbwg7ruIYmFM+dErIpTiLRDvOy+0vgPcBVDfSUHwUSgUtIkyC47UNQIDAQAB |

加密成功,现在已经解决了在请求时需要使用到的所有参数。
开始发送登录请求
在发送请求时,注意将data表单转化为JSON格式。这个在JS源码中也可以看到,在获取到e.data时调用了一个JSON.stringify()方法。


这里登录成功了,我们是否可以直接使用session会话请求到其他页面内容呢?
例如我们请求某个模拟考试(http://ks.wangxiao.cn/TestPaper/getPaperRuleQuestions),看是否能够拿到试题。



发现无法正常请求该地址,又自动跳转到了登录页面。

说明我们在此处通过session保存的cookie并没有保存到登录状态。这个就是我们前面说的该网站在处理Cookie时调用了JS对Cookie进行进一步处理。
对于这种情况只能通过分析网页JS后手动补全Cookie。


按照JS中写的手动补全Cookie。

数据获取成功。

完整代码
完整代码如下,其中账号密码需要手动填入。
1 | import json |
tujianAPI.py
1 | import base64 |