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


Crackatoa
door Tla

To err is human...
De nieuwste rage op het World Wide Web (Internet volgens sommigen) is Java. Java is een objectgeoriënteerde programmeertaal gemaakt door Sun. Java is makkelijk, heeft garbage collection, is multi-threaded en zo heeft het nog meer dingen die door Sun als "voordeel" gepresenteerd worden. Java wordt niet direct naar machinecode gecompileerd, maar naar een pseudomachinecode (Java bytecode), die uitgevoerd wordt door de Virtual Machine. In plaats van de bytecode te interpreteren is het ook mogelijk hem om te zetten naar echte machinecode. Dit wordt gedaan door de Just In Time Compiler (JIT).
Tot zover heeft het weinig met hacken te maken. De reden dat Java ineens zo populair geworden is, is omdat Sun een webbrowser (HotJava) heeft gemaakt die een bepaald soort Java programmaatjes, de zogenaamde applets, in een webpagina kan laten uitvoeren (Deze applets hebben overigens niet zo veel te maken met de programmeertaal Java, ze hadden even goed in Pascal of COBOL (hoewel) geschreven en vervolgens naar bytecode gecompileerd kunnen zijn. Ik zal om de verwarring nog groter te maken zowel de programmeertaal als het idee van applets uitvoeren met de naam 'Java' aanduiden). Door een speciale tag in HTML wordt de bytecode van je applet opgehaald via het netwerk en volledig automagisch op de machine van de persoon die je pagina opvraagt uitgevoerd. Dit is wel een hele aantrekkelijke manier om in te breken en het is nog maar de vraag of het jouw schuld is als iemand bij zichzelf jouw inbraakprogramma opstart (bewust of onbewust, in het laatste geval zal het misschien wel onder de wet computercriminaliteit vallen). Applets hebben in meer of mindere mate toegang tot bepaalde resources van de machine waar ze op draaien. Sun kan maar niet genoeg zeggen dat Java secure is. Kortom: dit vraagt gewoon om gehackt te worden. Kunnen we Java straks qua security in dezelfde categorie als NFS en SunOS (ook beiden van Sun) plaatsen?

...to hack divine
Doordat Java zo simpel is, geen manipulaties op pointers kan uitvoeren, type checking heeft bij een typecast en nog meer van dit soort dingen, is het niet meer mogelijk om "per ongeluk" foutjes te maken in java code zoals bijvoorbeeld het gebruik van gets() of sprintf() in C. Om op dit niveau te hacken zul je dus zelf met opzet stoute bytecode moeten gaan maken, een echte brasaap schrijft hiervoor natuurlijk even een compilertje. Er is alleen één maar: de Javamakers hebben hier rekening mee gehouden en een hoop zaken die normaal compile time zouden gebeuren, gebeuren nu runtime, zoals het toekennen van adressen aan references van objecten, type checking en zo voort. Deze runtime checks worden uitgevoerd door de Byte Code Verifier. Het is aan de Turing-fans onder ons om hier iets leuks mee te doen (laat de verifier zichzelf maar eens proberen te verifiëren). Per ongeluk foutjes maken onmogelijk maken lijkt een utopie. En inderdaad, ook bij Java gaat de wet van behoud van ellende op; je kunt nog steeds per ongeluk een foutje maken dat de veiligheid aantast. Zo komen we op iets redelijk nieuws: objectgeoriënteerd hacken.

OOH! (Object Oriented Hacking)
In Java is elk programma een zogenaamde class. Een class kun je zien als de beschrijving van een bepaald iets. Laten we een voorbeeld nemen uit de Abstract Window Toolkit (AWT) die bij de Java Developer's Kit (JDK) geleverd wordt, namelijk een window. Een window heeft een aantal eigenschappen, zoals een positie, een grootte, een voor- en achtergrondkleur. Deze eigenschappen worden vastgelegd door een aantal variabelen (fields). Verder zijn er nog een aantal operaties die op een window uitgevoerd kunnen worden, zoals verplaatsen, vergroten of verkleinen, naar de voorgrond halen of naar de achtergrond zetten, het window tekenen etc. Deze operaties worden vastgelegd door functies die werken op de fields (memberfuncties of methods). In Java zou dit er als volgt uitzien (erg versimpeld):

public class Window
{
public Color fore, back; // foreground and background colors
private int w,h; // width and height
protected int x,y; // position

public int getWidth() { return w; }
public int getHeight() { return h; }

private void changeColor(Color c) { /* verander de kleur */ }

protected void fillRect(int xx, int yy, int ww, int hh)
{
/* teken een gevulde rechthoek op (xx,yy) met breedte ww en hoogte hh */
}

protected void drawBorder(int xx, int yy, int ww, int hh)
{
/* teken een kader op (xx,yy) met breedte ww en hoogte hh */
}

public void show()
{
changeColor(back);
fillRect(x,y,w,h);
changeColor(fore);
drawBorder(x,y,w,h);
}

// constructor, cre"eert een instantiatie van de class Window public Window(int xx, int yy, int ww, int hh)
{
x=xx; y=yy; w=ww; h=hh;
/* ... */
}
}

Bovenstaand stukje code definieert een window. Het is nu gewoon mogelijk om variabelen van het type Window te gebruiken. De waarde van zo'n variabele is een instantiatie van de class. Zoiets heet een object. Een voorbeeldje:

Window score_window, game_window;

// maak een window van grootte 100x100 op positie (23,43)
game_window = new Window(23,43,100,100);
// geef het window een kleurtje
game_window.fore = Color.black;
game_window.back = Color.yellow;

score_window = game_window;
// score_window refereert nu aan hetzelfde window als game_window!

// laat maar zien
game_window.show();
// wat mooi een geel met zwart window
// nu verander je score_window (dus eigenlijk game_window) van kleur
score_window.back = Color.green;
// laat maar zien
game_window.show();
// hee, een groen met zwart window

Nu enige uitleg: De class Window heeft twee variabelen van het type Color. Hiervoor staat public en dit wil zeggen dat deze variabelen bij elk Window object op te vragen en te veranderen zijn vanuit elk stuk code. Vervolgens zijn er twee variabelen die private zijn. Dit betekent dat alleen methods van de class Window (of iedere instantie hiervan) deze variabelen kunnen opvragen en wijzigen. protected betekent iets soortgelijks, op het verschil komen we later terug. Vervolgens staan er een aantal methods gedefinieerd, ook weer met dezelfde woorden ervoor. Bij een method betekent public dat de method vanuit elk stuk code aan te roepen is, en private en protected komen er op neer dat alleen methods van een class deze method aan kunnen roepen.

Het tweede stukje code laat het gebruik zien van de Window class. Zoals je ziet kunnen twee verschillende variabelen naar hetzelfde object wijzen. Deze beruchte eigenschap staat bekend onder de naam aliasing. Aliasing wordt meestal beschouwd als een nadeel, bij veel aliasing is haast niet meer na te gaan over welk object het nu gaat.

Stel dat we nu een ander soort window willen maken, dat een aantal extra eigenschappen heeft naast het oorspronkelijke window. We hoeven dan niet weer opnieuw alles in te typen, maar maken een zogenaamde derived class of subclass van de class Window (dit heet dan de base class of superclass). In de AWT bestaat er een subclass genaamd Frame. Deze heeft als extra's o.a. een titel en een ikoontje. In Java zou dit er zo uitzien (wederom versimpeld):

// extends Window geeft aan dat we een subclass van Window willen
public class Frame extends Window
{
private MenuBar menubar;
public Image iconimage;

protected showicon() { /* teken het ikoontje */ }

public iconify()
{
/* laat het window van het scherm verdwijnen */
showicon();
}
}

De class Frame heeft nu alle fields en methods van een Window en elk Frame object kan als een Window object benaderd worden. Verder heeft een Frame een aantal extra fields en methods. Als in een subclass een method gedefinieerd wordt die ook al in de superclass stond dan vervangt de method van de subclass die van de superclass.
Dan nu eindelijk de verklaring van al die irritante worden als private. Dit zijn access modifiers en bepalen of je de waarde van een field mag opvragen of veranderen of een method mag aanroepen. Er zijn vier toegangsnivo's:

  • public : Iedereen mag deze method aanroepen of dit field veranderen of bekijken.
  • private : Alleen memberfuncties van deze class mogen deze method aanroepen of bij dit field komen.
  • protected : Alleen memberfuncties van de classes uit dezelfde package als deze class of memberfuncties van een subclass van deze class hebben toegang tot de memberfunctie of het field. Een package is een verzameling classes, zo is java.awt de package voor de grafische user interface.
  • private protected : Alleen memberfuncties uit deze class of uit een subclass hiervan hebben toegang.

Deze modifiers worden veel gebruikt in systeemclasses om low-level calls af te schermen. Dit gaat als volgt:

class FileSystem
{
private void remove(File f)
{
// code voor remove
}
public void RemoveFile(File f)
{
// doe een securitycheck
// als alles in orde is:
remove(f);
}

// ... nog meer methods
}

Door onzorgvuldig gebruiken of helemaal niet gebruiken van deze modifiers sluipen er security bugs in programma's. Als in bovenstaand voorbeeld remove nu niet private, maar protected (of zelfs private protected) was, dan hadden we de volgende truuk uit kunnen halen:

class HackedFileSystem extends FileSystem
{
public void RemoveFile(File f)
{
// doe GEEN securitycheck
remove(f);
}
}

Als we een andere class (bijvoorbeeld eentje van je webbrowser) nu wijs kunnen maken dat er een HackedFileSystem gebruikt moet worden in plaats van een gewone FileSystem, dan kunnen we files weghalen.

Soms is het niet aantrekkelijk om alle low-level calls private te maken, omdat dan veel te veel checks uitgevoerd moeten worden, ook bij classes die je vertrouwt en waarvan je weet dat ze veilig zijn ("Trust is your worst enemy" gaat ook hier op). Meestal zitten deze "trusted" classes in dezelfde package en is de low-level call protected. Om te voorkomen dat bovenstaande truuk werkt kun je het woordje final toevoegen op één van de volgende twee plaatsen:

  • Voor de method: public final void RemoveFile. Dit betekent deze method in een subclass niet opnieuw gedefininiëerd mag worden.
  • Voor de class: final class FileSystem { ... }. Dit betekent dat er geen subclass van deze class gedefiniëerd mag worden.

Al deze access modifiers maken de boel wel erg complex en dat is vaak de reden dat er toch per ongeluk security bugs ontstaan.

Het laden en uitvoeren van bytecode
Helaas zitten de bugs niet allemaal in de access modifiers (dan zou het wel heel makkelijk zijn om te hacken). De meer ernstige bugs vergen de nodige inventiviteit en moeite om op te sporen. Ze bevinden zich in het mechanisme dat de bytecode via het netwerk ophaalt en uitvoert.
De Java bytecode wordt door een zogenaamd ClassLoader object opgehaald. Vervolgens worden er allerlei controles uitgevoerd doordat de ClassLoader aan de Byte Code Verifier vraagt om de bytecode te checken. Hierbij worden de types van argumenten, de access modifiers van methods en dergelijke gecontroleerd en ook of de bytecode zich naar behoren gedraagt (stack overflow, illegal typecast). Tevens wordt aan elke class een namespace toegekend en classes worden eerst in de lokale namespace gezocht (waarin alleen maar brave applets zitten) en dan pas in de andere namespaces. In principe is het dus niet interessant om een systeemclass na te maken, omdat deze toch niet geladen wordt als er een echte systeemclass nodig is. In de eerste Java versies bleek er echter niet altijd eerst lokaal gezocht te worden. Als we het systeem een zelfgemaakte ClassLoader kunnen laten draaien kunnen we de typechecking en de namespaces-check omzeilen en zo stoute bytecode uitvoeren. Een andere fout was dat er niet op de private modifier gelet werd zodra een class lokaal geladen werd. Op die manier was het mogelijk je eigen SecurityManager (zie hierna) in te stellen.
De security checks die tijdens het uitvoeren plaatsvinden worden uitgevoerd door een zogenaamd SecurityManager object. De security manager bepaalt wat een applet wel en niet mag, zoals toegang tot het filesystem of het netwerk. Dit is gedaan zodat iedereen die een Java implementatie maakt zelf de security kan bepalen (zodat Sun geen verantwoordelijkheid heeft). Het namaken en laten draaien van een zelfgemaakte security manager is dan ook een ideale hack.

Zelfs al lijkt de SecurityManager veilig, dan is er via een omweg wel weer iets mee te doen, zoals het volgende verhaal illustreert: Een tijd geleden was het mogelijk om een applet een connectie te laten maken met een willekeurige host. Door zelf een nameserver te draaien die liegt kon je, door de applet een hostname op te laten vragen waarbij je zeker wist dat jouw DNS server gebruikt werd, twee IP nummers aan de browser terugsturen die overeenkwamen met het IP nummer waar de applet vandaan kwam en het IP nummer van de host waarnaar je wilt connecten. Op die manier dacht de SecurityManager van de browser dat het IP nummer van die host een IP nummer was waarvan de applet kwam en zodoende werd de netwerkconnectie toegelaten. Zodoende was het simpel om door een firewall heen te komen. Het schijnt nu niet meer te kunnen.

Een andere leuke fout was de volgende: als een naam van een class met een '/' begon, probeerde je webbrowser deze class van het lokale filesystem te laden. Een class die je lokaal laadt, mag meestal meer dan een class die via het netwerk binnenkomt. Als je nu op een of andere manier een bytecode op het systeem van het slachtoffer kan zetten (anonymous ftp, NFS of zelfs de cache van de webbrowser(!), in het laatste geval moet je natuurlijk wel de naam van de cachefile weten), dan kun je via een omweg meer privileges krijgen. Overigens: waarschijnlijk kun je de naam van de cachefiles via een omweg in JavaScript te weten komen, het gaat echter te ver om dat hier uit te leggen. Toen ik wat aan het "spelen" was met een beeehhta versie van Netschaap 3.0 kwam ik erachter dat dit eigenlijk wel moet kunnen, maar ik moet nog proberen of het echt werkt.

Naast de ClassLoader en de SecurityManager zijn er ook heel wat andere classes gevoelig voor fouten. Denk bijvoorbeeld aan applets voor betalingsverkeer via het internet, of classes voor encryptie.

De omgeving
De technieken hierboven lijken allemaal wel mooi in theorie, om ze in de praktijk te laten werken heb je wel geluk nodig. Een eigen ClassLoader of SecurityManager laten draaien is leuk, maar de webbrowser moet het toevallig maar toestaan. Er zijn echter ook een aantal "features" in de Java omgeving die op een goede of op een slechte, maar in ieder geval op een simpele manier gebruikt kunnen worden:

  • Java heeft Threads, stukjes code die je in de achtergrond kan laten draaien. Een Thread kan zelf bepalen welke prioriteit hij nodig heeft en zo een webbrowser flink vertragen door ook nog eens een hoop geheugen op te eten.
  • Een applet kan een window buiten de browser op het scherm zetten. Er is geen grens aan het aantal of de grootte.
  • Een applet kan irritante geluiden afspelen of ongewenste plaatjes op het scherm zetten.
  • Een applet kan methods aanroepen van applets op dezelfde pagina. Met een slecht ontworpen applet valt er misschien iets te hacken. Bij een encryptie class zou je de seed voor een randomgetal misschien in kunnen stellen. Om bij de andere classes op een webpagina te komen moet een applet zijn AppletContext object opvragen door de method getAppletContext(). Door van deze AppletContext weer de method getApplets() aan te roepen krijg je de applets terug. Overigens is dit in Netscape versie 3 uitgezet. Nu mogen alleen applets van dezelfde host methods van elkaar aanroepen. In hoeverre dit met frames in Netscape te combineren is heb ik nog niet uitgezocht, maar misschien dat een combinatie van Java en JavaScript wat kan helpen (Java en JavaScript zijn in Netscape versie 3 te combineren).

De meeste Java implementaties zijn niet beveiligd tegen het opvreten van al het systeemgeheugen of het permanent laten lopen van Threads. Iemand pesten via het Internet is nu dus extreem makkelijk geworden en daarom lichtelijk flauw. Overigens hoeft een applet niet eens te zien te zijn op de webpagina; op die manier kun je een javan horse maken. Sterker nog: je kunt een applet een Thread op laten starten en die niet meer laten stoppen. Deze Thread kan een poosje wachten en pas in actie komen als de user al lang van de webpagina af is. Dit is overigens heel simpel om te maken, de mogelijkheden zijn standaard al aanwezig.

Tegenmaatregelen
Een aantal van de mogelijkheden in Java waar iemand misbruik van kan maken is natuurlijk inherent aan het hele idee van Java. Als je bijvoorbeeld niet wil dat er ongevraagd code uitgevoerd wordt op je machine moet je Java niet gebruiken. Wil je het toch dan zijn er verschillende oplossingen:
Heb je computers zat en een netwerk, dan gebruik je één machine om op te websurfen met een Java-enhanced browser. Deze machine moet zelf niet alles mogen in het netwerk anders heeft het weinig zin. Ben je erg paranoïde dan bekijk je eerst de source van elk HTML document dat je ophaalt. Een HTML-tag met een applet die je niet ziet in je document kan verdacht zijn. Overigens betekent dit niet dat je hiermee alle ongewenste applets detecteert, iemand die zijn javan horse goed wil verbergen verstopt hem in een "nuttige" applet.
Sun komt ooit nog met het concept van signed classes, op deze manier kun je er redelijk zeker van zijn dat een bepaalde class van de goeie persoon afkomstig is. Tegen de "annoyance attacks" is in de meeste gevallen wel iets te doen: je kunt bijvoorbeeld een optie in je browser maken waarmee je alle classes ziet die in het geheugen zitten (of alleen die classes die via het netwerk binnengekomen zijn). Hiermee moet je dan ook bepaalde classes weg kunnen gooien of bepaalde Threads kunnen stoppen. Het is vreemd dat zo'n mogelijkheid (nog) niet in de browsers te vinden is.

Meer Java brouwsels
Java is met een ontzettende hype de wereld in gebracht. Het is voortgekomen uit een mislukt project dat te maken had met set-top boxes (toentertijd nog niet populair). Door dit te porten naar het Internet begon het zonnetje weer te schijnen voor Sun. De bedoeling is om met Java de heerschappij van MicroSoft aanzienlijk aan te tasten en Sun is razend enthousiast over Java. Maar liefde maakt blind en er vinden een aantal ontwikkelingen plaats waarvan ik me afvraag of er over de beveiliging goed nagedacht wordt. Enkele voorbeeldjes:
Toen Java begin 1995 populair begon te worden bleek dit voor sommige mensen niet simpel genoeg ("compileren? wa-isda?") en bij Netscape begon men aan een scripttaaltje voor in een HTML document onder de naam JavaScript. Inmiddels heeft MicroSofts Internep Exploder ook al Java en JavaScript support. In JavaScript is het mogelijk om met je browser allerlei leuke geintjes uit te halen, zoals een nieuw document window openen, rekenen in je html pagina etc. Ook hiermee zijn minder ethische dingen te doen; een poosje geleden kon je, zodra iemand je pagina bezocht, de browser een mailtje namens diegene laten versturen zonder dat hij/zij het merkte. In versie 3.0 van Netscape kunnen er ook methods van applets aangeroepen worden en kan vanuit een applet JavaScript code uitgevoerd worden. De veiligheid van je browser kan hiermee flink verminderen, met een beetje geluk kan een hacker op deze manier bij iedere applet komen die actief is in een willekeurig window. Ook moet het bij Netscape op deze wijze mogelijk zijn allerlei details van een systeem op te kunnen vragen, zoals de directorytree van een host die voor de user readable is (kun je remote ls of dir doen).
Voor de Windows 95 versie van Netscape 3.0 is er al een JIT in de browser gebakken. Het zou me niets verwonderen als de JIT een security bug bevatte. Natuurlijk kun je de virtual machine ook in hardware bouwen. Maak een kastje waarop je een keyboard, muis, monitor en telefoonlijn kan aansluiten en je hebt een Network Computer (NC) gemaakt. Volgens sommigen de opvolger van de PC, maar dit vereist een betrouwbaar netwerk (en dus niet het Internet). Als je aan de client kant zo makkelijk programma's kan uitvoeren, waarom dan ook niet aan de server kant? Dit kan inderdaad ook als je een soort van RPC mechanisme bouwt, waarmee een class aan de kant van de client methods aan de kant van de server kan uitvoeren en misschien ook wel andersom. Dit zal over een tijdje ongetwijfeld het CGI programmeren gaan vervangen, maar als je even nadenkt vraag je je af of we zoiets niet al hadden, RPC bestaat immers al lang. Wat het ook wordt, er zal flink wat aandacht besteed moeten worden aan de beveiliging.

Tenslotte zijn er nog wat wilde ideeën om Java in het OS in te bouwen. Hiermee veroorzaak je nog meer risico qua security. Hetgene dat dan beveiligd moet worden is immers veel belangrijker dan alleen een browsertje. Het lijkt wel sinterklaasfeest voor de hacker. Zoveel nieuwe speeltjes, daar moet wel lol mee te beleven zijn! Het security beleid bij Java is tot nu toe zo geweest dat de bugs pas gemeld werden nadat ze verholpen waren. Dit is niet echt leerzaam voor de hacker en ook heeft het als nadeel dat er niet door een grote groep van mensen over een oplossing nagedacht wordt. Verder geeft Java de mogelijkheid om erg privacy aantastende dingen te doen. Bijvoorbeeld als je straks on-line muzieksamples kan downloaden (tegen elektronische betaling), dan is binnen de kortste keren je muzieksmaak bekend bij de aanbieder en door middel van applets kan hij/zij hier direct op inspelen. Met de commercialisering van het Internet zal dit steeds belangrijker worden voor bedrijven. De consument moet het allemaal maar slikken. Maar dat is weer een ander verhaal.


Meer lezen/spelen
Een van de allereerste artikelen over Java Security is "Java Security" van Joseph A. Bank, (http://swissnet.ai.mit.edu/~jbank/javapaper/javapaper.html). Het gaat over object oriented hacking in Java en de maatregelen die Sun heeft genomen om dit tegen te gaan. Echte bugs worden niet besproken, alleen de security voor zover die betrekking heeft op het Java-idee. Het artikel van Drew Dean, Edward W. Felten en Dan S. Wallach daarentegen behandelt de bugs in de implementaties van de web browsers HotJava en Netscape. Het heet "Java Security: From HotJava to Netscape and Beyond" en staat op http://www.cs.princeton.edu/sip/Publications.html. Het is lekker technisch en staat vol met sappige details. Alhoewel het meeste niet meer werkt kan het toch helpen om nieuwe bugs op te sporen. Het misbruik van features in webbrowsers is te bekijken en te beleven (inderdaad, er staan voorbeelden bij) op de zogenaamde "Hostile Applets Homepage" van Mark D. LaDue (http://www.math.gatech.edu/~mladue/HostileApplets.html) Enkele leuke voorbeelden zijn The Business Assassin, die er voor zorgt dat je de applets van een bepaalde host niet meer kan draaien, een fakemail applet en een applet die een groot produkt van twee priemgetallen ontbindt zonder dat je dit in de gaten hebt en het resulaat terugstuurt naar zijn schrijver. Natuurlijk is er ook de java homepage van Sun (http://java.sun.com/ of http://www.javasoft.com/), waarop je de Java produkten en documentatie kan vinden. Om aan de source code te komen is iets lastiger; hiervoor moet je eerst een overeenkomst uitprinten, ondertekenen en naar Amerika faxen, vervolgens krijg je het password voor de ftp server en kun je de source downloaden. Als je een Java compiler en interpreter wilt hebben kun je die ook van deze site halen, maar alleen voor Solaris, Macintosh en Windows. Een JDK voor Linux is te halen op http://java.blackdown.org/. Een hoop Java applets en pgramma's staan op Gamelan (http://www.gamelan.com/). Er zit allicht ook wat over security bij.

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.