Contents

近期一些CTF比赛的题目(MISC+CRYPTO)

0x00 深育杯-Login

在页面下载example.zip,用winrar查看

010editor尝试修改伪加密,得到示例副本

然后使用ARCHPR进行已知明文攻击,得到压缩包的密码为qwe@123

得到password.zip,查看发现里面的三个TXT文件非常小,猜测可以用crc32爆破。

python crc32.py reverse crc32密文

组合在一起就是welc0me_sangforctf,解压得到.password.swp,kali下执行vim -r .password.swp恢复出原文件,得到:

账号:Admin
密码:5f4dcc3b5aa765d61d8327deb882cf99

登录页面,查看源代码即可获得flag。

0x01 深育杯-GeGe

from Crypto.Util.number import *
import gmpy2
from flag import flag

def encrypt(plaintext):
    p = getStrongPrime(3072) 
    m = bytes_to_long(plaintext)
    r = getRandomNBitInteger(1024)
    while True:
        f = getRandomNBitInteger(1024)
        g = getStrongPrime(768)
        h = gmpy2.invert(f, p) * g % p
        c = (r * h + m * f) % p
        return (h, p, c)

h, p, c = encrypt(flag)
with open("cipher.txt", "w") as f:
    f.write("h = " + str(h) + "\n")
    f.write("p = " + str(p) + "\n")
    f.write("c = " + str(c) + "\n")

参考https://xz.aliyun.com/t/7163https://mp.weixin.qq.com/s/1V5BEsfdZNRKwWP1mCs8wQ整理如下:

现在只要求f、g,就能解出m,看做格来求解SVP问题。

可以构造一个由下面这个矩阵M中的两个行向量(1,h), (0,p)所张成的格

https://cocalc.com上在线运行sage代码

# Construct lattice.
v1 = vector(ZZ, [1, h])
v2 = vector(ZZ, [0, p])
m = matrix([v1,v2]);

# Solve SVP.
shortest_vector = m.LLL()[0]
f, g = shortest_vector
if f < 0:
    f = -f
if g < 0:
    g = -g

# Decrypt.
a = f * c % p % g
m = a * inverse_mod(f, g) * inverse_mod(f, g) % g
print(hex(m))

解得:0x666c61677b70666132733166363561647334667765763173326433763163787861767165737d,转十六进制,得到

SangFor{pfa2s1f65ads4fwev1s2d3v1cxxavqes}

0x02 深育杯-Disk

解压文件得到文件名zse456tfdyhnjimko0-=[;.,.vera,官方的hint,文件名初级磁盘密码。

根据文件名在键盘上画出图形,得到密码。

使用VeraCrypt挂载后得到两个文件

用010editor打开good,发现文件头是7z。

解压得到附件gooood,分析发现为windows下的分区。

重命名为vhd文件,用DiskGenius打开发现存在BitLocker加密。

使用bitlocker2john -i gooood.vhd,将User Password hash的第一个值或第二个值保存成hash.txt

https://image-1303962289.cos.ap-beijing.myqcloud.com/image/20210119143922.png

1
2
3
$bitlocker$0$16$6c1fbe8314e64b4042110147cb1632d2$1048576$12$a0348897f591d70103000000$60$fb026c1039aec7a85c77964d9cf2b63f6261579f431dfdb675322ab91e44acab870c75a64b5722be3500b35bcee969dc59e31ffdf88c1cb3a07776fa

$bitlocker$1$16$6c1fbe8314e64b4042110147cb1632d2$1048576$12$a0348897f591d70103000000$60$fb026c1039aec7a85c77964d9cf2b63f6261579f431dfdb675322ab91e44acab870c75a64b5722be3500b35bcee969dc59e31ffdf88c1cb3a07776fa

使用hashcat -m 22100 hash.txt rockyou.txt --show,指定哈希类型后爆破。

得到密码是abcd1234,解锁打开回收站,发现hint和一个7z文件。

rdp协议默认开启位图缓存功能,会产生bmc文件,使用bmc-tool或者BMC Viewer能够恢复出缓存的图像。

7c解压后用BMC Viewer查看,得到cmRwY2FjaGUtYm1j,解密base64得到flag

或者使用bmc-tools.py -s bcache24 -d 1

找到 flag 缩略图

0x03 深育杯-Brige

用Stegsolve发现存在LSB隐写,导出PNG文件

010editor删除文件头多余的部分后得到图片

分析其像素

from PIL import Image

img = Image.open('1.png')
height = img.size[0]
width = img.size[1]
pixeltxt = open('pixel.txt','a')
for x in range(height):
    for y in range(width):
        pixel = img.getpixel((x,y))
        pixeltxt.write(str(pixel) + '\n')

发现像素的第三部分存在问题,。

将前四个数据,处理后得到zip文件的文件头

提取生成数据,用010editor生成压缩包文件

from PIL import Image

img = Image.open('1.png')
height = img.size[0]
width = img.size[1]
pixeltxt = open('pixel.txt','a')
zipstrings = ''
for x in range(height):
    for y in range(width):
        pixel = img.getpixel((x,y))[2]
        hexnum = hex(pixel)
        zipstrings +=str(hexnum)[2:].zfill(2)
zip = open('flag.txt','a')
zip.write(zipstrings)

分析brige.png发现存在异常的chunk,结合pngcheck发现IDAT数据块存在问题

010editor中看到最后一个IDAT数据块长度异常,将IDAT标识后面的87 9C两个字节,恢复成zlib数据头标识78 9C,导出这段zlib数据。

导出zlib数据为flag文件,用python脚本解出

import zlib

file = open('flag','rb').read()
data = zlib.decompress(file)
rar = open('1.rar','wb')
rar.write(data)

使用exiftool分析原图,发现异常数据。

转16进制得到dynamical-geometry,解压之前获得的压缩包,看到stl文件,打开获得一半flag

把flag2同样修改成stl文件预览,得到整个flag。

0x04 湖湘杯-signin

from Crypto.Util.number import *
from secret import flag
import random

m1 = bytes_to_long(flag[:len(flag) // 2])
m2 = bytes_to_long(flag[len(flag) // 2:])

def gen(pbits, qbits):
    p1, q1 = getPrime(pbits), getPrime(qbits)
    n1 = p1**4*q1
    q2 = getPrime(qbits)
    bound = p1 // (8*q1*q2) + 1
    p2 = random.randrange(p1, p1 + bound)
    while not isPrime(p2):
        p2 = random.randrange(p1, p1 + bound)
    n2 = p2**4*q2
    return (n1, n2), (p1, q1), (p2, q2)

e = 0x10001
pbits = int(360)
qbits = int(128)
pk, sk1, sk2 = gen(pbits, qbits)
c1 = pow(m1, e, pk[0])
c2 = pow(m2, e, pk[1])
print(f'pk = {pk}')
print(f'c1, c2 = {c1, c2}')

给出了n1、n2、c1、c2、e,和[羊城杯 2020]RRRRRRRSA类似,用维纳攻击解,先得出

from Crypto.Util.number import *
import gmpy2

def continuedFra(x, y): #不断生成连分数的项
    cF = []
    while y:
        cF += [x // y]
        x, y = y, x % y
    return cF
    
def Simplify(ctnf): #化简
    numerator = 0
    denominator = 1
    for x in ctnf[::-1]: #注意这里是倒叙遍历
        numerator, denominator = denominator, x * denominator + numerator
    return (numerator, denominator) #把连分数分成分子和算出来的分母
    
def getit(c):
    cf=[]
    for i in range(1,len(c)):
        cf.append(Simplify(c[:i])) #各个阶段的连分数的分子和分母
    return cf #得到一串连分数

def wienerAttack(e, n):
    cf=continuedFra(e,n)
    for (Q2,Q1) in getit(cf):#遍历得到的连分数,令分子分母分别是Q2,Q1
        if Q1 == 0:
            continue
        if N1%Q1==0 and Q1!=1:#满足这个条件就找到了
            return Q1,Q2
    print('not find!')

Q1,Q2 = wienerAttack(N1,N2)
P1 = gmpy2.iroot(N1//Q1,4)[0]
P2 = gmpy2.iroot(N2//Q2,4)[0]
phi1 = P1 * P1 * P1 * (P1-1) * (Q1-1)
phi2 = P2 * P2 * P2 * (P2-1) * (Q2-1)
d1 = gmpy2.invert(e,phi1)
d2 = gmpy2.invert(e,phi2)
m1 = long_to_bytes(gmpy2.powmod(c1,d1,N1))
m2 = long_to_bytes(gmpy2.powmod(c2,d2,N2))
print((m1 + m2))

0x05 西湖论剑-YUSA的小秘密

stegsolver发现red plane 0和green plane 0都有数据

from cv2 import cv2 as cv
img = cv.imread('yusa.png')
src = cv.cvtColor(img, cv.COLOR_BGR2YCrCb)
Y, Cr, Cb = cv.split(src)
cv.imwrite('Y.png', (Y % 2) * 255)
cv.imwrite('Cr.png', (Cr % 2) * 255)
cv.imwrite('Cb.png', (Cb % 2) * 255)

0x06 西湖论剑-Yusa的秘密

volatility -f Yusa-PC.raw --profile=Win7SP1x64 hashdump,发现yusa用户,使用PTF爆破密码YusaYusa520,打开压缩包Who_am_I

题目中提到Sakura组织,这里对文件进行搜索

分别导出文件 Sakura-didi导出后是一个加密的压缩包 公告内容是全体成员注意,我们将在11月20号,对地球发起总攻,请做好准备。 备忘录的内容是2021.11.15:请组织内的人务必删除所有不必要的联系方式,防止我们的计划出现问题。 根据备忘录获取的信息,找一下联系方式有关的文件

导出Mystery Man.contact,发现一串可疑的字符串

1
LF2XGYPPXSGOPO4E465YPZMITLSYRGXGWS7OJOEL42O2LZFYQDSLRKXEXO56LCVB566IZ2FPW7S37K7HQK46LLUM42EJB354RTSL3IHFR6VONHEJ4S4ITZNEVHTJPNXJS62OHAECGZGCWWRVOBUXMNKMGJTTKTDZME2TKU3PGVMWS5ZVGVYUKYJSKY2TON3ZJU2VSK3WGVGHK3BVGVJW6NLBGZCDK33NKQ2WE6KBGU3XKRJVG52UQNJXOVNDKTBSM42TK4KFGVRGK3BVLFLTGNBUINBTKYTFNQ2VSVZTGVNEOOJVLJBU4NKMGZSDKNCXNY2UY4KHGVGHSZZVG52WMNSLMVCTKWLJLI2DIQ2DMEZFMNJXG54WCT2EJF3VSV2NGVGW2SJVLJVFKNCNKRIXSWLNJJUVS6SJGNMTERLZJ5KFM3KNK5HG2TSEM46Q====

解Base32得到

再解Base64得到一个key值820ac92b9f58142bbbc27ca295f1cf48

解密压缩包得到key.bmp

在Yusa.contact中发现hint

使用pstree查找下便笺相关的进程

volatility -f Yusa-PC.raw --profile=Win7SP1x64 memdump -p 2228 -D ./导出进程,再使用foremost -T 2228.dmp进行分离 得到带密码的压缩包

在00003824.ole发现rtf文件

删除掉多余的字符,构造rtf文件

1
{\rtf1\ansi\ansicpg936\deff0\deflang1033\deflangfe2052{\fonttbl{0\f0\fnil\fcharset134 \'ce\'a2\'c8\'ed\'d1\'c5\'ba\'da;}}{\*\generator Msftedit 5.41.21.2510;}\viewkind4\uc1\pard\tx336\tx672\tx1008\tx1344\tx1680\tx2016\tx2352\tx2688\tx3024\tx3360\tx3696\tx4032\tx4368\tx4704\tx5040\tx5376\tx5712\tx6048\tx6384\tx6720\tx7056\tx7392\tx7728\tx8064\tx8400\tx8736\tx9072\tx9408\tx9744\tx10080\tx10416\tx10752\highlight0\lang2052\f0\fs22\'d6\'d5\'d3\'da\'c4\'c3\'b5\'bd\'c1\'cb\'d7\'e9\'d6\'af\'b5\'c4\'ba\'cb\'d0\'c4\'c3\'dc\'c2\'eb\'a3\'ac\'ce\'d2\'b2\'bb\'cf\'eb\'d4\'d9\'b5\'b1\'ce\'d4\'b5\'d7\'c1\'cb\'a3\'ac\'ce\'d2\'cf\'eb\'b8\'cf\'bd\'f4\'c0\'eb\'bf\'aa\'d5\'e2\'b8\'f6\'b9\'ed\'b5\'d8\'b7\'bd\'a1\'a3\'ba\'cb\'d0\'c4\'c3\'dc\'c2\'eb\'ca\'c7\'a3\'ba\'ca\'c0\'bd\'e7\'c3\'bb\'c1\'cb\'d0\'c4\'cc\'f8\'a1\'a3\par }

打开得到世界没了心跳

解压压缩包,得到exp,内容如下:

from PIL import Image
import struct
pic = Image.open('key.bmp')
fp = open('flag', 'rb')
fs = open('Who_am_I', 'wb')

a, b = pic.size
list1 = []
for y in range(b):
    for x in range(a):
        pixel = pic.getpixel((x, y))
        list1.extend([pixel[1], pixel[0], pixel[2], pixel[2], pixel[1], pixel[0]])

data = fp.read()
for i in range(0, len(data)):
    fs.write(struct.pack('B', data[i] ^ list1[i % a*b*6]))
fp.close()
fs.close()

这是加密的过程,解密脚本如下:

from PIL import Image
import struct
pic = Image.open('key.bmp')
fp = open('flag', 'wb')
fs = open('Who_am_I', 'rb')

a, b = pic.size
list1 = []
for y in range(b):
    for x in range(a):
        pixel = pic.getpixel((x, y))
        list1.extend([pixel[1], pixel[0], pixel[2], pixel[2], pixel[1], pixel[0]])

data = fs.read()
for i in range(0, len(data)):
    fp.write(struct.pack('B', data[i] ^ list1[i % a*b*6]))
fp.close()
fs.close()

得到flag,经过判断为gif文件

我们用010editor打开,发现高度不对,6、7字节为宽, 8、9字节为高,且为小端序储存方式 ,修改为8、9字节为1D 10

打开可以看到flag

0x07 西湖论剑-hardrsa

[羊城杯 2020]Power魔改

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
from Crypto.Util.number import *
import sympy
e = 0x10001
dp = 379476973158146550831004952747643994439940435656483772269013081580532539640189020020958796514224150837680366977747272291881285391919167077726836326564473
c = 57248258945927387673579467348106118747034381190703777861409527336272914559699490353325906672956273559867941402281438670652710909532261303394045079629146156340801932254839021574139943933451924062888426726353230757284582863993227592703323133265180414382062132580526658205716218046366247653881764658891315592607194355733209493239611216193118424602510964102026998674323685134796018596817393268106583737153516632969041693280725297929277751136040546830230533898514659714717213371619853137272515967067008805521051613107141555788516894223654851277785393355178114230929014037436770678131148140398384394716456450269539065009396311996040422853740049508500540281488171285233445744799680022307180452210793913614131646875949698079917313572873073033804639877699884489290120302696697425
c1 = 78100131461872285613426244322737502147219485108799130975202429638042859488136933783498210914335741940761656137516033926418975363734194661031678516857040723532055448695928820624094400481464950181126638456234669814982411270985650209245687765595483738876975572521276963149542659187680075917322308512163904423297381635532771690434016589132876171283596320435623376283425228536157726781524870348614983116408815088257609788517986810622505961538812889953185684256469540369809863103948326444090715161351198229163190130903661874631020304481842715086104243998808382859633753938512915886223513449238733721777977175430329717970940440862059204518224126792822912141479260791232312544748301412636222498841676742208390622353022668320809201312724936862167350709823581870722831329406359010293121019764160016316259432749291142448874259446854582307626758650151607770478334719317941727680935243820313144829826081955539778570565232935463201135110049861204432285060029237229518297291679114165265808862862827211193711159152992427133176177796045981572758903474465179346029811563765283254777813433339892058322013228964103304946743888213068397672540863260883314665492088793554775674610994639537263588276076992907735153702002001005383321442974097626786699895993544581572457476437853778794888945238622869401634353220344790419326516836146140706852577748364903349138246106379954647002557091131475669295997196484548199507335421499556985949139162639560622973283109342746186994609598854386966520638338999059


g = 2
y = 449703347709287328982446812318870158230369688625894307953604074502413258045265502496365998383562119915565080518077360839705004058211784369656486678307007348691991136610142919372779782779111507129101110674559235388392082113417306002050124215904803026894400155194275424834577942500150410440057660679460918645357376095613079720172148302097893734034788458122333816759162605888879531594217661921547293164281934920669935417080156833072528358511807757748554348615957977663784762124746554638152693469580761002437793837094101338408017407251986116589240523625340964025531357446706263871843489143068620501020284421781243879675292060268876353250854369189182926055204229002568224846436918153245720514450234433170717311083868591477186061896282790880850797471658321324127334704438430354844770131980049668516350774939625369909869906362174015628078258039638111064842324979997867746404806457329528690722757322373158670827203350590809390932986616805533168714686834174965211242863201076482127152571774960580915318022303418111346406295217571564155573765371519749325922145875128395909112254242027512400564855444101325427710643212690768272048881411988830011985059218048684311349415764441760364762942692722834850287985399559042457470942580456516395188637916303814055777357738894264037988945951468416861647204658893837753361851667573185920779272635885127149348845064478121843462789367112698673780005436144393573832498203659056909233757206537514290993810628872250841862059672570704733990716282248839

x=sympy.discrete_log(y,c1,g)
print(x)

a = sympy.Symbol('a')
p = sympy.solve(2019*a**2+2020*a**3+2021*a**4-x,a)[0]
print(p)
print(long_to_bytes(pow(c,dp,int(p))))

0x08 西湖论剑-密码人集合

nc连接访问

------------------------------
论 *  *  | *  *  *  | *  *  一
*  *  *  | 要 *  一 | *  *  * 
*  一 西 | *  论 第 | *  我 * 
------------------------------
*  要 *  | *  一 *  | *  *  剑
*  *  *  | *  *  湖 | *  *  * 
*  *  *  | *  *  *  | *  湖 * 
------------------------------
*  *  一 | *  第 *  | *  *  * 
剑 *  *  | *  *  *  | *  *  * 
西 *  *  | 一 湖 *  | *  第 * 
------------------------------

可以发现是西湖论剑我要拿第一中的几个字构成的数独,用数字替换,得到

------------------------------
6 *  *  | *  *  *  | *  *  9
*  *  *  | 2 *  9 | *  *  * 
*  9 4 | *  6 8 | *  1 * 
------------------------------
*  2 *  | *  9 *  | *  *  7
*  *  *  | *  *  5 | *  *  * 
*  *  *  | *  *  *  | *  5 * 
------------------------------
*  *  9 | *  8 *  | *  *  * 
7 *  *  | *  *  *  | *  *  * 
4 *  *  | 9 5 *  | *  8 * 
----------------------------

在线求解,去掉换行得到612534879378219465594768213125893647836475921947126358259681734781342596463957182,替换得到,论我要湖拿西第剑一拿剑第要我一西论湖湖一西剑论第要我拿我要湖第一拿论西剑第拿论西剑湖一要我一西剑我要论拿湖第要湖一论第我剑拿西剑第我拿西要湖一论西论拿一湖剑我第要