正则使用不当导致的路径穿越问题
Frost Pattern
- code
class TokenStorage {
public function performAction($action, $data) {
switch ($action) {
case 'create':
$this->createToken($data);
break;
case 'delete':
$this->clearToken($data);
break;
default:
throw new Exception('Unknown action');
}
}
public function createToken($seed) {
$token = md5($seed);
file_put_contents('/tmp/tokens/' . $token, '...data');
}
public function clearToken($token) {
$file = preg_replace("/[^a-z.-_]/", "", $token);
unlink('/tmp/tokens/' . $file);
}
}
$storage = new TokenStorage();
$storage->performAction($_GET['action'], $_GET['data']);
- preg_replace(函数执行一个正则表达式的搜索和替换)
-
payload
$action = $delete$data = ../../config.php
WeEngine0.8
- web/source/site/category.ctrl.php:176
file_delete文件删除函数

- framework/function/file.func.php:294
查看file_delete函数

- 追朔$file变量从何而来
if (!empty($navs)) {
foreach ($navs as $row) {
file_delete($row['icon']);
}
- 追朔$navs从何而来
$navs = pdo_fetchall("SELECT icon, id FROM ".tablename('site_nav')." WHERE id IN (SELECT nid FROM ".tablename('site_category')." WHERE id = {$id} OR parentid = '$id')", array(), 'id');
- web/source/site/category.ctrl.php:137

- web/source/site/category.ctrl.php:130

$nav[‘icon’] 即为文件删除函数的参
parse_str函数缺陷
- parse_str
parse_str的作用就是解析字符串并且注册成变量,它在注册变量之前不会验证当前变量是否存在,所以会直接覆盖掉当前作用域中原有的变量。

preg_replace函数之命令执行
Candle
- code
header("Content-Type: text/plain");
function complexStrtolower($regex, $value) {
return preg_replace(
'/(' . $regex . ')/ei',
'strtolower("\\1")',
$value
);
}
foreach ($_GET as $regex => $value) {
echo complexStrtolower($regex, $value) . "\n";
}
- preg_replace(函数执行一个正则表达式的搜索和替换)
mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )
$pattern 存在 /e 模式修正符,允许代码执行
/e 模式修正符,是 preg_replace() 将 $replacement 当做php代码来执行
将GET请求传过来的参数通过complexStrtolower函数执行,preg_replace函数存在e修正符
- payload
S*=${phpinfo()}
参考
CmsEasy 5.5
- 环境搭建

漏洞分析
- lib/tool/form.php:90
如果$form[$name][‘default’]内容被匹配到就会执行eval

- cache/template/default/manage/#guestadd.php:175
全局搜索getform,主要注意catid是作为$name的

- lib/table/archive.php:25
追朔catid,寻找到default

- lib/tool/front_class.php:2367

- lib/tool/front_class.php:493

- lib/tool/front_class.php:332
$form[$name][‘default’]可控

- lib/default/manage_act.php:29

- 测试

str_replace函数过滤不当
Rabbit
- code
class LanguageManager {
public function loadLanguage() {
$lang = $this->getBrowserLanguage();
$sanitizedLang = $this->sanitizeLanguage($lang);
require_once("/lang/$sanitizedLang");
}
private function getBrowserLanguage() {
$lang = $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? 'en';
return $lang;
}
private function sanitizeLanguage($language) {
return str_replace('../', '', $language);
}
}
(new LanguageManager())->loadLanguage();
- str_replace(子字符串替换)
str_replace(字符串1,字符串2,字符串3):将字符串3中出现的所有字符串1换成字符串2。
str_replace(数组1,字符串1,字符串2):将字符串2中出现的所有数组1中的值,换成字符串1。
str_replace(数组1,数组2,字符串1):将字符串1中出现的所有数组1一一对应,替换成数组2的值,多余的替换成空字符串。
- payload
....// 或者 ..././
Metinfo 6.0.0
- strstr
查找字符串的首次出现到结尾的字符串

漏洞分析
- app/system/include/module/old_thumb.class.php:14

- include/thumb.php:6
全局搜索

- app/system/include/class/load.class.php:113

- payload
http://localhost/metInfo/include/thumb.php?dir=.....///http/.....///最终用户授权许可协议.txt
程序未恰当exit导致的问题
Anticipation
- code
extract($_POST);
function goAway() {
error_log("Hacking attempt.");
header('Location: /error/');
}
if (!isset($pi) || !is_numeric($pi)) {
goAway();
}
if (!assert("(int)$pi == 3")) {
echo "This is not pi.";
} else {
echo "This might be pi.";
}
- extract
从数组中将变量导入到当前的符号表

- payload
pl=phpinfo()
- 测试

FengCms 1.32
- install/index.php
如果安装完成会生成INSTALL文件,访问文件如果存在此文件则会弹窗提示退出,但没有及时exit,导致程序逻辑还是往下走,还是会安装

Simple-Log1.6网站重装漏洞
- install/index.php
访问文件如果存在此文件则会弹窗提示退出,但没有及时exit,只是跳转到首页,导致程序逻辑还是往下走,还是会安装

Tips整理
- parse_str
parse_str的作用就是解析字符串并且注册成变量,它在注册变量之前不会验证当前变量是否存在,所以会直接覆盖掉当前作用域中原有的变量
- preg_replace
$pattern 存在 /e 模式修正符,允许代码执行
/e 模式修正符,是 preg_replace() 将 $replacement 当做php代码来执行
- extract
从数组中将变量导入到当前的符号表
- 尾声
本系列是弟弟跟着红日安全产出的代码审计教程系列学习的,原项目地址:[PHP-Audit-Labs]
(https://github.com/hongriSec/PHP-Audit-Labs)
原创文章,作者:syst1m,未经授权禁止转载!如若转载,请联系作者:syst1m