前置思路文章
JS 逆向混淆前端对抗
油猴 JS 逆向插件
JS 加解密之 mitmproxy 工具联动 Burp
# JS 挖掘基础
# 伪协议
JavaScript
伪协议是一种在浏览器中模拟网络请求的方法。它使用 window.XMLHttpRequest
对象或 fetch()
方法来模拟发送 HTTP 请求,而不是通过实际的网络请求来获取数据。
例如,以下代码使用 fetch()
方法模拟发送一个 GET 请求到 example.com
,并处理返回的数据
1 | fetch('https://example.com') |
在这个例子中,我们使用 fetch()
方法发送一个 GET 请求到 https://example.com
,然后使用 .text()
方法获取响应的文本内容,最后使用 console.log()
方法将响应的内容输出到控制台。
需要注意的是,虽然使用 JavaScript 伪协议可以模拟网络请求,但它并不能完全取代实际的网络请求,因为它的性能和可靠性都比实际的网络请求要差。此外,使用 JavaScript 伪协议可能会导致一些安全问题,因为它可以被恶意代码利用来获取敏感信息
# XSS
利用 JS 变量提升
XSS 案例
JavaScript 中的变量提升是指在代码执行过程中,JavaScript 引擎会将变量声明提升到其作用域的顶部,但不会提升变量的赋值。这意味着您可以在变量声明之前访问变量,但变量的值将是 undefined
undefinedVar
是个未命名的变量,如果我们直接使用的话会被变量未定义错误。但是如果我们在下面再次去使用这个变量并且去声明它赋值,那么上面的就不会报错了
下方代码前者是未定义就使用的,但下面还是正常的去声明使用了,整体并没有报错出现,这是因为变量提升的原因,把 var
undefinedVar
提升到了顶部,最开头 所以往下的 undefinedVar = null
并不会报错
# F12 控制台参数
F12 查看接口出参入参
F12 数据包接口信息
Fkalis 文章接口测试
# 获取接口信息
F12
打开控制台下方就是整体的数据,包括选择的接口,以 Edge
为例在网络选项中打开此页面,如果对响应头或者是请求头不明白直接 ChatGPT
审计就是
Fetch/XHR :
这个功能可以帮助开发人员分析和调试网络请求,包括请求的 URL、请求方法、请求头、请求体、响应状态码、响应头、响应体等信息。通过查看 Fetch/XHR 选项中的请求和响应信息,开发人员可以快速定位网络请求的问题,例如请求失败、响应慢、响应数据异常等,其实也就是一个筛选器,
选项右边我们还可以只查看 CSS JS 这些
测试中接口地址响应后返回了相关的数据,那么我们就可以尝试对这个 /ums/ums/getRole
接口的 getRole
参数进行 Fuzz
观察数据包的请求和响应就可以确定这个接口获取请求是否存在漏洞
数据包:
1 | POST /ums/ums/getRole HTTP/1.1 |
响应包:
1 | HTTP/1.1 200 OK |
请求标头可以获取到 Cookie
# 查看入参
请求就是入参 响应就是出参,这里的入参格式有 key-value 格式也有 json 格式
关于二者区别
它们的区别在于数据的组织方式和传输效率
Key-value
形式的数据是一种简单的数据组织方式,它由一系列键值对组成,每个键值对之间用特定的分隔符分隔。这种数据格式通常用于传输简单的数据,例如表单数据、查询参数等。Key-value 形式的数据传输效率较高,因为数据量较小,传输速度较快
JSON
格式的数据是一种轻量级的数据交换格式,它由一组键值对或数组组成,可以嵌套使用。JSON 格式的数据通常用于传输复杂的数据结构,例如对象、数组等。JSON 格式的数据传输效率较低,因为数据量较大,传输速度较慢。但 JSON 格式的数据具有良好的可读性和可扩展性,可以方便地进行解析和处理选择何种数据格式取决于具体的应用场景和数据传输需求。如果需要传输简单的数据,可以选择 key-value 形式的数据;如果需要传输复杂的数据结构,可以选择 JSON 格式的数据
在负载这里看到查询字符串参数,[1] 就是入参数据并且可以查看请求源,它是拼接后的数据 下方拼接后为
1 | positionId=644&queryWord=&articleId=0&adId=5518 |
# 查看出参
响应页面看出参数据..
# 查看 Cookie 数据格式
选择请求右侧 Cookie 它的组成其实就是一个个的 key 和 value
# JS 审计
JS
文件可以看是否存在版本或者名称信息这样可以去网上找相关漏洞
# 手动搜索参数
控制台直接搜索这种 api
语句就可以找到不同的接口,获取到特殊的路径,获取其他的敏感字眼
1 | Path |
找到的是隐藏的接口 类似 api/login/name
拼接到主站域名中,普通的路由也就网站的路径,接口指后端中的函数,调用接口等于调用了后端某个函数功能实现增删改查等等
1 | 网站路径 = url = 目录 = 路由 |
如果拼接出来是空白的,就按照路径慢慢删掉,回到上级目录有的 .net
网站会有接口管理器,找到一个接口返回上级目录就可以看到所有接口,而且有的 aspx
接口是可以看到参数值的)
1 | baidu.com/api/login/name |
找到的是 url
在浏览器执行即可 一般会得到 JSON
格式的数据
类似这种路径下存在参数,可以路径带参数构造
http://xx.xx.xx.xx /commonServletfromflag=queryWorkUserBySectionId§ionId_search=1
控制台查看了一下 RPC
函数的 js
源码,也算是一个审计 js
源码的小 trick
: js
函数名 +'' 会自动调用 js
函数对象的 toString
方法,从而输出对应的 js 函数的源码,避免了自己一步步从一堆源码里寻找这个函数
1 | console.log(RPC+'') |
# 审计源码
在控制台应用程序选项,拉到底部可以在这里看到这个页面所有的 JS脚本
,一般 JS
文件通常会 报出 CMS版本
,和一些 验证判断响应值
有了 CMS 可以尝试去网上找通杀 Nday 攻击,并且还有有其他注释没有来的及删除的信息,渗透测试的本质就是信息收集
在挖掘时别人能挖掘出水平越权垂直越权,是因为这个越权漏洞的传参值都是在接口中进行的,所以我们要在挖掘的时候利用 Burp 抓住每一个包
然后再去看Burp
里面的http
历史记录 查看接口信息
Webpack
会包含很多接口信息
如果在站点页面是无法看见?id 这个参数的,而你在 burp 历史包中即可以看见此参数,这个参数就是个人身份的参数
接使用浏览器的控制台中的网络即可查找,重发刷新页面就会再进行一次请求,如果再下方找到隐藏的身份参数后,讲 uid=xxx 修改为别人的数值 即是测试越权
# Python 解决 JS 加密
逆向出参数是由什么加密而来的,首尾加入了什么固定的字符串,加密几个参数就写一个方法解密出这些参数
1 | import execjs |
passwd
是 保存明文密码的文件
# 反编译 js.map
[2]
反编译 Webpakc js.map
提取 WebPack 打包站点接口
JSFuzz 接口导致铭感信息泄露
Vue
使用 webpack
(静态资源打包器) 的时候,如果未进行正确配置,会产生一个 js.map
文件,而这个 js.map
可以通过工具来反编译还原 Vue
源代码,产生代码泄露,并且前后端分析网站前端使用 Vue
重点找 xxx.app.js
再从中提取新的接口
1 | reverse-sourcemap --output-dir . xxx.js.map |
# 数据包接口构造
前端 JavaScript 渗透测试步步为营
JSFuzz 接口实现 SSRF
JS 更换请求方式构造
JSFuzz 接口导致铭感信息泄露
JS 拼接杂谈
fkalis 关于 JS 研究
JS 接口系列文章
# Fuzz 前置目录
JS
找到的接口某些情况下不能直接访问,前置或者还有一层目录,这个就需要我们去进行 fuzz
或者信息收集寻找接口间的共性再进行爆破,直接的话只能使用字典,我建议先找个登录点抓个包看看路径是否有一个基路径(一级目录),然后再拼接跑一遍。
1 | /data/teach/hr/search?key= // 可疑接口,后面带入参数可疑搜索更多 |
# 构造接口
其实很好理解,如果网站功能点只能允许查看 info
那么在查询接口功能抓包,构造参数为删除 delete
, 接口有的是主动构造有的是工具熊猫头或其他审计得到的接口,整理后 GET
POS
方法访问
1 | api/info?id=1 // 正常查询接口 |
常见业务接口格式如果 js
文件中只有查询的接口,那么自己可以尝试一下构造添加、修改和删除接口
多观察接口,推测其功能,然后根据功能去 FUZZ,毕竟你要实现一个 web 功能,基本都要有对应的增删改查接口
1 | // 后台的模块的接口格式 |
1 |
|
# 构造参数
JS 寻找关键参数
应该如何寻找参数的蛛丝马迹
无论是熊猫头还是其他工具得到的接口其实是不完整的,直接拼接的话缺少参数是无法访问接口会报错,需要构造 ** 参数,** 如果我们直接去 fuzz
猜参数,那基本上是属于大海捞针,几乎不太可能成功。那这时候就需要去 JS
源码里面找一下它的调用代码,看看它是怎么请求的,都有什么参数
GET
请求参数拼接到链接中, POST
请求构造参数拼接到下方 Body
# 构造 JS 文件
实战某金融 SRC 通过 JS 接口进入后台
当接口参数无法操作,信息收集只要少量 JS
文件既可以使用爆破模块对 JS
进行 fuzz
如果响应了新的文件再从响应包中审计新的接口,案例见标题
实战 FuzzJS 文件
文章展示了针对古老的站点测试手段,野战和 edu
测试功能点无从下手的时候可以回来看看这篇文章看看有没有启发 PHP/ASP.NET
fuzzjs
可以利用 BP
配合字典直接开测,观察响应接口 文章推荐了 FFUF
工具操作 对与 403
页面尝试绕过和 dr
工具爆破
# Fuzz
爆破 / 接口路径
api 接口猜测爆破
观察抓取到的数据包的接口,寻找共同函数的特征,爆破后面的数字或许会有未授权访问的接口或者功能可以先猜目录再猜参数网站就一个文件夹存放了很多的文件
1 | /funtion123 |
响应包出现我们不知道参数,第一先去 JS
中全局找这个参数看看有没有相似的路径拼接构造,有就拼;无则 fuzz
# JS 逆向
逆向加密是为了应对数据包中出现
sign
或者token
的情况,sigh
和对应的passwd
字段关联,修改了passwd
字段sign
匹配不上就无法测试所以
sign
的加密肯定会有passwd
字段参与,找到加密sign
的位置构造我们想要测试的passwd
生成新的sign
字段就是我们所测试生成的字段这样响应包就不会显示签名问题
小程序 F12
1 | https://blog.csdn.net/u010062917/article/details/135649668 // 文章 |
# 定位加密参数方式
全局搜索 ** password
**
根据网络请求已经发现了加密字段 password
全局搜索即可,或是全局搜索 encrypt
函数一般加密前缀都是此名称,利用搜分析其实非常快速
1 | (1)复制加密参数的键名 |
** XHR
** 定位
同样定位到加密字段的请求,请求路径即可,不需要携带参数,针对普通的跟栈找不到 data
数据情况
1 | /login.php |
输入对应的请求路径后再次点击登录就会定位到我们所选择的堆栈函数
跟随堆栈定位
爱拍案例就是此方法,跟进每个函数后还可以在此函数的 JS
里面全局搜索加密字段,因为断点位置可能并无加密方法,也可能是在上下文
# 爱拍案例 MD5
定位出加密的函数有两种方式,1 是定向的找字段,2 是根据请求跟请求调用栈,第一种全局搜索加密参数 但是试用于搜索出来值很少 十个以内就可以利用搜的方法,这里还是选择跟踪加密数据包堆栈函数
# 0X01 堆栈寻找加密函数
进入网站打开网络,任意输入账户密码,在网络中找到关键的请求里面是对应加密过后的账户密码 password
并且要把保留日志和停用缓存勾选,对应关键请求查找就是看哪个存在加密就跟哪个函数
选择启动器查看堆栈函数,从下往上执行结束,我就从结束的点往下选择加密位置
跟入堆栈打入断点并放掉余下的包,余下还有其他的待执行的脚本包,类似于 BP
拦截,所以要全部放掉,之后再次点击登录发出新的包,不然的话包是不一样的
断点完成最新的堆栈出现,开始一个个往下跟寻找加密位置,找到未加密前的函数,找到的是加密后的函数就直接放弃进入下一个,直到未加密位置
1 | 函数名称如果是JQ库或是其他语义化比较明显的js就直接跳过因为这种加密都是现成的并没有算法 |
一个个移动堆栈直到找到对应的加密算法,为 md5
1 | e.md5(q) q=123456 // 明文 |
控制台也可以验证此函数打印后的值就是就加密后的值 并和 BP
值一致
控制台控制 q
的值并再使用算法可以生成新的值,试用于手动的进行替换,这样加密参数就为我们所控
# 0X02 跟入函数内部
确定好加密算法位置,然后对此打入断点并放掉所有的脚本重新点击登录数据就会卡在此处,如果先前有断点也要清除只保留这一处断点即可
使用浏览器堆栈工具跟入加密 md5
函数内部并返回,确定了是 md5
加密方式 并返回上一步函数,测试了忽略断点工具使用
md5
算法
# 0X03 工具生成算法
跟踪到加密算法后虽然可以在控制台手动的去将加密函数执行并手动替换,但是还是脚本来的快速,打开 WT-JS
选择原生的加解密库 CryptoJS
选择加密方式为 md5
生成加密本地的加密算法
加入打印方法调用加密的函数,得出我们所需的加密值
1 | // MD5加密执行 |
# 快乐学堂 DES
前期根据加密请求跟栈找到密码加密位置,在 pass
密码出打入新的断点并清除先前断点,再点击登录,就会在密码卡住,明文被 encryptByDES
函数所加密,从名称上是 DES
对称加密需要寻找函数中的 key
1 | pass: encryptByDES(s) |
使用右侧工具跟进此函数内部
发现此加密函数逻辑并出现 Key
打开 WT
工具进行复现写入对应设置生成加密算法
1 | // 定义密钥和初始化向量 |
# 翼龙贷 DES
寻找关键的请求花费了一些时间,因为加密的 pass
并未在堆栈中显示,需要自行上下找才行,找到了就打入断点对此加密方法进行跟进测试,注意必须是断点打入到加密函数中才能进入如 encrypt
不然会进错
1 | e = e9284d45-cf2a-4e46-9367-f122413ca6b0 |
写入算法完成
# sign 逆向
sign
加密出的字段都是和当前正常的 username
和 passwd
有关,每个数据包参数对应签名,参数被修改 sign
签名失效无法测试
1 | username=admin123&&passwd=000000 == a |
# Python 生成 sign 原理
追踪到的 sign
生成逻辑,给到 AI
分析然后告诉它利用 Python
编写于 Passwd
和 sign
对应的爆破字典, AI
给出具体的生成代码,并会有关键的字典让你填写进去,除了一些固定的参数如版本号或者其他字段,最重要的就是需要生成 sign
的 passwd
字典
之前一直不明白为什么可以一直反复的替换,原来是生成了对应的
sign
字典再来爆破替换的,每个生成的sign
对应了我们固定修改的值,爆破多个字段记得Python
生成的逻辑也不同,需要写入两个文件修改来爆破,但是一般是只修改一个字典的值,如密码或者固定的支付中的单号,最终只会产生一个sign.txt
供替换,所以原字典需要自己准备也就是想要爆破的值