0x00 前言
没啥师傅带,自闭学web安全,上班摸鱼学学开发的知识,前期在B站根据黑马程序员的java学习路线刷完了基础篇:javaSE、servlet+jsp、spring、springmvc、springboot,尝试通关下webgoat和代码阅读来检验下学习成果
关于webgoat前期安装部署步骤图就略过了。github下载,通过maven导入模块,idea会自动下载所需的jar包,然后运行主配置文件就能跑起来了。没什么需要配置的
一、java Web必备的基础知识与webgoat介绍
1. web项目架构
1.1 java web开发的技术规范与演化
对于java web开发流行的技术路线而言,主要是三个阶段,第一个阶段是servlet+jsp,目前应该只有很老很老的万年老网站还在使用,第二阶段是ssh,应该也很少了,第三阶段是ssm与ssj,对于国内使用较多的是ssm,webgoat项目使用的是ssj,而spring boot不是什么新技术,他只是一个快速部署项目的工具框架,相对springmvc省去一些基础或固定项目代码的编写,使代码开发更加配置化,更加简单,好比一键日卫星。
1.2 各java技术框架的角色与功能简述
servlet
:一个javaEE规范,以tomcat容器为例,它实现了servlet规范,通过识别http请求路径和参数等,将请求的参数交给匹配到相关路径的实现了servlet接口的类来处理,处理完成后将结果以html的形式返回给客户端浏览器,第一阶段的jsp就是负责前端页面的处理,jsp文件类似于php文件,可以写html,也可以写java代码,servlet处理完的结果被jsp文件读取填入,前后端不分离,耦合高,开发难度大spring
:一个伟大的技术框架,一个复杂的java程序本质上就是各种类和方法的互相依赖和调用,导致文件耦合度很高,spring核心功能实现了类的自动加载与生命周期管理,例如A类有一个属性b需要引用B类,以前是需要写成 B b = new B();的,现在不需要了,只需要写B b,加上注解,只要B类被spring容器管理,那么A的属性b自然被spring通过依赖注入功能将对应的B类实例化提供给AspringMVC
:基于spring的java Web核心技术,通过分层的概念形成了一套低耦合的通用开发规范,以一个http请求为例,tomcat收到请求,交给springMVC处理,首先是controller层进行http请求的url路径和请求方法匹配,匹配成功就执行对应方法,方法内容基本是调用service层的方法代码与其他的处理逻辑,service层的代码主要是不同dao层的方法代码的组合,最终是dao层执行完一个个增删改查并把结果封装成pojo类返回给客户端。emmm,非常多的名词,整体的处理路线如下:
对应到后端开发的代码结构如下:
1.3 各层功能与代码包结构总结
tomcat
:servlet容器,接收http请求并调用servlet进行处理spring
:java类的生命周期管理(当然还有事务等功能,略过)controller包
:这个包里的类是接收servlet的请求匹配对应方法执行,调用serviceservice包
:这个包里类的接收controller的调用,去调用dao层dao包
:这个包里的类通过mybatis完成java类和数据库数据的映射与解析转换进行数据库查询,将查询请求交给数据库连接池,所以审计数据库注入的代码主要是看这里的sql语句编写,当然后来又出现了一个mybatisPlus插件,这玩意将所有sql语句函数化了,用了mp插件,sql语句就不用编写了就不存在这个包下了。druid
:一个数据库连接池,接收并处理来自dao层的请求,合理分配数据库连接资源jdbc驱动
:真正连接数据库的驱动,java官方规定了JDBC一系列的接口和方法,由数据库厂商去实现,对于java程序员而言,只需要调用相应方法即可,不管底层代码实现,由各个数据库厂商提供的一套java代码库。aop包
:利用spring的aop功能负责对controller包、dao包、service等包里的代码在不改变源代码的基础上做增强的,类似Python的装饰器exception包
:处理web服务运行时的异常定义与处理config包
:springMVC必备的包,用来手动定义整体的框架配置,在springboot框架下被移除的,因为springboot已经做了这一步
2.webgoat项目介绍
webgoat
,一个由owasp机构基于java编写的owasp10 web漏洞编写了一个靶场,代码结构没有采用上述严格分层的目录结构,主要目录如下:
二、broken access control章节
1.Hijack a session会话劫持
可以看到这里是每个关卡对应一个包,这个关卡有五个类。本关是会话劫持。
根据提示,这里需要操作hijack_cookie的值,用户登录后会获得这么一个值,我们需要去猜出其他用户的值来通关,即劫持他的会话身份
1.1 安全测试
burpsuite 的repeater模块,提交几遍,可以看到,这个hijack_cookie的值一直有规律的变动,第一个请求发过去,响应是5167209730199248178-1681981224573
第二个是5167209730199248179-1681981224728
第三个是5167209730199248181-1681981224924
按道理来说第三个请求的响应的该值第一部分尾部应该是180才对,也就是说程序派了180给其他用户了,也就意味着有一个用户拿到了这么一个令牌5167209730199248180-1681981224(728-924),我们要枚举出来得到他
扔到intruder模块进行枚举
很快啊,第2个包就出结果了
1.2 第一次人工请求的代码逻辑分析
本章节类说明
从前端点击发送请求开始读起,HijackSessionAssignment类接收web请求,处理请求参数
如果前端请求中的cookie没有hijack_cookie的值,那就传入前端接收的用户名和密码实例化一个认证状态类,此时该类的认证状态属性是false,id为空。
将认证状态类做为参数给认证逻辑类HijackSessionAuthenticationProvider进行处理
我们第一次访问的时候,只是输入了账号密码,所以进入这个逻辑,来到了认证逻辑类,将参数代入认证逻辑判断,为认证状态类设置id,此时认证状态类的有了前端传来的用户名、密码,以及后端给的ID,还差一个认证状态需要改成true
他调用了authorizedUserAutoLogin()方法,只要能进入这个逻辑就可以设置为true,并添加到会话队列中。最终返回一个认证对象给web处理类HijackSessionAssignment,此时认证对象多了个ID了
他的逻辑是,随机生成一个0-1之间的小数值,如果小于0.75则为true,再取反则为false,也就是说,得随机值大于0.75才能进入这个逻辑(emmm我特么也不知道他为啥要这么设置)
回到web处理对类HijackSessionAssignment,至此第一次请求结束
1.3 使用burp猜解其他会话的代码逻辑
还是从HijackSessionAssignment类接收web请求,处理请求参数开始,请求参数里直接带有hijack_cookie的值,所以,由于带有该值,web处理类的逻辑是将认证对象将ID直接实例化,而逻辑处理类仅验证id值不为空且在会话队列中就直接返回认证状态为true了,至此通关
2、Insecure Direct Object References不安全的对象引用
2.1 关卡说明
这一关考验的是越权的知识,即水平越权或垂直越权
2.2 安全测试
按照提示,输入tom和cat登录进入下一页
点击view profile,提示查看响应包的字段
有role和userId字段,填入前往下一页,此时得知用户ID是2342384,访问路径是/WebGoat/IDOR/profile
这一页提示目前的应用遵循restful模式,需要用另一种方式来访问我们的配置信息
什么是restful,说人话就是类似动态页面静态化,使用get(查询)、post(更改)、put(新增)、delete(删除)四个方法来代表动作,请求的参数作为路径的一部分,比如,
- 老式的url get查询指定id的写法: htttp://www.example.com/selectBook.do?id=1
- restful写法:请求方法必须是Get http://www.example.com/books/1 1就是参数,get代表查询,books的s是必须加的
- restful查询所有的写法 : http://www.example.com/books/
- 同理,根据id删除的写法 http://www.example.com/books/1 方法必须是deleterestful模式通过隐藏了url上面的请求动作,显得安全一些,而且针对某个对象开发的url也统一了。
回到正题,第4页需要通过post请求,提交一个restful路径来访问自己的配置文件,直接吧上面的路径放过来,加上id,就是restful风格的访问,
过关往下走,第五页的要求是查看其它人的信息和修改Buffalo Bill的信息
首先我们知道自己的ID是2342384,那么稍微枚举一下后三位试试,跑个384到400试试
跑到2342388这个ID正好就跑出来buffalo bill的信息,把biill的ID代入请求访问一下就通关了
还需要将bill信息中的颜色从brown改成red,权限改成高权限即role为较低的数字,上面讲过restful风格,修改需要使用post方法,那么我们可以将修改的信息以json的方式放在post的请求包的body,当然最终也没让我们改,返回405只允许get方法
post一般是修改对象部分数据,但post不行,那就试试put,put类似新增,这里相当于覆盖bill原来的所有信息,所有要把所有的字段都提交,修改相应的字段,至此通关
2.3 代码分析
先是登录模块,没啥好讲的,就是输入tom/cat就算登录成功
查看自己的配置文件模块,这个逻辑也相对简单
通过另外的方式访问自己的配置文件,也是非常简单
修改他人的文件配置
3.Missing Function Level Access Control缺少功能级访问控制
3.1 关卡说明
依赖前端进行访问功能的限制,未从后端解决,通过前端代码来找到隐藏的功能
3.2 安全测试
简要来说,这种漏洞类型主要是体现在不同用户角色登录到同一个网页上看到的功能模块是不一样的,比如有3个模块,其中一个是管理员才可以看到的Admin模块,而普通用户应该只能看到2个,是看不到Admin的
这里我们只看到了两个模块,一个account,一个message,需要找出隐藏的模块里的功能
使用浏览器开发工具看到正常访问的模块功能被定义在一个无序列表ul标签中
同时发现了一个隐藏模块Admin,有两个组件,一个Users,一个Config也是定义在无序列表中,这就是第2页的答案,同时也找到了一个URI路径
第三页,根据文字描述要我们获取jerry的用户信息
我们在上一页找到了一些隐藏的URL,/access-control/users,这看起来就是查找到所有用户信息的,直接get访问试试,因为这个网站前后端分离以及restful风格,所以content-type要改成json,获得了所有用户的信息,包括Jerry,过关
第四页,一直做不出来,get不到什么意思,用前面的jerry的哈希就是不行,当然也不可能是两个问题都用一个hash,先跳过
3.3 代码分析
DisplayUser类说明
MissingAccessControlUserRepository类说明,操作数据库的,就是上面说的dao类,一般放在dao或mapper包中
MissingFunctionAC本章节的说明类
MissingFunctionACHiddenMenus类,第二页隐藏菜单项的判断逻辑类
MissingFunctionACUsers,access-control/users和access-control/users-admin-fix的逻辑处理类
看到下面这里我才明白第四关的意思,他需要我将当前登录到webgoat的用户添加到这个库,这样他就会判断会话用户存在,于是返回每个用户的数据时,加的是admin的盐,得到了jerry新的hash
所以第4页的步骤就先是添加会话用户到这里,然后再返回所有用户
MissingFunctionACYourHash类,第3页jerry的哈希碰撞逻辑
MissingFunctionACYourHashAdmin,第4也jerry的哈希碰撞逻辑
User类,一个普通的javaBean
4. Spoofing an Authentication Cookie 欺骗身份验证cookie
4.1 关卡说明
通过猜解cookie生成的算法,直接用生成的cookie验证登录
4.2 安全测试
提示信息,给了webgoat账号密码和admin账号密码
看上去应该是登录这两个账号来看看都拿到了什么cookie,来猜测下一个cookie的值让tom登录
先登录webgoat拿到了一个值
decoder 用base64解码得出7a75547854786373564574616f67626577
再登录admin拿到另一个值
decoder 用base64解码得出7a7554785478637356456e696d6461
整体上看就像是十六进制编码,拿出解码成字符串看看,会发现后面几个字母就是登录的用户名字母倒写
那么tom的cookie值应该是:zuTxTxcsVEmot,然后再转回16进制,再转回base64
repeater重放一下,过关
4.3 代码分析
SpoofCookieAssignment处理web请求类
三、总结
第一关就结束了。感觉安全测试也好,代码审计也好,路还是挺难走的。这还是在靶场有提示的情况下。起码是能看懂这些代码了,上班摸鱼的时候刷了小半年的java视频没白费。
至于漏洞利用那一块,又是一条遥远的路...