Kyberdigi Labs

PHP patch exec_dir

C. McCohy <mccohy@kyberdigi.cz>
Aktuální verze: 5.2.13
Omezení spouštění externích příkazů z jazyka PHP cz en
Kyberdigi Labs
Projekty
Exec_dir
Download
Instalace
Konfigurace
Ostatní
Chyby
Historie

Počet přístupů
Counter

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:

Verze PHP Patch exec_dir Velikost MD5
5.2.13 php-exec-dir.5.2.13.patch.gz 1646 B 67a2b388f40a7448e63ccab157040f9c
5.2.12 php-exec-dir.5.2.12.patch.gz 1662 B 5aaff8163b1d6a2bc3ca729b31cf840d
5.2.11 php-exec-dir.5.2.11.patch.gz 1679 B f3baff3c6c0c6b9f3f97c1fc975120de
5.2.10 php-exec-dir.5.2.10.patch.gz 1631 B ef906a1781ba401225767291767774c6
5.2.9 php-exec-dir.5.2.9.patch.gz 1610 B f6c10955043df74519420dd7a7921785
5.2.8 php-exec-dir.5.2.8.patch.gz 1644 B 06d0c00224958c9a3ca4a827fa054f93
5.2.7 php-exec-dir.5.2.7.patch.gz 1675 B fa349a9c3c005a6b9cec9149ffe26ef1
5.2.6 php-exec-dir.5.2.6.patch.gz 1655 B fdf7b9089317b768899edaed47edb4a6
5.2.5 php-exec-dir.5.2.5.patch.gz 1655 B bb9860a6b6abea4df5ecfba0770571dc
5.2.4 php-exec-dir.5.2.4.patch.gz 1642 B e97f87622c5056b880f096547c1521d2
5.2.3 php-exec-dir.5.2.3.patch.gz 1645 B 83a12c2a380d1597cdd017da4b9f2ac4
5.2.2 php-exec-dir.5.2.2.patch.gz 1647 B d5565bb4af91afc41bcd961d254207da
5.2.1 php-exec-dir.5.2.1.patch.gz 1644 B 3a311800ee45b3ed8e28c94c148190bf
5.2.0 php-exec-dir.5.2.0.patch.gz 1596 B 0edc3f5607a9211d4e1d5987b41c1cff
5.1.6 php-exec-dir.5.1.6.patch.gz 1643 B 38cf24d5675e9a2489c48ad4db1669da
5.1.5 php-exec-dir.5.1.5.patch.gz 1643 B 4a8cb3f2f84b03fa86193ab0f845fbe0a
5.1.4 php-exec-dir.5.1.4.patch.gz 1588 B b3e7bb57b806db4c70f45b1fda263c8d
5.1.3 php-exec-dir.5.1.3.patch.gz 1611 B 509acfd8fb4b060731f917b855ea7a0d
5.1.2 php-exec-dir.5.1.2.patch.gz 1585 B b42dcbde9d6ad540fafad795038721f6
5.1.1 php-exec-dir.5.1.1.patch.gz 1637 B 2590c0def73955c0f534b815fc3dbfe3
5.1.0 php-exec-dir.5.1.0.patch.gz 1665 B 91c628fcf29d2908ae7dae3a60120254
5.0.5 php-exec-dir.5.0.5.patch.gz 1673 B 5c2193621313c88ff8267b352b71302e
5.0.4 php-exec-dir.5.0.4.patch.gz 1654 B 29bb4bb4a9de2600839c673978e0b7d6
5.0.3 php-exec-dir.5.0.3.patch.gz 1686 B e4deac1a1675459441b01af6695c74fe
5.0.2 php-exec-dir.5.0.2.patch.gz 1628 B 795c4d02244cd54900ba5b33cb7b7633
5.0.1 php-exec-dir.5.0.1.patch.gz 1679 B b553a4d66f305b709a9639ed6e42e61a
5.0.0 php-exec-dir.5.0.0.patch.gz 1675 B 244b20e45aab59d858eaf470286cddd8
4.4.9 php-exec-dir.4.4.9.patch.gz 1898 B 3b0d5b757f9ecf921c92ce79f6141d18
4.4.8 php-exec-dir.4.4.8.patch.gz 1924 B 117bc6e13139f8b8543f5a7cd6a0abc6
4.4.7 php-exec-dir.4.4.7.patch.gz 1904 B b8a95e2f2c2793b2acb5dfd44cfc7514
4.4.6 php-exec-dir.4.4.6.patch.gz 1900 B eb38ff40ec2d31d19c89102589136a71
4.4.5 php-exec-dir.4.4.5.patch.gz 1898 B fd3c4213fd1195bcd5a4c1ab0ead610f
4.4.4 php-exec-dir.4.4.4.patch.gz 1931 B 386e78c0f7d6b6f85559d18c94def4f2
4.4.3 php-exec-dir.4.4.3.patch.gz 1932 B aff9215b65245df2d89860e991a59a38
4.4.2 php-exec-dir.4.4.2.patch.gz 1872 B c16133f2a3ef55b5918495a48bc59d69
4.4.1 php-exec-dir.4.4.1.patch.gz 1963 B 5972e35781848cd40d448829c55670c2
4.4.0 php-exec-dir.4.4.0.patch.gz 1974 B 1c207f9733ecbb2f65a40adf723e5bba
4.3.11 php-exec-dir.4.3.11.patch.gz 2013 B 288cf48d25631021ef4875b5454b204b
4.3.10 php-exec-dir.4.3.10.patch.gz 2066 B 7a127d0038a20ba036fdec4807b01b76
4.3.9 php-exec-dir.4.3.9.patch.gz 2002 B f2cc540a01548ddef3f3a28482171fe6
4.3.8 php-exec-dir.4.3.8.patch.gz 1992 B 6130360a0f05a4f93278377dac864819
4.3.7 php-exec-dir.4.3.7.patch.gz 1897 B fe7f67e15fb5cc35b7bb284afed265df
4.3.6 php-exec-dir.4.3.6.patch.gz 1918 B f5b0b55383a0ba617eeb142a854c64e9
4.3.5 php-exec-dir.4.3.5.patch.gz 1928 B 8ee3d449efafc24f9a733fec0a2ae679
4.3.4 php-exec-dir.4.3.4.patch.gz 1969 B 1518afb2f6ba3e9b86638caee6b2cb32
4.3.3 php-exec-dir.4.3.3.patch.gz 1996 B a00fcbc5e281b7f1423034717247df0c
4.3.2 php-exec-dir.4.3.2.patch.gz 1930 B c11d5e3e97d5e0a87b878bcc9ddb3995


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ě.

Valid HTML 4.01 Kyberdigi Labs