DevStart Blogi Napisano Luty 26, 2014 Zgłoś Udostępnij Napisano Luty 26, 2014 Introduction"120" is the second web challenge from the Codegate CTF Preliminary 2014. It has been solved by 100 teams, but our team was the fastest.The challenge contains two files: index.php and auth.php, where both are very similar:Additionally, we are given the source code of index.php:<?phpsession_start();$link = @mysql_connect('localhost', '', '');@mysql_select_db('', $link);function RandomString(){ $filename = "smash.txt"; $f = fopen($filename, "r"); $len = filesize($filename); $contents = fread($f, $len); $randstring = ''; while( strlen($randstring)<30 ){ $t = $contents[rand(0, $len-1)]; if(ctype_lower($t)){ $randstring .= $t; } } return $randstring;}$max_times = 120;if ($_SESSION['cnt'] > $max_times){ unset($_SESSION['cnt']);}if ( !isset($_SESSION['cnt'])){ $_SESSION['cnt']=0; $_SESSION['password']=RandomString(); $query = "delete from rms_120_pw where ip='$_SERVER[REMOTE_ADDR]'"; @mysql_query($query); $query = "insert into rms_120_pw values('$_SERVER[REMOTE_ADDR]', '$_SESSION[password]')"; @mysql_query($query);}$left_count = $max_times-$_SESSION['cnt'];$_SESSION['cnt']++;if ( $_POST['password'] ){ if (eregi("replace|load|information|union|select|from|where|limit|offset|order|by|ip|\.|#|-|/|\*",$_POST['password'])){ @mysql_close($link); exit("Wrong access"); } $query = "select * from rms_120_pw where (ip='$_SERVER[REMOTE_ADDR]') and (password='$_POST[password]')"; $q = @mysql_query($query); $res = @mysql_fetch_array($q); if($res['ip']==$_SERVER['REMOTE_ADDR']){ @mysql_close($link); exit("True"); } else{ @mysql_close($link); exit("False"); }}@mysql_close($link);?>ReconWe can see that the script is setting a random password for every 120 consecutive requests.The password is linked to our unique IP address and stored in the MySQL database.We are able to send password parameter via POST, which is tested on the blacklist: if (eregi("replace|load|information|union|select|from|where|limit|offset|order|by|ip|\.|#|-|/|\*",$_POST['password'])){ @mysql_close($link); exit("Wrong access"); }Yes, this challenge is about SQL injection attack. Let's look at the vulnerable line: $query = "select * from rms_120_pw where (ip='$_SERVER[REMOTE_ADDR]') and (password='$_POST[password]')";It's impossible to alter $_SERVER[REMOTE_ADDR], but $_POST[password] is under our control!Magic quotes were disabled on that server, so there was no problem to close a single quote.Take a look at the rest of the code: $q = @mysql_query($query); $res = @mysql_fetch_array($q); if($res['ip']==$_SERVER['REMOTE_ADDR']){ @mysql_close($link); exit("True"); } else{ @mysql_close($link); exit("False"); }Errors are stripped (@ before functions names), so our attack may be boolean blind injection based on True/False output.Functions like sleep or benchmark are not on the blacklist, so we can also do time-based attack.The second idea is more reasonable, because we have only 120 queries....is it?eregi - old and badWAF is based on the eregi function. In the manual we can read:WarningThis function has been DEPRECATED as of PHP 5.3.0. Relying on this feature is highly discouraged.Why is that? For example because eregi stops reading strings on the first null byte.Remember that PHP allows us to send strings containing null bytes.By setting first byte of password to null we can bypass eregi and use all forbidden words from the blacklist!120? - just think out of the boxAfter every 120 requests new password linked to our IP address is generated.So logical is that we have to get our password in 120 queries....is it?Who said it must be our password? :)We just can use our first IP address to get password linked to a second IP address we control.For example:1) Request index.php to generate new password and store it in the database. Use first IP to do it.2) Do blind SQL injection attack to get password linked to the first IP. Use second IP to do it.3) Login in auth.php and profit. Use first IP to do it.PayloadThe last missing thing is the payload. After bypassing the whole blacklist creating one is not difficult.%00') union select if((select 1 from rms_120_pw where ip='$IP_with_static_password' and ord(mid(password,$i,1))>$guess limit 1),'$IP_with_exploit',0),2-- xWe can do fast binsearch boolean-based blind SQL injection using this.Congrats!After all we solved it in very fast and smart way :)Congrats! the key is DontHeartMeBaby*$#@!The challenge has been solved by Mawekl, member of the Dragon Sector.Wyświetl pełny artykuł Cytuj Link do komentarza Udostępnij na innych stronach More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.