A Final Thought: Non-File-Based Canonicalization Issues

A Final Thought: Non-File-Based Canonicalization Issues

The core of this chapter relates to canonical file representation, and certainly the vast majority of canonicalization security vulnerabilities relate to files. However, some vulnerabilities exist in the cases in which a resource can be represented by more than one name. The two that spring to mind relate to server names and usernames.

Server Names

Servers, be they Web servers, file and print servers, or e-mail servers, can be named in a number of ways. The most common way to name a computer is to use a DNS name for example, www.northwindtraders.com. Another common way is to use an IP address, such as 192.168.197.100. Either name will access the same server from the client code. Also, a local computer can be known as localhost and can have an IP address in the 127.n.n.n subnet. And if the server is on an internal Windows network, the computer can also be accessed by its NetBIOS same, such as \\northwindtraders.

So, what if your code makes a security decision based on the name of the server? It s up to you to determine what an appropriate canonical representation is and to compare names against that, failing all names that do not match. The following code can be used to gather various names of a local computer:

/* CanonServer.cpp */ for (int i = ComputerNameNetBIOS; i <= ComputerNamePhysicalDnsFullyQualified; i++) { TCHAR szName[256]; DWORD dwLen = sizeof szName / sizeof TCHAR; TCHAR *cnf; switch(i) { case 0 : cnf = ComputerNameNetBIOS"; break; case 1 : cnf = ComputerNameDnsHostname"; break; case 2 : cnf = ComputerNameDnsDomain"; break; case 3 : cnf = ComputerNameDnsFullyQualified"; break; case 4 : cnf = ComputerNamePhysicalNetBIOS"; break; case 5 : cnf = ComputerNamePhysicalDnsHostname"; break; case 6 : cnf = ComputerNamePhysicalDnsDomain"; break; case 7 : cnf = ComputerNamePhysicalDnsFullyQualified"; break; default : cnf = Unknown"; break; } BOOL fRet = GetComputerNameEx((COMPUTER_NAME_FORMAT)i, szName, &dwLen); if (fRet) { printf( %s in %s format.\n", szName, cnf); } else { printf( Failed %d", GetLastError()); } }

The complete code listing is available on the companion CD in the folder Secureco\Chapter 8\CanonServer. You can get the IP address or addresses of the computer by calling the Windows Sockets (Winsock) getaddrinfo function or by using Perl. You can use the following code:

my ($name, $aliases, $addrtype, $length, @addrs) = gethostbyname mymachinename"; foreach (@addrs) { my @addr = unpack( C4 , $_); print IP: @addr\n"; }

Usernames

Finally, we come to usernames. Historically, Windows supported one form of username: DOMAIN\UserName, where DOMAIN is the name of the user s domain and UserName is, obviously, the user s name. This is also referred to as the SAM name. For example, if Blake is in the DEVELOPMENT domain, his account would be DEVELOPMENT\Blake. However, with the advent of Windows 2000, the user principal name (UPN) was introduced, which follows the now-classic and well-understood e-mail address format of user@domain for example, blake@development.northwindtraders.com.

Take a look at the following code:

bool AllowAccess(char *szUsername) { char *szRestrictedDomains[]={ MARKETING , SALES }; for (i = 0; i < sizeof szRestrcitedDomains / sizeof szRestrcitedDomains[0]; i++) if (_strncmpi(szRestrictedDomains[i], szUsername, strlen(szRestrictedDomains[i]) == 0) return false; return true; }

This code will return false for anyone in the MARKETING or SALES domain. For example, MARKETING\Brian will return false because Brian is in the MARKETING domain. However, if Brian had the valid UPN name brian@marketing.northwindtraders.com, this function would return true because the name format is different, which causes the case-insensitive string comparison function to always return a nonzero (nonmatch) value.

Windows 2000 and later have a canonical name it s the SAM name. All user accounts must have a unique SAM name to be valid on a domain, regardless of whether the domain is Windows NT 4, Windows 2000, Windows 2000 running Active Directory, or Windows XP.

You can use the GetUserNameEx function to determine the canonical user name, like so:

/* CanonUser.cpp /* #define SECURITY_WIN32 #include <windows.h> #include <security.h> for (int i = NameUnknown ; i <= NameServicePrincipal; i++) { TCHAR szName[256]; DWORD dwLen = sizeof szName / sizeof TCHAR; TCHAR *enf; switch(i) { case 0 : enf = NameUnknown"; break; case 1 : enf = NameFullyQualifiedDN"; break; case 2 : enf = NameSamCompatible"; break; case 3 : enf = NameDisplay"; break; case 4 : enf = NameUniqueId"; break; case 5 : enf = NameCanonical"; break; case 6 : enf = NameUserPrincipal"; break; case 7 : enf = NameUserPrincipal"; break; case 8 : enf = NameServicePrincipal ; break; default : enf = Unknown ; break; } BOOL fRet = GetUserNameEx((EXTENDED_NAME_FORMAT)i, szName, &dwLen); if (fRet) { printf( %s in %s format.\n", szName, enf); } else { printf( %s failed %d\n", enf, GetLastError()); } }

You can also find this example code on the companion CD in the folder Secureco\Chapter 8\CanonUser. Don t be surprised if you see some errors; some of the extended name formats don t apply directly to users.

Finally, you should refrain from making access control decisions based on the username. If at all possible, use ACLs.



Writing Secure Code
Writing Secure Code, Second Edition
ISBN: 0735617228
EAN: 2147483647
Year: 2005
Pages: 153

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net