前言
在做一些CTF的审计题或者复现漏洞时,会得到 Docker 环境。需要我们在 Docker环境中进行代码调试。在 PHP 代码审计中,没有好的调试环境(如 xdebug这类调试工具),单单靠 var_dump 和 debug_print_backtrace 来手撕代码,效率十分低下。而要配好一个调试环境有时也是挺多坑的。俗话说“搭建环境两小时,漏洞复现两分钟”。本文就来简单说说如何使用 PHPSTORM 调试 Docker项目。
在开始之前,需要简单了解下 Docker。至少要会最基本的用法。不过由于主要是讲 PHPSTORM 调试的。所以 Docker介绍不会讲太多。若想了解更多的话建议看手册。
Docker基本用法
首先要知道 Docker 最基本的两样东西:image和 container
image 镜像,搭建一个 Docker 环境最基本的就是 image。可以简单理解为这就是创建虚拟机的那个镜像。
container 容器。即 依据 image,创建出来的虚拟环境。可以简单理解为就是运行着的虚拟机
Docker 的配置文件为 Dockerfile。该文件内容为构建 container 的命令。基本命令有:
FROM 设置 container 运行在哪个 image 上。必须写在 Dockerfile 的开头。可以在 Docker Hub里找适合的 image。
RUN 在 image build时执行命令。一般用于安装环境
CMD 在 container刚启动时执行命令。一般用于启动服务
COPY 将宿主机的文件拷贝到 container中
WORKDIR 设置工作目录。所有命令都会在这个目录的基础上进行工作
了解了上面的三个命令后,我们可以来简单写一个 Dockerfile了。
#基础 image 为 php:7.3-apache
FROM php:7.3-apache
#安装 xdebug 扩展 并开启
RUN pecl install xdebug && \
docker-php-ext-enable xdebug
#将 宿主机的 phpinfo.php 拷贝到 container /var/www/html/phpinfo.php 中
COPY ./phpinfo.php /var/www/html/phpinfo.php
写完后在 Dockerfile 的目录里运行
docker build -t test/testmyphp .
等命令跑完,输入以下命令即可看到创建好的 image
$ docker image ls
REPOSITORY TAG IMAGE ID ......
test/testmyphp latest 4931b92274f2 ......
要想让 container 运行起来,使用如下命令。使用-p
来指定映射端口,左边是宿舍机端口,右边是 container 端口
docker run -p 81:80 test/testmyphp
查看运行中的 container
$ docker container ls
CONTAINER ID IMAGE PORTS ......
10b8c28b2f69 test/testmyphp 0.0.0.0:81->80/tcp ......
进入 container 的 shell
$ docker exec -it CONTAINER_ID值 bash
root@10b8c28b2f69:/var/www/html#
至此,基本的 Docker 环境我们就建好了。接下来研究下如何让 PHPSTORM 调试 Docker 项目
调试方式一 – Docker挂载调试
这里做测试使用前文的 Dockerfile,需要按照实际情况进行配置添加。
配置Dockerfile
#基础 image 为 php:7.3-apache
FROM php:7.3-apache
#安装 xdebug 扩展 并开启
RUN pecl install xdebug && \
docker-php-ext-enable xdebug
# !!! 使用一个启动脚本来启动服务 !!!
COPY ./start.sh /start.sh
RUN chmod +x /start.sh
CMD ["/start.sh"]
start.sh 内容
#配置 Xdebug
echo "xdebug.client_host = host.docker.internal" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
echo "xdebug.client_port = 9003" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
echo "xdebug.mode = debug" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
echo "xdebug.max_nesting_level = 1000" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
echo "xdebug.discover_client_host = true" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
#重启 apache ssh
service apache2 restart
重建 image:
#最好先删掉之前的再重建
docker image rm IMAGE值 -f
docker build -t test/testmyphp .
重建完先不急着跑 container。先定位到我们的项目代码位置
使用 Docker 的 Bind mounts 技术。将宿主机的项目目录映射到 container 的网站目录下
docker run -p 81:80 --mount type=bind,source=/home/xp/test_docker/test_program,target=/var/www/html test/testmyphp
至此,调试环境所需要的服务就安装好了,接下来配置 PHPSTORM。
配置 PHPSTORM
直接使用Open
打开项目
配置 目录映射
进入 File -> Settings -> Languages & Frameworks -> PHP -> Servers。配置目录映射
注意一定要把 Use path mappings 的勾勾上,才能配置目录映射
Absolute path on the server 是要手动打上服务器路径的
设置Xdebug端口
进入 File -> Settings -> Languages & Frameworks -> PHP -> Debug。设置 Xdebug Debug port 为 9003。和 php 配置一致。
配置一个 Run/Debug Configuration
点击 PHPSTORM 右上角的 Add Configuration….。进入配置面,新增一个 PHP Web Page。并进行如下简单的配置即可(改名字设url 路径)
启动 PHP Debug Listening
直接点击 PHPSTROM 右上角的 小电话 ,即可开启监听
验证
在 php文件上打上断点,点击 右上角 甲壳虫样式的 Debug按钮。即可成功断点
调试方式二 – ssh 隧道
这种方式不仅仅可以用在 Docker 环境上,同样可以用在 远程服务器上。缺点就是要在 container 里头安装许多额外服务。
配置Dockerfile
-
安装ssh服务。 PHPSTORM需要 ssh 来进行目录映射,不然无法成功 Debug
-
安装 xdebug。这是调试的基础扩展组件
-
设置 ssh 允许 root 登陆。毕竟只是个 docker 调试环境,就不弄那么麻烦了。当然如果是线上业务啥的当然要做好权限分配。
-
修改 root密码。毕竟不知道密码也无法连接
-
启动 ssh 服务
-
重启 apache 服务
这里做测试使用前文的 Dockerfile,需要按照实际情况进行配置添加。
修改前文的 Dockerfile。
#基础 image 为 php:7.3-apache
FROM php:7.3-apache
ENV APACHE_DOCUMENT_ROOT /var/www/html
#安装 ssh 服务
RUN apt-get update && \
apt-get install ssh -y
#安装 xdebug 扩展 并开启
RUN pecl install xdebug && \
docker-php-ext-enable xdebug
#将宿主机的 phpinfo.php 拷贝到 container /var/www/html/phpinfo.php 中
COPY ./phpinfo.php /var/www/html/phpinfo.php
# !!! 使用一个启动脚本来完成流程 3 4 5 的工作 !!!
COPY ./start.sh /start.sh
RUN chmod +x /start.sh
CMD ["/start.sh"]
start.sh 内容
#!/bin/bash
#设置 ssh 允许 root 登录
echo 'PermitRootLogin yes' >> /etc/ssh/sshd_config
#修改root密码
echo root:123456 | chpasswd
#配置 Xdebug。Xdebug 3 的配置如下,和 Xdebug 2不太一样
echo "xdebug.client_host = host.docker.internal" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
echo "xdebug.client_port = 9003" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
echo "xdebug.mode = debug" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
echo "xdebug.max_nesting_level = 1000" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
echo "xdebug.discover_client_host = true" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
#重启 apache ssh
service apache2 restart
service ssh restart
#要加上这个,不然 container 运行完就停止了。
sleep infinity
重建 image:
#最好先删掉之前的再重建
docker image rm IMAGE值 -f
docker build -t test/testmyphp .
启动 container:
docker run -p 81:80 -p 2222:22 test/testmyphp
至此,调试环境所需要的服务就安装好了,接下来配置 PHPSTORM。
配置 PHPSTORM
打开 PHPSTORM,新建一个 Project。选择 New Project from Existing Files
选择 Web server is on remote host。
一路 Next。走到配置 Remote Server
然后又是一路 Next 即可。
配置完成后,将能看到我们的项目。
此时是不能直接进行代码调试的。我们要做以下工作
-
配置 CLI Interpreter
-
配置目录映射
-
设置Xdebug端口
-
配置一个 Run/Debug Configuration
-
启动 PHP Debug Listening
ps:由于有些步骤是一样的,就直接拉上文的截图过来了。
配置 CLI Interpreter
进入 File -> Settings -> Languages & Frameworks -> PHP。设置 CLI Interpreter
新建一个 CLI Interpreter。选择 From Docker, Vagrant, VM, WSL,Remote….
这里我们可以填 SSH,也可以直接选择 Docker。我这里用的是 SSH
设置 PHP executable 路径。不知道可以进入 container 中使用whereis php
进行搜索
配置 目录映射
进入 File -> Settings -> Languages & Frameworks -> PHP -> Servers。配置目录映射
注意一定要把 Use path mappings 的勾勾上,才能配置目录映射
Absolute path on the server 是要手动打上服务器路径的
设置Xdebug端口
进入 File -> Settings -> Languages & Frameworks -> PHP -> Debug。设置 Xdebug Debug port 为 9003。和 php 配置一致。
配置一个 Run/Debug Configuration
点击 PHPSTORM 右上角的 Add Configuration….。进入配置面,新增一个 PHP Web Page。并进行如下简单的配置即可(改名字设url 路径)
启动 PHP Debug Listening
直接点击 PHPSTROM 右上角的 小电话 ,即可开启监听
验证
在 php文件上打上断点,点击 右上角 甲壳虫样式的 Debug按钮。即可成功断点
扩展 – 远程服务器调试
这里可以扩展以一下,如果调试目标是远程服务器而不是本地 Docker,该如何配置?
其实和上面的步骤一样的,只是 Xdebug 监听的流量我们要做修改下。
简单说说 Xdebug 监听的原理:
当 php-xdebug 接收到带有 XDEBUG_SESSION_START 的请求时,将会把当前的 Debug信 息发送给 xdebug 中配置的 client_host 和 cilent_port。
在我们的 start.sh 启动文件中,设置如下:
xdebug.client_host = host.docker.internal
xdebug.client_port = 9003
host.docker.internal
值在 Xdebug 中是自动将请求端的 ip 设置为 调试端,即自动将 Debug信息 发送给任何请求IP。
而xdebug.client_port
的值是 Debug信息 被发送至的端口。
我们可以想下,在本地,xdebug端是能访问到到我们请求端的 ip 和 端口 的,因为都是同一局域网。
但若调试的是远程服务器,由于公网和内网的原因,公网服务器是无法发送 Debug信息 调试端的(除非调试端也在公网上。。)
所以我们需要将xdebug.client_host
设置为127.0.0.1
,让 xdebug 转发 Debug信息 到本地的 9003 端口中。
接着使用 ssh 隧道进行端口转发,把调试端监听的 9003 端口映射到 服务端的 9003 上。这样就能接收到 xdebug 转发的 Debug信息了。这一点使用 ssh 隧道是可以做到的。
我们来测试下,首先修改 php.ini。让xdebug.client_host
值为127.0.0.1
进行 ssh隧道端口转发
ssh -N -R 远程IP:远程端口:127.0.0.1:9003 root@远程IP
这样就能使用调试远程程序了。
Reference:
https://docs.docker.com/engine/reference/builder/
来源:freebuf.com 2021-03-17 17:46:46 by: xiaopan233
请登录后发表评论
注册