某站点SIgn值逆向

admin 2023年2月16日21:22:11评论78 views字数 4537阅读15分7秒阅读模式

随着网络安全的发展,如何保护API接口的数据安全性成了一个很重要的问题:

  • 请求身份来源是否合法?

  • 请求参数是否被篡改?

  • 请求的唯一性


面临以上一些问题,Sign(签名)也被设计出来保护API接口数据的安全。更多应用厂商也开始意识到,很多应用系统已经开始采用验证签名的方法来保护,防止一些攻击,如 Replay attack (重放攻击),Data tampering(数据篡改)。

但是加上Sign并不是说其它漏洞或者安全问题就不存在,还是需要我们进行渗透测试,验证系统是否安全,有防自然有攻,还是那句话,没有绝对安全的系统。

在应用系统加上签名后,进行Web端渗透测试时就面临了一些麻烦,不能重放,修改请求数据,使用 Sign 值的应用系统确实提高了一定的安全性,但是还是存在很大的安全隐患。Sign 值在生成的过程中是在Web前端完成的,Web前端代码对我们可见,虽说大多数进行过混淆,但是只要去找,一定可以将应用系统 Sign 值生成方式逆向出来。

抓包分析

以下是对某个站点Sign值的逆向过程,如有错误请各位指正。

打开应用系统尝试抓包测试,发现应用系统使用Sign来验证接口安全,修改参数则提示签名校验失败。


某站点SIgn值逆向


简单观察一下Header头,Customized-Field 和 Sign 是重点

某站点SIgn值逆向

Customized-Field 和 Sign 分析

Customized-Field 头由三个值组成:

  • api 请求接口URL

  • client-type 字面意思为连接的类型

  • timestamp 时间戳(timestamp)是指格林威治时间1970年01月01日00时00分00秒起至现在的总秒数。

Sign 头:

  • 长度为64位数字加大写字母组合

根据了解的一些加密算法特征,猜测为SHA256加密算法。

参考常见的一些加密编码类型的密文特征:

https://cloud.tencent.com/developer/article/1748394

前端代码分析

通过简单的对请求进行分析,找到了一些关键点,现在我们在控制台中去查找一下这些关键字:

Sign值

F12 打开控制台,找到调试器,CTRL + F 查找Sign值(PS-1):

PS-1:JS逆向定位技巧有很多,这里采用全局搜索关键字来进行定位,介绍几个常用的

  • 全局搜索关键字,如 sign , password=, .post , .get

  • Dom元素事件监听

  • xhr断点

  • Initator栈追踪


某站点SIgn值逆向

经过全局查找(PS-2),可以看到四个比较可能是Sign值生成的位置。

PS-2:目标系统使用VUE前端框架,在生成JS文件时一般如**_app.js**形式的文件是主要入口文件,所以在逆向查找时从该文件进入

先看 this.headers.sign, 进入该行代码查看:

某站点SIgn值逆向

该位置为某些接口的验证

进入 sign: Object(c.b) (l, n, a)

某站点SIgn值逆向

某站点SIgn值逆向

简单查看可以确认是生成Sign值和Customized-Field的位置,在这行打断点开始调试:

某站点SIgn值逆向


打上断点后刷新网站,运行到断点处停止,在控制台打印 sign: Object(c.b) (l, n, a) 各个参数看看:

1
2
3
4
5
6
7
l
"{"api":"/imessage/queryMessage","client-type":"web","timestamp":"1662359962053"}"
c.b
function p(e, t, n)

a
Object { }
  • l 为Customized-Field值

  • c.b 为 function p

  • a 为空

继续跟进 function p(e, t, n)

某站点SIgn值逆向

运气很好,跟进进来直接看到我们需要的东西

1
2
3
4
5
6
7
8
9
10
11
12
13
14
p = function (e, t, n) {
var r = '',
o = d(s({
}, n, {
'Customized-Field': e
}));
for (var c in o) {
var l = o[c] || 0 === o[c] ? 'object' === a(o[c]) ? JSON.stringify(o[c]) : o[c] : '';
0 === l || l ? r += ''.concat(c, '=').concat(l, '&') : delete n[c]
}
r += 'key='.concat(u);
var f = i.a.HmacSHA256(r, u);
return i.a.enc.Hex.stringify(f).toUpperCase()
}

现在可以确认加密编码方式为 Hmac-SHA256

有部分看不懂部的代码,打印一下输出。

i.a.enc

某站点SIgn值逆向

现在知道是什么意思了,代表调用的加密方法,其它情况也可以这样去判断,对不了解的函数直接谷歌查找一下就OK。

继续跟进 funtion p

某站点SIgn值逆向

跟进函数 d()

1
2
3
4
5
function d(e) {
for (var t = Object.keys(e).sort(), n = {
}, r = 0; r < t.length; r++) n[t[r]] = e[t[r]];
return n
}

Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致。

默认情况下,sort() 方法将按字母和升序将值作为字符串进行排序。

对 e 进行了排序处理,按照数组首字母进行升序排序。

继续跟进 s

某站点SIgn值逆向

1
2
3
4
5
6
7
8
9
10
11
  for (var t = 1; t < arguments.length; t++) {
var n = null != arguments[t] ? arguments[t] : {
};
t % 2 ? o(Object(n), !0).forEach((function (t) {
c(e, t, n[t])
})) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(n)) : o(Object(n)).forEach((function (t) {
Object.defineProperty(e, t, Object.getOwnPropertyDescriptor(n, t))
}))
}
return e
}

forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数。注意:forEach() 对于空数组是不会执行回调函数的。

Object.getOwnPropertyDescriptors() 方法用来获取一个对象的所有自身属性的描述符。

还是不太能看懂要干什么,继续跟进看输出

某站点SIgn值逆向

虽然具体不理解 s() 要干什么,但是知道 **s()**是什么也行。大致对 e 进行处理,可以看到 e 是 参数 Customized-Field 。

某站点SIgn值逆向

那么 o = d(s({}, n, {‘Customized-Field’: e})) ,就是进行了数组排序处理。

继续更进:

某站点SIgn值逆向

1
2
3
4
5
for (var c in o) {
var l = o[c] || 0 === o[c] ? 'object' === a(o[c]) ? JSON.stringify(o[c]) : o[c] : '';
0 === l || l ? r += ''.concat(c, '=').concat(l, '&') : delete n[c]
}
r += 'key='.concat(u);

PS-3: 以上调试时未在请求中post数据

再请求中带上POST数据后

某站点SIgn值逆向

对排序过后的 o 进行重组,重组格式大致如下:

1
"Customized-Field={"api":"/user/institutionListByAccount","client-type":"web","timestamp":"1662367339537"}&account=admin&key=JQGyyyXXXXXCA9WPEx72jXXXXXXUNpEK1FL6B" 

Customized-Field + = + {排序后api, client-type, timestamp} + & 参数(字母顺序升序排序)+ & + 参数值 + & + key值(不参与排序)

继续跟进,Sign值生成

某站点SIgn值逆向

到这不用关注加密是怎么执行,步出得到结果就行,控制台执行 i.a.enc.Hex.stringify(f).toUpperCase()

某站点SIgn值逆向

好了,现在已经得到Sign值的加密以及生成方法了。整个流程大致如下:

某站点SIgn值逆向

整个分析过程也比较简单,第一步便找到入口点,那后面的只需要时间就能解决了。下面使用python来实现一下加密代码:

Python代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import hmac
from hashlib import sha256
import time
import json
import operator


timestamp = str(time.time()*1000)[0:-4][0:-1] # 返回当前时间的时间戳(1970纪元后经过的浮点秒数)。
key = "JQGyyy1dP2ku1XXXXXXXXX2S3UIf1n0uUNpEK1FL6B"


if __name__ == "__main__":
url = r'/file/download?fileName=&type=1' # GET 参数
data = """{"taskId":2,"pageNum":1,"pageSize":10}""" # POST参数
datan = dict(sorted(json.loads(data).items(), key=operator.itemgetter(0))) # POST参数str型使用json处理,按照首字母顺序进行重排列
post_datam = str(datan).replace('"',"").replace(':','=').replace(",","&").replace("{","&").replace("}","&").replace("'","").replace(" ","")
get_params = "&" + url.split("?")[1] + "&"
signdata = 'Customized-Field={' + '"api":"{}","client-type":"web"'.format(url) + "," + '"timestamp":"{}"'.format(timestamp) + "}" + '{}'.format(params) + "key={}".format(key)
sign = hmac.new(bytes(key, encoding='UTF-8'), bytes(signdata, encoding='UTF-8'), digestmod=sha256).hexdigest() # hmac-sha256加密
print(timestamp)
# print(signdata)
print(sign.upper())

PS-4: 代码写的太烂,各位师傅勿视。

某站点SIgn值逆向

目前第一版代码如上,后续会配合@f0ng师傅写的 项目autoDecoder 结合在BurpSuite中实现自动更新Sign值和Customized-Field。

项目地址:https://github.com/f0ng/autoDecoder

参考:

https://juejin.cn/post/7037704683468619807


原文始发于微信公众号(Aizero安全团队):某站点SIgn值逆向

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年2月16日21:22:11
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   某站点SIgn值逆向http://cn-sec.com/archives/1282195.html

发表评论

匿名网友 填写信息