Appearance
Bash scripting a Command injection
Nyní už se konečně dostáváme k prvnímu útoku, Command injectionu. Před tím než si vysvětlíme tento útok, je nutné vysvětlit si jak je možné spojovat více příkazů za sebou a jak je možné mezi sebou předávat vstupy a výstupy růzdných příkazů.
Váš terminál je skriptovací jazyk
Doteď jsme v terminálu vždy jen spoušteli jednotlivé příkazy a někdy jsme jim předávali argumenty. (jako cd <složka>) Většina shellů (program který podle zadaného textu spouští růzdné příkazy) podporuje mnohem větší funkcionalitu, první ze všech je tzv. exit code.
Exit code
Každá (správná) aplikace, kterou můžeme spustit by měla vracet exit code, jednoduchý číselný indikátor podle kterého shell pozná zda v příkazu došlo k chybě. (nenulový exit code) Příkladem je třeba exit code 1 pokud se snažíme přečíst soubor který neexistuje pomocí cat supersusamongus.
Exit code programu se zapisuje do proměnné pojmenované ?, (o proměnných více později) tedy můžeme si ho vypsat pomocí printf $?. Je nutné si však uvědomit že historie exit kódů se neukládá, takže pokud jste před vypsáním spustili další příkaz, vypíše se vám kód posledního spuštěného příkazu.
Proměnné
Jak jsem zmínil dříve, váš terminál je skriptovací jazyk, a většina programovacích jazyků se neobejde bez proměnných. Proměnné jsou pojmenované hodnoty, které mohou být později použity jako argument nebo dokonce jako příkaz.
Proměnnou můžeme vytvořit stejně jako když spouštíme příkazy, jen vše musí být zapsáno správně.
bash
MOJE_JMENO=Marek
Příklad výše vytvořil proměnou pojmenovanou MOJE_JMENO. Stejně jako jsme před chvílí vypsali proměnnou ?, můžeme si vypsat i tuto novou proměnou (echo $MOJE_JMENO) to nám vypíše Marek.
Co když ale nepoužiju echo a napíšu pouze $MOJE_JMENO, co se stane?
shelly interpretují naše proměnné před spuštení příkazu, takže z příkazu $MOJE_JMENO se najednou stane příkaz Marek a na to nám shell řekne že žádný takový příkaz nezná.
bash: command not found: Marek
pokud by však v proměnné byla hodnota jako pwd, nedošlo by k žádné chybě, ale spustil by se příkaz pwd, takže by se vypsala naše aktuální složka. (/home/kbbstudent)
Kombinování více příkazů
Poslední věc kterou si ohledně bash skriptování v této kapitole řekneme je jak spouštět více příkazů najednou. Místo toho abychom museli vždy čekat než doběhne předchozí příkaz, můžeme zkombinovat více příkazů dohromady a nemusíme čekat. Kombinování je možné více způsoby, podívejme se na první:
bash
wget muj.velmi.zajimavy.film/video.mp4; vlc video.mp4
Pomocí středníku (;) shellu řekneme že končí náš první příkaz a začíná druhý, tyto příkazy se spustí po sobě, tedy příkaz vlc se spustí až po stažení souboru video.mp4. Co když ale uprostřed stahování vypadne internet? Vlc se pokusí otevřít soubor, který neexistuje nebo soubor, který není kompletní, proto můžeme příkazy kombinovat i logickými operátory. && znamená AND neboli a, pokud místo středníku na spojení příkazů použijeme &&, druhý příkaz se spustí pouze pokud ten první byl úspěšný.
bash
wget muj.velmi.zajimavy.film/video.mp4 && vlc video.mp4
Jak jsme si před chvílí říkali, každý program vrací nějáký exit code a pokud je tento code 0 náš shell ví, že příkaz byl spuštěn bez chyby. Výše upravený příkaz tedy stáhne video.mp4 a pokud je stažení úspěšné, tak se pomocí programu přehraje, pokud však stažení úspěšné není, wget vrátí jiný kód než 0 a příkaz vlc se nespustí
Poslední způsob o kterém si v této kapitole řekneme je || neboli OR, to je přesný opak &&, tedy spustí následující příkaz pouze pokud exit code předchozího příkazu nebyl 0, tedy pokud v předchozím příkazu došlo k chybě. Díky tomu můžeme udělat například následující.
bash
cd test || (mkdir test && cd test)
Tento příkaz se pokusí přejít do složky test a pokud neexistuje se ji pokusí vytvořit a pak do vytvořené složky přejít.
Všimněte si, že mkdir a cd příkazy jsou v závorce. To je proto aby se 2. cd test spustilo pouze pokud tu složku vytváříme.
Command Injection
Teď tedy k samotnému útoku. Představme si aplikaci, která vypisuje obsah souboru, řekněme něco jako github. Taková aplikace může brát jako vstup jméno souboru a pro přečtení souboru může použít příkaz cat /path/to/<input> Toto bude fungovat, ale jak jsme si před chvílí řekli, do jména souboru můžeme přidat ; a nějáký příkaz a on se spustí. Řekněme že jméno souboru, které zadáváme je README.md; id, aplikace nám nyní ukáže obsah souboru README.md a na konec přidá výstup příkazu id, např. uid=0(root) gid=0(root) groups=0(root)
Shrnutí
- Shell, na kterém spoušťíme příkazy umí mnohem víc než jen spouštení jednoho příkazu
- Každý příkaz vrací tzv. exit code, který nám dává informaci, zda příkaz byl úspěšný
- V shellu můžeme definovat proměnné, které dále mohou být využity na spuštení příkazů nebo předávání hodnot jako argument příkazu
- Pomocí
;,&&a||můžeme kombinovat více příkazů do jednoho - Pokud neřešíme text, který shellu předáváme, přidáním
;můžou být spuštěné i další příkazy, což je nechtěné