#### I participated in the National CTF, and it was an absolute blast! The challenges were tough, and I found myself scratching my head at times, but that's what made it so exciting and enjoyable. I successfully conquered some of these mind-boggling puzzles, and now I'm eager to share my solutions with everyone. Let's delve into the thrill and adventure of the CTF! ![](https://hackmd.io/_uploads/Hywf7Qach.png) #### Also i won the first place ![](https://hackmd.io/_uploads/B1aX8Yach.png) ### Crypto ### ezrsa : 200 Points **Description:** We found the flag but it's been encrypted. We got the public key it was encrypted with, but we're missing the private key we are given : key0.enc , key1.enc , key2.enc , key3.enc , key.pub i started this crypto challenge by Downloading those encoded values and the public key ![](https://hackmd.io/_uploads/ryVxVtp93.png) As the public key were given to us i just decided to performed RSA attack using RSACTFTOOL to get the private key ➜ `CTF RsaCtfTool/RsaCtfTool.py --publickey key.pub --private` ![](https://hackmd.io/_uploads/HJKDStaqh.png) ``` Private key : -----BEGIN RSA PRIVATE KEY----- MIGpAgEAAiEAiuRQNYCzJoj2MkG+5l1A74vabCw2e5QXAHPwSDDtaSMCAwEAAQIg LtLVr5PZ0a3uwfakMulRUG4W7m5WCMEC5M90EyhA9iECEQCVlQ79oWv0KjWtB7gO HMwZAhEA7bQ+gioaCm94gZvZ2QdGmwIQJRNRJ+R+0YI007J6GGVi4QIQY0wFRLiz siJIs9PYGBo6+wIQTm8yG2O4wyQMX9rA9UcfcQ== -----END RSA PRIVATE KEY----- ``` Private key gotten , i save it and write a python script to find the value of p.q and d which is needed to decode the cipher text ```python #!/usr/bin/python3 #@author: manasse from Crypto.PublicKey import RSA #Sample private key string private_key_str = """-----BEGIN RSA PRIVATE KEY----- MIGpAgEAAiEAiuRQNYCzJoj2MkG+5l1A74vabCw2e5QXAHPwSDDtaSMCAwEAAQIg LtLVr5PZ0a3uwfakMulRUG4W7m5WCMEC5M90EyhA9iECEQCVlQ79oWv0KjWtB7gO HMwZAhEA7bQ+gioaCm94gZvZ2QdGmwIQJRNRJ+R+0YI007J6GGVi4QIQY0wFRLiz siJIs9PYGBo6+wIQTm8yG2O4wyQMX9rA9UcfcQ== -----END RSA PRIVATE KEY-----""" #Save the private key to a file with open('priv.key', 'w') as f: f.write(private_key_str) #Read the private key from the file and import it private_key = open('priv.key', "rb").read() key = RSA.importKey(private_key) #Print the representation of the key print(repr(key)) ``` i successfully got the script executed and got the values of p & q and d as well ![](https://hackmd.io/_uploads/BkN9atpc2.png) ``` n=62822567817398821412634307651976037645064332193891475950277853356969488640291 e=65537 d=21178903723966760155190844763458177452716443299090469143032403667752371418657 p=198828927652291316291569791180652465177 q=315962916257647735873011221555688457883 u=150285859421016194683682063130352799393 ``` Since i was able to get the both the prime numbers (p & q) and the private exponent (d) i was able decode the cipher text and solve the challenge using python script :100: here we go ```python #!/usr/bin/python3 #@author: manasse from Crypto.Util.number import bytes_to_long, long_to_bytes p = 198828927652291316291569791180652465177 q = 315962916257647735873011221555688457883 N = p * q d = 21178903723966760155190844763458177452716443299090469143032403667752371418657 # Convert key0.enc to hex using cyberchef key0 = bytes.fromhex('0e48d8a6371ca3888f2b8514be91dba5e7ce3b5428c73ef1493f79530cb348be') enc0 = bytes_to_long(key0) key1 = bytes.fromhex('5e1c7116f70832d547a734d600715bc677201bb6acf233c12af64f7107134d2b') enc1 = bytes_to_long(key1) key2 = bytes.fromhex('0b03a010e0eb7de447f00a215ee4b5d3251e686dd8b4c4113a5a8161e9fde703') enc2 = bytes_to_long(key2) key3 = bytes.fromhex('34d14a15a86607da5d16faa5c3ba7224b440edf6c363401d1fa580fe614e1f72') enc3 = bytes_to_long(key3) decoded = [] decoded.append(pow(enc0, d, N)) decoded.append(pow(enc1, d, N)) decoded.append(pow(enc2, d, N)) decoded.append(pow(enc3, d, N)) flag = '' for i in decoded: flag += long_to_bytes(i).decode() print(flag) ``` i got the script executed as well and the got the flag :accept: ![](https://hackmd.io/_uploads/rJ1pQ9p9n.png) `flag{43bc9aaf8b315435c2459fcb5aaf710a683a917294130b64413f3814465aaf30ffb84a3e86dcf904b2da35352322fa10fccb3e70b6d6b20efb3dc756e5}` -------------------------------- ## Xor1 : 100 points **Description**: An XOR or eXclusive OR is a bitwise operation indicated by ^.See if you can find the right byte to translate these base64 encoded bytes IConIT0+KTQZNjMyNRkyLiMZIDMoGS8oGSAzKCInKyMoMicqOw== into a flag. this was xor1 challenge i solved it by two approach using https://icyberchef.com and the second way using python script to bruteforce ### fisrt approach i used CyberChef to perform XOR decryption with brute force on data that has been Base64 encoded and got the key and the flag as well https://icyberchef.com/#recipe=From_Base64('A-Za-z0-9%2B/%3D',true,false)XOR_Brute_Force(1,100,0,'Standard',false,true,false,'')&input=SUNvbklUMCtLVFFaTmpNeU5Sa3lMaU1aSURNb0dTOG9HU0F6S0NJbkt5TW9NaWNxT3c9PQ ![](https://hackmd.io/_uploads/rkxCHpa9n.png) ### second approach i wrote a python script that perform the brutefore to get the flag ```python #!/usr/bin/python3 #@author: manasse from base64 import b64decode as decode enc_string = 'IConIT0+KTQZNjMyNRkyLiMZIDMoGS8oGSAzKCInKyMoMicqOw==' dec_string = decode(enc_string).decode('utf-8') decimal = [ord(c) for c in dec_string] try: for key in range(0xff + 1): dec = ''.join(chr(i ^ key) for i in decimal) if dec.startswith('flag'): print(f'Key: {key}\nFlag: {dec}') break else: print('Flag not found.') except Exception as e: print(e) ``` ![](https://hackmd.io/_uploads/SkBW5Tp5n.png) i got the flag after execution ``` Key: 70 Flag: flag{xor_puts_the_fun_in_fundamental} ``` ------------------------ ## Xor2 : 100 points **Description**: The flag is formatted normally with the flag{...} format. Use this to your advantage when cracking the 7 character key and decrypting the flag. IAUPA1sVCjQ2HhFUHjoyAQs7UBgLGQAAO1AYCxkLDxdFCTogBQ8DXQ== We are given the encrypted flag which is xored with a key of length 7 and then base64 encoded From this point i know that the plaintext of the flag is `flag{` . let do this quick reminder about the commutative property of xor :100: ``` a ^ b = c: When you XOR two values, a and b, the result is a new value, c. XORing c with either a or b again will return the value of the other operand. This is because XOR is a reversible operation, and applying it twice will effectively cancel itself out, resulting in the original value. a ^ c = b: If you XOR a with c (the result of a ^ b), the output will be the original value of b. This is because a ^ b ^ a = b, where a ^ b results in c, and then c ^ a (which is equivalent to a ^ c) results in b. b ^ c = a: Similarly, if you XOR b with c (the result of a ^ b), the output will be the original value of a. This is because b ^ a ^ b = a, where b ^ a results in c, and then c ^ b (which is equivalent to b ^ c) results in a. ``` Back to the challenge i come to got the first 5 part of the flag by xoring the base64 decoded value with `flag{` and for the purpose i used python pwn module to do that on my terminal ``` ➜ CTF python3 Python 3.11.4 (main, Jun 7 2023, 10:13:09) [GCC 12.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> from pwn import xor >>> from base64 import b64decode as decode >>> enc = decode('IAUPA1sVCjQ2HhFUHjoyAQs7UBgLGQAAO1AYCxkLDxdFCTogBQ8DXQ==') >>> plaintext = 'flag{' >>> xored = xor(enc, plaintext) /usr/local/lib/python3.11/dist-packages/pwnlib/util/fiddling.py:327: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes strs = [packing.flat(s, word_size = 8, sign = False, endianness = 'little') for s in args] >>> print(xored) b'Find sfUQew8\x7f]IggZ7cmuag@6tj~pi{$nAFind&' >>> ``` ![](https://hackmd.io/_uploads/B18fICa52.png) i got `Find` as well but It might be hard to notice but there's actually a space character after letter `d` so at this point the key known , the key is 5 characters and i though about easily brute force the remaining two characters my python script to that solve the challenge :1234: bimm ````python #!/usr/bin/python3 # @author: manasse from base64 import b64decode as decode from pwn import xor def combination(): for a in range(32, 127): for b in range(32, 127): yield f"{chr(a)}{chr(b)}" enc_string = decode('IAUPA1sVCjQ2HhFUHjoyAQs7UBgLGQAAO1AYCxkLDxdFCTogBQ8DXQ==') known_key = b'Find ' for char_ in combination(): try: key = known_key + char_.encode('utf-8') print(f'Trying key: {key}') decoded = xor(key, enc_string) print(decoded.decode('utf-8')) except Exception as e: print(e) ```` BOOM After execution i got the flag with the key` Find me` ![](https://hackmd.io/_uploads/SyEj710c2.png) To confirmed that i used also cyberchef ![](https://hackmd.io/_uploads/B10eH1Rqh.png) we good hehe `flag{xor_puts_the_pun_in_pun_based_flag}` ----------------------------------------- # Reverse ### Bye-byte : 100 points **Description** : Can you recover the flag from this .NET binary? we're given a Binary : `Bye-byte.exe` started opening the Program on Cutter to start look at the function main , enc , dec and strings . After somes analysis i realised the program related to sort of bitwise XOR and i found on stringdump some strings from differents memory addresses.there was a strings that was encoded in base64 and i noticed program is initialising an interaction with the user to asking this : `Send me 4 characters and i can decrypt something for you...` and it prompt an exit message or a goodbye message ![](https://hackmd.io/_uploads/H1MTk3mon.png) for futher analysis i identified these strings on the main code using cutter Advanced strings indentification fonctionality ![](https://hackmd.io/_uploads/BkURVnXih.png) so after some quiet moment of code analysis of the main , enc , dec functions i realised that it's simple base64+XOR and i decided to write python script to bruteforce to get the key of 4 characters and the flag as well my python script :100: ```pyth #!/usr/bin/python3 @author: manasse import base64 def xor_decrypt(data, key): result = bytearray() for i in range(len(data)): result.append(data[i] ^ key[i % len(key)]) return bytes(result) def bruteforce_decrypt(ciphertext): possible_keys = [ord(char) for char in "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"] for key1 in possible_keys: for key2 in possible_keys: for key3 in possible_keys: for key4 in possible_keys: key = bytes([key1, key2, key3, key4]) decrypted = xor_decrypt(ciphertext, key) print(f"Key: {chr(key1)}{chr(key2)}{chr(key3)}{chr(key4)}, Decrypted message: {decrypted}") if __name__ == "__main__": # Base64 encoded ciphertext provided base64_ciphertext = "PD1VICE4WRgpOVU1KjRGGC45VSkFKFsyBSVcLjQ6SQ==" ciphertext = base64.b64decode(base64_ciphertext) bruteforce_decrypt(ciphertext) ``` the script got executed successfully after running and grep it as well ➜ CTF `python3 bruteforce.py | grep flag{` `Key: ZQ4G, Decrypted message: b'flag{im_sharper_than_you_think}'` ![](https://hackmd.io/_uploads/HJhhBgEs3.png) i got the `Key: ZQ4G`, and the `flag{im_sharper_than_you_think}` ----------------- ### lab32 : 100 points **Description**: 32 bit binary bomb lab! :) nc 0.cloud.chals.io 29115 we're given a binary : `lab32` This reverse challenge was quiet weird and simple at the same time. let go :100: i started opening the file in ghidra , main function shows there are three checks to be passed! and if you fail any explode function is called which basically quits the program with a try harder message ![](https://hackmd.io/_uploads/H1qX1R5s2.png) ### Phase1 On phase1 function we get a loop that is basically comparing each character of our input with another character of a hardcoded string! If any of the characters don't match explode function is called as weell. To be able to pass this check we need to supply that exact string... ![](https://hackmd.io/_uploads/r1h3105oh.png) ### Phase2 The phase2 is doing alot of job , trying to understand the decompiled code proved to be tiresome, but the code helps in that we know the input we give should be equal to that hardcoded value! ![](https://hackmd.io/_uploads/H1htlCci2.png) one of the best way to be able to know that is to enumerate the right input to give is using dynamic analysis, we are suppossed to enter 4 numbers , since we dont have a bruteforce script we can enter the same number 4 times and check if the resultant value is close the hardcoded value. eg 500 gives 2040000 which is slightly higher than the required value ![](https://hackmd.io/_uploads/BkoBMCqin.png) ```c (gdb) disass phase2 Dump of assembler code for function phase2: 0x00000a04 <+0>: push ebp 0x00000a05 <+1>: mov ebp,esp 0x00000a07 <+3>: push ebx 0x00000a08 <+4>: sub esp,0x34 0x00000a0b <+7>: call 0x700 <__x86.get_pc_thunk.bx> 0x00000a10 <+12>: add ebx,0x2590 0x00000a16 <+18>: mov eax,gs:0x14 0x00000a1c <+24>: mov DWORD PTR [ebp-0xc],eax 0x00000a1f <+27>: xor eax,eax 0x00000a21 <+29>: sub esp,0xc 0x00000a24 <+32>: lea eax,[ebx-0x20a2] 0x00000a2a <+38>: push eax 0x00000a2b <+39>: call 0x640 <puts@plt> 0x00000a30 <+44>: add esp,0x10 0x00000a33 <+47>: mov DWORD PTR [ebp-0x34],0x0 0x00000a3a <+54>: jmp 0xa4e <phase2+74> 0x00000a3c <+56>: call 0x8cd <get_number> 0x00000a41 <+61>: mov edx,eax 0x00000a43 <+63>: mov eax,DWORD PTR [ebp-0x34] 0x00000a46 <+66>: mov DWORD PTR [ebp+eax*4-0x1c],edx 0x00000a4a <+70>: add DWORD PTR [ebp-0x34],0x1 0x00000a4e <+74>: cmp DWORD PTR [ebp-0x34],0x3 0x00000a52 <+78>: jle 0xa3c <phase2+56> 0x00000a54 <+80>: mov DWORD PTR [ebp-0x30],0x0 0x00000a5b <+87>: mov DWORD PTR [ebp-0x2c],0x0 0x00000a62 <+94>: jmp 0xab5 <phase2+177> 0x00000a64 <+96>: mov eax,DWORD PTR [ebp-0x2c] 0x00000a67 <+99>: mov eax,DWORD PTR [ebp+eax*4-0x1c] 0x00000a6b <+103>: mov DWORD PTR [ebp-0x20],eax 0x00000a6e <+106>: mov DWORD PTR [ebp-0x28],0x0 0x00000a75 <+113>: jmp 0xaab <phase2+167> 0x00000a77 <+115>: mov DWORD PTR [ebp-0x24],0x0 0x00000a7e <+122>: jmp 0xaa1 <phase2+157> 0x00000a80 <+124>: mov eax,DWORD PTR [ebp-0x28] 0x00000a83 <+127>: lea edx,[eax*4+0x0] 0x00000a8a <+134>: mov eax,DWORD PTR [ebp-0x24] 0x00000a8d <+137>: add eax,edx 0x00000a8f <+139>: mov eax,DWORD PTR [ebx+eax*4+0x80] 0x00000a96 <+146>: imul eax,DWORD PTR [ebp-0x20] 0x00000a9a <+150>: add DWORD PTR [ebp-0x30],eax 0x00000a9d <+153>: add DWORD PTR [ebp-0x24],0x1 0x00000aa1 <+157>: cmp DWORD PTR [ebp-0x24],0x3 0x00000aa5 <+161>: jle 0xa80 <phase2+124> 0x00000aa7 <+163>: add DWORD PTR [ebp-0x28],0x1 0x00000aab <+167>: cmp DWORD PTR [ebp-0x28],0x3 0x00000aaf <+171>: jle 0xa77 <phase2+115> 0x00000ab1 <+173>: add DWORD PTR [ebp-0x2c],0x1 0x00000ab5 <+177>: cmp DWORD PTR [ebp-0x2c],0x3 0x00000ab9 <+181>: jle 0xa64 <phase2+96> 0x00000abb <+183>: cmp DWORD PTR [ebp-0x30],0x1cc320 0x00000ac2 <+190>: je 0xac9 <phase2+197> 0x00000ac4 <+192>: call 0x92d <explode> 0x00000ac9 <+197>: mov eax,0x1 0x00000ace <+202>: mov ecx,DWORD PTR [ebp-0xc] 0x00000ad1 <+205>: xor ecx,DWORD PTR gs:0x14 0x00000ad8 <+212>: je 0xadf <phase2+219> 0x00000ada <+214>: call 0xe30 <__stack_chk_fail_local> 0x00000adf <+219>: mov ebx,DWORD PTR [ebp-0x4] 0x00000ae2 <+222>: leave 0x00000ae3 <+223>: ret End of assembler dump. (gdb) b *phase2+183 Breakpoint 1 at 0xabb (gdb) r Starting program: /tmp/haha/lab32 [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Are u ready for a bomb lab? smLet's begin!! Phase 1 Begin!!! slimelove Better luck next time ... [Inferior 1 (process 41038) exited with code 0255] (gdb) r Starting program: /tmp/haha/lab32 [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Are u ready for a bomb lab? Let's begin!! Phase 1 Begin!!! slimelove Better luck next time ... [Inferior 1 (process 41090) exited with code 0255] (gdb) r Starting program: /tmp/haha/lab32 [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Are u ready for a bomb lab? slime lovLet's begin!! Phase 1 Begin!!! e passed phase1 Alright! Here is phase 2:) 500 500 500 500 Breakpoint 1, 0x56555abb in phase2 () (gdb) x $ebp-0x30 0xffffcf28: 0x001f20c0 (gdb) p 0x001f20c0 $1 = 2040000 (gdb) p 0x1cc320 $2 = 1884960 (gdb) ``` we can keep reducing the value till we get the right one :100: ### Phase3 The phase 3 creates some kind of linked list and calls the validate function like this ![](https://hackmd.io/_uploads/S1wxSR5jh.png) let's digging. this the validate function . In order to pass this phase we need to enter the ascii characters in their decimal equivalent, in the way that the node is followed very simple and to guesstable 😂 ![](https://hackmd.io/_uploads/H1xFH05s2.png) This is kind of linked list and it checks for node 42 which is the first one and checks if it holds character A , which i believe is 42 in decimal it continues like that till the end . the second it checks if node 27 holds letter K and so on , here the concept is simple you just need to understand the logic behind linked lists , one value points to the other , the other to another etc . so just you start with 42 which is already defined and enter the rest as well , very simple . To make easy `Uvar2` is the node created with first value as 42 and then now from 42 you go to 65 and like that to 35. piece of cake 🎂 just like this : ``` 1st => 65 2nd => 27 3rd => 75 4th => 57 5th => 12 6th => 35 ``` All that work good and as final result we got like : #### phase 1 `slime love` #### phase 2 `462` #### phase 3 ``` 1st => 65 2nd => 27 3rd => 75 4th => 57 5th => 12 6th => 35 ``` it work properly hehe then run it now : ![](https://hackmd.io/_uploads/Bk1OnR5s2.jpg) ``` ➜ CTF nc 0.cloud.chals.io 29115 _ _ _________ | | __ | |__|__ /___ \ | |/ ` | ' \ |_ \ __) | | | (_| | |_) |__) / __/ |_|\__,_|_.__/____/_____| ************************** Are u ready for a bomb lab? Let's begin!! Phase 1 Begin!!! slime love passed phase1 Alright! Here is phase 2:) 462 462 462 462 passed phase2 Welcome to phase3!! 65 27 75 57 12 35 passed phase3 flag{32B1t_b0mB_l48_compl3te} ``` FLAG : ```flag{32B1t_b0mB_l48_compl3te}```