前言
当进行渗透测试或安全评估时,JavaScript(JS)成为我们特别关注的领域之一。在前端源代码中,我们可能会找到接口、敏感信息以及一些逻辑处理,比如参数加解密等。为了防止攻击者拦截数据包篡改参数,使服务端执行恶意指令,开发者通常会在前端对输入参数进行加密,这是一种常见的防御手段。这导致我们抓取到的数据包中传入的参数和返回的包内容都是加密的。我们需要对加密方式进行逆向分析。如果无法还原出加密和解密方式,渗透测试可能会受到阻碍。逆向分析有多种方法,下面将介绍一种常用的,即JSRPC在JS逆向中的应用。
JSRPC工作原理
案例
先抓个包看看是哪个接口
a:三十多位随机值
o:g.a.sign(a + s() (e.data) + n)
n:时间戳
email:SG_sm4encrypt("[email protected]","N200y834yEhD5gX5")
s()(e.data):{"email":SG_sm4encrypt("[email protected]","N200y834yEhD5gX5"),"simpleCaptcha":"YNS2a"}
param:g.a.globalEncrypt(a + s() (e.data) + o)
t:时间戳,0
Requesttime:g.a.globalEncrypt(t)
这些可以通过控制台进行调试出来
第二种:在控制台调试出相应函数全局搜索
全局搜索
至此函数所用到的加密参数都知道了,a是三十多位的随机值可以写死,s() (e.data) 里面带有邮箱和图形验证码,o的加密公式也知道了,n是时间戳,t是时间戳,其他:
param的值就是:SG_sm4encrypt(a + s() (e.data) + o,'N200y834yEhD5gX5')
Requesttime的值就是:SG_sm4encrypt(t,'N200y834yEhD5gX5')
JSRPC案例
function
Hlclient
(
wsURL
)
{
this
.wsURL = wsURL;
this
.handlers = {
_execjs
:
function
(
resolve, param
)
{
var
res =
eval
(param)
if
(!res) {
resolve(
"没有返回值"
)
}
else
{
resolve(res)
}
}
};
this
.socket =
undefined
;
if
(!wsURL) {
throw
new
Error
(
'wsURL can not be empty!!'
)
}
this
.connect()
}
Hlclient.prototype.connect =
function
(
)
{
console
.log(
'begin of connect to wsURL: '
+
this
.wsURL);
var
_this =
this
;
try
{
this
.socket =
new
WebSocket(
this
.wsURL);
this
.socket.onmessage =
function
(
e
)
{
_this.handlerRequest(e.data)
}
}
catch
(e) {
console
.log(
"connection failed,reconnect after 10s"
);
setTimeout(
function
(
)
{
_this.connect()
},
10000
)
}
this
.socket.onclose =
function
(
)
{
console
.log(
'rpc已关闭'
);
setTimeout(
function
(
)
{
_this.connect()
},
10000
)
}
this
.socket.addEventListener(
'open'
, (event) => {
console
.log(
"rpc连接成功"
);
});
this
.socket.addEventListener(
'error'
, (event) => {
console
.error(
'rpc连接出错,请检查是否打开服务端:'
, event.error);
});
};
Hlclient.prototype.send =
function
(
msg
)
{
this
.socket.send(msg)
}
Hlclient.prototype.regAction =
function
(
func_name, func
)
{
if
(
typeof
func_name !==
'string'
) {
throw
new
Error
(
"an func_name must be string"
);
}
if
(
typeof
func !==
'function'
) {
throw
new
Error
(
"must be function"
);
}
console
.log(
"register func_name: "
+ func_name);
this
.handlers[func_name] = func;
return
true
}
//收到消息后这里处理,
Hlclient.prototype.handlerRequest =
function
(
requestJson
)
{
var
_this =
this
;
try
{
var
result =
JSON
.parse(requestJson)
}
catch
(error) {
console
.log(
"catch error"
, requestJson);
result = transjson(requestJson)
}
//console.log(result)
if
(!result[
'action'
]) {
this
.sendResult(
''
,
'need request param {action}'
);
return
}
var
action = result[
"action"
]
var
theHandler =
this
.handlers[action];
if
(!theHandler) {
this
.sendResult(action,
'action not found'
);
return
}
try
{
if
(!result[
"param"
]) {
theHandler(
function
(
response
)
{
_this.sendResult(action, response);
})
return
}
var
param = result[
"param"
]
try
{
param =
JSON
.parse(param)
}
catch
(e) {}
theHandler(
function
(
response
)
{
_this.sendResult(action, response);
}, param)
}
catch
(e) {
console
.log(
"error: "
+ e);
_this.sendResult(action, e);
}
}
Hlclient.prototype.sendResult =
function
(
action, e
)
{
if
(
typeof
e ===
'object'
&& e !==
null
) {
try
{
e =
JSON
.stringify(e)
}
catch
(v) {
console
.log(v)
//不是json无需操作
}
}
this
.send(action + atob(
"aGxeX14"
) + e);
}
function
transjson
(
formdata
)
{
var
regex =
/"action":(?<actionName>.*?),/g
var
actionName = regex.exec(formdata).groups.actionName
stringfystring = formdata.match(
/{..data..:.*..w+..:s...*?..}/g
).pop()
stringfystring = stringfystring.replace(
/\"/g
,
'"'
)
paramstring =
JSON
.parse(stringfystring)
tens =
`{"action":`
+ actionName +
`,"param":{}}`
tjson =
JSON
.parse(tens)
tjson.param = paramstring
return
tjson
}
然后再控制台建立链接JSRPC服务器的通信
// 注入环境后连接通信
var
demo =
new
Hlclient(
"ws://127.0.0.1:12080/ws?group=zzz"
);
// 可选
//var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=zzz&clientId=hliang/"+new Date().getTime())
后续就是需要注册需要调用哪个函数的方法,JSRPC作者也是提供了demo,过一遍就行,这里不做解释,这里我们只需要注册相应调用函数的方法就可以了
demo.regAction(
"SG_sm3encrypt"
,
function
(
resolve,param
)
{
//这样添加了一个param参数,http接口带上它,这里就能获得
var
o = SG_sm3encrypt(param)
resolve(o);
})
demo.regAction(
"SG_sm4encrypt"
,
function
(
resolve,param
)
{
//这里还是param参数 param里面的key 是先这里写,但到时候传接口就必须对应的上
res=SG_sm4encrypt(param[
"value"
],param[
"key"
])
resolve(res);
})
然后编写脚本识别图形验证码获取图形验证码的值,带入函数中即可,核心代码逻辑就这些
那么解密过程也是同理,后续就是与burp联动这些了,有时间再分享。
原文始发于微信公众号(极星信安):SRC思路分享-JS逆向(jsrpc运用)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论