I've been trying to bypass a certain feature in SQLite injection, but I'm facing difficulties. Here's what I've attempted so far:
Standard Injection Techniques: I've tried standard SQL injection techniques such as UNION SELECT statements and Boolean-based blind injection to extract data from the database. However, the application seems to be sanitizing inputs effectively, preventing me from executing these queries successfully.
Escape Characters: I've experimented with various escape characters such as single quotes ('), double quotes ("), backslashes (), and HTML encoding to try to bypass input sanitization. Unfortunately, none of these approaches seem to work in my case.
Error-based Injection: I attempted error-based injection by injecting malformed SQL queries to trigger errors that might reveal information about the underlying database schema or data. However, the application seems to handle errors gracefully without disclosing sensitive information.
Time-based Injection: Another approach I've tried is time-based injection, where I introduce delays in SQL queries to infer whether my injections are successful or not. Unfortunately, I haven't been able to observe any noticeable delays, indicating that my injections might not be taking effect.
Analyzing Application Logic: I've also tried to analyze the application logic to identify any potential vulnerabilities or weak points that might be exploited for injection. However, the codebase seems to be well-written and follows secure coding practices, making it challenging to find any exploitable vulnerabilities.
Despite these efforts, I haven't been able to bypass the feature in SQLite injection successfully. Any insights, suggestions, or alternative approaches would be greatly appreciated. Thank you in advance for your assistance!
main.js
const tweetButton = document.querySelector('#tweet-btn');
const tweetForm = document.querySelector('#tweet');
const tweetsTable = document.querySelector('#tweets-table');
const statusText = document.querySelector('.status-text');
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
const postTweet = async() => {
try {
statusText.style.color = "white";
statusText.innerHTML = "Please wait...";
statusText.style.visibility = "visible";
const resp = await axios.post('/api/v1/tweets', { tweet: tweetForm.value });
if (resp.data.success) {
statusText.innerHTML = "Very nice, your tweet has been recorded";
statusText.style.color = '#1ED931';
let postedTweet = resp.data.data;
if (!postedTweet) {
statusText.innerHTML = "No tweets found";
statusText.style.color = '#fa2525';
return
}
let row = tweetsTable.insertRow();
row.insertCell(0).innerHTML = postedTweet.tweetID;
row.insertCell(1).innerHTML = escapeHtml(postedTweet.tweet);
} else {
statusText.innerHTML = resp.data.data;
statusText.style.color = '#fa2525';
}
} catch (error) {
statusText.style.color = '#fa2525';
//Check if API has returned a custom response
const errorMessage = error.response.data.data;
if (errorMessage) {
statusText.innerHTML = errorMessage;
} else {
statusText.innerHTML = 'Ooopsie! Something went wrong';
}
}
}
tweetButton.addEventListener('click', postTweet);
db.js
const path = require('path');
const sqlite = require('sqlite-async');
let appDatabase;
const setupDatabase = async() => {
appDatabase = await sqlite.open(path.join(__dirname, 'ctf-challenge.db'));
await appDatabase.exec(`
DROP TABLE IF EXISTS tweets;
CREATE TABLE IF NOT EXISTS tweets (
tweetID INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
tweeterID VARCHAR(255) NOT NULL,
tweet TEXT NOT NULL
);
DROP TABLE IF EXISTS secrets;
CREATE TABLE IF NOT EXISTS secrets (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
flag VARCHAR(255) NOT NULL UNIQUE
);
INSERT INTO secrets (flag) VALUES ('CTF{testing_flag}');
`);
}
const insertTweet = async(tweeterID, tweet) => {
return new Promise(async(resolve, reject) => {
try {
// TODO: Migrate to prepared statements and rollout to production
let prepared = await appDatabase.prepare(`INSERT INTO tweets (tweeterID, tweet) VALUES (?, '${tweet}')`);
await prepared.run(tweeterID);
prepared = await appDatabase.prepare('SELECT * FROM tweets WHERE tweeterID = ? ORDER BY tweetID DESC');
resolve(await prepared .get(tweeterID));
} catch (error) {
reject(error);
}
});
}
module.exports = { setupDatabase, insertTweet }
Standard Injection Techniques:
Attempted UNION SELECT statements.
Tried Boolean-based blind injection to extract data from the database.
Escape Characters:
Experimented with single quotes ('), double quotes ("), backslashes (), and HTML encoding to bypass input sanitization.
Error-based Injection:
Injected malformed SQL queries to trigger errors that might reveal information about the underlying database schema or data.
Time-based Injection:
Introduced delays in SQL queries to infer whether injections were successful or not.
Analyzing Application Logic:
Reviewed the application logic to identify potential vulnerabilities or weak points for exploitation.
Despite employing these methods, the feature in SQLite injection remains challenging to bypass. Your efforts reflect a thorough approach to troubleshooting the issue. If you have any further insights or alternative strategies, they would be greatly appreciated.