1#!/usr/local/bin/bash
2#
3# ratproxy - report generator
4# ---------------------------
5#
6# This is essentially a prettyprinter for ratproxy logs. It removes
7# dupes, sorts entries within groups, then sorts groups base don highest
8# priority within the group, and produces some nice HTML with form replay
9# capabilities.
10#
11# TODO: Use standalone stylesheets to conserve bytes.
12#
13# Author: Michal Zalewski <lcamtuf@google.com>
14#
15# Copyright 2007, 2008 by Google Inc. All Rights Reserved.
16#
17# Licensed under the Apache License, Version 2.0 (the "License");
18# you may not use this file except in compliance with the License.
19# You may obtain a copy of the License at
20#
21#   http://www.apache.org/licenses/LICENSE-2.0
22#
23# Unless required by applicable law or agreed to in writing, software
24# distributed under the License is distributed on an "AS IS" BASIS,
25# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26# See the License for the specific language governing permissions and
27# limitations under the License.
28#
29
30if [ "$1" = "" ]; then
31  echo "Usage: $0 ratproxy.log" 1>&2
32  exit 1
33fi
34
35if [ ! -f "$1" ]; then
36  echo "Input file not found." 1>&2
37  exit 1
38fi
39
40test "$RAT_URLPREFIX" = "" || RAT_URLPREFIX="/$RAT_URLPREFIX/"
41
42# Output prologue...
43
44cat <<_EOF_
45<html>
46
47<head>
48<meta http-equiv="Content-Type" content="text/plain; charset=iso-8859-1">
49<title>ratproxy - security testing proxy</title>
50<style>
51a:link, a:visited { text-decoration: none; color: green }
52a:hover { text-decoration: underline; color: red }
53body { background-color: white; background-image: url('ratproxy-back.png'); background-repeat: no-repeat; }
54</style>
55</head>
56
57<body>
58
59<div style="width: 60%">
60<span style="float: left; height: 190px; width: 350px"></span>
61
62<font face="arial,helvetica" size=+0>
63<b>Ratproxy audit report</b>
64<p>
65<font size=-1>
66Generated on: <b>`date +'%Y/%m/%d %H:%M'`</b><br>
67Input file: <b>$1</b>
68</font>
69<p>
70<font color="crimson" size=-1>NOTE: Not all of the issues reported necessarily
71correspond to actual security flaws. Findings should be validated
72by manual testing and analysis where appropriate. When in doubt,
73<a href="mailto:lcamtuf@google.com">contact the author</a>.</font>
74<br clear=all>
75
76<hr size=1 color=black>
77<p>
78<font size=-1>
79<div style="border: 1px solid teal; background-color: white">
80<b>Report risk and risk modifier designations:</b>
81<table border=0>
82<tr>
83<td width=25%>
84<font face="Bitstream Vera Sans Mono,Andale Mono,lucida console" size=-2>
85<span style="border: solid black 1px; background-color: blue; color: white; padding: 0.1em 0.4em 0.1em 0.4em"><b>LOW</b></span>
86to
87<span style="border: solid black 1px; background-color: crimson; color: white; padding: 0.1em 0.4em 0.1em 0.4em"><b>HIGH</b></span>
88</td>
89<td><font size=-1>Issue urgency classification (composite of impact and identification accuracy)</font></td>
90</tr>
91<tr>
92<td width=25%>
93<font face="Bitstream Vera Sans Mono,Andale Mono,lucida console" size=-2>
94<span style="border: solid black 1px; background-color: gray; color: white; padding: 0.1em 0.4em 0.1em 0.4em"><b>INFO</b></span>
95</td>
96<td><font size=-1>Non-discriminatory entry for further analysis</font></td>
97</tr>
98<tr>
99<td width=25%>
100<font face="Bitstream Vera Sans Mono,Andale Mono,lucida console" size=-2>
101<span style="border: solid gray 1px; background-color: #fffece; color: #800000; padding: 0.1em 0.4em 0.1em 0.4em">ECHO</span>
102/
103<span style="border: solid gray 1px; background-color: #fffece; color: #A0A080; padding: 0.1em 0.4em 0.1em 0.4em">echo</span>
104</font>
105</td>
106<td><font size=-1>Query parameters echoed back / not echoed in HTTP response, respectively</font></td>
107</tr>
108<tr>
109<td width=25%>
110<font face="Bitstream Vera Sans Mono,Andale Mono,lucida console" size=-2>
111<span style="border: solid gray 1px; background-color: #fffece; color: #800000; padding: 0.1em 0.4em 0.1em 0.4em">PRED</span>
112/
113<span style="border: solid gray 1px; background-color: #fffece; color: #A0A080; padding: 0.1em 0.4em 0.1em 0.4em">pred</span>
114</font>
115</td>
116<td><font size=-1>Request URL or query data likely is / is not predictable to third parties, respectively</font></td>
117</tr>
118<tr>
119<td>
120<font face="Bitstream Vera Sans Mono,Andale Mono,lucida console" size=-2>
121<span style="border: solid gray 1px; background-color: #fffece; color: #800000; padding: 0.1em 0.4em 0.1em 0.4em">AUTH</span>
122/
123<span style="border: solid gray 1px; background-color: #fffece; color: #A0A080; padding: 0.1em 0.4em 0.1em 0.4em">auth</span>
124</font>
125</td>
126<td><font size=-1>Request requires / does not require cookie authentication, respectively</font></td>
127</tr>
128</table>
129</div>
130</font>
131<p>
132<hr size=1 color=black>
133
134<script>
135function toggle(id) { 
136  var i = document.getElementById(id);
137  if (i.style.display == 'none') i.style.display = 'inline'; else i.style.display = 'none';
138  i = document.getElementById('hid_' + id);
139  if (i.style.display == 'none') i.style.display = 'inline'; else i.style.display = 'none';
140}
141</script>
142
143<font face="arial,helvetica" size=-1>
144<ul>
145_EOF_
146
147if [ ! -s "$1" ]; then
148  echo "<b>No activity to report on found in log file."
149  exit 1
150fi
151
152PREVDESC=X
153CNT=0
154SCNT=0
155
156# So this is some nearly incomprehensible logic to sort entries by priorities,
157# sort groups based on highest priority within a group, and then remove any
158# duplicates (paying no attention to some fields, such as trace file location),
159# group "offending value" fields, and more. At some point - too late in the
160# game - it became painfully obvious that this should not be a shell script ;-)
161
162( sort -t '|' -k 1,9 -k 11,100 -ru <"$1" | grep '^[0123]|' | sort -t '|' -k 3,3 -s | \
163  awk -F'|' '{if ($3!=PF) { npri=$1;PF=$3; }; printf "%s-%s|%s\n", npri, $3, $0}' | \
164  sort -r -k 1,1 -s | sed 's/|!All /|All /'; echo "Dummy EOF" ) | \
165  awk -F'|' '{
166
167               PTRM=TRM; PFR=FR; PTA=TA;
168               FR=""; TA=""; TRM=""; GOTVAL="";
169
170               for (a=1;a<=NF;a++) {
171                 if (a < 5) {
172                   TRM=TRM "|" $a;
173                   FR=FR $a "|";
174                 } else if (a > 5) {
175                   TRM=TRM "|" $a;
176                   TA=TA "|" $a;
177                 } else GOTVAL=$a;
178
179               }
180
181               if (PTRM == TRM) {
182                 if (GOTVAL != "-") {
183                   if (LIST == "-") LIST="<span style=\"background-color: #FFFFB0\">" GOTVAL "</span>";
184                   else LIST=LIST ", <span style=\"background-color: #FFFFB0\">" GOTVAL "</span>";
185                 }
186               } else {
187                 if (PTRM != "") print PFR LIST PTA;
188                 if (GOTVAL == "-") LIST="-";
189                 else LIST="<span style=\"background-color: #FFFFB0\">" GOTVAL "</span>";
190               }
191
192             }' | \
193  while IFS="|" read -r skip severity modifier desc offend code len mime sniff cset trace method url cookies payload response; do
194
195    # If issue name changed, output a new header, complete with fold / unfold controls.
196    # Default groups with 'info' items only to folded state.
197
198    if [ ! "$PREVDESC" = "$desc" ]; then
199
200      SCNT=$[SCNT+1]
201
202      if [ ! "$severity" = "0" ]; then
203
204        echo "</ul></span><font size=+1><u>$desc</u></font>&nbsp;<font size=-2 color=gray>[<a href=\"javascript:void(0)\" onclick=\"toggle('list$SCNT')\">toggle</a>]</font>"
205        echo "<span id=hid_list$SCNT style=\"display:none\"><br><br><font color=gray><i>Section hidden</i></font><p></p></span>"
206        echo "<span id=list$SCNT style=\"display:inline\"><ul style=\"margin-top: 0px\"><font size=-2>"
207
208      else
209
210        echo "</ul></span><font size=+1><u>$desc</u></font>&nbsp;<font size=-2 color=gray>[<a href=\"javascript:void(0)\" onclick=\"toggle('list$SCNT')\">toggle</a>]</font>"
211        echo "<span id=hid_list$SCNT style=\"display:inline\"><br><br><font color=gray><i>Section hidden</i></font><p></p></span>"
212        echo "<span id=list$SCNT style=\"display:none\"><ul style=\"margin-top: 0px\"><font size=-2>"
213
214      fi
215
216      echo "<font color=darkslateblue>"
217      grep -F "~$desc~" messages.list | cut -d'~' -f3
218      echo "</font></font><p>"
219
220      PREVDESC="$desc"
221
222    fi
223
224    # Output severity data.
225
226    echo -n "<li><font face=\"Bitstream Vera Sans Mono,Andale Mono,Lucida Console\" size=-2>"
227
228    if [ "$severity" = "3" ]; then
229      echo -n "<span style=\"border: solid black 1px; background-color: crimson; color: white; padding: 0.1em 0.4em 0.1em 0.4em\"><b>HIGH</b></span>"
230    elif [ "$severity" = "2" ]; then
231      echo -n  "<span style=\"border: solid black 1px; background-color: darkmagenta; color: white; padding: 0.1em 0.4em 0.1em 0.4em\"><b>MEDIUM</b></span>"
232    elif [ "$severity" = "1" ]; then
233      echo -n  "<span style=\"border: solid black 1px; background-color: blue; color: white; padding: 0.1em 0.4em 0.1em 0.4em\"><b>LOW</b></span>"
234    else
235      echo -n  "<span style=\"border: solid black 1px; background-color: gray; color: white; padding: 0.1em 0.4em 0.1em 0.4em\"><b>INFO</b></span>"
236    fi
237
238    # Provide additional flags on all but 'All visited URLs' sections.
239
240    if [ ! "$desc" = "All visited URLs" ]; then
241
242      echo -n "<span style=\"border: solid gray; border-width: 1px 1px 1px 0px; background-color: #fffece; color: #A0A040; padding: 0.1em 0.4em 0.1em 0.4em\">"
243
244      if [ "$[modifier & 4]" = "0" ]; then
245        echo -n "echo&nbsp;"
246      else
247        echo -n "<font color=\"#800000\">ECHO</font>&nbsp;"
248      fi
249
250      if [ "$[modifier & 1]" = "0" ]; then
251        echo -n "pred&nbsp;"
252      else
253        echo -n "<font color=\"#800000\">PRED</font>&nbsp;"
254      fi
255
256      if [ "$[modifier & 2]" = "0" ]; then
257        echo -n "auth"
258      else
259        echo -n "<font color=\"#800000\">AUTH</font>"
260      fi
261
262      echo -n "</span>&nbsp;"
263
264    else
265
266      echo -n "&nbsp;"
267
268    fi
269
270    # Prepare trace / decompile links, if available.
271
272    if [ "$trace" = "-" ]; then
273      TLINK=""
274    else
275
276      if [ -s "$trace.flr" ]; then
277        TLINK="&nbsp;<font size=-2>[<a href=\"$RAT_URLPREFIX$trace.flr\">decompile</a>]&nbsp;[<a href=\"$RAT_URLPREFIX$trace\">view&nbsp;trace</a>]</font>"
278      else
279        TLINK="&nbsp;<font size=-2>[<a href=\"$RAT_URLPREFIX$trace\">view&nbsp;trace</a>]</font>"
280      fi
281
282    fi
283
284    # Output URL, query, and response data.
285
286    test "$method" = "-" && method="[Referer]"
287
288    if [ "$payload" = "-" ]; then
289
290      echo "<font color=\"teal\">$method</font>&nbsp;<a href=\"$url\">$url</a>&nbsp;&rArr;&nbsp;$code$TLINK<br>"
291
292      if [ ! "$response" = "-" ]; then
293        echo "<font size=-3 color=gray>Response&nbsp;($len):&nbsp;$response</font><br>"
294      fi
295
296      if [ ! "$cookies" = "-" ]; then
297        echo "<font size=-3 color=royalblue>Cookies&nbsp;set:&nbsp;$cookies</font><br>"
298      fi
299
300      if [ ! "$offend" = "-" ]; then
301        echo "<font size=-3 color=darkred>Offending&nbsp;value:&nbsp;$offend</font><br>"
302      fi
303
304      if [ "$method" = "[Referer]" ]; then
305        echo "<font size=-3 color=black>Target&nbsp;resource:&nbsp;<a href=\"$sniff\">$sniff</a></font>"
306      else
307        echo "<font size=-3 color=black>MIME type: <font color=teal>$mime</font>, detected: <font color=teal>$sniff</font>, charset: <font color=teal>$cset</font></font>"
308      fi
309
310    else
311
312      isfile=""
313
314      if echo "$payload" | grep -qF "=FILE["; then
315        isfile="(FILE)&nbsp;"
316      fi
317
318      echo "<font color=\"crimson\">$isfile$method</font>&nbsp;<a href=\"javascript:void(0)\" onclick=\"document.getElementById('form$CNT').submit();return false;\">$url</a>&nbsp;&rArr;&nbsp;$code$TLINK<br>"
319      echo "<font size=-3 color=teal>Payload:&nbsp;$payload</font><br>"
320
321      if [ ! "$response" = "-" ]; then
322        echo "<font size=-3 color=gray>Response&nbsp;($len):&nbsp;$response</font><br>"
323      fi
324
325      if [ ! "$cookies" = "-" ]; then
326        echo "<font size=-3 color=royalblue>Cookies&nbsp;set:&nbsp;$cookies</font><br>"
327      fi
328
329      if [ ! "$offend" = "-" ]; then
330        echo "<font size=-3 color=darkred>Offending&nbsp;value:&nbsp;$offend</font><br>"
331      fi
332
333      echo "<font size=-3 color=black>MIME type: <font color=teal>$mime</font>, detected: <font color=teal>$sniff</font>, charset: <font color=teal>$cset</font></font><br>"
334
335      if ! echo "$payload" | grep -q '^GWT_RPC\['; then
336
337        echo "<input type=submit value=\"edit values\" onclick=\"document.getElementById('form$CNT').style.display='inline';return false;\" style=\"border-width: 1px; background-color: #FFFFC0; font-size: 0.9em; display: inline\">"
338        echo "<form action=\"$url\" method=\"POST\" id=\"form$CNT\" style=\"display: none\">"
339        echo "$payload" | sed 's/\&#x\(..\);/%\1/g' | sed 's/&/\
340/g' | sed 's/%26/\&/g;s/%3B/;/g' | sed 's/\%\(..\)/\&#x\1;/g' | \
341        while IFS='=' read -r param val; do
342          echo "<INPUT TYPE=text STYLE=\"border-width: 1px; background-color: #FFC0A0; font-size: 0.9em\" NAME=\"$param\" VALUE=\"$val\">"
343        done
344        echo "</form>"
345
346      fi
347
348    fi
349
350    echo "</font><p></li>"
351
352    CNT=$[CNT+1]
353
354  done
355
356echo "</ul></div></body></html>"
357