Description
The Local Authority portal hides its credentials inside ancillary JavaScript. Browse the secondary login file to enumerate referenced assets and recover the cleartext username/password pair.
Setup
View the page source; it references a POST to login.php even though that file isn't linked anywhere.
Manually browse to /login.php to load the script includes, then inspect secure.js for hard-coded credentials.
Return to the original page and sign in with the recovered username/password to reach admin.php.
Solution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1
Enumerate hidden assetsObservationI noticed the main page's HTML form action pointed to login.php even though that file was not linked anywhere, which suggested navigating directly to login.php to trigger its script includes and discover additional referenced assets like secure.js.Open login.php directly (e.g., http://saturn.picoctf.net:64710/login.php). The browser now lists secure.js among the sources.What didn't work first
Tried: Right-clicking the main page and selecting 'View Page Source' to look for hidden files.
View Source shows the raw HTML of the main page, which does reveal the login.php form action but does not load login.php or any of its own script includes. You need to actually navigate your browser to login.php so it makes a fresh HTTP request and the browser parses that page's script tags, pulling in secure.js.
Tried: Checking the Network tab in DevTools on the main page to find secure.js.
The Network tab only captures requests made while that tab is open for the current page. Since secure.js is only loaded by login.php, you will not see it until you navigate to login.php. Open DevTools before navigating to login.php and watch the Network tab fill in as the page loads.
Learn more
Asset enumeration is the process of discovering resources on a web server that aren't explicitly linked from the main page. Common techniques include reading the page source for referenced URLs, checking
robots.txtandsitemap.xml, and using directory brute-forcing tools like gobuster or dirsearch to probe for common filenames.Here, the form action attribute in the main page's HTML points to
login.php, which is enough of a breadcrumb. Manually navigating to that URL loads it in the browser, which in turn causes the browser to request all scripts and stylesheets referenced bylogin.php- includingsecure.js. This is a reliable way to discover secondary resources: follow every link, form action, and script reference you find.In real web application testing, this reconnaissance phase is critical. Tools like Burp Suite's Spider, OWASP ZAP's crawler, or
wget --mirrorcan automate the discovery of linked resources across an entire site.Step 2
Read secure.jsObservationI noticed a file named secure.js was loaded by login.php, and the suggestive name combined with the challenge's theme of client-side credential storage pointed directly to reading its contents for a hardcoded username and password.secure.js contains a validation function that checksusername === 'admin'andpassword === 'strongPassword098765'(or declares them as constants). Use these credentials on the main login form.What didn't work first
Tried: Looking for credentials in the Console tab by typing 'password' or 'username' to search for variables.
The Console only shows logged output and lets you evaluate expressions; it does not surface all declared variables unless you know their exact name. The reliable approach is to open the Sources tab (or Network tab response preview), navigate to secure.js, and read the full file. Once you know the variable names from reading the source, you can confirm them in the Console.
Tried: Trying common passwords like 'admin', 'password', or '123456' on the login form before checking the JS file.
Guessing credentials is unreliable and slow - there are thousands of common passwords. The challenge explicitly stores the password in a JavaScript file served to the browser. Reading secure.js gives you the exact string in seconds without any guessing.
Learn more
Storing credentials in client-side JavaScript is a severe security vulnerability. The entire purpose of authentication is to distinguish authorized users from unauthorized ones - but if the password is in the JavaScript file that every visitor's browser downloads, any visitor can read it. This type of vulnerability is so common that browsers' built-in developer tools are sufficient to exploit it: no specialized tools required.
A "secure" filename for a JavaScript file containing cleartext credentials is ironic, but this naming pattern (trying to obscure the purpose through the filename) is a form of security through obscurity - it provides no actual protection. The real fix is to perform authentication server-side: the server compares submitted credentials against a hashed value in a database, and the client never sees the reference value.
This pattern also illustrates why Single Page Applications (SPAs) that implement authentication logic in JavaScript are inherently limited: you can gate the UI, but you can never gate the data if the same JavaScript file is accessible to all users.
Step 3
Retrieve the flagObservationI noticed secure.js exposed the exact plaintext credentials used by the server-side login check, which meant submitting those credentials to the login form at login.php would authenticate successfully and redirect to admin.php where the flag is displayed.Successful authentication redirects to admin.php, which prints the picoCTF flag in plain text. Once you're inside, probe sibling routes -/admin.php,/debug.php,/users.php,/settings.php- to see what other surfaces the same auth check unlocked. Real-world admin panels almost always expose more than the one page you're sent to.What didn't work first
Tried: Entering the credentials on the original challenge homepage instead of login.php.
The main page may not have a login form - the form lives at login.php. Submitting credentials to the wrong endpoint either produces an error or does nothing. Navigate to login.php, fill in the username and password fields there, and submit.
Learn more
Once you have the credentials from
secure.js, logging in is straightforward. The server-side authentication check validates the submitted credentials and, if they match, grants access to the admin page. Even though the validation happens server-side, the credentials were exposed client-side - making the server-side check irrelevant from a security standpoint.This challenge models a real attack pattern: credential harvesting from client-side code. Security researchers regularly find API keys, database passwords, and auth tokens embedded in JavaScript bundles shipped to browsers. Tools like truffleHog and gitleaks scan codebases for such accidental exposures, and browser extensions like DotGit look for exposed
.gitdirectories that might reveal source code and embedded secrets. The post Web challenges: real-world bug patterns collects the rest of this family - hidden form fields, JS-side auth checks, exposed admin routes.
Interactive tools
- Strings ExtractorPull printable text from any binary, library, or image. ASCII and UTF-16 detection, configurable minimum length, flag-like highlight, no command line needed.
Flag
Reveal flag
picoCTF{j5_15_7r4n5p4r3n7_b0c...}
Because the credentials live in front-end JavaScript, simply browsing to the referenced file is enough.