利用LD_PRELOAD bypass disable_function

上一篇翻译中讲述了用LD_PRELOAD劫持系统的rand()函数,使rand()函数永远return 42,算是简单介绍了原理。

在这一篇中,我们把这个思想再深入一点,讲讲CTF中常见的利用LD_PRELOAD来bypass disable_function。

disable_function 是什么?

我们来看一看官方说明:

https://www.php.net/manual/zh/ini.core.php#ini.disable-functions

本指令可用于禁止某些函数。接受逗号分隔的函数名列表作为参数。
此指令仅能禁用 内置函数。 不能影响用户自定义函数。
本指令只能设置在 php.ini 中。例如,无法在 httpd.conf 中设置。

最基本的

index.php:

1
2
<?php
@eval($_REQUEST['c']);

Dockerfile:

1
2
3
4
5
FROM nimmis/apache-php7
COPY index.php /var/www/html/index.php
RUN rm -rf /var/www/html/index.html && \
sed -i 's~;open_basedir =~open_basedir=/tmp/:/var/www/html/~' /etc/php/7.0/apache2/php.ini && \
sed -i 's/disable_functions = pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,/disable_functions = passthru,exec,system,putenv,chroot,chgrp,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv,pcntl_signal_get_handler,pcntl_async_signals,/' /etc/php/7.0/apache2/php.ini
1
2
docker build -t ld_preload_test .
docker run -di -p 8081:80 --name test ld_preload_test

然后访问 http://localhost:8081/,传入参数c=phpinfo();,能够看到phpinfo说明你的环境正确:

窝很可爱,请给窝钱