Open-source-operativsystemdistribusjonen OpenBSD er velkjent blant systemadministratorer, spesielt de som administrerer servere, for sitt fokus på sikkerhet over hastighet, funksjoner og fancy front-ends.
Passende nok er logoen kanskje en pufferfisk – oppblåst, med piggene klare til å avvise alle listige hackere som måtte komme.
Men OpenBSD-teamet er sannsynligvis ikke mest kjent for hele distroen, men for verktøysettet for ekstern tilgang OpenSSH som ble skrevet på slutten av 1990-tallet for inkludering i selve operativsystemet.
SSH, forkortelse for sikkert skall, ble opprinnelig laget av en finsk informatiker Tatu Ylönen på midten av 1990-tallet i håp om å avvenne systemadministratorer fra den risikable vanen med å bruke Telnet-protokollen.
Problemet med Telnet
Telnet var bemerkelsesverdig enkelt og effektivt: i stedet for å koble til fysiske ledninger (eller bruke et modem over en telefonlinje) for å lage en teletype-tilkobling til eksterne servere, brukte du en TELetype NETwork-tilkobling i stedet.
I utgangspunktet ble dataene som vanligvis strømmet frem og tilbake over en dedikert seriell tilkobling eller oppringt telefonlinje sendt og mottatt over internett, ved å bruke en pakkesvitsjet TCP-nettverkstilkobling i stedet for en kretssvitsjet punkt-til-punkt-kobling .
Samme kjente påloggingssystem, billigere tilkoblinger, ikke behov for dedikerte datalinjer!
Den gigantiske feilen i Telnet var selvfølgelig dens totale mangel på kryptering, slik at det var trivielt å snuse opp den eksakte terminaløkten din, slik at crackere kunne se hver kommando du skrev (selv feilene du gjorde, og alle gangene du traff [Backspace]
), og hver byte med utdata som produseres...
…og, selvfølgelig, brukernavnet og passordet ditt ved starten av økten.
Alle på nettverksbanen din kunne ikke bare enkelt rekonstruere sysadmin-sesjonene dine i sanntid på sin egen skjerm, men sannsynligvis også tukle med økten din ved å endre kommandoene du sendte til den eksterne serveren og falske svarene som kom tilbake slik at du ikke la merke til underskuddet.
De kan til og med sette opp en bedragerserver, lokke deg til den og gjøre det overraskende vanskelig for deg å oppdage bedraget.
Sterk kryptering FTW
Ylönens SSH hadde som mål å legge til et lag med sterk kryptering og autentisering til hver ende av en Telnet-lignende økt, og skape en sikkert skall (det er det navnet står for, hvis du noen gang har lurt på, selv om nesten alle bare kaller det ess-ess-aitch disse dager).
Det ble en umiddelbar hit, og protokollen ble raskt tatt i bruk av systemadministratorer overalt.
OpenSSH fulgte snart, som vi nevnte ovenfor, og dukket først opp på slutten av 1999 som en del av OpenBSD 2.6 slipp.
OpenBSD-teamet ønsket å lage en gratis, pålitelig, åpen kildekode-implementering av protokollen som de og alle andre kan bruke, uten noen av lisensierings- eller kommersielle komplikasjoner som hadde belastet Ylönens opprinnelige implementering i årene umiddelbart etter utgivelsen.
Faktisk, hvis du kjører Windows SSH-serveren og kobler til den fra en Linux-datamaskin akkurat nå, vil du nesten helt sikkert stole på OpenSSH-implementeringen i begge ender.
SSH-protokollen brukes også i andre populære klient-servertjenester, inkludert SCP og SFTP, en forkortelse for sikker kopi og sikker FTP hhv. SSH betyr løst, "koble til sikkert og kjør et kommando-SHell i den andre enden", typisk for interaktive pålogginger, fordi Unix-programmet for et kommandoskall vanligvis er /bin/sh
. SCP er lik, men for kopiering av filer, fordi Unix-filkopi-kommandoen vanligvis kalles /bin/cp
, og SFTP heter omtrent på samme måte.
OpenSSH er ikke det eneste SSH-verktøysettet i byen.
Andre kjente implementeringer inkluderer: libssh2, for utviklere som ønsker å bygge SSH-støtte rett inn i sine egne applikasjoner; dropbear, en nedstrippet SSH-server fra australsk koder matt johnston som er mye funnet på såkalte IoT (Internet of Things) enheter som hjemmerutere og skrivere; og PuTTY, en populær, gratis samling av SSH-relaterte verktøy for Windows fra uavhengig åpen kildekodeutvikler Simon Tatham i England.
Men hvis du er en vanlig SSH-bruker, har du nesten helt sikkert koblet til minst én OpenSSH-server i dag, ikke minst fordi de fleste moderne Linux-distribusjoner inkluderer det som standard fjerntilgangsverktøy, og Microsoft tilbyr både en OpenSSH-klient og en OpenSSH server som offisielle Windows-komponenter i disse dager.
Dobbeltfri feilretting
OpenSSH versjon 9.2 kom akkurat ut, og den utgiv notater rapporter som følger:
Denne utgivelsen inneholder reparasjoner for […] et minnesikkerhetsproblem. [Denne feilen] antas ikke å kunne utnyttes, men vi rapporterer de fleste nettverks-tilgjengelige minnefeil som sikkerhetsfeil.
Feilen påvirker sshd
, OpenSSH-serveren (den -d
suffikset står for daemon, Unix-navnet for den typen bakgrunnsprosess som Windows kaller en tjeneste):
sshd(8): fikse en dobbeltfri minnefeil før autentisering introdusert i OpenSSH 9.1. Dette antas ikke å kunne utnyttes, og det skjer i den uprivilegerte forhåndsgodkjenningsprosessen som er underlagt chroot(2) og er ytterligere sandkasset på de fleste større plattformer.
En dobbeltfri feil betyr at en minneblokk du allerede har returnert til operativsystemet for å bli gjenbrukt i andre deler av programmet...
… vil senere bli overlevert igjen av en del av programmet som ikke lenger "eier" det minnet, men som ikke vet at det ikke gjør det.
(Eller overlevert bevisst ved oppfordring til kode som prøver å provosere feilen med vilje for å snu en sårbarhet inn i et utnytte.)
Dette kan føre til subtile og vanskelige å løse feil, spesielt hvis systemet markerer den frigjorte blokken som tilgjengelig når den første free()
skjer, tildeler den senere til en annen del av koden din når den ber om minne via malloc(
), og merker deretter blokken fri igjen når det overflødige kallet til free()
vises.
Det etterlater deg i den typen situasjon du opplever når du sjekker inn på et hotell som sier: «Åh, gode nyheter! Vi trodde vi var fulle, men en annen gjest bestemte seg for å sjekke ut tidlig, slik at du kan få rommet deres.»
Selv om rommet er pent rengjort og klargjort for nye beboere når du går inn, og dermed ser ut som om det var riktig tildelt for ditt eksklusive bruk, må du fortsatt stole på at den forrige gjestens nøkkelkort faktisk ble korrekt kansellert, og at deres " tidlig utsjekking» var ikke en utspekulert list å snike seg tilbake senere samme dag og stjele den bærbare datamaskinen.
Feilretting for feilretting
Ironisk nok, hvis du ser på den nylige OpenSSH-kodehistorikken, vil du se at OpenSSH hadde en beskjeden feil i en funksjon kalt compat_kex_proposal()
, brukes til å sjekke hvilken type nøkkelutvekslingsalgoritme som skal brukes når du setter opp en tilkobling.
Men å fikse den beskjedne feilen introduserte en mer alvorlig sårbarhet i stedet.
Tilstedeværelsen av feilen i en del av programvaren som brukes under oppsett av en tilkobling er forresten det som gjør dette til en såkalt nettverks-tilgjengelig forhåndsgodkjenning sårbarhet (eller feil før godkjenning for kort).
Den dobbeltfrie feilen skjer i kode som må kjøres etter en klient har startet en ekstern økt, men før du enhver nøkkelavtale eller autentisering har funnet sted, så sårbarheten kan i teorien utløses før noen passord eller kryptografiske nøkler har blitt presentert for validering.
I OpenSSH 9.0, compat_kex_proposal
så omtrent slik ut (veldig forenklet her):
char* compat_kex_proposal(char* suggestion) { if (condition1) { return suggestion; } if (condition2) { suggestion = allocatenewstring1(); } if (condition3) { suggestion = allocatenewstring2(); } if (isblank(suggestion)) { error(); } return suggestion; }
Tanken er at den som ringer sender inn sin egen minneblokk som inneholder en tekststreng som foreslår en nøkkelutvekslingsinnstilling, og får tilbake enten en godkjenning for å bruke selve forslaget de sendte inn, eller en nylig tildelt tekststreng med et oppdatert forslag .
Feilen er at hvis betingelse 1 er usann, men betingelsene 2 og 3 er sanne, allokeres koden to nye tekststrenger, men returnerer bare en.
Minneblokken tildelt av allocatenewstring1()
blir aldri frigjort, og når funksjonen kommer tilbake, er minneadressen tapt for alltid, så det er ingen måte for noen kode å free()
det i fremtiden.
Den blokken er i hovedsak forlatt, noe som forårsaker det som er kjent som en hukommelsestap.
Over tid kan dette føre til problemer, kanskje til og med tvinge serveren til å slå seg av for å komme seg etter minneoverbelastning.
I OpenSSH 9.1 ble koden oppdatert i et forsøk på å unngå å tildele to strenger, men å forlate en av dem:
/* Always returns pointer to allocated memory, caller must free. */ char* compat_kex_proposal(char* suggestion){ char* previousone = NULL; if (condition1) { return newcopyof(suggestion); } if (condition2) { suggestion = allocatenewstring1(); } if (condition3) { previousone = suggestion; suggestion = allocatenewstring2(); } free(previousone); } if (isblank(suggestion()) { error(); } return suggestion; }
Dette har den dobbeltfrie feilen, fordi hvis betingelse 1 og betingelse 2 begge er usanne, men betingelse 3 er sann, tildeler koden en ny streng som skal sendes tilbake som svar ...
…men frigjør feil strengen som den som ringte opprinnelig sendte inn, fordi funksjonen allocatenewstring1()
blir aldri kalt for å oppdatere variabelen suggestion
.
Den innsendte forslagsstrengen er minne som tilhører den som ringer, og at den som ringer derfor vil frigjøre temaer senere, noe som fører til den dobbeltfrie faren.
I OpenSSH 9.2 har koden blitt mer forsiktig, og holder styr på alle tre mulige minneblokker som brukes: originalen suggestion
(minne eies av noen andre), og to mulige nye strenger som kan tildeles underveis:
/* Always returns pointer to allocated memory, caller must free. */ char* compat_kex_proposal(char* suggestion) { char* newone = NULL; char* newtwo = NULL; if (condition1) { return newcopyof(suggestion); } if (condition2) { newone = allocatenewstring1(); } if (condition3) { newtwo = allocatenewstring2(); } free(newone); newone = newtwo; } if (isblank(newone)) { error(); } return newone; }
Hvis betingelse 1 er sann, brukes en ny kopi av den innsendte strengen, slik at den som ringer kan senere free()
deres innsendte strengs minne når de vil.
Hvis vi kommer forbi betingelse 1, og betingelse 2 er sann, men betingelse 3 er usann, vil det alternative forslaget opprettet av allocatenewstring1()
blir returnert, og sendt inn suggestion
streng blir stående alene.
Hvis betingelse 2 er usann og betingelse 3 er sann, blir en ny streng generert og returnert, og det sendes inn suggestion
streng blir stående alene.
Hvis både betingelse 2 og betingelse 3 er sanne, blir to nye strenger tildelt underveis; den første blir frigjort fordi den ikke er nødvendig; den andre returneres; og den vedtatte suggestion
streng blir stående alene.
Du kan RTxM for å bekrefte det hvis du ringer free(newone)
når newone
is NULL
, så "ingen operasjon utføres", fordi det alltid er trygt å free(NULL)
. Likevel beskytter mange programmerere seg robust mot det med kode som f.eks if (ptr != NULL) { free(ptr); }
.
Hva gjør jeg?
Som OpenSSH-teamet foreslår, vil det være vanskelig å utnytte denne feilen, ikke minst på grunn av de begrensede privilegiene som sshd
programmet har mens det setter opp tilkoblingen for bruk.
Likevel rapporterte de det som et sikkerhetshull fordi det er det det er, så sørg for at du har oppdatert til OpenSSH 9.2.
Og hvis du skriver kode i C, husk at uansett hvor erfaren du er, er minnebehandling lett å ta feil...
...så ta vare der ute.
(Ja, Rust og dens moderne venner vil hjelpe deg med å skrive riktig kode, men noen ganger må du fortsatt bruke C, og til og med Rust kan ikke garantere det stoppe deg med å skrive feil kode hvis du programmerer uforbeholdent!)
- SEO-drevet innhold og PR-distribusjon. Bli forsterket i dag.
- Platoblokkkjede. Web3 Metaverse Intelligence. Kunnskap forsterket. Tilgang her.
- kilde: https://nakedsecurity.sophos.com/2023/02/03/openssh-fixes-double-free-memory-bug-thats-pokable-over-the-network/