任务
在公选课计算机安全技术中,老师重点提到了SQL注入名词,有些感兴趣而进行查询,发现注入攻击是OWASP多次评选最具威胁的web漏洞TOP10中居榜首。看文章时,注意到有个类似闯关的SQL注入学习项目,决定通过这个体验SQL注入。
在配置好闯关项目后,按照教程编辑链接还是有些茫然,又在B站上观看视频,发现良心好课:SQL注入(精讲,原理,实战,绕过,防御)。在有些眉目后,去尝试老师提供的靶机,进展不错,留下记录。
GitHub项目:https://github.com/Audi-1/sqli-labs
安装sqli-labs
进入服务器根目录进行项目下载,原项目要求PHP为低版本,而现有版本为7.x,因此无法进行数据库配置。在原项目的issue中发现有人提供方法,使用修改后的项目:
//PHP低版本使用原项目 git clone https://github.com/Audi-1/sqli-labs.git sqli-labs //PHP高版本使用下面的命令 git clone http://github.com/Rinkish/Sqli_Edited_Version
配置数据库
按照文档教程,将位于/sqli-connections目录下的db-creds.inc文件进行MySQL数据库用户名username和密码的修改即可。
开始闯关
第一关提示输入id做为参数
不知所云,参考博客教程sqli-lab教程——1-35通关Writeup,url后输入 ?id=0’出现下列提示,说明可被SQL注入攻击
输入下列代码成功获取数据库名称,然而我还是不清楚这其中道理,决定去B站进行视频学习。
?id=-1' union select 1,2,database() --+
基本知识
幸运发现刚出炉的好课,SQL注入(精讲,原理,实战,绕过,防御),干货满满。
只听了第一开始的基础讲解就对整个过程明白一二:
- url是动态的请求过程
- 解释语言会在运行过程被攻击性命令利用
- 在进行的SQL命令中加上
- ‘ 进行语句的闭合
- or 1==1 (数据库讲解要避免的 永为真 情况)
- — 对后面的语句注释
靶机实战
关卡1 用户登录
来到老师提供的靶机地址 http://cse19.club/进行了闭合语句的测试,虽然界面很友好打印了相应提示,但让人感觉SQL注入无法成功——输入的内容在闭合的标签中,即使修改url中相应位置也落败。
尝试搜索课程提到的万能密码 ,选取一个复制粘贴,登录成功!
a'or' 1=1--
关卡2 用户数据
这里可以看出通过输入已录入数据库中的学号可以进行下一步登录。
但这里输入万用密码会被检测到并踢出~
爬虫获取存在用户
当输入不存在的用户名时,会报告没有此用户
而观察此时的URL如下
http://cse19.club/ShowDetail.php?name=U2017&votebutn=%E8%BF%9B%E5%85%A5
则通过构造URL便可起到访问数据库的作用,我不禁想到了用爬虫实现。
基本获取网页信息
import urllib.request as u
url="http://www.cse19.club/ShowDetail.php?name=U2017&votebutn=%E8%BF%9B%E5%85%A5"
response=u.urlopen(url)
html=response.read()
print((html).decode("utf-8"))
在译码后发现网页中并未出现需要的内容,需要登录状态才可以查询。
传入cookie
通过之前爬虫的项目实战明白cookie中记录登录信息,通过向请求中加入自己登录后的cookie即可成功。
cookie在network中的文件中的header可以找到
import requests
import re
user-agent='xxxx'#上图中相应位置
cookie='xxxx'#上图中相应位置
headers = {
'User-Agent':user-agent,
'Cookie': cookie
}
获取关键信息getInfo
由于目前仅知不存在用户的界面为何,所以通过re网页内容进行字符匹配,如果结果中包含有No User的提示,就回车刷新输出;如果不包含!那就是我们需要的用户名,换行输出,在窗口留下记录
def getInfo(url):
response=requests.get(url,headers=headers)
if response.status_code == 200:
try:
contents = re.findall('</tr>(.*?)<!--right end -->',response.text,re.S)
for content in contents:
tip=re.findall('No Users',content)
if not tip:
print(url)
else:
print(url,end='\r')
except:
pass
else:
pass
构造url
上面的函数需要的参数是url,构造url至为关键。原本乖巧地按照题目提示:6个X。那就从000000-999999遍历吧。开了多个分批进行,不时关心一下情况——一无所获,心里有些发毛。
决定还是先自己缩小范围:华科学号命名规则:
哪一届都一样,我是13届。学号U201315032,U是university, 2013是届数,15是计算机学院,032有三位,因为每个院人数在001~999之间各人编号不同
我有些绝望默念了自己的学号,是的,年份后面是5位,是5位!
urlLeft='http://www.cse19.club/ShowDetail.php?name=U201715'
urlRight='&votebutn=%E8%BF%9B%E5%85%A5'
urls=[urlLeft+("{:0>3d}".format(i))+urlRight for i in range(0,1000)]
这次没有令人失望,得到了2个换行结果!
输入后,得到了相应结果
因为时代变迁,在学号为14打头的部分获得了更多的输出结果。
当然,现在已经知道了正确用户名的输出格式,便可通过爬虫获取相应的数据。但这里的数据都是假数据,目前进行到这步已经可以告一段落了。
当对SQL注入进一步深入后,可以有方法绕过检测,因此未完待续……