JAVA INSTRUMENTATION AT CONTRAST SECURITY How Contrast Security uses the powerful and obscure Java Instrumentation API to detect vulnerable code paths, in two acts [email protected] 2018-09-09
ABOUT ME Johnathan Gilday Java agent developer at Contrast Security. Traditionally, full-stack web application and data services developer github.com/gilday @jdgilday johnathangilday.com [email protected] 2018-09-09
JAVA INSTRUMENTATION AT CONTRAST SECURITY How Contrast Security uses the powerful and obscure Java Instrumentation API to detect vulnerable code paths, in two acts [email protected] 2018-09-09
DID YOU KNOW THE JDK SHIPS WITH AN INSTRUMENTATION PACKAGE THAT CONTAINS JUST 5 CLASSES WHICH ALLOWS DEVELOPERS TO TRANSFORM JVM BYTE CODE AT RUNTIME? [email protected] 2018-09-09
JAVA.LANG.INSTRUMENT Provides services that allow Java programming language agents to instrument programs running on the JVM. The mechanism for instrumentation is modification of the byte-codes of methods. — package docs [email protected] 2018-09-09
HAVE YOU INSTRUMENTED YOUR CODE WITH A JAVA AGENT? > ⚡ APM: App Dynamics, New Relic > ✅ Code Coverage: JaCoCo > # Security: Contrast [email protected] 2018-09-09
SHOW ME THE CODE! Emoji Agent Replaces boring string literals with something more exciting $ java HelloWorld hello, world! $ java \ -javaagent:emoji-agent.jar \ -cp asm-all-5.2.jar:. \ HelloWorld ! hello, world! ignore this asm-all-5.2.jar for now , we'll get there [email protected] 2018-09-09
WHERE CAN I FIND A SAMPLE JAVA PROGRAM? public final class HelloWorld { public static void main(final String[] args) { System.out.println("hello, world!"); } } javac HelloWorld.java [email protected] 2018-09-09
ENTRYPOINT The manifest of the agent JAR file must contain the attribute Premain-Class. The value of this attribute is the name of the agent class. The agent class must implement a public static premain method similar in principle to the main application entry point. — java.lang.instrument JavaDoc public static void premain(String agentArgs, Instrumentation inst); [email protected] 2018-09-09
public static void premain(String args, Instrumentation instrumentation) { instrumentation.addTransformer(new EmojiClassFileTransformer()); } static final class EmojiClassFileTransformer implements ClassFileTransformer { @Override public byte[] transform( final ClassLoader loader, final String className, final Class> classBeingRedefined, final ProtectionDomain protectionDomain, final byte[] classfileBuffer) { throw new RuntimeException("not yet implemented"); } } [email protected] 2018-09-09
public static void premain(String args, Instrumentation instrumentation) { instrumentation.addTransformer(new EmojiClassFileTransformer()); } static final class EmojiClassFileTransformer implements ClassFileTransformer { @Override public byte[] transform( final ClassLoader loader, final String className, final Class> classBeingRedefined, final ProtectionDomain protectionDomain, final byte[] classfileBuffer) { throw new RuntimeException("not yet implemented"); } } [email protected] 2018-09-09
public static void premain(String args, Instrumentation instrumentation) { instrumentation.addTransformer(new EmojiClassFileTransformer()); } static final class EmojiClassFileTransformer implements ClassFileTransformer { @Override public byte[] transform( final ClassLoader loader, final String className, final Class> classBeingRedefined, final ProtectionDomain protectionDomain, final byte[] classfileBuffer) { throw new RuntimeException("not yet implemented"); } } [email protected] 2018-09-09
WHAT DOES HELLOWORLD BYTECODE LOOK LIKE? HelloWorld.java public final class HelloWorld { public static void main(final String[] args) { System.out.println("hello, world!"); } } HelloWorld.class ? [email protected] 2018-09-09
BYTECODE MANIPULATION 101 > ASM is the defacto Java library for reading and writing bytecode > ASM uses a low-level, visitor pattern based reading and writing API > Higher-level libraries built on ASM are typically desirable [email protected] 2018-09-09
EMOJIAGENT ASM 1. ClassReader for reading bytecode from byte[] 2. ClassWriter a visitor that writes instructions to byte[] buffer 3. EmojiClassVisitor a class visitor that composes the EmojiMethodVisitor 4. EmojiMethodVisitor a method visitor that looks for String constants to replace [email protected] 2018-09-09
ASM ClassVisitor private static final class EmojiClassVisitor extends ClassVisitor { EmojiClassVisitor(final ClassVisitor classVisitor) { super(ASM5, classVisitor); } @Override public MethodVisitor visitMethod( final int access, final String name, final String descriptor, final String signature, final String[] exceptions) { final MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); return new EmojiMethodVisitor(mv); } } [email protected] 2018-09-09
ADD ASM-FU TO THE EmojiClassFileTransformer static final class EmojiClassFileTransformer implements ClassFileTransformer { public byte[] transform( final ClassLoader loader, final String className, final Class> classBeingRedefined, final ProtectionDomain protectionDomain, final byte[] classfileBuffer) { final ClassReader reader; try { reader = new ClassReader(new ByteArrayInputStream(classfileBuffer)); } catch (IOException e) { throw new IllegalArgumentException("failed to read class " + className, e); } final int flags = 0; final ClassWriter writer = new ClassWriter(flags); final ClassVisitor visitor = new EmojiClassVisitor(writer); reader.accept(visitor, flags); return writer.toByteArray(); } } [email protected] 2018-09-09
DATA FLOW ANALYSIS Many vulnerabilities, including XSS, SQL injection, command injection, LDAP injection, XML injection, and more happen when programmers send untrusted data to dangerous calls.1 — Jeff Williams, Contrast Co-Founder 1 https://www.contrastsecurity.com/security-influencers/why-appsec-tools-need-great-data-flow-analysis [email protected] 2018-09-09
HOW DOES CONTRAST DISCOVER THE DATA FLOW USING INSTRUMENTATION? Instruments four categories of methods 1. Sources 2. Propagators 3. Sinks 4. Sanitizers [email protected] 2018-09-09
HOW DOES CONTRAST DISCOVER THE DATA FLOW USING INSTRUMENTATION? Instruments four categories of methods 1. Sources 2. Propagators 3. Sinks 4. Sanitizers [email protected] 2018-09-09
SOURCE ! HttpServletRequest.getParameter() is a source - the String it returns is untrusted data. Remember the object reference of that String @WebServlet("/hello-world") public final class VulnerableHelloWorldServlet extends HttpServlet { @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { final String param = "audience"; final String audience = request.getParameter(param) == null ? "world" : request.getParameter(param); response.setContentType("text/html"); try (final PrintWriter out = response.getWriter()) { final String greeting = "Hello," + audience + ""; out.println(greeting); } } } [email protected] 2018-09-09
HOW DOES CONTRAST DISCOVER THE DATA FLOW USING INSTRUMENTATION? Instruments four categories of methods 1. Sources 2. Propagators 3. Sinks 4. Sanitizers [email protected] 2018-09-09
PROPAGATOR ! The StringBuilder.append(String) method is a propagator - it propagates the untrusted data passed in as a method parameter to the StringBuilder. Remember that the String built by this StringBuilder contains untrusted data @WebServlet("/hello-world") public final class VulnerableHelloWorldServlet extends HttpServlet { @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { final String param = "audience"; final String audience = request.getParameter(param) == null ? "world" : request.getParameter(param); response.setContentType("text/html"); try (final PrintWriter out = response.getWriter()) { final String greeting = "Hello," + audience + ""; out.println(greeting); } } } [email protected] 2018-09-09
HOW DOES CONTRAST DISCOVER THE DATA FLOW USING INSTRUMENTATION? Instruments four categories of methods 1. Sources 2. Propagators 3. Sinks 4. Sanitizers [email protected] 2018-09-09
SINK ! The PrintWriter.println(String) method of an instance returned by HttpServletResponse.getWriter() is a sink - when untrusted data that has not been HTML encoded is passed to this PrintWriter, there is an XSS vulnerability @WebServlet("/hello-world") public final class VulnerableHelloWorldServlet extends HttpServlet { @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { final String param = "audience"; final String audience = request.getParameter(param) == null ? "world" : request.getParameter(param); response.setContentType("text/html"); try (final PrintWriter out = response.getWriter()) { final String greeting = "Hello," + audience + ""; out.println(greeting); } } } [email protected] 2018-09-09
! XSS VULNERABILITY DETECTED Data from the HttpServletRequest source was propagated to a new String which was passed to the PrintWriter.println(String) sink without being sanitized [email protected] 2018-09-09
HOW DOES CONTRAST DISCOVER THE DATA FLOW USING INSTRUMENTATION? Instruments four categories of methods 1. Sources 2. Propagators 3. Sinks 4. Sanitizers [email protected] 2018-09-09
LET'S PATCH THE VulnerableHelloWorldServlet ! The Apache Commons StringEscapeUtils.escapeHTML method is a sanitizer - the String instance returned by this method is HTML encoded @WebServlet("/hello-world") public final class HelloWorldServlet extends HttpServlet { @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { final String param = "audience"; final String audience = request.getParameter(param) == null ? "world" : request.getParameter(param); response.setContentType("text/html"); try (final PrintWriter out = response.getWriter()) { final String sanitized = StringEscapeUtils.escapeHTML(audience); final String greeting = "Hello," + sanitized + ""; out.println(greeting); } } } [email protected] 2018-09-09
WHERE ARE YOUR VULNERABILITIES? Contrast Community Edition is free for Java developers Try it out then tell us how you feel! [email protected] 2018-09-09
IMAGE CREDITS > Marek Cyzio https://flic.kr/p/22MbuxK > Pål-Kristian Hamre https://flic.kr/p/mn3ScM > ricky montalvo https://flic.kr/p/6882RG > Porapak Apichodilok https://www.pexels.com/photo/adult-barista-beverage-cafe-373639/ > Raw Pixel https://www.pexels.com/photo/yeah-with-brown-wooden-frame-745407/ > Photo by Patrick Fore on Unsplash > Photo by Christian Wiediger on Unsplash > Photo by Magda Ehlers from Pexels > Photo by Jairo Alzate on Unsplash > Photo by Waranya Mooldee on Unsplash > Photo by Leio McLaren (@leiomclaren) on Unsplash [email protected] 2018-09-09