Heim  >  Artikel  >  Betrieb und Instandhaltung  >  So analysieren Sie die Codeüberwachung in Java Web Security

So analysieren Sie die Codeüberwachung in Java Web Security

PHPz
PHPznach vorne
2023-05-16 08:04:211740Durchsuche

1. JavaWeb-Sicherheitsgrundlagen

1. Was ist Code-Auditing?

Für Laien bedeutet Java-Code-Auditing, Fehler in der Java-Anwendung selbst durch Auditing zu entdecken Da Java selbst eine kompilierte Sprache ist, können wir den Java-Code auch dann prüfen, wenn nur Klassendateien vorhanden sind. Bei unkompilierten Java-Quellcodedateien können wir den Quellcode direkt lesen, bei kompilierten Klassen- oder JAR-Dateien müssen wir sie jedoch dekompilieren.

Die Prüfung von Java-Code selbst ist nicht sehr schwierig. Solange Sie sich mit dem Prüfungsprozess und den gängigen Techniken zur Schwachstellenprüfung auskennen, können Sie die Codeprüfungsarbeit relativ einfach abschließen. Die Methode der Java-Codeprüfung besteht jedoch nicht nur darin, den gesamten Java-Projektcode mit einem Prüftool zu scannen. Einige Systemcodeprüfungen mit komplexer Geschäftslogik und Programmarchitektur erfordern, dass Prüfer eine bestimmte Java-Grundlage beherrschen und über die entsprechenden Fähigkeiten verfügen Nur mit bestimmten Prüfungserfahrungen, Fähigkeiten und sogar einem tieferen Verständnis und einer tieferen Praxis der Java-Architektur können Sicherheitsprobleme tiefer erkannt werden.

Dieser Artikel ist in mehrere Kapitel unterteilt, um die für die Java-Code-Prüfung erforderlichen Vorkenntnisse sowie die Prozesse und Techniken der Java-Code-Prüfung zu beschreiben.

2. Bereiten Sie die Umgebung und Hilfstools vor

Bitte installieren Sie die Java-Entwicklungsumgebung selbst, bevor Sie mit dem Java-Code-Audit beginnen. Es wird empfohlen, MacOS- und Ubuntu-Betriebssysteme zu verwenden.

Wie das Sprichwort sagt: „Wenn Sie Ihre Arbeit gut machen wollen, müssen Sie zuerst Ihre Werkzeuge schärfen.“ Der sinnvolle Einsatz einiger Hilfstools kann die Effizienz und Qualität unserer Code-Audits erheblich verbessern!

Die folgenden Hilfstools sind wärmstens zu empfehlen:

1.Jetbrains IDEA(IDE)

2.Sublime Text (Texteditor)

3.JD-GUI(Decompilation)

4.Fernflower(Decompile)

5.Bytecode-Viewer

# 🎜🎜 #6.Eclipse(IDE)

7.NetBeans(IDE)

如何分析Java Web安全中的代码审计

2. Anti-Compilation Fähigkeiten

Die Codes, die während des Penetrationstests geprüft werden müssen, sind normalerweise Klassendateien oder JAR-Pakete. Wie sollten wir sie also prüfen? Lassen Sie uns zunächst lernen, was Java-Quellcode und Bytecode sind.

1. Grundlagen der Java-Klassenkompilierung und -Dekompilierung

Einfach ausgedrückt ist der Java-Quellcode eine unkompilierte .java-Datei. Der Bytecode Die .class-Datei ist die Bytecode-Datei, die nach der Kompilierung der .class-Datei generiert wird. Wir können sie nicht direkt über ein Dekompilierungstool konvertieren Code.

Beispielcode Test.java:

/**
 * @author yz
 */
public class Test {

	public static void hello() {
		System.out.println("Hello~");
	}

	public void world() {
		System.out.println("World!");
	}

	public static void main(String[] args) {
		hello();
	}

}

Test.java-Kompilierungsausführungsprozess:

如何分析Java Web安全中的代码审计Test.java Quellcode, Bytecode

如何分析Java Web安全中的代码审计#🎜 🎜 #Aufgrund der schlechten Lesbarkeit von Klassendateien müssen wir normalerweise Java-Dekompilierungstools verwenden, um den Code zu dekompilieren. Normalerweise verwenden wir Tools wie JD-GUI, IDEA Fernflower Plug-in, Bytecode-Viewer, Fernflower, JAD, JBE, JEB usw., um Klassen zu dekompilieren.

Unter diesen ist JD-GUI möglicherweise das am häufigsten verwendete Tool zur Dekompilierung, aber ich persönlich bin der Meinung, dass die Dekompilierungsfähigkeit von JD-GUI der von IDEA weit unterlegen ist (IDEA sollte die modifizierte Fernflower sein). verwendet), da IDEA standardmäßig die Dekompilierung von JARs und Klassen unterstützt, daher empfehle ich persönlich dringend, IDEA zum Dekompilieren von Klassencode zu verwenden.

Natürlich sind Dekompilierungstools oft nicht allmächtig und können nicht dekompiliert werden oder das Programm stürzt während des Dekompilierungsvorgangs normalerweise ab Wenn IDEA nicht dekompilieren kann, können Sie JBE verwenden, um den Bytecode des Klassendatei-Leseprogramms zu laden. Wenn JBE die Klasseninformationen immer noch nicht lesen kann, können Sie auch den mit dem JDK gelieferten Befehl javap verwenden, um den Klassencode zu lesen Wenn nicht alle Methoden dekompiliert werden können, kann es sein, dass die Klasse selbst nicht kompiliert werden kann oder die Klassendatei verschlüsselt wurde. Vielleicht werden Sie sagen, dass kompilierte Java-Klassen nicht verschlüsselt werden können? Ja, die hier erwähnte Verschlüsselung dient eigentlich dazu, den kompilierten Klassencode vor der Dekompilierung zu schützen. Es handelt sich lediglich um eine Möglichkeit, die verschlüsselte Klasse durch die Implementierung eines benutzerdefinierten ClassLoaders zu laden. Diese Verschlüsselungsmethode wurde auch im tatsächlichen Kampf angetroffen.

2. Dekompilieren Sie die gesamte Jar-Technik

Normalerweise erhalten wir in einigen speziellen Szenarien nur die JAR-Datei. Wie sollten wir also die Klasse des gesamten JAR-Pakets dekompilieren? sind die Dateien?

2.1. Fernflower

Fernflower kann leicht eine vollständige Dekompilierung von jar erreichen, führen Sie einfach den folgenden Befehl aus: java -jar fernflower. jar jarToDecompile. jar decomp/ wobei jarToDecompile.jar die JAR-Datei ist, die dekompiliert werden muss, und decomp das Verzeichnis ist, in dem die dekompilierten Klassendateien gespeichert sind. Es ist zu beachten, dass Fernflower möglicherweise leere Java-Dateien generiert, wenn diese nicht dekompiliert werden können!

2.2. JD-GUI

JD-GUI ist ein Dekompilierungstool mit GUI, klicken Sie im Menü von JD-GUI auf Datei -- >Alle Quellen speichern, um das JAR zu dekompilieren.

2.3. IDEA

IDEA默认就支持jar包反编译,同时还支持class文件名(⇧⌘F)、类方法名称(⇧⌘O)搜索。

2.4. Bytecode-Viewer

FernFlower提供了GUI版本Bytecode-Viewer,Bytecode-Viewer提供了直接反编译的class、jar、zip、apk、dex功能,直接拖拽jar就可以直接对整个jar进行反编译了。

如何分析Java Web安全中的代码审计

2.5. Find命令

find命令并不能支持Java反编译,但是find命令可以非常方便的搜索经过编译后的二进制文件中的内容,所以有的时候使用find命令通常是最简单实用的,直接解压jar包然后使用find命令搜索: find ./ -type f -name “*.class” |xargs grep XXXX 即可搞定。

2.6 使用Find命令和Fernflower实现批量反编译jar

当我们只有项目war包且源码经过打包后发布到WEB-INF/lib的情况下,我们不得不去找出待审计源码的具体jar文件并反编译。遇到这种情况我们可以巧妙的使用find命令来反编译所有目标的jar包。

这里以jcms的一个非常老版本为例,jcms最终给客户部署的war包中源码并不是在WEB-INF/classes目录下,而是将整个jcms系统按模块打包成了多个jar包放在了WEB-INF/lib目录下。我们可以通过搜索com.hanweb包名称来找出所有jar中包含了jcms的文件并通过Fernflower来反编译。

java -jar /Users/yz/Desktop/javaweb-decomplier/javaweb-decomplier.jar -dgs=1 $(find /Users/yz/Desktop/jcms/WEB-INF/lib/ -type f -name "*.jar" |xargs grep "com.hanweb" |awk '{print $3}') /Users/yz/jcms-decomplier

依赖的jar: javaweb-decomplier、Intellij java-decompiler。

执行上面的命令后会在jcms-decomplier目录下看到所有的jar已经被Fernflower反编译了。

如何分析Java Web安全中的代码审计

3. IntelliJ IDEA 推荐

IntelliJ IDEA是Jetbrains出品的一款非常强大的Java IDE,IDEA提供了强大的代码搜索、近乎完美的反编译、动态调试等功能可以最大程度的辅助我们代码审计。

不可以否认,与IDEA相比虽然Eclipse和Netbeans也有与之类似的功能,但是在真正的实战体验中个人更倾向于使用IDEA,虽然曾经的我也是一个重度Eclipse开发者。

三、IDEA代码搜索技巧

IDEA的搜索快捷键是:⇧⌘F,使用IDEA提供的搜索功能可以非常快速的定位漏洞点信息。

如何分析Java Web安全中的代码审计

IDEA可以通过自定义搜索范围来精确查找我们需要审计的代码。默认搜索的是所有的位置,不过我们可以点击红色箭头指向的...按钮来细化我们的搜索范围。

1. 自定义范围搜索

如何分析Java Web安全中的代码审计

自定义搜索范围示例:

如何分析Java Web安全中的代码审计自定义搜索范围后就可以在搜索时使用自定义的配置进行范围搜索了,有助于我们在挖漏洞的时候缩小代码定位范围。

如何分析Java Web安全中的代码审计

2. 标记搜索

搜索快捷键: ⌘O,标记搜索支持类名、方法名搜索(包括class或jar文件中的方法也支持搜索)。

如何分析Java Web安全中的代码审计

3. Java调用链搜索

当我们审计代码的时候发现某个方法或类有漏洞时我们需要定位到漏洞的请求地址(触发点),复杂业务系统往往会让我们很难定位到漏洞的触发点。借助IDEA的方法调用链搜索功能就可以很轻松的找出方法的调用链和触发点。

选择类或者方法名-->右键-->Find Useages或者使用快捷键⌥F7

如何分析Java Web安全中的代码审计

四、Java Web基础

1. Java分层思想

为了更好的管理项目我们通常会采用分层架构的方式来开发Java Web项目,分层设计的好处在于可以非常方便的分清楚包之间的业务逻辑关系。

常见的JavaWeb项目分层:

视图层(View 视图)

控制层(Controller、Action 控制层)

服务层(Service)

业务逻辑层BO(business object)  

实体层(entity 实体对象、VO(value object) 值对象 、模型层(bean)。

Persistenzschicht (dao- Data Access Object Datenzugriffsschicht, PO (persistentes Objekt) persistentes Objekt)

Beispielprojekt basierend auf Java-Schichtarchitektur:

如何分析Java Web安全中的代码审计

2. Modulare Java-Entwicklung von heute

Heutiges relativ großes Java Webprojekte werden normalerweise modular entwickelt. Mithilfe der Abhängigkeitsverwaltungstools Maven und Gradle kann Java die modulare Entwicklung problemlos abschließen. Darüber hinaus ist es auch üblich, die OSGi-Technologie (Open Service Gateway Initiative zur Ermöglichung der Hot-Module-Bereitstellung) zur Entwicklung dynamischer Java-Modulsysteme zu verwenden.

Die Einführung der modularen Entwicklung wird es für uns auch schwierig machen, Code-Audits durchzuführen, da wir den zu prüfenden Code in stärker abhängigen Bibliotheken finden müssen.

Beispiel für ein mit Maven entwickeltes JavaWeb-Projekt:

如何分析Java Web安全中的代码审计如何分析Java Web安全中的代码审计

3. Was ist Servlet?

Servlet ist ein kleines Programm, das auf einem Java-Webcontainer ausgeführt wird. Es ist erwähnenswert, dass Sie nach Servlet3.0 (Tomcat7+) Anmerkungen zum Konfigurieren von Servlets verwenden können.

Annotationsbasiertes Servlet

如何分析Java Web安全中的代码审计

Versionen vor Servlet3.0 müssen in web.xml konfiguriert werden, bestehend aus Das Spring MVC-Framework wird auf Basis der Servlet-Technologie implementiert.

Servlet basierend auf der Konfiguration implementiert

如何分析Java Web安全中的代码审计

HttpServlet-Klasse

如何分析Java Web安全中的代码审计

Es ist sehr einfach, ein Servlet zu implementieren. Sie müssen nur die Klasse javax.servlet.http.HttpServlet erben und die doXXX-Methode oder Service-Methode überschreiben Dies erfordert Beachten Sie, dass durch Überschreiben der Dienstmethode der HttpServlet-Klasse Anforderungen für die oben genannten sieben HTTP-Anforderungsmethoden erhalten werden können.

4. Die Beziehung zwischen JSP und Servlet

JSP- und JSPX-Dateien sind dynamische Skripte, die direkt vom Java-Container analysiert werden können. Sie können nicht nur für die Anzeige von Seitendaten verwendet werden auch zur Verarbeitung der Backend-Geschäftslogik.

Im Wesentlichen ist JSP ein Servlet, da die JSP-Datei schließlich in eine Klassendatei kompiliert wird und diese Klassendatei tatsächlich ein spezielles Servlet ist.

Die JSP-Datei wird in eine Java-Klassendatei kompiliert. Beispielsweise generiert index.jsp zwei Dateien, index_jsp.java und index_jsp.class, nachdem es von Jasper in Tomcat kompiliert wurde. Index_jsp.java erbt von der HttpJspBase-Klasse und ist ein Standard-Servlet, das die HttpJspPage-Schnittstelle implementiert und die HttpJspPage-Schnittstellenmethode erbt, ähnlich der Service-Methode in Servlet. Service-Methodenaufruf.

如何分析Java Web安全中的代码审计

5. Was ist Filter? Filter ist ein Filter in JavaWeb, der zum Filtern von URL-Anfragen verwendet wird. Über Filter können wir Funktionen wie die Überprüfung der URL-Anforderungsressourcenberechtigung und die Benutzeranmeldungserkennung implementieren. Filter ist eine Schnittstelle. Um einen Filter zu implementieren, müssen Sie nur die Methoden init, doFilter und destroy neu schreiben. Die Filterlogik ist in der doFilter-Methode implementiert.

Filter ist wie Servlet der Kernbestandteil von Java Web. Natürlich kann das MVC-Framework auch mithilfe des Filtermechanismus implementiert werden Filter.

Die Filterkonfiguration ähnelt der von Servlet und besteht aus zwei Tags: und . Wenn die Servlet-Version höher als 3.0 ist, können Sie auch Anmerkungen zum Konfigurieren von Filter verwenden.

如何分析Java Web安全中的代码审计6. Zusammenfassung von Filter und Servlet

Bei einfachen Architekturprojekten, die auf Filter und Servlet basieren, liegt der Schwerpunkt der Codeprüfung darauf, alle Filter zu finden, ihre Filterregeln zu analysieren und herauszufinden, ob es eine globale Sicherheitsfilterung gibt. ob die vertrauliche URL-Adresse einer Berechtigungsüberprüfung unterliegt und versucht, die Filterfilterung zu umgehen. Der zweite Punkt besteht darin, alle Servlets zu finden und zu analysieren, ob es Sicherheitsprobleme im Servlet-Geschäft gibt. Wenn es Sicherheitsprobleme gibt, können diese ausgenutzt werden? Haben Sie eine Zugriffsberechtigung? Ziehen Sie bei Fragen wie der Filterung durch einen Filter keine voreiligen Schlüsse, wenn Sie die Schwachstellen in Servlets und JSPs sehen. Vergessen Sie nicht, dass sich vor dem Servlet wahrscheinlich ein globaler Sicherheitsfilter befindet.

Filter und Servlet sind beide von Java Web bereitgestellte APIs. Kurz zusammengefasst haben sie die folgenden gemeinsamen Punkte.

  1.Filter和Servlet都需要在web.xml或注解(@WebFilter、@WebServlet)中配置,而且配置方式是非常的相似的;

  2.Filter和Servlet都可以处理来自Http请求的请求,两者都有request、response对象;

  3.Filter和Servlet基础概念不一样,Servlet定义是容器端小程序,用于直接处理后端业务逻辑,而Filter的思想则是实现对Java Web请求资源的拦截过滤;

  4.Filter和Servlet虽然概念上不太一样,但都可以处理Http请求,都可以用来实现MVC控制器(Struts2和Spring框架分别基于Filter和Servlet技术实现的);

  5.一般来说Filter通常配置在MVC、Servlet和JSP请求前面,常用于后端权限控制、统一的Http请求参数过滤(统一的XSS、SQL注入、Struts2命令执行等攻击检测处理)处理,其核心主要体现在请求过滤上,而Servlet更多的是用来处理后端业务请求上

7. 初识JavaWeb MVC框架

传统的开发存在结构混乱易用性差耦合度高可维护性差等多种问题,为了解决这些毛病分层思想和MVC框架就出现了。MVC即模型(Model)、视图(View)、控制器(Controller), MVC模式的目的就是实现Web系统的职能分工。

截至2018年底,绝大多数的新项目都已然改为了基于Spring Boot的Spring MVC实现,也就是说曾经站在JavaWeb MVC最巅峰的Struts2框架已经逐渐陨落。

7.1 Spring MVC 控制器

在Spring进入了3.0时代,使用Java注解的方式也逐渐的流行了起来,曾经写一个Spring的控制器我们通常要在xml中声明Spring bean并配置处理的URL,而在新时代的Spring项目中我们通常用Spring MVC注解就可以轻松完成Spring MVC的配置了。

一个基于Spring 注解配置的控制器:

package org.javaweb.codereview.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class IndexController {
@RequestMapping("/index.php")
public String index() {
return "/index.html";
}
}

Spring Controller注解:

@Controller

@RestController

@RepositoryRestController

Spring MVC请求配置注解:

@RequestMapping

@GetMapping

@PostMapping

@PutMapping

@DeleteMapping

@PatchMapping

Spring MVC除了上述6种Http请求处理注解以外还有Spring Data JPA Rest提供的特殊的@RepositoryRestResource注解,@RepositoryRestResource是基于Spring Data JPA REST库实现的,Spring Data JPA REST提供的API可支持通过JPA查询数据并处理Http请求服务。

基于XML配置的Spring MVC

对于一些老旧的项目可能还保留了一些基于xml配置的方式Spring MVC项目,这里只简单的介绍下如何配置不做过多的描述。基于配置方式的控制器一般是在Controller类中实现了Spring的org.springframework.web.servlet.mvc.Controller接口的handleRequest方法(当然还有其他途径,如:AbstractCommandController和SimpleFormController但都已经过时了)。

TestController.java示例代码:

package org.javaweb.codereview.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * @author yz
 */
public class TestController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mv = new ModelAndView();
mv.setViewName("index");
return mv;
}
}

XML配置具体的bean

<bean name="/test.do" class="org.javaweb.codereview.controller.TestController"/>

7.2 Struts2控制器

Struts2主要的开发模式是基于xml配置,在struts.xml中配置Action地址和对应的处理类。

如何分析Java Web安全中的代码审计

不过Struts2(2.1.6版本开始)也可以使用struts2-convention-plugin插件来实现基于注解方式的配置。

如何分析Java Web安全中的代码审计

需要注意的是Struts2的参数是可以通过get/set方法传入的,如上图TestActionAnnotation类的username变量是可以直接在Http请求中的URL传入的。

7.3 快速找出Http请求请求URL

代码审计中我们可以选择优先从Controller、Servlet和JSP中入手,也可以选择从漏洞点反向推出Http请求的入口地址,这里将讲解下如何快速找到这些请求入口,因为Struts2和Spring MVC的原理比较接近,所以本节只以Spring MVC为例。

7.3.1 查找Spring MVC所有的控制器

如果有源码的情况下可以使用find命令或者IDEA的全局搜索功能即可快速搜索到所有的控制器,如果只有class文件的情况下可以使用find命令:

find ~/cms/ -type f -name "*.class" |xargs grep -E "Controller|@RestController|RepositoryRestController"

7.3.2 查找所有的请求处理URL

查找请求处理URL的方式同理,使用如下find命令查找所有class中的请求处理注解:

find ~/cms/ -type f -name "*.class" |xargs grep -E "RequestMapping|GetMapping|PostMapping|PutMapping|DeleteMapping|PatchMapping|RepositoryRestResource"

7.4 Spring MVC和Struts2控制器小结

这一小节我们只是简单的介绍下Spring MVC和Struts2的控制器,在后面的框架服务章节将会详细介绍。至于如何去快速定位Struts2的action请自行参考Spring MVC的Controller查找方式这里不再讲解。

五、Java语言的动态性

Java语言动态性一直以来都比较差,并不像PHP那样灵活。在Java中的动态性往往需要使用一些曲折的方式来实现.这里简单列举了Java十余种动态性相关技术并总结部分技术实现安全问题。

1.Java反射机制

2.MethodHandle

3.JDK动态代理

4.使用JVM上的动态语言(如:Groovy、JRuby、Jython)

5.表达式库(如:OGNL、MVEL、SpEL、EL)

6.JSP、JSPX、Quercus(Resin容器提供了PHP5支持)

7.字节码库(如:Asm、Javassist、Cglib、BCEL)

8.ScriptEngineManager(脚本引擎)。

9.动态编译(如:JDT、JavaCompiler)

10.ClassLoader、URLClassLoader

11.模版引擎(如:Freemarker、Velocity)

12.序列化、反序列化(包含Java 对象序列化、XML、JSON等)

13.JNI、JNA(Java调用C/C++)

14.OSGi(Open Service Gateway Initiative)

15.RMI(Java远程方法调用,基于对象序列化机制实现)

16.WebService

17.JDWP(Java Platform Debugger Architecture Java调试协议)

18.JMX(Java Management Extensions)

1. Java反射机制特性

Java反射机制可以无视类方法、变量访问权限修饰符,可以调用任何类的任意方法、访问并修改成员变量值。也就是说只要发现一处Java反射调用漏洞几乎就可以为所欲为了。当然前提可能需要你能控制反射的类名、方法名和参数。

一行代码即可实现反射调用Runtime执行本地命令:

Runtime.class.getMethod("exec", String.class).invoke(Runtime.class.getMethod("getRuntime").invoke(null), "whoami")

获取一个类的对象(如Runtime类)我们一般会采用如下几种方式:

  1.Class.forName("java.lang.Runtime")、"".getClass().forName("java.lang.Runtime")

  2.Runtime.class

  3.ClassLoader.getSystemClassLoader().loadClass("java.lang.Runtime")

Java反射获取类方法有两种方式:

  1.getMethod(xxx),getMethods()

  2.getDeclaredMethod(xxx)、getDeclaredMethods()。

区别在于getMethod会返回当前类和父类的所有public方法,而getDeclaredMethod返回的是当前的所有方法。

Java反射获取类成员变量有两种方式:

  1.getField(xxx)、getFields()

  2.getDeclaredField(xxx)、getDeclaredFields()

getField和getDeclaredField区别同上,如果想要调用private修饰的Field或者Method只需要设置下setAccessible为true就可以了,如:xxxMethod.setAccessible(true)。

Java的大部分框架都是采用了反射机制来实现的(如:Spring MVC、ORM框架等),所以我们不得不掌握Java反射机制来提升我们的代码审计能力。

Java反射机制实现无关键字执行命令

import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Scanner;
/**
 * @author yz
 */
public class ReflectionTest {
public static void exec() {
try {
System.out.println(Runtime.class.getMethod("exec", String.class).invoke(Runtime.class.getMethod("getRuntime").invoke(null), "curl -i localhost:8000"));
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
try {
String str = "whoami";
// java.lang.Runtime
String runtime = new String(new byte[]{106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 82, 117, 110, 116, 105, 109, 101});
// Runtime.class
Class<?> c = Class.forName(runtime);
// 获取getRuntime方法,Runtime.getRuntime()
Method m1 = c.getMethod(new String(new byte[]{103, 101, 116, 82, 117, 110, 116, 105, 109, 101}));
// 获取Runtime的exec方法,rt.exec(xxx)
Method m2 = c.getMethod(new String(new byte[]{101, 120, 101, 99}), String.class);
// Runtime.getRuntime().exec(str)
Object obj2 = m2.invoke(m1.invoke(null), str);
// 获取命令执行结果Process类的getInputStream()方法
Method m = obj2.getClass().getMethod(new String(new byte[]{103, 101, 116, 73, 110, 112, 117, 116, 83, 116, 114, 101, 97, 109}));
m.setAccessible(true);
// process.getInputStream()
InputStream in = (InputStream) m.invoke(obj2, new Object[]{});
// 输出InputStream内容到
Scanner scanner = new Scanner(in).useDelimiter("\\A");
System.out.println(scanner.hasNext() ? scanner.next() : "");
} catch (Throwable t) {
t.printStackTrace();
}
}
}

2. JDK7+ MethodHandle

JDK7开始Java提供了MethodHandle可以非常方便的访问和调用类方法,MethodHandle的能力和Java反射机制相似,但效率却远高出Java反射机制,但MethodHandle也并不是那么完美的,缺点是MethodHandle必须要求JDK版本大于等于1.7,MethodHandle也无法像反射那样调用私有方法和变量。

参考:通过代码简单介绍JDK 7的MethodHandle,并与.NET的委托对比。

基于MethodHandle实现的调用Runtime执行系统命令

import java.io.InputStream;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Scanner;
/**
 * @author yz
 */
public class MethodHandlesTest {
public static void main(String[] args) {
try {
String               str          = "ping p2j.cn -c 1";
Class                runtimeClass = Runtime.class;
MethodHandles.Lookup lookup       = MethodHandles.lookup();
// Runtime rt = Runtime.getRuntime()
MethodHandle methodHandle = lookup.findStatic(
runtimeClass, "getRuntime", MethodType.methodType(runtimeClass)
);
// 获取Runtime的exec方法
MethodHandle execMethod = lookup.findVirtual(
runtimeClass, "exec", MethodType.methodType(Process.class, new Class[]{
String.class
})
);
// 获取Process的getInputStream方法
MethodHandle inputStreamMethod = lookup.findVirtual(
Process.class, "getInputStream", MethodType.methodType(InputStream.class)
);
// 调用Runtime.getRuntime().exec(xxx).getInputStream()
InputStream in = (InputStream) inputStreamMethod.invoke(
execMethod.invoke(methodHandle.invoke(), str)
);
// 输出InputStream内容到
Scanner scanner = new Scanner(in).useDelimiter("\\A");
System.out.println(scanner.hasNext() ? scanner.next() : "");
} catch (Throwable t) {
t.printStackTrace();
}
}
}

六、Java代码审计-Checklist

通常我喜欢把代码审计的方向分为业务层安全问题、代码实现和服务架构安全问题,。

1. 业务层安全常见问题

业务层的安全问题集中在业务逻辑和越权问题上,我们在代码审计的过程中尽可能的去理解系统的业务流程以便于发现隐藏在业务中的安全问题。

1.1 业务层中常见的安全问题Checklist

1.用户登陆、用户注册、找回密码等功能中密码信息未采用加密算法。

2.用户登陆、用户注册、找回密码等功能中未采用验证码或验证码未做安全刷新(未刷新Session中验证码的值)导致的撞库、密码爆破漏洞。

3.找回密码逻辑问题(如:可直接跳过验证逻辑直接发包修改)。

4.手机、邮箱验证、找回密码等涉及到动态验证码等功能未限制验证码失败次数、验证码有效期、验证码长度过短导致的验证码爆破问题。

5.充值、付款等功能调用了第三方支付系统未正确校验接口(如:1分钱买IPhone X)。

6.后端采用了ORM框架更新操作时因处理不当导致可以更新用户表任意字段(如:用户注册、用户个人资料修改时可以直接创建管理员账号或其他越权修改操作)。

7.后端采用了ORM框架查询数据时因处理不当导致可以接收任何参数导致的越权查询、敏感信息查询等安全问题。

8.用户中心转账、修改个人资料、密码、退出登陆等功能未采用验证码或Token机制导致存在CSRF漏洞。

9.后端服务过于信任前端,重要的参数和业务逻辑只做了前端验证(如:文件上传功能的文件类型只在JS中验证、后端不从Session中获取用户ID、用户名而是直接接收客户端请求的参数导致的越权问题)。

10.用户身份信息认证逻辑问题(如:后台系统自动登陆时直接读取Cookie中的用户名、用户权限不做验证)。

11.重要接口采用ID自增、ID可预测并且云端未验证参数有效性导致的越权访问、信息泄漏问题(如:任意用户订单越权访问)。

12.条件竞争问题,某些关键业务(如:用户转账)不支持并发、分布式部署时不支持锁的操作等。

13.重要接口未限制请求频率,导致短信、邮件、电话、私信等信息轰炸。

14.敏感信息未保护,如Cookie中直接存储用户密码等重要信息。

15.弱加密算法、弱密钥,如勿把Base64当成数据加密方式、重要算法密钥采用弱口令如123456。

16.后端无异常处理机制、未自定义50X错误页面,服务器异常导致敏感信息泄漏(如:数据库信息、网站绝对路径等)。

17.使用DWR框架开发时前后端不分漏洞(如:DWR直接调用数据库信息把用户登陆逻辑直接放到了前端来做)。

2. 代码实现常见问题

代码审计的核心是寻找代码中程序实现的安全问题,通常我们会把代码审计的重心放在SQL注入、文件上传、命令执行、任意文件读写等直接威胁到服务器安全的漏洞上,因为这一类的漏洞杀伤力极大也是最为致命的。

###2.1 代码实现中常见的安全问题Checklist

  1.任意文件读写(文件上传、文件下载)、文件遍历、文件删除、文件重命名等漏洞

  2.SQL注入漏洞

  3.XXE(XML实体注入攻击)

  4.表达式执行(SpEL、OGNL、MVEL2、EL等)

  5.系统命令执行漏洞(ProcessBuilder)

  6.反序列化攻击(ObjectInputStream、JSON、XML等)

  7.Java反射攻击

  8.SSRF攻击

2.1.1 Java 文件名空字节截断漏洞(%00 Null Bytes)

空字节截断漏洞漏洞在诸多编程语言中都存在,究其根本是Java在调用文件系统(C实现)读写文件时导致的漏洞,并不是Java本身的安全问题。不过好在高版本的JDK在处理文件时已经把空字节文件名进行了安全检测处理。

2013年9月10日发布的Java SE 7 Update 40修复了空字节截断这个历史遗留问题。此次更新在java.io.File类中添加了一个isInvalid方法,专门检测文件名中是否包含了空字节。

如何分析Java Web安全中的代码审计

修复的JDK版本所有跟文件名相关的操作都调用了isInvalid方法检测,防止空字节截断。

如何分析Java Web安全中的代码审计

修复前(Java SE 7 Update 25)和修复后(Java SE 7 Update 40)的对比会发现Java SE 7 Update 25中的java.io.File类中并未添加\u0000的检测。

如何分析Java Web安全中的代码审计

受空字节截断影响的JDK版本范围:JDK<1.7.40,单是JDK7于2011年07月28日发布至2013年09月10日发表Java SE 7 Update 40这两年多期间受影响的就有16个版本,值得注意的是JDK1.6虽然JDK7修复之后发布了数十个版本,但是并没有任何一个版本修复过这个问题,而JDK8发布时间在JDK7修复以后所以并不受此漏洞影响。

参考:

JDK-8014846 : File and other classes in java.io do not handle embedded nulls properly。

维基百科-Java版本歷史

Oracle Java 历史版本下载

2.1.2 测试Java写文件截断测试

测试类FileNullBytes.java:

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
/**
 * @author yz
 */
public class FileNullBytes {
public static void main(String[] args) {
try {
String fileName = "/tmp/null-bytes.txt\u0000.jpg";
FileOutputStream fos = new FileOutputStream(new File(fileName));
fos.write("Test".getBytes());
fos.flush();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

使用JDK1.7.0.25测试成功截断文件名:

如何分析Java Web安全中的代码审计

使用JDK1.7.0.80测试写文件截断时抛出java.io.FileNotFoundException: Invalid file path异常:

如何分析Java Web安全中的代码审计

空字节截断利用场景

Java空字节截断利用场景最常见的利用场景就是文件上传时后端使用了endWith、正则使用如:.(jpg|png|gif)$验证文件名后缀且文件名最终原样保存,同理文件删除(delete)、获取文件路径(getCanonicalPath)、创建文件(createNewFile)、文件重命名(renameTo)等方法也可适用。

空字节截断修复方案

最简单直接的方式就是升级JDK,如果担心升级JDK出现兼容性问题可在文件操作时检测下文件名中是否包含空字节,如JDK的修复方式:fileName.indexOf('\u0000')即可。

2.1.2 任意文件读取漏洞

任意文件读取漏洞即因为没有验证请求的资源文件是否合法导致的,此类漏洞在Java中有着较高的几率出现,任意文件读取漏洞看似很简单,但是在这个问题上翻车的有不乏一些知名的中间件:Weblogic、Tomcat、Resin又或者是主流MVC框架:Spring MVC、Struts2。所以在审计文件读取功能的时候要非常仔细,或许很容易就会有意想不到的收获!

任意文件读取示例代码file-read.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.io.ByteArrayOutputStream" %>
<%@ page import="java.io.File" %>
<%@ page import="java.io.FileInputStream" %>
<%
    File file = new File(request.getParameter("path"));
    FileInputStream fis = new FileInputStream(file);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] b = new byte[1024];
    int a = -1;
    while ((a = fis.read(b)) != -1) {
        baos.write(b, 0, a);
    }
    out.write("<pre class="brush:php;toolbar:false">" + new String(baos.toByteArray()) + "
");     fis.close(); %>

访问file-read.jsp文件即可读取任意文件:http://localhost:8080/file/file-read.jsp?path=/etc/passwd

如何分析Java Web安全中的代码审计

快速发现这类漏洞得方式其实也是非常简单的,在IDEA中的项目中重点搜下如下文件读取的类。

  1.JDK原始的java.io.FileInputStream类

  2.JDK原始的java.io.RandomAccessFile类

  3.Apache Commons IO提供的org.apache.commons.io.FileUtils类

  4.JDK1.7新增的基于NIO非阻塞异步读取文件的java.nio.channels.AsynchronousFileChannel类。

  5.JDK1.7新增的基于NIO读取文件的java.nio.file.Files类。常用方法如:Files.readAllBytes、Files.readAllLines

如果仍没有什么发现可以搜索一下FileUtil很有可能用户会封装文件操作的工具类。

Java WebSevice

Web Service是一种基于SOAP协议实现的跨语言Web服务调用,在Java中Web Service有如下技术实现:Oracle JWS、Apache Axis1、2、XFire、Apache CXF、JBossWS。

Axis1.4 配置

web.xml配置Axis1.4

如何分析Java Web安全中的代码审计

配置server-config.wsdd文件注册Web Service服务类和方法:

如何分析Java Web安全中的代码审计

FileService类,提供了文件读写接口:

如何分析Java Web安全中的代码审计

使用IDEA创建Web Service项目默认会创建管理Web Service的API:/servlet/AxisServlet、/services、SOAPMonitor、/servlet/AdminServlet,*.jws以及用监控Web Service的端口5001或5101。

如何分析Java Web安全中的代码审计

访问Web Service的FileService服务加上?wsdl参数可以看到FileService提供的服务方法和具体的参数信息。

如何分析Java Web安全中的代码审计

使用SOAP-UI调用Web Service接口示例:

如何分析Java Web安全中的代码审计

需要注意的是Web Service也是可以设置授权认证的,如实现了WS-Security的WSS4J。

如何分析Java Web安全中的代码审计

使用IDEA根据wsdl生成Web Service客户端代码:

如何分析Java Web安全中的代码审计

设置wsdl地址、包名:

如何分析Java Web安全中的代码审计

新建FileServiceTest类测试接口调用:

package org.javaweb.codereview.axis.client;
import java.net.URL;
/**
 * 文件Web Service服务测试
 *
 * @author yz
 */
public class FileServiceTest {
public static void main(String[] args) {
try {
FileServiceService         fileService   = new FileServiceServiceLocator();
URL                        webServiceUrl = new URL("http://localhost:8080/services/FileService");
FileServiceSoapBindingStub soapService   = new FileServiceSoapBindingStub(webServiceUrl, fileService);
String content = soapService.readFile("/etc/passwd");
System.out.println(content);
} catch (Exception e) {
e.printStackTrace();
}
}
}

Das obige ist der detaillierte Inhalt vonSo analysieren Sie die Codeüberwachung in Java Web Security. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen