0ctf Wallbreaker Easy Writeup
本文首发于先知
周末打了两天, 自闭 web 狗就做出来这一题, 另一题不知道调用啥 mbean 能拿 shell. 总之题目质量真的是非常高, 学到了很多.
描述
1Imagick is a awesome library for hackers to break `disable_functions`.
2So I installed php-imagick in the server, opened a `backdoor` for you.
3Let's try to execute `/readflag` to get the flag.
4Open basedir: /var/www/html:/tmp/949c1400c8390865cb5939a106fec0b6
5Hint: eval($_POST["backdoor"]);
提示
1WALLBREAKER EASY
2Ubuntu 18.04 / apt install php php-fpm php-imagick
第一眼看上去, 直接给了 webshell, 要求是执行根目录下的 /readflag
,
先执行一波 phpinfo()
看看信息.
可以看到是 lnp 64 位环境, disable_function 如下
1pcntl_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,system,exec,shell_exec,popen,proc_open,passthru,symlink,link,syslog,imap_open,ld,mail
Imagick 信息如下
题解
可以看到禁用了全部能直接执行程序的函数, 顺便还禁用了 mail, 不然的话可以直接用 LD_PRELOAD
来执行系统命令. 具体可以看这个项目.
接下来第一反应是通过 ghostscript 的 0day 打一波试试, 但尝试了几次全部都没有反应… 好吧没有报错太蛋疼了, 我们还是照着提示搭一波环境吧.
然后发现这里其实就真的跟提示一样, 全是最新的环境, 所以肯定是不存在已知的严重 0day 的…
同时, 可以看到在默认的配置文件中, 已经禁用了 ghostscript 的使用, 不能通过 gs 来命令执行.
1$ cat /etc/ImageMagick-6/policy.xml
2<?xml version="1.0" encoding="UTF-8"?>
3<!DOCTYPE policymap [
4<!ELEMENT policymap (policy)+>
5<!ELEMENT policy (#PCDATA)>
6<!ATTLIST policy domain (delegate|coder|filter|path|resource) #IMPLIED>
7<!ATTLIST policy name CDATA #IMPLIED>
8<!ATTLIST policy rights CDATA #IMPLIED>
9<!ATTLIST policy pattern CDATA #IMPLIED>
10<!ATTLIST policy value CDATA #IMPLIED>
11]>
12<policymap>
13 <!-- <policy domain="resource" name="temporary-path" value="/tmp"/> -->
14 <policy domain="resource" name="memory" value="256MiB"/>
15 <policy domain="resource" name="map" value="512MiB"/>
16 <policy domain="resource" name="width" value="16KP"/>
17 <policy domain="resource" name="height" value="16KP"/>
18 <policy domain="resource" name="area" value="128MB"/>
19 <policy domain="resource" name="disk" value="1GiB"/>
20 <policy domain="delegate" rights="none" pattern="URL" />
21 <policy domain="delegate" rights="none" pattern="HTTPS" />
22 <policy domain="delegate" rights="none" pattern="HTTP" />
23 <!-- in order to avoid to get image with password text -->
24 <policy domain="path" rights="none" pattern="@*"/>
25 <policy domain="cache" name="shared-secret" value="passphrase" stealth="true"/>
26 <!-- disable ghostscript format types -->
27 <policy domain="coder" rights="none" pattern="PS" />
28 <policy domain="coder" rights="none" pattern="EPI" />
29 <policy domain="coder" rights="none" pattern="PDF" />
30 <policy domain="coder" rights="none" pattern="XPS" />
31</policymap>
看起来好像一切的都没了希望, 但这时突然想起, 有没有可能通过 Imagick
来达到 mail
函数类似的效果呢? 上面的 LD_PRELOAD
其实是劫持了启动进程这一行为, 也就是说, 如果我们能让 Imagick
调用外部进程, 我们完全可以不通过 mail
来执行系统命令.
Imagick
的底层是 ImageMagick
, 这里就要说 ImageMagick
的 delegate
问题, ImageMagick
其实并没有实现所有文件格式的转换, 而是启动外部程序来进行转换, 就像上面的 ghostscript, 如果要将图片转换为 pdf, 就需要调用 ghostscript 来转换, 而这就会启动新的进程, 触发 LD_PRELAOD
.
1$ cat /etc/ImageMagick-6/delegates.xml
2<!DOCTYPE delegatemap [
3<!ELEMENT delegatemap (delegate)+>
4<!ELEMENT delegate (#PCDATA)>
5<!ATTLIST delegate decode CDATA #IMPLIED>
6<!ATTLIST delegate encode CDATA #IMPLIED>
7<!ATTLIST delegate mode CDATA #IMPLIED>
8<!ATTLIST delegate spawn CDATA #IMPLIED>
9<!ATTLIST delegate stealth CDATA #IMPLIED>
10<!ATTLIST delegate thread-support CDATA #IMPLIED>
11<!ATTLIST delegate command CDATA #REQUIRED>
12]>
13<delegatemap>
14<!-- 省略很多行 -->
15 <delegate decode="bmp" encode="wdp" command="/bin/mv "%i" "%i.bmp"; "JxrEncApp" -i "%i.bmp" -o "%o.jxr"; /bin/mv "%i.bmp" "%i"; /bin/mv "%o.jxr" "%o""/>
16 <delegate decode="ppt" command=""soffice" --convert-to pdf -outdir `dirname "%i"` "%i" 2> "%u"; /bin/mv "%i.pdf" "%o""/>
17 <delegate decode="pptx" command=""soffice" --convert-to pdf -outdir `dirname "%i"` "%i" 2> "%u"; /bin/mv "%i.pdf" "%o""/>
18 <delegate decode="ps:alpha" stealth="True" command=""gs" -sstdout=%%stderr -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=pngalpha" -dTextAlphaBits=%u -dGraphicsAlphaBits=%u "-r%s" %s "-sOutputFile=%s" "-f%s" "-f%s""/>
19 <delegate decode="ps:cmyk" stealth="True" command=""gs" -sstdout=%%stderr -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=pamcmyk32" -dTextAlphaBits=%u -dGraphicsAlphaBits=%u "-r%s" %s "-sOutputFile=%s" "-f%s" "-f%s""/>
20<!-- 省略很多行 -->
21</delegatemap>
可以看到有很多的 delegate, 在进行这些格式的编码以及解码时, ImageMagick
会调用这些外部程序. 但是这些外部程序大部分其实都不自带, 得自己安装, 不会起新的进程, 但是可以注意到这个特殊的格式,
1<delegate decode="bmp" encode="wdp" command="/bin/mv "%i" "%i.bmp"; "JxrEncApp" -i "%i.bmp" -o "%o.jxr"; /bin/mv "%i.bmp" "%i"; /bin/mv "%o.jxr" "%o""/>
其中有系统自带的 mv, 这肯定是能执行成功的, 我们只要通过转换格式就能调用这个 delegate.
通过 strace 也可以发现确实调用了 mv, 即使因为 JxrEncApp 不存在导致图片转换失败, 但只要因为 mv 调起了新进程, 我们就能执行任意命令.
这样, 就可以通过 ImageMagick
来触发新进程的产生, 并通过修改 LD_PRELOAD
的方式来执行任意系统命令.
最后 exp 如下, 写入so文件
修改 LD_PRELOAD
并转换图片格式, 最终执行系统变量 EVIL_CMDLINE
里的命令.
PS. 写入 so 文件的时候记得把 base64 里的 +
给编码, 不然会被当成空格.
还有一种思路是修改 PATH
环境变量, 修改为 /tmp/xxx/
, 然后新建一个名为 JxrEncApp
之类的的恶意文件,ImageMagick
在 delegete
的时候将会调用这个, 从而执行命令.
不得不说题目质量是真的高, 膜 rr.
总结
除了这种 LD_PRELOAD
的方式之外, 还有其他一些骚操作, 可以看 l3m0n 师傅总结的.
在遇到这种困境时, 不防想想有没有什么其他办法能 bypass 掉当前的限制, 开辟新的方法.