2023年“羊城杯”网络安全大赛 MISC WriteUp

admin 2024年8月6日15:22:11评论95 views字数 8027阅读26分45秒阅读模式

--Misc
---ai和nia的交响曲
---EZ_misc
---Matryoshka
---程序猿Quby的附件
---GIFuck
---Easy_VMDK
---两只老虎

Misc

ai和nia的交响曲

打开直接导出http流

2023年“羊城杯”网络安全大赛 MISC WriteUp

145kb的upload.php查看一下是一个hex,cyberchef转一下得到一张图片

2023年“羊城杯”网络安全大赛 MISC WriteUp

发现每条黑线中间一共7个黑or白像素,猜测7bit,把黑色当0那么就是正常的8bit

用QQ的截图看了一下中间的黑线也不是(0,0,0),因此这里使用一个范围代表黑色和白色,我这里把小于30的当成黑色

from PIL import Image
img = Image.open("flag1.png")
w,h = img.size
flag = ''
for i in range(w):
    for j in range(h):
        pixel = img.getpixel((i,j))[0]
        if(pixel < 30):
            flag += '0'
        else:
            flag += '1'
f = open('outs.txt','w').write(flag)

cyberchef转一下,在结果的尾部得到hint和part1

2023年“羊城杯”网络安全大赛 MISC WriteUp

http导出的flag2是伪加密,把09改00

2023年“羊城杯”网络安全大赛 MISC WriteUp

结合hint是b站视频,每一行看成该视频的时间

但是不得不说,00:03是C我不是很理解(在晚上的时候上了hint说要加一秒嘻嘻),最后测试下来是CAOCAOGAIFAN

最后得到flag

@i_n1a_l0v3S_CAOCAOGAIFAN

EZ_misc

发现有两个IEND,并且中途就提前IEND掉了,但是查看发现只有一个PNG

联想到之前*CTF做到的snipping的CVE

但是使用之前github上的Acropalypsa Multi Tool没有成功,看了一下powershell发现是图片高度错了导致无法加载。

通过CRC计算得到实际高度是138,再放进工具即可

2023年“羊城杯”网络安全大赛 MISC WriteUp

2023年“羊城杯”网络安全大赛 MISC WriteUp

Matryoshka

解压出来一个flag.img,使用winhex打开查看,能拿到三个文件。

normal_rar.rar not_real_cat.jpg encrypt

其中发现normal_rar尾部有个jpg,分离后发现与not_real_cat是一个图片,猜测双图隐写,直接xor发现有蓝色的线条,直接锁定盲水印,使用bwmforpy3的版本

python3 .bwmforpy3.py decode .not_real_cat.jpg .normal_rar.jpg out.png --oldseed --alpha 10

2023年“羊城杯”网络安全大赛 MISC WriteUp

得到密码(注意第一个w小写)watermark_is_fun

查看encrypt文件,发现都是混乱字节且正好大小是整数20mb,直接根据该信息锁定是veracrypt(或truecrypt),使用veracrypt挂载即可得到flag.txt

flag.txt发现长度只有70多但是却占了100多字节,猜测存在0宽。

解base32后发现不是直接DASCTF,猜测需要维吉尼亚,最后得到flag

2023年“羊城杯”网络安全大赛 MISC WriteUp

2023年“羊城杯”网络安全大赛 MISC WriteUp

DASCTF{congratulati0n_you_f1nd_th3_f14g!!!}

程序猿Quby的附件

解压发现图片后面有个rar文件,分离出来发现该rar文件需要密码

图片查看最低位发现有LSB,直接查RGB0没有信息,说明是有密码,猜测cloacked-pixel

图片本身是夏多密码,根据规则转换得到HAVEANICEDAY

cloacked-pixel> python '.lsb.py' extract .QUBY.png xixixi.txt HAVEANICEDAY

得到rar密码we1c0met0ycbCTF!!!

然后随便查看一个excel,能够发现中间(50多~1000多行)的部分被收起来了,展开再改颜色能看到两种不同的数字

2023年“羊城杯”网络安全大赛 MISC WriteUp

另一个文件是3.33和6.66就不截图了

猜测画图,丢给GPT4(这是3.33和6.66的图)

2023年“羊城杯”网络安全大赛 MISC WriteUp

将两张图拼起来的结果如下:

2023年“羊城杯”网络安全大赛 MISC WriteUp

 

密码w0wyoudo4goodj0b

既然有密码,猜测wav隐写,发现deepsound有密码

2023年“羊城杯”网络安全大赛 MISC WriteUp

extract出来,解压,得到两个txt文件

:JOJ[=%tJD9gr2Q79*;T:-qZD=]S0c:0'nT7orYd9L_TD=Ys#Z9iY:q;-$Xo:dQs>9ia&M9i3]K5r2G>8Oc'9=%u:f8QIW;;bp(8Ms%=10QJ$:KBnd<AmK;7p.T97oN8J其中这个丢cyberchef直接base85再32能够得到一串base64

2023年“羊城杯”网络安全大赛 MISC WriteUp

另一个文件也是base64,猜测为换表base

2023年“羊城杯”网络安全大赛 MISC WriteUp

DASCTF{Qu6y_d0_not_lik3_w0rking_4t_all}

GIFuck

最后写出汇总的脚本,GPT参与了part2和part3

首先发现题目是给了一张GIF图片,分出来之后发现是brainfuck的图,写脚本提取能够得到一堆符合brainfuck的字符。但是直接放brainfuck编译器中使用debug查看时,发现在开头存在栈内值为0的时候仍然在减1(即存在下溢),但是在某些工具中并不会出现停止(因为这些工具会%256),但是在有些工具中就会直接停止。因此能猜测栈内可能存在信息,直接查看栈内发现基本都是0。因此猜测gif图片还有其他信息。

接着查看gif发现每一帧的帧时长有所不同。写脚本print之后发现均为60的倍数,猜测每个字符需要*(x//60),因此写出以下脚本

'''part1:get brainfuck'''
from PIL import Image
flag = []
for i in range(1099):
    pic = Image.open(f'Frame{i}.png')
    JIA = pic.getpixel((34,23))[0]
    zkuo = pic.getpixel((30,4))[0]
    jian = pic.getpixel((23,24))[0]
    da = pic.getpixel((16,35))[0]
    xiao = pic.getpixel((31,36))[0]
    ykuo = pic.getpixel((18,47))[0]
    dian = pic.getpixel((19,38))[0]
    if (JIA == 0):
        flag.append('+')
    elif (zkuo == 0):
        flag.append('[')
    elif (jian == 0):
        flag.append('-')
    elif (da == 0):
        flag.append('>')
    elif (xiao == 0):
        flag.append('<')
    elif (ykuo == 0):
        flag.append(']')
    elif (dian == 0):
        flag.append('.')
    else:
        flag.append('?')
print(flag,len(flag))

'''part2:'''

from PIL import Image

def extract_frame_durations(gif_path):
# Open the GIF file
gif = Image.open(gif_path)

# Extract frame durations
frame_durations = []
while True:
frame_durations.append(gif.info.get('duration'0)//60)  # Some GIFs might not have a 'duration' field for each frame
try:
gif.seek(gif.tell() + 1)
except EOFError:
break  # No more frames

return frame_durations

gif_path = "flag.gif"  # Replace with the path to your GIF file
durations = extract_frame_durations(gif_path)
print("Frame Durations:", durations,len(durations))

for i in range(len(durations)):
flag[i] = flag[i]*durations[i]
print(''.join(flag))
brainfuck_code = ''.join(flag)

'''part3'''
#
pointer = 0
tape = [0] * 30000  # Initialize a tape with 30000 cells, all set to 0
code_pointer = 0

# Loop variables
bracket_map = {}
stack = []
output = []

# Map brackets for quick jumps
for i, command in enumerate(brainfuck_code):
if command == '[':
stack.append(i)
elif command == ']':
start = stack.pop()
bracket_map[start] = i
bracket_map[i] = start

# Start interpreting the Brainfuck code
f = open('brainfuck.txt','a')
while code_pointer < len(brainfuck_code):
command = brainfuck_code[code_pointer]

if command == '>':
pointer += 1
elif command == '<':
pointer -= 1
elif command == '+':
tape[pointer] = (tape[pointer] + 1) % 256
elif command == '-':
tape[pointer] = (tape[pointer] - 1) % 256
elif command == '.':
output.append(tape[pointer])
f.write(f'output:{tape[pointer]}')
elif command == ',':
raise NotImplementedError("Input command ',' is not supported.")
elif command == '[':
if tape[pointer] == 0:
code_pointer = bracket_map[code_pointer]
elif command == ']':
if tape[pointer] != 0:
code_pointer = bracket_map[code_pointer]

# Move to the next command
code_pointer += 1

# Print the state for debugging
# f.write(f"Command: {command}, Pointer: {pointer}, Tape: {tape[:100]}, Code Pointer: {code_pointer}n")

# Return the tape and output
print(''.join(str(output)),tape[:100])

 

得到的结果如下:

[83, 111, 114, 114, 121, 32, 98, 117, 116, 32, 121, 111, 117, 114, 32, 102, 108, 97, 103, 32, 105, 115, 32, 110, 111, 116, 32, 104, 101, 114, 101, 46] [68, 65, 83, 67, 84, 70, 123, 80, 101, 110, 95, 80, 105, 110, 101, 97, 112, 112, 108, 101, 95, 65, 112, 112, 108, 101, 95, 80, 101, 110, 125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

第一个数组是直接输出的内容,为Sorry but your flag is not here.

第二个数组是栈内未打印的数据,为DASCTF{Pen_Pineapple_Apple_Pen}

栈内未打印信息即是需要找到的flag

Easy_VMDK

尝试明文爆破,明文只需要满足8字节连续,一共12字节已知即可,查看自己有的vmdk文件,发现一共可知12字节:4B 44 4D 56 01 00 00 00 03 00 00 00

把上面12字节写入key.txt

使用bkcrack爆破:.bkcrack.exe -C .Easy_VMDK.zip -c flag.vmdk -p .key.txt

2023年“羊城杯”网络安全大赛 MISC WriteUp

得到key e6a73d9f 21ccfdbc f3e0c61c

解密得到vmdk文件。使用winhex发现一共有两个文件

2023年“羊城杯”网络安全大赛 MISC WriteUp

提取出来,发现flag.zip后面还有一个zip文件,手动分离得到key.txt加密过程:

import cv2
import base64
import binascii

img = cv2.imread("key.png")
r, c = img.shape[:2]
print(r, c)
# 137 2494

with open("key.txt""w"as f:
for y in range(r):
for x in range(c):
uu_byte = binascii.a2b_uu(', '.join(map(lambda x: str(x), img[y, x])) + "n")
f.write(base64.b64encode(uu_byte).decode() + "n")

直接丢给GPT得到GPT逆向的内容

#Create by GPT
# Initialize an empty list to store the pixel values
decoded_img_data = []

# Read the key.txt file
with open("/mnt/data/key.txt""r"as f:
lines = f.readlines()

# Loop through each line to decode the pixel values
for line in lines:
try:
# Decode from Base64 to uu-encoded bytes
uu_byte = base64.b64decode(line.strip())

# Decode from uu-encoded bytes to original string
decoded_byte = binascii.b2a_uu(uu_byte)

# Convert the comma-separated string back to a list of integers (RGB values)
pixel_values = list(map(int, decoded_byte.decode().strip().split(", ")))

# Append to the image data list
decoded_img_data.append(pixel_values)
except Exception as e:
print(f"An error occurred: {e}")

# Convert the list to a NumPy array and reshape to the original image dimensions
decoded_img_data = np.array(decoded_img_data, dtype=np.uint8)
decoded_img_data = decoded_img_data.reshape((13724943))  # Based on the original image dimensions

# Save the decoded image
decoded_img_path = "/mnt/data/decoded_key.png"
cv2.imwrite(decoded_img_path, decoded_img_data)

decoded_img_path

2023年“羊城杯”网络安全大赛 MISC WriteUp

得到压缩包的密码HELLO_DASCTF2023_WORLD

解压得到flag:DASCTF{2431a606-00a3-4698-8b0f-eb806a7bb1be}

两只老虎

解压后得到一张图片,但是发现这张图片后面IDAT大小突然变了

2023年“羊城杯”网络安全大赛 MISC WriteUp

这里就猜测第chunk[21]是否即这张正常PNG图片的末尾,而再后面部分为多余部分。

接着在chunk[22]发现新的0x789c字节(即满足zlib)

因此合理猜测第一个84EE后面就应该是IEND,尝试删掉chunk[22]与后面的IDAT块,发现对原图并没有影响,因此前面猜测很可能是正确的。

那么删掉chunk[1]~chunk[22]。发现图片有点抽象,猜测高宽不对,先爆破宽度

2023年“羊城杯”网络安全大赛 MISC WriteUp

爆破一下宽度

f = open("2.png",'rb').read()
for i in range(1800):
    fw = open(f'./out/{i}.png','wb')
    data = b''
    data += f[:16]
    w = i.to_bytes(4'big')
    data += w
    data += f[20:]
    fw.write(data)

2023年“羊城杯”网络安全大赛 MISC WriteUp

发现第二张png图片比第一张的宽度多了10,并且两图做xor发现有部分位置不同

2023年“羊城杯”网络安全大赛 MISC WriteUp

发现很多行都有不一样的内容,但是由于不是蓝色的线因此排除盲水印,这里看看每行的颜色和个数


from PIL import Image
img = Image.open('solved.bmp')
w,h = img.size
count = []
for i in range(h):
    tmp = 0
    for j in range(w):
        pixel = img.getpixel((j,i))
        if(pixel != (0,0,0)):
            tmp += 1
    if(tmp!=10):
        count.append(tmp-10)
print(count)

[68, 65, 83, 67, 84, 70, 123, 116, 87, 111, 95, 116, 49, 103, 101, 114, 115, 95, 114, 85, 110, 95, 102, 64, 115, 116, 125]

2023年“羊城杯”网络安全大赛 MISC WriteUp

原文始发于微信公众号(n03tAck):2023年“羊城杯”网络安全大赛 MISC WriteUp

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年8月6日15:22:11
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   2023年“羊城杯”网络安全大赛 MISC WriteUphttps://cn-sec.com/archives/2003525.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息