Closed ikornaselur closed 8 years ago
#!/usr/bin/python
from Crypto.Cipher.AES import AESCipher
import SocketServer as ss
import signal
import base64
from secret import KEY, FLAG
PORT = 6001
def pad(text, bs):
text = text + FLAG
pad_num = (bs - len(text) % bs)
return text + chr(pad_num) * pad_num
def recvline(req):
buf = b""
while not buf.endswith(b"\n"):
buf += req.recv(1)
return buf
class RequestHandler(ss.BaseRequestHandler):
def handle(self):
req = self.request
# Close the connection after 5 seconds.
signal.alarm(5)
req.sendall("Welcome to l33tserver where all your encryption needs are served.\n")
req.sendall("Send me something to encrypt:\n")
data = recvline(req).strip()
# Try to base64 decode the message
try:
data = base64.b64decode(data)
except:
req.sendall("bad data\n")
req.close()
return
# Return a error if the message didn't start with 'l33tserver please'
if not data.startswith("l33tserver please"):
req.sendall("You didnt say the magic word :(\n")
req.close()
return
# Encrypt the message using `KEY` and pad the data with the FLAG
c = AESCipher(KEY).encrypt(pad(data, 16))
req.sendall("Your l33tcrypted data:\n")
req.sendall(base64.b64encode(c) + "\n")
req.close()
class TCPServer(ss.ForkingMixIn, ss.TCPServer):
pass
ss.TCPServer.allow_reuse_address = True
server = TCPServer(("0.0.0.0", PORT), RequestHandler)
print("Server listening on port %d" % PORT)
server.serve_forever()
I assume that padding each message with the same payload each time (the flag) is a weakness that can be exploited to generate the private key.
I'm gonna walk through the code and comment it so I can get a better understanding of how it works. So just know that the comments added to @ikornaselur comment above are made by me.
I don't think this is a padding oracle attack since it "[...] relies on having a "padding oracle" who freely responds to queries about whether a message is correctly padded or not. "
This might be some attack where when you know the padding and the beginning you can bruteforce the rest. Looking for resource on a attack like that right now but coming up with very little :(
Pretty sure this is a plaintext attack due to the encryption is AES ECB. Looking at this guide.
import sys
with open('strings.txt', 'r') as f:
strings = [x.strip() for x in f.readlines()]
argument = sys.argv[1]
for l in range(len(argument)):
test_string = argument[:len(argument)-l]
found = []
for s in strings:
match = s[2:]
if match.startswith(test_string):
found.append(s)
if len(found):
for f in found:
print f
print " " + test_string
break
How to run:
have strings.txt
with strings in format:
A asjdilas
B ajisdijsa
and then do python script.py test_string
I've been working on this for a bit now and recently got stuck. Pretty sure this is a known-plaintext attack but my scripts aren't working.
Here they are:
☁ l33tscript cat hax.sh
#!/bin/bash
echo -e "l33tserver please $1" | base64 | nc l33tcrypt.vuln.icec.tf 6001 | tail -n 1
☁ l33tscript cat looper.sh
#!/bin/bash
echo > outputs
grep -o . <<< "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_{}?%$@#^*()[];:" | while read letter; do echo "$letter $(./hax.sh "...............$letter")" >> outputs; done
import socket
import time
import sys
from base64 import b64encode
chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_ {}'
PORT = 6001
HOST = 'l33tcrypt.vuln.icec.tf'
block = 'l33tserver please '
key = ''
def send_msg(msg):
answer = ''
retries = 1
while len(answer) == 0:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.recv(256) # Welcome to l33tserver where all your encryption needs are served. # noqa
s.recv(256) # Send me something to encrypt:
s.send('{}\n'.format(b64encode(msg)))
s.recv(256) # Your l33tcrypted data:
answer = s.recv(256)
s.close()
if len(answer) == 0:
retries += 1
sys.stdout.write('.')
sys.stdout.flush()
sleep = 1 if retries < 5 else 5
time.sleep(sleep)
sys.stdout.write('\n')
sys.stdout.flush()
return answer
def get_longest(string, arr):
for l in range(len(string)):
test_string = string[:len(string)-l]
found = []
for s in arr:
if s.startswith(test_string):
found.append(s)
if len(found) == 1:
return found[0]
elif len(found) > 1:
raise Exception('what the shit')
pad_len = 16 - len(block + key) % 16
padding = 'A' * pad_len
msg = block + key + padding
initial = send_msg(msg)
while True:
print "Testing base string string: {}".format(block + key)
results = []
for char in chars:
pad_len = 16 - len(block + key) % 16
msg = block + padding + key + char
sys.stdout.write("Testin {}.".format(msg))
result = send_msg(msg)
results.append((char, result))
longest = get_longest(initial, [x[1] for x in results])
char = [x[0] for x in results if x[1] == longest][0]
print 'Found "{}" as the next char'.format(char)
key += char
Seemed to work for a bit.. but second letter hit a snag, so it's not correct.
import socket
import time
import sys
from base64 import b64encode
chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_ {}'
PORT = 6001
HOST = 'l33tcrypt.vuln.icec.tf'
block = 'l33tserver please '
key = 'IceCTF{unle'
def send_msg(msg):
answer = ''
retries = 1
while len(answer) == 0:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.recv(256) # Welcome to l33tserver where all your encryption needs are served. # noqa
s.recv(256) # Send me something to encrypt:
s.send('{}\n'.format(b64encode(msg)))
s.recv(256) # Your l33tcrypted data:
answer = s.recv(256)
s.close()
if len(answer) == 0:
retries += 1
sys.stdout.write('.')
sys.stdout.flush()
sleep = 1 if retries < 5 else 5
time.sleep(sleep)
sys.stdout.write('\n')
sys.stdout.flush()
return answer
def get_longest(string, arr):
for l in range(len(string)):
test_string = string[:len(string)-l]
found = []
for s in arr:
if s.startswith(test_string):
found.append(s)
if len(found) == 1:
return found[0]
elif len(found) > 1:
raise Exception('what the shit')
while True:
# First iteration, last block padded with 15 A
pad_len = 15 - len(block + key) % 16
padding = 'A' * pad_len
msg = block + padding
# len(msg) == 31
print "pad_len: {}".format(pad_len)
print "Getting base for: {} (len {})".format(msg, len(msg))
initial = send_msg(msg)
results = []
for char in chars:
msg = block + padding + key + char
sys.stdout.write("Testin {}.".format(msg))
result = send_msg(msg)
results.append((char, result))
longest = get_longest(initial, [x[1] for x in results])
char = [x[0] for x in results if x[1] == longest][0]
print 'Found "{}" as the next char'.format(char)
key += char
HOW DO YOU LIKE ME NOW
IT'S HARD WORK CRACKING DEM CODES
Final version of the script
import socket
import time
import sys
from base64 import b64encode
class WhatTheFuck(Exception):
pass
chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_}'
PORT = 6001
HOST = 'l33tcrypt.vuln.icec.tf'
block = 'l33tserver please '
key = 'IceCTF{unleash_th3_Blocks_aNd_find_what_yo'
def send_msg(msg):
answer = ''
retries = 1
while len(answer) == 0 or not answer.startswith('OH7ZG'):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.recv(128) # Welcome to l33tserver where all your encryption needs are served. # noqa
s.recv(64) # Send me something to encrypt:
s.send('{}\n'.format(b64encode(msg)))
s.recv(64) # Your l33tcrypted data:
answer = ''
while not len(answer):
answer = s.recv(256)
s.close()
if not answer.startswith('OH7ZG'):
retries += 1
sys.stdout.write('.')
sys.stdout.flush()
sleep = 0 if retries < 5 else 1
time.sleep(sleep)
sys.stdout.write('\n')
sys.stdout.flush()
return answer
def get_longest(string, arr):
for l in range(len(string)):
test_string = string[:len(string)-l]
found = []
for s in arr:
if s.startswith(test_string):
found.append(s)
if len(found) == 1:
return found[0]
elif len(found) > 1:
raise WhatTheFuck('u wot')
while True:
# First iteration, last block padded with 15 A
pad_len = 15 - len(block + key) % 16
padding = 'A' * pad_len
msg = block + padding
# len(msg) == 31
print "pad_len: {}".format(pad_len)
print "Getting base for: {} (len {})".format(msg, len(msg))
initial = send_msg(msg)
results = []
for char in chars:
msg = block + padding + key + char
sys.stdout.write("Testing {}.".format(msg))
result = send_msg(msg)
results.append((char, result))
longest = get_longest(initial, [x[1] for x in results])
char = [x[0] for x in results if x[1] == longest][0]
if char == '}':
print 'HEHEHEHEHE'
print key
break
print 'Found "{}" as the next char'.format(char)
key += char
Description
l33tcrypt is a new and fresh encryption service. For added security it pads all information with the flag! Can you get it?
nc l33tcrypt.vuln.icec.tf 6001
server.pySolution
Flag is:
IceCTF{unleash_th3_Blocks_aNd_find_what_you_seek}