0xGame2022 Week1~4 Misc Offical Writeup & 全附件

全附件点这里

Week1

Singin

关注关注快关注

看不见的字符

根据描述得知存在0宽字符隐写,使用在线工具即可成功提取隐藏数据,然后把解出来的密文解若干次base64即可拿到flag

旅游照片

图片属性中可以找到拍摄的日期和时间

接下来只要去网上找B-7631号在这段时间的航班信息就可以了(官方找法是用”飞常准“app,但不是唯一解)

垃圾邮件

拿到key.txt先进行解密,顺序为:AAencode-->Brainfuck-->Base64-->Base64-->Base58-->Base32

得到key:P@33w0rD

如果你不知道flag.txt里的内容的话,可以上网搜,就可以搜到有关这种隐写的解密网站,在里面选择带密码的解密模式即可成功解密

EzPcap

简单的流量分析,只要过滤http流即可看到flag

奇怪的符号

Langue Sheikah,找个表解密一下即可

好多压缩包

本题的提示全在注释里,第一步根据注释进行六位数字爆破得到密码114514

第二步伪加密,修改标记位即可

第三步掩码爆破,选择小写字母即可得到密码iohaewbf

最后一步明文攻击,不难发现3333里面有一个crc值和4444里面lookatme.txt一摸一样的文档,再注意到注释里的以存储形式压缩,明文攻击即可

Signin(校内版)

来了就有

Week2

booooom

注意到password被分成了三个部分并且每个部分都在6字节以下,考虑crc32爆破,使用现成工具或者写脚本爆破都可以,得到password:You_Know_CRC32

flag.txt里的表情是emojiaes加密

🙃💵🌿🎤🚪🌏🐎🥋🚫😆✅🚫😁ℹ🎈🚨🌊📮😁🔬🌏🍵🚫✖🎅🕹🐘🎈⌨😇🚹☂🚰☀🌿😎😂🐅💵☀💵⌨🤣🚫😇😎☀🤣🚫😀😆🚪😂🦓🌏ℹ🎤🍴👉🎈😇✉⏩🏹🔪🎤🏎🚹🐍⏩💵🎤🚨🚫⌨🎤🌪👑📮✉✉ℹ🍌💵📂😀🗒🗒

使用在线工具以及上面的密码再解一次即可

0xGame{8d815cfe-851c-4c8c-b283-858d3f3e8c91}

BabyRe

先是pyc反编译,用在线工具或者uncompyle6都可以,得到原来的加密代码

# uncompyle6 version 3.8.0
# Python bytecode 2.7 (62211)
# Decompiled from: Python 3.9.13 (main, Jun 8 2022, 09:45:57)
# [GCC 11.3.0]
# Embedded file name: 1.py
# Compiled at: 2022-08-22 17:01:47
import base64

def encode(str):
  fflag = '0'
  for i in range(1, len(flag)):
      x = ord(flag[i]) ^ ord(flag[(i - 1)])
      x += 30
      fflag += chr(x)

  return base64.b64encode(fflag)


flag = open('flag.txt').read()
enc = encode(flag)
print enc
# okay decompiling flag.pyc

可以发现加密函数就是将原flag的每一位与上一位异或的结果再加30最后整体base64加密

于是可以轻松写出解密代码

import base64

cipher=open(r"C:\Users\16334\Desktop\out.txt").read()
ccipher=base64.b64decode(cipher)
flag='0'

for i in range(1,len(ccipher)):
  a=ccipher[i]-30
  flag+=chr(ord(flag[i-1])^a)

print(flag)

得到flag

0xGame{afd9461d-35fb-4e9b-9716-aa83b3ed681a}

哥们在这给你说唱

音频的两个经典考点,由描述可知存在deepsound,使用deepsound提取文件时提示需要密码,密码在silenteye里

直接提取就行

0xGame{5d4d7df0-6de7-4897-adee-e4b3828978f8}

不太普通的图片

stegsolve可以发现在rgb0通道有明显的lsb特征,可是stegsolve却解不出来,猜测是带密码的lsb,同时在b0通道可以发现密码:0xGameyyds

使用cloacked-pixel解一下即可

0xGame{Hidd3n_1n_Pic}

隔空取物

由提示可知这里用的是zip传统加密,同时可以看到压缩包内部是png文件,而png文件头的16字节是固定的,这时候就可以使用已知明文攻击的方法解开压缩包

需要使用的是bkcrack,png头对于png本身的偏移量是0,所以构造攻击命令

echo 89504E470D0A1A0A0000000D49484452 | xxd -r -ps > png_header
bkcrack -C flag.zip -c flag.png -p png_header -o 0 >1.log

跑个几分钟就可以得到密钥

ab7d8bcd 6ce75578 4de51c12

然后拿来提取文件

bkcrack -C flag.zip -c flag.png -k ab7d8bcd 6ce75578 4de51c12 -d flag.png

这样就可以成功得到flag.png

最后发现图片crc值错误,脚本爆破一下就可以得到正确宽高:1080x608

import binascii
import struct

crcbp = open("1.png", "rb").read() #打开图片
crc32frombp = int(crcbp[29:33].hex(),16) #读取图片中的CRC校验值
print(crc32frombp)

for i in range(4000): #宽度1-4000进行枚举
for j in range(4000): #高度1-4000进行枚举
data = crcbp[12:16] + \
struct.pack('>i', i)+struct.pack('>i', j)+crcbp[24:29]
crc32 = binascii.crc32(data) & 0xffffffff
#print(crc32)
if(crc32 == crc32frombp): #计算当图片大小为i:j时的CRC校验值,与图片中的CRC比较,当相同,则图片大小已经确定
print(i, j)
print('hex:', hex(i), hex(j))
exit(0)

最后得到flag

0xGame{D0_Y0u_L1k3_89504E47?}

Week3

BabyUSB

基础的键盘流量分析,后半部分的密码和第一周是同样的手法,得到:Part of the zip password is s_Here

另一部分简单分析后可以将流量中含有hiddata的部分先提取出来再用脚本一把梭

import os
os.system("tshark -r 1.pcapng -T fields -e usb.capdata > usbdata.txt")
normalKeys = {"04":"a", "05":"b", "06":"c", "07":"d", "08":"e", "09":"f", "0a":"g", "0b":"h", "0c":"i", "0d":"j", "0e":"k", "0f":"l", "10":"m", "11":"n", "12":"o", "13":"p", "14":"q", "15":"r", "16":"s", "17":"t", "18":"u", "19":"v", "1a":"w", "1b":"x", "1c":"y", "1d":"z","1e":"1", "1f":"2", "20":"3", "21":"4", "22":"5", "23":"6","24":"7","25":"8","26":"9","27":"0","28":"<RET>","29":"<ESC>","2a":"<DEL>", "2b":"\t","2c":"<SPACE>","2d":"-","2e":"=","2f":"[","30":"]","31":"\\","32":"<NON>","33":";","34":"'","35":"<GA>","36":",","37":".","38":"/","39":"<CAP>","3a":"<F1>","3b":"<F2>", "3c":"<F3>","3d":"<F4>","3e":"<F5>","3f":"<F6>","40":"<F7>","41":"<F8>","42":"<F9>","43":"<F10>","44":"<F11>","45":"<F12>"}

shiftKeys = {"04":"A", "05":"B", "06":"C", "07":"D", "08":"E", "09":"F", "0a":"G", "0b":"H", "0c":"I", "0d":"J", "0e":"K", "0f":"L", "10":"M", "11":"N", "12":"O", "13":"P", "14":"Q", "15":"R", "16":"S", "17":"T", "18":"U", "19":"V", "1a":"W", "1b":"X", "1c":"Y", "1d":"Z","1e":"!", "1f":"@", "20":"#", "21":"$", "22":"%", "23":"^","24":"&","25":"*","26":"(","27":")","28":"<RET>","29":"<ESC>","2a":"<DEL>", "2b":"\t","2c":"<SPACE>","2d":"_","2e":"+","2f":"{","30":"}","31":"|","32":"<NON>","33":"\"","34":":","35":"<GA>","36":"<","37":">","38":"?","39":"<CAP>","3a":"<F1>","3b":"<F2>", "3c":"<F3>","3d":"<F4>","3e":"<F5>","3f":"<F6>","40":"<F7>","41":"<F8>","42":"<F9>","43":"<F10>","44":"<F11>","45":"<F12>"}


nums = []
keys = open('usbdata.txt')
for line in keys:
#print(line)
if len(line)!=17: #首先过滤掉鼠标等其他设备的USB流量
continue
nums.append(line[0:2]+line[4:6]) #取一、三字节
#print(nums)
keys.close()
output = ""
for n in nums:
if n[2:4] == "00" :
continue

if n[2:4] in normalKeys:
if n[0:2]=="02": #表示按下了shift
output += shiftKeys [n[2:4]]
else :
output += normalKeys [n[2:4]]
else:
output += '[unknown]'
print('output :' + output)

于是可以得到第一部分密码:“Part<SPACE>of<SPACE>the<SPACE>password<SPACE>is<SPACE>P@334<DEL>w0rD_1”

去掉空格等按键后得到:Part of the password is P@33w0rD_1

使用两部分的密码即可成功解开压缩包拿到flag

0xGame{E43y_Traff1c_Analy3i3}

螺旋升天

结合题目名可以发现,密码大概符合这种规律

是螺旋形,以及根据hint,可以得知压缩包的结构也被一样根据螺旋打乱了,正好压缩包的大小是289=17*17,于是就可以构造一个17*17的矩阵来进行变换,脚本如下(相关算法可以在网上找到

def function(n):
matrix = [[0] * n for _ in range(n)]

number = 1
left, right, up, down = 0, n - 1, 0, n - 1
while left < right and up < down:
# 从左到右
for i in range(left, right):
matrix[up][i] = number
number += 1

# 从上到下
for i in range(up, down):
matrix[i][right] = number
number += 1

# 从右向左
for i in range(right, left, -1):
matrix[down][i] = number
number += 1

for i in range(down, up, -1):
matrix[i][left] = number
number += 1
left += 1
right -= 1
up += 1
down -= 1
# n 为奇数的时候,正方形中间会有个单独的空格需要单独填充
if n % 2 != 0:
matrix[n // 2][n // 2] = number
return matrix

import struct
s = function(17)
s = sum(s,[])
f = open('flag.zip','rb').read()
arr = [0]*289
for i in range(len(s)):
arr[s[i]-1] = f[i]
with open('fflag.zip', 'wb')as fp:
for x in arr:
b = struct.pack('B', x)
fp.write(b)

这样就可以还原原压缩包,再用给的密码就可以拿到flag

0xGame{6e93c04c-5478-4d34-9dd2-c46742d551bb}

证取单简

入门级内存取证,先获取版本

volatility -f mem imageinfo

得到版本为Win7SP1x64,再看看进程

volatility -f mem --profile=Win7SP1x64 pslist

可以看到有cmd,notepad,explorer等可疑进程,于是分别使用参数cmdscan,editbox,iehistory查看

可以发现cmd里有一段重要信息,说的是出题人喜欢用一样的密码,包括开机密码,这里就可以用各种工具去获取密码,得到用户zysgmzb的密码:0xGame2022

又在editbox里发现一段密文,根据题目名,可以联想到需要倒过来解密,这是U2Fsd开头的加盐AES,很明显是用某网站解密,配合上面得到的密码即可解密

0xGame{F1rst_St3p_0f_Forens1cs}

Time To Live

直接搜索题目名即可得知大概的意思,即把所有数字转2进制之后可以发现后6位全是1,取前两位即可解密,但是这里改了改,换成了后四位,但是解密脚本还是很好写

file=open(r"C:\Users\16334\Desktop\Time To Live.txt").read().splitlines()
bina=''
for i in file:
a=int(i)
a=bin(a)[2:].zfill(8)
bina+=a[0:4]
base=long_to_bytes(int(bina,2))

提取之后就可以得到一段完整的base64,同时可以看出这是一个jpg图片转过来的base64,解密即可得到原图,再根据题目描述可以猜到有一个图片盲水印,由于只有一张图,所以猜测是傅里叶盲水印,脚本或者工具都可以解密,完整exp如下

from Crypto.Util.number import *
import base64
file=open(r"C:\Users\16334\Desktop\Time To Live.txt").read().splitlines()
bina=''
for i in file:
a=int(i)
a=bin(a)[2:].zfill(8)
bina+=a[0:4]
base=long_to_bytes(int(bina,2))
flagimg=base64.b64decode(base)
with open(r"C:\Users\16334\Desktop\1.jpg",'wb') as f:
f.write(flagimg)
f.close

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
img = cv.imread(r"C:\Users\16334\Desktop\1.jpg", 0)
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
s1 = np.log(np.abs(fshift))
plt.subplot(121)
plt.imshow(img, 'gray')
plt.title('original')
plt.subplot(122)
plt.imshow(s1,'gray')
plt.title('center')
plt.show()

下图是工具解密效果,比脚本好一些

我也很异或呢

看见题目名就可以知道这题和异或有关系,大概有两种方法,一种是github上的工具xortool一把梭

另一种则是仔细观察,可以发现文件hex里有许多类似于0xGame的文本

猜测和尝试之后也可以试出密码是0xGame,再写脚本进行整体异或

import struct
f=open('flag','rb').read()
a=[0]*len(f)
key='0xGame'
for i in range(len(f)):
a[i]=(f[i]^ord(key[i%len(key)]))
with open('fflag', 'wb')as fp:
for x in a:
b = struct.pack('B', x)
fp.write(b)

两种方法都可以得到正确结果(但是xortool大多数情况下不是很好用

发现得到的结果是一个压缩包,然后就可以提取出文件flagishere.Q,搜索一下后缀为.Q的文件就可以知道这是按键精灵的脚本文件,下个按键精灵再运行脚本即可(好像有点语法上的问题

Week4

听首音乐?

midi文件,如果上网仔细搜的话可以搜到有一种esolang就是以midi音频的形式存在的,官方文档里有现成的编译器,直接拿来编译

接着运行编译好的文件,发现是纯输出字符的程序

What a long number:4642488275724448709921860001805542920743247922240305533

稍微fuzz一下,猜测是用密码学的库里面的long_to_bytes函数

0xGame{StRAnGe_eSOL4N9}

ColorfulDisk

先是各凭本事打开磁盘,我用的是取证大师。

可以发现一共就几个文件,其中包含两个加密文件和一个password.txt

再根据提示,使用密码去挂载那个1,得到一张很怪的图片。再根据hint,fuzz一下,导出所有rgb值并写入文件

from PIL import Image, ImageDraw
import struct
width = 1042
height = 1042
img=Image.open("1.png")
a=[]
for i in range(height):
for j in range(width):
pi=img.getpixel((j,i))
for k in range(3):
a.append(pi[k])
with open('flag', 'wb')as fp:
for x in a:
b = struct.pack('B', x)
fp.write(b)

发现读出来一个wav音频,简单听一下,一眼丁真,鉴定为sstv。直接用Github现成工具解一下,得到密码

拿密码解下压缩包拿到flag

0xGame{RGB_Co1or_Pix3l}

走失的猫猫

根据题目描述,简单fuzz下,猜测是被删了,要数据恢复,取证大师直接梭

恢复出一张catcat.png

可以发现图片hex值尾部有几个参数

a = 114  b = 514  st = 1

根据参数的数量和图片名以及图片特征,猜测是arnold变换,网上脚本直接解

from PIL import Image

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

st = 1
a = 114
b = 514
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('flag.png')

0xGame{C4t_1n_Th3_Disk}

SIMPLE_QR

第一部分没什么好说的,反色之后简单修一修,即可得到第一段flag

0xGame{ed4a6398-9360-????

接着binwalk分离一下图片,发现有一个多出来的idat块,解一下zlib压缩,得到一段数据

000000011011001100110011010000000011111011100010001000100010111110010001010001000100010001010100010010001011000100010001000110100010010001011101110111011101110100010011111011011101110111011110111110000000010101010101010101010000000111111110001000100010001011111111000100000100110011001100100111011010100111100110011001100110010010000011000011101110111011110110010001001110110111011101110100110101000111001111011101110111010011111011011110010001000100010010011010111111001100010001000100010010010000011110101000100010001011010110100001000010110011001100100110110101010100000110011001100100110000000110011101101110111011100011000110000110010111011101110111010111110101001011011101110111000010111101100111110001000100010010010110011111011100010001000100001111110101000101011000100010001011110111010110010110110011001100000000101111111110110110011001101011100100000000010011101110111011010101110011111010010111011101110011100110010001010101011101110111000000110010001011010001000100011101001111010001010110010001000101010000110011111010001000100010000110000101000000010010110011001100111100100

观察一下,数据大小为1089个字节,刚好是33的平方,而33x33也是一个常见的二维码尺寸,所以把0转黑,1转白写个脚本

from PIL import Image
MAX = 33
pic = Image.new("RGB",(MAX, MAX))
str = "000000011011001100110011010000000011111011100010001000100010111110010001010001000100010001010100010010001011000100010001000110100010010001011101110111011101110100010011111011011101110111011110111110000000010101010101010101010000000111111110001000100010001011111111000100000100110011001100100111011010100111100110011001100110010010000011000011101110111011110110010001001110110111011101110100110101000111001111011101110111010011111011011110010001000100010010011010111111001100010001000100010010010000011110101000100010001011010110100001000010110011001100100110110101010100000110011001100100110000000110011101101110111011100011000110000110010111011101110111010111110101001011011101110111000010111101100111110001000100010010010110011111011100010001000100001111110101000101011000100010001011110111010110010110110011001100000000101111111110110110011001101011100100000000010011101110111011010101110011111010010111011101110011100110010001010101011101110111000000110010001011010001000100011101001111010001010110010001000101010000110011111010001000100010000110000101000000010010110011001100111100100"
i=0
for y in range (0,MAX):
  for x in range (0,MAX):
      if(str[i] == '0'):
          pic.putpixel([x,y],(0, 0, 0))
      else:
          pic.putpixel([x,y],(255,255,255))
      i = i+1
pic.show()
pic.save("flag.png")

扫一下得到后面一段

0xGame{ed4a6398-9360-????-9c89-82272f3c621e}

最后是中间一小段,仔细观察原图可以发现存在两个png尾,并且前一个png是完整的,后一个没头。

接下来就很简单了,复制下后半段的数据,手动补一下16个字节的头,就可以得到最后一个二维码,扫码补全flag

0xGame{ed4a6398-9360-41ff-9c89-82272f3c621e}

两个版本附件都差不多,只有那个多余的idat块那里的考点有区别,旧版的附件处理之后得到的结果是这样的

4132d396338392d3832323732663363363231657d0ec3866203861203666203065203437206366206239

这里需要参考一下二维码的阅读标准,涉及到一些二维码的编码以及纠错方面的知识(其实就是ACTF原题

推荐这篇文章

初步了解后,我们可以先解一下这段密文并转为二进制

如果把这段数据想成是二维码的数据的话,根据阅读标准,那么前四位就是模式标识符,这里是0100也就是字节模式。模式标识符后八位代表所承载数据的长度,所以可以读出数据长度为19。同时在字节模式下,数据是按照每个字节八位二进制的方式存储的。

最后,直接删掉4位的模式标识符和8位的长度标识符,就可以读出这段长度为19的数据了,也就是flag最后一段。

后面冗余数据则是结束符和纠错码,不用管它。

这样,也可以得到一样的flag

0xGame{ed4a6398-9360-41ff-9c89-82272f3c621e}
posted @ 2022-10-28 08:32  zysgmzb  阅读(1174)  评论(0编辑  收藏  举报