一常潮、堆疊注入的原理
mysql數(shù)據(jù)庫sql語句的默認結(jié)束符是以";"號結(jié)尾币狠,在執(zhí)行多條sql語句時就要使用結(jié)束符隔
開,而堆疊注入其實就是通過結(jié)束符來執(zhí)行多條sql語句
比如我們在mysql的命令行界面執(zhí)行一條查詢語句,這時語句的結(jié)尾必須加上分號結(jié)束
如果我們想要執(zhí)行多條sql那就用結(jié)束符分號進行隔開,比如在查詢的同時查看當前登錄用戶是誰
顯而易見堆疊注入就是在不可控的用戶輸入中通過傳入結(jié)束符+新的sql語句來獲取想要的息,可以通過簡單的流程圖來了解過程
![6VA1K@PGK[73%B}8AY8I.png
二、堆疊注入觸發(fā)條件
堆疊注入觸發(fā)的條件很苛刻,因為堆疊注入原理就是通過結(jié)束符同時執(zhí)行多條sql語句,這就需要服
務(wù)器在訪問數(shù)據(jù)端時使用的是可同時執(zhí)行多條sql語句的方法,比如php中mysqli_multi_query()
函數(shù),這個函數(shù)在支持同時執(zhí)行多條sql語句,而與之對應(yīng)的mysqli_query()
函數(shù)一次只能執(zhí)行一條sql語句,所以要想目標存在堆疊注入,在目標主機沒有對堆疊注入進行黑名單過濾的情況下必須存在類似于mysqli_multi_query()
這樣的函數(shù),簡單總結(jié)下來就是
- 目標存在sql注入漏洞
- 目標未對";"號進行過濾
- 目標中間層查詢數(shù)據(jù)庫信息時可同時執(zhí)行多條sql語句
可以做一個簡單的實驗,創(chuàng)建test.html和test.php兩個文件內(nèi)容分別為
- test.html
<html>
<head><title>學生ID查詢</title><head>
<body>
<form method="get" action="index.php">
<input type="text" placeholder="輸入學生id查詢成績">
<br>
<input type="submit">
</form>
</body>
</html>
- index.php (頁面寫的有點著急不要介意哈韭赘!)
<?php
$id=$_GET['id'];
$con=mysqli_connect("localhost","root","123","test");
if (mysqli_connect_errno($con))
{
echo "Failed to connect to MySQL: ".mysqli_connect_error();
}
mysqli_select_db($con, "test");
$sql="SELECT * FROM student WHERE id='$id'";
mysqli_multi_query($con, $sql);
$result = mysqli_store_result($con);
$row = mysqli_fetch_row($result);
print_r($row);
echo "<br>";
echo "you sql: ".$sql.";";
mysqli_close($con);
?>
在mysql命令行中創(chuàng)建一個test數(shù)據(jù)庫,再創(chuàng)建一個student表插入一些數(shù)據(jù)
create database test;use test;create table student( id int, name varchar(100), score varchar(100));insert into student(id,name,score) values(1,"toert","100"),(2,"giao","10");
先檢查一下頁面功能是否正常
直接構(gòu)造堆疊注入去創(chuàng)建一張test表參照student表的數(shù)據(jù)
可以看到原來的sql語句經(jīng)過堆疊注入惡意構(gòu)造變成了SELECT * FROM student WHERE id='1';create table test like student;
三、堆疊注入實戰(zhàn)
0x1 sqli-labs38關(guān)卡
sqli-labs靶場包含了很多類型的sql注入環(huán)境,不知道怎么搭建的可以看上一篇的sql注入環(huán)境搭建
傳入單引號報錯,發(fā)現(xiàn)錯誤回顯分析后構(gòu)造單引號閉合發(fā)現(xiàn)字符型注入
經(jīng)過測試存在union聯(lián)合注入,使用聯(lián)合注入爆破出users表中有id、username坡氯、password三個 字段,于是嘗試堆疊注入將id為1的用戶密碼改成123,可以配合聯(lián)合查詢來判斷sql是否執(zhí)行
然后再次查詢id為1的用戶時發(fā)現(xiàn)password信息已經(jīng)被成功執(zhí)行,說明目標存在堆疊注入,如果目標沒有限制執(zhí)行的sql語句,那就可以隨心所欲的執(zhí)行你想要執(zhí)行的sql語句了!
0x2 BUUCTF的一道堆疊注入題目
測試注入點發(fā)現(xiàn)GET型字符注入,
order by爆破字段2
配合union select發(fā)現(xiàn)過濾規(guī)則
沒有過濾分號,測試堆疊注入成功,查詢當前數(shù)據(jù)庫的表有1919810931114514
洋腮、words
兩張表
接下來查詢每張表中有哪些列明,繼續(xù)使用堆疊注入配合show,發(fā)現(xiàn)191開頭的表中存在flag關(guān)鍵字,這邊需要注意一下的是因為這張表的名字為純數(shù)字,在使用時需要通過"`"號括起來
因為目標過濾了select語句所以直接查詢是不太可能了,這時就得用到其他可以讀取表數(shù)據(jù)的方法,在網(wǎng)上找了找發(fā)現(xiàn)mysql數(shù)據(jù)庫中可以使用handler語句讀取表中的數(shù)據(jù),閱讀官方文檔后發(fā)現(xiàn)這玩意就相當于一個數(shù)據(jù)指針,先創(chuàng)建要一個準備讀取的對象然后操作這個數(shù)據(jù)指針去讀取表中的數(shù)據(jù),help查看用法如下
- handler 要讀取的表名 open as 別名;(打開一個句柄實例,也可以不取別名,用一個as是為了下面更加方便操作)
- handler 別名 read next;(將句柄移動到表中的第一行數(shù)據(jù)并且讀取箫柳,也可以用first或者last讀取第一行和最后一行)
- handler 別名 close;(將這個句柄實例關(guān)閉)
了解handler的用法再配合堆疊注入拿到flag
對于這道題目網(wǎng)上搜了一下還有一種做法,就是將1919810931114514表改成words表,然后使用alter table將1919810931114514表中的falg列名修改為words中的id列名,然后通過原本的查詢將flag查詢出來,具體payload如下
第二種通過修改表名字段的方式最好再用alter table add
將1919810931114514表新增一個名為data列,這樣就完美模擬了原來的words表結(jié)構(gòu),沒有增加data列是因為目標原本的select語句應(yīng)該是select * from words where id='',因為加了“*”所以什么都能查出來,如果語句為select id,data from words,那用原本的方法就沒辦法查出flag值了,因為找不到data列select語句會報錯,針對這個情況可以做一個簡單的實驗
使用select查詢固定列名信息
當student表中沒有name字段后再通過剛剛的語句就會報錯