SQL注入漏洞从发现到修复

发现漏洞

一、环境准备

1、在Linux主机上准备一套Xampp:模拟攻防

2、在VSCode利用Remote Development进行远程调试

3、在Lampp的htdos目录下创建security目录,用于编写服务器PHP代码

二、编写Login.html

三、编写Login.php

<?php` `// 获取用户提交的登录请求数据``$username = $_POST['username'];``$password = $_POST['password'];``$vcode = $_POST['vcode'];``   ``   ``// 验证码的验证,OWASP-认证和授权失败``if($vcode !== '0000'){`    `die("vcode-error");    //向前端输出一条消息同时结束代码的运行``}``   ``   ``// 连接数据库``$conn = mysqli_connect('127.0.0.1','root','123456','learn') or die("数据库连接不成功!");` `   ``   ``// 设置数据库的编码格式``mysqli_query($conn,"set names utf8;");``   ``   ``$sql = "select * from user where username ='$username' and password = '$password'";``$result = mysqli_query($conn,$sql);     //$result称之为结果集``   ``   ``// 以下代码没用进行爆破的防护(OWASP-认证和授权失败)``   ``   ``if (mysqli_num_rows($result) == 1){`     `echo "login-pass<br/>";``   ``   `    `echo "<script>location.href='welcome.php'</script>";``}``else{`    `// echo "login-fail<br/>";`    `echo "<script>location.href='login.html'</script>";``}``   ``   ``//关闭数据库``mysqli_close($conn)``?>

四、编写一个登录后才能访问的welcome.php

<?php``// OWASP-失效访问控制`    `// 修复方法:在显示文本之前,先进行SESSION变量的验证``include "common.php";``//isset() 函数用于检测变量是否已设置并且非 NULL。``if (!isset($_SESSION['islogin']) or $_SESSION['islogin'] != 'true'){`    `die ("请登录后再访问此页面</br>");``}``echo '欢迎来到安全测试平台';``?>

五、进行登录的渗透测试

在登录界面输入一个单引号[']作为用户名,Burp响应如下:

<b>Warning</b>:  mysqli_num_rows() expects parameter 1 to be mysqli_result, boolean given in <b>/opt/lampp/htdocs/security/login.php</b>

以上响应出现MySQL报错信息,上述报错信息存在两个漏洞:

1、单引号可以成功引起SQL语句报错,说明后台没有专门对单引号进行处理

select * from user where username ='$username' and password = '$password'`  `正常情况:select * from user where username ='root' and password = '$password'`  `攻击情况:select * from user where username =''' and password = '$password'`    `攻击Payload:`             `username:x' or userid=1#'`    `Post正文:`             `username=x' or+userid=1#'&password=111111&vcode=0000`    `select * from user where username ='x' or userid=1#'' and password = '$password'

2、在报错信息里泄露了敏感信息

/opt/lampp/htdocs/security/login.php(当前代码的绝对路径)

六、总结

上述代码一共发现了6个漏洞

1、welcome.php页面谁都可以访问,没有进行登录判断(中)

2、在登录界面输入’作为用户名,报错信息存在login.php的绝对路径,暴露了系统后台的敏感信息(低)

3、保存用户信息的数据表中,密码字段是明文保存的,不够安全(中)

4、登录界面可以进行SQL注入,进而轻易实现登录(高)

5、login.php页面使用了万能验证码(中)

6、登录功能可以被爆破,没有进行爆破防护(中)

SQL注入-登录漏洞-基础修复

一、使用Python进行注册测试

import requests``# 利用Python对PHP的登录界面进行Fuzz测试``   ``   ``def login_fuzz():`    `# 先使用单引号进行测试`    `url = 'http://192.168.72.148/security/login.php'`    `data = {'username': "'", 'password': '666666', 'vcode': '0000'}`    `resp = requests.post(url=url, data=data)``   ``   `    `if 'Warning' in resp.text:`        `print("本登录功能可能存在SQL注入漏洞,可以尝试")`        `# 如果单引号存在利用嫌疑,则继续利用`        `payload_list = ["x' or id=1#", "x' or userid=1#", "x' or userid=2#"]`        `for username in payload_list:`            `data = {'username': username, 'password': '666666', 'vcode': '0000'}`            `resp = requests.post(url=url, data=data)`            `if "login-fail" not in resp.text:`                `print(f'登录成功,payload为:{data}')`    `else:`        `print('通过试探,发现后台界面对单引号不感兴趣;')``   ``   ``if __name__ == '__main__':`    `login_fuzz()

二、任意访问授权界面

welcome.php页面谁都可以访问,没有进行登录判断,该页面是登录后才能访问,所以在该页面需要进行登录判断,代码修改为:

1、在common.php中添加session_start(),让其他页面引入,便于直接使用Session

<?php``session_start();``function create_connection(){`    `// 连接数据库`    `$conn = mysqli_connect('127.0.0.1','root','123456','learn') or die("数据库连接不成功!");``    // 设置数据库的编码格式`    `mysqli_query($conn,"set names utf8;");`    `mysqli_set_charset($conn,'utf8');`    `return $conn;``}``?>

2、在welcome.php页面中,源代码修改为

<?php``// OWASP-失效访问控制`    `// 修复方法:在显示文本之前,先进行SESSION变量的验证``include "common.php";``//isset() 函数用于检测变量是否已设置并且非 NULL。``if (!isset($_SESSION['islogin']) or $_SESSION['islogin'] != 'true'){`    `die ("请登录后再访问此页面</br>");``}``echo '欢迎来到安全测试平台';``?>

3、在login.php中,登录成功后添加以下代码

if (mysqli_num_rows($result) == 1){`    `echo "login-pass<br/>";`    `// 登录成功后,记录SESSION变量`    `$_SESSION['username'] = $username;`    `$_SESSION['islogin'] = 'true';`    `echo "<script>location.href='welcome.php'</script>";``}

三、修复login.php暴露文件路径

当在用户名输入单引号时,会引起后台报错,一方面说明后台没有对单引号进行转义处理,导致单引号可以被注入到SQL语句中,进而导致SQL语句中存在单独的一个单引号,SQL语句无法有效闭合,发生错误。同时,还将该代码的绝对路径暴露出来,属于敏感信息,应该将其屏蔽,修复代码如下:

$result = mysqli_query($conn,$sql) or die("SQL语句执行错误!") ;

四、修改用户表密码为明文

1、使用md5函数

$source = 'YikJiang';``echo md5($source);``   ``   ``//提示一:user表中password字段必须是32+位``//提示二:在用户注册时,必须使用md5函数将密码加密保存

SQL注入-登录漏洞-SQL注入防护

从代码和SQL语句的逻辑层面进行考虑,不能轻易让密码对比失效

基于将用户输入的引号(单引号和双引号)进行转义处理的前提,可以使用PHP内置函数addslashes进行强制转义

一、登录SQL语句的逻辑问题

1、该SQL语句在实现登录操作时,存在严重的逻辑问题,用户名和密码的对比不应该放在同一条SQL语句中。

2、应先通过用户名查询user表,如果确实找到一条记录(用户名唯一的情况下),找到记录后再进行密码的单独对比。

修复后的代码如下:

$sql = "select * from user where username ='$username'";``$result = mysqli_query($conn,$sql) or die("SQL语句执行错误!") ;     //$result称之为结果集``// 以下代码没用进行爆破的防护(OWASP-认证和授权失败)``//如果用户名真实存在,刚好找到一条,则再单独进行密码比较,即使用户名出现SQL注入漏洞,但是只要密码不正确,也无法登录``if (mysqli_num_rows($result) == 1){`    `// $row = mysqli_fetch_all($result,MYSQLI_ASSOC);       //索引数组+下标数组`    `// $row = mysqli_fetch_row($result);       //索引数组`    `$row = mysqli_fetch_assoc($result);     //下标数组`    `// var_dump($row);`    `if ($password == $row['password']){`        `echo "login-pass<br/>";`        `// 登录成功后,记录SESSION变量`        `$_SESSION['username'] = $username;`        `$_SESSION['islogin'] = 'true';`        `echo "<script>location.href='welcome.php'</script>";`    `}`    `else{`        `echo "login-fail";`    `}``   ``}``else{`    `echo "login-fail<br/>";`    `echo "<script>location.href='login.html'</script>";``}

二、使用addslashes函数

addslashes函数可以将字符串中的单引号、双引号、反斜杠、NULL值自动添加转义符,从而防止SQL注入中对单引号和双引号的预防。

原始SQL语句如下:

select * from user where username ='$username' and password = '$password'

如果用户输入x’ or userid=1#',则SQL语句变成:

select * from user where username ='x' or userid=1#'' and password = '$password'

如果使用addslashes强制为用户输入添加转义符,则变成:

select * from user where username ='x\' or userid=1#\'' and password = '$password'

上述SQL语句的用户名为:x\’ or userid=1#\’

三、使用MySQL面向对象方式

1、面向过程方式

使用PHP自带的函数

// 面向过程的方式``function create_connection(){`    `// 连接数据库`    `$conn = mysqli_connect('127.0.0.1','root','123456','learn') or die("数据库连接不成功!");``    // 设置数据库的编码格式`    `mysqli_query($conn,"set names utf8;");`    `mysqli_set_charset($conn,'utf8');`    `return $conn;``}``// 将数据库查询的结果集中的数据取出,保存到一个数组当中``$row = mysqli_fetch_assoc($result);``//mysqli_fetch_all默认使用索引数组,也可以设定参数强制使用关联数组``// $row = mysqli_fetch_all($result,MYSQLI_ASSOC);`      `// $row = mysqli_fetch_row($result);       //索引数组

2、面向对象方式

function create_connection_oop(){`    `    $conn = new mysqli('127.0.0.1','root','123456','learn') or die("数据库连接不成功!");`    `// 两种方法设置字符集`    `// 1、$conn->query("set names utf8;")`    `// 2、`    `$conn->set_charset('utf8');`    `return $conn;``}``   ``   ``// 执行SQL语句``function test_mysqli_opp(){`    `$conn = create_connection_oop();`    `$sql = "select * from user where userid < 6";`    `$result = $conn->query($sql);`    `//获取结果集行数`    `echo $result->num_rows."</br>";`    `// 获取结果集数组`    `// 使用关联数组`    `$rows = $result->fetch_all(MYSQLI_ASSOC);`    `// var_dump($rows);`    `// 遍历数组`    `foreach ($rows as $row){`        `echo "username:". $row['username'] . ",passwrod" . $row['password'] . "</br>";`    `}``}

四、使用MySQL预处理功能

1、预处理功能的用法

预处理的过程,就是先交给SQL数据库进行SQL语句的准备,准备好后再将SQL语句中的参数进行值的替换,引号会进行转义处理,将所有参数变成普通字符串,再进行第二次正式的SQL语句执行。MySQL的预处理既支持面向过程,也支持面向对象方式,但是我们后续直接使用面向对象的方式。

$conn = create_connection_oop();``$sql = "select userid,username,password,role from user where username= ?";``$stmt = $conn->prepare($sql);``$stmt->bind_param("s",$username);       // 绑定查询参数``$stmt->bind_result($userid,$username2,$password2,$role);    // 绑定结果参数``$stmt->execute();       // 执行``$stmt->store_result();  //调用结果

2、使用预处理来防止SQL注入

3、配置MySQL临时日志查看SQL语句

在MySQL数据库中运行以下语句,开启临时日志,将日志信息保存到表格mysql数据库的general_log表中。

#开启``use mysql;``set global log_output = 'TABLE';``set global general_log = 'ON';``#确认``show variables like "general_log";
MySQLi的预处理功能同样支持面向过程和面向对象``除了MySQLi用于处理数据库外,在PHP中还有最传统的MySQL和PDO两种方式

SQL注入-登录漏洞-验证码处理

一、验证码生成原理

核心目的是确保是人在使用系统,图片验证码、拖动验证码、拼图验证码、问答验证码、计算验证码等。

二、验证码代码实现

添加源代码vcode.php,基于PHP绘制基础图片,生成验证码,然后将该验证码保存到Session变量

<?php``// 利用Session保存图片验证码``session_start();``getCode();``// 生成验证码图片``function getCode($vlen=4 , $width = 80 , $height = 25){`    `// 定义响应类型为PNG图片`    `header("content-type:image/png");`    `// 生成随机验证码字符串,并将其保存于Session中`    `$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';`    `$vcode =substr(str_shuffle($chars),0,$vlen);`    `$_SESSION['vcode'] = $vcode;`    `// 定义图片并设置背景色RGB为100,200,100`    `$image = imagecreate($width,$height);       // 创建一个画布`    `$imageColor = imagecolorallocate($image,100,200,100);`    `// 以RGB=0,0,0,的颜色回值黑色的文字`    `$color = imagecolorallocate($image,0,0,0);`    `imagestring($image,5,20,5,$vcode,$color);       // 5:字体大小  20:距离x轴的距离   5:距离y轴的距离`    `// 生成随机位置的干扰点`    `for($i=0;$i<50;$i++){`        `imagesetpixel($image,rand(0,$width),rand(0,$height),$color);`    `}`    `// 输出图片验证码,并将其在内存的数据销毁`    `imagepng($image);`    `imagedestroy($image);``}``?>

三、修改HTML页面调用验证码

修改login.html

input[name='vcode']{`  `width: 200px;``}``<body style="background-image:url(./image/1.png); background-size:cover;">`        `<div class="login top-100 font-30">YikJiang</div>`        `<form action="login-3.php" method="post">`            `<div class="login">`                `<input type="text" name="username" />`            `</div>`            `<div class="login">`                `<input type="password" name="password" />`            `</div>`            `<div class="login">`                `<input type="text" name="vcode" /> &nbsp;&nbsp;&nbsp;`                `<img src="vocde.php"/>`            `</div>``   ``   `            `<div class="login">`                `<!--*type="submit" 代表按钮类型为提交表单-->`                `<button type="submit">登录</button>`            `</div>`        `</form>`    `<div class="footer top-100">版权所有©YikJiang 沪ICP备18011293号</div>``</body>``</html>

四、登录的验证码校验

修改login.php

if(strtoupper($_SESSION['vcode'])  != strtoupper($vcode) ){`    `die("vcode-error");    //向前端输出一条消息同时结束代码的运行``}

验证码一旦生成后,不一定必须保存在Session中,任何可以存储数据的方式均可以。比如数据库、文件、内存中,或者保存在Redis缓存服务器中。比如短信验证码,通常会有一个时间限制(5分钟内有效),最好的解决方案就是使用Redis缓存,并设置Key的过期时间

声明:

仅供安全研究与学习之用,若将工具做其他用途,由使用者承担全部法律及连带责任,作者不承担任何法律及连带责任。

网络安全学习资源分享:

最后给大家分享我自己学习的一份全套的网络安全学习资料,希望对想学习 网络安全的小伙伴们有帮助!

零基础入门

对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。

如果你对网络安全入门感兴趣,那么你需要的话可以点击这里👉网络安全重磅福利:入门&进阶全套200G学习资源包免费分享!

1.学习路线图

攻击和防守要学的东西也不少,具体要学的东西我都写在了上面的路线图,如果你能学完它们,你去接私活完全没有问题。

2.视频教程

网上虽然也有很多的学习资源,但基本上都残缺不全的,这是我自己录的网安视频教程,上面路线图的每一个知识点,我都有配套的视频讲解。

技术文档也是我自己整理的,包括我参加大型网安行动、CTF和挖SRC漏洞的经验和技术要点,电子书也有200多本【点击领取技术文档】

在这里插入图片描述

(都打包成一块的了,不能一一展开,总共300多集)

3.技术文档和电子书

技术文档也是我自己整理的,包括我参加大型网安行动、CTF和挖SRC漏洞的经验和技术要点,电子书也有200多本【点击领取书籍】

在这里插入图片描述

4.工具包、面试题和源码

“工欲善其事必先利其器”我为大家总结出了最受欢迎的几十款款黑客工具。涉及范围主要集中在 信息收集、Android黑客工具、自动化工具、网络钓鱼等,感兴趣的同学不容错过。

在这里插入图片描述

最后就是我这几年整理的网安方面的面试题,如果你是要找网安方面的工作,它们绝对能帮你大忙。

这些题目都是大家在面试深信服、奇安信、腾讯或者其它大厂面试时经常遇到的,如果大家有好的题目或者好的见解欢迎分享。

参考解析:深信服官网、奇安信官网、Freebuf、csdn等

内容特点:条理清晰,含图像化表示更加易懂。

内容概要:包括 内网、操作系统、协议、渗透测试、安服、漏洞、注入、XSS、CSRF、SSRF、文件上传、文件下载、文件包含、XXE、逻辑漏洞、工具、SQLmap、NMAP、BP、MSF…

在这里插入图片描述

因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取
CSDN大礼包:《黑客&网络安全入门&进阶学习资源包》免费分享

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值