背景:
這個題目是今年某一期三個白帽的題目,看過之后很感興趣针肥,于是便還原出來饼记,題目地址
分析:
上代碼:
<?php
function waf($str) {
if(stripos(strtolower($str),"select")!==false)
die("Be a good person!");
if(stripos(strtolower($str),"union")!==false)
die("Be a good person!");
}
function wafArr($arr) {
foreach ($arr as $k => $v) {
waf($k);
waf($v);
}}
wafArr($_GET);
wafArr($_POST);
wafArr($_COOKIE);
wafArr($_SESSION);
function stripStr($str) {
if (get_magic_quotes_gpc())
$str = stripslashes($str);
$a=addslashes(htmlspecialchars($str, ENT_QUOTES, 'UTF-8'));
return $a;
}
$uri = explode("?",$_SERVER['REQUEST_URI']);
if(isset($uri[1])) {
$parameter = explode("&",$uri[1]);
foreach ($parameter as $k => $v) {
$v1 = explode("=",$v);
if (isset($v1[1])) {
$_REQUEST[$v1[0]] = stripStr($v1[1]);
}
}}
var_dump($_REQUEST);
$con=mysqli_connect("localhost","root","123","demo");
$result = mysqli_query($con,"SELECT * FROM ctf where user=".$_REQUEST['id'].";");
echo "</br>";
var_dump($row = mysqli_fetch_array($result));
highlight_file('index.php');?>
數(shù)據庫結構
CREATE TABLE `ctf` (
`user` int(11) DEFAULT NULL,
`pass` varchar(255) DEFAULT NULL)
CREATE TABLE `ctf2` (
`user` int(11) DEFAULT NULL,
`flag is here` varchar(255) DEFAULT NULL)
下面分析一下waf的代碼。首先慰枕,檢查get,post,cookies,這些參數(shù)具则,在這里我只用了簡單的字符串匹配。當然了具帮,這塊不是重點博肋,這塊我只是想強調get,post這些參數(shù)被過濾。
隨后進入if 分支蜂厅,也就是重組request了匪凡。首先使用?去分割url。根據規(guī)定掘猿,?前面是地址病游,后面是用戶所提交的參數(shù)。并且將前面所得到的數(shù)組的第二個元素稠通,也即是里面是參數(shù)的那個衬衬,再使用=分割买猖,獲取健值,并且將值使用stripStr函數(shù)過濾滋尉。過濾完成后玉控,重組在系統(tǒng)的REQUEST數(shù)組中。
全部過濾好參數(shù)后狮惜,再執(zhí)行數(shù)據庫語句奸远。
這個題主要考查的是http參數(shù)污染。也就是說同時提交許多參數(shù)一樣的值讽挟,根據環(huán)境的不同懒叛,將會產生覆蓋等問題。例如在本題中耽梅,如果提交的參數(shù)是?id=1?&id=2的話薛窥,apache默認會使用后面的值去覆蓋前面的值。所以在php接收get參數(shù)的時候眼姐,將會接收到id=2诅迷,而不是id=1。
根據上面講的众旗,我們可以繞過第一個waf的檢測罢杉。
第二個是重點,題目把所接收到的url(http://11.com/index.php?id=1)使用?分割贡歧,并且使用分割后數(shù)組的第二個元素去執(zhí)行waf過濾滩租。那么問題來了,如果我提交的字符串里面還有一個?呢利朵?(http://11.com/index.php?id=1?&id=2)很簡單律想,會分割成含有三個元素的數(shù)組,第一部分含有url地址绍弟,第二部分含有id=1,第三部分含有 &id=2技即,并且第三部分的數(shù)據并不會參與任何運算,而且還可以被識別成get所提交的參數(shù)樟遣。
所以我們可以提交url中參數(shù)為id=xxxxxx?id=1這樣的參數(shù)去繞過waf檢測而叼,在if分支中,會使用url中的id=xxx這段代碼去重組豹悬,并放入request數(shù)組中葵陵。看一下下面的數(shù)據庫執(zhí)行語句屿衅,使用的request數(shù)組埃难。所以呢,我們只需要繼續(xù)分析if分支的過濾代碼即可。
分支中涡尘,值將會被addslashes
, htmlspecialchars
這兩個函數(shù)過濾忍弛。第二個函數(shù)是轉義html實體編碼的,針對于空格考抄,我們使用mysql的注釋符號即可繞過/**/
细疚。再看第一個函數(shù)。第一個函數(shù)會將單引號川梅,雙引號疯兼,反斜杠注釋掉,去防止sql注入贫途。那么是否意味著就沒有sql注入了呢吧彪?再分析一下數(shù)據庫和所執(zhí)行的數(shù)據庫語句,"SELECT * FROM ctf where user=".$_REQUEST['id'].";"
丢早,而且ctf表的user字段類型是int,題目也恰好不需要單引號和雙引號去閉合(參見繞過intval注入)姨裸。于是,直接注入即可怨酝,不需要考慮addslashes
函數(shù)傀缩。注意只要不出現(xiàn)單引號和雙引號即可注入成功。
參見payload
https://ctf.f4ck0.com/ctf/?id=0/**/union/**/select/**/*/**/from/**/ctf2?&id=1
當然了农猬,這個題要是想load_file怎么辦呢赡艰,文件的路徑名必須的用單引號啊。這里我們可以使用字符串轉16進制斤葱,即可突破限制慷垮。
參見payload
https://ctf.f4ck0.com/ctf/?id=-1/**/union/**/select/**/1,LOAD_FILE(0x2f6574632f706173737764)?&id=1
后記
我在第一次看參考的那兩位的wp時候并沒有直接看懂,因為有點問題苦掘,說的比較籠統(tǒng)换帜。尤其是這句話
當然waf不生效了,而在重組$_REQUEST
時鹤啡,覆蓋并沒有發(fā)生,所以注入語句順利的被執(zhí)行
和
所以根本不需要懟waf蹲嚣,uri被處理后递瑰,GET
_REQUEST的值可以不一樣,然后直接注入就好了
尤其困惑隙畜,而且看payload,也沒說出個所以然來抖部。于是根據博客中提供的代碼,還原部分環(huán)境去本地測試议惰。結果發(fā)現(xiàn)題目中好多巧合慎颗,才導致的addslashes
的繞過。其實如果這道題稍微做一下改動,兩位表哥所分析的可能就不對了俯萎。所以我在這里寫下詳細的分析過程傲宜,幫助其他人學習。??