# from Crypto.Util.number import *importstringimportsecretsfromhashlibimportsha256fromrandomimportrandint,shuffle,choicedefproof_of_work():s=''.join([secrets.choice(string.digits+string.ascii_letters)for_inrange(20)])print(f'sha256(XXXX+{s[4:]}) == {sha256(s.encode()).hexdigest()}')ifinput('Give me XXXX: ')!=s[:4]:exit(1)ROUND_NUM=50PREROUND_NUM=13CHEST_NUM=6withopen('flag','r')asf:flag=f.read()white_list=['==','(',')','0','1','and','or','B0','B1','B2','B3','B4','B5']defcalc(ans,chests,expr):B0,B1,B2,B3,B4,B5=chestsreturnans(eval(expr))defround():chests=[choice((True,False))for_inrange(CHEST_NUM)]print("Six chests lie here, with mimics or treasure hidden inside.")print("But don't worry. Skeleton Merchant knows what to do.")print("Be careful, Skeleton Merchant can lie twice!")truth=lambdar:notnotrlie=lambdar:notrlie_num=randint(0,2)lie_status=[truth]*(PREROUND_NUM-lie_num)+[lie]*lie_numshuffle(lie_status)foriinrange(PREROUND_NUM):try:question=input('Question: ').strip()forwordinquestion.split(' '):assertwordinwhite_list,f"({word}) No treasure for dirty hacker!"result=calc(lie_status[i],chests,question)print(f'Answer: {result}!')exceptExceptionase:print("Skeleton Merchant fails to understand your words.")print(e)print('Now open the chests:')returnchests==list(map(int,input().strip().split(' ')))if__name__=='__main__':proof_of_work()print('Terraria is a land of adventure! A land of mystery!')print('Can you get all the treasure without losing your head?')foriinrange(ROUND_NUM):ifnotround():print('A chest suddenly comes alive and BITE YOUR HEAD OFF.')exit(0)else:print('You take all the treasure safe and sound. Head to the next vault!')print(f"You've found all the treasure! {flag}")
WP
首先我们有异或运算:
r1 xor r2 = ((r1 and r2) == 0 ) and (r1 or r2)
考虑先询问每个值一次,询问方法类似:
B0 == 1
得到每个bool变量的初始值。
由于可能说谎,验证一下,询问:
B0 xor B1 == 1
B2 xor B3 == 1
B4 xor B5 == 1
假设上面的询问与第一轮得到的值有矛盾,则说明A、B、A xor B 中有一个假信息。(有两个假信息概率较小)
frompwnimport*context.log_level='info'fromCrypto.Util.numberimport*frompwnlib.util.itersimportmbruteforcefromhashlibimportsha256fromgmpy2import*table=string.ascii_letters+string.digitsdefpasspow():io.recvuntil(b"XXXX+")suffix=io.recv(16).decode("utf8")io.recvuntil(b"== ")cipher=io.recvline().strip().decode("utf8")gg=0print(suffix)print(cipher)fori1inrange(len(table)):fori2inrange(len(table)):fori3inrange(len(table)):fori4inrange(len(table)):sss=sha256((table[i1]+table[i2]+table[i3]+table[i4]+suffix).encode()).hexdigest()ifsss==cipher:gg=1io.sendline((table[i1]+table[i2]+table[i3]+table[i4]).encode())breakifgg==1:breakifgg==1:breakifgg==1:break#io.sendline(proof.encode()) defXor(a,b):returnf"( ( ( {a} and {b} ) == 0 ) and ( {a} or {b} ) )"defNot(x):ifx==1:return0else:return1defsolve(a,b,vala,valb):io.recvuntil(b"Question: ")io.sendline(f'{Xor(f"B{a}",f"B{b}")} == 1'.encode())io.recvuntil(b"Answer: ")tmp=io.recvline().strip()[:-1]if(eval(tmp))==((vala^valb)==1):returnvala,valb,1io.recvuntil(b"Question: ")io.sendline(f'{Xor(f"B{a}",f"B{b}")} == 1'.encode())io.recvuntil(b"Answer: ")tmp2=io.recvline().strip()[:-1]if(eval(tmp2))==((vala^valb)==1):returnvala,valb,2io.recvuntil(b"Question: ")io.sendline(f'B{a} == 1'.encode())io.recvuntil(b"Answer: ")tmp=io.recvline().strip()[:-1]if(eval(tmp))==vala:returnvala,Not(valb),3else:returnNot(vala),valb,3defexp():passpow()print("DONEPOW")ROUND_NUM=50#io.interactive()io.recvuntil(b"Can you get all the treasure without losing your head?")foriinrange(ROUND_NUM):io.recvuntil(b"Be careful, Skeleton Merchant can lie twice!")print(f'round = {i}')ans=[]forjinrange(6):io.recvuntil(b"Question: ")io.sendline(f'B{j} == 1'.encode())io.recvuntil(b"Answer: ")tmp=io.recvline().strip()[:-1]if(eval(tmp)):ans.append(1)else:ans.append(0)num=6a,b,c=solve(0,1,ans[0],ans[1])num+=cans[0]=aans[1]=ba,b,c=solve(2,3,ans[2],ans[3])num+=cans[2]=aans[3]=ba,b,c=solve(4,5,ans[4],ans[5])num+=cans[4]=aans[5]=bremain=13-numforjinrange(remain):io.recvuntil(b"Question: ")io.sendline(f'B{j} == 1'.encode())io.recvuntil(b"Answer: ")tmp=io.recvline().strip()[:-1]tosend=str(ans)[1:-1].replace(',','')io.recvuntil(b'Now open the chests:\n')io.sendline(tosend)io.interactive()whileTrue:try:io=remote("1.13.154.182",32664)exp()exceptExceptionase:print(e)