Skip to content

Commit

Permalink
Start to implement inline-gadgets
Browse files Browse the repository at this point in the history
  • Loading branch information
qtc-de committed Oct 20, 2023
1 parent cb150ad commit 295fd56
Show file tree
Hide file tree
Showing 9 changed files with 267 additions and 14 deletions.
16 changes: 16 additions & 0 deletions src/de/qtc/rmg/exceptions/InvalidGadgetException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package de.qtc.rmg.exceptions;

/**
* @author Tobias Neitzel (@qtc_de)
*/
public class InvalidGadgetException extends Exception
{
private static final long serialVersionUID = 1L;

public InvalidGadgetException() {}

public InvalidGadgetException(String message)
{
super(message);
}
}
2 changes: 1 addition & 1 deletion src/de/qtc/rmg/internal/ArgumentHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ public Object getGadget()
else
{
gadget = (String) RMGOption.require(RMGOption.GADGET_NAME);
command = RMGOption.require(RMGOption.GADGET_CMD);
command = RMGOption.GADGET_CMD.getValue();
}

return PluginSystem.getPayloadObject(this.getAction(), gadget, command);
Expand Down
8 changes: 7 additions & 1 deletion src/de/qtc/rmg/internal/RMGOption.java
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,10 @@ public enum RMGOption {
SOCKET_FACTORY_SSL("--socket-factory-ssl", "enforce SSL connections from dynamically created socket factories", Arguments.storeTrue(), RMGOptionGroup.CONNECTION),
SOCKET_FACTORY("--socket-factory", "dynamically create a socket factory class with the specified name", Arguments.store(), RMGOptionGroup.CONNECTION, "classname"),

SPRING_REMOTING("--spring-remoting", "enforce method calls to be dispatched via spring remoting", Arguments.storeTrue(), RMGOptionGroup.CONNECTION);
SPRING_REMOTING("--spring-remoting", "enforce method calls to be dispatched via spring remoting", Arguments.storeTrue(), RMGOptionGroup.CONNECTION),

FILE_GADGET("--gadget-file", "the specified gadget is actually a file containing the gadget", Arguments.storeTrue(), RMGOptionGroup.ACTION),
B64_GADGET("--gadget-b64", "the specified gadget is actually a b64 string containing the gadget", Arguments.storeTrue(), RMGOptionGroup.ACTION);

public final String name;
public final String description;
Expand Down Expand Up @@ -366,6 +369,9 @@ public static void addModifiers(RMGOption option, Argument arg)
} else if( option == RMGOption.DGC_METHOD ) {
arg.choices("clean", "dirty");

} else if( option == RMGOption.GADGET_CMD || option == RMGOption.BIND_GADGET_CMD ) {
arg.nargs("?");

} else if( intOptions.contains(option) ) {
arg.type(Integer.class);

Expand Down
109 changes: 109 additions & 0 deletions src/de/qtc/rmg/io/GadgetOutputStream.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package de.qtc.rmg.io;

import java.io.IOException;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;

public class GadgetOutputStream implements ObjectOutput
{
private final ObjectOutput out;

public GadgetOutputStream(ObjectOutput out)
{
this.out = out;
}

@Override
public void writeBoolean(boolean v) throws IOException {
out.writeBoolean(v);
}

@Override
public void writeByte(int v) throws IOException {
out.writeByte(v);
}

@Override
public void writeShort(int v) throws IOException {
out.writeShort(v);
}

@Override
public void writeChar(int v) throws IOException {
out.writeChar(v);
}

@Override
public void writeInt(int v) throws IOException {
out.writeInt(v);
}

@Override
public void writeLong(long v) throws IOException {
out.writeLong(v);
}

@Override
public void writeFloat(float v) throws IOException {
out.writeFloat(v);
}

@Override
public void writeDouble(double v) throws IOException {
out.writeDouble(v);
}

@Override
public void writeBytes(String s) throws IOException {
out.writeBytes(s);
}

@Override
public void writeChars(String s) throws IOException {
out.writeChars(s);
}

@Override
public void writeUTF(String s) throws IOException {
out.writeUTF(s);
}

@Override
public void writeObject(Object obj) throws IOException {
if (obj instanceof GadgetWrapper)
{
RawObjectOutputStream rout = new RawObjectOutputStream(out);
rout.writeRawObject(((GadgetWrapper)obj).getGadget());
}

else
{
out.writeObject(obj);
}
}

@Override
public void write(int b) throws IOException {
out.write(b);
}

@Override
public void write(byte[] b) throws IOException {
out.write(b);
}

@Override
public void write(byte[] b, int off, int len) throws IOException {
out.write(b, off, len);
}

@Override
public void flush() throws IOException {
out.flush();
}

@Override
public void close() throws IOException {
out.close();
}
}
40 changes: 40 additions & 0 deletions src/de/qtc/rmg/io/GadgetWrapper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package de.qtc.rmg.io;

import java.nio.ByteBuffer;
import java.util.Base64;

import de.qtc.rmg.exceptions.InvalidGadgetException;
import de.qtc.rmg.utils.RMGUtils;

public class GadgetWrapper
{
private final byte[] gadget;

public GadgetWrapper(String gadget) throws InvalidGadgetException
{
this.gadget = truncate(Base64.getDecoder().decode(gadget.getBytes()));
}

public GadgetWrapper(byte[] gadget) throws InvalidGadgetException
{
this.gadget = truncate(gadget);
}

public byte[] getGadget()
{
return gadget;
}

private byte[] truncate(byte[] fullGadget) throws InvalidGadgetException
{
if (!ByteBuffer.wrap(fullGadget, 0, 4).equals(ByteBuffer.wrap(RMGUtils.hexToBytes("aced0005"))))
{
throw new InvalidGadgetException();
}

byte[] truncated = new byte[fullGadget.length - 4];
System.arraycopy(fullGadget, 4, truncated, 0, truncated.length);

return truncated;
}
}
29 changes: 28 additions & 1 deletion src/de/qtc/rmg/io/RawObjectOutputStream.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

import java.io.DataOutput;
import java.io.IOException;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import de.qtc.rmg.internal.ExceptionHandler;

Expand All @@ -18,14 +20,15 @@ public class RawObjectOutputStream {

private DataOutput bout;
private OutputStream outStream;
private Method setBlockDataMode;

/**
* Wraps an ObjectOutputStream into an RawObjectOutputStream. The underlying OutputStream object is made
* accessible via reflection. This underlying OutputStream can then be used to perform raw byte operations.
*
* @param out OutputStream to wrap around
*/
public RawObjectOutputStream(ObjectOutputStream out)
public RawObjectOutputStream(ObjectOutput out)
{
try {
Field boutField = ObjectOutputStream.class.getDeclaredField("bout");
Expand All @@ -38,6 +41,9 @@ public RawObjectOutputStream(ObjectOutputStream out)
if(c.getCanonicalName().endsWith("BlockDataOutputStream")) {
outputStreamField = c.getDeclaredField("out");
outputStreamField.setAccessible(true);

setBlockDataMode = c.getDeclaredMethod("setBlockDataMode", new Class<?>[] {boolean.class});
setBlockDataMode.setAccessible(true);
}
}

Expand All @@ -58,4 +64,25 @@ public void writeRaw(byte content) throws IOException
{
outStream.write(content);
}

/**
* Write raw bytes to the underlying output stream.
*
* @param content bytes to write
* @throws IOException
*/
public void writeRawObject(byte[] content) throws IOException
{
try
{
setBlockDataMode.invoke(bout, false);
outStream.write(content);
setBlockDataMode.invoke(bout, true);
}

catch (Exception e)
{
e.printStackTrace();
}
}
}
16 changes: 12 additions & 4 deletions src/de/qtc/rmg/networking/RMIEndpoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import de.qtc.rmg.internal.MethodArguments;
import de.qtc.rmg.internal.MethodCandidate;
import de.qtc.rmg.internal.Pair;
import de.qtc.rmg.io.GadgetOutputStream;
import de.qtc.rmg.io.MaliciousOutputStream;
import de.qtc.rmg.io.RawObjectInputStream;
import de.qtc.rmg.plugin.PluginSystem;
Expand Down Expand Up @@ -227,11 +228,14 @@ public void unmanagedCall(ObjID objID, int callID, long methodHash, MethodArgume

try {
ObjectOutputStream out = (ObjectOutputStream)call.getOutputStream();

if(locationStream)
out = new MaliciousOutputStream(out);

for(Pair<Object,Class> p : callArguments) {
marshalValue(p.right(), p.left(), out);
for(Pair<Object,Class> p : callArguments)
{
ObjectOutput gadgetStream = new GadgetOutputStream(out);
marshalValue(p.right(), p.left(), gadgetStream);
}

} catch(java.io.IOException e) {
Expand Down Expand Up @@ -276,7 +280,8 @@ public void unmanagedCall(ObjID objID, int callID, long methodHash, MethodArgume
*/
private static void marshalValue(Class<?> type, Object value, ObjectOutput out) throws IOException
{
if (type.isPrimitive()) {
if (type.isPrimitive())
{
if (type == int.class) {
out.writeInt(((Integer) value).intValue());
} else if (type == boolean.class) {
Expand All @@ -296,7 +301,10 @@ private static void marshalValue(Class<?> type, Object value, ObjectOutput out)
} else {
throw new Error("Unrecognized primitive type: " + type);
}
} else {
}

else
{
out.writeObject(value);
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/de/qtc/rmg/operations/Operation.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ public enum Operation {
RMGOption.BIND_GADGET_NAME,
RMGOption.BIND_GADGET_CMD,
RMGOption.YSO,
RMGOption.B64_GADGET,
RMGOption.FILE_GADGET,
RMGOption.SOCKET_FACTORY,
RMGOption.SOCKET_FACTORY_SSL,
RMGOption.SOCKET_FACTORY_PLAIN,
Expand Down Expand Up @@ -184,6 +186,8 @@ public enum Operation {
RMGOption.GADGET_NAME,
RMGOption.GADGET_CMD,
RMGOption.YSO,
RMGOption.B64_GADGET,
RMGOption.FILE_GADGET,
}),

OBJID("dispatchObjID", "<objid>", "Print information contained within an ObjID", new RMGOption[] {
Expand Down Expand Up @@ -216,6 +220,8 @@ public enum Operation {
RMGOption.BIND_GADGET_NAME,
RMGOption.BIND_GADGET_CMD,
RMGOption.YSO,
RMGOption.B64_GADGET,
RMGOption.FILE_GADGET,
RMGOption.SOCKET_FACTORY,
RMGOption.SOCKET_FACTORY_SSL,
RMGOption.SOCKET_FACTORY_PLAIN,
Expand Down Expand Up @@ -274,6 +280,8 @@ public enum Operation {
RMGOption.GADGET_NAME,
RMGOption.GADGET_CMD,
RMGOption.YSO,
RMGOption.B64_GADGET,
RMGOption.FILE_GADGET,
RMGOption.FORCE_ACTIVATION,
RMGOption.SERIAL_VERSION_UID,
RMGOption.SOCKET_FACTORY,
Expand Down
Loading

0 comments on commit 295fd56

Please sign in to comment.