隐秘的角落
打开,die,发现是go,idagolanghelper,一套行云流水的操作。
找到关键函数main_main、main_Myencode和main_checkflag。在checkflag找到判定正确的字样:
所以这玩意大概率就是检查flag正确性的。主要还得看Myencode,我们能在里面找到密钥main_enc_key_str。
所以接下来,要么确认它是什么加密,要么直接动调弄出密文。密文猜测为被当作checkflag判断条件的qword_55EA78,我们直接下断点(跟涅普的golang题一样下在判断处),掏出kali就是一个林克死大头。
结果密文不是这玩意,反倒是下面的main_enc指向的unk_54DF80。我们直接从里头掏数据出来。Myencode里头不是用了rc4加密的函数吗,我们照解:
真解出来一玩意。再结合之前再checkflag里看到的东西,我们直接弄出flag:
flag{9e1963bbbb1285b993c862a5a6f12604}
Fantastic_maze
只能说调教了半天的bruteHASH,最后竟然治不了这区区sha256碰撞,还是直接自个写了个针对性脚本才好使。
import hashlib
sha256 = "d6332bef2902cd05d5f39a2ed281b8b2247bf5978544a0d5cab08d6bc8fd3ce4"
strr="ABCDEFGHIJKMLNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
for i in strr:
for j in strr:
for k in strr:
for l in strr:
asc = i+j+k+l
proof = asc + "MiXq73WVMvdx3jYL"
digest = hashlib.sha256(proof.encode('utf-8')).hexdigest()
if digest == sha256:
finale = proof + '\n' + digest+ '\n'
print(finale)
一开始会给你链接,nc一下,sha256碰撞,你会得到一串巨长无比的base64,想来就是题目的真身了。
直接蔡博厨房烤一烤,上ida,草,走,忽略ጿ ኈ ቼ ዽ ጿ
可以看到程序里这帮子函数基本都一个样。在运行了一阵过后发现这就是一个超大号迷宫,迷宫上每一个节点都连接着十个节点,要我们找到一条路杀出去,满足路长等于1000。
但是在运行的过程中发现,每次输入0都会使得过程重置,回到开始的节点(这里没截上图,各位可以自行理解)
好办,遍历图,最短路,前面填充0,完事。由于图的条件太过充裕,甚至连正经最短路都不用,建议广搜(其实是点太少边太多容易出环,一般最短路反倒不好整)。
另外,在运行后发现每次提供的地图都有细微差别,并且端口还会有超时关停,所以还是得实时提取实时操作,这玩意要像pwn题那样处理。(我不熟python,按官解写的,flag挂了,有人有头绪吗)
from pwn import *
import hashlib
import sys
strr="ABCDEFGHIJKMLNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
r = remote("node4.buuoj.cn",25617)
def de_sha256(): #还是之前那样的sha256
r.recvuntil(b'[+] sha256(XXXX+')
salt = r.recv(16).strip().decode()
r.recvuntil(b') == ')
sha256 = r.recv(64).strip().decode()
for i in strr:
for j in strr:
for k in strr:
for l in strr:
asc = i+j+k+l
proof = asc + salt
digest = hashlib.sha256(proof.encode('utf-8')).hexdigest()
if digest == sha256:
print(asc)
r.sendlineafter(b'[+] Plz Tell Me XXXX :', asc.encode('utf-8'))
return
def get_elf(): #在sha256之后提取程序
r.recvuntil(b'map :\n')
data = r.recvuntil(b'That\'s all\n',drop=True)[:-1]
data = base64.b64decode(data)
fd = open('program','wb')
fd.write(data)
fd.close()
de_sha256()
get_elf()
fd = open("./program","rb")
offset = 0x13C0 #所需数据的起始位置
def get_Map(fd,offset):
#接下来经常出现0xd3,代表每个数据组之间的间距,也就是函数偏移
#同理,0xa,每个待取数据之间的偏移
Map = []
for i in range(1000):
addr = offset
for j in range(10):
fd.seek(addr)
fc = u64(fd.read(4).ljust(8,b'\x00'))
if fc <= 0x33765: #话说明明func_999的地址都到0x34000+了,为啥这里设了这么低的上限
fc = fc//0xd3 + i + 1 #取出与当前点连边的点
else: #对于在上限外的点,应该就是对func_1000的条件进行特判吧,条件不符就属于正常点
fc = fc - 0x100000000
if fc > -0xd3:
fc = i
else:
if addr+fc < 0x134A:
fc = 1000
else:
fc = fc//0xd3
fc = i+1+fc
Map.append(fc)
addr += 0xa
offset += 0xd3
return Map
Map = get_Map(fd,offset)
def bfs(Map):
edge = []
keys = []
for st in range(1000):
for ed in range(10):
if ed == 0:
edge.append([])
edge[st].append(Map[ed + st * 10]) #还得麻烦的将一维数组转换成邻接表
for i in range(1000):
keys.append(i)
point_data = dict(zip(keys,edge)) #然后打包成点和边的集合
q = [(0,'')] #python在变量定义上的好处,啥边一块记了
check_map = {}
result1 = None
while len(q):
f = q[0]
q = q[1:]
if(f[0] == 1000):
result1 = f[1]
break
if f[0] not in check_map:
check_map[f[0]] = 1 #ban掉走过的边防止回环
for i in range(10):
if point_data[f[0]][i] not in check_map:
q.append((point_data[f[0]][i],f[1]+str(i)))
return result1
result = bfs(Map)
print(result)
result = str(result)
times = 999 - len(result)
for i in range(times):
r.sendline(b'0')
for i in range(len(result)):
r.sendline(str(int(result[i])+1).encode('utf-8'))
data = r.recvuntil(b'}',drop=True)[:-1]
fin_fd = open('./result.txt','wb')
fin_fd.write(data)
fin_fd.close()
DASCTF{d46dfb6b-610a-48d5-a1d6-2035aa4af67}(未通过)