Naar de inhoud

Blog ·

Een match die weigert zeker te zijn

Vier feiten uit vier bronnen, uit elkaar gehouden. Waarom een KEV-vermelding nooit een ernst verhoogt, en waarom alleen een begrensd versiebereik echt telt.

Door Provibr

Een bannerscanner leest SSH-2.0-OpenSSH_8.9p1 van een poort en schrijft een product en een versie op. Een kwetsbaarheidsfeed zegt dat een reeks versies van dat product een bekend probleem heeft. Die twee bij elkaar leggen is één regel code en een van de makkelijkste manieren om een securityscherm te bouwen dat binnen een maand niemand meer vertrouwt.

De reden is dat de twee zinnen niet dezelfde soort bewering zijn. De ene is een meting van een dienst die tegen jou kan liegen. De andere is de bewering van iemand anders over een versiebereik dat mogelijk geschreven is voordat de reparatie bestond. Een scherm dat ze als één getal toont heeft precies datgene weggegooid waarmee een klant zou kunnen beslissen wat hij moet doen.

Vier feiten uit vier bronnen

Er zitten vier losse beweringen in deze machine heeft CVE-1234.

  • Bereikbaar is gemeten. Er kwam op een bepaald moment een TCP-verbinding tot stand.
  • De versie is afgeleid. Wij knipten een token uit een begroeting, en de dienst kan zo ingesteld zijn dat hij van alles zegt, en een distributie kan een patch teruggezet hebben zonder het nummer te wijzigen.
  • De advisory is van iemand anders. NVD zegt dat een versiebereik van een product getroffen is.
  • Actief misbruikt is opnieuw een derde partij. CISA zegt dat dit CVE in het wild gebruikt wordt.

Het blijven vier kolommen. Ze tot één score vermenigvuldigen is precies de betekenisloze samenstelling die de specificatie van deze functie verbiedt, en een vermelding in de catalogus van actief misbruikte kwetsbaarheden als een ernstverhoging behandelen is dezelfde fout in het klein.

Een KEV-vermelding verhoogt dus nooit een ernst. De ernst komt uit de CVSS-basisscore en verder nergens uit, de zekerheid blijft laag omdat het bewijs een banner is, en misbruik is een eigen kolom met drie standen: ja, nee, en niet van toepassing voor bevindingen die helemaal niet op een advisory rusten. Gemeten op de fixtures: een Exim-advisory op CVSS 9,8 is kritiek en draagt een KEV-vlag; een OpenSSH-advisory op 8,1 is hoog en draagt er geen. De 9,8 is kritiek vanwege zijn score en niet vanwege de vlag.

De catalogus kan bovendien per constructie geen match op eigen kracht opleveren. Hij draagt een CVE-id, een leverancier, een productnaam en een datum, en helemaal geen versiebereiken. Apache HTTP Server tegen een banner leggen zou gokken zijn. Hij zet alleen ooit een vlag op een advisory die NVD al aan een versiebereik gekoppeld heeft.

De feeds zijn platformtabellen

Beide feeds leven in tabellen zonder organisatiekolom. Een CVE is van niemand: het is geen persoonsgegeven, het is niet de data van een klant, en het is dezelfde rij voor elk account op het platform. Hij zit dus niet in de opruiming die draait als een organisatie sluit, en niet in een AVG-export. De koppeling tussen een bevinding en een advisory is wél van de klant, en die zit in allebei.

De ophaler heeft een allowlist op de host en niet op de URL, en de URL's zelf staan in code. Een worker die een URL uit de omgeving of uit de database leest is een request-forgeryprimitief met een planner eromheen: wie die waarde kan zetten laat onze gateway een verzoek doen vanuit ons netwerk, met onze uitgaande adressen. De host van elke uiteindelijke URL wordt ook getoetst, zodat een omleiding naar een andere host geweigerd wordt in plaats van gevolgd.

De waarheidstabel

Bij een productnaam die overeenkomt en een CPE-regel uit de advisory zijn er precies drie mogelijke antwoorden, en de meeste interessante regels leveren het middelste op.

Waargenomen versieDe CPE-regelUitkomst
wat dan ookproductnaam wijkt afniets
niet te lezenwat dan ookmogelijke match, ongeverifieerd
leesbaarexacte versie, gelijk, update pastadvisorymatch
leesbaarexacte versie, gelijk, update wijkt afmogelijke match, ongeverifieerd
leesbaarexacte versie, ongelijkniets
leesbaarbereik mét bovengrens, erbinnenadvisorymatch
leesbaarbereik mét bovengrens, erbuitenniets
leesbaaralleen ondergrens, erbovenmogelijke match, ongeverifieerd
leesbaarhelemaal geen grenzenmogelijke match, ongeverifieerd

Alleen CPE-regels met part a, voor applicatie, tellen mee. Een o voor besturingssysteem of een h voor hardware zou Ubuntu 22.04 aan een SSH-banner hangen, en dat is precies de soort match die overtuigend oogt en niets betekent: wij zagen de dienst en niet het systeem eronder.

De regel waar iets over te zeggen valt is alleen een ondergrens. Een regel die zegt alles vanaf 8.0, zonder bovengrens, omvat versies die ná de advisory uitkwamen en het probleem al opgelost hadden. NVD schrijft bereiken zo op als de reparatie nog niet gepubliceerd was, en herziet ze achteraf niet altijd. Zo'n regel op een machine plakken zou een gepatchte server als kwetsbaar melden, en na twee van die meldingen leert een klant het hele scherm negeren. Ongeverifieerd is het eerlijke etiket, en ongeverifieerd is geen kleinere uitvoering van bevestigd. Het is een andere bewering.

Draagt één advisory tientallen CPE-regels, één per getroffen release, dan wint de sterkste uitkomst. Slaat er één exact aan, dan is dat het antwoord, ook als er tien vage naast staan.

Een herbeoordeling schrijft een nieuwe revisie en raakt geen bewijs

Feeds veranderen. NVD herziet een score, een bereik wordt versmald, een CVE dat vorige week matchte doet dat niet meer. De sweep die open bevindingen tegen de huidige feeds herbeoordeelt heeft één harde regel: hij schrijft of wijzigt nooit een occurrence.

Een occurrence is het antwoord op was het er om 03:14. Daar verandert een feedupdate niets aan. Wat wél verandert is de conclusie eroverheen, en die krijgt een nieuwe rij in de assessmenttabel met een eigen revisiekenmerk dat beide feedmomentopnames noemt. Gemeten: na het verplaatsen van een advisory van CVSS 9,8 naar 7,5 kwamen de bestaande occurrencerijen byte-identiek terug.

Een verdwenen match sluit de bevinding als closed_unverified en nooit als resolved_verified. Die tweede is een uitspraak over een meting, en er is niet gemeten. Wat veranderde is onze eigen afleiding. De naam is de hele reden dat die status bestaat.

Er wordt ook niets geschreven als er niets veranderd is. De momentopname wordt eerst vergeleken met het vorige oordeel, want een sweep die elke ronde een rij wegschrijft levert binnen een maand honderdtwintig identieke assessments onder elke bevinding op, en dan is de tijdlijn onleesbaar.

Geen sweep zonder een geslaagde feed

De laatste grendel kostte de minste code en voorkomt de ergste uitkomst.

Is er nog nooit een feed geslaagd, dan is de huidige advisoryrevisie leeg en keert de sweep meteen terug zonder ook maar iets te bekijken. Zonder die controle zou hij draaien, merken dat de kandidatenvraag niets oplevert, en élke advisorygebaseerde bevinding bij élke klant sluiten als niet meer matchend. Een hele vloot zou groen worden op grond van een feed die stuk is.

Een mislukte ophaling laat bovendien de vorige cache staan mét zijn eigen tijdstip van slagen, zodat de twee vragen wanneer probeerden we het voor het laatst en wanneer slaagden we voor het laatst twee losse kolommen zijn in plaats van één hoopvolle.

Wat dit kost, en wat het oplevert

De kosten zijn dat het scherm veel regels mogelijke match, ongeverifieerd toont, en die zijn minder bevredigend dan een getal. Een beheerder moet er eentje bekijken en beslissen of de versie die hij draait werkelijk getroffen is.

Wat het oplevert is dat de regels die als bevestigd gemarkeerd staan het waard zijn om op te handelen, en dat elke regel uit elkaar te halen is in de vier feiten waaruit hij is opgebouwd: wat er gemeten is, wat er afgeleid is, wat iemand anders beweerde, en wat gewoon niet bekend is. Een bevinding die niet kan uitleggen waar elk deel van zichzelf vandaan komt is een bevinding die iemand op een dag zal leren overslaan.

Uit het securitywerk van Provibr. Waarom een exposurescan die een banner leest helemaal geen payload verstuurt staat in een scanner die nul bytes verstuurt, en waarom een incident nooit door stilte gesloten wordt staat in een incident dat nooit op stilte sluit.

Begin met één host en één agent

Maak een account aan, installeer de agent met één commando en koppel je eerste Proxmox-host. De proefperiode loopt 14 dagen en vraagt geen betaalgegevens.