Writeup Intigriti challenge-0923
Tags: writeup Created time: September 27, 2023 6:48 PM Created time 1: September 27, 2023 6:48 PM
This is an interesting challenge, so I want to write in detail and analyze the process I followed, as well as provide a clear explanation of the issues I encountered when approaching this challenge.
Overview
The challenge interface looks like this:
We have full access to the source code in path
challenge.php?showsource=1
, so this is a whitebox challenge. Let's read and analyze it together
Quick explanation of the code snippet above.
The code checks if a GET parameter named
**max
** is present in the URL and if it meets certain criteria. It ensures that**max
** is not an array and that its value is greater than 0 โ So it must be a number.An array named
$words
is defined, which contains a list of characters to check for in the**max
** parameter. This list includes various characters that are often associated with security vulnerabilities when handling user input.The code then iterates through each character in the
$words
array using aforeach
loop. Inside the loop, it uses a regular expression (preg_match
) to check if the character exists in the**max
** parameter. If any of these characters are found in the**max
** parameter, it exits the script with the message "H4ckerzzzz." โ yeah we have to bypass thisAfter validating the
**max
** parameter, the code attempts to execute a database query. It uses theprepare
method to create a prepared statement with a SQL query that selects**id
,name
** and**email
** from a**users
** table where**id
** is less than or equal to the value of$max
.The prepared statement is executed using the
execute
method, and the results are fetched into the$results
variable usingfetchAll
.
So the first question is How we can bypass that blacklist and trigger SQLi?
At first, I tried many different approaches, but I was limited by characters like
'
,"
,;
,,
which are necessary for SQLiWhen using only
'
, I got some information, but it's essentially because the value ofmax
needs to be a number to satisfy the condition$_GET['max']>0
, and of course, I got blocked.After a day of searching and researching, I observed that what was necessary at this point was the ability to perform a UNION, and what we needed most was to bypass spaces.
Of course, none of common payload like (//), %09, %0D, %0Aโฆ.** were effective as they are all blacklisted characters.
Play around and printing out all the special characters that weren't filtered, I noticed something interesting: parentheses
()
weren't filtered.With this characters, we can immediately execute the UNION query. However, we need to consider the initial value of the
max
variable, which should be a number to satisfy the condition$_GET['max']>0
. So, I used1*(1)union(select(1),(2),(3))
because the character*
is not blocked**.** Of course, it's easy to recognize that this is MySQL.
Now, we encountered the second issue: How to query the value of the password?
At this point, despite my efforts, I was stuck until I received the first hint from INTIGRITI.
I searched around Google and found this article. It turned out to be the way to Bypass Column Names Restriction exactly. In essence, it goes like this:
MySQL supports aliases, which are used to give a table or a column in a table a temporary name. Aliases are often used to make column names more readable or to provide a shorter name for a table or column when writing SQL queries
An alias is created with the
**AS
** keyword, which violates the blacklist. However, an interesting point is that we can still create aliases without using the**AS**
keyword, as follows:
One great feature of aliases is that they allow us to directly query a column using the column's name within the alias. For example, if we have a column named
**column_name
** in a table called**alias
โ** we can query it using the syntax**alias.column_name**
And when we use the query
select 1, 2, 3, 4 union select * from users
, we're actually assigning names to 4 columns, virtual names being 1, 2, 3, and 4. After the union with the**users
** table, we can query the values of the**password
** column through without explicitly referencing the**password
** keyword.
This query means I am querying the value of the fourth column in the newly created table F (at this point, table F includes 4 columns: id, name, email, password from the users table and the values 1, 2, 3, 4 correspondingly).
So, returning to the challenge, after combining the above idea of bypassing spaces using parentheses, we get the following payload:
And got the flagโฆ.
At this point, I thought it was all done, but I only received the string REDACTED ??
From this piece of code, we can understand that when displaying the value of a row, if there's the term **
INTIGRITI
**it ****will immediately be replaced with**REDACTED**
. However, as we know, the flag format is INTIGRITI{..}. So, we are confident that we're on the right track, and this is the final step.
So, the final question is: How can we display the flag without including the string INTIGRITI?
Here, I searched and listed all the functions in MySQL that don't include keywords from the blacklist. Some of the functions that caught my attention were LEFT, MID, and LOWER.
With LEFT and MID: I realized that with
LEFT(F.4,8)
, I can see the beginning of the flag content, which isINTIGRIT
, because printing the entireINTIGRITI
would be blocked. So, I combined it with MID to display the content.
like this
So when combine with the function MID, we got the flag
Observe this more clearly in the browser
Flag: INTIGRITI{bl4ckli5t1ng_1z_n0t_7h3_w4y}
Another faster way is to use
LOWER
since it only checks for the**INTEGRITI
** substring. So, simply displaying it without this substring on the screen is sufficient. That's right, usingLOWER
to convert all characters in the flag to lowercase, including the**intergriti
** substring.
However, one noteworthy point here is that in cases where the flag contains a mixture of uppercase and lowercase characters like
INTIGRITI{BL4CKli5t1ng_1z_n0t_7h3_W4Y}
, using LOWER() might not be the best idea. But, for this specific case, it works quite well.
Conclusion:
This is a very interesting challenge. I have learned a new way to use aliases to bypass blacklists and perform SQL injection queries without using column names.
#END
Thank you for reading ๐.
If you have any feedback, you can contact me through the following channels.
Giongfnef
Last updated