WEB40 无参RCE

web40

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 06:03:36
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/


if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
        eval($c);
    }
        
}else{
    highlight_file(__FILE__);
}

审计发现:禁用了0-9 之间的数字、~、反引号、@、#、$、%、^、&、*、中文的左括号、中文的右括号、-、=、+、{、[、]、}、英文冒号、单引号、双引号、逗号、<、>、/、?、\

方法1:

?c=show_source(next(array_reverse(scandir(pos(localeconv())))));

步骤分解:
localeconv()
返回包含本地化设置的数组,第一个元素通常是小数点字符.(当前目录)。

pos()
别名current(),获取数组第一个元素,即.。

scandir('.')
列出当前目录下的所有文件和目录,按字母升序排列,如['.', '..', 'file1', 'file2']。

array_reverse()
反转数组顺序,变为['file2', 'file1', '..', '.']。

next()
将数组指针从第一个元素移动到第二个,并返回其值。例如,反转后数组为['file2', 'file1', '..', '.'],next()返回'file1'。

show_source()
显示指定文件的源代码(语法高亮),若文件存在则输出内容,否则报错。

当前题目环境分布解析:

  1. localeconv()
    返回本地化信息数组,默认第一个元素是小数点 .(当前目录)。
    输出:['.', …]
  2. pos(localeconv())
    pos() 获取数组第一个元素,即 .。
    输出:'.'
  3. scandir('.')
    扫描当前目录,返回按字母升序排列的文件列表:
    输出:['.', '..', 'flag.php', 'index.php']
    (flag.php 在 index.php 前,因为字母 f < i)
  4. array_reverse()
    反转数组顺序,得到:
    输出:['index.php', 'flag.php', '..', '.']
  5. next()
    初始指针指向第一个元素 index.php。调用 next() 后,指针移动到第二个元素 flag.php,并返回该值。输出:'flag.php'
  6. show_source('flag.php')

方法2(此种方法仅为了解,无法获取到flag):

?c=session_start();system(session_id());

如下图,修改PHPSESSID为要执行的命令。由于PHPSESSID仅允许字符:a-z A-Z 0-9 , -(正则规则:[0-9a-zA-Z,-]),且长度通常限制为32或26字符,所有无法获取到flag

session_start()

功能:启动或恢复PHP会话。

检查请求中是否存在有效的会话ID(通常通过PHPSESSID Cookie)。

若无有效ID,生成新的会话ID并发送Set-Cookie头。

system(session_id())

  • session_id():返回当前会话的ID(字符串形式)。
  • system():执行系统命令并输出结果。
  • 组合逻辑
    • 将会话ID(PHPSESSID)作为命令传递给system()执行。
    • 攻击者通过篡改PHPSESSID的值注入恶意命令。

攻击原理

  1. 控制会话ID
    • 攻击者设置Cookie头:PHPSESSID=恶意命令
    • 例如:PHPSESSID=ls
  2. 触发Payload
    • 访问URL:?c=session_start();system(session_id());
    • session_start()读取攻击者设定的PHPSESSID
    • system(session_id())执行PHPSESSID中的命令(如ls

为什么需要session_start()

session_start() 是PHP会话管理的核心函数,其作用不仅仅是“启动会话”,更关键的是 将会话数据与当前请求绑定。以下是必须包含 session_start() 的原因:

1. 会话ID的读取依赖 session_start()

  • PHP默认不会自动读取客户端的 PHPSESSID Cookie,除非显式调用 session_start()
  • 如果没有 session_start()
    • session_id() 返回的是空字符串或上一次会话残留的ID。
    • 攻击者设置的恶意 PHPSESSID Cookie 不会被PHP识别,因此无法注入命令。

2. 会话数据的初始化

  • session_start() 会:
    1. 根据 PHPSESSID 加载或创建会话文件。
    2. 初始化 $_SESSION 数组。
    3. 将 session_id() 的值与当前请求关联。
  • 如果跳过这一步,session_id() 的值与 PHPSESSID Cookie 完全无关,攻击者无法通过Cookie传递命令。

消息盒子
# 您需要首次评论以获取消息 #
# 您需要首次评论以获取消息 #

只显示最新10条未读和已读信息