Java代码审计-路径遍历、漏洞修复-代码案例
⭐代码审计及渗透测试相关思路,如下:
人工代码审计,关注关键字:
1 new FileInputStream( path
2 new FileOutputStream( path
3 new File( path
4 RandomAccessFile fp = new RandomAccessFile(fname,"r");
5mkdirs
6 getOriginalFilename
7 entry.getName(
...
问题代码,示例如下:
1、文件在获取响应文件路径或者创建响应的目录时,对读入的文件路径没有进行过滤与限制,用户可控。
2 //创建读取 要拷贝的文件
3 InputStream inStream = new FileInputStream(file1);
4 //创建 要复制到的文件,filename未经校验
5 OutputStream inStream = new FileOutputStream(new File(file2+"\\"+filename));
2、直接获取文件名称,未进行校验,创建文件(与1同类)
1 String orgName = mf.getOriginalFilename();//获取文件名
然后
1 File file = new File(orgName);
2 file.mkdirs();//创建文件根目录
3、路径操纵:压缩项覆盖
应用接受恶意zip压缩包,会造成受保护的文件或目录被覆盖等危害
1 //开始解压
2 Enumeration entries = zipFile.entries();
3
4 //遍历entries 获得entry
5 while(entries.hasMoreElements()){
6 ZipEntry entry = (ZipEntry)entries.nextElement();
7 ...
8 File targetFile = new File(entry.getName());
9 ...
10 targetFile.getParentFile().mkdirs();
11 }
渗透测试
路径遍历漏洞隐藏一般在文件读取或者展示图片功能块这样的通过参数提交上来的文件名
例如:http://www.test.com/my. jsp?file=abc.html,
攻击者就可以假定my.jsp能够从文件系统中获取文件并构造如下的恶意URL:
1、目录跳转符可以是…/,也可是…/的ASCII编码或者是unicode编码等,或者 ~/
.%2E /%2F 空格 %20 换行符 %0a
http://www.test.com/my.jsp?file=.../.../Windows/system.ini http://www.test.com/my.jsp?file=%2e./...%2fWindows/system.ini http://192.168.32.163/view.php?page=%20../../../../../../../../../../etc/passwd
在类Unix的系统中也可以使用Url编码的换行符,
例如:../../../etc/passwd%0a.jpg
如果文件系统在获取含有换行符的文件名,会截短为文件名。也可以尝试%20,
例如: ../../../index.jsp%20
2、Java %c0%ae 安全模式绕过漏洞 :
Apache Tomcat UTF-8目录遍历漏洞。漏洞CVE编号为CVE-2008-2938,Tomcat处理请求中的编码时存在漏洞,
如果在context.xml或server.xml中将allowLinking设置为true且连接器配置为URIEncoding=UTF-8的话,则向Tomcat提交恶意请求就可以通过目录遍历攻击读取服务器上的任意文件
在Java端"%c0%ae"解析为"\uC0AE",最后转义为ASCCII低字符-"."。通过这个方法可以绕过目录保护读取包配置文件信息
将目录跳转符里的点编码为%c0%ae,如果服务器使用的受该漏洞影响的Tomcat版本,则可能攻击成功:
http://www.target.com/%c0%ae%c0%ae/%c0%ae%c0%ae/foo/bar
3、绕过文件类型白名单过滤,可以借助“%00”截断符再进行尝试
/WeBid/loader.php?js=…/…/…/…/…/WINDOWS/SchedLgU.txt%00.js
⭐修复方案 及 修复代码案例,如下:
修复代码
https://xbuba.com/questions/12690652
一、使用严格符合规范的可接受输入白名单。
①、 使用正则表达式验证文件路径和文件名,如下
推荐 正则-代码案例:写个过滤函数,白名单形式的,如下案例:
根据业务需求,只允许包含字母、数字、. 、/、-, 且不允许 . 和 / ,或者 . 和 \ 连在一起,直接完全防止 ../ ..\ 等情况的发生.
public class CommUtils{
private static final String patternString = "^[a-zA-Z\\d-/.]+$";
private static final String patternString1 = "./|/.";
public static String filePathFilter(String filepath){
final String[] split = patternString1 .split("\\|");
for(String s : split){
filepath = filepath.replace(s,"");
}
if(filepath.matches(patternString)){
return filepath;
}
return null;
}
}
② 、对文件路径、后缀进行白名单控制,对包含了恶意的符号或者空字节进行拒绝。
如下,解析可接受字符的白名单的输入:(从输入中拒绝路径中不需要的任何字符。它可以被删除或替换。)
以下是一个例子。这确实通过了Fortify审核。重要的是要记住这里返回文字,而不是被检查的字符。Fortify会跟踪原始输入的部件。如果您使用任何原始输入,您可能仍会收到错误。
1 public class CleanPath { 2 3 public static String cleanString(String aString) { 4 if (aString == null) return null; 5 String cleanString = ""; 6 for (int i = 0; i < aString.length(); ++i) { 7 cleanString += cleanChar(aString.charAt(i)); 8 } 9 return cleanString; 10 } 11 12 private static char cleanChar(char aChar) { 13 14 // 0 ‐ 9 15 for (int i = 48; i < 58; ++i) { 16 if (aChar == i) return (char) i; 17 } 1 19 // 'A' ‐ 'Z' 20 for (int i = 65; i < 91; ++i) { 21 if (aChar == i) return (char) i; 22 } 23 24 // 'a' ‐ 'z' 25 for (int i = 97; i < 123; ++i) { 26 if (aChar == i) return (char) i; 27 } 28 29 // other valid characters 30 switch (aChar) { 31 case '/': 32 return '/'; 33 case '.': 34 return '.'; 35 case '‐': 36 return '‐'; 37 case '_': 38 return '_'; 39 case ' ': 40 return ' '; 41 } 42 return '%'; 43 } 44 }
③ 、使用受信任目录的白名单作为有效输入;
2 public static void main(String[] args) {
3 File file=new File(args[0]);
4 if (!isInSecureDir(file)) {
5 throw new IllegalArgumentException();
6 }
7 String canonicalPath = file.getCanonicalPath();
8 if (!canonicalPath.equals("/img/java/file1.txt") &&
9 !canonicalPath.equals("/img/java/file2.txt")) {
10 // Invalid file; handle error
11 }
12
13 FileInputStream fis = new FileInputStream(f);
14 } }
二、严格进行输入验证
也就是拒绝任何不严格符合规范的输入,或将其转换为符合要求的输入。
即 程序对非受信的用户输入数据净化,对网站用户提交过来的文件名进行硬编码或者统一编码,过滤非法字符。
黑名单 过滤的 非法字符 包括:
/ \ " : ~ | * ? < > % ../ ..\
正则-代码案例1 :黑名单——
public String filter(String data){ Pattern pattern = Pattern.complie("[\\s\\\\/:\\*\\?\\\"<>\\|]"); Matcher matcher = pattern.matcher(data); data = matcher.replaceAll(""); return data; }
正则-代码案例2: 黑名单——采用正则表达式过滤掉特殊字符 ”/ \ " : ~ | * ? < >
如果黑名单过滤 "..", 攻击者可替换为 “....”过滤".."后 还剩下一个"..",从而实现绕过,
黑名单的话,很容易过滤不严,被各种方式绕过,仍然会有风险,建议尽量采用白名单的形式。
三、合理配置 web 服务器的目录权限。
(禁止目录浏览,分配好目录权限等)
部署新的业务系统或者安装新的软件或应用后应通过web扫描工具积极查找系统是否存在目录遍历漏洞,尽可能不要在服务器上安装与业务不相关的第三方软件以避免引入目录遍历漏洞。
除此之外,还应该合理配置web服务器(禁止目录浏览,分配好目录权限等)并积极关注所使用的各种软件和应用的版本发布情况,及时升级新的软件版本。
不同web服务器禁止目录浏览方法有所不同。对IIS而言,如果不需要可执行的CGI,可以删除可执行虚拟目录或直接关闭目录浏览;如果确实需要可执行的虚拟目录,建议将可执行的虚拟目录单独放在一个分区。
对于Apache而言,管理员需要修改配置文件,禁止浏览列出目录和文件列表,如可通过修改conf目录下的httpd.conf文件来禁止使用目录索引。以Apache 2.2.25版本为例,打开httpd.conf文件将“Options Indexes FollowSymLinks”中的“Indexes”删除,这样web目录下的所有目录都不再生成索引。