全国大学生信息安全竞赛初赛部分Write up
纯队友做出来的就不写了,只写一下我参与解题的。(不会WEB,不会PWN,我打个锤子的ctf)
Misc
tiny traffic
流量题,直接过滤http包,在末尾发现两个GET请求,分别获取了test和secret的br包。
使用python对br包进行解压,发现test是proto3的源码,secret是一串字节型数据。
<!-- /test.protp -->
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;
}
利用/test的源码可以对数据进行序列化,因此尝试对secret反序列化。
使用protobuf编译工具将/test的源码编译成python脚本。
./protoc.exe --python_out=. test.proto
生成test_pb2.py, 然后用python编写脚本反序列化secret,得到flag的五个部分,按要求进行拼接即可。
test = b'\x1b\x68\x01\x00\x1c\x07\x8e\xdb\x90\xdb\x43\xd4\x8f\x63\xd0\x96\xdb\xbc\x24\xed\x15\x2c\xd3\x02\x5e\xb0\xfe\x58\xa3\x41\x14\xd2\xfa\xd6\x8e\x90\xe5\xad\xa2\x27\xb1\xba\xdf\xde\x66\x14\xd1\x46\xd2\x84\xa6\x91\x4c\x88\x4a\x12\xaa\x12\xe8\x36\xa1\xe3\x11\xc2\xd4\x2d\x09\x8a\xbd\x7d\xed\xef\x74\xa4\x8f\x33\x7e\xd9\xe6\x63\x26\xaf\x02\x8a\x0b\x75\x87\xfe\x8f\x4d\x07\xe1\xcb\xa1\x1a\xe0\x4d\xca\xf6\xeb\x22\xc9\x10\x8f\xea\x2b\x1e\x73\x6c\xca\x27\x2e\xc3\x17\xad\x90\xcb\x02\x99\x0a\x7a\x92\x4c\xeb\xce\xa9\x8f\x4b\x08\x1f\xcc\xd6\x66\xc8\xfa\xf8\x21\x29\xa4\xd1\x04\x0a\x49\x36\x44\x4a\x23\x04\x8b\x19\x31\x33\x24\x8f\x38\x68\x37\x83\x09\xd9\xbc\x0b\x74\xa1\x2d\x7f\xde\x3d\x4f\x8f\x32\xb6\x85\x45\xc2\xe7\xd6\xc1\xa0\x17\x12\x0d\xf1\x73\x07'
secret = b'\x0b\x1c\x80\x08\xc8\x01\x10\xa2\xd4\x99\x07\x1a\x0e\x0a\x05\x65\x32\x33\x34\x35\x12\x05\x37\x61\x66\x32\x63\x1a\x0f\x0a\x06\x37\x38\x38\x39\x62\x30\x12\x05\x38\x32\x62\x63\x30\x20\xc6\xa2\xec\x07\x2a\x09\x64\x31\x37\x32\x61\x33\x38\x64\x63\x03'
import brotli
import test_pb2
# test = brotli.decompress(test).decode('utf-8')
# print(test)
secret = brotli.decompress(secret)
target = test_pb2.PBResponse()
target.ParseFromString(secret)
print(target)
flag = hex(target.flag_part_convert_to_hex_plz)[2:] + target.dataList[0].flag_part + target.dataList[1].flag_part + hex(target.flag_part_plz_convert_to_hex)[2:] + target.flag_last_part
print('CISCN{%s}' %flag)
running_pixel
gif隐写,第一步是分离每一帧,使用kali上的convert
命令:
convert running_pixel.gif running_pixel.png
得到382帧图像,仔细查看,发现有些图像中有极小的白点。
使用画图提取小白点的位置和像素,像素值为(233,233,233)。发现临近的帧在临近的位置有相同像素的小白点。使用python脚本提取所有帧中的位置,并按照顺序重新绘图。
from PIL import Image
pix_t = []
pix_s = []
# 获取所有异常像素点
for k in range(382):
fname = './in/running_pixel-'+str(k)+'.png'
img = Image.open(fname)
img = img.convert("RGB")
for i in range(400):
for j in range(400):
tmp = img.getpixel((i,j))
if tmp == (233,233,233):
pix_t.append([i,j])
# print(pix_t)
# 将异常像素点按顺序按字符分组绘图并放大
def create_letter(pixel, path):
img = Image.new("RGB", [15,15], 'white')
pix = img.load()
l0, l1 = pix_t[start][0]-5, pix_t[start][1]-5
for each in pixel:
pix[each[1]-l1, each[0]-l0] = 1
img = img.resize((75, 75), Image.ANTIALIAS)
img.save('./out/'+str(path)+'.png')
start = 0
name = 0
for i in range(1, len(pix_t)):
if abs(pix_t[i][0]-pix_t[i-1][0])>=2 and abs(pix_t[i][1]-pix_t[i-1][1])>=2:
create_letter(pix_t[start:i], name)
name += 1
start = i
create_letter(pix_t[start:], name)
最后画出来的异常像素如下图所示:
Crypto
rsa
分析源码,三段rsa加密破解分别满足小公钥指数攻击、共模攻击和已知高位攻击。原理有一点点复杂,但是好在都给了实现的代码,改一改就能用。
对于已知高位攻击,使用sage
是最方便的,如果没有装,可以使用在线版。
from sage.all import *
import binascii
n = 113432930155033263769270712825121761080813952100666693606866355917116416984149165507231925180593860836255402950358327422447359200689537217528547623691586008952619063846801829802637448874451228957635707553980210685985215887107300416969549087293746310593988908287181025770739538992559714587375763131132963783147
p4 = 7117286695925472918001071846973900342640107770214858928188419765628151478620236042882657992902
cipher = 59213696442373765895948702611659756779813897653022080905635545636905434038306468935283962686059037461940227618715695875589055593696352594630107082714757036815875497138523738695066811985036315624927897081153190329636864005133757096991035607918106529151451834369442313673849563635248465014289409374291381429646
e = 65537
pbits = 512
kbits = pbits - p4.nbits()
p4 = p4 << kbits
PR.<x> = PolynomialRing(Zmod(n))
f = x + p4
roots = f.small_roots(X=2^kbits, beta=0.4)
if roots:
p = p4 + int(roots[0])
assert n % p == 0
q = n/int(p)
phin = (p-1)*(q-1)
d = inverse_mod(e,phin)
flag = hex(int(pow(cipher,d,n)))[2:]
print(binascii.unhexlify(flag))
# b'nd black, and pale, and hectic red,\nPestilence-stricken multitudes: O thou,\nWho chariotest to their dark wintry bed\n'
其他两部分python就可以实现
import md5
from gmpy2 import *
n1 = 123814470394550598363280518848914546938137731026777975885846733672494493975703069760053867471836249473290828799962586855892685902902050630018312939010564945676699712246249820341712155938398068732866646422826619477180434858148938235662092482058999079105450136181685141895955574548671667320167741641072330259009
e1 = 3
c1 = 19105765285510667553313898813498220212421177527647187802549913914263968945493144633390670605116251064550364704789358830072133349108808799075021540479815182657667763617178044110939458834654922540704196330451979349353031578518479199454480458137984734402248011464467312753683234543319955893
n2 = 111381961169589927896512557754289420474877632607334685306667977794938824018345795836303161492076539375959731633270626091498843936401996648820451019811592594528673182109109991384472979198906744569181673282663323892346854520052840694924830064546269187849702880332522636682366270177489467478933966884097824069977
e2 = 17
e3 = 65537
c2 = 54995751387258798791895413216172284653407054079765769704170763023830130981480272943338445245689293729308200574217959018462512790523622252479258419498858307898118907076773470253533344877959508766285730509067829684427375759345623701605997067135659404296663877453758701010726561824951602615501078818914410959610
c3 = 91290935267458356541959327381220067466104890455391103989639822855753797805354139741959957951983943146108552762756444475545250343766798220348240377590112854890482375744876016191773471853704014735936608436210153669829454288199838827646402742554134017280213707222338496271289894681312606239512924842845268366950
c3 = invert(c3, n2)
n3 = 113432930155033263769270712825121761080813952100666693606866355917116416984149165507231925180593860836255402950358327422447359200689537217528547623691586008952619063846801829802637448874451228957635707553980210685985215887107300416969549087293746310593988908287181025770739538992559714587375763131132963783147
c4 = 59213696442373765895948702611659756779813897653022080905635545636905434038306468935283962686059037461940227618715695875589055593696352594630107082714757036815875497138523738695066811985036315624927897081153190329636864005133757096991035607918106529151451834369442313673849563635248465014289409374291381429646
p4 = 7117286695925472918001071846973900342640107770214858928188419765628151478620236042882657992902
def get_m1():
inputs = range(0, 100)
for i in inputs:
a, b = iroot(c1 + i * n1, 3)
if b == 1:
return '{:x}'.format(int(a)).decode('hex')
def get_m2():
s = gcdext(e2, e3)
s1 = s[1]
s2 = -s[2]
m = (pow(c2,s1,n2) * pow(c3 , s2