记一次对捕获的样本进行分析

之所以开始学习V8漏洞利用,就是起源于需要对一个捕获到的样本进行分析复现,这里记录一下。

解混淆

抓到的样本跟正常情况下的JavaScript代码差不多,都是有一坨,这个时候需要对代码进行美化,js代码美化的工具一堆。

美化后就是需要对代码进行分析了,最开始有一个变量:

1
const a = ['w79PNDLDqw==', 'w4F7ccK9w54=', 'wq0pw4bCi8OF', 'P8OtSsOnw4dQw6F0A8KlPGLCl8O7w5LCpMOmw60zd8Ku', 'w6lSSMKfw4I=', 'w6rDo8KZwpIe', 'wrjDpjxVw5g=', 'FcKGYQLDuw==', 'wrldw4PDsXk=', 'wo90w6XDi34=', 'wrYAblPCpA==', 'wr3CpFjDjMKh', 'w5cwwqTCocOX', 'wrPCtcKawpHDkQ==', 'w6Auw7PDgAU=', 'RMKIwrcWfg==', 'wrInW8KUMQ==', 'QsOIw6xXGQ==', 'woMYw7pQwo9Iw4g2wrDDjMOq', 'woIhW8KgKcKiU8KIEsKcw6XCuBgmwpxdwp5/YlbCjw==', 'w6U2w4TDpRTDoBA=', 'QAvDqDBLBsOjCHpgc1E6wrk8JX3DjUfDkVpcwoPDow==', 'wqPCkcK+wqQ=', 'wpMrQcKmL8K+BsOERMOTwrw=', 'JsO2wpjDlQzClVs=', 'w6LDm8OLwoE=', 'Aj/DpRZc', 'w73DkV5LTw==', 'wqfChsKiwqTDj18rXCg=', 'wozCiHJO', 'fULDnwI=', 'w4pFw5DCl8OI', 'w7o7wqzCjcOU', 'JcOwU8O4w5A=', 'wpfDnwJkw4g=', 'woIbf1DCmQ==', 'CxDDthhh', 'w4DCuzMmDw==', 'WCFFRDc=', 'E8K+Yh7DpQ==', 'w755ZsK9dw==', 'w4RVBsK9aQ==', 'w6kRwofCvcOO', 'LhPCg15ba8O4EGp7GD8qw5QnPA==', 'woUyw7LCmMON', 'wrPCgcK8wr/DrA==', 'w4bDpUxydsO3', 'EsKzSQHDgiM=', 'wr7CuH/DrMKG', 'w73DicKCwpEs', 'w6o8w4fDsgnDpA==', 'wobChHBFwpdA', 'w5vCuDEhFg==', 'SMKybsKQwqw=', 'agFzZik=', 'FxkTcy8=', 'w4XDvsKO', 'w6Jlw47DvsOWw5dXag==', 'w6TDvsKNwowxwoA=', 'wqxEMF/Cl8Kk', 'w7bCkwoIMcOQ', 'woVFPyHCk1PDqj8=', 'w4J7wpDChw==', 'AMKzTMOr', 'NcOswobDjQ==', 'w59lO8KjajrDk8Odwp4=', 'wpMyfETCncO1GF97', 'w7wRwrvCm8Ou', 'woYKw5LCsw==', 'w4Vuw4XDvg==', 'wpzCgHJXwoY=', 'wqdmw4dWOA==', 'wr7DojlEw7Y=', 'wr7Dpzdew7Yq', 'VsKNwqUJc8Kd', 'w5d2wpPCgE/CncK5wonCkBDCpsKNw70='];

随后定义了一个b函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
const b = function (c, d) {
c = c - 0x0;
let e = a[c];
if (b['SOSnEX'] === undefined) {
(function () {
let h;
try {
const j = Function('return\x20(function()\x20' + '{}.constructor(\x22return\x20this\x22)(\x20)' + ');');
h = j();
} catch (k) {
h = window;
}
const i = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
h['atob'] || (h['atob'] = function (l) {
const m = String(l)['replace'](/=+$/, '');
let n = '';
for (let o = 0x0, p, q, r = 0x0; q = m['charAt'](r++); ~q && (p = o % 0x4 ? p * 0x40 + q : q, o++ % 0x4) ? n += String['fromCharCode'](0xff & p >> (-0x2 * o & 0x6)) : 0x0) {
q = i['indexOf'](q);
}
return n;
});
}());
const g = function (h, l) {
let m = [],
n = 0x0,
o, p = '',
q = '';
h = atob(h);
for (let t = 0x0, u = h['length']; t < u; t++) {
q += '%' + ('00' + h['charCodeAt'](t)['toString'](0x10))['slice'](-0x2);
}
h = decodeURIComponent(q);
let r;
for (r = 0x0; r < 0x100; r++) {
m[r] = r;
}
for (r = 0x0; r < 0x100; r++) {
n = (n + m[r] + l['charCodeAt'](r % l['length'])) % 0x100;
o = m[r];
m[r] = m[n];
m[n] = o;
}
r = 0x0;
n = 0x0;
for (let v = 0x0; v < h['length']; v++) {
r = (r + 0x1) % 0x100;
n = (n + m[r]) % 0x100;
o = m[r];
m[r] = m[n];
m[n] = o;
p += String['fromCharCode'](h['charCodeAt'](v) ^ m[(m[r] + m[n]) % 0x100]);
}
return p;
};
b['QOnWUq'] = g;
b['oBsFAj'] = {};
b['SOSnEX'] = !![];
}
const f = b['oBsFAj'][c];
if (f === undefined) {
if (b['KJgxSv'] === undefined) {
const h = function (i) {
this['EkZxlG'] = i;
this['ckjFsJ'] = [0x1, 0x0, 0x0];
this['lbERAb'] = function () {
return 'newState';
};
this['mDWdPl'] = '\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*';
this['tZNXmI'] = '[\x27|\x22].+[\x27|\x22];?\x20*}';
};
h['prototype']['Xwletx'] = function () {
const i = new RegExp(this['mDWdPl'] + this['tZNXmI']);
const j = i['test'](this['lbERAb']['toString']()) ? --this['ckjFsJ'][0x1] : --this['ckjFsJ'][0x0];
return this['tKNvcJ'](j);
};
h['prototype']['tKNvcJ'] = function (i) {
if (!Boolean(~i)) {
return i;
}
return this['uWXLxq'](this['EkZxlG']);
};
h['prototype']['uWXLxq'] = function (j) {
for (let k = 0x0, l = this['ckjFsJ']['length']; k < l; k++) {
this['ckjFsJ']['push'](Math['round'](Math['random']()));
l = this['ckjFsJ']['length'];
}
console.log("test1: ", k, l);
return j(this['ckjFsJ'][0x0]);
};
new h(b)['Xwletx']();
b['KJgxSv'] = !![];
}
e = b['QOnWUq'](e, d);
b['oBsFAj'][c] = e;
} else {
e = f;
}
return e;
};

然后在之后的代码中有一堆:b('0x0', 'gW&A')这样的代码,很明显,代码是被混淆的,解混淆函数就是b函数,所以随后需要对b函数进行分析,然后得到解混淆的脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import base64
def b(n, char):
a = ['w79PNDLDqw==', 'w4F7ccK9w54=', 'wq0pw4bCi8OF', 'P8OtSsOnw4dQw6F0A8KlPGLCl8O7w5LCpMOmw60zd8Ku', 'w6lSSMKfw4I=', 'w6rDo8KZwpIe', 'wrjDpjxVw5g=', 'FcKGYQLDuw==', 'wrldw4PDsXk=', 'wo90w6XDi34=', 'wrYAblPCpA==', 'wr3CpFjDjMKh', 'w5cwwqTCocOX', 'wrPCtcKawpHDkQ==', 'w6Auw7PDgAU=', 'RMKIwrcWfg==', 'wrInW8KUMQ==', 'QsOIw6xXGQ==', 'woMYw7pQwo9Iw4g2wrDDjMOq', 'woIhW8KgKcKiU8KIEsKcw6XCuBgmwpxdwp5/YlbCjw==', 'w6U2w4TDpRTDoBA=', 'QAvDqDBLBsOjCHpgc1E6wrk8JX3DjUfDkVpcwoPDow==', 'wqPCkcK+wqQ=', 'wpMrQcKmL8K+BsOERMOTwrw=', 'JsO2wpjDlQzClVs=', 'w6LDm8OLwoE=', 'Aj/DpRZc', 'w73DkV5LTw==', 'wqfChsKiwqTDj18rXCg=', 'wozCiHJO', 'fULDnwI=', 'w4pFw5DCl8OI', 'w7o7wqzCjcOU', 'JcOwU8O4w5A=', 'wpfDnwJkw4g=', 'woIbf1DCmQ==', 'CxDDthhh', 'w4DCuzMmDw==', 'WCFFRDc=', 'E8K+Yh7DpQ==', 'w755ZsK9dw==', 'w4RVBsK9aQ==', 'w6kRwofCvcOO', 'LhPCg15ba8O4EGp7GD8qw5QnPA==', 'woUyw7LCmMON', 'wrPCgcK8wr/DrA==', 'w4bDpUxydsO3', 'EsKzSQHDgiM=', 'wr7CuH/DrMKG', 'w73DicKCwpEs', 'w6o8w4fDsgnDpA==', 'wobChHBFwpdA', 'w5vCuDEhFg==', 'SMKybsKQwqw=', 'agFzZik=', 'FxkTcy8=', 'w4XDvsKO', 'w6Jlw47DvsOWw5dXag==', 'w6TDvsKNwowxwoA=', 'wqxEMF/Cl8Kk', 'w7bCkwoIMcOQ', 'woVFPyHCk1PDqj8=', 'w4J7wpDChw==', 'AMKzTMOr', 'NcOswobDjQ==', 'w59lO8KjajrDk8Odwp4=', 'wpMyfETCncO1GF97', 'w7wRwrvCm8Ou', 'woYKw5LCsw==', 'w4Vuw4XDvg==', 'wpzCgHJXwoY=', 'wqdmw4dWOA==', 'wr7DojlEw7Y=', 'wr7Dpzdew7Yq', 'VsKNwqUJc8Kd', 'w5d2wpPCgE/CncK5wonCkBDCpsKNw70=']
h = base64.b64decode(a[int(n, 16)]).decode()
m = []
for x in range(0x100):
m.append(x)
n = 0
l = char.encode()
for x in range(0x100):
n = (n + m[x] + l[x%len(l)]) % 0x100
o = m[x]
m[x] = m[n]
m[n] = o
r = 0
n = 0
p = b""
for x in h:
r = (r + 1)%0x100
n = (n + m[r])%0x100
o = m[r]
m[r] = m[n]
m[n] = o
p += bytes([(ord(x) ^ m[(m[r]+m[n])%0x100])])
return p

f = open('index.html', 'r')
data = f.read()
f.close()

import re

re_list = re.findall("b\('(.+?)','(.+?)'\)", data)
for r in re_list:
res = b(r[0], r[1])
print(r, res)

data = data.replace("b('"+r[0]+"','"+r[1]+"')", repr(res.decode('utf-8')))
print(data)

混淆部分并不是很难,但是在研究b函数的过程中发现一个神奇的函数

反美化

1
2
3
4
5
6
7
8
h['prototype']['uWXLxq'] = function (j) {
for (let k = 0x0, l = this['ckjFsJ']['length']; k < l; k++) {
this['ckjFsJ']['push'](Math['round'](Math['random']()));
l = this['ckjFsJ']['length'];
}
console.log("test1: ", k, l);
return j(this['ckjFsJ'][0x0]);
};

这是一个死循环函数,而程序总会运行到这,所以调试运行美化后的样本,总会进行入死循环,导致无法执行后续流程。

深入研究发现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const h = function (i) {
this['EkZxlG'] = i;
this['ckjFsJ'] = [0x1, 0x0, 0x0];
this['lbERAb'] = function () {
return 'newState';
};
this['mDWdPl'] = '\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*';
this['tZNXmI'] = '[\x27|\x22].+[\x27|\x22];?\x20*}';
};
h['prototype']['Xwletx'] = function () {
const i = new RegExp(this['mDWdPl'] + this['tZNXmI']);
const j = i['test'](this['lbERAb']['toString']()) ? --this['ckjFsJ'][0x1] : --this['ckjFsJ'][0x0];
return this['tKNvcJ'](j);
};
h['prototype']['tKNvcJ'] = function (i) {
if (!Boolean(~i)) {
return i;
}
return this['uWXLxq'](this['EkZxlG']);
};

关键代码在上述这部分,Xwletx函数对lbERAb函数进行了正则匹配,但是按照上面的代码匹配总是失败,所以之后调用了:this['tKNvcJ'](0) -> !Boolean(~0) == false -> this['uWXLxq'](this['EkZxlG']) <- 死循环函数

随后发现,原始代码中,lbERAb函数为:this['lbERAb']=function(){return 'newState';};,如果我这么定义代码,正则匹配就能匹配成功,随后的流程就是:this['tKNvcJ'](1) -> !Boolean(~1) == true-> return 1,就不会进行死循环函数了。

从上诉逻辑可以看出,该函数就是专门用来针对代码美化的,不过单了解了其作用后,直接把这块的逻辑删除就好了。

而且这种反美化的代码还不止一处,不过这种的特点是正则匹配,遇到这种,大概率都是可以删掉的。

记一次对捕获的样本进行分析

https://nobb.site/2021/12/16/0x71/

Author

Hcamael

Posted on

2021-12-16

Updated on

2021-12-30

Licensed under