路径穿越
起因
webgoat中出现了一道路径穿越的题目,利用的方法是通过url编码绕过对..
和/
的过滤
但是笔者不太了解为什么可以这么做,于是查看了webgoat源码。
原理
webgoat采用springboot框架,路径穿越部分逻辑如下
var queryParams = request.getQueryString();
if (queryParams != null && (queryParams.contains("..") || queryParams.contains("/"))) {
return ResponseEntity.badRequest().body("Illegal characters are not allowed in the query params");
}
try {
var id = request.getParameter("id");
var catPicture = new File(catPicturesDirectory, (id == null ? RandomUtils.nextInt(1, 11) : id) + ".jpg");
if (catPicture.getName().toLowerCase().contains("path-traversal-secret.jpg")) {
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType(MediaType.IMAGE_JPEG_VALUE))
.body(FileCopyUtils.copyToByteArray(catPicture));
}
if (catPicture.exists()) {
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType(MediaType.IMAGE_JPEG_VALUE))
.location(new URI("/PathTraversal/random-picture?id=" + catPicture.getName()))
.body(Base64.getEncoder().encode(FileCopyUtils.copyToByteArray(catPicture)));
}
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.location(new URI("/PathTraversal/random-picture?id=" + catPicture.getName()))
.body(StringUtils.arrayToCommaDelimitedString(catPicture.getParentFile().listFiles()).getBytes());
} catch (IOException | URISyntaxException e) {
log.error("Image not found", e);
}
return ResponseEntity.badRequest().build();
可以看到在进行检查时,采用的是getQueryString
方法,获取id
是使用的是getParamter
方法。如果我们访问这样一个url:http://127.0.0.1:8000/WebGoat/PathTraversal/random-picture?id=%2e%2e
,
那么getQueryString
得到的是%2e%2e
而getParamter
得到的则是..
,为了验证这一想法,笔者写了一个小demo
@RestController
public class IndexController {
@RequestMapping("index")
public String index(HttpServletRequest request){
return request.getQueryString()+'\n'+request.getParameter("id");
}
}
效果如下:
同时验证其他编码方式,返回400
由于webgoat使用的是springboot框架,springboot使用内置的tomcat启动,而tomcat在解析请求参数时(getParamter
),貌似会自动进行解码,不过解码只针对形如%十六进制数
的格式
所以二次编码时,有如下的效果
至于二次编码的利用形式,笔者还没有遇到过。