I am testing out a blind boolean SQL injection endpoint in a course and am having some issues figuring out where my payload is going wrong.
I have tested the below in the mysql shell on the target box and it works.
GRANT/**/ALL/**/ON/**/*.*/**/TO/**/root#localhost;
But when I submit it in the q GET param I am getting an error in the application.
php?q=off')/**/or/**/GRANT/**/ALL/**/ON/**/*.*/**/TO/**/root#localhost%23
I tested a basic boolean statement with '1'='1' instead and it works fine so I am assuming there is something wrong with my actual query in the context of the URL.
q=off')/**/or/**/'1'='1'%23
I have tried the payload url encoded as well but still with the same issues.
Any idea what might be causing this?
Using SQL injection to combine a partial expression like
OR '1'='1' as part of some other query works because there are many ways to append extra expression syntax to an existing SQL query that already has a WHERE clause.
For example, it's easy to see in the below example how the additional expression can be appended to the first query, and it's still a legal expression.
SELECT * FROM mytable WHERE col1 = 'off'
SELECT * FROM mytable WHERE col1 = 'off' OR '1'='1' -- '
But GRANT is a statement on its own. It cannot be appended to another query like that. There's no way to combine GRANT with a SELECT statement.
SELECT * FROM mytable WHERE col1 = 'off' OR GRANT ALL ON *.* TO ...
That's just not a legal SQL query. You can study the online syntax reference for SELECT and other types of statements.
SQL injection works by tricking the app into executing one SQL statement with different syntax than the original intended SQL statement. But it can't make invalid syntax work!
Related
I get the error "IF" is not valid in this position. as soon as I enter an IF in WorkBench. Anyone who knows why? Never get a chance to test this query.
USE arter;
IF (SELECT lokNavn FROM lokalitet WHERE lokNavn='Lodviken') IS NULL THEN
SELECT 1 ELSE SELECT 2 END IF
IF statements can only be used in procedures, not regular queries.
You can use the IF() function or a CASE expression.
SELECT IF(EXISTS(SELECT lokNavn FROM lokalitet WHERE lokNavn='Lodviken')), 1, 2)
I am trying to accomplish a simple licensing system in golang and have tried numerous ways to get it to work. Basically, I have input a couple of random licensing keys into my database and my golang program should check to see if the user-input key exists and if it does then add the user specified username and password into the database to login later.
This is the code that I have that hasn't been working:
"IF EXISTS (SELECT * FROM login WHERE LK = "+reglicenceEntry.Text()+") THEN
INSERT INTO `login` (`Username`, `Password`, `LK`) VALUES
('"+regusernameEntry.Text()+"', '"+regpasswordEntry.Text()+"', ''); "
This is the golang error:
Error 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'IF EXISTS (SELECT * FROM login WHERE LK = '5qp515YHXEmSDzwqgoJh') THEN INSERT IN' at line 1
Thanks so much!
MySQL syntax doesn't support IF...THEN constructs except within stored routines and triggers and events. See https://dev.mysql.com/doc/refman/8.0/en/sql-syntax-compound-statements.html
I suggest an alternative solution for your code:
INSERT INTO `login` (`Username`, `Password`, `LK`)
SELECT ?, ?, ''
FROM `login`
WHERE `LK` = ?
LIMIT 1
If your login table does not have the LK value, the SELECT above will return 0 rows, therefore it will not insert anything.
If your login table has the LK value, the SELECT above will return at least 1 row (and I limit it to 1), therefore it will insert a row. The row it inserts is comprised of your username and password, and a blank string for the LK.
I showed use of parameter placeholders. You should use parameters in SQL instead of concatenating variables into your query. This is good practice to avoid accidental SQL injection. See http://go-database-sql.org/prepared.html for examples.
The purpose of using parameters is to avoid SQL injection problems. See my answer to What is SQL injection? for an explanation of SQL injection.
Or my presentation SQL Injection Myths and Fallacies (or youtube video).
When using parameters, you do two steps.
The first step to prepare a query with placeholders (?) where you would otherwise concatenate variables into your SQL query.
The second step is to execute the prepared query, and this is the time you pass the variables to fill in the placeholders.
The point is to keep variables separate from your query, so if there's anything in the variable that could unintentionally change your SQL syntax (like imbalanced quotes), it is never combined with the SQL. After you do the prepare, the SQL has already been parsed by the MySQL server, and there's no way to change the syntax after that.
MySQL remembers which parts of the query need to be filled in, and when you pass variables during the execute step, MySQL fills in the missing parts of the query using your values — but this happens within the MySQL server, not in your application.
Thus the dynamic parts of the query — your variables — are kept separate from the SQL syntax and you avoid SQL injection problems.
For your task described in your question, it would look something like this (I have not tested this Go code, but it should put you on the right path).
stmt, err := tx.Prepare("INSERT INTO `login` (`Username`, `Password`, `LK`) SELECT ?, ?, '' FROM `login` WHERE `LK` = ? LIMIT 1")
if err != nil {
log.Fatal(err)
}
defer stmt.Close()
_, err = stmt.Exec(regusernameEntry.Text(), regpasswordEntry.Text(), reglicenceEntry.Text())
if err != nil {
log.Fatal(err)
}
The order of parameters is important. The variables you pass to Exec() must be in the same order that the ? placeholders appear in your prepared SQL statement. They are matched up, one for one, in the same order, by the MySQL server.
Do not put quotes around the placeholders in your prepared SQL statement. That will work as a literal string '?' in SQL. Use an unquoted ? character for a placeholder. When it gets combined by MySQL in the server, it will work as if you had put quotes around the value like a string — but with no risk of SQL injection even if that string value containing special characters.
Here's another site that gives more code examples: https://github.com/go-sql-driver/mysql/wiki/Examples
The Exec() function is for executing SQL that has no result set, like INSERT, UPDATE, DELETE. There are other functions in the Go SQL driver like Query() and QueryRow() that also accept parameter arguments. You'd use these if your SQL returns a result set.
I can not figure out (not sure what the error codes mean) what is wrong with the below SQL statement and I am do not have enough experience to troubleshoot it. Thank you :).
UPDATE `dbo.Custom_PrimerSet`
SET `Hyperlink` = replace(Hyperlink, 'xxxx', 'pxlence')
Error
Error in table name or view name in UPDATE clause.
Error in set list in UPDATE clause.
Incomplete SET clause.
Unable to parse query text.
You use both Hyperlink and 'Hyperlink'. If you make those consistent and correct does it work out better?
Correct in this case being to omit the quote in the update statement. At least that what works for me in a sqlfiddle
I need this query for testing exception handling, so I would prefer that the query is not schema dependent. I am looking for something like SELECT 1; but of course that doesn't fail.
I am using Java and MySQL but I hope to find answers that doesn't depend on programming languages and/or RDBMSs.
What about "SELECT 1/0" for starters?
You could put an invalid token into the query
select doesnotexist.* from something_else
Or of course, what you should do is mock out the method and have it throw the exception during your test.
there are tons of ways to make a query fail, like mispelling a field, or selecting from non existing tables. for example:
SELECT some_fake_field FROM table_that_doesnt_exists
One way to trigger a failure is to call a stored procedure with the wrong number of parameters. Another similar idea is to write an update/insert statement with the wrong number of arguments...
More ideas here:
How to raise an error within a MySQL function
Any old syntax error will do... like an unterminated string
select 'bob
To get 1/0 to raise an error in MySQL, you need to set sql_mode to ERROR_FOR_DIVISION_BY_ZERO.
Try this:
SET sql_mode = 'ERROR_FOR_DIVISION_BY_ZERO';
SELECT 1/0;
If this sql_mode isn't set, MySQL will return a NULL instead of an error.
You can check what your current settings are with the following:
SELECT ##GLOBAL.sql_mode;
SELECT ##SESSION.sql_mode;
Does anyone know what something like OR 1# means in the context of mysql injection?
It is MySQL's version of the line comment delimiter. In standard SQL, the line comment delimiter is --.
-- This is a standard SQL comment.
# This is a MySQL comment.
So in the context of SQL injection, if the attacker knows you're using MySQL he may use it to abruptly terminate the malicious SQL statement, causing MySQL to ignore whatever is behind the # and execute only the stuff that comes before it. This is only effective against single-line SQL statements, however. Here's an example:
Input:
Username: fake' OR 1#
Password: pass
Resultant SQL:
SELECT * FROM users WHERE username = 'fake' OR 1#' AND password = 'pass'
Which is executed as this, which returns every row:
SELECT * FROM users WHERE username = 'fake' OR 1
This is the start of a comment. It means that anything after that will be skipped by the parser.