习题牛刀小试: 找出Flag
可见提示是 hook eval 那我们就试一下,那我们就用油猴脚本hook一下
var _eval=eval;
eval=function (){
console.log(arguments)
return _eval(arguments)
}
报了一个错,不能在严格模式下运行这个脚本,那么我们就取消严格模式,并且在一开始就hook他的eval函数
出现了一个假答案,额...(哼恶趣味),输入假答案看看是啥
额过分还有检测,那就上绝招,用代理器hook一下eval函数
eval = new Proxy(eval,{
apply(target, thisArg, argArray) {
let result = Reflect.apply(target, thisArg, argArray)
console.log(`function name is ${target.name}, thisArg is ${thisArg}, argArray is [${argArray}], result is ${result}.`)
return result
},
construct(target, argArray, newTarget) {
var result = Reflect.construct(target, argArray, newTarget)
console.log(`construct function name is ${target.name}, argArray is [${argArray}], result is ${JSON.stringify(result)}.`)
return result;
}
, get(target, p, receiver) {
let res=Reflect.get(target, p, receiver);
console.log(`get ${target.name} ${res}`)
return res
}
,set(target, p, value, receiver) {
let res=Reflect.set(target, p, value, receiver);
console.log(` set ${target.name} ${value}`)
return res;
}
})
让我看到了吧,调用了toString,跟进去看一下,打一个断点,f10开始
混淆了5555,看着好乱,我们就一个个的来看看它做了什么
eval[_0x5572a4(0x132)]() === _0x5572a4(0x13d) ? window['$eval1'] = !![] : window[_0x5572a4(0x137)] = ![],
Function[_0x5572a4(0x134)][_0x5572a4(0x132)][_0x5572a4(0x136)](eval) === 'function\x20eval()\x20{\x20[native\x20code]\x20}' ? window[_0x5572a4(0x131)] = !![] : window[_0x5572a4(0x131)] = ![];
_0x5572a4(0x132)="toString"
_0x5572a4(0x13d)="function eval() { [native code] }"
_0x5572a4(0x137)="$eval1"
_0x5572a4(0x134)="prototype"
_0x5572a4(0x132)="toString"
_0x5572a4(0x136)="call"
_0x5572a4(0x131)="$eval2"
翻译一下就是
eval["toString"]=="function eval() { [native code] }"?window['$eval1']=!![]:window['$eval1']=![]
Function['prototype']['toString']['call'](eval)==='function\x20eval()\x20{\x20[native\x20code]\x20}'?window["$eval2"]=!![]:window["$eval2"]=![]
那这样就清晰了,蓝师傅监控了toString方法和原型链上的toString方法
那么我们hook掉这两个方法就好了,最后的代码如下
var _eval=eval;
eval=function (){
console.log(arguments)
return _eval(arguments)
}
eval.toString=function (){
console.log(1111)
return "function eval() { [native code] }"
}
Function.prototype.toString=function(){return "function eval() { [native code] }"}
接着刷新一下界面看一下
输入一下啊欢迎来到大数据安全技术学习JS课程
,成功了
题目 2021年6月份JS逆向第三题
观察题目只有一个按钮点击后出现浏览器的设备指纹
查看网络请求看他有没有发包
有的那就说明是通过后端校验的,这是我们可以hook AJAX或者通过查看网络请求的调用栈来获得发包的内容,我们采用查看包的调用栈的方式来跟踪,
在app.js中跟进去看一下
this.fingerprint = this.$Encrypt.sign(e),
p()({
method: "post",
url: "http://www.dtasecurity.cn:35555/subject3202106",
data: {
sign: this.fingerprint,
fingerprint: window.btoa(e)
},
transformRequest: [function (e) {
var t = "";
for (var a in e)
t += encodeURIComponent(a) + "=" + encodeURIComponent(e[a]) + "&";
return t = t.substring(0, t.lastIndexOf("&"))
}
],
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
发包方式知道了,关键参数就是sign和fingerprint,先看一下sign是如何生成的,追踪进去this.$Encrypt.sign
和e,e是明文的很容易就能看懂关键是sign函数我们继续跟踪
发现了md5字样菜猜测是md5算法,尝试一下,发现一模一样那么这里就是md5算法了
接着分析fingerprint也就是e是怎么来的,可以看到下面的这一行代码,那么就分析getfingerprint函数,跟踪进去
var e = this.getfingerprint();
getfingerprint: function () {
var e = []
, t = e.push.bind(e);
return [navigator, location, history].forEach(function (e) {
for (var a in _()(window, e),
e) {
var n = e[a];
n && "string" == typeof n && t(a + ":" + n)
}
}),
e.join("###")
}
getfingerprint函数非常的简单,可以通过nodejs来模拟一下,尝试补出他的环境,如下图开始补环境
let rawindexof = String.prototype.indexOf
String.prototype.indexOf = function (str) {
var res = rawindexof.call(this, str)
console.log(`[String] "${this}" is indexof "${str}", res is ${res}`)
return res
}
let mydocument = {
"head": {},
"documentElement": {
"getAttribute": function () {
}
},
"readyState": "complete",
"addEventListener": function () {
},
"createElement": function () {
return {}
},
"getElementsByTagName": function (str) {
console.log(str)
if (str === "meta") {
let metaRes = []
metaRes["meta-pro"] = {
"content": {
"length": 6
}
}
return metaRes
}
}
}
let mynavigator = Object.create({
"vendorSub": "",
"productSub": "20030107",
"vendor": "Google Inc.",
"maxTouchPoints": 0,
"userActivation": {},
"doNotTrack": null,
"geolocation": {},
"connection": {},
"plugins": {
"0": {
"0": {}
},
"1": {
"0": {}
},
"2": {
"0": {},
"1": {}
}
},
"mimeTypes": {
"0": {},
"1": {},
"2": {},
"3": {}
},
"webkitTemporaryStorage": {},
"webkitPersistentStorage": {},
"hardwareConcurrency": 4,
"cookieEnabled": true,
"appCodeName": "Mozilla",
"appName": "Netscape",
"appVersion": "5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36",
"platform": "Linux x86_64",
"product": "Gecko",
"userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36",
"language": "zh",
"languages": [
"zh",
"en-US",
"en"
],
"onLine": true,
"webdriver": false,
"scheduling": {},
"mediaCapabilities": {},
"permissions": {},
"mediaSession": {}
});
let mysrceen = Object.create({
height: 852,
width: 1918,
colorDepth: 24,
});
let mylocation = {
"ancestorOrigins": {},
"href": "http://www.dtasecurity.cn:11080/details?url=http%3A%2F%2Fwww.dtasecurity.cn%3A30080%2Fsubject%2F%23%2F202106subject3",
"origin": "http://www.dtasecurity.cn:11080",
"protocol": "http:",
"host": "www.dtasecurity.cn:11080",
"hostname": "www.dtasecurity.cn",
"port": "11080",
"pathname": "/details",
"search": "?url=http%3A%2F%2Fwww.dtasecurity.cn%3A30080%2Fsubject%2F%23%2F202106subject3",
"hash": ""
}
let myhistory = {
"length": 4,
"scrollRestoration": "manual",
"state": {
"key": "680.400"
}
}
let mywindow = {
XMLHttpRequest: function () {
},
sessionStorage: {},
localStorage: {},
navigator: mynavigator,
scrollTo: function () {
},
addEventListener: function () {
},
attachEvent: function () {
},
screen: mysrceen,
location: mylocation,
chrome: {},
document: mydocument,
};
let Image = function () {
};
let rawstringify = JSON.stringify;
JSON.stringify = function (Object) {
if ((Object?.value ?? Object) === global) {
return "global"
} else {
return rawstringify(Object)
}
}
function checkproxy() {
//Object.keys(window)
window.a = {
"b": {
"c": {
"d": 123
}
}
}
window.a.b.c.d = 456
window.a.b
window.btoa("123")
window.atob.name
"c" in window.a
delete window.a.b
Object.defineProperty(window, "b", {
value: "bbb"
})
Object.getOwnPropertyDescriptor(window, "b")
Object.getPrototypeOf(window)
Object.setPrototypeOf(window, {"dta": "dta"})
// for (let windowKey in window) {
// windowKey
// }
Object.preventExtensions(window)
Object.isExtensible(window)
}
function getMethodHandler(WatchName) {
let methodhandler = {
apply(target, thisArg, argArray) {
let result = Reflect.apply(target, thisArg, argArray)
console.log(`[${WatchName}] apply function name is [${target.name}], argArray is [${argArray}], result is [${result}].`)
return result
},
construct(target, argArray, newTarget) {
var result = Reflect.construct(target, argArray, newTarget)
console.log(`[${WatchName}] construct function name is [${target.name}], argArray is [${argArray}], result is [${JSON.stringify(result)}].`)
return result;
}
}
return methodhandler
}
function getObjhandler(WatchName) {
let handler = {
get(target, propKey, receiver) {
let result = Reflect.get(target, propKey, receiver)
if (result instanceof Object) {
if (typeof result === "function") {
//console.log(`[${WatchName}] getting propKey is [${propKey}] , it is function`)
//return new Proxy(result,getMethodHandler(WatchName))
} else {
console.log(`[${WatchName}] getting propKey is [${propKey}], result is [${JSON.stringify(result)}]`);
}
return new Proxy(result, getObjhandler(`${WatchName}.${propKey}`))
}
console.log(`[${WatchName}] getting propKey is [${propKey?.description ?? propKey}], result is [${result}]`);
return result;
},
set(target, propKey, value, receiver) {
if (value instanceof Object) {
console.log(`[${WatchName}] setting propKey is [${propKey}], value is [${JSON.stringify(value)}]`);
} else {
console.log(`[${WatchName}] setting propKey is [${propKey}], value is [${value}]`);
}
return Reflect.set(target, propKey, value, receiver);
},
has(target, propKey) {
var result = Reflect.has(target, propKey);
console.log(`[${WatchName}] has propKey [${propKey}], result is [${result}]`)
return result;
},
deleteProperty(target, propKey) {
var result = Reflect.deleteProperty(target, propKey);
console.log(`[${WatchName}] delete propKey [${propKey}], result is [${result}]`)
return result;
},
getOwnPropertyDescriptor(target, propKey) {
var result = Reflect.getOwnPropertyDescriptor(target, propKey);
console.log(`[${WatchName}] getOwnPropertyDescriptor propKey [${propKey}] result is [${JSON.stringify(result)}]`)
return result;
},
defineProperty(target, propKey, attributes) {
var result = Reflect.defineProperty(target, propKey, attributes);
console.log(`[${WatchName}] defineProperty propKey [${propKey}] attributes is [${JSON.stringify(attributes)}], result is [${result}]`)
return result
},
getPrototypeOf(target) {
var result = Reflect.getPrototypeOf(target)
console.log(`[${WatchName}] getPrototypeOf result is [${JSON.stringify(result)}]`)
return result;
},
setPrototypeOf(target, proto) {
console.log(`[${WatchName}] setPrototypeOf proto is [${JSON.stringify(proto)}]`)
return Reflect.setPrototypeOf(target, proto);
},
preventExtensions(target) {
console.log(`[${WatchName}] preventExtensions`)
return Reflect.preventExtensions(target);
},
isExtensible(target) {
var result = Reflect.isExtensible(target)
console.log(`[${WatchName}] isExtensible, result is [${result}]`)
return result;
},
ownKeys(target) {
var result = Reflect.ownKeys(target)
console.log(`[${WatchName}] invoke ownkeys, result is [${JSON.stringify(result)}]`)
return result
},
apply(target, thisArg, argArray) {
let result = Reflect.apply(target, thisArg, argArray)
console.log(`[${WatchName}] apply function name is [${target.name}], argArray is [${argArray}], result is [${result}].`)
return result
},
construct(target, argArray, newTarget) {
var result = Reflect.construct(target, argArray, newTarget)
console.log(`[${WatchName}] construct function name is [${target.name}], argArray is [${argArray}], result is [${JSON.stringify(result)}].`)
return result;
}
}
return handler;
}
const navigator = new Proxy(mynavigator, getObjhandler("navigator"));
const screen = new Proxy(mysrceen, getObjhandler("screen"));
const location = new Proxy(mylocation, getObjhandler("location"));
const document = new Proxy(mydocument, getObjhandler("document"));
const history = new Proxy(myhistory, getObjhandler("history"));
const window = new Proxy(Object.assign(global, mywindow), getObjhandler("window"));
//checkproxy()
module.exports = {
window,
navigator,
screen,
location,
String,
Image,
document,
history
}
(ps:直接用蓝师傅的环境真香哈),之前讲过就不多说了,接着我们遇到了我们的第一个错误_没定义
回到浏览器中查看一下_是个什么东西,发现到了下面这里,然后继续打断点跟踪
var n = r && r.__esModule ? function() {
return r.default
}
查看一下r.default是什么,是一个属性删除函数,那么这一段的逻辑就是,在浏览器上删除不到这些属性,而在nodejs上能删除这些属性,那么其实_方法是无效的我们根本不需要这个删除方法,就把他删掉就好了
可以正常运行
最后打印一下这个匿名方法
console.log((function () {
var e = []
, t = e.push.bind(e);
return [navigator, location, history].forEach(function (e) {
for (var a in e) {
var n = e[a];
n && "string" == typeof n && t(a + ":" + n)
}
}),
e.join("###")
})());
复制上去访问一下看看能不能过
通过了,可以看到蓝师傅的环境真好用
有兴趣可以一起学习一下呀