在github發(fā)現(xiàn)了個(gè)代碼審計(jì)學(xué)習(xí)的資料,項(xiàng)目叫PHP-Audit-Labs,紅日安全做的,跟著學(xué)習(xí)下做個(gè)記錄吧。
知識(shí)點(diǎn):in_array(),在不知道列名的情況跑數(shù)據(jù),make_set()。
in_array():檢查數(shù)組中是否存在某個(gè)值,可以接受3個(gè)參數(shù)(a,b,c)。在b中尋找a,如果存在則返回true,否則返回false。第三個(gè)參數(shù)c默認(rèn)為false,如果指定為TRUE ,則 in_array() 函數(shù)會(huì)進(jìn)行強(qiáng)檢查,檢查a的類型是否和b中的相同,則返回 TRUE,否則返回 FALSE。
將他的代碼下到本地,我這使用phpstudy,用它給的sql語句在本地?cái)?shù)據(jù)庫里運(yùn)行一下,再將數(shù)據(jù)庫賬號(hào)密碼改下,訪問,配置成功。
先黑盒測(cè)試,待會(huì)在對(duì)照代碼測(cè)試。需要傳一個(gè)id。隨便傳一個(gè)id=1,返回?cái)?shù)據(jù),添加單引號(hào),報(bào)錯(cuò)。傳id=1' and '1'='1,也出錯(cuò)。傳id=1 and 1=1,返回正常,傳id=1 and 1=2返回異常。存在數(shù)字型注入。
嘗試union查詢,發(fā)現(xiàn)union被過濾了。接著用updatexml(1,concat(0x7e,(select database()),0x7e),1),發(fā)現(xiàn)concat被過濾了。用burpsuite的intruder模塊fuzz測(cè)試下,大概過濾了or,union,concat,sub,join這些關(guān)鍵字。直接盲注吧,用mid()代替substr(),id=2 and if(mid((select database()),1,1)='d',sleep(5),1)。
然后想起了or被過濾了,用不了information.schema,也就是說跑不了表名和列名。emmmm接下來盲猜一下它的表(admin,user,users之類的),猜到表名users,列名從頁面顯示中得到有(id,name,email,salary)。
如果實(shí)在不知道列名,可以通過這個(gè)姿勢(shì)
select `4` from (select 1,2,3,4 union select * from users)a
正常查詢

發(fā)現(xiàn)列名變成了1,2,3,4

成功查到第3列

但是這里過濾了union,此處用不上這個(gè)姿勢(shì)。
接著對(duì)應(yīng)著代碼看,先看index.php,大意是得到一個(gè)id,經(jīng)過stop_hack()處理,再用in_array()處理后查詢。
//index.php
<?php
include 'config.php';
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
die("連接失敗: ");
}
$sql = "SELECT COUNT(*) FROM users";
$whitelist = array();
$result = $conn->query($sql);
if($result->num_rows > 0){
$row = $result->fetch_assoc();
$whitelist = range(1, $row['COUNT(*)']);
}
$id = stop_hack($_GET['id']);
$sql = "SELECT * FROM users WHERE id=$id";
if (!in_array($id, $whitelist)) {
die("id $id is not in whitelist.");
}
$result = $conn->query($sql);
if($result->num_rows > 0){
$row = $result->fetch_assoc();
echo "<center><table border='1'>";
foreach ($row as $key => $value) {
echo "<tr><td><center>$key</center></td><br>";
echo "<td><center>$value</center></td></tr><br>";
}
echo "</table></center>";
}
else{
die($conn->error);
}
?>
在config.php中,過濾了一些關(guān)鍵字。
//config.php
<?php
$servername = "localhost";
$username = "root";
$password = "root";
$dbname = "day1";
function stop_hack($value){
$pattern = "insert|delete|or|concat|concat_ws|group_concat|join|floor|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile|dumpfile|sub|hex|file_put_contents|fwrite|curl|system|eval";
$back_list = explode("|",$pattern);
foreach($back_list as $hack){
if(preg_match("/$hack/i", $value))
die("$hack detected!");
}
return $value;
}
?>
再看下題解,發(fā)現(xiàn)它用make_set()替代了concat()。搜了一下它的用法
id=4 and (select updatexml(1,make_set(3,'~',(select flag from flag)),1))
make_set(bits,str1,str2,,,,),將第一個(gè)參數(shù)轉(zhuǎn)化為二進(jìn)制,在1處打印字符str,0處不打印,詳情如下
1的二進(jìn)制為0001,倒過來為1000,打印a。

2的二進(jìn)制為0010,倒過來為0100,打印b。

7的二進(jìn)制為0111,倒過來為1110,打印a,b,c。
[圖片上傳中...(圖片.png-7b38da-1562846283165-0)]