提问人:Fabio R. 提问时间:10/22/2021 最后编辑:Fabio R. 更新时间:10/22/2021 访问量:286
SQL 注入按原样返回注入的代码
SQL Injection returns injected code as it is
问:
我试图击败这个 CTF:一个正在建设中的网站,有一个简单的登录页面,您可以在其中登录或注册新用户。
它使用 和 DB。node express
SQLite
分析源代码,我发现了这个查询:
getUser(username){
return new Promise((res, rej) => {
db.get(`SELECT * FROM users WHERE username = '${username}'`, (err, data) => {
if (err) return rej(err);
res(data);
});
});
},
此函数在中间件检查会话 cookie 后调用,以便在 GET 时检索用户名。jsonwebtoken
'/'
这就是它的名字:
router.get('/', AuthMiddleware, async (req, res, next) => {
try{
let user = await DBHelper.getUser(req.data.username);
if (user === undefined) {
return res.send(`user ${req.data.username} doesn't exist in our database.`);
}
return res.render('index.html', { user });
}catch (err){
return next(err);
}
});
AuthMiddleware:
module.exports = async (req, res, next) => {
try{
if (req.cookies.session === undefined) return res.redirect('/auth');
let data = await JWTHelper.decode(req.cookies.session);
req.data = {
username: data.username
}
next();
} catch(e) {
console.log(e);
return res.status(500).send('Internal server error');
}
}
由于这似乎是唯一以这种方式格式化的查询(其他查询都使用 ),并且通常是唯一明显的漏洞,因此我怀疑该标志存储在数据库中的某个地方。?
由于调用该函数的唯一方法是有一个活动会话,我使用“恶意”sql代码注册了一个用户作为用户名。起初,我试图关闭报价并附加一个以获取所有用户:OR WHERE
SELECT * FROM users WHERE username = '${username}'
+
bob' OR WHERE username IS NOT NULL
=
SELECT * FROM users WHERE username = 'bob' OR WHERE username IS NOT NULL
这至少应该抛出一个错误,因为它应该在网页上呈现为时返回一个包含数据库中所有用户的集合WHERE username = 'bob' OR WHERE username IS NOT NULL
欢迎 {{ user.username }}
本网站正在开发中。
请稍后再来。
我期望至少“数组上没有用户名属性”或类似的东西。相反,它总是返回我给他的完整用户名
欢迎 bob' 或 WHERE 用户名 IS NOT NULL
此网站正在开发中。
请稍后再来。
我错过了什么吗?有没有办法逃避在cookie读取过程中可能添加的最终引号?
编辑:
这是尝试登录时调用的函数 /auth 路由:
router.post('/auth', async (req, res) => {
const { username, password } = req.body;
if((username !== undefined && username.trim().length === 0)
|| (password !== undefined && password.trim().length === 0)){
return res.redirect('/auth');
}
if(req.body.register !== undefined){
let canRegister = await DBHelper.checkUser(username);
if(!canRegister){
return res.redirect('/auth?error=Username already exists');
}
DBHelper.createUser(username, password);
return res.redirect('/auth?error=Registered successfully&type=success');
}
// login user
let canLogin = await DBHelper.attemptLogin(username, password);
if(!canLogin){
return res.redirect('/auth?error=Invalid username or password');
}
let token = await JWTHelper.sign({ // Maybe something can be done with this function?
username: username.replace(/'/g, "\'\'").replace(/"/g, "\"\"")
})
res.cookie('session', token, { maxAge: 900000 });
return res.redirect('/');
});
attemptLogin():
attemptLogin(username, password){
return new Promise((res, rej) => {
db.get(`SELECT * FROM users WHERE username = ? AND password = ?`, username, password, (err, data) => {
if (err) return rej();
res(data !== undefined);
});
});
}
编辑 2.0:
我刚刚注意到它存储会话cookie的部分:
let token = await JWTHelper.sign({
username: username.replace(/'/g, "\'\'").replace(/"/g, "\"\"")
})
它显然用 .我可以通过转义引号来解决其中的一半,使其变成 .这允许我关闭语句,但我仍然需要找到一种方法来使第二个 .'
\'\'
\\'\'
username=''
\'
答: 暂无答案
评论
req.data.username
bob' OR WHERE username LIKE '%64_[^!_%65/%aa?F%64_D)_(F%64)_%36([)({}%33){()}£$&N%55_)$*£()$*R”_)][%55](%66[x])%ba][$*”£$-9]_%54'
bob' OR WHERE username LIKE 'admin'
/auth?error=Invalid%20username%20or%20password