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!
|