Encoding Challenge
Desc
Setelah memahami ASCII, hex, Base64, ROT13, dan integer besar, challenge ini meminta kita mengotomatisasi proses decoding. Server akan mengirim 100 data acak dengan tipe encoding berbeda, lalu kita harus mengirim balik hasil decode yang benar.
Jika semua 100 level berhasil dijawab, server akan mengirim flag.
File 13377.py adalah source code logic server. File pwntools_example.py adalah template client untuk connect ke server dan mengirim response JSON.
Untuk informasi lebih lanjut tentang cara terhubung ke challenge interaktif, lihat FAQ CryptoHack. Jika ingin mengetes secara lokal, perlu modul
utils.listenerdari CryptoHack.
Connect at socket.cryptohack.org 13377
Attachment
- https://cryptohack.org/static/challenges/13377_86793614535c47dea371d2f0e406dbd9.py
- https://cryptohack.org/static/challenges/pwntools_example_f93ca6ccef2def755aa8f6d9aa6e9c5b.py
#!/usr/bin/env python3
from Crypto.Util.number import bytes_to_long, long_to_bytes
from utils import listener # this is cryptohack's server-side module and not part of python
import base64
import codecs
import random
FLAG = "crypto{????????????????????}"
ENCODINGS = [
"base64",
"hex",
"rot13",
"bigint",
"utf-8",
]
with open('/usr/share/dict/words') as f:
WORDS = [line.strip().replace("'", "") for line in f.readlines()]
class Challenge():
def __init__(self):
self.no_prompt = True # Immediately send data from the server without waiting for user input
self.challenge_words = ""
self.stage = 0
def create_level(self):
self.stage += 1
self.challenge_words = "_".join(random.choices(WORDS, k=3))
encoding = random.choice(ENCODINGS)
if encoding == "base64":
encoded = base64.b64encode(self.challenge_words.encode()).decode() # wow so encode
elif encoding == "hex":
encoded = self.challenge_words.encode().hex()
elif encoding == "rot13":
encoded = codecs.encode(self.challenge_words, 'rot_13')
elif encoding == "bigint":
encoded = hex(bytes_to_long(self.challenge_words.encode()))
elif encoding == "utf-8":
encoded = [ord(b) for b in self.challenge_words]
return {"type": encoding, "encoded": encoded}
#
# This challenge function is called on your input, which must be JSON
# encoded
#
def challenge(self, your_input):
if self.stage == 0:
return self.create_level()
elif self.stage == 100:
self.exit = True
return {"flag": FLAG}
if self.challenge_words == your_input["decoded"]:
return self.create_level()
return {"error": "Decoding fail"}
import builtins; builtins.Challenge = Challenge # hack to enable challenge to be run locally, see https://cryptohack.org/faq/#listener
listener.start_server(port=13377)from pwn import * # pip install pwntools
import json
r = remote('socket.cryptohack.org', 13377, level = 'debug')
def json_recv():
line = r.recvline()
return json.loads(line.decode())
def json_send(hsh):
request = json.dumps(hsh).encode()
r.sendline(request)
received = json_recv()
print("Received type: ")
print(received["type"])
print("Received encoded value: ")
print(received["encoded"])
to_send = {
"decoded": "changeme"
}
json_send(to_send)
json_recv()Solution
Contoh manual dengan nc hanya membuktikan format komunikasinya: server mengirim JSON berisi type dan encoded, lalu client membalas JSON berisi decoded.
wget https://cryptohack.org/static/challenges/13377_86793614535c47dea371d2f0e406dbd9.py -O 13377.py
wget https://cryptohack.org/static/challenges/pwntools_example_f93ca6ccef2def755aa8f6d9aa6e9c5b.py -O pwntools_example.py
nc socket.cryptohack.org 13377
# {"type": "bigint", "encoded": "0x726561636865735f61746c61735f6d61726b657273"}
# {"decoded": "reaches_atlas_markers"}
# {"type": "bigint", "encoded": "0x70726f66696c655f656469746f72735f636f6e74696e75697479"}Untuk menyelesaikannya, kita buat fungsi decode() yang menangani semua tipe encoding yang mungkin dikirim server.
from pwn import *
import json
from Crypto.Util.number import long_to_bytes
import base64
import codecs
def decode(encoded, encoding_type):
if encoding_type == "base64":
return base64.b64decode(encoded).decode()
if encoding_type == "hex":
return bytes.fromhex(encoded).decode()
if encoding_type == "rot13":
return codecs.decode(encoded, "rot_13")
if encoding_type == "bigint":
return long_to_bytes(int(encoded, 16)).decode()
if encoding_type == "utf-8":
return "".join(chr(b) for b in encoded)
raise ValueError(f"Unknown encoding: {encoding_type}")
r = remote("socket.cryptohack.org", 13377, level="debug")
def json_recv():
line = r.recvline()
return json.loads(line.decode())
def json_send(hsh):
request = json.dumps(hsh).encode()
r.sendline(request)
received = json_recv()
while True:
decoded_value = decode(received["encoded"], received["type"])
print(f"Decoded value: {decoded_value}")
json_send({"decoded": decoded_value})
received = json_recv()
if "flag" in received:
print(f"Flag: {received['flag']}")
break
print("Received type:")
print(received["type"])
print("Received encoded value:")
print(received["encoded"])Penjelasan fungsi decoding:
base64:base64.b64decode(encoded).decode()mengubah Base64 menjadi bytes, lalu bytes menjadi string.hex:bytes.fromhex(encoded).decode()mengubah hex menjadi bytes, lalu bytes menjadi string.rot13:codecs.decode(encoded, "rot_13")menggeser huruf ROT13 kembali ke teks asli.bigint:int(encoded, 16)membaca integer hex dari server, lalulong_to_bytes()mengubahnya menjadi bytes.utf-8: server mengirim list angka ordinal, jadichr(b)mengubah tiap angka menjadi karakter.
Loop utama akan terus menerima challenge baru, decode sesuai type, mengirim {"decoded": decoded_value}, lalu berhenti ketika response server berisi key flag.
Summary
Challenge ini melatih otomasi decoding dan komunikasi JSON. Library yang dipakai adalah pwntools untuk socket, json untuk encode/decode request, base64 untuk Base64, codecs untuk ROT13, dan Crypto.Util.number.long_to_bytes untuk integer besar.
Flag
crypto{3nc0d3_d3c0d3_3nc0d3}