(渗透过程:了解js代码的过程)
一般网站的请求不愿意让机器去发送请求的,所以会设置一些难以获取的参数。通过js代码分析就可以得到请求的参数然后就可以用机器发送请求
js逆向:了解js代码后,用python进行实现。(通过分析js动态加载,把js加载的代码还原出来利用,逆向的过程主要体现在逆向分析它js动态加载的源码,和黑客的逆向工程理念类似)
js动态:有算法的,给一个内容就会做出反馈的。
一些功能处理都是需要通过js来处理的。
Chrome调试面板
常用面板
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gkrrKqbB-1614400516946)(.\渗透I图片\常用面板.png)]
-
定位小箭头按钮(左边第一个):
选中Elements面板,并启动该按钮,可以在页面中定位相应元素的源代码位置,或者选择源代码位置可定位到页面相应的元素。 -
手机-PC视图切换按钮(左边第二个):
启动该按钮,网页可以在pc网址网页和手机网址网页之间进行转换。由于在爬虫过程中,爬取手机网址网页相对来说更容易,所以可以通过该按钮将网页切换至移动网页实现更快速爬取操作。 -
Elements面板(元素面板)
该面板显示了渲染完毕后的全部HTML源代码,在使用selenium爬取网页时可通过这些源代码找到各标签的位置,属性等特征。更重要的是,双击html源码或者右侧的css,可以更改网页外观,即可以对静态网页进行调试。 -
Console面板(控制台面板)
该面板用来显示网页加载过程中的日志信息,包括打印,警告,错误及其他可显示的信息等。同时它也是一个js交互控制台。 -
Sources面板(源代码面板)(有网页的所有动态资源)
该面板以站点为分组,存放着请求下来的所有资源(html,css,jpg,gif,js等)。正是因为该面板存放了所有的资源,因此在调试js时,目标代码都是在此处寻找的。该面板也提供了调试按钮工具。 -
Network面板(网络面板)(xhr有着ajax的请求,动态加载请求)
Network面板记录了网络请求的详细信息,包括请求头,响应头,表单数据,参数信息等,通过查找请求头的常变动参数放到元素位置查找,可以得到对应的信息,或更了解js代码,如果找不到就不是静态页面中的
Network面板
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yEqbHU1u-1614400516950)(.\渗透I图片\Network面板.png)]
- all:所有的请求
- XHR(XmlHttpRequest对象js生成): js动态加载请求
- JS: JS代码
- Css: 样式
- image: 图片
- Media: 音频,视频
- Font: 字体
- DOC: 首页
- WS: WebSocket
设置断点
可在xhr的initrator找到请求,点进去后,左下角点{}可以切换阅览模式,然后打断点后执行网页会停在该断点位置,出现灰色网页的反应是在调试状态下到所断点的位置停了下来。
目的:通过调试找到目标数据生成的地方
在一些网页的渲染,行为和请求等等的实现后面都有JS代码进行执行,我们对JS代码打了断点之后,当JS执行到我们打断点的那一行时就会暂停执行,其实就像我们在IDE中编写Python一样,是对代码进行调试的一个工具。
使用断点来暂停JavaScript代码,审查变量的值和在特定时刻所调用的堆栈。
设置断点的最基本的方法是在特定的代码行上手动添加一个断点。也可以将这些断点配置为仅在满足特定条件时触发。
在源代码的左侧,您可以看到行号。这个区域称为line number gutter(行号槽)。单击行号槽中的行号,就会在该行代码上添加一个断点。
例如事件,DOM更改。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zjRvyn3L-1614400516956)(.\渗透I图片\设置断点.png)]
逐步调试
恢复执行这个常用的场景有两个,一个是结束调试,比如要同一个页面要换一个请求分析的时候可以结束当前调试,另一个是进入一个相当长的不重要的循环中,但是又需要分析同一个函数中后面的代码,这时可以在循环外面打一个断点,再恢复执行,可以快速跳出循环。后面的几个功能描述都比较清晰就不多讲了,后面在使用中会慢慢熟悉。
作用域
当脚本中断的时候,Scope(作用域)窗格将显示当前时刻所有当前定义的属性。
调用堆栈
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eZD57JHQ-1614400516962)(.\渗透I图片\调用堆栈.png)]
- 靠近边栏顶部的是Call Stack(调用堆栈)窗格。当代码在断点处暂停时,CallStack(调用堆栈)窗格显示执行路径,按时间逆序,将代码带到该断点。这有助于理解现在执行到哪里,它是如何到达这里的,是调试的一个重要因素。
- 调用函数链,下面调用上面的函数(回调原理)
可以这样理解,每次在函数中需要调用新的函数时,就会把新函数压到最上面,这样我们每次都会关注最新的函数执行。
console可以查看函数,方法,属性,还可以调用测试函数,方法······
请求分析
参数构造流程
这种提交数据得到响应的的请求,往往参数比较麻烦,所以参数的构造是得到完整请求的关键.
首先我们要明确目标,爬取这个网站的目的是什么,那我们的目的就是模拟浏览器发送请求,完成翻译的功能,明确了目标之后我们再定位到相关的URL就比较容易了。
现在先打开chrome的调试工具,然后输入需要翻译的内容,比如我们输入一个需要翻译的词,中国,如果觉得无关的请求太多了可以把当前的页面请求清空,重新点击翻译发送翻译相关的请求,然后再请求过滤器中选择XHR,这样请求就非常清晰了。通过请求的名字可以猜到,第一请求应该是检测语言的请求,对我们的目标好像没什么用,其实眼尖的人应该很快就发现了,第二个请求就是我们需要的URL
以定位到URL为前提
- 先作对比,找出不同的参数
- 从之前的请求响应中找数据
(1)网页源代码中查找
(2)全局请求搜索 - JS加载调试,查找生成规律
参数来源(重要)(参数获得越多,伪造越相似)
不变的参数写固定值,变动的参数的来源在JS中寻找,即JS渗透
一个动态请求的参数来源只可能有两个:
一是来自之前的请求响应,二是JS生成
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NIZnIq9X-1614400516966)(.\4.JS渗透(一)]\请求分析1.png)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WaCuuDQq-1614400516967)(.\4.JS渗透(一)]\请求分析2.png)
参数对比来源
现在我们找到了相关的URL,也就是说给这个URL发送请求,那它返回的结果中就应该有翻译的结果。但是肯定需要通过请求告诉服务器需要翻译的词是什么,那么接下来就一起看一看发送请求需要携带什么参数。(翻译两个词,如你好和世界,将表单数据复制下来查看区别)
现在我们来看一下这两次的请求表单的数据有什么区别,主要的区别有两个字段,分别是query,sign,还有一个token是看起来就比较重要的参数,query很显然是我们自己输入的数据,那么这个sign和token就是需要找到的两个参数(,后面token是可以从访问https://fanyi.baidu.com得到的静态页面中获取),所以我们的重点任务就是找到这个sign的生成方式
query
是自己输入的数据
sign是动态加载的
token 可以从访问https://fanyi.baidu.com得到的静态页面中获取
获取token值
首先获取token值,这个值的获取比较容易,是静态页面中写好的,复制之前请求中的token值然后直接在界面中搜索可以看到这边token的定义位置,然后通过正则匹配出来就可以了,很简单,应该都能看得懂吧,这里就不多讲了,下面用Python代码进行实现功能,有时前几次变动,刷新几次就不变了
这里获取token时可以多获取几次,因为有时这个token值会发生改变,我实验了几下一般发送3次请求获得的token值就固定了,后面就不会再变化了
获取sign值
token找到了,接下来就需要找到sign值了,这个值因为是JS动态生成的,在页面上无法直接找到,所以要进行分析然后找到相关的JS代码。接下来我们一起看一下这个值是怎么生成的。
调试细节
-
定位url 查看数据
-
进入initiator
-
调整显示格式
-
打断点
底层函数(send是一个底层函数)
通过点击initiator 进入的代码,可能是一个底层的函数;多种动态请求均可以调用此函数;所以要通过请求的url判断,此次触发是否是目标请求的v2transapi
找到生成sign的函数
进入生成sign的函数
不停的f10直到sign出现,因为send比较底层,所以多个函数都可以调用它,所以经常选到调用它的函数,所以要一直F10
PyExecJs执行js代码(execjs:是一个python执行js代码的库)
解释器不能越过环境,所以所选的环境最好是解释器所在的环境
找到对应的JS代码后把完整的函数作为一个新的文件粘贴出来,JS代码如果比较长可能不太好找到完整的函数,这里可以把光标放在在定义函数的位置后面的大括号,代码提示会告诉我们函数结束的大括号在什么位置,这样就找到了完整的函数定义。之后用PyExecJs直接执行JS代码,如果想了解sign的具体实现方式可以自己分析一下JS代码,在chrome调试工具中的Console可以执行具体的JS代码帮助理解,这里就不展开了。
生成sign的js完整代码
function n(r, o) {
for (var t = 0; t < o.length - 2; t += 3) {
var a = o.charAt(t + 2);
a = a >= "a" ? a.charCodeAt(0) - 87 : Number(a),
a = "+" === o.charAt(t + 1