1. 前に書く
最近、クローラーを作成していたときに、いくつかの小さな Web サイトで MD5 暗号化が使用されているのを発見しました。私たちのチームが開発した何千もの Web サイト クローラーで、この種の MD5 暗号化が使用されているケースが多数見つかりました。多くを語る必要はありません。ただ取り出して波を分析してください。
その後、時間をかけて、JS 暗号化関数をすばやく検索して特定し、一般的な暗号化アルゴリズムの特性を分析して特定する方法に関するいくつかのヒントを要約する予定です。
対象サイト:
aHR0cHM6Ly93d3cub2Fwa3p5aC5jbi9zL3MtJUU2JThCJTlCJUU1JTk1JTg2JUU5JTkzJUI2JUU4JUExJThDPyZzaz1kMmRiMGJjZjI1MTExMzlkMzZiNzUxNTg5YTc1ZTllOA==
2. 分析
このウェブサイトでは主に検索インターフェースについて説明していますが、検索 URL にskというパラメータがあることがわかりますが、このパラメータが分析と復元の対象です。
skパラメータの暗号化は外部 JS ファイルの呼び出しを通じて処理されるため、Web サイト内で関連する暗号化エントリを直接検索することはできません。
ここでは招商銀行の検索を例に挙げますが、 skパラメータの暗号化された値は次のとおりです。
d2db0bcf2511139d36b751589a75e9e8 (これは修正されました)
これは 32 ビットで暗号化された値であることがわかります。まず、skパラメータを追加せずに検索インターフェイスからデータを取得できると仮定しましょう。
単純な構築リクエストでは検索データが取得できないことがわかり、渡されたのは短い HTML コードであり、この HTML コードの文字列に注目します。
HTML コードには次のパラメータがあります。これらは、MD5 で暗号化された JS ファイルを呼び出すために必要なパラメータです。
hexcase、b64pad、chrsz、s_wb
このうち、s_wbは暗号化して渡すパラメータ値であり、各キーワード検索に対応するs_wbとskの値は固定されています
3. 控除コードの確認
返された HTML コードには 2 つの JS ファイルがあることに注意してください。まず最初の5dm.jsファイルを見てみましょう。
function hex_md5(s){
return binl2hex(core_md5(str2binl(s), s.length * chrsz));}
function b64_md5(s){
return binl2b64(core_md5(str2binl(s), s.length * chrsz));}
function hex_hmac_md5(key, data) {
return binl2hex(core_hmac_md5(key, data)); }
function b64_hmac_md5(key, data) {
return binl2b64(core_hmac_md5(key, data)); }
function calcMD5(s){
return binl2hex(core_md5(str2binl(s), s.length * chrsz));}
function md5_vm_test()
{
return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
}
function cxx(a, d) {
var e;
a = a - 0,e = str_spl[a]
return e;
}
function core_md5(x, len)
{
x[len >> 5] |= 0x80 << ((len) % 32);
x[(((len + 64) >>> 9) << 4) + 14] = len;
var a = 1732584193;
var b = -271733879;
var c = -1732584194;
var d = 271733878;
for(var i = 0; i < x.length; i += 16)
{
var olda = a;
var oldb = b;
var oldc = c;
var oldd = d;
a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);
b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);
c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);
d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);
b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);
c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);
d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);
a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);
b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);
c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);
d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);
a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);
b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);
d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);
a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
a = safe_add(a, olda);
b = safe_add(b, oldb);
c = safe_add(c, oldc);
d = safe_add(d, oldd);
}
return Array(a, b, c, d);
}
function md5_cmn(q, a, b, x, s, t)
{
return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
}
function md5_ff(a, b, c, d, x, s, t)
{
return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function md5_gg(a, b, c, d, x, s, t)
{
return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function md5_hh(a, b, c, d, x, s, t)
{
return md5_cmn(b ^ c ^ d, a, b, x, s, t);
}
function md5_ii(a, b, c, d, x, s, t)
{
return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
}
function core_hmac_md5(key, data)
{
var bkey = str2binl(key);
if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);
var ipad = Array(16), opad = Array(16);
for(var i = 0; i < 16; i++)
{
ipad[i] = bkey[i] ^ 0x36363636;
opad[i] = bkey[i] ^ 0x5C5C5C5C;
}
var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
return core_md5(opad.concat(hash), 512 + 128);
}
function safe_add(x, y)
{
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF);
}
function bit_rol(num, cnt)
{
return (num << cnt) | (num >>> (32 - cnt));
}
function str2binl(str)
{
var bin = Array();
var mask = (1 << chrsz) - 1;
for(var i = 0; i < str.length * chrsz; i += chrsz)
bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
return bin;
}
function binl2hex(binarray)
{
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
var str = "";
for(var i = 0; i < binarray.length * 4; i++)
{
str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF);
}
return str;
}
function binl2b64(binarray)
{
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var str = "";
for(var i = 0; i < binarray.length * 4; i += 3)
{
var triplet = (((binarray[i >> 2] >> 8 * ( i %4)) & 0xFF) << 16)
| (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )
| ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
for(var j = 0; j < 4; j++)
{
if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
}
}
return str;
}
これは典型的な MD5 暗号化アルゴリズムです。MD5 、SHA1、BASE64、16 進数などの暗号化には、すべていくつかのキーワードの特徴があります。フォローアップ記事では要約に焦点を当てます。
MD5 の暗号化アルゴリズムと HTML のパラメーターを取得しました。これらのパラメーター変数を注意深く見てください。これらのパラメーター変数は、まさに JS 暗号化コードに必要なものです。
ここではコンソール上でテストして検証してみますが、下図に示すように、MD5暗号化アルゴリズムに問題がないことがわかります暗号化後、 s_wbは32ビットの値を取得します。
ただし、前述したように各キーワードの検索暗号化値は固定されているため、上記Webサイトで取得される値と同じではありません。
明らかに、暗号化パラメータs_wbの値はソルト化されているようです。ソルト化とは、ハッシュ化された結果が元のパスワードを使用してハッシュ化された結果と一致しないように、任意の固定位置に特定の文字列を挿入することです。
ここで別の JS ファイルを分析します。この JS コードは難読化されています
eval( function ( p, a, c, k, e, d ) {
e = function ( c ) {
return ( c < a ? "" : e( parseInt( c / a ) ) ) + ( ( c = c % a ) > 35 ? String.fromCharCode( c + 29 ) : c.toString( 36 ) )
};
if ( !''.replace( /^/, String ) ) {
while ( c-- ) d[ e( c ) ] = k[ c ] || e( c );
k = [ function ( e ) {
return d[ e ]
} ];
e = function () {
return '\\w+'
};
c = 1;
};
while ( c-- )
if ( k[ c ] ) p = p.replace( new RegExp( '\\b' + e( c ) + '\\b', 'g' ), k[ c ] );
return p;
}( 'g 1Y=\'6,1,3,a,c,a,b,b,v,v,j,j,0,r,o,c,e,a,d,c,a,c,a,c,o,p,c,1,y,t,z,2m,1g,V,1w,1p,1q,3i,3D,2s,2q,;2R=/,3|0|1|4|2,2U,3|1|0|2|4,2T,2V,2X,2W,2S,2O,2N,2P,2Q,35,34,36,38,A,37,33,2Z,2Y,30,32,31,2M,2x,0|2|1|3|5|4,2w,2y,2A,2z,2v,2r,2u,2t,0|3|2|5|1|4,n,2I,2H,t,2J,2L,2K,2G 2C 2B 2D 2F.,2E,39,3E,3F,3H=,3G=,3C,D,3y,3x,3z,3B,3A,3P,3O,3Q/K,3S,3R,3N,3J,I-l,q-l,[[[3I]]]:,3K,3M,/0.3L:3w:3h/,0|3|4|5|1|2,3g,G.A,3k,3j,a,3f,3b,3a,3c,3e,3d,3s,3r,3t,3v,3u,3q,b,q-J-C,3m,3l,3n,3p,3o,1s,1r,1t,1v,1u,1n,1m,1o,1D,1C,1E,1G,1F,1y,a,1x,1z,1B,1A,1l,17,Y,Z E,W,18,U,X,19,1h-l,1i,1k,1j,1f,1b,1a,1c,1e,1d,2a,29,2c,[i 2d],28,24,23: ,25,27,26,2l,2n,2p,2o,2k,2g-F,2f,2h,2j,2i,1O,1N,1P,1R,1Q: ,1M,1I,1H: ,1J,1L,1K,1Z,20,22,21,1X,1T,1S,1U,1W,1V,2e,3T,i, - ,5H,5G,5I,5K,5J,5F,%2b,5B,5A,5C,F,G,5E,=; 5D-5L=-5T;,5S-5U,5W,5V,5R,<H D="L:w">E 5N: 5M</H>,5O,5Q,5P,5z,5j,5i,5k,5m,5l,k-B,n=,5h,a,5d/K,5c,5e,5g,5f+5n-5v,5u i: ,5w,5y,5x,5t,5p,5o,5q,5s,5r,6n,6m,6o,6q,6p,6i,6h,6j,L,6l,5X,5Z,61,6k,6c,6e,6g,6f,67,69,6b,6a,68,6d,60,I-J-C,5Y,65,66,64,62,63,6r,5b,4k,4j,4m,4l,4i,4f,4e,/4h-4g/k-4n/,4u,4t,4w,n-4v-m,a,4s,4p,4o,4r,c,4q,u,4d,40,3Z,12|11|5|10|16|6|13|0|7|2|14|9|3|4|1|15|8,42,41,3Y,3V,3U,3X,3W,43-k-m,4a/x-49-B-4c,4b,48,45,44,47,46,4x,4Y,4X,50,4Z-u-m,4W,4T,4S,4V,4U,51,58,2|1|3|4|0,57,5a,59,56,53: ,52,55,54,w,4R,4E,4D,4G,N,4F,4C,4z,4y,4B,4A,4H,4O\'.N(\',\');(4N(){g P=\'g \'+f(\'O\')+\' = \'+f(\'M\')+\'.\'+f(\'R\')+\'.\'+f(\'Q\'),4Q=h(P),S=\'g j \'+\'=\'+f(\'O\')+\'+\\\'&\'+f(\'4P\')+\'\\\'+\'+f(\'4M\')+f(\'4J\')+\'("\'+h(f(\'4I\')+f(\'4L\'))+f(\'T\')+f(\'T\')+\'")\',4K=h(S),s=f(\'M\')+"."+f(\'R\')+"."+f(\'Q\')+"="+"j";h(s)})();', 62, 400, '|||||||||||||||cxx|var|eval|object||challenge|content|warning|location|||jc||h_j||cookie||none||||stringify|form|wait|style|error|type|JSON|span|cf|please|ov|display|0xaa|split|0x71|str|0xba|0x4e|j_S|0xc3|xDIKE|yDqjz|tAtvf|GwSAy|IrPMz|script||||||||RltNA|SpLsv|getTime|rZLDP|window|s_wb|okWgA|CApNt|SVWkt|EhTGM|yjs|xMQBH|GYXiM|YPpdz|join|Jdglm|VgXRq|infln|hex_m|Hncqi|rzkXR|getUTCMonth|kEOXS|bOXho|setTimeout|hostname|hqtkF|EonFu|readystatechange|wvqDm|uBOBk|feBet|Myfvu|qDVbz|bwTLt|YvUtC|URL|oDCWZ|ontimeout|TGsOO|createElement|TBaRt|totFh|lq|UDJRh|Line|cFPWv|push|KXAyu|cLt|QXLIM|NBiYs|attachEvent|str_spl|HKfkZ|qYoox|cookieEnabled|number|Column|hasOwnProperty|test|xUpbx|iHPsA|toString|ActiveXObject|xYMlq||dnUwI|Array|UfcDe|hwkrP|Content|timeout|getUTCHours|kVHHP|tfJEB|wmFQu|toJSON|href|QTNba|KacOr|RDADr|call|WDFnZ|coSfZ|nUfnU|YylIg|setTime|oQBSD|fMdPD|IfNGB|GVsnR|is|browser|not|xCynh|supported|This|FDkwn|GcHHU|cTqHN|IlWoV|aHejK|cf_chl_prog|GGrkR|length|okQTr|pjUVI|path|WNlgm|luXAx|document|RaRva|sffVy|Krhfs|vsvuu|open|wLHhJ|pow|LnGrE|fromCharCode|uHHsU|boolean|cNounce|getUTCFullYear|oIiHN|TOuRq|CXZDT|DDqjf|floor|xRkJm|cRay|null|url|33416065404de2bd6354dea0e1474b01e183783d55747f8b3651888d63074b8d|DVOWi|GTERe|zTmET|msg|fYLnU|BQXry|atob|ofmCw|iLeUB|qwuXF|sqjnL|BWrSc|LbpXa|MQWiJ|1630987682|SHA256|replace|XMLHttpRequest|getElementById|gunvR|RMShh|alert|iMlwG|RcmsS|sk|expires|ERROR|indexOf|cRq|15241746233417997|iGYSA|oYHLt|PsAOD|LACbK|flow|xyKFA|IgbxZ|InyOx|protocol|lastIndex|console|uJExb|aURPj|LKabo|AuGvf|reload|_5|cached|Function|s_w|POST|QFzyD|ppp|www|application|UrAfO|urlencoded|EGDrE|jkMkZ|Math|cgi|cdn|chC|NcMkh|tkmOi|DOMContentLoaded|zuFRo|platform|UpcSS|sendRequest|LjmFC|cvId|hlI|min|ReBaF|mismatch|send|YUfsT|NejMd|eKtkL|cuERA|OZghr|setRequestHeader|parseInt|Wfjmc|afuXt|d5|getUTCSeconds|0x150|0x16d|j_u|0x82|0x23|function|jshsZ|0x5b|s_u|_3|pJTgp|chReq|nCJFD|nWwNw|cf_chl_|FjBAA|xOwTw|no|navigator|muapd|iIhbT|Message|zfuDm|nHOsW|valueOf|cTTimeMs|pdaor|_4|Tkqkc|VVKvU|cQNqs|beacon|mLnip|IOHg1ali3SWG5eCDVu7xYb2rtq|chCAS|0123456789abcdef|QugZe|complete|cf_chl_rc_ni|lCTri|WFCvu|shd9X4ovfmQwLj|qkyzk|bLKyY|interactive|EdaME|RysJB|block|Error|6Uy0ZNJpRT8BPAM|PyVdX|cHash|QiMoT|gzqYy|OFxWm|readyState|toUTCString|Max|zBFoF|substring|HXbmy|_2|eOAln|ehNpB|parse|Age|1020|code|slice|now|nQzbt|getUTCMinutes|CF|99999999|Challenge|zDkeF|cdDUS|vdRbf|PdPTi|SUEcW|EnrBZ|FJLlp|LSzbf|innerHTML|FROtN|OAtFE|ZjUsu|apply|_0|GJeLc|cXHng|BRGoE|lqlq|status|onreadystatechange|yuUej|addEventListener|Vglij|onerror|FUQZM|Dqbnu|TFMGn|WJqZU|_1|DkVfm|XxAgU|jump|HFZgm'.split( '|' ), 0, {
} ) )
見てください。eval ()関数を使用して難読化されたコードを実行します。複数の変数は単純に見ることができず、復元しないとロジックを理解できません。
ただし、難読化されたコード上のロジックの一部が、文字列の操作、分割、連結、計算などの操作を行っているように見えることがわかります。
したがって、高確率文字列のソルティング操作はこの JS コード内にあります
コードを復元すると、ソルトを追加した結果も修正されていることがわかります。これは、 MD5 暗号化パラメータs_wb文字列の後に 4 桁の固定文字列を追加するのと同じです。
テスト検証の結果を確認できます。d2db0... は、最初に検索したキーワードChina Merchants Bankの暗号化された最終的なskパラメータ値です。
最後に、さらにいくつかのキーワードをテストしました
さて、ここにいる皆さんとまたお別れの時間です。作成するのは簡単ではありません。離れる前に「いいね!」をお願いします。皆様のご支援が創作の原動力となっており、より質の高い記事をお届けしたいと思っております