James Cao
QnQSec CTF - s3cr3ct w3b Revenge

QnQSec CTF - s3cr3ct w3b revenge Writeup

Room / Challenge: s3cr3ct_w3b revenge (Web) Metadata Author: jameskaois CTF: QnQSec CTF 2025 Challenge: s3cr3ct_w3b revenge (web) Target / URL: http://161.97.155.116:8088/ Points: 50 Date: 20-10-2025 Goal We have to get the flag by leveraging XML viewer. My Solution Examine the source code, the source code is written in PHP however examine the Dockerfile, unlike s3cre3ct_web the DockerFile now is different: FROM php:8.2-apache RUN docker-php-ext-install pdo pdo_mysql RUN a2enmod rewrite COPY public/ /var/www/html/ RUN mkdir -p /var/flags && chown www-data:www-data /var/flags COPY flag.txt /var/flags/flag.txt WORKDIR /var/www/html/ EXPOSE 80 The flag.txt file is copied to /var/flags/flag.txt so we cannot access it like the s3cre3ct_web challenge anymore. ...

October 27, 2025 · 1 min
QnQSec CTF - s3cr3ct w3b

QnQSec CTF - s3cr3ct w3b Writeup

Room / Challenge: s3cr3ct_w3b (Web) Metadata Author: jameskaois CTF: QnQSec CTF 2025 Challenge: s3cr3ct_w3b (web) Target / URL: http://161.97.155.116:8081/ Points: 50 Date: 20-10-2025 Goal We have to get the flag by finding the secret. My Solution Examine the source code, the source code is written in PHP however examine the Dockerfile, we can find something really “secret”: FROM php:8.2-apache RUN docker-php-ext-install pdo pdo_mysql RUN a2enmod rewrite COPY public/ /var/www/html/ COPY includes/ /var/www/html/includes/ COPY flag.txt /var/www/html/ WORKDIR /var/www/html/ EXPOSE 80 The flag.txt file is copied to /var/www/html where it is normally served. So we can easily get the flag by visiting http://161.97.155.116:8081/flag.txt. ...

October 27, 2025 · 1 min
QnQSec CTF - QnQSec Portal

QnQSec CTF - QnQSec Portal Writeup

Room / Challenge: QnQSec Portal (Web) Metadata Author: jameskaois CTF: QnQSec CTF 2025 Challenge: QnQSec Portal (web) Target / URL: http://161.97.155.116:5001/ Points: 50 Date: 20-10-2025 Goal We have to get the flag by get access as admin. My Solution First we have to examine the app.py. There are some noticable routes: /login route: @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'GET': return render_template('login.html') username = (request.form.get('username') or '').strip() password = request.form.get('password') or '' if not username or not password: flash('Missing username or password', 'error') return render_template('login.html') db = get_db() row = db.execute( 'select username, password from users where username = lower(?) and password = ?', (username, md5(password.encode()).hexdigest()) ).fetchone() if row: session['user'] = username.title() role = "admin" if username.lower() == "flag" else "user" token = generate_jwt(session['user'],role,app.config['JWT_EXPIRES_MIN'],app.config['JWT_SECRET']) resp = make_response(redirect(url_for('account'))) resp.set_cookie("admin_jwt", token, httponly=False, samesite="Lax") return resp flash('Invalid username or password', 'error') return render_template('login.html') /account route: ...

October 27, 2025 · 4 min
QnQSec CTF - A Easy Web

QnQSec CTF - A Easy Web Writeup

Room / Challenge: A Easy Web (Web) Metadata Author: jameskaois CTF: QnQSec CTF 2025 Challenge: A Easy Web (web) Target / URL: http://161.97.155.116:5000/ Points: 50 Date: 20-10-2025 Goal We have to get the flag by guessing the UID to gain access as admin. My Solution This is an easy challenge however we need to do some guessing and hope for luck. The description of the challenge is: This is the web I mad for testing but I don’t know if there anything strange can you help me figure out? We need to find something strange in the website to leverage it and gain access as admin. Let’s visit the page: ...

October 27, 2025 · 2 min
DVWA XSS Stored

DVWA XSS Stored Low/Medium/High Security

Description Vulnerability: XSS (Stored) Impact: Leveraging XSS Scripting to get our desired data. LOW Security Level if( isset( $_POST[ 'btnSign' ] ) ) { // Get input $message = trim( $_POST[ 'mtxMessage' ] ); $name = trim( $_POST[ 'txtName' ] ); // Sanitize message input $message = stripslashes( $message ); $message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); // Sanitize name input $name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); // Update database $query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); //mysql_close(); } The app just INSERT the records to database with no checks ...

October 20, 2025 · 3 min
DVWA XSS Reflected

DVWA XSS Reflected Low/Medium/High Security

Description Vulnerability: XSS (Reflected) Impact: Leveraging XSS Scripting to get our desired data. LOW Security Level The source code doesn’t have any check: header ("X-XSS-Protection: 0"); // Is there any input? if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) { // Feedback for end user echo '<pre>Hello ' . $_GET[ 'name' ] . '</pre>'; } So similar to XSS (DOM) we can use simple payload <script>alert(document.cookie)</script> MEDIUM Security Level This source code has new check on <script>: header ("X-XSS-Protection: 0"); // Is there any input? if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) { // Get input $name = str_replace( '<script>', '', $_GET[ 'name' ] ); // Feedback for end user echo "<pre>Hello {$name}</pre>"; } So we can use the img trick: <img src=x onerror=alert(document.cookie)> ...

October 20, 2025 · 1 min
DVWA XSS DOM

DVWA XSS DOM Low/Medium/High Security

Description Vulnerability: XSS (DOM) Impact: Leveraging XSS Scripting to get our desired data. LOW Security Level This source code doesn’t have any checks: <?php # No protections, anything goes ?> And the choosing language functionality take the value and add them to the query param default on the URL: /vulnerabilities/xss_d/?default=<value>, the web app with take the <value> render them to the first option element: You can try type a Javascript code to get cookie of the browser: ?default=<script>alert(document.cookie)</script> ...

October 20, 2025 · 2 min
DVWA Weak Session IDs

DVWA Weak Session IDs Low/Medium/High Security

Description Vulnerability: Weak Session IDs Impact: Session IDs may be guessed to gain access as other accounts. LOW Security Level This level has really simple code: <?php $html = ""; if ($_SERVER['REQUEST_METHOD'] == "POST") { if (!isset ($_SESSION['last_session_id'])) { $_SESSION['last_session_id'] = 0; } $_SESSION['last_session_id']++; $cookie_value = $_SESSION['last_session_id']; setcookie("dvwaSession", $cookie_value); } ?> The dvwaSession cookie will simply increases 1 when we click the Generate button. MEDIUM Security Level This MEDIUM Security Level is also simple it take time() value which is the current Unix timestamp and set that to dvwaSession cookie value: ...

October 20, 2025 · 1 min
DVWA SQL Injection

DVWA SQL Injection Low/Medium/High Security

Description Vulnerability: SQL Injection Impact: Using vulnerability in SQL queries to get access to restricted data. LOW Security Level The source code doesn’t have any check on the input id it just pass the value to the query. We can easily use this payload to get tables list: ' UNION SELECT user, password FROM users # Source code doesn’t check anything: $query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';"; Result: ...

October 20, 2025 · 2 min
DVWA SQL Injection Blind

DVWA SQL Injection Blind Low/Medium/High Security

Description Vulnerability: SQL Blind Injection Impact: Levaraging SQL Blind Injection to get the data that we aren’t supposed to know. LOW Security Level The SQL Blind Injection is basically harder for us to retreive our desired data when comparing to normal SQL Injection. You can see this code from the source: $exists = false; if ($result !== false) { try { $exists = (mysqli_num_rows( $result ) > 0); } catch(Exception $e) { $exists = false; } } And whatever we give id param it just have 2 results: ...

October 20, 2025 · 3 min