当前位置: 首页 > news >正文

公章在线制作网站wordpress外链批量保存本地

公章在线制作网站,wordpress外链批量保存本地,美发网站模板带手机版,互联网公司网站建设ppt模板下载声明 本文章中所有内容仅供学习交流使用#xff0c;不用于其他任何目的#xff0c;不提供完整代码#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理#xff0c;严禁用于商业用途和非法用途#xff0c;否则由此产生的一切后果均与作者无关#xff01; 本文章未… 声明 本文章中所有内容仅供学习交流使用不用于其他任何目的不提供完整代码抓包内容、敏感网址、数据接口等均已做脱敏处理严禁用于商业用途和非法用途否则由此产生的一切后果均与作者无关 本文章未经许可禁止转载禁止任何修改后二次传播擅自使用本文讲解的技术而导致的任何意外作者均不负责若有侵权请在公众号【K哥爬虫】联系作者立即删除 目标 目标Luosimao 螺丝帽人机验证逆向分析 网址aHR0cHM6Ly9jYXB0Y2hhLmx1b3NpbWFvLmNvbS9kZW1vLw 抓包分析 进入官网提供的 demo 页面F12 开启抓包首先加载 demo 页面这个页面包含一个 site-key每个网站都不一样会在后续用到 接下来是一个 captcha.js主要用于后续的加密参数生成乍一看以为是个 OB 混淆其实只是更换了变量名然后一些值是从大数组里面取的没有 OB 混淆里的打乱数组的操作比 OB 混淆要简单很多后文会利用 AST 对这三个 JS 进行解混淆后续类似的还加载了 widget.js 和 frame.js也都是和加密参数的生成有关。 然后是一个 widget 的请求该请求返回的源码里面有个 data-token也是后续要用到的。 接下来是一个 request 的请求接口返回的一些参数也是后续要用到的同时返回的 w 值就是要点击的文字提示信息。 然后是一个 frame 请求请求带了两个加密参数这个请求返回的源码里面包含了验证码图片信息。 然后就加载了验证码图片注意这里的图片是被切割之后乱序排列了的和极验三代的类似所以后文我们还要对其进行顺序还原。 点击图像完成之后就会发起校验请求 user_verify校验成功的话返回的 res 为 success相反校验不成功就是 failed。 点击立即登录触发最后一个 submit 请求提交的 data 值就是上一步 user_verify 验证成功后返回的 resp 值。 小结一下螺丝帽就可以分为三个比较重要的步骤request 接口请求得到要点击的内容frame 接口请求拿到验证码图片user_verify 接口验证点击是否正确下文将详细分析这些步骤。 AST 解混淆 先别着急找加密逻辑前面抓包的时候说了一共有三个 JS 参与了加密分别是 captcha.js、widget.js 和 frame.js这三个 JS 是被混淆了的为了后续比较好分析我们可以先使用 babel 将其转换成 AST 语法树后进行解混淆操作。 以 widget.js 为例观察该 JS我们可以总结出以下三个问题 开头一个大数组如 _0x8f24后续变量赋值操作就是从这个大数组里取值如 _0x8f24[1]、_0x8f24[2]所有的字符串都被转换成了十六进制编码的形式不易阅读访问对象属性是 _0x3ba3x1[Number]而不是 _0x3ba3x1.Number不易阅读。 所以我们只需要做三个操作 从数组取值转为直接赋值_0x8f24[1] \x63\x61\x6C\x6C十六进制编码的字符串还原\x63\x61\x6C\x6C call对象属性还原_0x3ba3x1[Number] _0x3ba3x1.Number。 首先是从数组取值转为直接赋值先将这个 JS 扔到 astexplorer.net 分别看看原始结构如_0x8f24[1]和替换后的结构如\x63\x61\x6C\x6C 从上图可以看到类似 _0x8f24[1] 取值的节点类型为 MemberExpression这个大数组没有像 OB 混淆那样做了乱序操作可以直接取值那么如果我们先拿到 _0x8f24 这个大数组然后遍历 MemberExpression 节点再将其替换成 StringLiteral 类型的节点就行了。当然遍历的时候也要有限制必须是 path.node.object.name 的值和大数组的名称一样才能替换。然后就是我们怎么拿到 _0x8f24 这个大数组呢这个大数组在 AST 中的位置是 program.body[0]我们可以将其转换成 JS 代码然后 eval 执行一下把大数组加载到内存里后续就能直接按索引取值了当然方法不止这一种可以按照自己的思路来实现这一部分的 visitor 可以这么写 const ast parse(code); eval(generate(ast.program.body[0]).code)const visitor {MemberExpression(path) {if (path.node.object.name _0x8f24) {path.replaceWith(types.stringLiteral(eval(path.toString())));}} }然后就是十六进制编码的字符串还原观察前后的 AST 语法树 可以发现只要将 path.node.extra.raw 的值换为 path.node.extra.rawValue 或者 path.node.value即可当然因为 NumericLiteral、StringLiteral 类型的extra 节点并非必需这样在将其删除时也不会影响原节点所以还可以直接 delete path.node.extra 或者 delete path.node.extra.raw 来还原字符串这一部分的 visitor 可以这么写 const visitor2 {StringLiteral(path) {if (path.node.extra) {// 以下方法均可// path.node.extra.raw path.node.extra.rawValue // path.node.extra.raw path.node.value // delete path.node.extradelete path.node.extra.raw}} }最后就是对象属性还原同样的先观察前后的 AST 语法树 可以看到 _0x3ba3x1[Number] _0x3ba3x1.Number是 MemberExpression 下的 property 节点由 StringLiteral 类型的变成了 Identifier 类型的computed 值由 true 变成了 false这一部分的 visitor 可以这么写 const visitor {MemberExpression(path){if (path.node.property.type StringLiteral path.node.property.value ! ) {path.node.computed falsepath.node.property types.identifier(path.node.property.value)}} }前面抓包的时候也说了一共有三个 JS 参与了加密分别是 captcha.js、widget.js 和 frame.js他们的混淆都是一样的所以综上所述我们的 AST 解混淆代码完整版可以是这样的 const fs require(fs); const types require(babel/types); const parse require(babel/parser).parse; const traverse require(babel/traverse).default; const generate require(babel/generator).default;function deconfusion(code, arrName) {const ast parse(code);eval(generate(ast.program.body[0]).code)const visitor1 {MemberExpression(path) {if (path.node.object.name arrName) {path.replaceWith(types.stringLiteral(eval(path.toString())));}}}const visitor2 {StringLiteral(path) {if (path.node.extra) {// 以下方法均可// path.node.extra.raw path.node.extra.rawValue // path.node.extra.raw path.node.value // delete path.node.extradelete path.node.extra.raw}},MemberExpression(path){if (path.node.property.type StringLiteral path.node.property.value ! ) {path.node.computed falsepath.node.property types.identifier(path.node.property.value)}}}traverse(ast, visitor1);traverse(ast, visitor2);delete ast.program.body[0]return generate(ast, {jsescOption: {minimal: true}}).code }const widget fs.readFileSync(widget.js, utf-8); const newWidget deconfusion(widget, _0x8f24) fs.writeFileSync(newWidget.js, newWidget, utf-8);const captcha fs.readFileSync(captcha.js, utf-8); const newCaptcha deconfusion(captcha, _0x2d28) fs.writeFileSync(newCaptcha.js, newCaptcha, utf-8);const frame fs.readFileSync(frame.js, utf-8); const newFrame deconfusion(frame, _0x3f7b) fs.writeFileSync(newFrame.js, newFrame, utf-8);解混淆之后将代码替换掉原始代码然后就可以愉快的进行分析了。 获取验证码信息 首先来看 request 接口POST 请求params 有 k 和 l 两个参数data 有 bg 和 b 两个加密参数如下图所示 k 参数通过直接搜索可以发现就存在于页面的 html 里如下图所示的 data-site-key 就是 k 的值从这个名字也可以看出应该是每个网站分配的一个 key。 bg 和 b 参数搜索不到且每次都是变化的通过观察可知这是一个 XHR 请求那么就可以通过 XHR 断点或者直接跟栈的方式来找加密入口好在栈也不多直接跟进去下断点在 ajax send 方法这里就可以看到 bg 和 b 已经生成。 继续往上跟栈就很容易发现 bg 和 b 的生成位置如下图所示 bg _0x3ba3xc.encryption(_0x3ba3x1) b _0x3ba3xc.encryption(_0x3ba3x3)先来看 _0x3ba3x1 和 _0x3ba3x3 是怎么生成的 var _0x3ba3x1 _0x3ba3xc.env.us || _0x3ba3xc.getToken() || _0x3ba3xc.env.sc.w : _0x3ba3xc.env.sc.h || _0x3ba3xc.env.pf.toLowerCase() || _0x3ba3xc.prefix.toLowerCase(), _0x3ba3x3 _0x3ba3xc.path[0] : _0x3ba3xc.timePoint[0] || _0x3ba3xc.path[1] : _0x3ba3xc.timePoint[1];_0x3ba3xc.env.usUser-Agent_0x3ba3xc.env.sc.w屏幕宽度_0x3ba3xc.env.sc.h屏幕高度_0x3ba3xc.env.pf.toLowerCase()platform如 win32 小写_0x3ba3xc.prefix.toLowerCase()浏览器引擎如 webkit小写。 _0x3ba3xc.getToken() 是一个函数跟进去可以看到是取 widget 请求返回的 html 里面的 data-token 值如下图所示 widget 请求还有个 i 参数也是加密生成的直接全局搜索 i:可以发现在 captcha.js 里 _0x7125x5.id 就是 i 的值如下图所示 跟进去generateID() 方法 return _ Math.random().toString(36).substr(2, 9); 就可以生成这个值了。 然后是 _0x3ba3x3主要由 path 和 timePoint 组成反复对比你会发现path [鼠标第一次进入点击区域的坐标鼠标点击时的坐标]timePoint [页面加载完毕的时间开始点击的时间]如下图所示可以在左上角和右下角都点一下看看这个点击的区域坐标范围是啥然后随机构建一下就行了。 总结下来_0x3ba3x1 和 _0x3ba3x3 就可以通过以下代码实现 function randomNum(min, max) {return Math.floor(Math.random() * (max - min 1) min); }const ua Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 const screen {width: 1920, height: 1080}; const platform Win32; const prefix Webkit; //[鼠标第一次进入点击区域的坐标鼠标点击时的坐标] const path [${randomNum(60, 200)},${randomNum(0, 3)},${randomNum(60, 200)},${randomNum(10, 20)} ]; // [页面加载完毕的时间开始点击的时间] const time new Date(); const timePoint [time, time randomNum(1000, 6000)];const _0x3ba3x1 ua || token || screen.width : screen.height || platform.toLowerCase() || prefix.toLowerCase(); const _0x3ba3x3 path[0] : timePoint[0] || path[1] : timePoint[1];最后一步加密 bg _0x3ba3xc.encryption(_0x3ba3x1) b _0x3ba3xc.encryption(_0x3ba3x3);跟进 encryption 方法熟悉的 iv、mode、padding但他这里写的却是 SHA3很明显是骗人的对比测试一下加密结果发现是 AES 加密直接引库就完事儿了。 至此 request 接口就分析完毕了。 获取验证码图片 然后是获取验证码图片直接搜索图片的名称可以发现是在 frame 请求返回的 html 源码里面如下图所示 这个 captchaImage 对象包含两个值p 是验证码乱序的图片有三个图片这个应该是防止宕机有多个节点实际三张图都是一样的内容而 l 则是用来还原乱序图片的。 var captchaImage {p:[https://i5-captcha.luosimao.com/22/aa27352e782eb74ccccef04eb91bc23c.png,https://i2-captcha.luosimao.com/22/aa27352e782eb74ccccef04eb91bc23c.png,https://i1-captcha.luosimao.com/22/aa27352e782eb74ccccef04eb91bc23c.png],l: [[40,80],[220,0],[280,0],[200,80],[100,0],[40,0],[0,80],[180,0],[20,0],[120,80],[220,80],[240,0],[180,80],[0,0],[280,80],[140,80],[140,0],[200,0],[160,0],[260,0],[20,80],[240,80],[100,80],[60,80],[120,0],[260,80],[160,80],[80,0],[80,80],[60,0]] };我们查看图片的源码可以发现这个 l 的坐标就是 css background-position 属性的值如下图所示 逻辑也很简单图片尺寸 300x160 px切割的乱序图片分为上下两部分每一部分又被分为 15 个小片段那么上半部分从左至右每一片段的左上角坐标为[0, 0]、[20, 0]、[40, 0] …以此类推下半部分则是 [0, 80]、[20, 80]、[40, 80] …以此类推而前面的 l 的值就表示原始图片第 N 个位置对应乱序图片的某个片段的左上角的坐标例如 l 的第一个值为 [40,80]则表示原始图片第一个位置是乱序图中坐标为 [40, 80] 的片段换句话说也就是原始图片第一个位置应该是乱序图中下半部分从左至右的第三个片段。图片的还原在 Python 中可以用以下代码实现 from PIL import Imagesection [[40,80],[220,0],[280,0],[200,80], ......] image Image.open(乱序图片.png) canvas Image.new(RGBA, (300, 160))for index in range(len(section)):x int(section[index][0])y int(section[index][1])slice_ image.crop(box(x, y, x 20, y 80))canvas.paste(slice_, box(index % 15 * 20, 80 if index 14 else 0))canvas.save(正确图片.png)然后就是这个 frame 请求包含了一个 s 参数这个是前面 request 请求返回的如下图所示 发送验证 然后就是点击发送验证请求了user_verify 包含三个参数 h、v 和 sh 是前面 request 接口返回的v 和 s 是需要我们逆向的如下图所示 同样也直接跟栈如下图所示 _0xaaefx15.toString() 就是最终的 s 值而 s 是最终的 v 值 先来看 ss _0xaaefx11.toString();而 _0xaaefx11 和前面一样也是 AES 加密其中 key 是前面 request 接口返回的 i 的值待加密的值是 _0xaaefx5而 _0xaaefx5 _0xaaefx3.dots.join(#)_0xaaefx3.dots 就是点击的坐标不过这个坐标要注意他的 x 和 y 坐标是反着排列的整个数组也是倒序的直观点儿来讲就是 _0xaaefx3.dots [第三次点击的 y第三次点击的 x, 第二次点击的 y第二次点击的 x, 第一次点击的 y第一次点击的 x]如下图所示 然后就是 _0xaaefx15经过 MD5 加密得到最终的值如下图所示 注意事项 请求会校验 header 的 Host 字段frame 接口和其他接口的 Host 是不一样的注意观察替换Host 不正确会导致请求失败。 至此所有流程就都分析完毕了。 结果验证
http://www.pierceye.com/news/271081/

相关文章:

  • 做国外产品描述的网站营销wordpress
  • 服务器2003怎么做网站枣庄网站建设电话
  • 南京网站建设一条龙汶上网站制作
  • 黑龙江微信网站开发郑州热门网络推广免费咨询
  • 深圳坪山站永久免费linux服务器
  • 东莞网站建议ipv6在家做网站
  • 政务网站源码1688电脑网页版
  • 大连企业网站网站rar文件
  • 揭阳东莞网站建设手机网站分享代码
  • 网站设计风格分析wordpress 用户介绍
  • 中国教育网站官网wordpress 自定义循环
  • 中国婚恋网站排名苏州网站建设设计公司哪家好
  • 微软雅黑做网站是否侵权杭州标志设计公司
  • 个人网站如何制作教程网站通栏广告设计
  • 网站建设与维护要求wordpress 常数函数
  • 网站开发u盘128够吗手机网站开发学习
  • 襄阳营销型网站国内最新保理公司排名
  • 网站开发系统学习网站需要续费吗
  • 问答网站如何优化wordpress简约电影
  • 公司做网站 手机 电脑wordpress图片批量修改
  • 电子商务网站怎么做建筑安全员考试成绩查询官网
  • 定制制作网站价格表网站设计步骤大全
  • 泉州网站建设制作北京企业网络推广方案
  • wordpress网站模板怎么用新闻类网站开发
  • 怎么换自己的网站服务器手机应用软件开发培训班
  • 大学生网站开发目的建盏厂家
  • 开业时网站可以做哪些活动吗虚拟机安装 wordpress
  • 可以进行网站外链建设的有wordpress 添加顶部公告
  • 电子商务网站建设臧良运课后答案没有网站怎么做链接视频
  • vps搭建网站教程怎么通过互联网做一个服务的网站