0xGame2022 Week1~4 Misc Offical Writeup & 全附件
Week1
关注关注快关注
看不见的字符
根据描述得知存在0宽字符隐写,使用
旅游照片
图片属性中可以找到拍摄的日期和时间
接下来只要去网上找B-7631号在这段时间的航班信息就可以了(官方找法是用”飞常准“app,但不是唯一解)
垃圾邮件
拿到key.txt先进行解密,顺序为:
得到key:P@33w0rD
如果你不知道flag.txt里的内容的话,可以上网搜,就可以搜到有关这种隐写的
EzPcap
简单的流量分析,只要过滤http流即可看到flag
奇怪的符号
Langue Sheikah,找个表解密一下即可
好多压缩包
本题的提示全在注释里,第一步根据注释进行六位数字爆破得到密码114514
第二步伪加密,修改标记位即可
第三步掩码爆破,选择小写字母即可得到密码iohaewbf
最后一步明文攻击,不难发现3333里面有一个crc值和4444里面lookatme.txt一摸一样的文档,再注意到注释里的以存储形式压缩,明文攻击即可
Signin(校内版)
来了就有
Week2
booooom
注意到password被分成了三个部分并且每个部分都在6字节以下,考虑crc32爆破,使用
flag.txt里的表情是emojiaes加密
🙃💵🌿🎤🚪🌏🐎🥋🚫😆✅🚫😁ℹ🎈🚨🌊📮😁🔬🌏🍵🚫✖🎅🕹🐘🎈⌨😇🚹☂🚰☀🌿😎😂🐅💵☀💵⌨🤣🚫😇😎☀🤣🚫😀😆🚪😂🦓🌏ℹ🎤🍴👉🎈😇✉⏩🏹🔪🎤🏎🚹🐍⏩💵🎤🚨🚫⌨🎤🌪👑📮✉✉ℹ🍌💵📂😀🗒🗒
使用
0xGame{8d815cfe-851c-4c8c-b283-858d3f3e8c91}
BabyRe
先是pyc反编译,用
# 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
使用
0xGame{Hidd3n_1n_Pic}
隔空取物
由提示可知这里用的是zip传统加密,同时可以看到压缩包内部是png文件,而png文件头的16字节是固定的,这时候就可以使用已知明文攻击的方法解开压缩包
需要使用的是
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。直接用
拿密码解下压缩包拿到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}