大二老腊肉第一次参加新生赛,虽然被hidden了,但还是玩的挺开心🙃
由于是新生赛,题目普遍难度不大,挑了几道比较有趣的题目写了WP
WP目录
- MISC-两只企鹅
- MISC-Show off
- CRYPTO-Easy RSA (非预期
MISC-两只企鹅
下载题目得到一张🐧图片,打开winhex拖到尾部发现压缩包。
用winhex搜索“PK”找到压缩包头部,正好也找到了压缩包密码。
分离压缩包并解压,得到flag.pyc,第一时间想到用uncompyle6到pyc反编译
uncompyle6 -o flag.py flag.pyc
然后运行flag.py画了另一只企鹅 (单身🐕HP-1
flag.py最后有DES加密过的flag,只有找到密钥才能解密。
密钥找了半天啥也找不到,就开了hint…说要注意冗余代码的作用,又卡了好久
直到群里师傅说到 Stegosaurus…
Stegosaurus是一种用于在Python字节码中嵌入Payload的隐写工具
具体可以看 https://www.freebuf.com/sectool/129357.html
直接用 Stegosaurus 解出pyc文件中隐藏的DES密码
运行flag.py输入密码得flag
MISC-Show off
(又是一道吃🐕粮的题
题目给了一个图片和一个加密脚本。通过阅读脚本,发现脚本把另外一张jpg的数据通过或和与非运算隐藏在了所给图片的RGB值中,其中每个色块隐藏了3位二进制值
#关键代码
if ((data[curr//8] >> (curr%8)) & 1) == 1:#隐藏位为1
pixel[k] &= ~(1 << (table.index(key[curr%KeyLen])%8) )
else:#隐藏位为0
pixel[k] |= (1 << (table.index(key[curr%KeyLen])%8) )
我们现有的是运算之后的色块RGB值和key的值。由于我太菜,不知道怎么倒回去求 发生了或运算还是与非运算,那就爆破吧!2333
def solve(c,key):#爆破
for i in range(256):
if i &~ key==c:
return '1'
return '0'
这样我们就得到了隐写进去的jpg文件的所有的01序列,也就得到了这张jpg图片
解密脚本:
#!/usr/bin/python3
from PIL import Image, ImageDraw
table = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789?!."
Key = "Wouldyouliketoseemygirlfriend?"
def solve(c,key):
for i in range(256):
if i &~ key==c:
return '1'
return '0'
class Cover:
def __init__(self,raw_path):
self.img = Image.open(raw_path)
self.img_heigh, self.img_width = self.img.size
self.draw = ImageDraw.Draw(self.img)
def extract(self,key:str):
s=self.img_heigh*(self.img_width)
KeyLen = len(key)
res=[]
temp=''
curr=0
for i in range(self.img_heigh):
for j in range(self.img_width):
pixel = list(self.img.getpixel((i,j)))
for k in range(3):
#print(pixel[k],(1 << (table.index(key[curr%KeyLen])%8)) )
temp+=solve(pixel[k],(1 << (table.index(key[curr%KeyLen])%8)))
curr+=1
if curr%100000==0:#输出解密进度
print(curr,curr/s/3)
if len(temp)==8:#每8位二进制转换为16进制
t=list(temp)
t.reverse() #这样解的二进制序列是反着的,需要倒回来
res.append(int(''.join(t),2))
temp=''
f=open('solve.jpg','wb')
f.write(bytes(res))
return bytes(res)
def show_off():
'''
with open("./test.txt", "rb") as f:
data = f.read()
'''
new_cover = Cover("merged.png")
new_cover.extract(Key)
if __name__ == "__main__":
show_off()
打开图片,啊这?!(单身🐕HP-100
右击图片查看属性,在备注栏找到flag
(🐧,yyds!
CRYPTO-Easy RSA (非预期
这题不小心用MISC的方法把⏳带佬的RSA给非预期了…
下面说一下思路:
题目给了加密后的PNG数据和加密脚本。阅读脚本,发现是用随机生成的key逐位异或PNG文件数据,最后用RSA加密了key。
由题目中key的生成看出key共有38位,key的数据 0-255
key = b''.join([urandom(1) for _ in range(38)])
为了形象地表达,我们画一个表格
我们知道PNG文件是有固定格式的(具体可以百度
①先看PNG文件头。随便找一张PNG,用winhex打开。我标蓝了文件头的前38比特,其中划红线的比特大多数的PNG都是一样的。
那么通过异或密文和明文,可以还原key的相应位。
②然后看文件尾,PNG文件尾12比特固定为 00 00 00 00 49 45 4E 44 AE 42 60 82
那么文件尾对应key中的哪几位呢?
我们用全文长度对38(key的长度)取余,发现结果是36。key又是循环使用的,说明文件尾12比特对应了key的24-35位。
③CRC32爆破PNG宽高求key中间部分
CRC32爆破PNG宽高是MISC中的常用手段,下图划红线的部分就是划蓝线部分的CRC32值
既然我们已知key的相应位,我们可以通过异或轻易求出flag.png的CRC32,通过对flag.png高宽的爆破,得到明文的16-23比特,再异或得到key的16-23比特。
下面给出一个python的爆破脚本
import zlib
import struct
crc32key = 0xCE084A0A #补上0x,winhex下copy hex value。
data = bytearray(b'\x49\x48\x44\x52\x00\x00\x05\x4A\x00\x00\x07\x02\x08\x06\x00\x00\x00') #winhex下copy grep hex。
n = 4095 #理论上0xffffffff,但考虑到屏幕实际/cpu,0x0fff就差不多了
for w in range(n):#高和宽一起爆破
width = bytearray(struct.pack('>i', w))#q为8字节,i为4字节,h为2字节
for h in range(n):
height = bytearray(struct.pack('>i', h))
for x in range(4):
data[x+4] = width[x]
data[x+8] = height[x]
crc32result = zlib.crc32(data)
if crc32result == crc32key:
print(width,height)
print(int.from_bytes(width,"big"),int.from_bytes(height,"big"))
print(hex(int.from_bytes(width,"big")),hex(int.from_bytes(height,"big")))
得到0x104,0x104,则flag.png对应位为: 00 00 01 04 00 00 01 04
④最后两比特通过爆破RSA解出
只需遍历最后两比特,用RSA加密key,与题中给出的cipher比较即可。
(遍历次数只有256*256次,完全可以爆破。)
通过以上四步我们就还原了key可以开心地解密了(因为是异或加密,解密就用加密脚本再加密一次就行了)
下面给出解密脚本
from random import *
from gmpy2 import *
from Crypto.Util.number import *
from os import urandom
import zlib
import struct
XOR = lambda s1,s2 : bytes([x1^x2 for x1,x2 in zip(s1,s2)])
def enc(plain , key):
block = len(plain) // len(key)
res = b''
if len(plain) % len(key) != 0:
block += 1
for i in range(block):
res += XOR(plain[i*len(key):(i+1) *len(key)] , key)
return res
def brute_force(key):
cipher = 6295099350956528607396037601959877791934298828699677426193295804984422774839568282303538751735922668555038227591570508075836074695625068231718282637434619892411169336112708789051866841386960010983915517645375007603334301928436122113314644281698850356618954553636354588295318626415800893401794520007438195584651069726083411367546831544328390372733644828779287264837918630675648320615405654401121853964018368418748858627359640564171296914178768702389891031507220222973953333450633882912483139393113713737597059909038607300118809911390415352026833692334281800776950518743683416169290877451319659303510788506268753501781
n = 18960722153219768424825297430288596402599615217676565923231065891419305439903969133336842165182164434305093888822528498525074593142143485234947709395152694407269932336781777523140964102701768500976985551580573991501756530871678077669095976326733950375907332862285201282966826531285878400261799511805034490220073023034504007192915282979526255340588329327377354539737224907994999568858311693959486822039283333461158422904468721851447600849924776566655800183080470425226397793377929935260296448192941725176241434514639433822949600965755910239847434831269722996200119639816772695986801602222805123304519611949635935587881
e = 7
for i in range(256):
for j in range(256):
key[36]=i
key[37]=j
k=bytes_to_long(bytes(key))
if pow(k,e,n)==cipher:
return
f=open('enc_flag.png','rb')
c=f.read()
f.close()
f=open('sample.png','rb')#sample:一张正常的PNG
s=f.read()
f.close()
s_start=s[:16]
s_end=s[-12:]
c_start=c[:16]
c_end=c[-12:]
k_start=XOR(s_start,c_start)#key 0-15
k_end=XOR(s_end,c_end) #key 24-35
#爆破出来是0x104*0x104,异或解出key 16-23
k_middle=[107, 56, 164, 91, 186, 40, 226, 217]#key 16-23
#ps 因为我懒得加 CRC32 加密脚本了,直接把爆破好的key放过来了.....
key=[]
for i in list(k_start):
key.append(i)
for i in list(k_middle):
key.append(i)
for i in list(k_end):
key.append(i)
key.append(0)
key.append(0)
brute_force(key)
#print(key)
f = open('flag.png' , 'wb')
m = enc(c , key)
f.write(m)
f.close()
解密后扫码得flag
若有错误,欢迎指出~
END~
共有条评论 网友评论