0x00 前提 自学Java 代码审计,主要自己一个人学习,有点闭门造车,搜索引擎学习法,但是还是记录一下,也分享一下,也便于将来的总结和反思,如果我能终能学到什么,我也会重新梳理思路,为那些自学者提供一个好的思路,所以有了下面的系列文章java代码审计自学篇。
0x01 文件路径穿越 简述: 
许多的文件漏洞都是来源于文件路径的问题,好多时候也是路径可控,再加上一下程序员奇怪的逻辑。 
如果漏洞路径可控提供很多其他突破的方法 
攻击者利用../可以上传至任意指定目录或者目录穿越。 
 
示例代码: 中间有../可以造成文件路径的不安全
1 2 3 4 5 6 7 8 9 10 11 12 13 package file; import java.io.File; import java.io.IOException; public class filepath {     public static void main(String[] args) throws IOException {         File file = new File("../../file/123.txt");         System.out.println(file.getAbsolutePath());         System.out.println(file.getCanonicalPath());         System.out.println(file.exists());     } } 
 
潜在的目录穿越: 一个文件被打开,然后读取文件内容,这个文件名来自于一个输入的参数。如果没有过滤这个传入的参数,那么本地文件系统中任意文件都会被读取。
1 2 3 4 5 6 文件读取有问题,别在里面拼接 val result = Source.fromFile("public/" + value).getLines().mkString // Weak point 修复:要在外面拼接好 filename = "public/" + FilenameUtils.getName(value) val result = Source.fromFile(filename).getLines().mkString  
 
0x02文件上传 简述: 文件上传过程中,因为未校验上传文件后缀类型,导致用户可上传jsp和jspx等一些webshell文件。
代码审计时可重点关注对上传文件类型是否有足够安全的校验。
漏洞示例: 没有任何过滤
jdk原始的流操作上传
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public  String FileUpload (MultipartFile file) {        String  fileName  =  file.getOriginalFilename();         if  (fileName==null ) {             return  "file is error" ;         }   			         String  filePath  =  "/static/images/uploads/" +fileName;         if  (!file.isEmpty()) {             try  {               	                 byte [] bytes = file.getBytes();               	                 BufferedOutputStream  stream  =                          new  BufferedOutputStream (new  FileOutputStream (new  File (filePath)));                                  stream.write(bytes);                                  stream.close();                 return  "OK" ;             } catch  (Exception e) {                 return  e.getMessage();             }         } else  {             return  "You failed to upload "  + file.getOriginalFilename() + " because the file was empty." ;         }     } 
 
框架常用的封装类上传
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 private  static  String  UPLOADED_FOLDER  =  "/tmp/" ;public  String FileUpload (@RequestParam("file")  MultipartFile file,RedirectAttributes redirectAttributes)  {                 if  (file.isEmpty()) {                          redirectAttributes.addFlashAttribute("message" , "Please select a file to upload" );             return  "redirect:/file/status" ;         }         try  {                        	             byte [] bytes = file.getBytes();                           Path  path  =  Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());           	              Files.write(path, bytes); 						           	              redirectAttributes.addFlashAttribute("message" ,                     "You successfully uploaded '"  + UPLOADED_FOLDER + file.getOriginalFilename() + "'" );         } catch  (IOException e) {             redirectAttributes.addFlashAttribute("message" , "upload failed" );             e.printStackTrace();             return  "redirect:/file/status" ;         }         return  "redirect:/file/status" ;     } 
 
审计函数 java中文件操作的函数特别多,有的是原始的字节字符流
java都是基于流的,还有好多都是后面有封装的,感觉如果不熟就直接 搜索file吧,再检查 过滤条件
JDK原始的java.io.FileInputStream
 
JDK原始的 BufferedOutputStream
 
JDK原始的各种OutputStream,流操作都可以
 
Apache Commons IO提供的org.apache.commons.io.FileUtils类
 
 
参考园长文章
修复方案 
使用白名单校验上传文件类型、大小限制、MIME类型 
白名单fileName.substring(fileName.lastIndexOf(“.”)); 检查后缀名 
还有一个BufferedImage类、Image类、Graphics类这些封装好的图片类,直接传进去试试 
 
1 BufferedImage bi = ImageIO.read(file); 
 
0x02文件读取 简述: Java其实读写是一体的,都是流的输入和输出
这个漏洞主要是要结合第一个,路径穿越的情况
代码: 1 2 3 4 5 6 7 8 9 10 @GetMapping("/path_traversal/") public  String getImage (String filepath)  throws  IOException {File  f  =  new  File (filepath);if  (f.exists() && !f.isDirectory()) {		     byte [] data = Files.readAllBytes(Paths.get(filepath));     return  new  String (Base64.encodeBase64(data)); } else  {     return  "File doesn't exist or is not a file." ; } 
 
审计函数 
JDK原始的java.io.RandomAccessFile类
 
JDK原始的inputsteam类
 
Apache Commons IO提供的org.apache.commons.io.FileUtils类
 
JDK1.7新增的基于NIO非阻塞异步读取文件的java.nio.channels.AsynchronousFileChannel类
 
JDK1.7新增的基于NIO读取文件的java.nio.file.Files类
常用方法如:Files.readAllBytes、Files.readAllLines
参考园长文章
 
 
修复方案: 过滤目录穿越关键字
0x01 目录遍历 简述: 目录遍历,主要看逻辑吧,能不能回显
有专门file.listFiles()函数可以处理。
代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package  file;import  java.io.File;import  java.io.FileFilter;public  class  filepath  {    public  static  void  main (String[] args)  {         String  path  =  "/Users/zy/Desktop/java_rmi/src/main/java/" ;		         File  file  =  new  File (path);		         func(file);     }     private  static  void  func (File file) {         File[] fs = file.listFiles();         for (File f:fs){             if (f.isDirectory())	                 func(f);             if (f.isFile())		                 System.out.println(f);         }     } }