作者:kw0ng

开始

通达OA上传到包含漏洞分析的文章已经有很多,本文重点分析,文件上传处决定路径信息是否回显的UPLOAD_MODE参数是怎么传递的。

代码分析

触发文件上传点位于/ispirit/im/upload.php中,服务端在接收文件信息的同时还需要几个参数,如不了解 multipart/form-data类型如何传递参数的可以先去学习下,通达OA的PHP代码采用了Zend54加密,但是我使用两个不同的工具解密却得到了不一致的代码,这也导致了这篇文章差点难产。首先是第一段代码:

$P = $_POST['P'];if (isset($P) || $P != '') {    ob_start();    include_once 'inc/session.php'; //如果P不为空    session_id($P);    session_start();    session_write_close();} else {    include_once './auth.php';}

这段代码需要一个POST传参获取P值,且为空时将会包含auth.php进行重认证,因为我们的POST包需要一个P值且不为空。

$DEST_UID = $_POST['DEST_UID']; $dataBack = array();if ($DEST_UID != '' && !td_verify_ids($ids)) {     $dataBack = array('status' => 0, 'content' => '-ERR ' . _('接收方ID无效'));    echo json_encode(data2utf8($dataBack));    exit;}if (strpos($DEST_UID, ',') !== false) { } else {    $DEST_UID = intval($DEST_UID); }if ($DEST_UID == 0) {    if ($UPLOAD_MODE != 2) {         $dataBack = array('status' => 0, 'content' => '-ERR ' . _('接收方ID无效'));        echo json_encode(data2utf8($dataBack));        exit;    }}

这段代码中我们需要提供DEST_UID参数,且如果DEST_UID为0,则触发判断UPLOAD_MODE是否等于2,不等于2则报error并退出,因此将DEST_UID不等于0可绕过。

if (1 <= count($_FILES)) { //返回数组中元素的数目:    if ($UPLOAD_MODE == '1') { //如果UPLOAD_MODE = 1        if (strlen(urldecode($_FILES['ATTACHMENT']['name'])) != strlen($_FILES['ATTACHMENT']['name'])) {            $_FILES['ATTACHMENT']['name'] = urldecode($_FILES['ATTACHMENT']['name']);        }    }    $ATTACHMENTS = upload('ATTACHMENT', $MODULE, false);    if (!is_array($ATTACHMENTS)) {        $dataBack = array('status' => 0, 'content' => '-ERR ' . $ATTACHMENTS);        echo json_encode(data2utf8($dataBack));        exit;    }    ob_end_clean();    $ATTACHMENT_ID = substr($ATTACHMENTS['ID'], 0, -1);    $ATTACHMENT_NAME = substr($ATTACHMENTS['NAME'], 0, -1);    if ($TYPE == 'mobile') {        $ATTACHMENT_NAME = td_iconv(urldecode($ATTACHMENT_NAME), 'utf-8', MYOA_CHARSET);    }} else {    $dataBack = array('status' => 0, 'content' => '-ERR ' . _('无文件上传'));    echo json_encode(data2utf8($dataBack));    exit;}
  1. 判断1 <= count($FILES) 就是$FILES是否取到上传数据。

  2. 判断UPLOAD_MODE是否等于1,如果等于1且文件名url解码后的长度不等于原长度则将文件名url解码。

  3. 调用upload函数$ATTACHMENTS = upload('ATTACHMENT', $MODULE, false);传入3个参数,$MODULE = 'im';。

  4. 使用PHP的$FILES函数来获取我们上传的文件信息$FILES['ATTACHMENT']['name'] $_FILES的第一个下标必须是我们的input name值,因此我们的POST包的Content-Disposition: form-data; name="ATTACHMENT"; filename="jpg"中的name必须是'ATTACHMENT'。

else if ($UPLOAD_MODE == "2") {  $DURATION = intval($_POST["DURATION"]);  $CONTENT = "[vm]" . $ATTACHMENT_ID . "|" . $ATTACHMENT_NAME . "|" . $DURATION . "[/vm]";  $query = "INSERT INTO WEIXUN_SHARE (UID, CONTENT, ADDTIME) VALUES ('" . $_SESSION["LOGIN_UID"] . "', '" . $CONTENT . "', '" . time() . "')";  $cursor = exequery(TD::conn(), $query);  echo "+OK " . $CONTENT;}else if ($UPLOAD_MODE == "3") {  if (is_thumbable($ATTACHMENT_NAME)) {    $FILE_PATH = attach_real_path($ATTACHMENT_ID, $ATTACHMENT_NAME, $MODULE);    $THUMB_FILE_PATH = substr($FILE_PATH, 0, strlen($FILE_PATH) - strlen($ATTACHMENT_NAME)) . "thumb_" . $ATTACHMENT_NAME;    CreateThumb($FILE_PATH, 320, 240, $THUMB_FILE_PATH);  }  echo "+OK " . $ATTACHMENT_ID;}

本段代码说明了UPLOAD_MODE等于2或3的时候会返回$CONTENT或$ATTACHMENT_ID变量的值(1也可以),且返回值与最终文件上传所在的路径、文件名是相关的。

综上所述我们得到了3个信息

  • 存在P值且不为空 ($_POST["P"]获取)

  • DEST_UID不为0 ($POST["DEST_UID"]获取)

  • UPLOAD_MODE = 1或2或3 (非$POST["UPLOAD_MODE"]获取)

  • Content-Disposition中name值为"ATTACHMENT"

流程图:

变量覆盖

由于在upload.php中未找到取UPLOAD_MODE值的方法,但在实际测试中POST的UPLOAD_MODE值可以被正常带入且影响文件上传走向,因此判断接收UPLOAD_MODE值的方法存在于被包含的文件中,在解密后使用搜索工具也仅发现UPLOAD_MODE这个参数名仅存在于upload.php中,开始追溯之旅最后在common.inc.php文件中发现了UPLOAD_MODE的源头.

具体调用为upload.php -> session.php -> coon.php -> td_config.php -> common.inc.php

漏洞代码为:

if (0 < count($_POST)) {    $arr_html_fields = array();    foreach ($_POST as $s_key => $s_value) {        if (substr($s_key, 0, 7) == '_SERVER') {            continue;        }        if (substr($s_key, 0, 15) != 'TD_HTML_EDITOR_') {            if (!is_array($s_value)) {                $_POST[$s_key] = addslashes(strip_tags($s_value));            }            ${$s_key} = $_POST[$s_key];        } else {            if ($s_key == 'TD_HTML_EDITOR_FORM_HTML_DATA' || $s_key == 'TD_HTML_EDITOR_PRCS_IN' || $s_key == 'TD_HTML_EDITOR_PRCS_OUT' || $s_key == 'TD_HTML_EDITOR_QTPL_PRCS_SET' || isset($_POST['ACTION_TYPE']) && ($_POST['ACTION_TYPE'] == 'approve_center' || $_POST['ACTION_TYPE'] == 'workflow' || $_POST['ACTION_TYPE'] == 'sms' || $_POST['ACTION_TYPE'] == 'wiki') && ($s_key == 'CONTENT' || $s_key == 'TD_HTML_EDITOR_CONTENT' || $s_key == 'TD_HTML_EDITOR_TPT_CONTENT')) {                unset($_POST[$s_key]);                $s_key = $s_key == 'CONTENT' ? $s_key : substr($s_key, 15);                ${$s_key} = addslashes($s_value);                $arr_html_fields[$s_key] = ${$s_key};            } else {                $encoding = mb_detect_encoding($s_value, 'GBK,UTF-8');                unset($_POST[$s_key]);                $s_key = substr($s_key, 15);                ${$s_key} = addslashes(rich_text_clean($s_value, $encoding));                $arr_html_fields[$s_key] = ${$s_key};            }        }    }    reset($_POST);    $_POST = array_merge($_POST, $arr_html_fields);}

首先一开始对$_POST长度进行了判断,这里$_POST实际是一个数组,存储了客户端传递的参数与值,接着使用foreach函数对数组进行遍历,foreach函数也是CTF变量覆盖漏洞经常考察的知识点,在这里我们假设$_POST数组中key为"UPLOAD_MODE",value为"2",那么我们将会最终进入这段代码中:

if (substr($s_key, 0, 15) != 'TD_HTML_EDITOR_') {            if (!is_array($s_value)) {                $_POST[$s_key] = addslashes(strip_tags($s_value));            }            ${$s_key} = $_POST[$s_key];

关键代码:

${$s_key}=$_POST[$s_key];

方便大家理解我使用IDE将这段代码运行下.

可以看到最终数组键名UPLOAD_MODE成了了变量名,而他的对应键值成为了变量值.

这也就是upload.php未直接接收UPLOAD_MODE值,而我们仍可以传递此参数影响函数走向的原因.

RCE

在明白了上传流程后,我们还需要配合本次的包含漏洞来包含我们上传的代码实现RCE,文件包含利用点在/ispirit/interface/gateway.php文件中. 首先

if ($P != "") {  if (preg_match("/[^a-z0-9;]+/i", $P)) {    echo _("非法参数");    exit();  }

参数P要为空值.接着

if ($json) {  $json = stripcslashes($json);  $json = (array) json_decode($json);  foreach ($json as $key => $val ) {    if ($key == "data") {      $val = (array) $val;      foreach ($val as $keys => $value ) {        $keys = $value;      }    }    if ($key == "url") {      $url = $val;    }  }  if ($url != "") {    if (substr($url, 0, 1) == "/") {      $url = substr($url, 1);    }    if ((strpos($url, "general/") !== false) || (strpos($url, "ispirit/") !== false) || (strpos($url, "module/") !== false)) {      include_once $url;    }  }  exit();}

由于存在json_decode($json);因此我们需要构造一个json,以及一个key为url且含有general/或ispirit/或module/的值,让函数走到include_once $url;处就完成了文件包含,至于$json从哪来,我想看到这你就明白了.

include_once "inc/session.php";include_once "inc/conn.php"

关于我们

蛇獴攻防实验室成立于2019年11月,专注网络攻防技术。

地点:吉林·长春

html 怎么让tr的css覆盖td的_通达OA上传漏洞之变量覆盖分析相关推荐

  1. jmeter file upload 变量_通达OA上传漏洞之变量覆盖分析

    作者:kw0ng 开始 通达OA上传到包含漏洞分析的文章已经有很多,本文重点分析,文件上传处决定路径信息是否回显的UPLOAD_MODE参数是怎么传递的. 代码分析 触发文件上传点位于/ispirit ...

  2. HDFS重复上传文件将会覆盖原文件

    HDFS重复上传文件,将会覆盖原文件.

  3. html 怎么让tr的css覆盖td的_前端项目实战——华图教育网页(适合学习了HTML和CSS的小伙伴们)...

    这是在我学习了HTML和CSS以后做的实战项目,项目整体比较简单,但是有利于新手(比如我)了解和熟悉前端编程的代码和结构,因为在我最开始写这个网页的时候其实对于代码该怎么写并没有一个比较清晰的思路,就 ...

  4. jpanel把原本内容覆盖掉_暖冬遇上倒春寒,花被大雪覆盖,小心一夜回到解放前...

    都说去年是个暖冬,不少花都没有休眠,有些甚至还在开花呢,开春来了一个倒春寒,真是危险了,这时候可要小心点,不然白养这么久了. 突如其来的大降温,给原本正在开放的花朵盖上白雪,先来欣赏一波精彩的雪中花, ...

  5. 为什么css效果在本地测试没问题,上传到服务器后却显示位置乱动,css下拉菜单本地正常,上传后360浏览器中显示错位,火狐、IE8显示正常...

    匿名用户 1级 2014-04-15 回答 首先你使用 #header .row-2 ul li:hover 这样ie6就不支持了.ie6支持的hover目前我知道的只有a标签. 要单纯用css实现下 ...

  6. input file详细介绍、更改css样式、获取图片地址、彻底清空上传文件(建议收藏)

    文章目录 博客内容 介绍 input 全部类型 file 类型 属性 accept属性 multiple属性 事件监听 css样式更改 上传图片文件,获取图片地址 input type file上传文 ...

  7. csrf漏洞防御方案_变量覆盖漏洞利用及防御方案

    一.漏洞简介 变量覆盖漏洞是指攻击者使用自定义的变量去覆盖源代码中的变量,从而改变代码逻辑,实现攻击目的的一种漏洞.通常来说,单独的变量覆盖漏洞很难有利用价值,但是在与其他应用代码或漏洞结合后,其造成 ...

  8. php之变量覆盖漏洞讲解

    1.变量没有初始化的问题(1): wooyun连接1:[link href="WooYun: PHPCMS V9 member表内容随意修改漏洞"]tenzy[/link] $up ...

  9. html 怎么让tr的css覆盖td的_html表格标签

    HTML表格标签 表格是一种组织整理数据的手段,在HTML当中表格使用<table> 标签来定义.每个表格均有若干行(由<tr> 标签定义),每行被分割为若干单元格(由 < ...

最新文章

  1. 漫画 | 人到中年,一地鸡毛
  2. 开发自己的Data Access Application Block[下篇]
  3. Win10安装Latex
  4. 正确获取硬盘序列号源码
  5. node seneca_使用Node.js和Seneca编写国际象棋微服务,第2部分
  6. [html] 列举几种多列等高布局的方法
  7. 波士顿动力放出新视频:谁都挡不住机器狗开你的门
  8. MUI框架 · 异步请求:mui.get()、mui.ajax()、mui.post() 技术罗列
  9. linux添加硬盘不重启(vmware下或者虚拟机下面)
  10. 【bzoj 4390】 [Usaco2015 dec]Max Flow(树上差分)
  11. FCKeditor上传漏洞总结
  12. BOOM!多模态遇上推荐系统
  13. [iOS][Question]performselector may cause a leak because its selector is unknown
  14. java中包定义_java中包的定义与使用
  15. android 常用机型尺寸_目前主流的智能手机的屏幕尺寸与分辨率是多少?
  16. 给第一次参加数学建模竞赛的小白的建议
  17. 机器人国际会议与期刊列表
  18. jdk1.8新特性:stream流 报错:stream has already been operated upon or closed
  19. Axure与Mockplus的区别
  20. TI的C28x系列芯片的存储结构(1)——总括

热门文章

  1. qq浏览器怎么导入其他浏览器收藏夹
  2. 【Python学习笔记】Python深拷贝和浅拷贝
  3. 追加一列 python_常用的python代码总结
  4. XSSFWorkbook与HSSFWorkbook的区别
  5. keyProperty=“id“ 和useGeneratedKeys=“true“作用
  6. charles 安装 ssl_「从零开始Python爬虫」1.7.1 Charles的安装与配置
  7. 从零开始学java 框架_从零开始学 Java - 搭建 Spring MVC 框架
  8. 程序员述职报告范文_物流人员述职报告范文(通用5篇)
  9. windows上配置nginx php,Windows下配置Nginx使之支持PHP
  10. 重定向地址_JavaWeb - Servlet:重定向和转发,状态管理