forked from WebGoat/WebGoat
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
deserialization made solvable again (WebGoat#673)
* first objects and unit tests for making a fix for the lesson * example added * unit test for windows and linux * added unit tests hints and feedbacks and updated lesson pages * small typo correction
- Loading branch information
Showing
8 changed files
with
330 additions
and
24 deletions.
There are no files selected for viewing
34 changes: 34 additions & 0 deletions
34
webgoat-integration-tests/src/test/java/org/owasp/webgoat/DeserializationTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package org.owasp.webgoat; | ||
|
||
import java.io.IOException; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
import org.dummy.insecure.framework.VulnerableTaskHolder; | ||
import org.junit.Test; | ||
import org.owasp.webgoat.deserialization.SerializationHelper; | ||
|
||
public class DeserializationTest extends IntegrationTest { | ||
|
||
private static String OS = System.getProperty("os.name").toLowerCase(); | ||
|
||
@Test | ||
public void runTests() throws IOException { | ||
startLesson("InsecureDeserialization"); | ||
|
||
Map<String, Object> params = new HashMap<>(); | ||
params.clear(); | ||
|
||
if (OS.indexOf("win")>-1) { | ||
params.put("token", SerializationHelper.toString(new VulnerableTaskHolder("wait", "ping localhost -n 5"))); | ||
} else { | ||
params.put("token", SerializationHelper.toString(new VulnerableTaskHolder("wait", "sleep 5"))); | ||
} | ||
checkAssignment(url("/WebGoat/InsecureDeserialization/task"),params,true); | ||
|
||
checkResults("/InsecureDeserialization/"); | ||
|
||
} | ||
|
||
|
||
} |
70 changes: 70 additions & 0 deletions
70
...cure-deserialization/src/main/java/org/dummy/insecure/framework/VulnerableTaskHolder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package org.dummy.insecure.framework; | ||
|
||
import java.io.BufferedReader; | ||
import java.io.IOException; | ||
import java.io.InputStreamReader; | ||
import java.io.ObjectInputStream; | ||
import java.io.Serializable; | ||
import java.time.LocalDateTime; | ||
|
||
public class VulnerableTaskHolder implements Serializable { | ||
|
||
private static final long serialVersionUID = 2; | ||
|
||
private String taskName; | ||
private String taskAction; | ||
private LocalDateTime requestedExecutionTime; | ||
|
||
public VulnerableTaskHolder(String taskName, String taskAction) { | ||
super(); | ||
this.taskName = taskName; | ||
this.taskAction = taskAction; | ||
this.requestedExecutionTime = LocalDateTime.now(); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "VulnerableTaskHolder [taskName=" + taskName + ", taskAction=" + taskAction + ", requestedExecutionTime=" | ||
+ requestedExecutionTime + "]"; | ||
} | ||
|
||
/** | ||
* Execute a task when de-serializing a saved or received object. | ||
* @author stupid develop | ||
*/ | ||
private void readObject( ObjectInputStream stream ) throws Exception { | ||
//unserialize data so taskName and taskAction are available | ||
stream.defaultReadObject(); | ||
|
||
//do something with the data | ||
System.out.println("restoring task: "+taskName); | ||
System.out.println("restoring time: "+requestedExecutionTime); | ||
|
||
if (requestedExecutionTime!=null && | ||
(requestedExecutionTime.isBefore(LocalDateTime.now().minusMinutes(10)) | ||
|| requestedExecutionTime.isAfter(LocalDateTime.now()))) { | ||
//do nothing is the time is not within 10 minutes after the object has been created | ||
System.out.println(this.toString()); | ||
throw new IllegalArgumentException("outdated"); | ||
} | ||
|
||
//condition is here to prevent you from destroying the goat altogether | ||
if ((taskAction.startsWith("sleep")||taskAction.startsWith("ping")) | ||
&& taskAction.length() < 22) { | ||
System.out.println("about to execute: "+taskAction); | ||
try { | ||
Process p = Runtime.getRuntime().exec(taskAction); | ||
BufferedReader in = new BufferedReader( | ||
new InputStreamReader(p.getInputStream())); | ||
String line = null; | ||
while ((line = in.readLine()) != null) { | ||
System.out.println(line); | ||
} | ||
} catch (IOException e) { | ||
e.printStackTrace(); | ||
} | ||
} | ||
|
||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
54 changes: 54 additions & 0 deletions
54
...-deserialization/src/main/java/org/owasp/webgoat/deserialization/SerializationHelper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package org.owasp.webgoat.deserialization; | ||
|
||
import java.io.ByteArrayInputStream; | ||
import java.io.ByteArrayOutputStream; | ||
import java.io.DataOutputStream; | ||
import java.io.IOException; | ||
import java.io.ObjectInputStream; | ||
import java.io.ObjectOutputStream; | ||
import java.io.Serializable; | ||
import java.util.Base64; | ||
|
||
public class SerializationHelper { | ||
|
||
private final static char[] hexArray = "0123456789ABCDEF".toCharArray(); | ||
|
||
public static Object fromString( String s ) throws IOException , | ||
ClassNotFoundException { | ||
byte [] data = Base64.getDecoder().decode( s ); | ||
ObjectInputStream ois = new ObjectInputStream( | ||
new ByteArrayInputStream( data ) ); | ||
Object o = ois.readObject(); | ||
ois.close(); | ||
return o; | ||
} | ||
|
||
public static String toString( Serializable o ) throws IOException { | ||
|
||
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | ||
ObjectOutputStream oos = new ObjectOutputStream( baos ); | ||
oos.writeObject( o ); | ||
oos.close(); | ||
return Base64.getEncoder().encodeToString(baos.toByteArray()); | ||
} | ||
|
||
public static String show() throws IOException { | ||
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | ||
DataOutputStream dos = new DataOutputStream(baos); | ||
dos.writeLong(-8699352886133051976L); | ||
dos.close(); | ||
byte[] longBytes = baos.toByteArray(); | ||
return bytesToHex(longBytes); | ||
} | ||
|
||
public static String bytesToHex(byte[] bytes) { | ||
char[] hexChars = new char[bytes.length * 2]; | ||
for ( int j = 0; j < bytes.length; j++ ) { | ||
int v = bytes[j] & 0xFF; | ||
hexChars[j * 2] = hexArray[v >>> 4]; | ||
hexChars[j * 2 + 1] = hexArray[v & 0x0F]; | ||
} | ||
return new String(hexChars); | ||
} | ||
|
||
} |
12 changes: 11 additions & 1 deletion
12
webgoat-lessons/insecure-deserialization/src/main/resources/i18n/WebGoatLabels.properties
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,14 @@ | ||
insecure-deserialization.title=Insecure Deserialization | ||
|
||
insecure-deserialization.intercept.success=Dangerous object received! | ||
insecure-deserialization.intercept.failure=Try again | ||
insecure-deserialization.intercept.failure=Try again | ||
|
||
insecure-deserialization.invalidversion=The serialization id does not match. Probably the version has been updated. Let's try again. | ||
insecure-deserialization.expired=The task is not executable between now and the next ten minutes, so the action will be ignored. Maybe you copied an old solution? Let's try again. | ||
insecure-deserialization.wrongobject=That is not the VulnerableTaskHolder object. Good try! because the code is not checking this after running the readObject(). Let's try again with the right object. | ||
insecure-deserialization.stringobject=That is not the VulnerableTaskHolder object. However a plain String is harmless. Let's try again with the right object. | ||
|
||
|
||
insecure-deserialization.hints.1=WebGoat probably contains the org.dummy.insecure.framework.VulnerableTaskHolder class as shown on the lesson pages. Use this to construct and serialize your attack. | ||
insecure-deserialization.hints.2=The VulnerableTaskHolder might have been updated on the server with a next version number. | ||
insecure-deserialization.hints.3=Not all actions are allowed anymore. The readObject has been changed. For serializing it does not effect the data. Follow the additional hints from the feedback on your attempts. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
94 changes: 94 additions & 0 deletions
94
...cure-deserialization/src/test/java/org/owasp/webgoat/deserialization/DeserializeTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
package org.owasp.webgoat.deserialization; | ||
|
||
import static org.hamcrest.Matchers.is; | ||
import static org.mockito.Mockito.when; | ||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; | ||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | ||
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; | ||
|
||
import org.dummy.insecure.framework.VulnerableTaskHolder; | ||
import org.hamcrest.CoreMatchers; | ||
import org.junit.Before; | ||
import org.junit.Test; | ||
import org.junit.runner.RunWith; | ||
import org.mockito.junit.MockitoJUnitRunner; | ||
import org.owasp.webgoat.assignments.AssignmentEndpointTest; | ||
import org.springframework.test.web.servlet.MockMvc; | ||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; | ||
|
||
@RunWith(MockitoJUnitRunner.class) | ||
public class DeserializeTest extends AssignmentEndpointTest { | ||
|
||
private MockMvc mockMvc; | ||
|
||
private static String OS = System.getProperty("os.name").toLowerCase(); | ||
|
||
@Before | ||
public void setup() { | ||
InsecureDeserializationTask insecureTask = new InsecureDeserializationTask(); | ||
init(insecureTask); | ||
this.mockMvc = standaloneSetup(insecureTask).build(); | ||
when(webSession.getCurrentLesson()).thenReturn(new InsecureDeserialization()); | ||
} | ||
|
||
@Test | ||
public void success() throws Exception { | ||
if (OS.indexOf("win")>-1) { | ||
mockMvc.perform(MockMvcRequestBuilders.post("/InsecureDeserialization/task") | ||
.header("x-request-intercepted", "true") | ||
.param("token", SerializationHelper.toString(new VulnerableTaskHolder("wait", "ping localhost -n 5")))) | ||
.andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(true))); | ||
} else { | ||
mockMvc.perform(MockMvcRequestBuilders.post("/InsecureDeserialization/task") | ||
.header("x-request-intercepted", "true") | ||
.param("token", SerializationHelper.toString(new VulnerableTaskHolder("wait", "sleep 5")))) | ||
.andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(true))); | ||
} | ||
} | ||
|
||
@Test | ||
public void fail() throws Exception { | ||
mockMvc.perform(MockMvcRequestBuilders.post("/InsecureDeserialization/task") | ||
.header("x-request-intercepted", "true") | ||
.param("token", SerializationHelper.toString(new VulnerableTaskHolder("delete", "rm *")))) | ||
.andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(false))); | ||
} | ||
|
||
@Test | ||
public void wrongVersion() throws Exception { | ||
String token = "rO0ABXNyADFvcmcuZHVtbXkuaW5zZWN1cmUuZnJhbWV3b3JrLlZ1bG5lcmFibGVUYXNrSG9sZGVyAAAAAAAAAAECAANMABZyZXF1ZXN0ZWRFeGVjdXRpb25UaW1ldAAZTGphdmEvdGltZS9Mb2NhbERhdGVUaW1lO0wACnRhc2tBY3Rpb250ABJMamF2YS9sYW5nL1N0cmluZztMAAh0YXNrTmFtZXEAfgACeHBzcgANamF2YS50aW1lLlNlcpVdhLobIkiyDAAAeHB3DgUAAAfjCR4GIQgMLRSoeHQACmVjaG8gaGVsbG90AAhzYXlIZWxsbw"; | ||
mockMvc.perform(MockMvcRequestBuilders.post("/InsecureDeserialization/task") | ||
.header("x-request-intercepted", "true") | ||
.param("token", token)) | ||
.andExpect(status().isOk()) | ||
.andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("insecure-deserialization.invalidversion")))) | ||
.andExpect(jsonPath("$.lessonCompleted", is(false))); | ||
} | ||
|
||
@Test | ||
public void expiredTask() throws Exception { | ||
String token = "rO0ABXNyADFvcmcuZHVtbXkuaW5zZWN1cmUuZnJhbWV3b3JrLlZ1bG5lcmFibGVUYXNrSG9sZGVyAAAAAAAAAAICAANMABZyZXF1ZXN0ZWRFeGVjdXRpb25UaW1ldAAZTGphdmEvdGltZS9Mb2NhbERhdGVUaW1lO0wACnRhc2tBY3Rpb250ABJMamF2YS9sYW5nL1N0cmluZztMAAh0YXNrTmFtZXEAfgACeHBzcgANamF2YS50aW1lLlNlcpVdhLobIkiyDAAAeHB3DgUAAAfjCR4IDC0YfvNIeHQACmVjaG8gaGVsbG90AAhzYXlIZWxsbw"; | ||
mockMvc.perform(MockMvcRequestBuilders.post("/InsecureDeserialization/task") | ||
.header("x-request-intercepted", "true") | ||
.param("token", token)) | ||
.andExpect(status().isOk()) | ||
.andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("insecure-deserialization.expired")))) | ||
.andExpect(jsonPath("$.lessonCompleted", is(false))); | ||
} | ||
|
||
|
||
|
||
@Test | ||
public void checkOtherObject() throws Exception { | ||
String token = "rO0ABXQAVklmIHlvdSBkZXNlcmlhbGl6ZSBtZSBkb3duLCBJIHNoYWxsIGJlY29tZSBtb3JlIHBvd2VyZnVsIHRoYW4geW91IGNhbiBwb3NzaWJseSBpbWFnaW5l"; | ||
mockMvc.perform(MockMvcRequestBuilders.post("/InsecureDeserialization/task") | ||
.header("x-request-intercepted", "true") | ||
.param("token", token)) | ||
.andExpect(status().isOk()) | ||
.andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("insecure-deserialization.stringobject")))) | ||
.andExpect(jsonPath("$.lessonCompleted", is(false))); | ||
} | ||
|
||
|
||
|
||
} |
Oops, something went wrong.