David Robert's -castlebbs- Blog

To content | To menu | To search

Development

Entries feed - Comments feed

Friday 6 August 2010

Porting WebScarab functions to Burp Proxy

I think that the "Reveal hidden fields in HTML pages" option from WebScarab is better that the equivalent option in Burp Proxy "unhide hidden form fields". Therefore I ported the WebScarab code in charge of this to Burp Suite as a BurpExtender extension.

Sometime it can save time just unhiding hidden fields to see/modify them when testing a web application. Both Burp Proxy and Webscarab offer this options. However it seems that the "unhide hidden form fields" in Burp only reveals the fields values and not the fields names.

With the native "unhide hidden form fields" option with Burp Proxy, the revealed fields look like:

BurpNative_unhide.jpg

With the Burp Proxy extension I wrote (with WebScarab code) the name of the fields are displayed before the value:

BurpNative_unhide.jpg

This code was tested with Burp Suite professional 1.3.07 and the free version 1.3.03.

import java.net.URL;
import java.util.*;
import java.util.regex.*;
import java.io.*;

public class BurpExtender {
    public burp.IBurpExtenderCallbacks mCallbacks;
    public byte[] processProxyMessage(int messageReference, boolean messageIsRequest,
                  String remoteHost, int remotePort, boolean serviceIsHttps, String httpMethod,
                  String url, String resourceType, String statusCode, String responseContentType,
                  byte[] message, int[] interceptAction) {

    if (!messageIsRequest)
        {
            try
            {
                URL uUrl = new URL(serviceIsHttps ? "HTTPS" : "HTTP", remoteHost, remotePort, url);
                // We are only looking at urls under scope with Burp (target tab) and also only text
                // based content-type In some case responseContentType is null, found this is the case
                // when Content-Lenght is 0 identified using mCallbacks.getHeaders()
                if (mCallbacks.isInScope(uUrl) && responseContentType != null
                     && responseContentType.contains("text"))
                {
                    return revealHidden(message);
                }
                else
                {
                    return message;
                }
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
        return message;
    }
    public void registerExtenderCallbacks(burp.IBurpExtenderCallbacks callbacks) {
        mCallbacks = callbacks;
    }

    // Code from WebScarab (slightly modified)
    private byte[] revealHidden(byte[] content) {
        /* We split this pattern into two parts, one before "hidden" and one after
         * Then it is simple to concatenate part 1 + "text" + part 2 to get an
         * "unhidden" input tag
         */
        Pattern inputPattern = Pattern.compile("(<input.+?type\\s*=\\s*[\"']{0,1})hidden([\"']{0,1}.+?>)", Pattern.CASE_INSENSITIVE);
        Matcher inputMatcher = inputPattern.matcher(new String(content));
        StringBuffer outbuf = new StringBuffer();
        boolean matchedOnce = false;
        /* matched hidden input parameter */
        while(inputMatcher.find()) {
            matchedOnce = true;
            String input = inputMatcher.group();
            String name = "noname";

            // extract hidden field name
            Pattern namePattern = Pattern.compile("name=[\"']{0,1}(\\w+)[\"']{0,1}", Pattern.CASE_INSENSITIVE);
            Matcher nameMatcher = namePattern.matcher(input);
            if (nameMatcher.find() && nameMatcher.groupCount() == 1){
                name = nameMatcher.group(1);
            }

            // make hidden field a text field - there MUST be 2 groups
            // Note: this way we don't have to care about which quotes are being used
            input = inputMatcher.group(1) + "text" + inputMatcher.group(2);

            /* insert [hidden] <fieldname> before the field itself */
            inputMatcher.appendReplacement(outbuf, "<STRONG style=\"background-color: white;\"> [hidden field name =\"" + name + "\"]:</STRONG> "+ input + "<BR/>");
        }
        inputMatcher.appendTail(outbuf);
        return matchedOnce ? outbuf.toString().getBytes() : content;
    }
} // end BurpExtender


You can download the extension as a jar file (attachement below). To use it, you need to launch Burp this way:

java -classpath burpreveal.jar:burpsuite_v1.3.03.jar burp.StartBurp

On Windows based platforms, use a semi-colon character instead of the colon as the classpath separator.

Only the websites that are defined in the proxy scope will see their fields revealed (Target->Scope).

Wednesday 16 May 2007

GNU httptunnel with CGI

I wrote this patch for GNU httptunnel 3.0.5. this adds the following functions:

  • HTTP Basic Authentication: Allows to authenticate against a firewall or a Web server
  • CGI options: For the client htc, a new option to enable the definition of a cgi-script URI. For the server hts enable the option not to send the HTTP return code (which must be sent only by the web server).

I wrote this initially to do a proof of concept in a penetration testing I did previously: if you can find a way to write to the cgi-bin folder of a vulnerable web server, you can then use this version of httptunnel to encapsulate any flows like the ssh protocol and rebound on other systems that can be accessed from the vulnerable webserver.

The server hts cannot be called directly by the web server because it must ensure input-outputs persistence. The idea is to use a small cgi which makes the interface between hts and the web server. I wrote a small script in python which makes this job but it is simple to do one in C:

#!/usr/bin/env python
# tun.py : cgi tunnel to httptunnel
# David ROBERT david@ombrepixel.com
import socket, string
import os, sys

# host where hts live
host="localhost"
# hts listen port
port=8888

stdin=sys.stdin
stdout=sys.stdout

def log(texte):
    f=open("/tmp/log","a")
    f.write(texte + "\n")
    f.close()

def processGet():
    # GET processing
    data = """GET /index.html HTTP/1.1
Host: %s
Connection: close""" % os.environ.get("HTTP_HOST")

    # Send headers
    for line in string.split(data,"\n"):
        sock.send(line+"\r\n")
    sock.send("\r\n")
    #log("Lignes envoyees")

    # Receive flow
    while 1:
        v=sock.recv(8192)
        if not v: break
        stdout.write(v)
        #log("recu : %s" % v)
        stdout.flush()

def processPost():
    # POST processing
    data = """POST /index.html HTTP/1.1
Host: %s
Content-Length: 102400
Connection: close""" % os.environ.get("HTTP_HOST")

    # Send headers
    for line in string.split(data,"\n"):
        sock.send(line+"\r\n")
    sock.send("\r\n")

    # Send flow
    while 1:
        v = stdin.read(1)       # Ecriture
        if len(v) == 0: break
        #log("lu : %s" % v)
        sock.send(v)

# __main__
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, port))
if os.environ.get("REQUEST_METHOD") == "GET":
    processGet()
elif os.environ.get("REQUEST_METHOD") == "POST":
    processPost()
else:
    print "Boum"

# Fin
sock.close()
sys.exit(0)

How does it work ?
  • On the server, copy tun.py in the cgi-bin folder. Start hts in cgi mode (-C or --cgi), listen to port 8888 and forward connexions to local port ssh (22):
    • hts -C -F localhost:22 8888
  • On the client, start htc in cgi mode provinding URI to tun.py (-C URI or --cgi URI). In the following example webserver must be the name of the web server (IP address resolution must be possible). This name is also used in the HTTP headers sent by htc and makes it possible to select different virtual hosts.
    • htc -C "/cgi-bin/tun.py" -F 2222 webserver:80
  • If authentication (only HTTP Basic) is required to reach the cgi script, you can specify login:password on the htc command line:
    • htc -C "/cgi-bin/tun.py" -a david:noway -F 2222 webserver:80

Saturday 14 April 2007

net2acid

I wrote net2acid. The goal is to insert into snort ACID database IP packets matched and jumped by netfilter QUEUE target. Version 0.0

I think it has never been completed

Thursday 12 April 2007

reStructWeb

reStructWeb is a small piece of software written in Python language. I wrote it to manage my personal web site. The most important features that I wished when I decided to write it are :

  • To be able to simply modify my website online
  • Not to have to write my pages in html or xml
  • To create links between the pages very easily (like Wiki )
  • To integrate templates and css to separate the presentation from the contents
  • To be multi-lingual
  • To be powerful and light for my poor computer ( SiteAbout ).

I took as a starting point the the Wiki system to update my Web site. The pages are created in text format using thereStructuredText format. 

Continue reading...

Wednesday 11 April 2007

Search my imap folder

Some explanations

I wrote a small program in python that can query my advisories email folder. I wished to be able to have a advanced query language, independent from the IMAP4 language. This abstraction is also made to avoid the risks of IMAP commands injections and also to be able to query other subsystems than IMAP.

As I've set up the form on my website for my own use, I let other people benefit from it (even if their number is negligible: -)

More details

My program uses a lex and yacc python implementation : ply. the grammatical analyzer transforms my query into an Abstract Syntax Tree (AST). This tree is then transformed into an IMAP4 query string.

The grammar I have defined for the query language :

expression : expression AND term
| expression OR term
| term
term : NOT term
| QWORDS
| WORD
| LPAREN expression RPAREN

For more details, look at the source code.

Thursday 18 November 2004

vdrpylib patch

My patch for vdrpylib 0.2. So you can use vdrpylib with the latests vdr versions. What's new :

  • Use socket interface instead of telnetlib.Telnet
  • changes because of the new EPG format