本次比赛除去签到题,misc出了5个,还有两个没出,分别是ThreeBody(只有长亭科技的大佬做了出来>_<,也是本次线上赛第一名,大佬终究是大佬),然而,作为【强网先锋】的题目“协议”,最后依旧零解,这里就不给wp了,毕竟自己太菜了,根本不会。下面就简要记录一下做题流程,太菜勿喷~
0x01 MISC Blue Teaming
解压后hex打开,发现7z文件头,修改文件格式,解压得到mem.dump
volatility 查看文件(用法),根据题目提示用了powershell的脚本执行,那么查找有关powershell的相关信息,千找万找最终决定查找powershell日志文件 ——evtx格式文件,将其导出,发现两端powershell代码,如下图,结果,发现上面的代码就是下面的结果,
无语,还以为要出题了呢。
无奈,继续思考题目的用意,突然想到注册表申请的命令行用法:
REG QUERY命令参数(注册表)参考链接
winhex查看文件,搜索“reg query”,发现一段代码如下
尝试提交该注册表~
Flag竟然就是这个????无语HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Communication
这里要说明一下,本次比赛,非正式格式flag会给说明,而本题就是,结果,兜兜转转,flag竟在眼前!!!啥也不说了,小丑竟是我自己,呜呜呜呜~
0x02 cipherman
本题下载文件后,发现依旧是一个内存取证题目,有了上一题的经验,这直接定位特殊文件了。volatility 查看memery,直接搜索txt文件
发现下面的文件
Device\HarddiskVolume2\Users\RockAndRoll\Desktop\BitLocker 복구 키 168F1291-82C1-4BF2-
B634-9CCCEC63E9ED.txt
还带韩文!但关键是BitLocker!!!
将该txt文件导出查看内容:
BitLocker 드라이브 암호화 복구 키
복구 키는 BitLocker로 보호되는 드라이브에서 데이터를 검색하기 위해 사용됩니다.
이 키가 올바른 복구 키인지 확인하려면 복구 화면에 표시된 것과 ID를 비교하십시오.
복구 키 ID: 168F1291-82C1-4B
전체 복구 키 ID: 168F1291-82C1-4BF2-B634-9CCCEC63E9ED
BitLocker 복구 키:
221628-533357-667392-449185-516428-718443-190674-375100
翻译后
BitLocker磁碟机加密恢复密钥
恢复键用来从BitLocker保护下的驱动器中获取数据。
对比ID和恢复屏幕中显示的恢复键,可以确定这是一个有效的恢复键。
恢复密钥ID: 168F1291-82C1-4B
整体恢复密钥ID: 168F1291-82C1-4BF2-B634-9CCCEC63E9ED
BitLocker恢复键:
221628 - 533357 - 667392 - 449185 - 516428 - 718443 - 190674 - 375100
已经很明显了,是一个bitlocker文件卷加密,使用diskginus打开输入恢复健即可打开,发现readme文件,跟内容说我们做题应该就到此结束了,题目显示依旧是非正式格式flag,难道这就是flag?
果然,到这里,做题的我已经被搞心态了,哈哈哈,还是不能按套路出牌。
Wow, you have a great ability. How did you solve this? Are you a hacker? Please give me a lesson later.
0x03 ExtremlySlow
流量包题目。先从流量中提取latest文件,需要按照content-range字段重新组合,得到latest之后,使用010editor打
开发现是pyc,检查了magic number应该是3.10以上的版本,修改unpyc,添加了GEN_START、修复字
典相关字节码处理,成功反编译出源码,分析源码可知需要输入26个字节的数据,打印RC4的密钥m得
到stegosaurus字符串,推测应该是pyc隐写,使用stegosaurus工具,适配3.10后即可解出26字节数
据。输入后打印c,即得到flag
该流量包最好先用命令(kali)tshark -2 -R “http” -r input.pcap -T json >output.json
导出json格式的文件,方便提取数据,下面是提取数据脚本
提取脚本1:
file = open("gh.json","r",encoding="utf-8")
f = open("ghres.json","a+",encoding="utf-8")
src = file.readlines()
for i in src:
if "http.response.line" in i and "content-range" not in i:
pass
else:
f.write(i)
f.close()
提取代码2
import json
F2 = open("ghres.json","r",encoding="utf-8")
content = json.loads(F2.read())
res = dict()
#[_source][layers][http][http.response.line]
#[_source][layers][data][data.data]
for pkt in content:
if "data" in pkt["_source"]["layers"].keys():
tmp = pkt["_source"]["layers"]["http"]["http.response.line"].split(" ")[2]
index = int(tmp[:tmp.find("-")])
res[index]=bytes.fromhex(pkt["_source"]["layers"]["data"]["data.data"])
SortedKeys = sorted(res.keys())
out = open("test","wb+")
for i in SortedKeys:
out.write(res[i])
out.close()
这是结合手工逆向字节码后的Pyc
import sys
from hashlib import sha256
MOD = 256
def KSA(key):
key_length = len(key)
# create the array "S"
S = list(range(MOD)) # [0,1,2, ... , 255]
j = 0
for i in range(MOD):
j = (j + S[i] + key[i % key_length]) % MOD
S[i], S[j] = S[j], S[i] # swap values
return S
def PRGA(S):
i = 0
j = 0
while True:
i = (i + 1) % MOD
j = (j + S[i]) % MOD
S[i], S[j] = S[j], S[i] # swap values
K = S[(S[i] + S[j]) % MOD]
yield K
def RC4(key):
S = KSA(key)
return PRGA(S)
def xor(p, stream):
return bytes(map(lambda x: x ^ stream.__next__(), p))
if __name__ == '__main__':
w = b'\xf6\xef\x10H\xa9\x0f\x9f\xb5\x80\xc1xd\xae\xd3\x03\xb2\x84\xc2\xb4\x0e\xc8\xf3<\x151\x19\n\x8f'
e = b'$\r9\xa3\x18\xddW\xc9\x97\xf3\xa7\xa8R~'
b = b'geo'
s = b'}\xce`\xbej\xa2\x120\xb5\x8a\x94\x14{\xa3\x86\xc8\xc7\x01\x98\xa3_\x91\xd8\x82T*V\xab\xe0\xa1\x141'
t = b"Q_\xe2\xf8\x8c\x11M}'<@\xceT\xf6?_m\xa4\xf8\xb4\xea\xca\xc7:\xb9\xe6\x06\x8b\xeb\xfabH\x85xJ3$\xdd\xde\xb6\xdc\xa0\xb8b\x961\xb7\x13=\x17\x13\xb1"
m = {2: 115, 8: 97, 11: 117, 10: 114}
n = {3: 119, 7: 116, 9: 124, 12: 127}
m |= {x : x ^ n[x] for x in n}
m |= ((i.bit_count(), i) for i in b)
print(m)
stream = RC4(list(map(lambda x: x[1], sorted(m.items()))))
print(xor(w, stream).decode())
p = sys.stdin.buffer.read(26)
e = xor(e, stream)
c = xor(p, stream)
if sha256(c).digest() == s:
print(xor(t, stream).decode())
else:
print(e.decode())
0x04 ISO1995
赛后才知道本题竟然是原题,只不过当时零解。下面就简单分析一下。
首先要知道,微软时间戳是从1900年1月1日开始的,本题文件是windows下的一个文件系统,使用isobuster打开,可以看到文件引导部分正确的时间
下图标蓝部分就是一般文件正确的时间戳,前面的01指的是文件大小(暂不考虑),这些字节分别对应 78(年) 0B(月) 02(日) 14(时) 33(分) 05(秒) 08(时区)
而本题关键在后面的数据分区,同样存在时间戳,但明显是不正确的,都是FFFFFFFF+不同的两字节+0802格式,想必此处有蹊跷。那么想办法把全部的不同的两个字节拿出来分析一下,看看什么情况。
到这里,就通过观察知道数据分区的flagfolder的时间戳是错的。这里还需要说明的是每一个foldflag文件里都有一个字节。 每一个foldflag文件的时间戳也存在字节不同,那么,联想到这,其实,也大概清楚了,最终的答案应该就是这些单独字节经过某种排序后可以获得flag。那么这字节提取脚本,就不放给大家了,方法很多,写脚本,word文档处理什么的都行,很快很方便。如下图,全部拿出!!!
将这些提取出的每两个字节看作十六进制,然后输出,会发现是数字0~1023,刚好对应1024个文件内容(即1024个字节)。其实到这里,本题就结束了,很明显,就是按照提取出的数字为索引,而1024个字节顺序不变,输出,里面就包含flag
其实,仔细地同学会发现,数字并不是0~1023连续的,提取出的字节中,出现了两次“0000”,最后发现这些数字中少了“01A0”也就是416,好在从原理上,不影响本题flag的出现,不知是否是出题人给的彩蛋呢!!!
file = open("Bytes_1024","rb")
src = file.read()
out = []
length = len(src)
for i in range(0,length):
if src[i] != 0:
out.append(src[i])
for i in out:
print(chr(i),end='')
two = []
f = open("Numbers.txt","r").read().split()
for i in f:
two.append(int(i,16))
for i in two:
print(chr(out[i]),end='')
0x05 EzTime
本题依旧很“突然”,明显是NTFS log文件,使用工具NTFS Log Tracker V1.2.exe将题目给的两个文件打开,能够导出一个文件
LogFile.csv
找到这个文件,根据提示,直接查看时间的错误就行。
下图中的文件访问时间早于修改时间,直接提交文件名即可
总结
信息隐藏依旧是需要积累经验的,感谢本次合作的队友,本次比赛确实收获了很多,但道路且长啊,仍需努力!!!