Web

flag-viewer

Challenge Description

https://flag-viewer.mc.ax/

We got a the following webpage and two files app.py,server.py

site

The most important part in the source code inapp.py is the following

1
2
3
4
5
6
7
8
9
@server.post('/flag')
async def flag(request):
data = await request.post()
user = data.get('user', '')

if user != 'admin':
return (302, '/?message=Only the "admin" user can see the flag!')

return (302, f'/?message={os.environ.get("FLAG", "flag missing!")}')

So basically if the username we enter is admin we should get the flag . Really! that’s so easy , let’s try. Oh turned out it is not that easy smh

site2

If we type another username we get the following message

1
Only the "admin" user can see the flag!

site3

It is time to try something else then . Let’s open Burp Suite, send a request and then see what happens behind the scenes

burp

In this case it is sending a post request with the parameter being user which contains the username we entered.

If you notice there is a redirection to another page let’s click that

web

We got redirected to another page which has a GET parameter message containing the message we saw before

1
/?message=Only+the+%22admin%22+user+can+see+the+flag!

web

Solution

If we go back to the previous request and change the username to admin from there would that work ? let’s try

web

Boom that worked , you can see the flag and the redirection to the page containing our flag. If we follow it we get what we came for 😀

web

Flag : hope{oops_client_side_validation_again}


inspect-me

Challenge Description

1
Just your average sanity check!

We got this webpage

web2

seems like it is a password checker. Let’s try to inspect the page

Oh! we got this message

web2

Then what about the page source . Looks like we can read it but some people said they couldn’t even right click to view the source code ( is that something related to the chrome version ? idk ). Anyways , when we read through the page source we notice this code right here

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
<script>(() => {
const scripts = document.querySelectorAll('script');
scripts.forEach((script) => script.remove());

const chr = (c) => c.charCodeAt(0);

const form = document.querySelector('form');
form.addEventListener('submit', (event) => {
event.preventDefault();
const input = document.querySelector('input[type="text"]');
const output = [];
for (const char of input.value.split('').map(chr)) {
if (chr('a') <= char && char <= chr('z')) {
output.push(chr('a') + ((char - chr('a') + 13) % 26));
} else if (chr('A') <= char && char <= chr('Z')) {
output.push(chr('A') + ((char - chr('A') + 13) % 26));
} else {
output.push(char);
}
}
const target = 'ubcr{pyvrag_fvqr_pyvpur}';
if (output.map((c) => String.fromCharCode(c)).join('') === target) {
document.querySelector('.content').textContent = 'Correct!';
} else {
input.removeAttribute('style');
input.offsetWidth;
input.style.animation = 'shake 0.25s';
}
});
})();
</script>

And what we are interested in is this line right here

1
const target = 'ubcr{pyvrag_fvqr_pyvpur}';

looks like it is a flag but it is rotated somehow. I threw it to CyberChef then tried rot13 and it worked!

web2

Now if we submit it in the password field and hit check we get the Correct! message

web2

web2

Flag : hope{client_side_cliche}


Reversing

Slices

Slices.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
flag = input('Enter flag: ')

def fail():
print('Wrong!')
exit(-1)

if len(flag) != 32: fail()

if flag[:5] != 'hope{': fail()
if flag[-1] != '}': fail()
if flag[5::3] != 'i0_tnl3a0': fail()
if flag[4::4] != '{0p0lsl': fail()
if flag[3::5] != 'e0y_3l': fail()
if flag[6::3] != '_vph_is_t': fail()
if flag[7::3] != 'ley0sc_l}': fail()

print('Congrats!')
print('flag is: ', flag)

I did it by hand lol

Solution

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
# test : hope{ABCDEFGHIJKLMNOPQRSTUVWXYZ}

# flag : hope{i_l0ve_pyth0n_slic3s_a_l0t}

# ABCDEFGHIJKLMNOPQRSTUVWXYZ
# i 0 _ t n l 3 a 0

# ABCDEFGHIJKLMNOPQRSTUVWXYZ
# p 0 l s l

# ABCDEFGHIJKLMNOPQRSTUVWXYZ
# 0 y _ 3 l

# ABCDEFGHIJKLMNOPQRSTUVWXYZ
# _ v p h _ i s _ t

# ABCDEFGHIJKLMNOPQRSTUVWXYZ
# l e y 0 s c _ l

### Equivalence

# ADGJMPSVY
# i0_tnl3a0

# {DHLPTX
# {0p0lsl

# eDINSX
# e0y_3l

# BEHKNQTWZ
# _vph_is_t

# CFILORUX}
# ley0sc_l}

### reference : https://onecompiler.com/python/3yas8dysd

Flag : hope{i_l0ve_pyth0n_slic3s_a_l0t}

Sequence

We got a binary and a server to connect to when getting things work locally.

I opened the binary in IDA and noticed this function called checker , it is the function that checks for our input if it is correct then the flag will be printed

rev

our input should be in this format %d %d %d %d %d %d so we need to find 6 numbers that are the solutions for this challenge

Solution

What we are interested in is this code right here

1
2
3
4
5
6
7
8
9
return 0LL;
if ( v2[0] != 12 )
return 0LL;
for ( i = 1; i <= 5; ++i )
{
if ( v2[i] != (3 * v2[i - 1] + 7) % 16 )
return 0LL;
}
return 1LL;

We have the value of v2[0] which is 12 so we can get the rest of the 5 values from v2[1] to v2[5] . I did this manually though

We have the general equation

1
v2[i] != (3 * v2[i - 1] + 7) % 16

If we want to calculate the value of v2[1] it will be

1
v2[1] != (3 * v2[0] + 7) % 16

and so on , until we get all the values.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
i = 1
v2[1] != (3 * v2[0] + 7) % 16
v2[1] = (3 * 12 + 7) % 16 = 11

i = 2
v2[2] != (3 * v2[1] + 7) % 16
v2[2] = (3 * 11 + 7) % 16 = 8

i = 3
v2[3] != (3 * v2[2] + 7) % 16
v2[3] = (3 * 8 + 7) % 16 = 15

i = 4
v2[4] != (3 * v2[3] + 7) % 16
v2[4] != (3 * 15 + 7) % 16 = 4

i = 5
v2[5] != (3 * v2[4] + 7) % 16
v2[5] != (3 * 4 + 7) % 16 = 3

sequence : 12 11 8 15 4 3

So our final sequence is

1
12 11 8 15 4 3

Let’s try it in the remote server. It worked!

rev

Flag : hope{definitely_solvable_with_angr}


Misc

orphan

Challenge Description

1
nothing to see here

We got a zip file that when we extract we get the following files

misc

There is a .git folder and a foo.txt file

misc

Usually when I work with .git folders I always use this tool https://github.com/internetwache/GitTools to extract the commits from the .git directory. For this challenge we gonna use the Extractor.sh script

misc

I made a folder called extract to save the extracted files there

misc

And right away we got a flag.txt file which contains our flag

misc

Flag : hope{ba9f11ecc3497d9993b933fdc2bd61e5


Crypto

obp

Challenge Description

1
The unbreakable One Byte Pad

encrypt.py

1
2
3
4
5
6
7
8
9
10
import random

with open('flag.txt', 'rb') as f:
plaintext = f.read()

key = random.randrange(256)
ciphertext = [key ^ byte for byte in plaintext]

with open('output.txt', 'w') as f:
f.write(bytes(ciphertext).hex())

output.txt

1
babda2b7a9bcbda68db38dbebda68dbdb48db9b7aba18dbfb6a2aaa7a3beb1a2bfb7b5a3a7afd8

This is a typical XOR challenge

Solve.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/env python3

def main():
ct = bytes.fromhex('babda2b7a9bcbda68db38dbebda68dbdb48db9b7aba18dbfb6a2aaa7a3beb1a2bfb7b5a3a7afd8')
for k in range(256):
pt = bytes(b ^ k for b in ct)

if b'hope' in pt:
print(f'Key: {k}')
print(f'Plain text: {pt.decode()}')
break

if __name__ == '__main__':
main()

crypto

Flag : hope{not_a_lot_of_keys_mdpxuqlcpmegqu}