With Metasploit community CTF 2020 approaching rapidly, I decided to refresh my knowledge about website penetration testing. When dealing with Web security, I use Weber Framework, my own personal proxy, whenever possible. In this post I want to introduce the basics of this nifty tool.

Weber

Weber is a console-based web proxy heavily inspired by famous projects such as Burp Suite, WebScarab, mitmproxy and others. I chose to implement my own solution because:

  • I wanted deeper knowledge about the matter,
  • existing tools could not have been efficiently controlled,
  • I wanted specific functionality according to my exact needs.

Despite the importance of website penetration testing, Weber is not ready for production use and is under development. However, it can already do the basic stuff and some more cool things, therefore I feel the introduction would not hurt anybody.

You shall be warned – for maximum efficiency Weber uses as short commands as possible – this idea comes from radare2 reverse engineering framework. And it is really useful approach, although the learning curve is initially quite steep. Each letter usually refers to a word; I will explain the actual meaning for every command we come across (look for text in parentheses).

Initialization

After cloning the git repository you run Weber directly as ./weber. Alternatively, you can build Weber as Docker container and run it in modern way – the command is in docker.sh file, for clarity it is:

sudo docker run --rm -it -v $PWD/files:/weber/files -p 8080:8080 --user $(id -u):$(id -g) --name weber lightfaith/weber

Weber now listens on port 8080, like other common proxies. You must now configure your browser to send requests over it. I prefer to create new profile at about:profiles (if running Firefox) and install and configure FoxyProxy plugin inside. Because of this I can pretend to be hacker in one browser window and seamlessly run Youtube in another one. The new profile can also be configured so Firefox itself will not spam the proxy with unimportant stuff. Later I might recall and sum up the way to do it.

Configure FoxyProxy as HTTP proxy to 127.0.0.1:8080. If you want to use wget instead of your browser, you can force proxy by specifying it in configuration file or as arguments, for example:

wget -e use_proxy=yes -e http_proxy=127.0.0.1:8080 -e https_proxy=127.0.0.1:8080 --no-check-certificate http://example.com

I like to store that command as alias in my ~/.bashrc:

alias wgetp="wget -e use_proxy=yes -e http_proxy=127.0.0.1:8080 -e https_proxy=127.0.0.1:8080 --no-check-certificate"

If you wonder why –no-check-certificate flag is present, it is because Weber generates fake certificates on the fly in order to grant access to encrypted flows. It is not a bug, it is a feature.

That is it, if you make a request now you should see something in Weber console:

./weber
[.] Loading config file...
[.]   interaction.timeout_warnings = False
[.]   overview.short_request = True

[.] Bend the knee!
 )>     1     http://example.com:80  GET /  200 OK  1256 B

Basic control

From this point every request you make is pushed through the Weber. Request-response pair overviews will pop-out in realtime (this feature can be disabled). First you should learn how to get help. Weber is self-documented, to see help use ? command. This will show what letters commands can start with. Write a letter and a question mark and you will see more detailed possibilities. Annoying, I know, but there is very well hidden logic. You will usually use 5-10 commands anyway.

 )> ?
    a[?]                                     analysis
    b[?]                                     brute-force (alias for `pwb`)
    q                                        quit
    r[?] [estu] [<rrid>[:<rrid>]]            print request-response overview (alias for `ro`)
    s[?]                                     show server overview
    w[?]                                     write
 )> r?
    r[?] [estu] [<rrid>[:<rrid>]]            print request-response overview (alias for `ro`)
    rD [<rrid>[:<rrid>]]                     delete requests/responses
    rH[?]                                    print HTML-related info
    ra[?] [<rrid>[:<rrid>]]                  print requests-response pairs verbose
    rc[?] [<rrid>[:<rrid>]]                  print cookies sent in requests
    rd[?] [<rrid>[:<rrid>]]                  print request-response data
    rh[?] [<rrid>[:<rrid>]]                  print request-response headers
    ro[?] [estu] [<rrid>[:<rrid>]]           print request-response overview
    rp [<rrid>[:<rrid>]]                     print HTTP parameters
    rq[?] [<rrid>[:<rrid>]]                  print requests verbose
    rs[?] [<rrid>[:<rrid>]]                  print responses verbose
    rt [<rrid>[:<rrid>]]                     print request/response timeline

Two question marks are even better! Use ?? to get some introduction to Weber or append the question marks to a command (e.g. r??) to get help on the command directly.

 )> ??

    Welcome! This is Weber Framework, an open-source protocol proxy.
    With Weber you can see the traffic, modify it and more!
    Currently, Weber will forward anything sent to '127.0.0.1:8080
...
 )> r??

    Use `r` or `ro` commands to get an overview of all captured
    request-response pairs.
    There are optional parameters 'e', 's', 't', 'u'.
...

Options

You can tune Weber with a number of options. Use wo (weber options) command to list current settings. Edit values with wos <key> <value> (weber option set) command, e.g. wos debug.flow True. You can also set default values in weber.conf file. We will deal with relevant options when needed.

 )> wo
    analysis.immediate              True
    analysis.ignored_tests          ''
    brute.placeholder               '###'
    brute.value_separator           ';'
...

Grep and less

You can filter receive output with grep-like functionality. Just specify ~ character and then your desired value. For example list available debug options with wo~debug.

 )> wo~debug
    debug.analysis                  False
    debug.chunks                    False
    debug.command                   False
    debug.config                    False
    debug.flow                      False
    debug.mapping                   False
    debug.parsing                   False
    debug.protocol                  False
    debug.server                    False
    debug.socket                    False
    debug.tampering                 False

Use two tilde characters to do regular expression filtering.

 )> wo~~(brute|spoof)
    brute.placeholder               '###'
    brute.value_separator           ';'
    brute.rps                       20
    brute.set_separator             '\n'
    spoof.arguments                 False

At some points you will want to read the output in more sophisticated way – why not use less command for that? Syntax is simple, just append $L to you command, e.g. wo$L.

 )> wo$L
    analysis.immediate              True
    analysis.ignored_tests          ''
...
    tamper.requests                 False
    tamper.responses                False
~
~
(END)

Requests and responses

Let’s move to something practial now. Mostly you will use commands related to requests and responses. Use r (requests/responses) to show the entire overview.

 )> r
    RRID  Server                 Request           Response         Size
    ====  =====================  ================  =============  ======
    1     http://example.com:80  GET /             200 OK         1256 B
    2     http://example.com:80  GET /favicon.ico  404 Not Found  1256 B

You can see RRID, which serves as an identifier to specific request-response pairs (or RRs for short). This will be used a lot. You can also see server the request is forwarded to, request method and path and corresponding response code. Lastly you can see size of the response.

Some information is hidden, for example time of response received. That can be shown if you set overview.show_time option to True or if you specify the t flag:

 )> r t
    Time          RRID  Server                 Request           Response         Size
    ============  ====  =====================  ================  =============  ======
    08:53:10.627  1     http://example.com:80  GET /             200 OK         1256 B
    08:53:11.785  2     http://example.com:80  GET /favicon.ico  404 Not Found  1256 B

You can also show overview for specific RRs only – just specify desired RRIDs. You can use comma-separated values or intervals, e.g. 1,2,5-10. This will work for most commands.

 )> r 1
    RRID  Server                 Request  Response    Size
    ====  =====================  =======  ========  ======
    1     http://example.com:80  GET /    200 OK    1256 B

Too many RRs on your plate? Show just the last 10 with rol (RR overview – last) command. And you can also use the grep.

If the request column is unbearably wide, force path shortening with overview.short_request option.

RR times

Sometimes it may be useful to see more exact timing of the process. Use rt (RR timing) for exactly that:

 )> rt
[!] The command has no documentation.
--- #1 ---
     thread_started: 2020-01-25 08:53:09.515312
   request_received: 2020-01-25 08:53:09.916196
  request_forwarded: 2020-01-25 08:53:09.916692
  response_received: 2020-01-25 08:53:10.627400
 response_forwarded: 2020-01-25 08:53:10.629773

--- #2 ---
     thread_started: 2020-01-25 08:53:10.667718
   request_received: 2020-01-25 08:53:11.068784
  request_forwarded: 2020-01-25 08:53:11.069128
  response_received: 2020-01-25 08:53:11.785801
 response_forwarded: 2020-01-25 08:53:11.787585

RR details

Now let’s see the actual content of requests and responses. There are many commands to do that, the most general is ra (RR – all) that shows everything (request, response, headers, data). You will definitely want to specify RRIDs and sometimes even the less view.

 )> ra 1
--- #1 ---
GET / HTTP/1.1
Host: example.com
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1


HTTP/1.1 200 OK
Content-Encoding: gzip
Age: 417682
Cache-Control: max-age=604800
Content-Type: text/html; charset=UTF-8
Date: Tue, 25 Jan 2020 07:53:10 GMT
Content-Length: 1256

<!doctype html>
<html>
<head>
    <title>Example Domain</title>
...
</body>
</html>

For request only use rq (request) command, rs (response) for response. For headers only, use rh (RR headers) command, rd (RR data) for data. Only interested in request headers? Clearly rqh (request headers), and rsd (response data) for response data and so on. See the pattern?

 )> rqh 2
--- #2 ---
GET /favicon.ico HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: image/webp,*/*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Dnt: 1
Connection: keep-alive

Use x at the end of your previous command, e.g. rsdx 1 (response data hexadecimal):

 )> rsdx 1
--- #1 ---
00000000  3c21 646f 6374 7970 6520 6874 6d6c 3e0a |<!doctype html>.|
00000010  3c68 746d 6c3e 0a3c 6865 6164 3e0a 2020 |<html>.<head>.  |
00000020  2020 3c74 6974 6c65 3e45 7861 6d70 6c65 |  <title>Example|
00000030  2044 6f6d 6169 6e3c 2f74 6974 6c65 3e0a | Domain</title>.|
...

How to save captured RRs into a file? Use w at the end of the command and specify path and RRIDs. You will often use rsdw /tmp/a 1 (response data write) to store received binary data for further analysis. Alternatively, use rsdwa /tmp/folder (response data write auto) to auto-save all received data.

Tampering

What a proxy without tampering feature would be useful for? Short answer: not much. Weber has capabilities of interrupting, modifying and forwarding individual requests and responses and we will look at it right now.

Enable tampering of requests with rqt (request tamper) command. This will pause forwarding of received requests so you can modify them. In overview such requests will have [T] mark near them.

You can specify number of requests to be affected: rqt 5. Short command for just one request tamper is rqt1 (request tamper 1). Finally, disable forwarding interruption with rqt- (request tamper off) command. Of course similar commands exist for responses, just start with rst (response tamper).

You can filter the overview for only tampered stuff with rot (RR overview – tampered) command.

 )> rqt
[.] Requests will be TAMPERED by default.
 )> r
    RRID  Server                 Request           Response         Size
    ====  =====================  ================  =============  ======
    1     http://example.com:80  GET /             200 OK         1256 B
    2     http://example.com:80  GET /favicon.ico  404 Not Found  1256 B
    5     http://example.com:80  [T] GET /         ...               - B
 )> rot
    RRID  Server                 Request    Response  Size
    ====  =====================  =========  ========  ====
    5     http://example.com:80  [T] GET /  ...        - B
 )> rqt-
[.] Requests are no longer tampered.

Even after stopping the tampering with rqt- or rst-, requests and responses will still hang in Weber. Already tampered requests/responses must be forwarded. Finally, forward requests with rqf (request forward) command (RRID can be also specified) and responses with rsf (response forward) command.

Tampered requests/responses can be modified with rqm <RRID> (request modify) or rsm <RRID> (response modify) command. This will open the request/response in you favourite editor, currently specified in edit.command option. See the process in asciinema at the end of this post.

Can you forward request that is not tampered? Yes, use rqr <RRID> (request replay) command to resend the request.

Save progress

Finally, you can save your entire Weber session with ww /tmp/a.web (weber write) command and restore it later with ./weber --restore /tmp/a.web. This functionality is currently tested.

Demo time

In the following asciinema features mentioned in the post are demonstrated. Namely:

  • Weber help (0:09),
  • options (0:28),
  • grep&less (0:37),
  • request/response overview (1:02),
  • request/response timing (1:31),
  • request and response details (1:34),
  • data saving (2:21),
  • request tampering, modification and forwarding (2:39),
  • progress saving and restoration (3:15).

Conclusion

In this post Weber Framework proxy was introduced. Although it may seem annoying at first, you can quickly realize it offers an effective approach to help you with website security testing. Next time we will deal with some real usage. Meanwhile remember that:

  • I am using RR abreviation a lot to talk about request and responses,
  • Weber is (will be) self-documented – use ? to see commands and ?? to read more about them,
  • you can grep output with ~ and ~~ modifiers,
  • you can read output in less with $L modifier,
  • RR overview is evoked with r command and you will use it a lot,
  • RR details can be retrieved with commands ra, rq, rs and their more detailed modifications,
  • you can get hexdump of RRs by appending x to previously mentioned commands and export the data by appending w,
  • you can auto-save all received data with rsdwa command,
  • you can tamper, modify and forward requests with rqt, rqm, rqf commands, that applies to responses as well,
  • you can save your Weber session with ww command.

Leave a Reply

Your email address will not be published. Required fields are marked *