{"id":19503420,"url":"https://github.com/oops-org-php/mod_execdir","last_synced_at":"2025-04-26T00:33:05.768Z","repository":{"id":254606325,"uuid":"61401112","full_name":"OOPS-ORG-PHP/mod_execdir","owner":"OOPS-ORG-PHP","description":"mod_execdir: jailed system function. Run only the shell command in the specified directory","archived":false,"fork":false,"pushed_at":"2022-02-12T10:07:37.000Z","size":496,"stargazers_count":7,"open_issues_count":1,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-04T05:40:14.090Z","etag":null,"topics":["jail","php8","security","shell-injection"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/OOPS-ORG-PHP.png","metadata":{"files":{"readme":"README.ko.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-06-17T20:41:16.000Z","updated_at":"2022-02-04T16:28:43.000Z","dependencies_parsed_at":"2024-08-24T18:39:14.294Z","dependency_job_id":null,"html_url":"https://github.com/OOPS-ORG-PHP/mod_execdir","commit_stats":null,"previous_names":["oops-org-php/mod_execdir"],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OOPS-ORG-PHP%2Fmod_execdir","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OOPS-ORG-PHP%2Fmod_execdir/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OOPS-ORG-PHP%2Fmod_execdir/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OOPS-ORG-PHP%2Fmod_execdir/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/OOPS-ORG-PHP","download_url":"https://codeload.github.com/OOPS-ORG-PHP/mod_execdir/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250917284,"owners_count":21507561,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["jail","php8","security","shell-injection"],"created_at":"2024-11-10T22:21:19.961Z","updated_at":"2025-04-26T00:33:05.303Z","avatar_url":"https://github.com/OOPS-ORG-PHP.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"PHP execdir extension\n===\n[![PHP license](https://img.shields.io/badge/license-PHP-blue.svg)](https://raw.githubusercontent.com/php/php-src/master/LICENSE) [![GitHub issues](https://img.shields.io/github/issues/OOPS-ORG-PHP/mod_execdir.svg)](https://github.com/OOPS-ORG-PHP/mod_execdir/issues) [![GitHub forks](https://img.shields.io/github/forks/OOPS-ORG-PHP/mod_execdir.svg)](https://github.com/OOPS-ORG-PHP/mod_execdir/network) [![GitHub stars](https://img.shields.io/github/stars/OOPS-ORG-PHP/mod_execdir.svg)](https://github.com/OOPS-ORG-PHP/mod_execdir/stargazers)\n\n## 1. License\n\nCopyright 2022. JoungKyun.Kim \u0026lt;http://oops.org\u0026gt; All rights reserved.\n\nThis program is under PHP License.\n\n## 2. Description\n\n***mod_execdir*** 확장은 특정 디렉토리에 있는 명령만 실행할 수 있도록 제한을 하여, web shell이나 system shell injection 공격을 \u003cu\u003e원천적으로 방어\u003c/u\u003e할 수 있습니다. open_basedir과 같이 사용을 하면 hosting 서버에서의 각 계정간의 침해도 완벽하게 방어할 수 있습니다.\n\n이 기능은 PHP 5.4 이전의 ***safe_mode_exec_dir*** 기능을 향상 구현한 것입니다.\n\n***safe_mode_exec_dir*** 기능은 오직 ***SAFE MODE*** 에서만 사용이 가능하며, PHP 5.4 이후 부터는 ***SAFE MODE*** 가 제거 되면서 더 이상 사용을 할 수가 없습니다. 또한, ***safe_mode_exec_dir*** 의 parser는 너무나 간단하게 되어 있어 사용을 하기에 제약이 많았습니다.\n\nexecdir 기능은 이런 ***safe_mode_exec_dir*** 기능의 단점을 보완하여, ***SAFE MODE*** 가 아니고, 또한 PHP 5.4 이후 버전에서도 사용할 수 있도록 지원을 합니다.\n\n2005년 5월 PHPBB의 \u003cu\u003ehighlight syntax security hole\u003c/u\u003e 때문에 만들어 졌으며, 대형 비지니스 사이트와 안녕 리눅스 배포본에 적용이 되어 10년 이상 검증이 되었습니다.\n\n이 기능은 소스 코드에 직접 patch를 하거나, 또는 php dynamic extension으로 사용할 수 있으며, 이 기능은 다음의 PHP 함수에 영향을 미칩니다:\n\n  * exec\n  * system\n  * passthru\n  * shell_exec\n  * popen\n  * proc_open\n  * pcntl_exec\n  * shell_exec\n  * backtick operator\n\n## 3. Installation\n\n### 3.1. Requirement\n\nPHP 5 와 PHP 7, PHP 8 이상에서 사용이 가능합니다.\n\nPHP 확장 모듈의 경우, PHP 5 호환 코드로 작성 하였지만, 실제 테스트는 PHP 5.1 이후 버전에서만 테스트 되었습니다.\n\n이 기능을 사용하기 위해서는 2가지의 방법이 있습니다. 이 중에서 원하는 방법을 선택 하십시오.\n  1. PHP source에 직접 패치\n      * 코드에 직접 패치를 하기 때문에 mod_execdir 보다 성능이 좋음.\n  2. mod_execdir 확장 사용\n      * 원 함수를 hooking 및 alias를 하기 때문에 소스 패치보다는 성능이 미세하게 떨어짐.\n      * ***pcntl_exec*** call 실패 시에, pcntl_get_last_error() 함수 사용을 못함. 코드 수정이 필요 함.\n\n\n### 3.2. PHP source 에 직접 patch를 하는 경우\n\n이 기능은 확장 모듈로서 사용을 할 수도 있고, PHP 소스에 직접 패치를 할 수도 있습니다. 확장 기능으로 사용하는 것 보다 PHP에 직접 패치를 해서 사용하는 것을 선호 한다면, [Patch 파일에 대한 설명](https://github.com/OOPS-ORG-PHP/mod_execdir/blob/master/patches/README.ko.md)을 참조 하십시오.\n\n### 3.3. 동적 확장으로 사용할 경우\n\n```shell\n[root@host mod_execdir]$ phpize\n[root@host mod_execdir]$ ./configure --with-execdir=/var/lib/php/bin\n[root@host mod_execdir]$ make test PHP_EXECUTABLE=/usr/bin/php\n[root@host mod_execdir]$ make install\n```\n\n***configure*** 시에 ***--with-execdir*** 옵션을 이용하여 jail을 시킬 기본 디렉토리를 지정할 수 있습니다.\n\n## 4.Usage\n\n### 4.1. 설정\n\n#### 4.1.1 module loading\n\nphp.ini에 다음의 설정을 추가 합니다. php 동적 확장으로 빌드를 했을 경우에는 execdir.so 를 php.ini에서 로딩해 줘야 합니다.\n\n```ini\n; for php 7.1 and before\nextension = execdir.so\n\n; for php 7.2 and after\n; default extension dir\nextension = execdir\n; use absolute path\nextension = /path/execdir.so\n\n; if you use with opcache, follow option is set false\n; When used with opcache, the proc_close function does not work properly.\n; opcache.fast_shutdown = 0\n```\n\n이 모듈은 기존의 system 함수들을 바꿔치기 하는 것이므로, 가장 마지막에 로딩되도록 추가해 줍니다.\n\n#### 4.1.2 ini 설정\n\n***exec_dir*** 옵션을 이용하여, jail 시킬 디렉토리를 지정할 수 있습니다.\n\n```ini\n; only executables located in the exec_dir will be allowed to be executed\n; via the exec family of functions. This is only AnNyung LInux patch\n; see also https://github.com/OOPS-ORG-PHP/mod_execdir/\nexec_dir = /var/lib/php/bin\n```\n\n아래와 같이 ***exec_dir*** 옵션이 설정이 되어 있지 않을 경우에는, ***configure*** 시에 지정한 ***--with-execdir*** 값이 사용이 됩니다. ***configure*** 시에 ***--with-execdir*** 옵션을 주지 않았다면, 이 경우 ***exec_dir*** 의 값은 빈 값이 됩니다.\n\n```ini\n; only executables located in the exec_dir will be allowed to be executed\n; via the exec family of functions. This is only AnNyung LInux patch\n; see also https://github.com/OOPS-ORG-PHP/mod_execdir/\n;exec_dir =\n```\n\n만약, jail을 하고 싶지 않다면 다음과 같이 빈 값을 지정해 놓아야 합니다.\n\n```ini\n; only executables located in the exec_dir will be allowed to be executed\n; via the exec family of functions. This is only AnNyung LInux patch\n; see also https://github.com/OOPS-ORG-PHP/mod_execdir/\nexec_dir =\n```\n\n#### 4.1.3 Apache VirtualHost\n\n***PHP*** 를 ***apache module*** 로 사용할 경우 ***php_admin_value*** 지시자를 이용하여 가상 호스트마다 설정을 다르게 할 수 있습니다.\n```apache\n\u003cVirtualHost *:80\u003e\n    ServerName domain.com\n    DocumentRoot /var/www/domain.com\n\n    \u003cIfModule php7_module\u003e\n        php_admin_flag exec_dir /var/php/domain.com/bin\n    \u003c/IfModule\u003e\n\u003c/VirtualHost\u003e\n\n\u003cVirtualHost *:80\u003e\n    ServerName domain-other.com\n    DocumentRoot /var/www/domain-other.com\n\n    \u003cIfModule php7_module\u003e\n        php_admin_flag exec_dir /var/php/domain-other.com/bin\n    \u003c/IfModule\u003e\n\u003c/VirtualHost\u003e\n```\n\n이 설정을 응용하면 ```\u003cDirectory\u003e```, ```\u003cLocation\u003e``` 등의 블럭에서도 사용이 가능 합니다.\n\n***exec_dir*** 옵션은 ***PHP_INI_SYSTEM*** 으로 할당이 되어 있기 때문에, ***.htaccess*** 에서는 사용이 불가능 합니다.\n\n#### 4.1.4 PHP FPM pool\n\n***PHP*** 를 ***fpm*** 모드로 사용할 경우에는, FPM pool 별로 설정이 가능 합니다.\n\n```ini\n[www]\nphp_admin_flag[exec_dir] = /var/php/pool/www/bin\n\n[www1]\nphp_admin_flag[exec_dir] = /var/php/pool/www1/bin\n```\n\n### 4.2. 명령어 파서 지원 형식\n\npaser에서 지원하는 형식은 다음과 같습니다:\n\n```\ncommand\n$(command)\n`command`\ncommand; command\ncommand $(command)\ncommand $(command $(command))\ncommand $(command `command`)\ncommand `command`\ncommand | command\ncommand \u0026\u0026 command\ncommand || command\n```\n\n파서 적용 예는 다음과 같습니다:\n\n```php\nexec ('ls -al /etc/hosts', $o, $r);\nexec ('ls -al /etc/ | grep hosts', $o, $r);\nexec ('/bin/ls /etc/ | grep hosts', $o, $r);\nexec ('cat $(echo \"/etc/passwd\") | grep root; ls -al', $o, $r);\nexec ('cat `echo \"/etc/passwd\"` | grep root; ls -al', $o, $r);\nexec (\"echo '$(ls -l | grep abc)' | grep abc\");\nexec ('echo \"$(ls -l | grep abc)\" | grep abc');\n```\n\nexecdir 설정이 되어 있을 경우, 위의 코드들은 실제로는 다음과 같이 실행이 됩니다:\n\n```php\nexec ('/var/lib/php/bin/ls -al /etc/hosts', $o, $r);\nexec ('/var/lib/php/bin/ls -al /etc/ | /var/lib/php/bin/grep hosts', $o, $r);\nexec ('/var/lib/php/bin/ls -al /etc/ | /var/lib/php/bin/grep hosts', $o, $r);\nexec ('/var/lib/php/bin/cat $(/var/lib/php/bin/echo \"/etc/passwd\") | /var/lib/php/bin/grep root; /var/lib/php/bin/ls -al', $o, $r);\nexec ('/var/lib/php/bin/cat $(/var/lib/php/bin/echo \"/etc/passwd\") | /var/lib/php/bin/grep root; /var/lib/php/bin/ls -al', $o, $r);\nexec (\"/var/lib/php/bin/echo '$(ls -l | grep abc)' | /var/lib/php/bin/grep abc\");\nexec ('/var/lib/php/bin/echo \"$(/var/lib/php/bin/ls -l | /var/lib/php/bin/grep abc)\" | /var/lib/php/bin/grep abc');\n```\n\n### 4.3. APIs\n\nmod_execdir 확장 패키지로 빌드를 했을 경우에만 해당 됩니다.\n\n#### 4.3.1. Original functions\n\n기존의 함수들은 ***_orig*** 접미사를 이용하여 호출을 할 수 있습니다.\n\n```php\n\u003c?php\nexec_orig ('ls /etc/hosts', $o, $r);\nvar_dump ($o);\n?\u003e\n```\n\n원 함수 목록은 다음과 같습니다.\n\n  * exec_orig\n  * system_orig\n  * passthru_orig\n  * shell_exec_orig\n  * popen_orig\n  * proc_open_orig\n  * proc_close_orig\n  * proc_terminate_orig\n  * proc_get_status_orig\n\n이 기능은 ```1.0.2``` 부터는 ***configure*** 시에 ***--enable-execdir-addon*** 옵션을 주어야 호출할 수 있습니다.\n\n#### 4.3.2. mod_execdir APIs\n\n  * ***exec_re*** : mapping ***exec*** function\n  * ***system_re*** : mapping ***system*** function\n  * ***passthru_re*** : mapping ***passthru*** function\n  * ***shell_exec_re*** : mapping ***shell_exec*** function\n  * ***popen_re*** : mapping ***popen*** function\n  * ***proc_open_re*** : mapping ***proc_open*** function\n  * ***proc_close_re*** : mapping ***proc_close*** function\n  * ***proc_terminate_re*** :  mapping ***proc_terminate*** function\n  * ***proc_get_status_re*** : mapping ***proc_get_status*** function\n  * ***pcntl_exec_re*** : mapping ***pcntl_exec*** function  \n    ***pcntl_exec*** 함수 호출 에러시에, ***pcntl_get_last_error()*** 함수를 사용할 수 없습니다. 그러므로, 다음과 같이 약간의 소스 수정이 필요 합니다.  \n    ***이전:***  \n\n    ```php\n    \u003c?php\n    if ( ($r = @pcntl_exec ('/bin/cat', array ('/etc/hosts')) === false ) {\n        echo pcntl_strerror (pcntl_get_last_error ()) . \"\\n\"\n    }\n    ?\u003e\n    ```\n    ***이후:***  \n\n    ```php\n    \u003c?php\n    ini_set ('track_errors', true);\n    if ( ($r = @pcntl_exec ('/bin/cat', array ('/etc/hosts')) === false ) {\n        echo $php_errormsg . \"\\n\";\n    }\n    ?\u003e\n    ```\n  * ***jailed_shellcmd*** : return jailed shell command strings\n    ```\n    Prototype: (string) jailed_shellcmd (string path)\n    ```\n  \n    ```php\n    \u003c?php\n    # 다음 코드는 system(command) 과 동일하게 동작\n    $jcmd = jailed_shellcmd ('/bin/ls');\n    system_orig ($jcmd);\n    ?\u003e\n    ```\n\n\n## 5.Contributors\nJoungKyun.Kim\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foops-org-php%2Fmod_execdir","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foops-org-php%2Fmod_execdir","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foops-org-php%2Fmod_execdir/lists"}