ShellCode #part 1

31.07.2008 21:35 | blackhole_socket

Tak kedže som v poslednej dobe na blackhole zanevrel a robil niektorim userom nervy pokusim sa to nejak odčinit dufam že dobrím článkom o shellkode, jeho rozdelení, tvorbe, použití :)

Zdrojový kód programu služiaci k napadnutiu a ovladnutiu procesu možeme rozdelit na dve zakladné časti:

  • funkcie, ktoré prevedu vloženie shellkodu a iniciujú jeho spustenie
  • samostatný shellkód

Podla metody konštrukcie shellkodu môžeme previesť nasledujúce rozdelenie:

    generický shellkód

    - Generický, alebo bežný shellkód prevedie vlastne iba čisté spustenie shellu. Jeho konštrukcia je priamočiara a vhodná pre dalšie rozširovanie funkčnosti a vlastností. Dva základné duhy sú :

    • Aleph One
      Tento shellkód pre zistenie adresy retazca "/bin/sh" využíva inštrukcie call.
    • Netric
      V tomto type generického shellkodu sa pre zistenie adresy retazca využíva jeho vloženie na zásobník a získanie adresy s registru ESP.

    nezavislý shellkód

    - Táto skupina shellkódov sa vyznačuje tým, že je možné previesť spustenie na viacerích operačných systémoch, resp. mikroprocesorových architektúrach. Dosahuje sa to pomocou úvodného 'magického' retazca, ktorý obsahuje postupnosť taktových bytov, že pre určitý OS/arch. majú dekódované inštrukcie význam skokov na natívny shellkod. Pre ostatné architektúry sa musí jednať o nepodstatné inštrukcie. Čím viac operačných systémov a architektúr shellkód zvláda, tým tažšie je najdenie úvodného retazca. Detekcia takéhoto shellkódu je pre antivsetko velmi lahká.

    • Shellkód nezavislý na operačnom systéme
      Táto varianta, umožnujúca spustenie len na jednej architektúre , je pomerne jednoduchá. Zložitý úvodný retazec netreba použiť. Stačí previest len rozsišenie specifických vlastností jednotlivých OS a následne skok na príslušný shellkód.
    • Shellkód nezavislý na architektúre
      Tu už magický retazec potrebujeme. Príkladom môže byť postupnosť bytov 0x90 0x90 0xeb 0x30. Procesory kompatibilné s x86 prevedú inštrukcie nop, nop a skok o 48B dalej, ale procesor Sparc prevedie nevýznamnú inštrukciu or.

    špecialny shellkód

    - Pretože generické a špecialne shellkódy idem pomerne lahko detekovat filtramy podľa špecifických sekvencií, začali útočníci používať alfanumerické a polymorfné shellkódy.

    • Alfanumerický shellkód
      Tento shellkód je tvorený len takými inštrukciami, ktorých hexadecimalna hodnota spadá do oblasti znakov alebo čísel v ASCII tabulke. Filtrovanie tekéhoto shellkódu je už tažké, pretože má tvar bežného textu a preto sa da velmi lahko umiestnit do vstupních polí ako sú meno adresára, predmet mailu a podobne.
    • Polymorfný shellkód
      Polymorfný shellkód sa skladá z bežného shellkódu a polymorfného API rozhrania, takže výsledkom kompilacie sú rôzne binárne podoby. Na tento druh sa velmi špatne aplikujú signatúrové IDS.

    bindshell

    - Bindshell je rozšírený shellkód, ktorý pripoji vstup a výstup shellu na volný port počítača/serveru. K takémuto portu sa potom už len stačí pripojiť (napríklad pomocou netcatu :P) a zadávať remote príkazy.



Prostredia

Zásobník


Zásobník je obsalť pameti, z ktorou pracujeme ako s frontou typu LIFO (Last In First Out). Príslušný segmentový sektor pre zásobník je register SS. Tento segmentovy register sa automaticky používa pre všetky zásobníkové operacie. Register ESP ukazuje na vrchol zásobníku. Keď použijeme instrukciu push, najprv sa hodnota ESP zmenší o velkosť operantu (napr. 4B) a potom sa hodnota operantu uloží na nový vrchol zásobníku. Pri výbere hodnoty zo zásobnku instrukcie pop sa hodnota najprv vyberie a potom ssa hodnota ESP zvetší o velkosť operandu (napr. 4B). Hovoríme, že zásobník rastie smerom ku nižším adresám. Register EBP sa používa pre vytvorenie lokálneho rámca funkcie na zásobníku. Premenné sú adresované posunom voči hodnote v regsitri EBP. Nad adresou obsadenou v registri EBP sa nachádzajú parametre predávané funkcii. Pod touto adresou sa nachádzajú lokálne premenné funkcie.

Proces v pameti


Pametový priestor procesu je rozdelený na niekolko oblastí (vid obrazok). Oblasti majú svoj význam, ktorý je daný príznakmy opravnení a kontextom. Pre nás sú najdôležitejšie príznaky ktoré povolujú zápis a spustitelnosť.
tab:


Dufam ze prekladat casti tabulky nie je potrebne.

Pozrime sa do akých pametových oblastí kompilátor jazyka C ukladá rozdielne typy premenných.
Globalne inicializované premenné (ich hodnota je známa v dobe kompilacie) sú umiestnené v oblasti data.
Globálne neiniciované premenné sú umiestnené v BSS. Lokálne premenné sa ukladajú na zásobník (stack). Dynamicky alokované oblasti pameti sa zakladajú v oblasti haldy (heap). Viac na priklade adries v pameti.

(gdb) list
1 /* shellkod1.c */
2 int a = 1; //data
3 int b;
4 int *c;
5
6 int main() {
7 int d; //stack
8 c = (int *)malloc(10); //heap
9 *c=0xAA;
10 return 0;
11 }
(gdb) break 10
(gdb) run
Breakpoint 1, main () at shellkod1.c:10
(gdb) print &a
$1 = (int *) 0x8049490
(gdb) info symbol 0x8049490
a in section .data
(gdb) print &b
$2 = (int *) 0x80495a8
(gdb) info symbol 0x80495a8
b in section .bss
(gdb) print &d
$3 = (int *) 0xbffffa38
(gdb) print &c
$4 = (int **) 0x80495ac
(gdb) x 0x80495ac
0x80495ac <c>: 0x080495b8
(gdb) print c
$5 = (int *) 0x80495b8
(gdb) x 0x80495b8
0x80495b8: 0x000000aa

(formatovanie tagu code je napicu);
Oblast ku je pristupna len pre čítanie a je používaná všetkými procesmy toho istého programu. Oblasť zásobníku je spustitelná. Existujú aj neoficiálne verzie linuxového jadra s nespustitelným zásobníkom a haldou. Bohužial, na takto upravenom jadre nefungujú niektoré programy.
Problémy vznikajú s nasledujúcich dôvodov:

Vnorené definicie funkcií
- Prekladač gcc implentuje rozšírenie jazyka C o vnorené funkcie. Môže dojsť k situácií na nasledújúcom príklade:

/* Ukazka vzniku trampoliny pri použití vnorených funkcií */
int spracuj(int (*addr)(int)) {
return addr(3);
}
int main() {
int x=2;
int interny_vypocet(int y) { return (x+y); }
return spracuj(interny_vypocet);
}

V tomto pripade je funkcia interny_vypocet() volaná mimo funkciu v ktorej bola definovaná. Tažko sa teda bude dostávať k lokálnym premenným funkcie main(). Situacia sa rieši tak, že funkcia main() vytvorí na zásobníku data, ktoré zodpovedajú inštrukciam presunu hodnoty z EBP do ECX a skok na funkciu interny_vypocet(). Tieto dve inštrukcie spustené zo zásobníku sa nazývajú trampolína.

Obslužné rutiny signálu
- Každý program môže vlastniť svoje rutiny pre obsluhu odchytitelných signálov. Pri doručení signálu jadro proces zastaví a na zásobník uloží data nutné pre pozdejšie obnovenie kontextu procesu. Dalej na zásobník vloží inštrukcie, ktoré prevedú vyvolanie obslužnej rutiny signálu a potom ukončenie systémového volania pomocou sigreturn(). Systémove volanie sigreturn() prevedie obnovenie kontextu procesu a odovzdá mu riadenie.

Funkcionálne jazyky
- Funkcionálne programovacie jazyky rovnako ako aj iné programy môžu závisieť na generovaní kódu na zásobníku za behu programu.

Prevedeni funkcie - tri kroky

Volanie funkcie


- Najprv sa na zásobník uložia parametre predávané funkcii. Ukladajú sa od konca. Tato konštrukcia umožnuje v jazyku C písať funkcie s premenným počtom parametrov. Potom sa uloží obsah registru EIP+5B. Hovoríme o tzv. návratovej adrese, 5B je dĺžka inštrukcie call s operandom. Táto adresa sa pozdejšie zo zásobníku vyberie a uloží speť do EIP.

Prolog funkcie


- Vytvorí sa nové prostredie pre funkciu. Najprv sa uloží na zásobník obsah registra EBP. Potom sa registrer EBP nastaví na rovnakú hodnotu, ako obsahuje refister ESP. Nakoniec sa register ESP zníži o potrebný počet bytov - tým sa vytvorí miesto pre lokálne premenne. Parametre funkcie maju teda oproti adrese v registri EBP kladné offsety. Lokalne premenne majú offsety záporné.

Epilog funkcie


- Vrátime stav zásobníka do rovnakého stavu, v akom bol pred volaním funkcie. Inštrukcie leave obnoví pôvodné hodnoty registrov EBP a ESP. Inštrukcia ret vyberie zo zasobníka návratovú adresu a uloží ju do EIP. Volajúce funkcie teraz už len odstránia zo zásobníku parametre.

Neštandartné využitie registru EBP

GNU kompilátor jazyka C umožnuje previesť volanie funkcie bez využitia registru EBP. Na všetky data uložené na zasobníku sa da odvolať pomocou offsetu a registru ESP. Pretože nedochádzajá k tvorbe lokálneho rámca na zásobníku pre danú funkciu, prolog funkcie uplne zaniká a návrat z funkcie je tovrený len inštrukciov ret. Register EBP je volný a môže byť použitý pre iné učely.
Na architektúre x86 s malým počtom všeobecných registrov sa da takto dospieť k významnj optimalizácií.
Túto optimalizáciu je vhodné previesť až po odladení programu. Súčasné trasovacie programy predpokladajú štandartné využitie registra EBP.

====================================
Tak ja už mám dosť, nabudúce (keď sa donútim) si preberieme samotnú tvoru shellkodu (ak si na to trufnem :D).

    • Re: ShellCode #part 1 01.08.2008 | 03:55
      Avatar vid   Používateľ

      Zaujimave, kopec z toho som nevedel. Inac si ma riadne zmylil tym 4B a 5B, ja ze su to hex cisla, nabuduce pre istotu napis rovno "4 bajty" :)

      To "nestandardne pouzitie EBP" je mam pocit na x86-64 uz standardom, aspon ja som este v zivote nevidel x86-64 kod co by nepouzival rovno stack pointer na adresaciu argumentov funkcie. Ani debuggeru by to nemalo robit problem, kedze sa to robi tak ze uz pri kompilacii sa zisti kolko lokalnej pamate bude treba, ta sa hned odpocita od SP, a pocas behu funkcie sa hodnota SP nemeni. Tym padom sa ani push/pop uz moc nepouziva. Akurat asi pri tejto metode asi velmi nejde pouzit alloca().

      PS: To co je preboha za blbost s tymi vnorenymi funkciami a "trampolinami"??? A kto to pouziva? Ja som teda uz videl vselico (vararg stdcall funkcie stoja za zmienku), ale toto je vazne sila.

      • Re: ShellCode #part 1 01.08.2008 | 10:40
        Avatar blackhole_socket   Používateľ

        viac z tejto teorie ti dojde pri tvorbe shellkodu, tam bude prakticky vydiet vyuzivanie chyb programov.
        PS. http://en.wikipedia.org/wiki/Trampoline_(computers)
        _______________________________________________________
        HTTP request sent, awaiting response... 200 OK

        • Re: ShellCode #part 1 01.08.2008 | 11:03
          Avatar blackhole_tommyhot   Používateľ

          Radsej odkazes na wiki, lebo ani sam nerozumies tomu, co si "pisal" (teda co si skopcil).

          Uz by si sa mohol prestat hrat na haxora, kazdy vie co si zac..
          ----------
          tommyhot@hackingmachine:~$ microsoft &> /dev/null

    • Re: ShellCode #part 1 01.08.2008 | 07:56
      Avatar blackhole_ventYl   Používateľ

      odporucam pred zverejnenim clanku tento prehnat nejakym spellcheckerom. mas v nom furu chyb, ktore by ti odhalil aj obycajny spellchecker vo firefoxe, keby si si ho obcas zapol.
      ---
      Cuchat s nadchou, to je ako sniffovat bez promiscu.

      --- Cuchat s nadchou, to je ako sniffovat bez promiscu.
    • Re: ShellCode #part 1 01.08.2008 | 10:57
      Avatar betmen   Používateľ

      >>Tak kedže som v poslednej dobe na blackhole zanevrel a robil niektorim userom nervy pokusim sa to nejak odčinit dufam že dobrím článkom o shellkode, jeho rozdelení, tvorbe, použití :)

      cim? dalsou kradezou cudzej prace? ruky by ti mali odseknut.
      http://www.google.sk/search?hl=sk&q=1+%2F*+shellkod1.c+*%2F&btnG=Hľadať+v+Google&meta=

      http://www.scycore.com/papers/low_linux_intro.pdf

      ______________
      nález plný strát

      ______________ kam by som chodil...na dvor
      • Re: ShellCode #part 1 01.08.2008 | 11:29
        Avatar blackhole_socket   Používateľ

        neviem na co narazas, ten odkaz mi nejde a tento clanok urcite nie je kradež, námet je s knihy LINUX - BEZPEČNOSŤ A EXPLOITY.
        _______________________________________________________
        HTTP request sent, awaiting response... 200 OK