Whitehat Contest 11 Forensics 200
Point: 200 http://material.wargame.whitehat.vn/contests/11/for1_206e72e52f2f73fa1a1080b70d528657.zip nc 118.70.80.143 7337
We are given an archive which contains a file named image
and an address to netcat
to. Try to run file
on image
, we got:
image: DOS/MBR boot sector, code offset 0x52+2, OEM-ID "NTFS ", sectors/cluster 8, Media descriptor 0xf8, sectors/track 63, heads 255, hidden sectors 128, dos < 4.0 BootSector (0x0), FAT (1Y bit by descriptor); NTFS, sectors/track 63, physical drive 0x80, sectors 20479, $MFT start cluster 853, $MFTMirror start cluster 2, bytes/RecordSegment 2^(-1*246), clusters/index block 1, serial number 060aabb3daabb0e92; contains Microsoft Windows XP/VISTA bootloader BOOTMGR
So, it is a NTFS disk image file. I moved it to the handy FTK Imager and found these 2 files:
And this little file encrypt.pyc
seems very interesting (cuz I don't know what the other file is anyway :( ). After decrypting it, we got this:
# Embedded file name: L:\DungBTb\DungBTb\exam ctf\contest 6\encrypt.py import socket, os, string, random, re, base64, sys #import decrypt SIZE_READ = 100 def long2hexstring(data): data = long(data) hex_string = hex(data).lstrip('0x').rstrip('L') return hex_string def long2hexlist(data): tmp = hex(data).lstrip('0x').rstrip('L') if len(tmp) % 2 == 1: tmp = '0' + tmp hex_list = [ tmp[i:i + 2] for i in xrange(0, len(tmp), 2) ] return hex_list def data2hexstring(data): hex_data = '' for char in data: tmp = ord(char) tmp = hex(tmp)[2:] if len(tmp) == 1: tmp = '0' + tmp hex_data += tmp return hex_data def data2hexlist(data): hex_data = [] for char in data: tmp = ord(char) tmp = hex(tmp)[2:] if len(tmp) == 1: tmp = '0' + tmp hex_data.append(tmp) return hex_data def extension_(): return ['.doc', '.docx', '.txt', '.mp4', '.mp3', '.jpg', '.jpng', '.flv', '.png', '.xlsx', '.ppt', '.pptx', '.pdf', '.html', '.php', '.jsp'] def getExponent(): ee = '' Dantonz = 'ZnV6dQ==' jtyiel = 'Z2tkb318zz==' t = 65535 if ee == '': return t + 2 e = base64.b64decode(ee) return long(e, 16) def getModule(): nn = 'MTA1NjM1NzA' nn += '3OTk0MjE1Nzg1MDY0NTkyNjg4ODI5NDMxNjAzMjk1MDkyM' nn += 'D' Dantonz = 'ZnV6dQ==' nn += 'E5MzMyOTQxMzQwMjE4MDYzMDI0MD' nn += 'MwMjE0MTEyNDM1NDc3Mzg4OTU1NDcyMDc4MDYxOTY3MzY2NTkxMjc0NDM5NzE' nn += chr(ord('z')) + chr(ord('N')) jtyiel = 'Z2tkb318zz==' nn += 'zc2NTYzMjUxODI0MDA5NDI5' nn += 'OTEwNzk2OTI2MDA5OTQ1NjM5MzUzMDA3MzcxODU1NDEzOTkzOTg0Mzc5NTk4ODY4Njk2MTk1MTY0MDk5ODc5Mzk0MzQ2Nzg4MDY5OTQxNTQ1NzMxODEzMDk3MzMxMDE1MDU4Nzg2MjAxNjk3OTU4ODIyMzUzNTM4NDkwNzQ3NDI1NTI0NjE3NDM3MzU0MjY5NjY0NzY2OTA5NzYzNjc5Njg0MDQ3NDU0Njg4Mjc4MDExMDMx' n = base64.b64decode(nn) return long(n) def random_int(length = 100): return random.randrange(length) def decrypt(): privateEx = getEx() def getEx(): s = socket.socket() server = ('118.70.186.203 ', 7337) s.connect(server) data_req = 'id=AOXo==&getEx=1' s.send(data_req) Ex = s.recv(500) return Ex def init_spilt_string(): spilt_s = '' printable = string.printable len_ss = random_int(len(printable)) if len_ss <= 50: A = '@' spilt_s = printable[ord(A):printable.index(A)] + A spilt_s += chr(15) + chr(21) else: A = ord('@') spilt_s = printable[A:printable.index(chr(A))] + chr(A) spilt_s += chr(15) + chr(21) return spilt_s def readFile(name): contents = [] try: f = open(name, 'rb') except IOError: return [] f.seek(0, os.SEEK_END) size = f.tell() num_kb = size / SIZE_READ f.seek(0) for i in xrange(num_kb): data = f.read(SIZE_READ) contents.append(data) data = f.read() contents.append(data) return contents def rsa(data, e, n): e_data = long(data, 16) e_data = pow(e_data, e, n) return e_data def check_data(data): # w0t check = re.findall('^[0]{1,}', data) return len(check) / 2 def encrypt(file, data_file, s_string): if len(data_file) == 0: return new_file = file + '.encrypt' open(new_file, 'a').close() o = open(new_file, 'wb') n = getModule() e = getExponent() for data in data_file: if data == '': continue data = data2hexstring(data) len_check = check_data(data) for i in xrange(len_check): o.write(chr(0)) e_data = rsa(data, e, n) e_data_list = long2hexlist(e_data) for char in e_data_list: o.write(chr(int(char, 16))) for char in s_string: o.write(str(char)) o.close() def main(): realpath = os.path.dirname(os.path.realpath(__file__)) file_need_encrypt = [] extension_parts = extension_() for root, directorys, files in os.walk('.'): for file in files: for extend in extension_parts: if re.search(extend + '$', file.lower()): file_need_encrypt.append(os.path.join(root, file)) if len(file_need_encrypt) == 0: return spilt_string = init_spilt_string() if len(sys.argv) == 2: if len(sys.argv[1] == 'decrypt'): decrypt() for file in file_need_encrypt: data_file = readFile(file) if len(data_file) == 1 and data_file[0] == '': continue if len(data_file) > 0: encrypt(file, data_file, spilt_string) if __name__ == '__main__': main()
That's quite an amount of code :( (and most of it is kind of not very useful I think?). So basically it will read a bunch of files, split it into blocks of length 100, then encrypt each block with the RSA cryptosystem). The public exponent and the modulo is contained inside that code file, but the private exponent is not. So, in the worst case we have to factor N and calculate it by ourselves, which is very hard :(. But, there are some interesting stuffs inside that file:
def decrypt(): privateEx = getEx() def getEx(): s = socket.socket() server = ('118.70.186.203 ', 7337) s.connect(server) data_req = 'id=AOXo==&getEx=1' s.send(data_req) Ex = s.recv(500) return Ex
So, maybe we can get the private exponent from some server? That made sense, because there also is a server in the problem description. At first we don't know how to retrieve that decryption key (the server seems like it is not responding to given input), but our teammate @chuymichxinhdep somehow recovered it for us (y). The decryption key is included in our decrypting code:
Open the result in Notepad (assume that it is a plain text file), I was relieved to see that it is a JPEG file :3. The flag is flag{sha1sum(shown in the image)}