CSRF(跨站请求伪造)
CSRF是一种对网站的恶意利用,通过伪装来自受信任用户的请求来利用受信任的网站。
原理是攻击者构造网站后台某个功能接口的请求地址,诱导用户去点击或者用特殊方法让该请求地址自动加载。用户在登录状态下这个请求被服务端接收后会被误以为是用户合法的操作。
low
由题目可得是让我们修改密码
在输入两次相同的密码后点击change,跳转至以下页面,显示密码已修改
由url可知输入的两次密码会被传输至url执行
分析源码
low等级只是对传入密码和确认密码进行比较,若相等,则操作成功,不相等则操作不成功,可以轻易执行csrf漏洞,通过控制url即可达到在网站外执行修改密码的行为,通过在新建标签页中输入一个传入密码和修改密码都相等的url即可攻击成功
medium
分析源码
medium等级只是比low等级多出了一个判断请求是否是从dvwa这个网站发起的,若不是则不执行后面的操作
medium等级加上了对用户请求头的中的Referer字段进行验证。即用户的请求头中的Referer字段必须包含了服务器的名字
先新建一个页面并输入两个密码相等的url并访问页面
发现报错
打开bp,先抓包一个正常的本网站的,然后抓包一个在新建标签页复制url得到的,对比发现在本网站中是有referer的,而复制url的没有referer
将本网站的referer复制添加到新建标签页的抓包中,然后放包,得到password change ,攻击成功
high
分析源码
high等级加上了对token的验证,每次用户执行操作时都会生成一个随机的token,服务器会优先验证token,token存在且正确时才能进行后续操作
先正常输入两个相同的密码,然后抓包
说明需要绕过token
send to intruder
攻击方式选择pitchfork,选中两个密码和token
设置密码和确认密码,每个最好设置两个以上
在redirections中改为always
然后在grep-extract中add
点击refetch response,然后找到token复制,点击ok
返回payloads,修改类型为recursive grep,将复制的payloads粘贴上
修改线程为1,开始攻击
攻击成功
File Inclusion(文件包含)
low
分析源码
low等级只是通过get方式获取一个变量page,没有任何验证或过滤
点开页面上的文件file1/2/3.php,发现都有内容显示,而且url上会显示?page=...说明可以通过修改url上的参数来达到目的
上传一个?page=file4.php
medium
分析源码
medium等级比low等级多出了对http、https、/、\\的过滤
可以使用php伪协议
传入file://D:\phpstudy_pro\www\dvwa\php.ini
high
分析源码
high等级的源码中有对开头是否为file或是否等于include.php的验证,若不等于,则将会输出一个错误消息并退出
先传入一个?page=php.ini尝试一下
验证开头是否为file,那么传入medium等级的payload即可
补充
php伪协议
php伪协议指的是php所支持的协议与封装协议,在web渗透漏洞中常用于配合文件包含进行web攻击,从而获取网站权限
常见的php伪协议有:
file:// 访问本地文件系统
php://访问各个输入/输出流
data:// 数据
zip://压缩流
allow_url_fopen On/Off 允许或禁止打开URL文件
allow_url_include On/Off 允许或禁止引用URL文件
File Upload(文件上传)
文件上传漏洞是指用户上传了一个可执行的脚本文件(php、jsp、xml、cer等文件),并通过此脚本文件获得了执行服务器端命令的能力。
low
准备一个一句话木马123.php(phpinfo()可以用于显示php的配置信息)
上传发现上传成功
访问文件
分析源码
首先检查是否点击了upload按钮
然后将$target_path设置为DVWA_WEB_PAGE_TO_ROOT."hackable/uploads/",后面附加上传文件的原始名称(通过basename获取),说明上传文件将会被保存在hackable/uploads/目录下,并保持原始文件名
然后利用move_uploaded_file函数将临时文件移动到指定的目标路径,移动成功则返回true,输出文件成功上传的路径,移动失败则输出“your image was uploaded”
medium
仍然选择一句话木马文件上传,发现没有上传成功,根据报错得知仅接受jpeg或png图像
分析源码
medium等级比low等级多出了对文件信息(文件名,文件类型,文件大小)的提取,和文件类型的检查,检查文件类型是否为image/jepg或image/png,文件大小是否小于100000字节,若符合要求,则上传成功,若不符合,则报错
将123.php改名为111.jpg后上传文件,使用bp抓包
在bp中将文件名改为111.php,然后放包,上传成功
查看文件
high
一句话木马先上传,发现报错,报错与medium相同
分析源码
high等级比medium等级多出了对文件扩展名upload_ext和临时文件名upload_tmp的提取
然后检查文件扩展名是否为jpg,jpeg,png,文件大小是否为100000字节
最后用getimagesize()函数检查文件是否为一个有效图像,若有效,返回一个包含图像信息的数组,若不是有效,返回false
可以选择图片马进行上传
先制作图片马
上传3.png,上传成功
Insecure CAPTCHA(不安全的验证码)
low
页面上面显示配置文件中缺少 reCAPTCHA API 密钥:,根据提示打开文件设置好即可,然后刷新
发现是一个修改密码的页面
分析源码
第一部分是当post发送的change还有step=1时,进行后续操作,如果点击了change按钮且发送的step=1,则将hide_form的值设置为true,(通常表示后续的验证码表单将会被隐藏或不在显示),然后获取用户输入的新密码和确认密码,然后通过调用recaptcha_check_answer()函数来验证验证用户提交的reCAPTCHA响应,如果验证错误,会在html中加入一个报错,hide_form的值变为false,return终止程序运行,如果验证正确,继续验证新密码和确认密码,如果密码匹配,它会显示一个确认更改的表单;如果密码不匹配,它会显示一个错误消息。
第二部分是当成功设置了change键,step=2时,进行后续操作,先设置hide_form值为true,然后获取用户输入的新密码和确认密码并验证,如果验证正确,先使用mysqli_real_escape_string()函数对密码进行转义,若GLOBALS["__mysqli_ston"]不存在或不是一个对象,代码将触发一个错误。然后,使用MD5算法对密码进行散列。然后将用户密码更新为新的散列密码,并执行该语句。如果查询失败,将显示错误信息并停止脚本执行。如果密码成功更新,向用户显示成功,如果新密码和确认密码不匹配,显示错误消息,并将hide_form的值变为false,,以便再次显示验证码表单。
从源码可知,当存在change还有step=2时,可以进行修改密码的操作
输入密码后抓包
将step的值改为2后放包,发现修改成功
medium
分析源码
medium等级比low等级多出了对passed_captcha的验证
输入密码后抓包,先将step的值改为2然后放包
报错提示没有通过CAPTCHA的验证
根据源码,在下面添加上passed_captcha=true,放包
修改成功
high
分析源码
high等级检查了g_recptcha_response的值是否为hidd3n_valu3,还有对user agent的值是否为reCAPTCHA的检查
输入密码,抓包,然后将相应的值修改后放包
修改成功
SQL Injection(SQL注入)
low
发现是要提交一个userid
当输入1的时候,没有报错且页面返回正常
当输入1'的时候,报错,说明存在注入
然后通过order by查看字段长度
传入1' and 1=1 order by 2#回显正常
传入1' and 1=1 order by 3#发现报错,说明有2个字段长度
传入1' and 1=1 union select 1,2#查看回显
传入1' and 1=1 union select 1,database()#,查看数据库名
得到数据库名为dvwa
传入1’ and 1=1 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #爆表
如果报错可能是编码问题
解决方法:打开phpadmin,修改编码方式
执行后传入1’ and 1=1 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #
得到两个表名,guestbook和users
传入1' union select user,password from users #获取user字段的数据
分析源码
首先检查是否设置了submit请求,然后直接从请求中获取id的值,然后根据配置决定使用MySQL数据库还是sqlite数据库,使用两个数据库都是先执行查询,然后提取数据并向用户返回查询结果
medium
medium等级的userid变成了下拉框,无法自主控制查询内容
分析源码
在此处添加了对用户输入的处理,使用mysqli_real_escape_string函数对id进行转义,以防止SQL注入攻击
在最后执行一个SQL查询计算user表中的行数,并在完成后关闭数据库连接。
提交id=1,抓包,发送请求
将id=1改为id=1‘发现报错
输入id=1 order by 2#
id=1 order by 3#
发现有两个字段
输入1 union select 1,database()#得到数据库名为dvwa
输入1 union select table_name,table_schema from information_schema.tables where table_schema= database()#爆表
输入1 union select 1, group_concat(column_name) from information_schema.columns where table_name=‘users’#查看字段名
发现报错,因为源码中对输入的数据进行了转义,所以需要绕过
使用十六进制绕过,users的十六进制为0x7573657273
所以输入1 union select 1, group_concat(column_name) from information_schema.columns where table_name=0x7573657273#进行查看
输入1 union select user,password from users查看users的内容
high
打开页面,发现让点击进行对id的修改
当输入1的时候,没有报错且页面返回正常
当输入1'的时候,报错
操作与low一样,传入1' union select user,password from users #时可以获取user字段的数据
SQL Injection (Blind)(sql盲注)
Weak Session IDs(弱会话ID)
弱会话
弱会话 ID(Weak Session ID)指的是具有可预测性、易猜测或容易被攻击者破解的会话 ID。这意味着攻击者可以通过猜测会话 ID 的值或使用可预测的模式,获取合法用户的会话标识并冒充该用户。
low
提示每点击一次按钮就会创造一个新的cookie
分析源码
首先检查请求方法是否为post,然后设置会话变量,当会话变量不存在时,初始化为·0,但每次post请求会话变量的值都会递增,然后设置cookie先给$cookie_value赋值为会话变量的当前值,然后使用setcookie函数设置cookie,值为会话变量的当前值
用bp抓包,获得cookie
清除浏览器的cookie缓存,代表dvwa未在该浏览器登录过,然后新建标签页,输入cookie
发现登陆成功
medium
分析源码
先初始化一个html变量,设置为空字符串,然后检查请求方法是否为post,若是post,代码会获取时间戳(自 Unix 纪元(1970 年 1 月 1 日 00:00:00 GMT)起的秒数),并将其存储在$cookie_value变量中,然后使用setcookie函数设置cookie,值为当前时间戳
bp抓包,发送至repeater,获得时间戳
然后操作同low等级,清除cookie缓存,新建页面,输入时间戳和cookie,登陆成功
high
分析源码
先初始化一个html变量,设置为空字符串,然后检查请求方式是否为post,然后设置会话变量,若不存在,初始化为0,每次post请求时值会递增,然后生成cookie$cookie_value被赋值为会话变量当前值的哈希值,然后设置cookie,过期时间设置为1小时后,路径被限制为/vulnerabilities/weak_id/,域名设置为当期南请求单主机名,两个false表示,不仅一个通过http传输,也不能被JavaScript访问
bp抓包,发送至repeater,获取cookie
解密得到值为1
选择下一个值加密
删除缓存,新建页面,输入cookie,登陆成功
DOM Based Cross Site Scripting (XSS)(基于dom的跨站脚本)
xss是一种常见的安全漏洞,指恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的
类型:
存储型 XSS(Stored XSS):攻击者将恶意代码存储到目标网站的数据库中,当其他用户浏览相关页面时,恶意代码会从服务器上返回并在用户的浏览器中执行
反射型 XSS(Reflected XSS):攻击者通过构造带有恶意代码的URL,并诱导用户点击该链接,服务器接收到请求后,将恶意代码反射回用户的浏览器并执行
DOM 型 XSS(DOM-based XSS):攻击者利用网页的 DOM(文档对象模型)结构漏洞,修改了网页的内容,使得恶意代码被执行
low
点击开发现是一个选择语言的页面
当修改语言并提交时发现url上也会出现变化
说明可以通过defult进行传参
传入xss代码
<script>alert(1)</script>
这是一个简单的 JavaScript 代码片段,它会在浏览器中弹出一个警告框(Alert box)显示数字 "1"。
medium
分析源码
首先检查是否get请求中有defult,且值不为null,若存在,赋值给$defult,然后使用stripos函数检查$defult是否包含字符串<script,如果包含,重定向
也就是说,过滤了<script标签
使用事件型
<img src=# οnerrοr=alert(1)>
检查元素,发现在select中
闭合标签
high
分析源码
代码使用白名单来限制default的值,如果输入的值不在白名单中,将会重定向回?default=english
使用#绕过
#<script>alert(1)</script>
Reflected Cross Site Scripting (XSS)(反射跨站脚本)
low
分析源码
没有任何过滤,直接传入xss代码即可
<script>alert(1)</script>
medium
分析源码
medium比low多出了对<script>标签的过滤,可以使用大小写混合、添加空格等方式来绕过这种
传入<scri<script>pt>alert(1)</script>
high
随意传入一个值,发现会显示
分析源码
首先禁用了反射型跨站保护机制,然后检查是否get请求中存在name参数且值不为null,然后使用preg_replace过滤掉可能的<script>标签,但是过滤不完全,可以使用大小写混合、插入空格或其他字符等方式来绕过过滤
采用事件型
<img src=1 οnerrοr=alert(1)>
Stored Cross Site Scripting (XSS)(储存式)
low
分析源码
首先检查是否设置了$_post['btnsign'],然后获取两个字段的值,使用trim函数出去前后空格
然后通过stripslashes函数移除斜杠,然后转义,检查$GLOBALS["__mysqli_ston"]是否存在且是一个对象,$name变量同理,然后将message和name插入guestbook表中
传入xss代码
<script>alert(1)</script>
medium
分析源码
medium比low多出了对<scrpit>标签的过滤
双写绕过
<scri<script>pt>alert(1)</script>
high
分析源码
high等级用preg_replace移除任何包含<script>标签的内容
传入事件型
<img src=1 οnerrοr=alert(1)>
Content Security Policy (CSP) Bypass(内容安全策略)
CSP 是一种用于增强 Web 应用程序安全性的安全机制。它通过允许网站管理员控制页面中加载内容的来源来减少跨站脚本攻击(XSS)等常见的安全风险。
工作原理是通过定义一组策略规则,指定哪些来源可以被信任和允许加载到页面中。这些来源可以是同源的网址、特定的域名、安全连接(如 HTTPS)或者是内联脚本和样式表。 CSP 可以阻止恶意代码、恶意插件或其他不受信任的资源被加载到页面上,从而增加页面的安全性。
low
您可以包含来自外部源的脚本,检查内容安全策略并输入要包含在此处的 URL:
分析源码
首先定义一个csp头部,限制一些域名可以被1用于脚本源,然后将这个csp头部添加到http响应中,提交表单时,将提交的url用作<script>的src属性,将该脚本包含到页面中,然后通过$page['body'],构建页面主体内容
通过分析可以看到被信任的网站有:
https://pastebin.com、example.com、code.jquery.com、https://ssl.google-analytics.com。
将代码保存在 https://pastebin.com 网站,然后把链接发送给需要攻击的用户,用户点击后,达到注入目的
alert(“1”)
点击raw后,复制链接,发送至页面即可
medium
分析源码
先定义一个csp头部,指定脚本只能从当前页面加载,允许内联脚本,要求所有内联脚本必须包含一个有效的nonce,用于确定脚本内容是由受信任的源提供
然后将x-xss-protection头部设置为0,即禁用了浏览器的xss保护机制
直接将源码中的注释发送即可
high
该页面调用 ../..//vulnerability/csp/source/jsonp.php 来加载一些代码。修改该页面以运行您自己的代码
分析源码
第一段源码首先先定义一个csp头部,指定脚本只能从当前页面加载
通过<script src="source/high.js"></sript>引入一个 的外部 JavaScript 文件
第二段代码先通过clickbutton函数创建一个新元素存储在变量s中,将新元素的src属性设置为"source/jsonp.php?callback=solveSum",当脚本加载时,调用solvesum函数,将返回的数据作为参数传递,将新元素添加到body中,触发对source/jsonp.php
的请求
然后solvesum函数接受一个通过 JSONP 请求从 source/jsonp.php
返回的对象作为参数,然后检查传入对象obj
是否包含一个名为 “answer”
的属性,若存在,设置为内部html
通过 document.getElementById("solve")
获取 id 为 "solve"
的元素,并将其存储在变量 solve_button
中,如果找到了这个元素(即 solve_button
不是 null
),则给它添加一个点击事件监听器,当这个按钮被点击时,调用 clickButton
函数,从而触发对 source/jsonp.php
的 JSONP 请求。
传入include=<script src="source/jsonp.php?callback=alert('xss');"></script>
JavaScript Attacks(javascript攻击)
low
直接提交发现无效
分析源码
使用 md5 加密在前端生成了 token,generate_token() 函数的作用是获取 “phrase” 参数中的值,将rot13 加密的结果再进行 md5 加密作为 token 的值。
直接注入success,发现token无效
说明提交的虽然是success,但是token还是ChangeMe的,因为generate_token()方法不会自动执行,需要在前端调用generate_token()方法生成相应token
抓包,修改token
medium
第一段代码是在页面 body 的末尾插入一个外部 JavaScript 文件的链接,以便在浏览器加载该页面时执行该 JavaScript 文件中的代码
第二段代码的大概流程为页面加载后等待 0.3 秒,然后调用 do_elsesomething
函数,传入 "XX" 作为参数,do_elsesomething
函数获取 ID 为 "phrase" 的元素的值,将其与 "XX" 拼接,然后反转这个拼接后的字符串,最后,将反转后的字符串设置为 ID 为 "token" 的元素的值
更换了加密方法
抓包
token 是 “XXChangMeXX” 的反转,在控制台运行下 do_elsesomething("XX") 函数
使用bp将输入框的值改为XXsseccusXX即可
high
分析源码
发现是一堆乱码,解码
http://deobfuscatejavascript.com/#
(function() {
'use strict';
var ERROR = 'input is invalid type';
var WINDOW = typeof window === 'object';
var root = WINDOW ? window : {};
if (root.JS_SHA256_NO_WINDOW) {
WINDOW = false
}
var WEB_WORKER = !WINDOW && typeof self === 'object';
var NODE_JS = !root.JS_SHA256_NO_NODE_JS && typeof process === 'object' && process.versions && process.versions.node;
if (NODE_JS) {
root = global
} else if (WEB_WORKER) {
root = self
}
var COMMON_JS = !root.JS_SHA256_NO_COMMON_JS && typeof module === 'object' && module.exports;
var AMD = typeof define === 'function' && define.amd;
var ARRAY_BUFFER = !root.JS_SHA256_NO_ARRAY_BUFFER && typeof ArrayBuffer !== 'undefined';
var HEX_CHARS = '0123456789abcdef'.split('');
var EXTRA = [-2147483648, 8388608, 32768, 128];
var SHIFT = [24, 16, 8, 0];
var K = [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2];
var OUTPUT_TYPES = ['hex', 'array', 'digest', 'arrayBuffer'];
var blocks = [];
if (root.JS_SHA256_NO_NODE_JS || !Array.isArray) {
Array.isArray = function(obj) {
return Object.prototype.toString.call(obj) === '[object Array]'
}
}
if (ARRAY_BUFFER && (root.JS_SHA256_NO_ARRAY_BUFFER_IS_VIEW || !ArrayBuffer.isView)) {
ArrayBuffer.isView = function(obj) {
return typeof obj === 'object' && obj.buffer && obj.buffer.constructor === ArrayBuffer
}
}
var createOutputMethod = function(outputType, is224) {
return function(message) {
return new Sha256(is224, true).update(message)[outputType]()
}
};
var createMethod = function(is224) {
var method = createOutputMethod('hex', is224);
if (NODE_JS) {
method = nodeWrap(method, is224)
}
method.create = function() {
return new Sha256(is224)
};
method.update = function(message) {
return method.create().update(message)
};
for (var i = 0; i < OUTPUT_TYPES.length; ++i) {
var type = OUTPUT_TYPES[i];
method[type] = createOutputMethod(type, is224)
}
return method
};
var nodeWrap = function(method, is224) {
var crypto = eval("require('crypto')");
var Buffer = eval("require('buffer').Buffer");
var algorithm = is224 ? 'sha224' : 'sha256';
var nodeMethod = function(message) {
if (typeof message === 'string') {
return crypto.createHash(algorithm).update(message, 'utf8').digest('hex')
} else {
if (message === null || message === undefined) {
throw new Error(ERROR)
} else if (message.constructor === ArrayBuffer) {
message = new Uint8Array(message)
}
}
if (Array.isArray(message) || ArrayBuffer.isView(message) || message.constructor === Buffer) {
return crypto.createHash(algorithm).update(new Buffer(message)).digest('hex')
} else {
return method(message)
}
};
return nodeMethod
};
var createHmacOutputMethod = function(outputType, is224) {
return function(key, message) {
return new HmacSha256(key, is224, true).update(message)[outputType]()
}
};
var createHmacMethod = function(is224) {
var method = createHmacOutputMethod('hex', is224);
method.create = function(key) {
return new HmacSha256(key, is224)
};
method.update = function(key, message) {
return method.create(key).update(message)
};
for (var i = 0; i < OUTPUT_TYPES.length; ++i) {
var type = OUTPUT_TYPES[i];
method[type] = createHmacOutputMethod(type, is224)
}
return method
};
function Sha256(is224, sharedMemory) {
if (sharedMemory) {
blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] = blocks[4] = blocks[5] = blocks[6] = blocks[7] = blocks[8] = blocks[9] = blocks[10] = blocks[11] = blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
this.blocks = blocks
} else {
this.blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
}
if (is224) {
this.h0 = 0xc1059ed8;
this.h1 = 0x367cd507;
this.h2 = 0x3070dd17;
this.h3 = 0xf70e5939;
this.h4 = 0xffc00b31;
this.h5 = 0x68581511;
this.h6 = 0x64f98fa7;
this.h7 = 0xbefa4fa4
} else {
this.h0 = 0x6a09e667;
this.h1 = 0xbb67ae85;
this.h2 = 0x3c6ef372;
this.h3 = 0xa54ff53a;
this.h4 = 0x510e527f;
this.h5 = 0x9b05688c;
this.h6 = 0x1f83d9ab;
this.h7 = 0x5be0cd19
}
this.block = this.start = this.bytes = this.hBytes = 0;
this.finalized = this.hashed = false;
this.first = true;
this.is224 = is224
}
Sha256.prototype.update = function(message) {
if (this.finalized) {
return
}
var notString, type = typeof message;
if (type !== 'string') {
if (type === 'object') {
if (message === null) {
throw new Error(ERROR)
} else if (ARRAY_BUFFER && message.constructor === ArrayBuffer) {
message = new Uint8Array(message)
} else if (!Array.isArray(message)) {
if (!ARRAY_BUFFER || !ArrayBuffer.isView(message)) {
throw new Error(ERROR)
}
}
} else {
throw new Error(ERROR)
}
notString = true
}
var code, index = 0,
i, length = message.length,
blocks = this.blocks;
while (index < length) {
if (this.hashed) {
this.hashed = false;
blocks[0] = this.block;
blocks[16] = blocks[1] = blocks[2] = blocks[3] = blocks[4] = blocks[5] = blocks[6] = blocks[7] = blocks[8] = blocks[9] = blocks[10] = blocks[11] = blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0
}
if (notString) {
for (i = this.start; index < length && i < 64; ++index) {
blocks[i >> 2] |= message[index] << SHIFT[i++ & 3]
}
} else {
for (i = this.start; index < length && i < 64; ++index) {
code = message.charCodeAt(index);
if (code < 0x80) {
blocks[i >> 2] |= code << SHIFT[i++ & 3]
} else if (code < 0x800) {
blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]
} else if (code < 0xd800 || code >= 0xe000) {
blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]
} else {
code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff));
blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]
}
}
}
this.lastByteIndex = i;
this.bytes += i - this.start;
if (i >= 64) {
this.block = blocks[16];
this.start = i - 64;
this.hash();
this.hashed = true
} else {
this.start = i
}
}
if (this.bytes > 4294967295) {
this.hBytes += this.bytes / 4294967296 << 0;
this.bytes = this.bytes % 4294967296
}
return this
};
Sha256.prototype.finalize = function() {
if (this.finalized) {
return
}
this.finalized = true;
var blocks = this.blocks,
i = this.lastByteIndex;
blocks[16] = this.block;
blocks[i >> 2] |= EXTRA[i & 3];
this.block = blocks[16];
if (i >= 56) {
if (!this.hashed) {
this.hash()
}
blocks[0] = this.block;
blocks[16] = blocks[1] = blocks[2] = blocks[3] = blocks[4] = blocks[5] = blocks[6] = blocks[7] = blocks[8] = blocks[9] = blocks[10] = blocks[11] = blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0
}
blocks[14] = this.hBytes << 3 | this.bytes >>> 29;
blocks[15] = this.bytes << 3;
this.hash()
};
Sha256.prototype.hash = function() {
var a = this.h0,
b = this.h1,
c = this.h2,
d = this.h3,
e = this.h4,
f = this.h5,
g = this.h6,
h = this.h7,
blocks = this.blocks,
j, s0, s1, maj, t1, t2, ch, ab, da, cd, bc;
for (j = 16; j < 64; ++j) {
t1 = blocks[j - 15];
s0 = ((t1 >>> 7) | (t1 << 25)) ^ ((t1 >>> 18) | (t1 << 14)) ^ (t1 >>> 3);
t1 = blocks[j - 2];
s1 = ((t1 >>> 17) | (t1 << 15)) ^ ((t1 >>> 19) | (t1 << 13)) ^ (t1 >>> 10);
blocks[j] = blocks[j - 16] + s0 + blocks[j - 7] + s1 << 0
}
bc = b & c;
for (j = 0; j < 64; j += 4) {
if (this.first) {
if (this.is224) {
ab = 300032;
t1 = blocks[0] - 1413257819;
h = t1 - 150054599 << 0;
d = t1 + 24177077 << 0
} else {
ab = 704751109;
t1 = blocks[0] - 210244248;
h = t1 - 1521486534 << 0;
d = t1 + 143694565 << 0
}
this.first = false
} else {
s0 = ((a >>> 2) | (a << 30)) ^ ((a >>> 13) | (a << 19)) ^ ((a >>> 22) | (a << 10));
s1 = ((e >>> 6) | (e << 26)) ^ ((e >>> 11) | (e << 21)) ^ ((e >>> 25) | (e << 7));
ab = a & b;
maj = ab ^ (a & c) ^ bc;
ch = (e & f) ^ (~e & g);
t1 = h + s1 + ch + K[j] + blocks[j];
t2 = s0 + maj;
h = d + t1 << 0;
d = t1 + t2 << 0
}
s0 = ((d >>> 2) | (d << 30)) ^ ((d >>> 13) | (d << 19)) ^ ((d >>> 22) | (d << 10));
s1 = ((h >>> 6) | (h << 26)) ^ ((h >>> 11) | (h << 21)) ^ ((h >>> 25) | (h << 7));
da = d & a;
maj = da ^ (d & b) ^ ab;
ch = (h & e) ^ (~h & f);
t1 = g + s1 + ch + K[j + 1] + blocks[j + 1];
t2 = s0 + maj;
g = c + t1 << 0;
c = t1 + t2 << 0;
s0 = ((c >>> 2) | (c << 30)) ^ ((c >>> 13) | (c << 19)) ^ ((c >>> 22) | (c << 10));
s1 = ((g >>> 6) | (g << 26)) ^ ((g >>> 11) | (g << 21)) ^ ((g >>> 25) | (g << 7));
cd = c & d;
maj = cd ^ (c & a) ^ da;
ch = (g & h) ^ (~g & e);
t1 = f + s1 + ch + K[j + 2] + blocks[j + 2];
t2 = s0 + maj;
f = b + t1 << 0;
b = t1 + t2 << 0;
s0 = ((b >>> 2) | (b << 30)) ^ ((b >>> 13) | (b << 19)) ^ ((b >>> 22) | (b << 10));
s1 = ((f >>> 6) | (f << 26)) ^ ((f >>> 11) | (f << 21)) ^ ((f >>> 25) | (f << 7));
bc = b & c;
maj = bc ^ (b & d) ^ cd;
ch = (f & g) ^ (~f & h);
t1 = e + s1 + ch + K[j + 3] + blocks[j + 3];
t2 = s0 + maj;
e = a + t1 << 0;
a = t1 + t2 << 0
}
this.h0 = this.h0 + a << 0;
this.h1 = this.h1 + b << 0;
this.h2 = this.h2 + c << 0;
this.h3 = this.h3 + d << 0;
this.h4 = this.h4 + e << 0;
this.h5 = this.h5 + f << 0;
this.h6 = this.h6 + g << 0;
this.h7 = this.h7 + h << 0
};
Sha256.prototype.hex = function() {
this.finalize();
var h0 = this.h0,
h1 = this.h1,
h2 = this.h2,
h3 = this.h3,
h4 = this.h4,
h5 = this.h5,
h6 = this.h6,
h7 = this.h7;
var hex = HEX_CHARS[(h0 >> 28) & 0x0F] + HEX_CHARS[(h0 >> 24) & 0x0F] + HEX_CHARS[(h0 >> 20) & 0x0F] + HEX_CHARS[(h0 >> 16) & 0x0F] + HEX_CHARS[(h0 >> 12) & 0x0F] + HEX_CHARS[(h0 >> 8) & 0x0F] + HEX_CHARS[(h0 >> 4) & 0x0F] + HEX_CHARS[h0 & 0x0F] + HEX_CHARS[(h1 >> 28) & 0x0F] + HEX_CHARS[(h1 >> 24) & 0x0F] + HEX_CHARS[(h1 >> 20) & 0x0F] + HEX_CHARS[(h1 >> 16) & 0x0F] + HEX_CHARS[(h1 >> 12) & 0x0F] + HEX_CHARS[(h1 >> 8) & 0x0F] + HEX_CHARS[(h1 >> 4) & 0x0F] + HEX_CHARS[h1 & 0x0F] + HEX_CHARS[(h2 >> 28) & 0x0F] + HEX_CHARS[(h2 >> 24) & 0x0F] + HEX_CHARS[(h2 >> 20) & 0x0F] + HEX_CHARS[(h2 >> 16) & 0x0F] + HEX_CHARS[(h2 >> 12) & 0x0F] + HEX_CHARS[(h2 >> 8) & 0x0F] + HEX_CHARS[(h2 >> 4) & 0x0F] + HEX_CHARS[h2 & 0x0F] + HEX_CHARS[(h3 >> 28) & 0x0F] + HEX_CHARS[(h3 >> 24) & 0x0F] + HEX_CHARS[(h3 >> 20) & 0x0F] + HEX_CHARS[(h3 >> 16) & 0x0F] + HEX_CHARS[(h3 >> 12) & 0x0F] + HEX_CHARS[(h3 >> 8) & 0x0F] + HEX_CHARS[(h3 >> 4) & 0x0F] + HEX_CHARS[h3 & 0x0F] + HEX_CHARS[(h4 >> 28) & 0x0F] + HEX_CHARS[(h4 >> 24) & 0x0F] + HEX_CHARS[(h4 >> 20) & 0x0F] + HEX_CHARS[(h4 >> 16) & 0x0F] + HEX_CHARS[(h4 >> 12) & 0x0F] + HEX_CHARS[(h4 >> 8) & 0x0F] + HEX_CHARS[(h4 >> 4) & 0x0F] + HEX_CHARS[h4 & 0x0F] + HEX_CHARS[(h5 >> 28) & 0x0F] + HEX_CHARS[(h5 >> 24) & 0x0F] + HEX_CHARS[(h5 >> 20) & 0x0F] + HEX_CHARS[(h5 >> 16) & 0x0F] + HEX_CHARS[(h5 >> 12) & 0x0F] + HEX_CHARS[(h5 >> 8) & 0x0F] + HEX_CHARS[(h5 >> 4) & 0x0F] + HEX_CHARS[h5 & 0x0F] + HEX_CHARS[(h6 >> 28) & 0x0F] + HEX_CHARS[(h6 >> 24) & 0x0F] + HEX_CHARS[(h6 >> 20) & 0x0F] + HEX_CHARS[(h6 >> 16) & 0x0F] + HEX_CHARS[(h6 >> 12) & 0x0F] + HEX_CHARS[(h6 >> 8) & 0x0F] + HEX_CHARS[(h6 >> 4) & 0x0F] + HEX_CHARS[h6 & 0x0F];
if (!this.is224) {
hex += HEX_CHARS[(h7 >> 28) & 0x0F] + HEX_CHARS[(h7 >> 24) & 0x0F] + HEX_CHARS[(h7 >> 20) & 0x0F] + HEX_CHARS[(h7 >> 16) & 0x0F] + HEX_CHARS[(h7 >> 12) & 0x0F] + HEX_CHARS[(h7 >> 8) & 0x0F] + HEX_CHARS[(h7 >> 4) & 0x0F] + HEX_CHARS[h7 & 0x0F]
}
return hex
};
Sha256.prototype.toString = Sha256.prototype.hex;
Sha256.prototype.digest = function() {
this.finalize();
var h0 = this.h0,
h1 = this.h1,
h2 = this.h2,
h3 = this.h3,
h4 = this.h4,
h5 = this.h5,
h6 = this.h6,
h7 = this.h7;
var arr = [(h0 >> 24) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 8) & 0xFF, h0 & 0xFF, (h1 >> 24) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 8) & 0xFF, h1 & 0xFF, (h2 >> 24) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 8) & 0xFF, h2 & 0xFF, (h3 >> 24) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 8) & 0xFF, h3 & 0xFF, (h4 >> 24) & 0xFF, (h4 >> 16) & 0xFF, (h4 >> 8) & 0xFF, h4 & 0xFF, (h5 >> 24) & 0xFF, (h5 >> 16) & 0xFF, (h5 >> 8) & 0xFF, h5 & 0xFF, (h6 >> 24) & 0xFF, (h6 >> 16) & 0xFF, (h6 >> 8) & 0xFF, h6 & 0xFF];
if (!this.is224) {
arr.push((h7 >> 24) & 0xFF, (h7 >> 16) & 0xFF, (h7 >> 8) & 0xFF, h7 & 0xFF)
}
return arr
};
Sha256.prototype.array = Sha256.prototype.digest;
Sha256.prototype.arrayBuffer = function() {
this.finalize();
var buffer = new ArrayBuffer(this.is224 ? 28 : 32);
var dataView = new DataView(buffer);
dataView.setUint32(0, this.h0);
dataView.setUint32(4, this.h1);
dataView.setUint32(8, this.h2);
dataView.setUint32(12, this.h3);
dataView.setUint32(16, this.h4);
dataView.setUint32(20, this.h5);
dataView.setUint32(24, this.h6);
if (!this.is224) {
dataView.setUint32(28, this.h7)
}
return buffer
};
function HmacSha256(key, is224, sharedMemory) {
var i, type = typeof key;
if (type === 'string') {
var bytes = [],
length = key.length,
index = 0,
code;
for (i = 0; i < length; ++i) {
code = key.charCodeAt(i);
if (code < 0x80) {
bytes[index++] = code
} else if (code < 0x800) {
bytes[index++] = (0xc0 | (code >> 6));
bytes[index++] = (0x80 | (code & 0x3f))
} else if (code < 0xd800 || code >= 0xe000) {
bytes[index++] = (0xe0 | (code >> 12));
bytes[index++] = (0x80 | ((code >> 6) & 0x3f));
bytes[index++] = (0x80 | (code & 0x3f))
} else {
code = 0x10000 + (((code & 0x3ff) << 10) | (key.charCodeAt(++i) & 0x3ff));
bytes[index++] = (0xf0 | (code >> 18));
bytes[index++] = (0x80 | ((code >> 12) & 0x3f));
bytes[index++] = (0x80 | ((code >> 6) & 0x3f));
bytes[index++] = (0x80 | (code & 0x3f))
}
}
key = bytes
} else {
if (type === 'object') {
if (key === null) {
throw new Error(ERROR)
} else if (ARRAY_BUFFER && key.constructor === ArrayBuffer) {
key = new Uint8Array(key)
} else if (!Array.isArray(key)) {
if (!ARRAY_BUFFER || !ArrayBuffer.isView(key)) {
throw new Error(ERROR)
}
}
} else {
throw new Error(ERROR)
}
}
if (key.length > 64) {
key = (new Sha256(is224, true)).update(key).array()
}
var oKeyPad = [],
iKeyPad = [];
for (i = 0; i < 64; ++i) {
var b = key[i] || 0;
oKeyPad[i] = 0x5c ^ b;
iKeyPad[i] = 0x36 ^ b
}
Sha256.call(this, is224, sharedMemory);
this.update(iKeyPad);
this.oKeyPad = oKeyPad;
this.inner = true;
this.sharedMemory = sharedMemory
}
HmacSha256.prototype = new Sha256();
HmacSha256.prototype.finalize = function() {
Sha256.prototype.finalize.call(this);
if (this.inner) {
this.inner = false;
var innerHash = this.array();
Sha256.call(this, this.is224, this.sharedMemory);
this.update(this.oKeyPad);
this.update(innerHash);
Sha256.prototype.finalize.call(this)
}
};
var exports = createMethod();
exports.sha256 = exports;
exports.sha224 = createMethod(true);
exports.sha256.hmac = createHmacMethod();
exports.sha224.hmac = createHmacMethod(true);
if (COMMON_JS) {
module.exports = exports
} else {
root.sha256 = exports.sha256;
root.sha224 = exports.sha224;
if (AMD) {
define(function() {
return exports
})
}
}
})();
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);
核心代码为
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);
首先将phrase 的值清空document.getElementById(“phrase”).value = “”;然后执行token_part_1(a, b),取phrase值并进行字符串翻转(逆序)处理。延迟300ms后执行token_part_2(e = “YY”),传入参数字符串’XX’和token值拼接并调用sha256()加密。点击按钮时执行token_part_3(t, y = “ZZ”),将token值和字符串’ZZ’拼接并调用sha256()加密,从而得到最终的token。在输入框输入 success 后,再到控制台输入token_part_1(“ABCD”, 44)和token_part_2(“XX”)这两个函数,最后点击按钮执行token_part_3()
Authorisation Bypass(授权绕过)
low
分析发现没有过滤
直接vulnerabilities/authbypass/即可
medium
检查当前用户是否不是管理员("admin")。如果不是管理员,执行以下操作:打印 "Unauthorised"(未授权),禁止访问,同时终止脚本执行
发现源代码有过滤,必须用户名是admin,试着访问/vulnerabilities/authbypass/get_user_data.php来查看用户数据
high
代码用于检查当前用户是否是管理员用户。如果不是管理员用户,则输出"Unauthorised"并设置HTTP响应状态码为403(表示禁止访问),然后退出脚本。
Open HTTP Redirect
low
首先是否存在名为 "redirect" 的键,并且该键的值不为空,然后通过 header ("location: " . $_GET['redirect']); 语句进行重定向,将浏览器重定向到 $_GET['redirect'] 指定的 URL,进行重定向之前使用 exit确保脚本停止执行,,若不存在 "redirect" 参数或者该参数的值为空,代码会设置 HTTP 响应码为 500,并报错 "Missing redirect target.",最后使用 exit确保脚本停止执行
随机点击一个
构建source/info.php?redirect=https://www.baidu.com
发现报错
构建low.php?redirect=https://www.baidu.com
medium
加入了对路径是否为绝对路径的判断,防止对外部域名的绝对 URL 进行重定向
传入127.0.0.1/dvwa/vulnerabilities/open_redirect/source/medium.php?redirect=//www.baidu.com
high
如果 redirect 参数存在并且其值不为空,代码将进入下一个判断:检查redirect参数的值是否包含 "info.php"。 如果包含 "info.php",则使用 `header` 函数将用户重定向到 `redirect` 参数指定的 URL,如果不包含 "info.php",则返回一个 HTTP 500 错误,并显示一个消息告诉用户只能重定向到 info 页面
传入127.0.0.1/dvwa/vulnerabilities/open_redirect/source/high.php?redirect=https://www.baidu.com/?wd=info.php
成功跳转