A-X Write up-Aster(没###)
第四届信安大挑战-Write up
--By Aster
> MISC
1. wow
首先查看属性,得到第一部分flag:d1no{We1co,然后喜闻乐见拖进010里面,在text最下面有flag2 : me_2_mi5c,最后打开虚拟机kali指令foremost -i wow.jpg -o output分离得
在文件夹input里面可以看到原图片隐藏的另外一张图片,由图片可以直接得到第三部分flag:_w0r1d}。最终将这三个flag拼起来就好。
2. 唐伯虎
首先打开文件是两张图片:第一张打不开,拖进010发现是缺了png的文件头89 50 4E 47 0D 0A 1A 0A 00 00 00补上就好就可以打开了。然后打开图片,该图片有缺失,用脚本判断是否修改长宽高。
import binascii
import struct
crcbp = open(r"C:\Users\zengjq\Desktop\新建文件夹\tbh.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))
结果是3863826129(crc值) 597 380 hex: 0x255 0x17c 和原图的png比不一样(00 00 01 3C)改成7c就好,然后得到下图
得到数字9527,好了下一步,研究另外一张看起来像是二维码的png,但是这个用QR识别不出来任何有用的东西(除了一串唐伯虎书生有秘密的英文)。
于是启用我们万能()的StegSlove!发现了lsb隐写的痕迹,然后在上面的analyse中选中data extract然后R,G,B通道都选0。得到了
526172211A0701003392B5E50A010506000501018080008EA3AD605502033CB00004A600206CBCA2C880030008666C61672E747874300100030F6AF6C2EB7EA36735BB9D95120281503D231B715090542F2ECF84AF8DB0C5D1F078B234AA1AC4BCDDC26E28D50A03027980A9FF1201DA01ACDF0616C72700403F5CB04510EE4D512DF5AEAA7545E1912A8B1DF985E201C8B9FEE99B4329DD3CC207C1E658304C1B1D77565103050400
这段东西一开始非常迷惑,还以为是base之类的东西,但是这样的话那个9527就没有用了,然后又像是各种有秘钥(是9527)的加密什么的但是都没对啊---最终发现是十六进制的东西,很棒,丢进万能的010!赞美010()然后发现是rar文件,密码就是9527.
最后flag就是dino{a4gbh300a5100ba78043765661b93a5c}(题外话困死了扛不住了睡了明天还有早自习六点半要早起我真的哭死第一节还是高数QAQ以后一定要有做题记录不然就会像我现在这样重新做一遍还要找之前的文件哭死)
3.YYDZ
首先打开压缩包,里面先是一个文件夹和一个显示要输入密码的txt文档,然后在那个文件夹里面又是一个可以提取出来的压缩包,压缩包打开后是一个图片和一个txt,都是要密码的。
一开始我是想着直接爆破的里面那个可以提取出来的压缩包的,然后什么都没有爆出来(用的是kali的rarcrack,然后就ERROR了)
现在是直接爆不出来,已知这个是一个压缩包套一个压缩包,刚刚是爆不出来里面的,那就老老实实地仔细观察外面的压缩包。拖进万能的010里面!发现居然是伪加密,好家伙(
不过因为这个压缩包里面东西太多了直接把所有的1400后面的09全部改成00会发现文件损坏了所以就只能改一些特定的(后面发现里面的是真加密不能直接改)于是就改了两个,一个是外面的txt的,另外一个是外面的zip的,如上图改的两个,改完后就可以打开外面的txt了
得到了"oh, you find me, here is the tip: the secret may be very very easy six numbers"
然后里面的这个应该就是真加密了,拿已知的外面的解除了伪加密的压缩包来撞这个里面的真加密的压缩包
然后得到图片
这个图片pngcheck什么都没有问题,但是我们这里有一个信息一直没有用,就是那六个数字的那个!联想一下以及查询资料(其中走过的弯路就不多说了)最终得到是LSB 隐写,这可以使用密码来加密将嵌入到图像中的信息。然后就通过脚本来解出最终的flag(下面的代码是lsb.py的脚本。)
import sys
import struct
import numpy
import argparse
import matplotlib.pyplot as plt
from Crypto.Util.number import long_to_bytes
from p_il import Image
from crypt import AESCipher
# Decompose a binary file into an array of bits
def decompose(data):
v = []
# Pack file len in 4 bytes
fSize = len(data)
bs = b''
size_byte = struct.pack('i', fSize)
bs += size_byte
bs += data
# bs += [ord(b) for b in data]
for b in bs:
for i in range(7, -1, -1):
v.append((b >> i) & 0x1)
return v
# Assemble an array of bits into a binary file
def assemble(v):
bs = b""
length = len(v)
for idx in range(0, len(v), 8):
b = 0
for i in range(0, 8):
if (idx + i < length):
b = (b << 1) + v[idx + i]
b = long_to_bytes(b)
bs = bs + b
# print("debug:", len(bs[:4]))
payload_size = struct.unpack("i", bs[:4])[0]
return bs[4: payload_size + 4]
# Set the i-th bit of v to x
def set_bit(n, i, x):
mask = 1 << i
n &= ~mask
if x:
n |= mask
return n
# Embed payload file into LSB bits of an image
def embed(imgFile, payload, outFile, password):
# Process source image
img = Image.open(imgFile)
(width, height) = img.size
conv = img.convert("RGBA").getdata()
print("[*] Input image size: %dx%d pixels." % (width, height))
max_size = width*height*3.0/8/1024 # max payload size
print("[*] Usable payload size: %.2f KB." % (max_size))
f = open(payload, "rb")
data = f.read()
f.close()
print("[+] Payload size: %.3f KB " % (len(data)/1024.0))
# Encypt
cipher = AESCipher(password)
data_enc = cipher.encrypt(data)
# Process data from payload file
v = decompose(data_enc)
# Add until multiple of 3
while(len(v)%3):
v.append(0)
payload_size = len(v)/8/1024.0
print("[+] Encrypted payload size: %.3f KB " % (payload_size))
if (payload_size > max_size - 4):
print("[-] Cannot embed. File too large")
sys.exit()
# Create output image
steg_img = Image.new('RGBA',(width, height))
data_img = steg_img.getdata()
idx = 0
for h in range(height):
for w in range(width):
(r, g, b, a) = conv.getpixel((w, h))
if idx < len(v):
r = set_bit(r, 0, v[idx])
g = set_bit(g, 0, v[idx+1])
b = set_bit(b, 0, v[idx+2])
data_img.putpixel((w,h), (r, g, b, a))
idx = idx + 3
steg_img.save(outFile, "PNG")
print("[+] %s embedded successfully!" % payload)
# Extract data embedded into LSB of the input file
def extract(in_file, out_file, password):
# Process source image
img = Image.open(in_file)
(width, height) = img.size
conv = img.convert("RGBA").getdata()
print("[+] Image size: %dx%d pixels." % (width, height))
# Extract LSBs
v = []
for h in range(height):
for w in range(width):
(r, g, b, a) = conv.getpixel((w, h))
v.append(r & 1)
v.append(g & 1)
v.append(b & 1)
data_out = assemble(v)
# Decrypt
cipher = AESCipher(password)
data_dec = cipher.decrypt(data_out)
# Write decrypted data
out_f = open(out_file, "wb")
out_f.write(data_dec)
out_f.close()
print("[+] Written extracted data to %s." % out_file)
# Statistical analysis of an image to detect LSB steganography
def analyse(in_file):
'''
- Split the image into blocks.
- Compute the average value of the LSBs for each block.
- The plot of the averages should be around 0.5 for zones that contain
hidden encrypted messages (random data).
'''
BS = 100 # Block size
img = Image.open(in_file)
(width, height) = img.size
print("[+] Image size: %dx%d pixels." % (width, height))
conv = img.convert("RGBA").getdata()
# Extract LSBs
vr = [] # Red LSBs
vg = [] # Green LSBs
vb = [] # LSBs
for h in range(height):
for w in range(width):
(r, g, b, a) = conv.getpixel((w, h))
vr.append(r & 1)
vg.append(g & 1)
vb.append(b & 1)
# Average colours' LSB per each block
avgR = []
avgG = []
avgB = []
for i in range(0, len(vr), BS):
avgR.append(numpy.mean(vr[i:i + BS]))
avgG.append(numpy.mean(vg[i:i + BS]))
avgB.append(numpy.mean(vb[i:i + BS]))
# Nice plot
numBlocks = len(avgR)
blocks = [i for i in range(0, numBlocks)]
plt.axis([0, len(avgR), 0, 1])
plt.ylabel('Average LSB per block')
plt.xlabel('Block number')
# plt.plot(blocks, avgR, 'r.')
# plt.plot(blocks, avgG, 'g')
plt.plot(blocks, avgB, 'bo')
plt.show()
#def show_usage():
#sys.exit()
if __name__ == "__main__":
usage_text = """
LSB steganogprahy. Hide files within least significant bits of images.
example:
python3 lsb.py hide -i [img_file] -s [payload_file] -o [out_file] -p [password]
python3 lsb.py extract -i [stego_file] -o [out_file] -p [password]
python3 lsb.py analyse -i [stego_file]
"""
parser = argparse.ArgumentParser(usage_text)
parser.add_argument('-i', help='file input', type=str, dest='in_file')
parser.add_argument('-o', help='file output', type=str, dest='out_file', default='out.png')
parser.add_argument('-s', help='file to hide as secret', type=str, dest='secret_file')
parser.add_argument('-p', help='passcode for hide/extract secret', type=str, dest='password')
if len(sys.argv) <= 1:
parser.print_help()
exit()
u = sys.argv.pop(1)
args = parser.parse_args()
if u == "hide":
if args.in_file and args.secret_file and args.out_file and args.password:
embed(args.in_file,
args.secret_file,
args.out_file,
args.password)
else:
parser.print_help()
elif u == "extract":
if args.in_file and args.out_file and args.password:
extract(args.in_file,
args.out_file,
args.password)
else:
parser.print_help()
elif u == "analyse":
if args.in_file:
analyse(args.in_file)
else:
parser.print_help()
else:
parser.print_help()
python lsb.py extract -i yydz.png -o 123456.txt -p 123456最终生成的txt里面打开就是flag
4. musique
这个题其实就用ffmpeg -i musique audio_input.wav利用ffmpeg就好,导出wav文件,然后网易云听歌识曲,(歌好听但是直接把歌名放上去好像不行,然后仔细听音乐发现最后面有点奇怪,再结合网易云评论和题目提示,得出是倒放,启动au倒放一遍,然后再识别,发现是另外一首歌!歌名就是flag了(这边就懒得放歌的照片了)
5. 蒸蒸日上
这张图片我一开始就丢到steg里面去看,很明显就可以看到里面有图片藏着,是像素点的感觉。然后经过各种绕弯路,最终是写了一个提取像素点的脚本
import cv2
import numpy as np
# 读取PNG图片
image_path = r"C:\Users\zengjq\misc\zheng.png"
image = cv2.imread(image_path)
# 定义间距
interval = 10
# 获取图片尺寸
height, width, _ = image.shape
# 计算合成图片的尺寸
new_width = (width - 1) // interval + 1
new_height = (height - 1) // interval + 1
# 创建合成图片
new_image = np.zeros((new_height, new_width, 3), dtype=np.uint8)
# 遍历原始图片的像素点,并将其复制到合成图片中
for y in range(0, height, interval):
for x in range(0, width, interval):
new_x = x // interval
new_y = y // interval
new_image[new_y, new_x] = image[y, x]
# 保存合成图片
output_path = r"C:\Users\zengjq\misc\2.png"
cv2.imwrite(output_path, new_image)
print("合成图片保存成功。")
另外这里附一个如何知道像素点坐标的脚本,手动点击肉眼看那个像素点,多点几个就会发现其间距为10
import cv2
import numpy as np
from PIL import Image
# 鼠标点击事件的回调函数
def mouse_callback(event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDOWN:
# 获取点击点的像素坐标
print("点击坐标:({}, {})".format(x, y))
# 获取点击点的像素值(BGR格式)
pixel_value = img[y, x]
print("像素值:", pixel_value)
# 加载图片
image_path = r"C:\Users\zengjq\Desktop\新建文件夹\solved2.png"
pil_image = Image.open(image_path).convert("RGB")
img = cv2.cvtColor(np.array(pil_image), cv2.COLOR_RGB2BGR)
# 创建窗口并绑定鼠标事件回调函数
cv2.namedWindow("Image")
cv2.setMouseCallback("Image", mouse_callback)
while True:
# 显示图片
cv2.imshow("Image", img)
# 按下Esc键退出循环
if cv2.waitKey(1) == 27:
break
# 关闭窗口
cv2.destroyAllWindows()
最终运行脚本得到下面的图片
最后喜闻乐见,丢到steg里面,然后在上面的analyse中选中data extract然后R,G,B通道都选0。然后就得到flag了。
6. 近源渗透
这个不多说,去209!|ू・ω・` )
7. OSINT-小蛮腰
这个其实有点取巧的方法,好吧就是我懒得看地图_(:ι」∠)_谷歌地图还要下载什么东西好麻烦(,因为是游客去看,所以搜索关键词,最佳观赏广州塔的地方,另外从图片看是公园,再加上公园,找一找试一试就出来了(。
最终得出是二沙岛艺术公园:广东省广州市越秀区二沙岛晴澜路72号
8. 绝密文件
重头戏来了,就是这个绝密文件!
利用Word文档的本质:docx文件在本质上是zip压缩包文件,因此将一个docx文件的后缀改为zip,这个文件是可以用压缩软件正常打开的,可以看到解压文件中有一个word文件夹,这里面包含了word文档的大部分内容。其中document.xml文件中含有的则是该文档的主要文本内容。所以里面就有很多没有用的xml文件,下图是我第一次做的时候是用010然后截了后面的zip部分得到压缩包的,也可以得到压缩包但是是笨方法,直接改后缀就好。
解压压缩包发现里面有一个图片,老规矩丢到steg里面,然后在上面的analyse中选中data extract然后R,G,B通道都选0。得到D1no{Th3 _trait0,这里用了一个很巧的方法,就是看修改日期,图片是23号修改的,所以同理另外一个flag也是在23号修改的,最终找到字体文件(otf后缀那个)在压缩包里有一个txt文件给了提示,说是阿尔法,首先这个是字体文件,而这里的阿尔法猜测是α,因为是字体嘛,想着还是先提取出来看看,上网搜索otf在线提取字体
然后出现啦!不过值得注意的是这个不是二维码,(我拼了好久的二维码,把那个定位的标标准准的p上去!!!!啊啊啊)是汉信码,然后用画图工具取个反色,丢到在线工具识别一下,就得到flag的后半段了。最终拼好是D1no{Th3_trait0r_1s_F@ckiNG_4gent_CaSO4!!!!}可喜可贺,终于misc结束啦!(ΦωΦ)
> Re
1. ezzzzRe
直接看伪代码,伪代码的意思是比较经过f异或操作的输入 s2 与预定的数组s1 是否相等,相等就对了。逆向方法就是直接将预定的数组和f异或就好,以下是脚本:
s1 = [2, 15, 8, 9, 29, 15, 57, 10, 15, 13, 3, 57, 30, 9, 20, 71, 27]
a = ord('f')
b = [char ^ a for char in s1]
print(b)
ascii = ''.join(chr(char) for char in b)
print(ascii)
最后要将输出的数字用ASCII码来转换成dino{i_like_xor!}
2. xxor
直接看伪代码,伪代码是将输入通过一系列运算然后和预设值比较,只要等于预设值就好了,如下图的一系列运算
那么如何逆向呢?直接反过来算就好,不过值得注意的是要用c来写,就是要用到c的溢出,用python反而得到的数据不对。
#include <iostream>
#include <stdint.h>
using namespace std;
__int64 __fastcall sub_400686(unsigned int *a1, uint32_t *a2)
{
__int64 result; // rax
unsigned int v0; // [rsp+1Ch] [rbp-24h]
unsigned int v1; // [rsp+20h] [rbp-20h]
int sum; // [rsp+24h] [rbp-1Ch]
int i; // [rsp+28h] [rbp-18h]
v0 = a1[0];
v1 = a1[1];
sum = 1166789954 * 64;
for (i = 63; i >= 0; --i)
{
v1 -= (v0 + sum + 20) ^ ((v0 << 6) + a2[2]) ^ ((v0 >> 9) + a2[3]) ^ 16;
v0 -= (v1 + sum + 11) ^ ((v1 << 6) + *a2) ^ ((v1 >> 9) + a2[1]) ^ 32;
sum -= 1166789954;
}
a1[0] = v0;
result = v1;
a1[1] = v1;
return result;
}
int main()
{
unsigned int a1[6] = {3746099070, 550153460, 3774025685, 1548802262, 2652626477, 2230518816};
// char a[10]={1,2,3,4,5,6,7,8,9,0};
// uint16_t
// printf("%d %d",a,b);
// cout << "Hello World"; // 杈撳嚭 Hello World
unsigned int key[4] = {
0x00000002, 0x00000002, 0x00000003, 0x00000004};
uint32_t tem[2] = {0};
for (int i = 0; i < 3; i++)
{
tem[0] = a1[i * 2];
tem[1] = a1[i * 2 + 1];
sub_400686(tem, key);
a1[i * 2] = tem[0];
a1[i * 2 + 1] = tem[1];
}
for(int i =0;i<6;i++){
printf("0x%x,",a1[i]);
}
return 0;
}
得到0x666c61,0x677b72,0x655f69,0x735f67,0x726561,0x74217d,这个是十六进制转换成字符串就好,最终得到flag{re_is_great!}
> Crypto3
是RSA加密,直接在网上找脚本,如下
import gmpy2
from Crypto.Util.number import *
def de(c, e, n):
k = 0
while True:
m = c + n * k
result, flag = gmpy2.iroot(m, e)
if True == flag:
return result
k += 1
e = 9
n = 2800044824704621161408665070096853947736471375809408114098504125569189326981850873756311998035561133370945799293194026395296121838093207817136585825949157679904170730243010344871339192919835817926135015055414284965057057708346778778581329589685284686696372352221082736286133576168931099271148252236883012403496658924224956405857439076345201056693601421753628592658844074893903298266563815677656415830541123249011148724016642256329797514085644462597502092709584001125596700232311250492638863550504723144793688211368899306332430229146836662375704351611753874378005540939509720322238106864311927416511422879
c = 50813016517568878016409873603227581583352450747957029419437128510454380806457561089831772166484562811261422445797830523681349099188802633361172741268812281751871116274963493305165486230968687852912899386295985135331424148166905314247488293529894149095924504781165982436403031658992809890245446381233851310676021230220800977360309867468788216091252005906528648738870947253335500012273885003081106254025970027025237698114781092720091942730994812261782658030289994286518315706862286214184975539812669654725865669250630154575679486008553567147644603766683460114727781413993626253671415044650579725532319901
m = de(c, e, n)
print(m)
print(long_to_bytes(m))
最终得到b'D1no{M1Nni3_Mans0n_Att@ck!!}'