Kyberdigi Labs
 Projekty
  Exec_dir
   Download
   Instalace
   Konfigurace
   Ostatní
   Chyby
   Historie
Počet přístupů
 
|
PHP patch exec_dir
Jazyk PHP umožňuje omezit spouštění externích příkazů z probíhajícího skriptu
pomocí konfigurační direktivy safe_mode_exec_dir.
Obsahem direktivy by mělo být celé jméno adresáře, který obsahuje ty
příkazy, které smí PHP skript volat. Jestliže se pokouší volat příkaz,
který v tomto adresáři není, příkaz se neprovede. Nicméně nutnou
podmínkou pro funkčnost této direktivy je zapnutí tzv. safe modu,
tedy trochu drsnějšího omezení uživatelů.
Jazyk PHP tedy postrádá možnost omezení volání externích příkazů bez
zapnutého safe modu, což je jistě škoda. Proto je zde tedy patch přímo
do PHP, který navíc přidává direktivu exec_dir, která funguje
naprosto totožně jako safe_mode_exec_dir, ale s tím rozdílem, že není třeba
mít zapnutý safe mode.
Tento patch omezuje volání funkcí z rodiny
exec, tedy např. exec(),
system() nebo popen().
Download
Patch si můžete stáhnout pouze pro konkrétní verzi PHP, kterou používáte:
Instalace
Protože tento patch upravuje přímo zdrojový kód jazyka PHP, je třeba si
nejprve tento kód obstarat, např. na
stránkách PHP. Po rozbalení archivu se přesuňte do vzniklého adresáře:
$ cd /cesta/do/adresare/php-x.y.z
Nyní aplikujte patch:
$ zcat /cesta/k/souboru/php-exec-dir.x.y.z.patch.gz | patch -p1
A pokud všechno proběhlo správně, program patch bude mít přibližně takovýto
nebo podobný výstup:
patching file ext/standard/exec.c
patching file ext/standard/file.c
patching file main/main.c
patching file main/php_globals.h
patching file php.ini-dist
patching file php.ini-recommended
Nyní už jen nakonfigurujte a nainstalujte PHP.
Poznámka: patch je zabalený programem gzip,
proto ze třeba jako vstup pro program patch předložit dekomprimovanou
verzi, kterou buď získáte příkazem zcat, nebo můžete předem
patch rozbalit příkazem gunzip.
Konfigurace
Celá konfigurace spočívá v nastavení konfigurační direktivy exec_dir.
Ta může být nastavena např. v souboru php.ini nebo v nastavení konfiguračních
souborů http serveru Apache.
Z bezpečnostních důvodů není možné nastavovat direktivu během běhu skriptu.
Obsah proměnné by měla být celá cesta do jednoho konkrétního (a existujícího)
adresáře, ve kterém jsou přímo soubory nebo odkazy na soubory, které lze
spustit.
Jako příklad si představme server, na kterém běží http server Apache, který
má nakonfigurované 2 virtuály: virtual1.tld a virtual2.tld,
každý virtuál spravuje jiný uživatel. Správce virtuálu virtul1.tld by chtěl
ve svých skriptech používat příkazy cp, rm a mv,
správce virtual2.tld by chtěl používat příkaz mysqldump.
Pokud nyní budeme chtít vyhovět všem přesně podle jejich požadavků,
vytvoříme pro virtual1.tld adresář např. /usr/local/php/bin/virtual1.tld
a do něj buď přímo nakopírujeme soubory cp, rm a mv nebo na ně jednoduše
uděláme symbolické odkazy. Obdobně uděláme adresář
/usr/local/php/bin/virtual2.tld a do něj nakopírujeme mysqldump. Samozřejmě
je výhodnější dělat pouze symbolické odkazy, což pak oceníme např. při
upgradu jednotlivých verzí spouštěných příkazů. Nyní ještě nastavíme apache:
<VirtualHost virtual1.tld>
php_admin_value exec_dir /usr/local/php/bin/virtual1.tld
</VirtualHost>
<VirtualHost virtual2.tld>
php_admin_value exec_dir /usr/local/php/bin/virtual2.tld
</VirtualHost>
Trochu jednodušší rešení je udělat něco jako seznam důvěryhodných příkazů
a ty potom povolit všem uživatelům, resp. jejich skriptům. V našem případě
můžeme pouze vytvořit adresář /usr/local/php a do něj nakopírovat (nebo
udělat odkazy) všechny povolené příkazy, tedy cp, rm, mv i mysqldump.
Nyní jedoduše vyeditujeme soubor php.ini, do kterého dáme takovouto
řádku:
exec_dir = /usr/local/php
Poznámka: po editaci php.ini nebo konfiguračních
souborů Apache je nutno restartovat běžící server Apache.
Ostatní
Nyní je třeba ještě popsat, jak funguje omezení volání příkazů uvnitř a jak
mají příkazy spouštět jednotlivé skripty. Jméno skriptu, který volá PHP
příkaz, se nejprve upraví tak, že se vezme jeho poslední část (tedy znaky za
posledním znakem '/'). Před tento základní název příkazu se vloží nastavení
direktivy exec_dir.
Např. voláme-li příkaz /bin/cp a direktiva exec_dir je nastavena na
/usr/local/php, upraví se příkaz /bin/cp nejprve na
cp a následně /usr/local/php/cp. Tento příkaz je nakonec
ve skutečnosti zavolán.
Pokud direktiva exec_dir není nastavena, fungují příkazy exec(),
popen() apod. normálně, tedy bez jakéhokoliv omezení.
Pokud je zapnutý safe_mode a je nastavena direktiva safe_mode_exec_dir,
nastavení direktivy exec_dir je ignorováno.
Pokud je direktiva exec_dir nastavena, volaný příkaz nesmí obsahovat
řetězce ".." a ";", obdobně jako direktiva
safe_mode_exec_dir.
Chyby
Možný problém s uvolňováním paměti objevil Manuel Mausz. Kromě objevení
problému také zaslal patch na exec_dir patch (díky!). Všechny verze exec_dir
patche nižší než 5.2.11 zřejmě obsahují tuto chybu, takže prosím upgradujte
na 5.2.11, patch pro tuto verzi by měl být v pořádku.
Objevil jsem minimalistickou chybu při vypínání funkce exec_dir. Pokud chcete
exec_dir vypnout např. v httpd.conf, přidáte následující řádku:
php_admin_value exec_dir none
I přes toto nastavení ale exec_dir konstruuje příkaz pro spuštění a jeko výsledek
je příkaz, který jako by se nacházel v kořenovém adresáři filesystému
(/ls, /df atd.). Pokud máte s takovým vypínáním potíže,
stáhněte si znovu patch pro vaši verzi PHP. Patche vyjmenované v sekci
download jsou opravené, takže porovnejte MD5 součty
vašeho patche s příslušným patchem v seznamu. Chybné byly všechny patche
pro verze 4.3.2 - 4.3.8 (včetně), 5.0.0 a 5.0.1. Tato chyba není nijak drastická
a není tedy nutné si dělat příliš velké starosti.
VeNoMouS informoval, že je možné spustit příkaz mimo zadané adresáře,
pokud se před volaný příkaz dá středník (';') nebo jiné ošklivé
znaky (např. '|' nebo &) a příkaz se volá
pomocí zpětného apostrofu. V původním safe_mode_exec_dir je volání příkazů
pomocí zpětného apostrofu vypnuto, v exec_dir je tato možnost ponechána.
Z tohoto důvodu byly všechny zde uvedené patche upraveny tak, že každé volání
příkazu pomocí zpětného apostorfu se upraví tak, že tyto nebezpečné
znaky se tzv. escapují, stejně jako je to u ostatních funkcí
(např. exec() nebo popen()).
Všichni, kdo používají tento patch,
by měli patch stáhnout znovu. Patche vyjmenované v sekci
download jsou opravené, takže porovnejte MD5 součty
vašeho patche s příslušným patchem v seznamu. Chybné byly všechny patche
od verze 4.3.2 do 4.3.7 včetně.
Zatím nejsou známé žádné další chyby. Pokud se vám i přes nastavenou direktivu
exec_dir příkaz mimo nastavený adresář, dejte vědět na
mccohy@kyberdigi.cz.
Poznámka: patch zatím nebyl testován na platformě
Windows, pokud to otestujete a bude to fungovat, dejte vědět.
Historie
Patch vznikl z potřeby omezit volání externích příkazů jednotlivých uživatelů
na vícedoménovém apache serveru, původně šlo o PHP verzi 4.2.1. Patch byl potom zaslán
vývojářům PHP, aby se direktiva exec_dir mohla stát přímo součástí PHP
(viz archiv konference php-dev),
ale nikdo z vývojářů PHP neprojevil pražádný zájem. Zájem ale projevili někteří
uživatelé PHP a proto je patch vystaven alespoň touto cestou samostatně.
|