Disable Functions Bypass - dl Function
Tip
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기:HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
dl() lets PHP load a shared extension at runtime. If you can make it load an attacker-controlled module, you can register a new PHP function that internally calls execve, system, or any other native primitive and therefore bypass disable_functions.
이것은 실제 프리미티브이지만, 현대 대상에서는 오래된 문서들이 암시하는 것보다 훨씬 드뭅니다.
Why this bypass is uncommon today
The main blockers are:
dl()must exist and must not be disabledenable_dlmust still allow dynamic loading- The target SAPI must support
dl() - The payload must be a valid PHP extension compiled for the same target ABI
- The extension must be reachable from the configured
extension_dir
The official PHP manual is the most important reality check here: dl() is only available for CLI and embed SAPIs, and for the CGI SAPI when run from the command line. That means the technique is usually not available in normal PHP-FPM/mod_php web requests, so check the SAPI before spending time building a payload.
Also note that enable_dl is an INI_SYSTEM setting and, as of PHP 8.3.0, PHP documents it as deprecated, so you usually cannot flip it at runtime from attacker-controlled PHP code.
If dl() is not viable, go back to the broader list of module/version dependent bypasses.
Fast triage from a foothold
Before building anything, collect the exact parameters that the module must match:
<?php
phpinfo();
echo "PHP_VERSION=" . PHP_VERSION . PHP_EOL;
echo "PHP_SAPI=" . php_sapi_name() . PHP_EOL;
echo "ZTS=" . (PHP_ZTS ? "yes" : "no") . PHP_EOL;
echo "INT_BITS=" . (PHP_INT_SIZE * 8) . PHP_EOL;
echo "enable_dl=" . ini_get("enable_dl") . PHP_EOL;
echo "extension_dir=" . ini_get("extension_dir") . PHP_EOL;
echo "disabled=" . ini_get("disable_functions") . PHP_EOL;
?>
What you care about:
PHP_SAPI: 이 값이fpm-fcgi또는apache2handler인 경우, 웹 익스플로잇에서dl()은 보통 막다른 길이다extension_dir: 페이로드는 여기에서 로드되어야 한다- PHP 버전, 아키텍처, debug/non-debug, 그리고 ZTS/non-ZTS: 모듈이 이들과 일치해야 한다
disable_functions:dl가 비활성화되어 없어졌는지, 아니면 SAPI가 이를 지원하지 않아 없는지 확인하라
Practical exploitation constraints
1. You normally need write access to extension_dir
이것이 가장 큰 병목이다.
dl()은 확장 파일명을 받아 extension_dir에서 로드한다. 실무적으로 이는 /var/www/html/uploads 같은 일반적인 임의 파일 업로드만으로는 충분하지 않음을 의미한다. PHP가 실제로 확장 모듈을 로드하는 경로에 .so/.dll을 놓을 수 있는 경로가 필요하다.
실제로 이 취약점이 이용될 수 있는 상황:
extension_dir가 쓰기 가능한 CTF 또는 고의로 취약한 실습 환경- 쓰기 가능한 extension 경로를 노출하는 공유 호스팅 또는 컨테이너 구성 실수
- 이미
extension_dir에 도달하는 별도의 임의 파일 쓰기 primitive - 이미 충분히 권한을 상승시켜 그곳에 파일을 배치할 수 있는 post-exploitation 시나리오
2. The module must match the target build
PHP_VERSION만 일치하는 것으로는 부족하다. 확장 모듈은 또한 다음과 일치해야 한다:
- OS 및 CPU 아키텍처
- libc/toolchain 요구사항
ZEND_MODULE_API_NO- debug vs non-debug 빌드
- ZTS vs NTS
이 항목들이 일치하지 않으면 dl()는 실패하거나 프로세스를 크래시시킨다.
3. open_basedir is not the main defense here
모듈을 extension_dir에 놓고 dl()를 호출할 수 있게 되면, 확장 모듈 코드는 PHP 프로세스 내부에서 실행된다. 그 시점에서 실질적인 장벽은 open_basedir가 아니라 확장 로딩 경로에 유효한 공유 객체를 배치할 수 있느냐이다.
Building the malicious extension
고전적인 방법은 여전히 유효하다:
- 가능한 한 타깃 빌드를 가깝게 재현한다
phpize,./configure, 그리고make를 사용해 shared extension을 빌드한다- 네이티브 명령 실행을 감싸는
bypass_exec($cmd)와 같은 PHP 함수를 export한다 - 컴파일된 모듈을
extension_dir에 업로드한다 dl()로 로드하고 export한 함수를 호출한다
이 공격은 오래되었지만 여전히 관련성이 있다. PHP 8.x 변경 로그에 dl() 관련 크래시 수정이 계속 포함되고 있기 때문이다. 해당 primitive는 여전히 존재한다; 어려운 부분은 접근 가능한 배포 환경과 일치하는 모듈을 배치할 수 있는 곳을 찾는 것이다.
Minimal workflow
On the attacker box
mkdir bypass && cd bypass
phpize
./configure
make
생성된 공유 객체는 일반적으로 modules/ 아래에 위치합니다.
만약 빌드하는 환경이 target과 다르다면, 생성된 파일은 ABI가 victim과 일치하는지 확인할 때까지 초안으로 취급하세요.
확장 기능 로드 및 사용
만약 target이 실제로 dl()을 지원하고 모듈이 extension_dir 안에 있다면, 런타임 측은 간단합니다:
<?php
if (!extension_loaded('bypass')) {
dl('bypass.so'); // use the correct filename for the target platform
}
echo bypass_exec($_GET['cmd']);
?>
Windows에서는 파일명이 일반적으로 .dll이고, Unix 계열 대상에서는 보통 .so입니다.
공격자 메모
- 일부 문서나 오래된 작성물에서
function_exists("dl")가 true를 반환한다고 해서 원격에서 작동한다고 가정하지 마세요; 실행 중인 SAPI를 검증하세요 - 모듈이 호환되지 않을 경우
dl()시도가 실패하면 PHP 워커가 종료될 수 있습니다 - PHP 8부터는 비활성화된 함수가 함수 테이블에서 제거되므로, 유저랜드 열거 결과가 이전 게시물들과 다를 수 있습니다
extension_dir에 쓸 수 없다면, 이 기법은 보통 FPM/FastCGI,LD_PRELOAD또는 이 섹션에서 이미 다룬 모듈별 우회 기법들보다 실용성이 낮습니다
참고자료
Tip
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기:HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.


