Wechall刷题(二) Training: MySQL I 总结

Training: MySQL I 总结

题目

题目总结分为四个部分

  1. 解题思路及部分答案
  2. 个人疑惑以及疑惑解答
  3. 常见的SQL注入语句
  4. 收获:通过本地模拟环境测试

1.解题思路及部分答案

这是一个简单的SQL注入题目,对于初初初学者学者的我来说连源代码都看不懂,所以就一点一点详细道来吧!

  • 首先源代码解析:

    /* TABLE STRUCTURE
    CREATE TABLE IF NOT EXISTS users (
    userid    INT(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    username  VARCHAR(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
    password  CHAR(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL
    ) ENGINE=myISAM;

    这部分就是创建一个表users,表的三个列分别为userid,username,password

  • 
    # Username and Password sent?
    
    if ( ('' !== ($username = Common::getPostString('username'))) && (false !== ($password = Common::getPostString('password', false))) ) {
          auth1_onLogin($chall, $username, $password);
    }

    这部分是判断用户名和密码是否已经发送给服务器,其中的Common::getPostString是调用已有函数,功能为从表单中获取字符串信息;auth1_onLogin为下边的自定义函数,功能为验证用户名和密码

  • /**
    * Get the database for this challenge.
    * @return GDO_Database
    */
    function auth1_db()
    {
          if (false === ($db = gdo_db_instance('localhost', WCC_AUTH_BYPASS1_USER, WCC_AUTH_BYPASS1_PASS, WCC_AUTH_BYPASS1_DB))) {
                  die('Database error 0815_1!');
          }
          $db->setLogging(false);
          $db->setEMailOnError(false);
          return $db;
    }

    这部分代码其实我还不是很清楚,我认为是初始化一个数据库实例,用来后续操作,这部分不影响完成题目

  • /**
    * Exploit this!
    * @param WC_Challenge $chall
    * @param unknown_type $username
    * @param unknown_type $password
    * @return boolean
    */
    function auth1_onLogin(WC_Challenge $chall, $username, $password)
    {
          $db = auth1_db();
    
          $password = md5($password);
    
          $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());
          }
    
          return true;
    }

    这部分就是之前提到的自定义函数,用来处理表单提交的数据。函数与表单之间通过参数“username”和“password”传递数据,这里只需要知道从html表单中输入的username和password就可以代入到这里的query语句中就可以了。

    接着 result= db->queryFirst($query)处理MySQL语句并且将结果返回给result,如果查询结果不是false,说明结果存在。

    $result[‘username’]) === ‘admin’判断用户是否是admin,如果是说明管理员登录。

    完成登陆过程。

  • 然后说明注入过程:这里要想办法输入username和password使得执行query语句的结果存在并且用户名为Admin。但是由于我们不知道真实的admin的密码,所以我们想办法绕过password。即我们可以减少select的限制条件,通过将query中AND及其后边的语句在MySQL语句中注释掉,就可以将query改写为:

    SELECT * FROM users WHERE username='admin'

    于是需要知道MySQL中的注释语法:MySQL注释

    这里我们选择单行注释,即’#’和’–’

  • 答案 :那么构造username分别为:username=admin’#和username=admin’– (注意这里–后边要加括号,原因见MySQL注释);password不填

2.个人疑惑及其解答

解题思路为“注释”,于是我认为下边的填写才正确;

username=admin' ";#

如果这样填写,源代码中的query就变成了

$query = "SELECT * FROM users WHERE username='admin'";#' AND password='$password'";

如此一来既保证了语法正确,而且还将#后边的内容注释掉了(因为#也是php语句的注释)。但结果并不是这样的,我们将不同的username输入之后得到的结果如下:

test

我本以为第三种情况才是正确的,因为这样得到的&query才是完整的,既有封闭的“”,还有分号作为php结束的标志,完全符合语句的标准。而像第一种情况得到的&query后边缺少分号,难道不会报语句完整性错误吗??

通过请教他人和查阅资料,发现php语句可以没有最后的分号作为结尾(但是前提是后边的分块的结尾符号,这里后边的注释语句。。。不知是否可行),这样的话,第一种情况就可以说的过去了;

“php变量的内容不能阶段php语句”

这句话点醒了为什么第三种情况不能成功注入了,这里的MySQL语句在注释之前多了一个”使得语法错误,不能通过。

这里很重要的一点是,输入的username中的注释都只能注释掉MySQL中的后边句子,而不能截断原来的php语句!!!

下边是MySQL SQL 和 PHP的注释语法

MySQL注释 SQL注释 PHP注释1 PHP注释2

3.常见的SQL注入语句测试

’ or ‘1’=’1
’ or 1=1 –
‘or’=’0’
“or 1=1 –
or 1=1 –
‘or’ a ‘=’ a
“or” a “=” a

师傅所传授!暂时还没有实践使用,先记下来

4.在解答疑惑的过程中的收获

师傅是这样解答我的疑惑的,他通过搭建一个本地的php的web环境,通过样例,给定输入得到输出,从而证明并解释了变量中的注释符号不能截断php的现象。所以,这样的解决问题的思路还是很值得学习的,加油!

你可能感兴趣的:(ctf)