网站首页 全球最实用的IT互联网站!

人工智能P2P分享Wind搜索发布信息网站地图标签大全

当前位置:诺佳网 > 软件工程 > 其他技术区 > 网络安全 >

Ivanti EPMM RCE CVE-2026-1340/1281完整分析

时间:2026-02-02 18:41

人气:

作者:admin

标签:

导读:前言: 文中技术分析仅供交流讨论,poc仅供合法测试,用于企业自查,切勿用于非法测试,未授权测试造成后果由使用者承担,与本公众号以及棉花糖无关。 介绍: 近日,Ivanti公司披露...

前言:

文中技术分析仅供交流讨论,poc仅供合法测试,用于企业自查,切勿用于非法测试,未授权测试造成后果由使用者承担,与本公众号以及棉花糖无关。

介绍:

近日,Ivanti公司披露了Ivanti Endpoint Manager Mobile (EPMM)中存在的代码注入漏洞(CVE-2026-1281CVE-2026-1340),并确认已存在在野利用。该漏洞源于 Apache HTTPd 调用的 Bash 脚本在处理时间戳比较时,未能有效过滤恶意参数,导致攻击者可利用 Bash 算术扩展特性注入系统命令。

分析:

首先拿到补丁包

RPM的包那就好办了,直接查看它执行了什么即可,使用命令:

rpm -qp --scripts ivanti-security-update-1761642-1.0.0L-5.noarch.rpm

emmm内容有点多,不过根据已知条件,该漏洞源于 Apache HTTPd ,补丁包里面很容易看到关键的修改Apache HTTPd配置的命令:

/bin/sed -i \
  -e 's|RewriteMap mapAppStoreURL prg:/mi/bin/map-appstore-url|RewriteMap mapAppStoreURL "prg:/bin/java -cp /mi/bin AppStoreUrlMapper"|g' \
  -e 's|RewriteMap mapAftStoreURL prg:/mi/bin/map-aft-store-url|RewriteMap mapAftStoreURL "prg:/bin/java -cp /mi/bin AFTUrlMapper"|g' \
  /etc/httpd/conf.d/ssl.conf

就是说把map-appstore-urlmap-aft-store-url给换掉了不用是吧,ok我们去看看这俩脚本是什么,目录已经给了在mi/bin下,我们直接进终端查一下

map-appstore-url和map-aft-store-url是个bash脚本,cat就可以直接看内容(另一个脚本内容差不太多,就不展示了)。

#!/bin/bash

set -o nounset

declare -x MI_DATE_COMMAND="date +%Y-%m-%d--%H-%M-%S"
declare -x MI_DATE_FORMAT="%Y-%m-%d--%H-%M-%S"

declare -r kScriptName=$(basename $0)
declare -r kScriptDirectory=$(dirname $0)
declare -r kLogFile="/var/log/${kScriptName}.log"
declare -r kSaltFile="/mi/files/appstore-salt.txt"

declare -r kScriptStartTimeSeconds=$(date +%s)
declare -r kValidTimeStampLength=${#kScriptStartTimeSeconds}

declare -r kAftFileStoreDirectory='/mi/files/aftstore'

# error codes that are used in /etc/httpd/conf.d/ssl.conf
declare -r kPathTraversalAttemptedErrorCode="c91bbeec40aff3fd3fe0c08044c1165a"
declare -r kLinkHashMismatchErrorCode="44b2ff3cf69c5112061aad51e0f7d772"
declare -r kTooLateErrorCode="c6a0e7ca11208b4f11d04a7ee8151a46"
declare -r kTooEarlyErrorCode="80862895184bfa4d00b24d4fbb3d942f"
declare -r kKeyIndexOutOfBoundsErrorCode="f74c27fce7d8e2fecd10ab54eda6bd85"
declare -r kURLStructureInvalidErrorCode="b702087a848177d489a6891bd7869495"
declare -r kTimestampLengthInvalidErrorCode="2ecad569fdaa07e2b66ed2595cf7240f"
declare -r kLinkSpoofErrorCode="cbfa488e9b08d4c5d7b3b2084ffb18e7"
declare -r kLinkUsingOddTraversalErrorCode="f489b91db387b684f56c07e7f5e4308b"

gShouldLogToFile="false"
gSaltFileModificationTime="0"
gTestMode="false"
gErrorCode=0
gErrorMessage=""
declare -a gSaltArray=( )
gCurrentSalt=""
gHostname=""
gPath=""
gStartTime=""
gEndTime=""

if (( $# > 0 )) ; then
  gTestMode="true"
fi

#echo "gTestMode=${gTestMode}"

# information
function log() {
  if ${gTestMode} ; then
    echo "`$MI_DATE_COMMAND` -- ${kScriptName} -- ${1}: ${@:2}"
  else
    # do not log since it kills performance
    echo "$($MI_DATE_COMMAND) -- ${kScriptName} -- ${1}: ${@:2}" >> ${kLogFile}
  fi
}

function logDebug() {
  if ${gTestMode} ; then
    echo "`$MI_DATE_COMMAND` -- ${kScriptName} -- ${1}: ${@:2}"
  else
    # do not log since it kills performance
    ${gShouldLogToFile} && echo "$($MI_DATE_COMMAND) -- ${kScriptName} -- ${1}: ${@:2}" >> ${kLogFile}
  fi
}

# errorCode
# information
function logDenial() {
  local theCurrentDate="$(MI_DATE_COMMAND)"
  if ${gTestMode} ; then
    echo "$theCurrentDate -- ${kScriptName} -- ${1}: denying: errorCode=${2}: ${@:3}"
  else
    #echo "$theCurrentDate -- ${kScriptName} -- ${1}: denying: errorCode=${2}: ${@:3}" >> "${kLogFile}"
    logger -t "${kScriptName}" -i -p local0.warning "$theCurrentDate -- ${1}: denying: errorCode=${2}: ${@:3}"
  fi
}

log "MAIN" "starting"

function dumpSaltArray() {
  log "${FUNCNAME}" "entered"

  for theSalt in "${gSaltArray[@]}" ; do
    log "${FUNCNAME}" "theSalt=$theSalt"
  done
}

log "MAIN" "after dumpSaltArray declaration"

function readSaltFile() {
  if [[ -f "${kSaltFile}" ]] ; then
    theCurrentSaltModificationTime=$(stat -c %Y "${kSaltFile}")
    logDebug "${FUNCNAME}" "theCurrentSaltModificationTime=${theCurrentSaltModificationTime}"
    theDeltaTime=$(($theCurrentSaltModificationTime - $gSaltFileModificationTime))
    logDebug "${FUNCNAME}" "theDeltaTime=${theDeltaTime}"

    if [[ "${theDeltaTime}" -ne 0 ]] ; then
      log "${FUNCNAME}" "theDeltaTime=${theDeltaTime} not zero; loading salt from kSaltFile=${kSaltFile}"
      gSaltArray=( $(cat ${kSaltFile}))
      gSaltArray[0]=""
      gSaltFileModificationTime=$theCurrentSaltModificationTime
    fi
  else
    log "${FUNCNAME}" "kSaltFile=${kSaltFile} not found"
  fi
}

log "MAIN" "after readSaltFile declaration"

#readSaltFile
#dumpSaltArray
#readSaltFile

function lookupSaltByIndex() {
#echo "$1 ${#gSaltArray[*]}"
  if [ "$1" -lt ${#gSaltArray[*]} ] ; then
    gCurrentSalt=${gSaltArray[$1]}
  else
    gCurrentSalt=""
  fi

  logDebug "${FUNCNAME}" "theKeyIndex=$1; gCurrentSalt=$gCurrentSalt"
}

log "MAIN" "after lookupSaltByIndex declaration"

function verifyURLConsistency () {
  logDebug "${FUNCNAME}" "${1}"
  local ret="" # this is what we eventually echo and it's the name of a file for httpd to send to the client or a pattern that Rewrite is aware of and kill the connection with the right HTTP error code
  #theAppStoreString=${1%%:*}
  #echo "${theAppStoreString}"
  #declare
  theOldIFS="${IFS}"
  local theArgumentArray

  # process what httpd gave us in $1 splitting on the _
  IFS="_" && theArgumentArray=(${1})

  theAftStoreString=${theArgumentArray[0]}
  theAftStoreAssetGUIDWithExtension=${theArgumentArray[1]}
  gHostname=${theArgumentArray[2]}
  theURLString=${theArgumentArray[3]}
  #echo "${theAftStoreString}"

  # process what mifs really gave us in $1 splitting on the ,
  IFS="," && theAftStoreKeyValueArray=(${theAftStoreString})

  IFS="${theOldIFS}"

  if (( ${#theArgumentArray[@]} != 4 )) ; then
    ret="${kURLStructureInvalidErrorCode}"
    log "${FUNCNAME}" "${ret}" "expecting 5 segments; actual=${#theArgumentArray[@]}"
  fi

  if [[ -z ${ret} ]] ; then
    for theKeyMapEntry in "${theAftStoreKeyValueArray[@]}" ; do
      theKey="${theKeyMapEntry%%=*}"
      theValue="${theKeyMapEntry##*=}"
      logDebug "${FUNCNAME}" "theKey=$theKey; theValue=$theValue"

      case ${theKey} in
        kid)
          gKeyIndex="${theValue}"
          ;;
        st)
          gStartTime="${theValue}"
          if (( ${#gStartTime} != "${kValidTimeStampLength}" )) ; then
            ret="${kTimestampLengthInvalidErrorCode}"
          fi
          ;;
        et)
          gEndTime="${theValue}"
          if (( ${#gEndTime} != "${kValidTimeStampLength}" )) ; then
            ret="${kTimestampLengthInvalidErrorCode}"
          fi
          ;;
        h)
          gHashPrefixString="${theValue}"
          ;;
        *)
          ret="${kURLStructureInvalidErrorCode}"
          logDenial "${FUNCNAME}" "${ret}" "unknown presented key=${theKey}; theValue=${theValue}"
          ;;
      esac
    done
  fi

  if [[ -z ${ret} ]] ; then
    lookupSaltByIndex ${gKeyIndex}

    if [[ -n "${gCurrentSalt}" ]] ; then
      logDebug "${FUNCNAME}" "continuing: gCurrentSalt=$gCurrentSalt"
      theCurrentTimeSeconds=$(date +%s)
      logDebug "${FUNCNAME}" "theCurrentTimeSeconds=${theCurrentTimeSeconds}"
      #theCurrentTimeSeconds=1336011206
      #theCurrentTimeSeconds=1336770818
      #gHostname="cot-0000001.mobileiron.com"
      #gHostname="qa42.mobileiron.com"

      if [[ ${theCurrentTimeSeconds} -gt ${gStartTime} ]] ; then
        logDebug "${FUNCNAME}" "continuing: not too early"

        if [[ ${theCurrentTimeSeconds} -lt ${gEndTime} ]] ; then
          logDebug "${FUNCNAME}" "continuing: not too late"

          # calculate the path
          gPath=${theURLString/\/sha256:${theAftStoreString} 
温馨提示:以上内容整理于网络,仅供参考,如果对您有帮助,留下您的阅读感言吧!
相关阅读
本类排行
相关标签
本类推荐

CPU | 内存 | 硬盘 | 显卡 | 显示器 | 主板 | 电源 | 键鼠 | 网站地图

Copyright © 2025-2035 诺佳网 版权所有 备案号:赣ICP备2025066733号
本站资料均来源互联网收集整理,作品版权归作者所有,如果侵犯了您的版权,请跟我们联系。

关注微信