DVWA奇妙之旅
本文最后更新于:1 分钟前
前言
ctf比赛中写pwn题目时常常遇到没有头绪或者卡壳的情况,所以为了避免坐牢,我开启了web学习之路,目的就是在比赛中能给web师傅们打打下手,提供一些帮助,不至于什么也不会。
此篇博客记录我在DVWA靶场通关练习。
暴力破解
low
1 |
|
high
增加了token验证,这样就三个payload,选择同时遍历攻击
命令注入
low
源码分析
1 |
|
stristr(a,b)在a中寻找第一次出现b的并返回b,以及其后面部分,不区分大小写
可以控制target的内容
1 |
|
medium
加了黑名单,源码中定义了一个关联数组,包含要替换的字符序列和它们对应的替换值
1 |
|
array_keys返回键(要替换的字符序列)
$substitutions表示替换后的值
$target目标字符串
所以直接执行127.0.0.1 & ipconfig就可以
high
1 |
|
又继续在黑名单中增加了更多的限制
仔细观察后127.0.0.1 |ipconfig可以绕过
impossible
1 |
|
这种就类似于白名单,比黑名单更有局限性,以我现在的实力绕过仍需要努力
CSRF
跨站请求伪造:攻击者利用·受害者未失效的身份信息,诱骗受害者点击恶意链接或者含有攻击代码的页面,在受害者不知情的情况下用受害者身份向服务器发起请求
low
http://t.nxw.so/cIMrJ 用这个链接打开密码成功被修改成改原链接的密码
同时我们也可以写一个错误页面,导致用户点击之后以为出错,实际上已经执行了恶意代码
1 |
|
medium
1 |
|
检查了Referer 中是否包含了 Host 的值,希望通过这种机制抵御CSRF攻击
想要恶意网站所发送的流量包,只需如下
Host: 127.0.0.3
Referer: http://127.0.0.1/127.0.0.3.html
在这种情况下,Referer 中包含了 Host 的值
就能绕过了
抓包
high
文件包含
当服务器开启了allow_url_include选项时,通过一些PHP的特性函数(比如:include(),require(),include_once()和require_once())利用URL去动态包含文件,此时如果没有对文件来源进行严格审查,就会导致任意文件读取或者任意命令执行。
分类:本地和远程
特性函数区别
1 |
|
low
1 |
|
没有任何防护,通过get获取文件内容。触发两种包含
本地包含
远程包含
medium
1 |
|
加了一些过滤,将“http://”,“https://”,“../”,“..\”全部替换成了空,这个地方其实可以考虑双写绕过。
…/./
high
1 |
|
使用伪协议:file://
1 |
|
文件上传
由于对上传文件的内、类型没有做严格的过滤、检查,使得攻击者可以将病毒,木马,webshell,其他恶意脚本或者是包含了脚本的图片上传到服务器。
一句话木马
1 |
|
medium
1 |
|
对文件上传的类型做了限制,要求必须是image/jpeg 或者 image/png 类型的。
抓包改content-type
high
1 |
|
函数会通过读取文件头,返回图片的长、宽等信息,如果没有相关的图片文件头,函数会报错。
可以看到,High级别的代码读取文件名中最后一个”.”后的字符串,期望通过文件名来限制文件类型,因此要求上传文件名形式必须是”*.jpg”、”*.jpeg” 、”*.png”之一。同时,getimagesize函数更是限制了上传文件的文件头必须为图像类型。
总的来说就是对文件头和文件名形式进行了检查,需要使用图片马,进行绕过
1 |
|
1.png:找到符合要求的图片
2.php:写一句话木马
3.png:上传的文件
验证码
逻辑漏洞
low
直接抓包跳过step1,可以使用csrf构造一个诱导页面
medium
源码中增加了一个passed_capt,当passed_capt为true时就可以修改密码了
抓包后,修改step2,在后面增加&passed_captcha=true
high
1 |
|
修改参数 $_POST[ ‘g-recaptcha-response’ ] == ‘hidd3n_valu3’ $_SERVER[ ‘HTTP_USER_AGENT’ == ‘reCAPTCHA’
sql注入
sql是操作数据库数据的结构化查询语言,网页的应用数据和后台数据库中的数据进行交互时会采用SQL。而SQL注入是将Web页面的原URL、表单域或数据包输入的参数,修改拼接成SQL语句,传递给Web服务器,进而传给数据库服务器以执行数据库命令。如Web应用程序的开发人员对用户所输入的数据或cookie等内容不进行过滤或验证(即存在注入点)就直接传输给数据库,就可能导致拼接的SQL被执行,获取对数据库的信息以及提权,发生SQL注入攻击。
low
首先输入1 或者 2 能查出指定信息
1 |
|
接着输入1’ and 1=1,报误
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘’’ at line 1
说明受到单引号闭合影响
接把SQL语句中后续语句全部注释掉不执行,在判断语句后加#或者–+即可,全部注释掉就可以不用考虑单双引号闭合的问题
1’ or 1=1#可以查出所有ID内容
逻辑解释:为了尝试注入一个始终为真的条件,从而绕过某些基于条件的验证或过滤,导致所有记录都被返回
1’
:这部分表示数字1后面跟着一个单引号。在SQL注入的上下文中,这通常用于尝试关闭前面的字符串或注释掉后续的SQL代码。or
:逻辑或操作符,用于连接两个条件。1=1
:这是一个永远为真的条件,因为1确实等于1。#
:在SQL中,井号(#)用于注释掉后面的内容。这意味着任何出现在#
之后的SQL代码都将被忽略。
查字段
1’ and 1=1 order by 2#
1’ and 1=1 order by 3#
如果2是正确的的,3返回错误那么就有2个字段,2即为分界点
显示报错位
1’ union select 1,2#
1’
:这试图关闭原始查询中的字符串。例如,如果原始查询是 SELECT * FROM users WHERE username = 'admin'
,那么 1’
会尝试将其变为 SELECT * FROM users WHERE username = 'admin'1’
。
查数据库名
1 |
|
查表名
1 |
|
查列名
1 |
|
查具体信息
1 |
|
md5解码就行
medium
传参方法改成post,使用了转义
sqlmap使用
low
sqlmap -u “ “时出现了302重定向会返回登录页面,证明这个页面需要cookie,那么我们接下来就复制数据包中的cookie
查看注入点信息
1 |
|
查看数据库相关信息
1 |
|
继续添加–current-db即可查看该数据库名称
继续添加命令 -D dvwa –tables(列出dvwa数据库中全部表名)
修改命令-D dvwa -T users –columns(列出user表中字段信息)
修改命令-D dvwa -T users -C user,password,user_id –dump(一般数据库中的信息都会加密,这个命令可以直接显示解密后的情况,并且会自动保存到本地)
medium
post传参
首先抓包,复制数据包,放在sqlmap目录下文本文件
python sqlmap.py -r a.txt –batch
后面的步骤一模一样
High
这个是跨页面,抓包
做法是前两做法一起使用
python sqlmap.py -r a.txt –batch –second-url “http://localhost:777/vulnerabilities/sqli/“ –dbs
之后步骤一样
盲注
不会将返回具体的数据信息或语法信息,只会将服务器包装后的信息返回到页面中。
布尔盲注
可通过构造真or假判断条件(数据库各项信息取值的大小比较,如:字段长度、版本数值、字段名、字段名各组成部分在不同位置对应的字符ASCII码…),将构造的sql语句提交到服务器,然后根据服务器对不同的请求返回不同的页面结果(True、False);然后不断调整判断条件中的数值以逼近真实值,特别是需要关注响应从True<–>False发生变化的转折点。
时间盲注
通过构造真or假判断条件的sql语句,且sql语句中根据需要联合使用sleep()函数一同向服务器发送请求,观察服务器响应结果是否会执行所设置时间的延迟响应,以此来判断所构造条件的真or假(若执行sleep延迟,则表示当前设置的判断条件为真);然后不断调整判断条件中的数值以逼近真实值,最终确定具体的数值大小or名称拼写。
low
布尔盲注
找到注入点,判断注入类型
1 |
|
查找库名(以数据库名的第一个字母为例)(最终查到的库名:root)
1 |
|
查找表名(以数据库的第一个表的第一个字母为例)(最终查到的表名:guestbook
1 |
|
查找表中的第一个字段名(以数据库中第一个表的第一个字段为例)(最终查到的列名:comment_id)
1 |
|
查找数据库中第一个表中第一个字段中的第一个数据的第一个字母(最终查到的数据:1)
1 |
|
弱会话
Weak Session IDs(弱会话),用户访问服务器的时候,一般服务器都会分配一个身份证 session id 给用户,用于标识。用户拿到 session id 后就会保存到 cookies 上,之后只要拿着 cookies 再访问服务器,服务器就知道你是谁了。但是 session id 过于简单就会容易被人伪造。根本都不需要知道用户的密码就能访问,用户服务器的内容了。
xss(dom)
XSS又叫CSS,跨站脚本攻击。它指的是恶意攻击者往web页面插入恶意的html代码。当用户浏览该页面时,嵌入到web里面的html代码会被运行,从而达到恶意攻击用户的特殊目的。
low
服务器端没有任何php代码,执行命令的只有客户端的js代码.在复选框中选择English,在上面的url地址栏中,我们会发现出现了English.顺势我们可以修改
medium
1 |
|
过滤掉了“<script”,当函数匹配到 <script 字符串的时候就会将URL后面的参数修正为 ?default=English.
可以通过onerror事件,在装载文档或图像的过程中如果发生了错误就会触发
1 |
|
白名单
如果default的值不为”French”、”English”、”German”、”Spanish”的话就重置URL为:?default=English ,这里只是对 default 的变量进行了过滤。
xss反射
反射型XSS的触发有后端的参与,而之所以触发XSS是因为后端解析用户在前端输入的带有XSS性质的脚本或者脚本的data URI编码,后端解析用户输入处理后返回给前端,由浏览器解析这段XSS脚本,触发XSS漏洞。
low
源代码中没有做任何限制
1 |
|
medium
1 |
|
str_replace函数,它是区分大小写的,因此可以使用大小写绕过
1 |
|
high
1 |
|
preg_replace() 函数执行一个正则表达式的搜索和替换,“*” 代表一个或多个任意字符,“i” 代表不区分大小写。也就是说 “< script >” 标签在这里被完全过滤了,但是我们可以通过其他的标签例如 img、body 等标签的事件或者iframe 等标签的 src 注入 JS 攻击脚本。
1 |
|
通过上述执行我们会发现,每次注入payload是一次性的,关闭页面再次进入我们会发现不会再执行,这与后面的存储型xss最大的区别。
xss已存储
XSS存储型攻击,攻击者事先将恶意代码上传或储存到漏洞服务器中,只要受害者浏览包含此恶意代码的页面就会执行恶意代码。这就意味着只要访问了这个页面的访客,都有可能会执行这段恶意脚本,因此储存型XSS的危害会更大。因为存储型XSS的代码存在于网页的代码中,可以说是永久型的。
存储型 XSS 一般出现在网站留言、评论、博客日志等交互处,恶意脚本存储到客户端或者服务端的数据库中。
low
1 |
|
对XSS方面没有做过滤与检查,而且数据将被存储到数据库中,因此存在存储型XSS
1 |
|
medium
1 |
|
Message处使用了htmlspecialchars()函数,将字符全部转为了HTML实体,因此Message处无法使用XSS形成攻击。
name处做了长度限制,因此考虑使用抓包在BP中修改name的值,还有就是他会将
high
源码如下,虽然此时后端已经没有设置白名单,但是还是会用 POST 方法传入 include 参数。
1 |
|
源码如下,在点击网页的按钮使 js 生成一个 script 标签,src 指向 source/jsonp.php?callback=solveNum。document 对象使我们可以从脚本中对 HTML 页面中的所有元素进行访问,createElement() 方法通过指定名称创建一个元素,body 属性提供对 < body > 元素的直接访问,对于定义了框架集的文档将引用最外层的 < frameset >。appendChild() 方法可向节点的子节点列表的末尾添加新的子节点,也就是网页会把 “source/jsonp.php?callback=solveNum” 加入到 DOM 中。
源码中定义了 solveNum 的函数,函数传入参数 obj,如果字符串 “answer” 在 obj 中就会执行。getElementById() 方法可返回对拥有指定 ID 的第一个对象的引用,innerHTML 属性设置或返回表格行的开始和结束标签之间的 HTML。这里的 script 标签会把远程加载的 solveSum({"answer":"15"}) 当作 js 代码执行, 然后这个函数就会在页面显示答案。
1 |
|
注意到需要向 “source/jsonp.php” 传入 “callback” 参数,这个参数并没有进行任何过滤,因此我们可以通过这个参数进行注入。
include=
javascript
low
1 |
|
直接提交success的话,是不可能成功的,因为提交的token值,是字符串ChangeMe进行md5加密后的token值,而不是success进行md5加密后的token值
根据源码审计的结果,token 的生成是基于 phrase 参数的,而现在该参数已经被我们覆盖了。因此现在我们重新拉取一下 token,在 Web 控制台运行generate_token() 函数。
如果运行 generate_token() 函数仍然注入失败,可以在包中手动修改 token。
md5(rot13(“Changeme”))
md5(rot13(“success”))
medium
攻击的方法和 low 差不多,首先注入 “success” 之后抓包看看,现在的 token 是 “XXChangMeXX” 的反转。
控制台运行下 do_elsesomething(“XX”) 函数,再次注入 “success” 即可
high
源码使用了js混淆
1 |
|
使用还原工具得到源码后得到关键代码部分如下。
1 |
|
由于执行 token_part_2(“XX”) 有 300 毫秒延时,所以 token_part_1(“ABCD”, 44) 会被先执行,而 token_part_3() 则是和提交按钮的 click 事件一起执行。
依次执行 token_part_1(“ABCD”, 44) 和 token_part_2(“XX”),最后点击提交执行 token_part_3()。