Analysis of the RCTF2015 EasySQL1 Challenge

The challenge presents a web application with login and registration functionality. The objective is to retrieve the hidden flag from the database.

Initial Exploration

Upon accessing the application, we notice registration and login options. Attempting to register with the username "admin" reveals that the account already exists, suggesting the flag might be associated with this privileged account.

We then attempt to log in as "admin" with various password combinations, but without succsess. This leads us to explore the password reset functionality.

Discovering Vulnerabilities

During the password reset process, we observe that the application doesn't provide immediate feedback, indicating potential for blind SQL injection. The update mechanism apears vulnerable:

UPDATE users SET password='new_password' WHERE username='admin'

This suggests we can manipulate the username parameter to execute arbitrary SQL commands.

Identifying Filtered Keywords

Using a fuzzing dictionary, we test various SQL keywords to identify those that are blocked by the application's filters. We discover that common keywords like "AND" and spaces are filtered, but error-based injection functions like extractvalue and updatexml remain accessible.

Extracting Database Information

With error-based injection confirmed, we proceed to extract database information. First, we retrieve table names:

admin"||extractvalue(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where(table_schema)=database()),0x7e))#

This reveals three tables. We then check the columns of each table, starting with a table we suspect might contain the flag:

admin"||extractvalue(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name)='flag')))#

However, the flag isn't found in this table. We then examine the users table:

admin"||extractvalue(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name)='users')))#

Overcoming Length Limitasions

We discover a column named "real_flag_1s_here" in the users table, but the full name isn't displayed due to extractvalue's 32-character limit. To overcome this, we use the reverse() function:

admin"||extractvalue(1,concat(0x7e,reverse((select(group_concat(column_name))from(information_schema.columns)where(table_name)='users'))))#

This reveals the complete column name.

Retrieving the Flag

With the column name identified, we attempt to extract the flag. However, we encounter another length limitation. We use a regular expression to extract the flag in parts:

admin"||extractvalue(1,concat(0x7e,(select(real_flag_1s_here)from(users)where(real_flag_1s_here)regexp('^f'))))#

Again, we use the reverse() function to handle the length limitation:

admin"||extractvalue(1,concat(0x7e,reverse((select(real_flag_1s_here)from(users)where(real_flag_1s_here)regexp('^f')))))#

By combining the reversed output with the original, we reconstruct the complete flag: flag{c27daacc-20a6-43e4-8113-8faa8e8a96e0}.

Tags: SQL Injection Error-Based Injection RCTF CTF Web Security

Posted on Sat, 11 Jul 2026 17:19:58 +0000 by samtwilliams