CSAW 2013: onlythisprogram

The task

As a task we got a the archive onlythisprogram.tgz containing 9 files file[0-9].enc and a script to encrypt and decrypt files.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/usr/bin/python
import os
import sys
import argparse

blocksize=256

parser = argparse.ArgumentParser(description="Custom encryption algorithm because a friend said that's the way to do it. Anyway, it's called 'Only This Program' since I'm pretty sure that only this program can securely decrypt the files as long as you don't give out your secret.dat file created when you encrypt something.")
parser.add_argument('--infile', metavar='i', nargs='?', type=argparse.FileType('r'), help='input file, defaults to standard in', default=sys.stdin)
parser.add_argument('--outfile', metavar='o', nargs='?', type=argparse.FileType('wb'), help='output file, defaults to standard out', default=sys.stdout)
parser.add_argument('--secretkey', metavar='s', nargs='?', type=argparse.FileType('a+'), help='output file, defaults to secretkey.dat', default='secretkey.dat')

args = parser.parse_args()


sys.stderr.write('\nReading random bytes from OS. If hung, please introduce entropy.\n')

args.secretkey.truncate()

while (args.secretkey.tell() < blocksize):
# maybe remove the next line for release since it makes it more obvious the key only generates once?
	sys.stdout.write('.')
	args.secretkey.write(os.urandom(1))

counter=0
args.secretkey.seek(0)
keydata = args.secretkey.read(blocksize)

while 1:
	byte = args.infile.read(1)
	if not byte:
		break
	args.outfile.write(chr(ord(keydata[counter % len(keydata)]) ^ ord(byte)))
	counter+=1

sys.stderr.write('\nSecret keyfile: %s\nInput file: %s\nOutput file: %s\nTotal bytes: %d \n' % (args.secretkey.name, args.infile.name, args.outfile.name, counter))

The encryption is a simple xor encryption with a random 256 byte xor-key. To decrypt these files we xored the first block of each file with the first block every other file. Especially xors with file7.enc produces some readable output. So we selected file8.enc and xored it with each 256byte block of file7.enc. Expecting that the original file7 conains many 0-bytes, we counted the occurences of the bytes on each position of the 256byte block and reassembled the block with the most occuring bytes. This leads to an known plaintext for the first block and therefore also the key.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/usr/bin/env python
def xor(a,b):
	return "".join(map(lambda c: chr((ord(c[0])^ord(c[1]))), zip(a,b)))

basedata = file("file8.enc").read(256)
f = file("file7.enc")
byte_log = []
for i in range(256):
	byte_log.append({})
while True:
	f7txt = f.read(256)
	if not f7txt:
		break
	i = 0
	for xor_byte in xor(basedata, f7txt):
		if xor_byte not in byte_log[i]:
			byte_log[i][xor_byte] = 0
		byte_log[i][xor_byte]+=1
		i+=1

known_plaintext = ""
for i in byte_log:
	bytes = map(lambda a: (a[1], a[0]), i.items())
	bytes.sort(reverse=True)
	known_plaintext += bytes[0][1]

key =  xor(known_plaintext, basedata)

for file_nr in range(9):
	fin = file("file%d.enc" % file_nr)
	fout = file("fout%d.out" % file_nr, "w")
	while 1:
		x = fin.read(256)
		if not x:
			break
		fout.write(xor(x, key))

With this key we are able to decrypt all files:

fout0.out: Standard MIDI data (format 1) using 11 tracks at 1/384
fout1.out: JPEG image data, JFIF standard 1.01, comment: "Created with The GIMP??"
fout2.out: PNG image data, 400 x 208, 8-bit grayscale, non-interlaced
fout3.out: JPEG image data, JFIF standard 1.01
fout4.out: gzip compressed data, from Unix, last modified: Wed Sep  4 02:25:26 2013
fout5.out: PC bitmap, Windows 3.x format, 1452 x 1600 x 1
fout6.out: GIF image data, version 89a, 135 x 46
fout7.out: CDF V2 Document, Little Endian, Os: Windows, Version 5.2, Code page: 1252, Title: Attacks on the RSA Cryptosystem, Author: Scott, Template: Normal.dot, Last Saved By: Scott Nelson (IE), Revision Number: 161, Name of Creating Application: Microsoft Office Word, Total Editing Time: 1d+12:34:00, Last Printed: Mon Mar  6 18:13:00 2006, Create Time/Date: Fri Mar  3 20:49:00 2006, Last Saved Time/Date: Mon Mar  6 19:22:00 2006, Number of Pages: 1, Number of Words: 1424, Number of Characters: 8123, Security: 0
fout8.out: PDF document, version 1.2

The zip-file contains a txt-file with the following content:

_____                                                                                        _  __           _                               _ _           _ _ _                  __ _       _      _             ___           _   _     _                                _ _   _                                                           _                                       _   _               __ _ _              _                 _                 _     _                 _       _                        _                                _                                           _____ _                       _         ___                                              _                                                         _     _     _                                            _            _     _                      _                                          _   _              _                  _           ____        _ _     ___   __                ___                  ____                  _       ____         ___  _   _                   _   _                     _       _    ____                       _ _         
|  ___|__  _ __     ___  ___  _ __ ___   ___     _ __ ___  __ _ ___  ___  _ __      _ __  ___(_)/ _| ___ _ __| |_ _____  __    _ __ ___  __ _| | |_   _    | (_) | _____  ___     / _(_) __ _| | ___| |_ ___      |_ _|_ __     | |_| |__ (_)___      ___ __ _ ___  ___    (_) |_( )___     _ __   ___  ___ ___  ___ ___  __ _ _ __ _   _    | |__   ___  ___ __ _ _   _ ___  ___    | |_| |__   ___     / _(_) | ___     ___(_)_______     ___| |__   ___  _   _| | __| |    _ __   ___ | |_    | |__   ___      __ _    | |__  _   _  __ _  ___      __ _(_)_   _____  __ ___      ____ _ _   _      |_   _| |__   ___  _   _  __ _| |__     |_ _|    ___ _   _ _ __  _ __   ___  ___  ___    (_)_ __ ___   __ _  __ _  ___  ___    __      _____  _   _| | __| |   | |__   __ ___   _____    __      _____  _ __| | _____  __| |   | |_ ___   ___         / \   _ __  _   ___      ____ _ _   _      | |_| |__   ___    | | _____ _   _    (_)___ _    | __ ) _   _(_) | __| \ \ / /__  _   _ _ __ / _ \__      ___ __  / ___|_ __ _   _ _ __ | |_ ___/ ___|  ___  / _ \| |_| |__   ___ _ __ ___| | | | __ ___   _____    | | ___ | |__/ ___|  ___  ___ _   _ _ __(_) |_ _   _ 
| |_ / _ \| '__|   / __|/ _ \| '_ ` _ \ / _ \   | '__/ _ \/ _` / __|/ _ \| '_ \    | '_ \/ __| | |_ / _ \ '__| __/ _ \ \/ /   | '__/ _ \/ _` | | | | | |   | | | |/ / _ \/ __|   | |_| |/ _` | |/ _ \ __/ __|      | || '_ \    | __| '_ \| / __|    / __/ _` / __|/ _ \   | | __|// __|   | '_ \ / _ \/ __/ _ \/ __/ __|/ _` | '__| | | |   | '_ \ / _ \/ __/ _` | | | / __|/ _ \   | __| '_ \ / _ \   | |_| | |/ _ \   / __| |_  / _ \   / __| '_ \ / _ \| | | | |/ _` |   | '_ \ / _ \| __|   | '_ \ / _ \    / _` |   | '_ \| | | |/ _` |/ _ \    / _` | \ \ / / _ \/ _` \ \ /\ / / _` | | | |       | | | '_ \ / _ \| | | |/ _` | '_ \     | |    / __| | | | '_ \| '_ \ / _ \/ __|/ _ \   | | '_ ` _ \ / _` |/ _` |/ _ \/ __|   \ \ /\ / / _ \| | | | |/ _` |   | '_ \ / _` \ \ / / _ \   \ \ /\ / / _ \| '__| |/ / _ \/ _` |   | __/ _ \ / _ \       / _ \ | '_ \| | | \ \ /\ / / _` | | | |     | __| '_ \ / _ \   | |/ / _ \ | | |   | / __(_)   |  _ \| | | | | |/ _` |\ V / _ \| | | | '__| | | \ \ /\ / / '_ \| |   | '__| | | | '_ \| __/ _ \___ \ / _ \| | | | __| '_ \ / _ \ '__/ __| |_| |/ _` \ \ / / _ \_  | |/ _ \| '_ \___ \ / _ \/ __| | | | '__| | __| | | |
|  _| (_) | |      \__ \ (_) | | | | | |  __/   | | |  __/ (_| \__ \ (_) | | | |   | |_) \__ \ |  _|  __/ |  | ||  __/>  <    | | |  __/ (_| | | | |_| |   | | |   <  __/\__ \   |  _| | (_| | |  __/ |_\__ \_     | || | | |   | |_| | | | \__ \   | (_| (_| \__ \  __/   | | |_  \__ \   | | | |  __/ (_|  __/\__ \__ \ (_| | |  | |_| |   | |_) |  __/ (_| (_| | |_| \__ \  __/   | |_| | | |  __/   |  _| | |  __/   \__ \ |/ /  __/   \__ \ | | | (_) | |_| | | (_| |   | | | | (_) | |_    | |_) |  __/   | (_| |   | | | | |_| | (_| |  __/   | (_| | |\ V /  __/ (_| |\ V  V / (_| | |_| |_      | | | | | | (_) | |_| | (_| | | | |    | |    \__ \ |_| | |_) | |_) | (_) \__ \  __/   | | | | | | | (_| | (_| |  __/\__ \    \ V  V / (_) | |_| | | (_| |   | | | | (_| |\ V /  __/    \ V  V / (_) | |  |   <  __/ (_| |   | || (_) | (_) |     / ___ \| | | | |_| |\ V  V / (_| | |_| |_    | |_| | | |  __/   |   <  __/ |_| |   | \__ \_    | |_) | |_| | | | (_| | | | (_) | |_| | |  | |_| |\ V  V /| | | | |___| |  | |_| | |_) | || (_) |__) | (_) | |_| | |_| | | |  __/ |  \__ \  _  | (_| |\ V /  __/ |_| | (_) | |_) |__) |  __/ (__| |_| | |  | | |_| |_| |
|_|  \___/|_|      |___/\___/|_| |_| |_|\___|   |_|  \___|\__,_|___/\___/|_| |_|   | .__/|___/_|_|  \___|_|   \__\___/_/\_\   |_|  \___|\__,_|_|_|\__, |   |_|_|_|\_\___||___/   |_| |_|\__, |_|\___|\__|___(_)   |___|_| |_|    \__|_| |_|_|___/    \___\__,_|___/\___|   |_|\__| |___/   |_| |_|\___|\___\___||___/___/\__,_|_|   \__, |   |_.__/ \___|\___\__,_|\__,_|___/\___|    \__|_| |_|\___|   |_| |_|_|\___|   |___/_/___\___|   |___/_| |_|\___/ \__,_|_|\__,_|   |_| |_|\___/ \__|   |_.__/ \___|    \__,_|   |_| |_|\__,_|\__, |\___|    \__, |_| \_/ \___|\__,_| \_/\_/ \__,_|\__, (_)     |_| |_| |_|\___/ \__,_|\__, |_| |_|   |___|   |___/\__,_| .__/| .__/ \___/|___/\___|   |_|_| |_| |_|\__,_|\__, |\___||___/     \_/\_/ \___/ \__,_|_|\__,_|   |_| |_|\__,_| \_/ \___|     \_/\_/ \___/|_|  |_|\_\___|\__,_|    \__\___/ \___(_)   /_/   \_\_| |_|\__, | \_/\_/ \__,_|\__, ( )    \__|_| |_|\___|   |_|\_\___|\__, |   |_|___(_)   |____/ \__,_|_|_|\__,_| |_|\___/ \__,_|_|   \___/  \_/\_/ |_| |_|\____|_|   \__, | .__/ \__\___/____/ \___/ \___/ \__|_| |_|\___|_|  |___/_| |_|\__,_| \_/ \___|\___/ \___/|_.__/____/ \___|\___|\__,_|_|  |_|\__|\__, |
                                                                                   |_|                                                            |___/                                 |___/                                                                                                                                       |___/                                                                                                                                                                                              |___/          |___/                                 |___/                               |___/                            |_|   |_|                                         |___/                                                                                                                                                 |___/               |___/|/                                 |___/                                                                                            |___/|_|                                                                                                                              |___/ 

For some reason psifertex really likes figlets. In this case it’s necessary because the file size should not be a huge giveaway. Though I suppose images would have worked to Anyway. the key is: BuildYourOwnCryptoSoOthersHaveJobSecurity