Bài này khi ta connect với server ta nhận đc mã Morse, khi decode mã Morse ta được bài RSA cổ điển với cipher cố định, e = 3 và N random nhưng điểm chung là rất lớn đối với c
n =122210677556715920469489888641269363693199366599255488173988172826554505844409054840356782750585839204246353553753879699378163362496336196111317791953233652238169552637885906298695803346642204941338769369532424723845873686548090743865592912214627795469389269724971994692308036391920187126382118274444019137473e =3c =152167424273977436702890273274501734012765882487008338973232502170356375148818609621863975256
*Part1:
ta dễ dằng decrypt bằng 3√c, đến đây ta thấy kí tự khá quen mắt " Cbxrzba Anzrf" quăng vào rot13 ta được "Pokemon Names" tuy nhiên ta cần nhập lại server nhanh vì mỗi lần chall chỉ verify tầm 10-15s.
*Part2:
sau khi gửi "Pokemon Names" server lại trả về mã morse tương tự, làm lại các bước ở Part1 ta sẽ được tên của một con pokemon, tiếp tục part 3,4,5... ta sẽ được các pokemon riêng biệt . Có 800+ pokemons và mỗi lần connect với server kết quả các pokemon lại khác nhau tại các part nên bỏ ngay ý định brute force. Mình viết script nhận dữ liệu từ server và response lập tức vì mỗi lần connect server chỉ verify đúng 1 lần.
from pwn import*from Crypto.Util.number import*import codecsimport base64p=remote("crypto.chal.csaw.io", 5001)# Dictionary representing the morse code chartMORSE_CODE_DICT ={'A':'.-','B':'-...','C':'-.-.','D':'-..','E':'.','F':'..-.','G':'--.','H':'....','I':'..','J':'.---','K':'-.-','L':'.-..','M':'--','N':'-.','O':'---','P':'.--.','Q':'--.-','R':'.-.','S':'...','T':'-','U':'..-','V':'...-','W':'.--','X':'-..-','Y':'-.--','Z':'--..','1':'.----','2':'..---','3':'...--','4':'....-','5':'.....','6':'-....','7':'--...','8':'---..','9':'----.','0':'-----',', ':'--..--','.':'.-.-.-','?':'..--..','/':'-..-.','-':'-....-','(':'-.--.',')':'-.--.-'}# Function to encrypt the string# according to the morse code chartdefencrypt(message): cipher =''for letter in message:if letter !=' ':# Looks up the dictionary and adds the# correspponding morse code# along with a space to separate# morse codes for different characters cipher += MORSE_CODE_DICT[letter]+' 'else:# 1 space indicates different characters# and 2 indicates different words cipher +=' 'return cipher# Function to decrypt the string# from morse to englishdefdecrypt(message):# extra space added at the end to access the# last morse code message +=' ' decipher ='' citext =''for letter in message:# checks for spaceif (letter !=' '):# counter to keep track of space i =0# storing morse code of a single character citext += letterelse: i +=1if i ==2: decipher +=' 'else: decipher +=list(MORSE_CODE_DICT.keys())[list(MORSE_CODE_DICT .values()).index(citext)] citext =''return decipherdeffind_invpow(x,n): high =1while high ** n < x: high *=2 low = high//2while low < high: mid = (low + high) //2if low < mid and mid**n < x: low = midelif high > mid and mid**n > x: high = midelse:return midreturn mid +1p.recvuntil("Can you decrypt them all to prove yourself?\r\n\r\nWhat does this mean?\r\n")message = p.recvuntil("\r\n>>",drop=True).decode("utf-8")message = message.replace('/',' ')result =decrypt(message)p.sendline('Pokemon Names')for i inrange(0,5): p.recvuntil("What does this mean?\r\n") message2 = p.recvuntil("\r\n>>",drop=True).decode("utf-8") message2 = message2.replace('/',' ') result2 =decrypt(message2) result2 = result2.split(' ') result2 = result2[:-1] num1 =list(map(int, result2)) lst = []for i in num1: lst.append(chr(i)) mystring ="".join(lst) vitri = base64.b64decode(mystring) vitri = vitri .decode("utf-8") n = vitri .find("c") vitri = vitri [n+3:] vitri =int(vitri ) key = codecs.encode(str(long_to_bytes(find_invpow(vitri ,3))), 'rot_13') key = key [2:-1]print(key) p.sendline(key)p.interactive()
from pwn import*from Crypto.Util.number import*p=remote("crypto.chal.csaw.io", 5008)p.recvuntil("What is the plaintext?")p.sendline('Wiener wiener chicken dinner')p.recvuntil("What is the plaintext?")p.sendline('Who came up with this math term anyway?')p.recvuntil("Part 3 --> Looks like there is a oracle which is telling the LSB of the plaintext. That will not help you, right?")message = p.recvuntil("\r\nWhat would you like to decrypt? (please respond with an integer)\r\n",drop=True).decode('utf-8')n = message.split('= ')N =int(n[1][:-4])c =int(n[3][:-2])i =1flag =""upper_limit = Nlower_limit =0while i<=1030: s = (c*pow(2**i,65537,N))%N p.sendline(str(s)) mes = p.recvuntil("\r\nWould you like to continue? (yes/no)\r\n",drop=True).decode('utf-8')if'The oracle responds with: 1'in mes: lower_limit = (lower_limit + upper_limit)//2elif'The oracle responds with: 0'in mes: upper_limit = (upper_limit + lower_limit)//2else:breakprint ("Unsuccessfull")print(upper_limit, i) p.sendline('1') p.recvuntil("What would you like to decrypt? (please respond with an integer)") i+=1print ("Flag : ", long_to_bytes(lower_limit))p.interactive()# key3: "Totally did not mean to put an oracle there"
Đây là giải vui nhất mình từng chơi tính đến thời điểm hiện tại. Phần dùng pwntool connect vào server mình không biết làm từ giải hcmus, về sau cứ hễ gặp bài nào tựa vậy là quá khứ ùa về :< .Mình làm được 2 bài trên do các bạn trong team hỗ trợ rất nhiều, ae chỉ từng dòng code, cỗ vũ từng phút. Đây cũng là lần đầu 4 ae cùng thức thâu đêm đến end giải. Cảm giác vui cực kì! chỉ có thể nói: Quá đãaaaaaaaaaaaaaa.