14

CTF | 2021 CISCN初赛 Misc WriteUp

 3 years ago
source link: https://miaotony.xyz/2021/05/25/CTF_2021CISCN_preliminary/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
image-20210525205134237.png

2021 全国大学生信息安全竞赛创新实践能力赛 (CISCN)

比赛时间: 2021-05-15 09:00 ~ 2021-05-16 09:00

比赛官网: http://www.ciscn.cn/

一年一度的国赛又来了,连续打 24h 太难受啦!

今年国赛正好碰上咱 ddl,打完国赛又去赶 ddl 去了,太难顶了。

于是一直也没时间来整理 WriteUp,今天摸鱼,就来写几道 misc 题目好了。

tiny traffic

抓包文件导出 http 对象

image-20210515152049089.png

192.168.2.1 是路由器,192.168.2.193 是台 NAS,5000端口开了个 python web 服务。看上去最后的是个 rpc

flag_wrapper 导出内容,解压之后得到

image-20210515144137795.png

testsecret 用 brotli 解压

import brotli

with open('test', 'rb') as fin:
    s = fin.read()
x = brotli.decompress(s).decode()
print(x)

with open('secret', 'rb') as fin:
    s2 = fin.read()
y = brotli.decompress(s2)  
print(y)

with open('secret1', 'wb') as fout:
    fout.write(y)

发现 testProtocol Buffzers

参考 https://github.com/MonsterMeng92/protobuf/blob/master/docs/%E5%AD%A6%E4%B9%A0%E6%8C%87%E5%8D%97(proto3).md

syntax = "proto3";

message PBResponse {
  int32 code = 1;
  int64 flag_part_convert_to_hex_plz = 2;
  message data {
    string junk_data = 2;
    string flag_part = 1;
  }
  repeated data dataList = 3;
  int32 flag_part_plz_convert_to_hex = 4;
  string flag_last_part = 5;
}

message PBRequest {
  string cate_id = 1;
  int32 page = 2;
  int32 pageSize = 3;
}

里面定义了传输中的格式。

secret 是序列化后的密文。

参考 Protobuf协议逆向解析-APP爬虫

先下载 Protobuf 编译器和调用编译器的接口,这里直接用 python 了

https://github.com/protocolbuffers/protobuf/releases/

image-20210515143119110.png
1: 200
2: 15100450
3 {
  1 {
    12: 0x35343332
  }
  2: "7af2c"
}
3 {
  1: "7889b0"
  2: "82bc0"
}
4: 16453958
5: "d172a38dc"

发现并不是很清楚,先生成 python 代码

protoc.exe test.proto --python_out=.

然后写个脚本解码

import test_pb2
r = test_pb2.PBResponse()
with open('secret1', 'rb') as fin:
    s = fin.read()
r.ParseFromString(s)
print(r)
code: 200
flag_part_convert_to_hex_plz: 15100450
dataList {
  flag_part: "e2345"
  junk_data: "7af2c"
}
dataList {
  flag_part: "7889b0"
  junk_data: "82bc0"
}
flag_part_plz_convert_to_hex: 16453958
flag_last_part: "d172a38dc"

拼成 flag,其中 junk_data 是垃圾数据不要

CISCN{e66a22e23457889b0fb1146d172a38dc}

image-20210515150924012.png

running_pixel

开局一张动图

running_pixel
running_pixel

一共有 382 帧,逐帧查看,导出每一帧。

import os
from PIL import Image, ImageSequence

def parseGIF(gifname):
    # 将gif解析为图片
    # 读取GIF
    im = Image.open(gifname)
    # GIF图片流的迭代器
    iter = ImageSequence.Iterator(im)
    # 获取文件名
    file_name = gifname.split(".")[0]
    index = 1
    # 判断目录是否存在
    pic_dirct = "imgs/{0}".format(file_name)

    def mkdirlambda(x): return os.makedirs(
        x) if not os.path.exists(x) else True  # 目录是否存在,不存在则创建
    mkdirlambda(pic_dirct)
    # 遍历图片流的每一帧
    for frame in iter:
        print("image %d: mode %s, size %s" % (index, frame.mode, frame.size))
        frame.save("imgs/%s/frame%d.png" % (file_name, index))
        index += 1

if __name__ == "__main__":
    parseGIF("running_pixel.gif")

随意看前几帧,放大来看,发现有个像素点在动。

所以题目名称中的跑动的像素应该就是这个了。

image-20210525212257022.png

提取得到这个像素点颜色 RGB 为 (233, 233, 233),而背景色是 (247, 247, 247)

另外发现每隔一定帧数,这个像素点会消失,然后在另一个地方出现。

于是写个脚本跑所有的帧,把这个像素点的轨迹画出来,每消失一次保存一张图片。

"""
MiaoTony
"""
import cv2
import os
from PIL import Image, ImageOps
import numpy as np

im2 = Image.new('RGB', (400, 400))
last_cnt = 0
# list(os.walk('imgs'))[0][2]
for cnt in range(1, 383):
    img_name = f'imgs/frame{cnt}.png'
    im = Image.open(img_name)
    rgb_im = im.convert('RGB')
    # print(rgb_im.size)
    # (400, 400)
    width = rgb_im.width
    height = rgb_im.height

    for j in range(height):
        for i in range(width):
            r, g, b = rgb_im.getpixel((i, j))
            if (r, g, b) == (233, 233, 233):
                # print('cnt', cnt)
                # print(i, j)
                if cnt != last_cnt + 1:
                    print(cnt)
                    im2.save(f'cnt{cnt}.png')
                im2.putpixel((j, i), (255, 255, 255))
                last_cnt = cnt

im2.show()
im2.save('final.png')

最后的图是这样的。

final.png

手动按顺序把出来的图片各个字母提取出来。

(其实更好的思路是每次像素点消失的时候新建一张图的……看的要眼瞎了

出来是个 UUID 的格式。

12504D0F-9DE1-4B00-87A5-A5FDD0986A00

裹上 CISCN,然后发现 19:00,草,交不上去了!

心态炸了!!!

(后来看大佬 wp 说这里还要转成小写再交上去

CISCN{12504d0f-9de1-4b00-87a5-a5fdd0986a00}

题目描述:Alice 和 Bob 进行隔空传话的时候被我“偷听”到了,你能帮我分析分析他们在交流什么吗?
注意:flag形式:CISCN{XXXXX}

你们又在加密通信!!!

(这题复现的,然而过去有一段时间了,当时找的资料忘记记录了,现在又懒得再找了,就佛系写一写8

(还是去找了下资料 唉

开局给了一堆格式类似的数据。

image-20210525222938369.png

查了一下发现是 SMS 短信里用的 PDU 编码。

PDU 编码规则

还找到了 在线 PDU 格式编码/解码的网站

https://tool.letmetellyou.xyz/pdu/ 或者 http://www.sendsms.cn/pdu/

在 pypi 找到了一个 python 的 module: smspdu

手动解码前几条

image-20210525224211606.png
hello,bob!what is the flag?
the first part of the flag is the first 8 digits of your phone number
那其他部分呢
看看你能从这些数据里发现什么?w465
5b4c4ce7b6d5edd6d5cb961fca84f193ca71471db155b62c9df5ea1ebed933929de07bebcdb7853ddaf6303ac6fbaaa0fff6bb23cbfefbecd716028173e1259796fbeebf3f12f43ea54fcfeee54f11c8
f5a91d7cb54fd0b83e927bbfbe7d6a121d32649748f453ca0fbffe56162c5e5c4e3f757804e9aeb17a8b441513c78591c43c9493bb2567c6a475e69c59912c9e2f0785fe43761a523efa7c7479effdbf
...

flag 的第一部分是号码的前8位,+8615030442000,那就是 15030442

之后就一堆 hex 编码。

写个脚本提取并导出到文件。

from smspdu.codecs import GSM, UCS2
from smspdu.easy import easy_sms
from binascii import unhexlify

# x = easy_sms('04910180F6040D91685130402400F0000012405291443408A0E65A381723DFC6E21ACD4C868971B3724E76138BCDE2F28D6C0BC76431F24C66A3E56E349C99569B8DC330B3D86C2ED76C319B6C5C2BD7C6B4F2CC7CABDD70305A39172E8B63B7304E4CA3C56AB1D9F886ABE56263DA6C9CA3E56662B1AC66BB8D6D61DAAD56B6E5C6B55C2E261BE7CA3233EC86AB99CBB4D9CD160BD764B3B2397C1BDF68B75CD96C268BCD')
# print(x)

with open('data.txt', 'r', encoding='utf-8') as fin:
    s = fin.read()

l = s.strip().split('\n')
l1 = l[4:]

x = ''
for i in l1:
    tmp = easy_sms(i)['content']
    print(tmp)
    x += tmp

print(x)
# x.encode()
y = unhexlify(x)

with open('decode.dat', 'wb') as fout:
    fout.write(y)

binwalk 一下发现有张 png 图片,提取出来。

然而发现打不开……

然后比赛的时候试了用 PCRT 来修复,但没成功。网上找了个工具然后要收钱,气死喵喵了!!!

后来发现需要按照时间顺序排序。

image-20210525232953543.png
"""
MiaoTony
"""
from smspdu.codecs import GSM, UCS2
from smspdu.easy import easy_sms
from binascii import unhexlify

with open('data.txt', 'r', encoding='utf-8') as fin:
    s = fin.read()

l = s.strip().split('\n')
l1 = l[4:]

x = []
ts = []
for i in l1:
    tmp = easy_sms(i)
    content = tmp['content']
    t = tmp['date']
    x.append(content)
    ts.append(t)

l2 = sorted(zip(x, ts), key=lambda x: x[1])
l3 = list(zip(*l2))[0]
info = ''.join(l3)
# type(info)
# str
y = unhexlify(info)

with open('decode2.dat', 'wb') as fout:
    fout.write(y)

得到一张图,终于能打开了,而且整个数据就是一整张图片。然而还是没思路。

image-20210526000029763.png

看了大佬们的 wp 才发现,w465 是宽度为 465 的意思……草!

改了之后得到

00000000.png

于是 flag 就是

CISCN{15030442_b586_4c9e_b436_26def12293e4}

robot

题目描述:分析给出的机器人仿真程序和流量包,提取机器人控制程序控制机器人写出的字符串,flag为”CISCN{md5(机器人绘制的字符串)}”(md5值小写)

Robot.rspag 是 RobotStudio 文件,cap.pcapng 是网络流量抓包,Control 目录下是一个图形化的基于 C# 写的一个图形化上位机,以及对应的 dll 文件。

用 ILSPY 反汇编 exe,发现其实都是调用底层 dll 提供的 SDK 接口,并没有自己去实现网络通信相关的功能。

参考相关的资料也是如此。

https://blog.csdn.net/weixin_39090239/article/details/81275759

https://blog.csdn.net/weixin_42837024/article/details/100542204

https://zhuanlan.zhihu.com/p/62390089?ivk_sa=1024320u

https://developercenter.robotstudio.com/

之后在流量里发现有一系列设置坐标的,盲猜这个就是机器人画的东西了。

image-20210516024416682.png

于是写个脚本提取一下,画张图。

"""
MiaoTony
"""
import re
import cv2
import os
from PIL import Image
import numpy as np

im = Image.new('RGB', (400, 400))

width = im.width
height = im.height


with open('test.dat', 'r', encoding='utf-8') as fin:
    s = fin.read()

re_pos = re.compile(r'tgPos{(\d+)}\.Value\.(\[\d+,\d+,\d+\])')
l = re_pos.findall(s, re.M)

with open('data.dat', 'w', encoding='utf-8') as fout:
    fout.write(str(l))

points = [eval(x[1])[:2] for x in l]
# l = [[27, 36, 0], [28, 35, 0], [29, 35, 0], [31, 35, 0], [32, 35, 0], [33, 35, 0], [35, 35, 0],
#      [36, 35, 0], [37, 35, 0], [39, 34, 0]]

for i in points:
    im.putpixel(i, (255, 255, 255))

im.show()
im.save('info.png')
# easy_robo_xx

还原出来机器人绘制的字符串为 easy_robo_xx

info.png

md5 d4f1fb80bc11ffd722861367747c0f10

CISCN{d4f1fb80bc11ffd722861367747c0f10}

感谢 360 首次将 CTF 靶场变成了考场。

比赛环境
比赛环境
image-20210525215412840.png

初赛就这么肝也太顶了,打不动了 Orz

华东北赛区也太卷了吧,喵呜呜呜。

唉,不过咱没进复赛,喵呜呜呜呜。

害,问题不大,可能也是最后一次国赛了吧,难得大师傅们带咱玩,也非常感谢队友一起打。

之后大佬们好好玩,咱溜了溜了喵。


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK