[Home/Nieuws]  [Magazines]  [Meetings]  [Downloads]  [Redaktie]  [Geschiedenis]


Hakken op internet
door /dev/null

Ben je uitgekeken op het alleen maar draaien van het zoveelste exploitscriptje? Wil je wel eens weten HOE een beveiligingslek in elkaar zit? Lees dan vooral verder! "Hakken op Internet" is een serie voor de beginnende/gevorderde (doorhalen wat niet van toepassing is) hacker die meer wil. In deze aflevering wordt het Network File System van SUN onder de loep genomen.

Het doel van NFS is om een file system op een andere computer net zo te kunen lezen en beschrijven als ware het een file system op een harddisk van computer zelf. Aan de hand van een "praktijk"voorbeeld zullen we eens kijken wat er met NFS allemaal kan.

NFS voor de systeembeheerder
Stel, op een universiteit wordt een praktikumzaal ingericht voor een verse lichting informaticastudenten. Wel vier splinternieuwe SUN 3/60's zijn hiervoor ter beschikking gesteld en twee hiervan hebben zelfs een harddisk. Laten we ze kirk, spock, bones en scotty noemen. Hoera, denkt de systeembeheer, die we voor het gemak Cor zullen noemen, nu kan ik eindelijk eens dat Network Filesystem van Sun uitproberen.
Op kirk zet hij de home directories van de studenten onder /home/victims. Op spock komt de praktikum software in /usr/local/prak. Bones en scotty zijn zogeheten diskless clients, zij moeten hun root en swap file system mounten vanaf kirk. Wie wat mag mounten wordt bepaald in de file /etc/exports, dus Cor zet daar (op kirk en spock) het volgende neer:

# kirk's export list
/home/student-access=enterprise
/exports/root/bones-access=bones,root=bones
/exports/swap/bones-access=bones,root=bones
/exports/root/scotty-access=scotty,root=scotty
/exports/swap/scorty-access=scotty,root=scotty

# spock's export list
/usr-access=bones:scotty
/usr/local/prak-ro,access=enterprise

Links staan de te exporteren directories, rechts de opties waarmee ze geexporteerd worden en naar wie: "access" geeft aan naar wie de dir geexporteerd wordt. Als je deze optie weglaat mag de hele wereld bij de directory. Normaliter wordt UID van root gemapped naar -2, naar user "nobody" dus, dit heet een root squash. Het vertrouwen van root van alle hosts waar je een directory naar exporteert vonden ze zelfs bij SUN te ver gaan. Soms (zoals bij diskless clients) is het ongewijzigd laten van UID 0 onvermijdelijk en dan kan dat met "root" worden aangegeven. "ro" staat voor read only. Standaard worden directories read/write geexporteerd. Cor heeft "enterprise" gedefinieerd als een netgroup met alle hosts erin. Op de clients moet hij nu nog aangeven welke file systems waar gemount moeten worden. Dit gebeurt in /etc/fstab:

# bones fstab
kirk:/exports/root/bones/nfsrw00
spock:/usr/usrnfsrw00
kirk:/home/student/home/studentnfsrw00
spock:/usr/local/prak/usr/local/praknfsro00

Van de opties zijn hier alleen de voor zich sprekende "rw" en "ro" gebruikt. Later zullen we nog een paar andere opties tegenkomen.
Tot zover Cor's verrichtingen, we gaan nu over naar klingon.invader.com waar de interessante dingen gebeuren... Op klingon is de Prime Directive het leven zuur maken van systeembeheerders als Cor. Een van de middelen is root hacken via NFS. Voor we het aanvalsplan ontvouwen wordt eerst dieper ingegaan op de technische details van het NFS protocol.
Op een host die directories exporteert draaien altijd twee daemons: de mount daemon (mountd) en de NFS daemon (nfsd). De mount daemon wordt alleen gebruikt in opstartfase. Alle lees- en schrijfoperaties worden uitgevoerd door de NFS daemon.

RPC
NFS maakt gebruik van het Remote Procedure Call protocol van SUN. Via dit protocol kan een applicatie (de "client") procedures aanroepen van op een RPC gebaseerd programma (de "server") zoals de NFS daemon. Wanneer een server opstart moet het eerst bij een portmapper daemon informeren via welk protocol (TCP of UDP) en welke port het aanroepen accepteert.  Dit is nodig omdat RPC servers geen vaste port toegewezen gekregen hebben, in tegenstelling tot bijvoorbeeld de telnet daemon die altijd op port 23 te vinden is. Door middel van de utility 'rpcinfo' kun je bij de portmapper opvragen welke RPC servers er draaien op een host:

klingon:~> rpcinfo -p kirk.uni-harderwijk.nl

    program  versproto  port
    100000   2tcp111    portmapper
    100000   2udp111    portmapper
    100005   1udp725    mountd
    100005   1tcp727    mountd
    100003   2udp2049   nfsd
    100003   2tcp2049   nfsd
    100002   3udp878    rusersd
    100002   2udp878    rusersd
    100007   1tcp1025   rexd

Op de eerste twee regels vinden we (altijd) de entries voor de portmapper zelf. Deze luistert altijd op port 111. Het kan voorkomen dat rpcinfo "No remote programs registered" teruggeeft. Dit is dan natuurlijk pure leugenarij! Het betekent slechts dat de remote portmapper geen zin heeft om jou antwoord te geven. Gelukkig hoeft dat helemaal niet erg te zijn. Van de portmapper willen we slechts weten op welke ports we welke daemons kunnen vinden. Nu treft het dat om historische redenen de NFS daemon zich altijd naar port 2049 luistert. Met rpcinfo kunnen aankloppen om te kijken of er een NFS daemon aanwezig is:

klingon:~> rpcinfo -p 2049 -u remote_host 100005
program 100005 version 2 ready and waiting

Hoera! Contact. De mount daemon is wat moeilijker te bereiken, hij kan zich verschuilen achter de ports tot nummer 1024. Dat wordt dan dus een scriptje schrijven dat gewoon alle ports probeert. Als je eenmaal de juiste port voor een server hebt kun je er direkt calls naar toe sturen.

Authenticatie in RPC
Omdat servers vaak willen weten met wie ze te doen hebben zijn drie soorten authenticatie aanwezig in Sun RPC, te weten AUTH_NONE, AUTH_UNIX en AUTH_DES.
AUTH_NONE betekent geen authenticatie: de server weet alleen van welke host een request komt en beslist op grond daarvan wat hij doet. De rusersd is een voorbeeld van een daemon die aan AUTH_NONE genoeg heeft.
Bij AUTH_UNIX wordt ook meegegeven welke UID de client user heeft en welke tot welke groups hij behoort. Bewijs van echtheid van deze informatie wordt gegeven op de bij UNIX systemen gebruikelijke manier: als de client zijn request stuurt van een priviliged port moet de client applicatie wel root privileges hebben en zal de UID wel niet gelogen zijn. (Als je de root user van een host niet kunt vertrouwen, dan kan je geen enkele user op die host vertrouwen). Het is aan de server applicatie om te controleren of de request van een priviliged port komt, dit wordt niet geeist door het RPC protocol!

AUTH_DES maakt gebruik van DES encryptie en public key cryptografie voor de authenticatie. Deze methode is zo veilig dat het bijna nergens gebruikt wordt. Hiervoor mogen wij de regering van de VS danken, daar zij cryptografie beschouwt als munitie die niet geëxporteerd mag worden uit de VS.

Authenticatie in NFS
De authenticatie in NFS is gebaseerd op AUTH_UNIX (of AUTH_NONE op punten waar authenticatie geen rol speelt). Ondersteuning voor AUTH_DES is ook aanwezig, maar dit wordt zelden gebruikt. Het leuke is nu dat standaard de nfs daemon de authenticatie maar half uitvoert: er wordt wel gebruik gemaakt van de aangeleverde UID's en GID's, maar er wordt helemaal niet gekeken of de request van een priviliged port komt. Dit betekent dat je als gewone user requests kan doen met de UID en GID van wie je maar wilt! Om het nog mooier te maken, kan het de gemiddelde nfs daemon ook niet schelen van welke host de requests komen. Het enige dat waar het hem om draait zijn de zogeheten file handles.

File Handles
File handles zijn 32 byte lange pointers naar files of directories op de server. De nfs daemon gaat er van uit dat als je een geldige file handle geeft, het betreffende file system naar je geexporteerd wordt. Normaliter komt een client aan de handle van de top directory door deze te vragen bij de mount daemon. Dit is dus het "mounten". In /etc/rmtab houdt de mountd bij welke hosts welke directories gemount hebben. Met uitzondering van onder andere de Linux NFS server gebeurt er verder niets met deze informatie. Om met nfs te kunnen spelen is het dus erg belangrijk om aan file handles te komen. Hiervoor zijn een aantal mogelijkheden:

  • Gewoon vragen aan de mount daemon. Het gebeurt vaak genoeg dat een file system zoals /tmp naar iedereen wordt geexporteerd. Waarom dan moeilijk doen als het makkelijk kan.
  • Gebruik maken van de CALLIT procedure in de portmapper van de remote host. Deze doet dan een mount aanvraag bij de mount daemon voor jou. Dit wil nog wel eens een handle opleveren als een hosts directories naar zichzelf exporteert. Bijkomend voordeel: de portmapper draait als root, dus de mount request komt van een priviliged port.
  • Van het net afluisteren met een ethernet sniffer. Als je root privs hebt op een machine kun je al het ethernetverkeer op het locale net afluisteren inclusief file handles die NFS clients versturen.
  • Simpelweg raden. De effectiviteit hiervan is zeer variabel omdat de opbouw van een handle per systeem erg kan verschillen. Veel implementaties maken gebruik van inode generation numbers om het raden van handles moeilijker te maken. Ieder inode heeft zo'n nummer dat (pseudo) random genereerd is. Alleen file handles met het bij de inode passende inode generation number zijn geldig. De utility fsirand initialiseert de inode generation numbers, maar de systeem beheerder wil nog wel eens vergeten het draaien. Dan heb je geluk en zijn alle inode generation numbers gelijk aan nul. De Linux server werkt met een heel ander schema voor de file handles. Deze server vertrouwt niet op het geheim zijn van handles in tegenstelling tot bijvoorbeeld de SUN implementatie.

De Enterprise onder vuur
En dan nu een beschrijving van een simpele inbraak van de enterprise computers vanaf klingon.invaders.com:

1) Bemachtig de handle van kirk:/home/student door via de portmapper een mount request te doen.
2) Voeg klingon toe aan de .rhosts file van een student.
3) rlogin naar bones en bemachtig de handle van kirk:/exports/root/bones
4) Kopieer via NFS een shell naar bones met owner root en het SUID bit aan.
5) Run de shell op bones.

Bingo! Root access op bones. Door de root squash op de andere directories kun je op deze manier niet root op kirk of spock hacken .... Veel NFS servers bevatten gelukkig een bug waarmee de root squash omzeild kan worden. De hack procedure wordt daarmee dan wel erg eenvoudig. Andere interessante users als bin en daemon hebben geen last van een squash, dus in het ergste geval moet je deze als omweg naar root gebruiken.

Als Cor interesse in beveiliging had gehad, had hij het hacken moeilijker kunnen maken:

Door toevoeging van de optie "secure" in /etc/exports accepteert de nfs server geen requests meer van gewone users. Door toevoeging van de optie "nosuid" in /etc/fstab had hij kunnen voorkomen dat we een SUID executable kunnen draaien. Voor root file systems van diskless clients is deze optie natuurlijk niet mogelijk. *smile*

Bugs in NFS implentaties
Er zitten ook een aantal fijne bugs in diverse NFS implementaties. Ik zal er hier een paar opnoemen:

De UID masking bug. Wanneer een file system geexporteerd wordt met optie "root_squash" controleert nfsd of de client UID 0 heeft. In dat geval wordt de UID "gesquashed" naar UID 65534 (nobody). De UID's en GID's van de client worden via RPC doorgeven in 32 bits integers. De UID's en GID's op UNIX systemen zijn echter maar 16 bits. De bovenste 16 bits vallen dus weg. Echter de controle op UID 0 vindt vaak plaats voor die overgang van 32 naar 16 bits. Het gevolg is dat het gebruik van uid 65536 root access geeft op de server!

De mknod bug. De file attributes die men kan opgeven bij de aanroep van een file create call worden niet goed gecontroleerd. Hierdoor kan men nieuwe devices maken, hetgeen gewone users low level toegang geeft tot hardware en daarmee tot root.

De chdir bug. In dit geval levert het opvragen van ".." de parent directory op zelfs als deze niet geexporteerd wordt. Deze bug zul je niet vaak meer tegenkomen.

De 256 bytes exports bug. Door een bug in de mount daemon worden alle directorties naar iedereen geexporteerd als de /etc/exports file langer is dan 256 bytes.

De fsirand bug. De methode die fsirand gebruikt om willekeurige inode generation numbers te maken is niet willekeurig genoeg. Dit maakt het mogelijk om file handles te raden. Zie het programma nfsbug van Leendert van Doorn voor een implementatie hiervan.

De klooi maar raak bug. Ok, dit is niet echt een bug, maar gewoon het compleet ontbreken van security. De Linux nfs server tot en met versie 2.0 geeft schrijftoegang tot de gehele directory tree van een hosts, zelfs als er geen enkele directory geexporteerd wordt! Vanaf versie 2.1 is de server veel veiliger geworden: het voert bij iedere request volledige authenticatie van de client uit.

De bind() bug. Deze bug bevindt zich niet in de nfs server maar in de implementatie van de bind() routine in de kernel. Hierdoor kan een proces udp pakketjes of de tcp connectie stelen van een process dat luistert naar "INADDR_ANY" oftewel iedere port van ierdere host. Gevolg is dat een gewone user een eigen nfs server kan draaien die de taak van de originele overneemt. Een paar nieuwe 'features' in deze server doen dan de rest :-)
De ftp bounce attack. Met behulp van het PORT commando kan je de ftp daemon data laten sturen naar een willekeurige port op een willekeurige host. De verbinding komt in zo'n geval van port 20 (een priviliged port!). NFS servers die niet controleren of een request van zo'n port komt, kunnen dus voor de gek gehouden worden. Nadeel is nutuurlijk wel dat je geen antwoord terug krijgt. Dit hoeft geen probleem te zijn als je alleen wilt schrijven naar files waarvan je een handle hebt (en op linux kun je als user de handle van iedere voor je toegankelijke file berekenen).

Ik wil ook aan de slag!
Om het leven van de hacker te veraangenamen, hebben een aantal nijvere zielen op deze aarde software geschreven voor het experimeteren met NFS:
"nfsbug" is een utility geschreven door Leendert van Doorn, dat een host test op configuratie- en systeemfouten in NFS.
"nfsmenu" is een tool geschreven door Bastiaan Bakker, voor het manipuleren van een NFS file system. Hiermee kun je de bugs uitbuiten die nfsbug heeft opgespoord. Er zitten ook handle sniffers bij voor SunOS en Linux.
Beide programma's zijn te vinden op: http://www.klaphek.nl/files/.
Daar staat ook Request For Comment 1094, dat een specificatie van het NFS protocol bevat. Verplicht leesvoer dus!

De informatie in 't Klaphek dient slechts een educatief doel. Gebruik van deze informatie zou strafbaar kunnen zijn. De redaktie wijst iedere verantwoordelijkheid voor gebruik door lezers van de in 't Klaphek opgenomen informatie af. De mening van een auteur weerspiegelt niet noodzakelijkerwijs de mening van de redaktie of uitgever.