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
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
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
} 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
} 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
} 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
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
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
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
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
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
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 = "<h1>Hello," + audience + "</h1>"; out.println(greeting); } } } [email protected] 2018-09-09
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 = "<h1>Hello," + audience + "</h1>"; out.println(greeting); } } } [email protected] 2018-09-09
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 = "<h1>Hello," + sanitized + "</h1>"; out.println(greeting); } } } [email protected] 2018-09-09
> 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