Simovits

Elasticsearch för trendanalys av Microsoft-buggar

Sedan senaste årens kritiska sårbarheter i Microsoft-baserade system har det surrats om huruvida det är värre nu än tidigare. Betyder det i sådana fall att patch-rutiner behöver uppdateras för att möta nya sårbarheter. Hur ofta behöver vi exempelvis räkna med att panik-patcha systemen och hur stor andel av tiden är en server sårbar i snitt ifall de använder mjukvara från Microsoft? Vi har ju förstås diverse Print Spooler-buggar som PrintNightmare [1], Exchange-buggar [2] och Zerologon [3] nära till hands som referens. Även PetitPotam [4] fick en del att höja på ögonbrynen.

Teorier framtagna med anekdoter är förstås ingen solid grund för att identifiera potentiella trender. Microsoft erbjuder ett API [5] för sin patch-data vilket ger en möjlighet att utföra en, självklart krasst rudimentär trendanalys, men ändå någon slags underbyggd indikation.

Jag skrev därför ett litet Python-skript [6] som ansluter mot Microsofts API och skjuter in data månad per månad. Januari 2016 valdes som startmånad på grundval av att det var startpunkt för Windows 2016. För att göra det smidigare att analysera data med Kibana gjordes en mindre databerikning där den högsta cvss-base-score valdes ut i varje logg-post och placerades i ett eget fält.

Skript

Skriptet är ett fåtal kodrader i Python som använder elasticsearch-klient-modulen för att ansluta mot Elasticsearch. För att förenkla analyser i Kibana görs en viss databerikning av CVSS-score där högsta CVSS base score lagras i ett separat flyttalsfält i Elastic. Notera även att tidsstämpeln för varje post sätts till senaste RevisionHistory. Det vill säga att en bugg som uppstår 2017 men korrigeras 2019 kommer få tidsstämpel 2019 (vi antar att revisions sätts i tidsordning i historik-vektorn). Detta sätt att hantera tidsstämpling har valts utifrån att Microsoft i vissa fall uppdaterar sårbarheternas karaktär i efterhand (se exempelvis [1]).

Se nedanstående urklipp ur skriptet som används för att skapa elastic-dokumentet nedan för att se hur berikningen funkar konkret.

 
def prepareElasticsearchDoc(esConnection, esTimestamp, doc, dtNow, uniqueId):
    if(esTimestamp == None):
        esTimestamp = "@timestamp"
    
    # Set the timestamp to the last revision
    if(doc['RevisionHistory'] != None):
        doc[esTimestamp] = timefunc( doc['RevisionHistory'][len(doc['RevisionHistory'])-1]['Date'])
    else:
        doc[esTimestamp] = timefunc(dtNow)

    highestBaseScore = 0.0
    highestTemporalScore = 0.0

    # Quite handy to parse out the highest scores. Sorting may also need to convert
    # objects to float (json inconsistencies have been seen in this dataset), hence some wonky linear search.
    if(doc['CVSSScoreSets'] != None):
        for bscore in doc['CVSSScoreSets']:
            tmpScore = float(bscore['BaseScore']) 

            if(tmpScore > highestBaseScore):
                highestBaseScore = tmpScore

            tmpScore = float(bscore['TemporalScore'])
            if(tmpScore > highestTemporalScore):
                highestTemporalScore = tmpScore

        doc['highestbasescore'] = highestBaseScore
        doc['highesttemporalscore'] = highestTemporalScore

    doc['ingesttime'] = timefunc(dtNow)           # Well, maybe not nice to hard code this.
    doc['vulnidentifier'] = uniqueId    # Well, maybe not nice to hard code this.

    return doc

Skriptet ansluter då det exekverar till Microsofts patch-databas via dess API och skjuter därefter in data i Elasticsearch månad för månad.

Parametrar

Nedan visas möjliga parametrar för skriptet

usage: msflaws2es.py [-h] [--month MONTH] [--proxy PROXY] [--start START] [--useragent USERAGENT]
                     [--basepath BASEPATH] [--elastichost ELASTICHOST] [--elasticindex ELASTICINDEX]
                     [--elasticuser ELASTICUSER] [--elasticpassword ELASTICPASSWORD] [--elastictls]
                     [--elasticskipcert] [--elasticport ELASTICPORT] [--elastictimefield ELASTICTIMEFIELD]

If no argument is given, the latest month is ingested.

optional arguments:
  -h, --help            show this help message and exit
  --month MONTH         Use this month
  --proxy PROXY         Proxy to use
  --start START         If we should ingest from a specific month, then this is it.  2021-Sep
  --useragent USERAGENT
                        User agent to use for requests
  --basepath BASEPATH   Use this path for microsoft cvrf
  --elastichost ELASTICHOST
                        Use this elasticsearch host for output (default=127.0.0.1)
  --elasticindex ELASTICINDEX
                        Use this elasticsearch index for output. Example: msflaws-#yyyy#
  --elasticuser ELASTICUSER
                        Use this elasticsearch user (if required by the elastic server)
  --elasticpassword ELASTICPASSWORD
                        Use this elasticsearch password (if required by the elastic server)
  --elastictls          Use if elasticsearch requires https (more common these days)
  --elasticskipcert     If specified no certificate validation occurs when connecting.
  --elasticport ELASTICPORT
                        If you have another port than 9200 for your elasticsearch 
  --elastictimefield ELASTICTIMEFIELD
                        Set the timefield for elasticsearch (default=@timestamp)

Test

För att skapa elastic-indexet gör enligt följande.

1. Installera Elasticsearch (https://www.elastic.co/guide/en/elasticsearch/reference/current/install-elasticsearch.html)

2. Installera Kibana (https://www.elastic.co/guide/en/kibana/current/install.html)

3. Ladda ned bloggens skript via git (förslagsvis)

git clone https://github.com/jamesrep/msflaws2es.git .

4. Exekvera skriptet (tar några minuter att exekvera klart)

python3 msflaws2es.py --start 2016-Jan --elastichost --elasticindex msflaws-blogg

Då skriptet exekverat klart ska ett elasticsearch-index skapats med patch-data från Januari 2016 (eller vilken startmånad man nu valt). Skriptet sparar historik över tidigare hämtad data i en historik-mapp i samma mapp som skriptet för att slippa skjuta in samma data flera gånger (ifall man vill göra en uppdatering av elastic-indexet).

Resultat

Vi vet inte huruvida Microsofts data är komplett eller innehåller felaktigheter vilka skulle kunnat påverka datakvaliteten. Antagandet är att Microsofts data via API-åtkomst av patchar kan användas för att analysera trender i sårbarheter för Microsoft-system. Det är svårt att hitta ett perfekt mått på vad som är en farlig kontra ofarlig sårbarhet. Särskilt ifall man tar aspekter som vart sårbarheten existerar i beaktande. Vi använder därför en grov och generell uppskattning av sårbarheternas allvarlighetsgrad baserad på CVSS base score nedan.

Baserat på uthämtning av Microsofts tillgängliga patchdata visas att Microsofts produkter har fått fler säkerhetsbrister senaste åren. Figuren nedan visar (graf i “stacked mode”) även en orange stapel med Remote Code Execution-sårbarheter vilket också visar på en ökande trend. Sökningen här bygger på att Microsoft noterat i beskrivningen för sårbarheten som ”Remote Code Execution”.

Ifall vi jämför antal, av Microsoft, uttryckligen beskrivna Remote Code Execution-brister (vilket naturligtvis ofta är högst intressanta vid penetrationstest/dataintrång) år för år:

Ett antal brister i webbläsare såsom Edge borde kunna rendera i RCE i praktiken men beskrivs ofta av Microsoft utifrån vad som är själva orsaken (Memory Corruption eller liknande) snarare än effekt. Ifall vi även lägger till resultat där något av CVSS-scores i sårbarheten har attack-vektor är Nätverk, Konfidentialitet Hög och Integritet Hög, vilket även borde tyda på någon slags Remote Code Execution, enligt följande Elastic-query.

NOT vulnidentifier:"Remote Code Execution" AND CVSSScoreSets.Vector:"AV:N" AND CVSSScoreSets.Vector:"C:H" AND CVSSScoreSets.Vector:"I:H"

Detta ger dock ingen större effekt på resultatet vilket visas i figuren nedan där varje stapel representerar antal i stacked mode.

Det kan finnas en effekt av att produkter har tillkommit år för år. Exempelvis finns förstås inga kända sårbarheter i Windows 2019 år 2017 innan det släppts. Dock borde bristerna inte ackumuleras från äldre produkter. Aspekten av vad det är som åstadkommer ökningen, det vill säga, ifall de nya produkterna har fler sårbarheter än de äldre, Microsofts rapportering blivit bättre etc. är inte analyserad i denna bloggpost. Det skulle dock kunna åstadkommas ifall man väger in fler parametrar såsom produktversioner och sårbarhetsklasser i analysen.

Tidsstämplarna i graferna i denna blogg räknas från senaste RevisionDate för varje bugg (om man kommer ihåg kodavsnittet). Så ifall Microsoft börjat att uppdatera tidigare revisions mer nu än tidigare så kommer det få effekten av att det ser ut som fler buggar men det kan egentligen vara att antalet revisioner på buggarna ökat. Detta är en viktig effekt att väga in. Ifall vi plottar grafen med överlapp mellan revisioner så ser vi ett visst sådant överlapp. Vissa buggar har en revision som sträcker sig mer än ett år efter den initiala revisionen. Dock är effekten att betrakta som försumbar i helheten.

Konkret, om vi tittar på år för år, utan hänsyn till revisionshistorik, dvs. vi istället baserar buggens uppståndelseår till CVE-nummer-dateringen (CVE-2021-xxxx antas buggen upptäckt 2021 osv.) så ser vi att det fortfarande är en tydlig ökning från 2019 och framåt. Se tabellen nedan.

Sammanfattning

Ökningen i upptäckta/patchade säkerhetsbrister är, baserat på statistik hämtat från Microsofts tillgängliga patch-api och de antaganden kring Microsofts data som görs i bloggposten, enligt eget tycke, dramatisk. Indikering finns i både ökning i antal och allvarligare sårbarheter. I system med säkerhetskrav, kan det i vissa fall därför vara av visst värde ta med detta i riskbedömningar och hantering av systemimplementationer som bygger på eller ansluter mot Microsoft-baserade plattformar. Det behöver inte konkret betyda att Microsofts system har blivit sämre utan kan bero på att rapporteringen kring systemen ökat från Microsofts sida (eller via extern part) eller att datakällan till Microsofts patch API förändrats senare åren.

Data som använts i denna blogg säger inte något om Azure-tjänster. I molntjänster, inklusive Azure, finns vanligen inte samma transparens över sårbarheter. CVE-nummer-systemet används exempelvis inte på samma sätt. Exempel på hur sårbarheter i Azure hanteras finns i beskrivningen av sårbarheten i Cosmos DB som offentliggjordes för ett par veckor sedan [8]. Transparens kring och hur sårbarheter i molntjänster bedöms/hanteras omfattas inte av det här blogginlägget men antas kunna vara ett högst intressant diskussionsämne framöver.

Referenser

[1] – PrinterNightmare – update guide – https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-34527

[2] – ProxyShell-bloggpost från Sophos – https://news.sophos.com/en-us/2021/08/23/proxyshell-vulnerabilities-in-microsoft-exchange-what-to-do/

[3] – Malwarebytes story of ZeroLogon – https://blog.malwarebytes.com/exploits-and-vulnerabilities/2021/01/the-story-of-zerologon/

[4] – PetitPotam – https://github.com/topotam/PetitPotam

[5] – Microsoft API för patch data – https://api.msrc.microsoft.com/cvrf/v2.0/swagger/index

[6] – Bloggens Python-skript för ingestion av microsoft-bugg-data till Elasticsearch – https://github.com/jamesrep/msflaws2es

[7] – Elasticsearch Downloads – https://www.elastic.co/fr/downloads/elasticsearch

[8] – ChaosDB – Azure Cosmos DB sårbarhet – https://chaosdb.wiz.io/