mfw sigh signature 请求协议分析(2)
mfw sigh signature 请求协议分析
环境
python: 3.8
frida: 12.8.0
objection: 1.8.4
app version: 9.3.7
oauth_signature
202111181138524.png
通过抓包,可以看到有个oauth_signature_method字段为HMAC-SHA1,由此初步推断oauth_signature的加密方法为HMAC-SHA1。
HMAC算法
这里给一下标准HMAC的大致实现,以sha1为例,需要传入key和要加密的文本text
# 伪python代码
def hmac_sha1(key, text):
if len(key) > 64:
key = sha1(key)
key = ljust(64, b'\x00') # 在后面填充\x00,直到长度为64
inner = sha1(key ^ 0x36 + text)
outer = sha1(key ^ 0x5C + inner)
return outer
Java层
之前已经提到过oauth_signature的加密方法是在com.mfw.tnative.AuthorizeHelper类的xAuthencode方法。
202111181138153.png
frida hook一下
// mfw_hmac.js
function dump(name, addr, legnth) {
console.log("======================== " + name + " ============");
console.log(hexdump(addr, {length:legnth||32}));
}
Java.perform(function(){
var helper = Java.use("com.mfw.tnative.AuthorizeHelper");
helper.xAuthencode.implementation = function(ctx, str1, str2, str3, z) {
console.log("xAuthencode-str1", str1);
console.log("xAuthencode-str2", str2);
console.log("xAuthencode-str3", str3);
console.log("xAuthencode-z", z);
var ret = this.xAuthencode(ctx, str1, str2, str3, z);
console.log("xAuthencode-ret", ret);
return ret;
}
})
202111181138798.png
小结一下,第二个参数str2就是要加密的参数,由url和params构造,其他的暂时不分析
固定参数
由于url和params参数经常变动,不利于分析,将加密的参数修改为ever。
// mfw_hmac.js
function dump(name, addr, legnth) {
console.log("======================== " + name + " ============");
console.log(hexdump(addr, {length:legnth||32}));
}
Java.perform(function(){
var helper = Java.use("com.mfw.tnative.AuthorizeHelper");
helper.xAuthencode.implementation = function(ctx, str1, str2, str3, z) {
str1 = "ever";
console.log("xAuthencode-str1", str1);
console.log("xAuthencode-str2", str2);
console.log("xAuthencode-str3", str3);
console.log("xAuthencode-z", z);
var ret = this.xAuthencode(ctx, str1, str2, str3, z);
console.log("xAuthencode-ret", ret);
return ret;
}
})
此时hook的结果为
202111181138635.png
so层
之前提到xAuthencode的真实函数为sub_2E3B8。ida查看
202111181138235.png
同样的,修改a1为_JNIEnv
202111181138994.png
通过Java层的分析,我们知道a4是要加密的参数(native函数的参数是从第二个开始)
202111181138661.png
由于v29 = a4,因此v20就是要加密的字符串。那么sub_2F518就是对v20进行加密,看看sub_2F518
202111181138208.png
有点复杂,先不分析,hook看看它的输入
Java.perform(function(){
var bptr = Module.findBaseAddress("libmfw.so");
var ptr_0x2F518 = bptr.add(0x2F518 + 1);
Interceptor.attach(ptr_0x2F518, {
onEnter: function(args) {
this.arg0 = args[0];
console.log(args[0], args[1], args[2], args[3]);
dump("0x2F518-arg0", args[0]);
dump("0x2F518-arg1", args[1]);
},
onLeave: function(retval) {
dump("0x2F518-arg0-ret", this.arg0);
console.log("\n");
}
})
})
202111181138828.png
202111181138765.png
从图中可以看出,函数执行了多次,不过我们还是能够看到输入的文本ever。可以看到sub_2F518前面还执行了几次,而且看它的输入有点像key,既然这样,我们看一下前面的函数sub_2EA60
202111181138740.png
可以看到函数里面也执行了sub_2F518,hook一下sub_2EA60
Java.perform(function(){
var bptr = Module.findBaseAddress("libmfw.so");
Interceptor.attach(bptr.add(0x2EA60+1),{
onEnter: function(args){
dump("0x2EA60-arg0", args[0]);
console.log("0x2EA60-arg1", args[1].readCString(parseInt(args[2])));
}
})
})
202111181138826.png
我们试着把它作为key,用标准HMAC-SHA1试一试输出
import base64
import hashlib
import hmac
KEY = b'9c2d2df9a049d1c489d084ca535daada&b51c30e9ec2b3beb549cbb2f6e766abd'
s = b'ever'
digest = hmac.new(KEY, s, hashlib.sha1).digest()
s0 = base64.b64encode(digest).decode()
print(s0)
assert s0 == 'gwOgWNY2tQTPMyJ4GIgoBLk9eCQ=', 'Not equal'
202111181139060.png
直接就出来了,说明并没有修改HMAC算法,而且使用的也是标准的sha1算法。
实现
import base64
import hmac
import hashlib
from functools import partial
from urllib.parse import urlencode, quote
KEY = b'9c2d2df9a049d1c489d084ca535daada&b51c30e9ec2b3beb549cbb2f6e766abd'
quote = partial(quote, safe='')
def calc_hmac(url, params, method='GET'):
data = method + '&' + quote(url) + '&' + quote(urlencode(sorted(params)))
data = data.encode('utf8')
digest = hmac.new(KEY, data, hashlib.sha1).digest()
sign = base64.b64encode(digest).decode()
return sign
验证
202111181139637.png
其他
事实上,我们可以在Java层通过hook得出,app是不验证zzzghostsigh参数的,也就是说,zzzghostsigh可以随便赋值,甚至可以不要这个字段,只要oauth_signature是正确的就能正常返回结果。还有就是,请求里面有个oauth_token字段,这个token是不能缺少的,也不能随机生成,暂时没有去研究它的有效时长以及生成的机制。
以上代码仅供把玩,本人并未采集任何数据。