学習目標
今日は社内射撃場に関する質問を 2 問お届けします。質問の難易度は中程度です。テーマは、js コードはブラウザーで実行できますが、nodejs になると、さまざまな環境監視に直面します。どうすればよいですか。これらのテストを回避するには、コピーした js コードを実行し、本体を生徒の視点で説明し、ついでに穴を踏みます (Master Lan yyds)
トピック: 射撃場内 トピック 2
1 特徴の観察
まず質問を入力すると、次の図に示すように、デバイスの指紋検出のボタンとプロンプト フィールドが1 つだけ
あることがわかります。ブラウザ環境をシミュレートします。
次に、開発者モードを開いて、下図のようにネットワークリクエストを確認すると、
ブラウザがデータと署名のパラメータを指定してポストリクエストを送信していることがわかりました。データと署名は両方とも暗号化されており、識別できません。このうちデータは14です。以下の図に示すように、base64 でデータを復号します。base64 の復号は文字化けしていることがわかり、正規の Base64 ではありません。下図に示すように、符号の長さが 32 であることを確認し
、記号は md5 (質問を先に残し、検証しないでください)
以下の図に示すようにコール スタックを観察し、Vue フレームワーク コードに加えて Fingerprintob があることを確認します。js は送信コードです
2.js解析
フォローアップして次の図を見てください。通常は乱雑すぎて観察できません。
ブレークポイントを作成し、js コードの復号化ステータスを確認すると、それが XMLHttpRequest オブジェクトのインスタンスによって呼び出される send メソッドであることがわかります。
send 関数のパラメータをコンソールで直接確認します。
('data=' + encodeURIComponent(_0x392f2d) + _0x369354(0xbe) + _0xd9e63f)
結果は下図のとおりで、ブラウザ上
ではポストリクエストのパラメータデータと符号を追跡できないことが判明したので、パラメータトレースバック用のコードをptcharmにコピーし、ctrl+leftを押すようにマスターLanが教えてくれました。マウス ボタンを押して、ここを見つけてブレークポイントを生成します。
これら 2 つの関数をコンソールに表示すると、それが探している答えであることがわかります。
この時点で、この関数を追跡して、その特定のロジックを確認できます (非常に適切かどうか)。シンプル、とても簡単)、コンソールに関数名を入力し、ダブルクリックして入力すると、人形でこの関数を見るのは気持ち悪い、5555が泣いた
3 シミュレーションの実行
ここで、マスター ランの導きで、前回の最初のレッスンの内容を復習するようになりました。コードがあまりにも気持ち悪いので、実行をシミュレートするために pycharm に入れて、直接実行できることがわかりました。後で、私は自分がそうだったことに気づきました。 sb, そしてリクエスト関数を呼び出しませんでした
... , 案の定、エラーが報告されました
. 環境の構築を開始します. 最初のステップはウィンドウを生成し、次に示すように前のレッスンのプロキシを v にインポートすることです下図のようなものを
実行し、エラー報告を続け、
環境構築に時間がかかります。1.jsをインポートします。
let mywindow={
XMLHttpRequest:function (){
}
}
let mynavigator={
}
const navigator=new Proxy(Object.create(mynavigato),getObjhandle("navigator"))
module.exports = {
window,navigator
}
work.js
let {
window,navigator} = require('./1.js');
次に、実行してエラー画面が未定義であることを確認し、画面への入力を続けてインターセプターをインポートします。
let myscreen={
}
const screen=new Proxy(Object.create(myscreen),getObjhandle("screen"))
module.exports = {
window,screen,navigator
}
work.js
let {
window,screen,navigator} = require('./1.js');
すると、下図のようにエラーが報告されメソッドが見つからず、どうしてメソッドが見つからないのか混乱してしまいましたが、エラーレポートによると、リクエストの一番下でエラーが報告されました。ブラウザで見つけて確認しました。コントラクト送信機能は 3 つあります。マスター ランは、コントラクト送信機能は分析には役に立たないため、削除してもよいと言いました。パラメータを出力するだけで済みます。 。
消去
_0xd532a8[_0x369354('0xbb')](_0x369354(0x9d), '/checkfing' + _0x369354(0xb9), !![]),
_0xd532a8[_0x369354(0x97) + _0x369354(0x93)](_0x369354('0xb4') + 'pe', _0x369354('0xb5') + _0x369354(0xad) + _0x369354(0xa0) + _0x369354('0xbc')),
_0xd532a8[_0x369354(0xc5)]('data=' + encodeURIComponent(_0x392f2d) + _0x369354(0xbe) + _0xd9e63f);
増加
console.log(encodeURIComponent(_0x392f2d)),
console.log(_0xd9e63f);
実行を続けると、結果が出ていることがわかります。テストに合格できるかどうか喜んで試してみてください。リクエスト
パッケージを右クリックし、コピー -> Curl (bash) としてコピーを右クリックすると、次の段落
curl 'Method Not Allowed' \
-H 'Connection: keep-alive' \
-H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36' \
-H 'Content-type: application/x-www-form-urlencoded' \
-H 'Accept: */*' \
-H 'Origin: 404 Not Found' \
-H 'Referer: FingerprintJS' \
-H 'Accept-Language: en-US,en;q=0.9' \
-H 'Cookie: access_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2MjkyNTE5MDMsIm5iZiI6MTYyOTI1MTkwMywianRpIjoiYjJiNTdjZjQtNmM0Ni00NTNkLThkM2EtZDNjY2IwN2U5NmQxIiwiZXhwIjoxNjI5MjU1NTAzLCJpZGVudGl0eSI6eyJ1aWQiOjQ1LCJzY29wZSI6ImxpbiJ9LCJmcmVzaCI6ZmFsc2UsInR5cGUiOiJhY2Nlc3MiLCJ1c2VyX2NsYWltcyI6eyJ1aWQiOjQ1LCJzY29wZSI6ImxpbiIsInJlbW90ZV9hZGRyIjpudWxsfX0.CAnZ_Wu8VdX0rO7oiQ2kV-ypPc4BIeQHeg_43AgFKcU; refresh_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2MjkyNTE5MDMsIm5iZiI6MTYyOTI1MTkwMywianRpIjoiNzlkYWI0MDQtODkzZS00MWEwLWE4YzktZjMzZjg4OWQ2YjM5IiwiZXhwIjoxNjMxODQzOTAzLCJpZGVudGl0eSI6eyJ1aWQiOjQ1LCJzY29wZSI6ImxpbiJ9LCJ0eXBlIjoicmVmcmVzaCJ9.-o5jGkDi0fdpIm0vVXs4korUv5a32LtDL37ASPkEqVM' \
--data-raw 'data=R6bq%2B6Mofhg9sLXriu4xkAT04dIrRc8rIRXpIjoraVbDZL8xn3u2W1McaNaEhNcVsw%2FwZt5wZEXShVC%2FR%2F2on1Mx%2BN%2FrTNaL%2BNgxn3ZSWAbQOhg7IE52sL89IR%2FpIRIMnuZCOAut%2Bhg9IwWpIwfLntIdILm5IRn5IPrtZYILntVVUjXLntZVWzacntIL4Pv9OhILnNOCkPZcntILOAuoWN%2FLntZAf6MwOhILnNOCkPZcntILOAuoWN%2FLntZAf6MwOhILnNOCkPZcntIL4Pv9OhILnVZSWAbQOhm8T3fr%2F1M9ONcpULx8kdvVf6voOhm3kNZ9k6ap4Ym1kdvQfD8qUAu2W1MxfNuV%2B6bpsdrQONb0ONMcs6ZSWAbQOh92O1OKW1TAUVZSWAbQOhm8T3fraAcc4NatULSqUAu2W1MxfNuV%2B6bpsdmyOz72O1fGRAuV%2BDOcn3Zo%2B6ap4jSqULxCWPmo%2B6ZC41c0kEb5s67CfNMKs1u2W1MxfNuV%2B6bpsdrQW17CfNMK&sign=0e7586abb2c960c1a32463d5de54bb42' \
--compressed \
--insecure
次に、Web サイト「Convertcurl コマンド構文を Python リクエスト、Ansible URI、ブラウザーフェッチ、MATLAB、Node.js、R、PHP、Strest、Go、Dart、Java、JSON、Elixir、および Rust コードに変換」にアクセスし、コピーしたコンテンツを直接貼り付けます。左側、右側のコンテンツを pycharm の新しいプロジェクトにコピーし、
次の図を実行して
正しいパスにいることを示し、次のステップは検出を通過することです。まず、
Google Chrome を見てください。どの UA が前のエージェントによって傍受された
場合、UA を作成します
let mynavigator={
userAgent:"\"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36\""
}
実行して見てください。
何も起こっていないことがわかります。ヒントもありません。フックの内容はゆっくりと見ることしかできません。画面とウィンドウが何度も呼び出されていることがわかります
。画面は次のように出力されます。
availHeight: 690
availLeft: 0
availTop: 0
availWidth: 1280
colorDepth: 24
height: 720
orientation: ScreenOrientation {
angle: 0, type: "landscape-primary", onchange: null}
pixelDepth: 24
width: 1280
[[Prototype]]: Screen
それを 1.js にコピーします
let myscreen={
availHeight: 690
,availLeft: 0
,availTop: 0
,availWidth: 1280
,colorDepth: 24
,height: 720
,pixelDepth: 24
,width: 1280
}
もう一度実行しますが、まだ通過できません。ウィンドウにパッチを適用することを検討し、何が使用されているかを確認します。監視プロトタイプ チェーンが多数あることがわかります。プロキシの下でそれを使用して、すべてのウィンドウにパッチを適用するだけです。プロパティが次のとおりであることがわかります
。 getOwnPropertyDescriptor によるプロトタイプです。チェーン上のメソッドは依然として独自のメソッドであるため、検出を回避するために新しいエージェントが使用されるときに、Object.create(mynavigator) を使用して継承層を実行します。
let mywindow={
XMLHttpRequest:function (){
},
sessionStorage:{
length: 0},
localStorage:{
length: 0}
}
let mynavigator={
userAgent:"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36"
,appCodeName:"Mozilla"
,language:"en-US"
,platform:"Win32"
}
const navigator=new Proxy(Object.create(mynavigator),getObjhandle("navigator"))
高度な演習
コースウェアで指定された js コードを実行し、正しい結果を出力します。
まず、最初の質問で指定した 1.js 補助環境を使用して実行して試し、スクリプトの先頭に記述します
let {
window,screen,navigator } = require('./1.js');
それでもエラーは補えます、window.navigator
let mywindow={
XMLHttpRequest:function (){
},
sessionStorage:{
length: 0},
localStorage:{
length: 0},
navigator:mynavigator
}
それを実行すると、下図のようにスタックしていることがわかります。
マスター Lan は、eval はデバッグが難しいと述べたので、コードをフォーマットして eval を削除し、t1000 をデバッグでデバッグした t1000Source 関数に直接置き換えてから、フォーマットして、 webdriverとscrollはブラウザと全く同じ環境を作ります
let mywindow={
XMLHttpRequest:function (){
},
sessionStorage:{
length: 0},
localStorage:{
length: 0},
navigator:mynavigator,
scrollTo:function(){
}
}
let mynavigator={
userAgent:"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36"
,appCodeName:"Mozilla"
,language:"en-US"
,platform:"Win32"
,webdriver:false
}
アンチデバッグ検出後はスタックしなくなることがわかりますが、エラーが報告され、最後にエラーが報告されます。場所が欠落しており、最初にすべて入力されます。しかし、いくつかの Web サイトでは
、見つからない 埋めることができないので、最初にそれらを配置します 場所が追加され、indexOf 関数が最後のエラー レポートに表示されます。つまり、このコードは文字列と一致するために大量の大きな IndexOf を使用するため、次のようになります。どの文字列が一致するかを監視するために、indexOf を書き換えます
let st=String.prototype.indexOf;
String.prototype.indexOf=function (cc){
console.log(cc)
return st(cc)
}
let mylocation={
cestorOrigins: {
length: 0}
,hash: ""
,host: "new-tab-page"
,hostname: "new-tab-page"
,href: "chrome://new-tab-page/"
,origin: "chrome://new-tab-page"
,pathname: "/"
,port: ""
,protocol: "chrome:"
,reload: function (){
}
,replace:function(){
}
,search: ""
}
完了した後、再びスタックしていることがわかりました。本当に...、これは、Master Lan のデバッグを使用し、問題がどこにあるかを確認するために一時停止することによってのみ実行できます。
一時停止後、コールスタックを見て判断を見つけて false (!_0x2f5962 の逆) に変更し、
直接実行してエラーを見つけます。プロンプトメソッドが未定義であることに腹が立ちます。時間が経っても進みません。最後にフォーマットします。コードを直接使用し、ドキュメントに記入して、ようやくデータが出てきたことがわかります。最終的な環境は次のとおりです。エラーが報告されますが、すでにデータ
var st=String.prototype.indexOf;
String.prototype.indexOf=function (cc){
console.log(cc)
return st.call(this,cc)
}
let mylocation={
cestorOrigins: {
length: 0}
,hash: ""
,host: "***.com"
,hostname: "new-tab-page"
,href: "chrome://new-tab-page/"
,origin: "chrome://new-tab-page"
,pathname: "/interdetailflightdetailinterlistflight_touch_react"
,port: ""
,protocol: "chrome:"
,reload: function (){
}
,replace:function(){
}
,search: ""
}
let mynavigator={
userAgent:"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36"
,appCodeName:"Mozilla"
,language:"en-US"
,platform:"Win32"
,webdriver:false
}
let mywindow={
XMLHttpRequest:function (){
},
sessionStorage:{
length: 0},
localStorage:{
length: 0},
navigator:mynavigator
,scrollTo:function (){
}
,location:mylocation
}
let myscreen={
availHeight: 690
,availLeft: 0
,availTop: 0
,availWidth: 1280
,colorDepth: 24
,height: 720
,pixelDepth: 24
,width: 1280
}
var Image=function (){
}
let mydocument={
createElement:function (img){
return img},
getElementsByTagName:function (a){
return {
}}}
function getObjhandle(Watchname){
let handle={
get(target, p, receiver) {
let res=Reflect.get(target, p, receiver);
if (res instanceof Object) {
if (typeof res === "function") {
console.log(`get [${
Watchname}] [${
p}] `)
} else {
console.log(`get [${
Watchname}] [${
p}] [${
JSON.stringify(res)}]`);
}
return new Proxy(res, getObjhandle(`${
Watchname}.${
p}`))
}
console.log(`get ${
Watchname} ${
p} ${
res}`)
return res
}
,set(target, p, value, receiver) {
let res=Reflect.set(target, p, value, receiver);
console.log(` set ${
Watchname} ${
p} ${
value}`)
return res;
},
has(target, p) {
let res=Reflect.has(target,p)
console.log(`has ${
Watchname} ${
p}`)
return res
},deleteProperty(target, p) {
let res=Reflect.deleteProperty(target,p)
console.log(`delete ${
Watchname} ${
p}`)
return res
}, getOwnPropertyDescriptor(target, p) {
let res=Reflect.getOwnPropertyDescriptor(target,p)
console.log(`getOwnPropertyDescriptor ${
Watchname} ${
p} ${
JSON.stringify(res)}`)
return res
}, defineProperty(target, p, attributes) {
let res=Reflect.deleteProperty(target, p, attributes)
console.log(` defineProperty ${
Watchname} ${
p} ${
attributes} ${
res}`)
return res;
}, defineProperty(target, p, attributes) {
let res=Reflect.deleteProperty(target, p, attributes)
console.log(` defineProperty ${
Watchname} ${
p} ${
JSON.stringify(attributes)}`)
return res;
},preventExtensions(target) {
console.log(`preventExtensions ${
Watchname} `)
return Reflect.preventExtensions(target)
},isExtensible(target) {
let res=Reflect.isExtensible(target)
console.log(`isExtensible ${
Watchname} ${
res}`)
return res;
},getPrototypeOf(target) {
let res=Reflect.getPrototypeOf(target)
console.log(`getPrototypeOf ${
Watchname} ${
JSON.stringify(res)}`)
return res;
},ownKeys(target) {
var result = Reflect.ownKeys(target)
console.log(`ownKeys [${
Watchname}] [${
JSON.stringify(result)}]`)
return result
}
,setPrototypeOf(target, v) {
let res=Reflect.setPrototypeOf(target,v)
console.log(`setPrototypeOf ${
Watchname} ${
JSON.stringify(v)}`)
return res;
}, 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 handle;
}
const window=new Proxy(Object.assign(global,mywindow),getObjhandle("window"))
const screen=new Proxy(Object.create(myscreen),getObjhandle("screen"))
const navigator=new Proxy(Object.create(mynavigator),getObjhandle("navigator"))
const location=new Proxy(Object.create(mylocation),getObjhandle("location"))
const document=new Proxy(Object.create(mydocument),getObjhandle("document"))
module.exports = {
window,screen,navigator,location,Image,document
}
最後に、誰もが一緒に勉強することを歓迎します。WeChat: r0ysue を追加して一緒に進歩することができます