初探网站
请求body被加密:
如请求加密不正确则会报错:
JS逆向
寻找特征
看加密密文,有点像AES/DES/RSA + Base64
,尝试搜索前端常用加密库关键词:
JSEncrypt(RSA)CryptoJS(AES、DES)
果然使用了JSEncrypt
:
加密定位
定位关键加密方法,JSEncrypt
有一个关键方法setPublicKey
,尝试搜索:
在第一行打上断点:
已看见明文:
进入控制台,打印a.publicKey
得到公钥:
公钥:
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCLMgOk8oGP1SYMXq6jSTbaiqUrKMbbRB1Rj93HZghOMJI2pGa55Q3hhHIH3usVRR6WrxQqQ2tZ7XVq7zRMMQBUz2cbYjII3yRl2cn7dNeb+uW30JPypLaqJjwsWhmxYNlVU41rjsUH3RIK7W+4bDlr3JrnHk7X5HDtytiVaYCkVwIDAQAB
手动验证
手动加密替换验证一下是否正确,这里推荐密码学工具:https://github.com/Leon406/ToolsFx,RSA支持大文本加密:
替换发送,服务端成功解密:
利用BurpGuard实现自动化
通常情况下,利用BurpGuard挂上下游代理,解密后修改再加密,但由于使用了非对称加密,且只有公钥没有私钥(私钥通常在服务器上),因此没法解密,需要换一种思路。这里我使用BurpGuard替换加密关键JS代码,让其不加密直接返回明文。尝试手动替换,右键添加覆盖脚本,保存在本地:
在本地打开并修改为直接返回:
刷新浏览器即可看到代码已更改:
尝试抓包看看效果,发现直接抓到了明文,但服务端不认识:
这里可以使用BurpGuard来自动替换,方便移植,如果不需要移植的话可以浏览器替换。
首先移除之前的手动替换:
将之前修改过的
index.39bfdf29.js
放入BurpGuard文件夹中,编写ClientProxyHandler.py,启动BurpGuard.py,浏览器走8081端口:
from mitmproxy import httpfrom Utils.Crypto import *import httpxfrom base64 import b64encode,b64decodefrom urllib.parse import quote,unquoteimport jsonimport tracebackclassClientProxyHandler:def__init__(self) -> None:self.client= httpx.Client(timeout=None,verify=False) # 处理来自客户端的请求,通常在这里对请求进行解密 def request(self,flow: http.HTTPFlow):try: req = flow.request # 获取请求对象 # 在这里编写你的代码 # ... except Exception as e: traceback.print_exception(e)finally:return flow # 处理返回给客户端的响应,通常在这里对响应进行加密 def response(self,flow: http.HTTPFlow):try: req = flow.request # 获取请求对象 rsp = flow.response # 获取响应对象 # 在这里编写你的代码 # ... # 匹配指定JSif"index.39bfdf29.js"in req.path: # 替换整个文件,修改的JS文件在上一级,根据实际需求替换with open("../index.39bfdf29.js","rb") as f: rsp.content = f.read() except Exception as e: traceback.print_exception(e)finally:return flowaddons = [ClientProxyHandler()]
查看是否替换成功:
接着编写BurpProxyHandler.py,来加密修改后的参数,思路就是获取params参数的值,然后利用脚本自带的RSA加密方法加密即可:
from mitmproxy import httpfrom Utils.Crypto import *import httpxfrom base64 import b64encode,b64decodefrom urllib.parse import quote,unquoteimport jsonimport tracebackclassBurpProxyHandler:def__init__(self) -> None:self.client= httpx.Client(timeout=None,verify=False) # 处理来自Burp的请求,通常在这里对请求进行加密 def request(self,flow: http.HTTPFlow):try: req = flow.request # 获取请求对象 # 在这里编写你的代码 # ... # 判断POST请求且为JSON类型,指定hostif req.method == "POST" and req.host == "xxx.com":if"application/json"in req.headers.get("Content-Type",""): # 复制请求body的JSON对象 json_data = req.json() # 拿到明文参数 params = json_data["params"] # 加密 encrypt_params = RSA.encrypt(params,"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCLMgOk8oGP1SYMXq6jSTbaiqUrKMbbRB1Rj93HZghOMJI2pGa55Q3hhHIH3usVRR6WrxQqQ2tZ7XVq7zRMMQBUz2cbYjII3yRl2cn7dNeb+uW30JPypLaqJjwsWhmxYNlVU41rjsUH3RIK7W+4bDlr3JrnHk7X5HDtytiVaYCkVwIDAQAB") # 替换为加密参数 json_data["params"] = encrypt_params # 替换请求体 req.text = json.dumps(json_data) except Exception as e: traceback.print_exception(e)finally:return flow # 处理返回给Burp的响应,通常在这里对响应进行解密 def response(self,flow: http.HTTPFlow):try: req = flow.request # 获取请求对象 rsp = flow.response # 获取响应对象 # 在这里编写你的代码 # ... except Exception as e: traceback.print_exception(e)finally:return flowaddons = [BurpProxyHandler()]
Burp设置上游代理走8082端口:
加入一个单引号显示参数格式错误,证明参数被服务端正常解析:
配合SQLMap
如果需要跑SQLMap的话可以直接走代理端口8080/8081,建议走8080,这样可以使用burp来观察SQLmap的注入情况,如下:
复制请求到文件:
SQLMap指定请求包文件一把梭:
sqlmap -r 1.txt --proxy http://127.0.0.1:8080 --batch
Burp历史记录可以看到SQLMap的注入情况:
文末福利
团队官网:https://redcellsec.cn/
现在我们已经建立了红细胞安全实验室技术交流群,希望各位师傅能积极交流、一起学习,共同营造网络安全良好技术氛围,目前星球是完全免费
的,旨在技术交流分享,文末有群聊二维码,进群以后可以私信群主或者其他师傅进入星球交流,若二维码过期了请私信后台获取星球邀请函,后续会不定期在星球内部或公众号上分享一些实战干货或者实用的工具以及资讯,希望能看到更多师傅们一起来交流行业前沿技术!
原文始发于微信公众号(红细胞安全实验室):【前端加解密】BurpGuard实战案例
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论