FEBS后台管理系统代码审计
环境准备:
下载源码:
下载文件jackliu-hao/shiro_boot—-: shiro_boot代码审计 (github.com)
Oracle安装:
1 |
|
进入容器docker exec oracle_11g -it bash
1 |
|
oralce的其他命令:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
>#补充命令
>#登录sqlplus并修改sys、system用户密码: 需要注意的是再oracle用户下操作
>sqlplus /nolog # 登录
>conn /as sysdba # 连接
>create user test identified by test; # 创建内部管理员账号密码;
>grant connect,resource,dba to yan_test; # 将dba权限授权给内部管理员账号和密码;
>alter system set processes=1000 scope=spfile; # 修改数据库最大连接数据;#修改以上信息后,需要重新启动数据库
>shutdown immediate; # 关闭数据库
>startup; # 启动数据库
>select instance from v$thread; # 查看数据库sid(实例名)
>clear SCR 或 clear screen 或 clea scre # sqlplus清屏命令#创建表空间
>create tablespace pts datafile '/home/oracle/app/oracle/oradata/helowin/pts.dbf' size 100m autoextend on next 10m
>drop tablespace PTS; # 删除表空间
>select tablespace_name from dba_tablespaces; # 查看所有表空间
>create user PTS identified by PTS default tablespace PTS; # 创建用户
>drop user pts cascade; # 删除用户
>SQL> grant sysdba to sys; # 为sys用户添加sysdba权限
>select * from dba_role_privs where granted_role='DBA'; # 查看哪些用户被授予DBA权限
>SQL> select userenv('language') from dual; # 查看数据库编码
Oracle连接:
当执行了上面的命令,修改system用户密码为system后,查看数据库的sid(实例名):
1 |
|
idea连接:jdbc:oracle:thin:@[host]:[port]:[sid]
如图所示:
连接即可。
审计:
1. 验证码复用:
漏洞复现:
抓包后修改账号和密码发现验证码存在复用情况,因此可以尝试爆破出账号和密码。
我们还看到登录中选择记住我后,存在rememberMe
字段,因此可以推断出使用了shiro的鉴权中间件。
代码审计:
查看登录接口:
主要是调用了生成验证码接口后保存在session中,在登陆的时候尝试获取session中的验证码然后进行比较。
如果验证码错误则直接跳出,返回验证码错误了,而不是重新刷新验证码。正确的做法是使当前验证码失效,然后抛出错误,重新调用验证码接口。
2. druid泄露:
访问/druid/index.html
,存在无需登录即可访问druid管理后台。
一般登录账号密码是druid
,druid123
。
由于这里使用了shiro的session来管理,而不是使用request中的session,因此点击session监控是查看不到当前保存的session的。
如果获取了session,可以保存所有session,然后使用burp进行爆破,可以尝试无感知登录。
3. shiro中间件漏洞:
shiro反序列化rce:
看到rememberMe
直接梭哈:
直接梭哈成功:
未授权访问:
漏洞复现:
查看shiro版本:1.4.0
存在可以绕过shiro授权,具体方法是
SpringBoot(Tomcat)和Shiro对URL处理的差异化
漏洞编号 | CVE-2020-1957 | CVE-2020-11989 | CVE-2020-13933 |
---|---|---|---|
影响版本 | Apache Shiro < 1.5.1 | Apache Shiro < 1.5.2 | Apache Shiro < 1.6 |
payload | /xxxx/..;/admin/ | /;/test/admin/page | /admin/;page |
Shrio 处理结果 | /xxxx/.. | / | /admin/ |
SpringBoot 处理结果 | /admin/ | /admin/page | /admin/;page |
查看shiro中的配置内容:
主要存在/js/**
的路径都可以匿名访问,根据CVE-2020-1957,我们请求/js/..;/user/list
,shiro则会处理成/js/..
,而sb则会处理成/user/list
。map.put("/**","user")
表示的是其他路径被配置为需要用户身份验证的请求。
根据这个可以构造以下poc:
1 |
|
实现了匿名访问:
代码审计:
在WebUtils
这个类中存在decodeAndCleanUriString()
方法
shiro鉴权中,调用了decodeAndCleanUriString
,主要逻辑是获取;
的索引然后判断是否存在,如果存在则截取;
前的路径,否则直接返回。
然后调用PathMatchingFilterChainResolver
中的getChain
方法,获取对应的filter过滤器:
当前匹配路径/js/..;/user/list
会被处理成/js/..
,由于/js/**
是匿名访问,因此绕过了shiro的鉴权。
在getPathWithinServletMapping
中调用了getPathWithinApplication
:
这个方法主要是去除路径的;
,把//
替换成/
:
getRequestUri
中调用了decodeAndCleanUriString
方法:
这一步处理完就成了/js/../user/list
然后继续调用getPathWithinServletMapping
中的getServletPath
方法,这个方法主要是获取servlet请求路径,这里明细了/foo/
会被处理成/foo
。
最终/js/../user/list
会处理成/user/list
4. 越权访问:
获取用户信息:
漏洞复现:
1 |
|
代码审计:
查看controller接口:
可以看到查询个人信息的接口是传入id的,而且是不加以权限的,因此可以实现越权查询其他人的信息,如图所示:
正确的做法应该是从session中获取当前登录的用户id,然后再查询,而不是由前端传入当前用户的id。
更改任意用户信息:
漏洞复现:
点击个人信息,抓包:
将用户名和id填写上去,可以修改任意用户的信息:
可以修改当前的状态。
代码审计:
查看service层接口:
这里将用户名和密码设置为null,然后调用updateNotNull
方法,因此这个接口不能修改当前用户名称和密码。
updateNotNull
调用了updateByPrimaryKeySelective
,即只修改修改过的值。
可以看到没有对user实体类的数据进行过滤,从而实现修改任意用户的信息,这里我修改了当前用户的状态,令修改的用户不能登录。
修复建议:
应该获取当前登录的用户,然后只修改当前用户信息,而不是从前端传入数据去修改。如果从前端获取的数据,应该判断需要修改的用户是否是当前登录的用户。
5. 任意文件下载:
漏洞复现:
目录穿越:
这个的fileName没有进行校验,所以导致了目录穿越。
1 |
|
可以读取任意文件:
目录穿越绕过方案
- 进行URL编码:点–>%2e 反斜杠–>%2f 正斜杠–>%5c
../ –> %2e%2e%2f
- 进行16为Unicode编码:点–>%u002e 反斜杠–>%u2215 正斜杠–>%u2216
%u002e%u002e%u2215文件名
- 进行双倍URL编码:点–>%252e 反斜杠–>%u252f 正斜杠–>%u255c
- 进行超长UTF-8 Unicode编码:
- 点–>%c0%2e %e0$40%ae %c0ae
- 反斜杠–>%c0af %e0%80af %c0%af
- 正斜杠–>%c0%5c %c0%80%5c
代码审计:
这里主要用到了FileInputStream
去读取文件,java中的目录穿越是原生的,支持这种../
目录。
修复建议:
对传入的文件名需要进行判断,对于../
这种的文件名需要进行拦截操作。