0% found this document useful (0 votes)
2 views

unit2

The document discusses secure coding techniques, focusing on vulnerabilities such as buffer overruns, heap overruns, array indexing errors, and format string bugs. It explains how these vulnerabilities can be exploited through examples in C programming, emphasizing the importance of proper input validation and access control mechanisms. The document also highlights the significance of using Access Control Lists (ACLs) to enhance security in coding practices.

Uploaded by

yvrannamayya
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views

unit2

The document discusses secure coding techniques, focusing on vulnerabilities such as buffer overruns, heap overruns, array indexing errors, and format string bugs. It explains how these vulnerabilities can be exploited through examples in C programming, emphasizing the importance of proper input validation and access control mechanisms. The document also highlights the significance of using Access Control Lists (ACLs) to enhance security in coding practices.

Uploaded by

yvrannamayya
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 44

Writing secure Code

UNIT II
Secure Coding Techniques:
Public Enemy #1: The Buffer Overrun: Static Buffer Overruns, Heap Overruns, Array Indexing
Errors, Format String Bugs, Unicode and ANSI Buffer Size Mismatches, Preventing Buffer Overruns.
Determining Good Access Control: Why ACLs Are Important. What Makes Up an ACL? A Method
of Choosing Good ACLs, Creating ACLs, NULL DACLs and Other Dangerous ACE Types, Other
Access Control Mechanisms.
Secure Coding Techniques
Static Buffer Overruns
• A static buffer overrun occurs when a buffer declared on the stack is
overwritten by copying data larger than the buffer.
• Variables declared on the stack are located next to the return address for the
function's caller.
• The usual culprit is unchecked user input passed to a function such as strcpy,
and the result is that the return address for the function gets overwritten by
an address chosen by the attacker.
• In a normal attack, the attacker can get a program with a buffer overrun to do
something he considers useful, such as binding a command shell to the port of
their choice.
• The attacker often has to overcome some interesting problems, such as the fact
that the user input isn't completely unchecked or that only a limited number of
characters will fit in the buffer.
• If you're working with double-byte character sets, the hacker might have to work
harder, but the problems this introduces aren't insurmountable.
• If you're the type of programmer who enjoys arcane puzzles—the classic
definition of a hacker—exploiting a buffer overrun can be an interesting
exercise.
Secure Coding Techniques
Static Buffer Overruns
• so I'll use a program written in C to show a simple exploit of an overrun. Let's
take a look at the code:
• /*This program shows an example of how a static buffer overrun can be used to
execute arbitrary code. Its objective is to find an input string that executes
the function bar.- */
• //include <stdio.h>
• //include <string.h>
• void foo(const char* input)
• {
• char buf[10];
• //What? No extra arguments supplied to printf?
• //It's a cheap trick to view the stack 8-)
• printf ("My stack looks 1ike:\n%p\n%p\n%p\n%p\n%p\n%p\n\n");
• //Pass the user input straight to secure code public enemy #1
• strcpy(buf, input);
• printf("%s\n", buf);
• printf ("Now the stack looks 1ike:\n%p\n%p\n%p\n%p\n%p\n%p\n\n");
• }
Secure Coding Techniques
Static Buffer Overruns
• void bar(void)
• {
• printf ("Augh! I've been hacked!\n");
• }
• int main(int argc, char* argv[])
• {
//Blatant cheating to make life easier on myself
printf ("Address of foo = %p\n", foo);
printf ("Address of bar = %p\n", bar); -
foo(argv[l]);
return 0;
}
The Buffer Overrun
• This application is nearly as simple as "Hello, World." I start off doing a little cheating and printing
the addresses of my two functions, foo and bar, by using the printf function's %p option, which
displays an address.
• If I were hacking a real application. I'd probably try to jump back into the static buffer declared
in foo or find a useful function loaded from a system dynamic-link library (DLL).
• The objective of this exercise is to get the bar function to execute.
• The foo function contains a pair of printf Statements that use a side effect of variable-argument
functions to print the values on the stack.
• The real problem occurs when the foo function blindly accepts user input and copies it into a 10-
byte buffer.
• The best way to follow along is to compile the application from the command line to produce a
release executable.
• Don't just load it into Microsoft Visual C++ and run it in debug mode—the debug version contains
checks for stack problems, and it won't demonstrate the problem properly.
• However, you can load the application into Visual C++ and run it in release mode.
• Let's take a look at some output after providing a string as the command line argument:
The Buffer Overrun
[d:\JStaticOverrun.exe Hello
Address of foo = 00401000
Address of bar = 00401045
My stack looks like:
00000000
00000000
7FFDF000
0012FF80
0040108A <-- We want to overwrite the return address for foo.
00410EDE
Hello
Now the stack looks like:
6C6C6548 <-- You can see where "Hello" was copied in.
0000006F
7FFDF000
0012FF80
0040108A
00410EDE
The Buffer Overrun
Now for the classic test for buffer overruns—we input a long string:
[d : \ ] StaticOverrun.exe AAAAAAAAAAAAAAAAAAAAAAAA
Address of foo = 00401000
Address of bar = 00401045
My stack looks like:
00000000
00000000
7FFDF000
0012FF80
0040108A
00410ECE
AAAAAAAAAAAAAAAAAAAAAAAA
Now the stack looks like:
41414141
41414141
41414141
41414141
41414141
41414141
And we get the application error message claiming the instruction at 0x41414141 tried to access memory
at address 0x41414141, as shown in Figure 3-1.
The Buffer Overrun
Heap Overruns
The Buffer Overrun
• A heap overrun is much the same problem as a static buffer overrun, but it’s
somewhat trickier to exploit.
• As in the case of a static buffer overrun, your attacker can write fairly
arbitrary information into places in your application that she shouldn't have
access to.
• One of the best articles I've found is wOOwOO on Heap Overpons, written by
Matt Conover of wOOwOO Security Development(CWSD).
• You can find this article at it www.wOOwOO.org/files/articles/heaptut.txt.
• WSD is a hacker organization that makes the problems they find public and
typically works with vendors to get the problems fixed.
• The article demonstrates a number of the attacks they list, but here's a
short summary of the reasons heap overflows can be serious
• Main programmers don't think heap overruns are exploitable, leading them to
handle allocated buffers with less care than static buffers.
• Tools exist to make static buffer overruns more difficult to exploit.
StackGuard, developed by Crispin Cowan and others, uses a test value—known as
a canary alter the miner's practice of taking a canary into a coal mine—to
make- a static buffer overrun much less trivial to exploit Visual C++ .NET
incorporates a similar approach. Similar tools do not currently exist to
protect against heap overruns.
Heap Overruns
The Buffer Overrun
• Some operating systems and chip architectures can be configured to have a
nonexecutable stack.
• Once again, this won't help you against a heap overflow because a
nonexecutable stack protects against stack-based attacks, not heap-based
attacks.
• Although Mart's article gives examples based on attacking UNIX systems, don't
be fooled into thinking that Microsoft Windows systems are any less
vulnerable.
• Several proven exploitable heap overruns exist in Windows applications.
• One possible attack against a heap overrun that isn't detailed in the wOOwOO
article is detailed in the following post to BugTraq by Solar Designer
(available at www.securityfocus.com/archive/1/71598):
Heap Overruns
The Buffer Overrun
• Some operating systems and chip architectures can be configured to have a
nonexecutable stack.
• Once again, this won't help you against a heap overflow because a
nonexecutable stack protects against stack-based attacks, not heap-based
attacks.
• Although Mart's article gives examples based on attacking UNIX systems, don't
be fooled into thinking that Microsoft Windows systems are any less
vulnerable.
• Several proven exploitable heap overruns exist in Windows applications.
• One possible attack against a heap overrun that isn't detailed in the wOOwOO
article is detailed in the following post to BugTraq by Solar Designer
(available at www.securityfocus.com/archive/1/71598):
The Buffer Overrun
Heap Overruns
The following application shows how a heap overrun can be exploited:
/*
HeapOverrun.cpp
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
Very flawed class to demonstrate a problem
class BadStringBuf
{
public:
BadStringBuf ( void)
m_buf = NULL;
~BadStringBuf (void)
if(m_buf != NULL)free(m_buf );
void Init(char* buf)
//Really bad code
m_buf = buf;
The Buffer Overrun
Heap Overruns
The following application shows how a heap overrun can be exploited:
void SetString(const char* input)
//This is stupid.
strcpy(m_buf . input);
const char* GetString( void)
return m_buf;
private:
char* m_buf;
};
//Declare a pointer to the BadStringBuf class to hold our input
BadStringBuf* g_plnput = NULL;
void bar(void)
{
printf ("Augh! I've been hacked!\n");
}
void BadFunc(const char* inputl, const char* input2)
{
//Someone told me that heap overruns weren't exploitable,
//so we'll allocate our buffer on the heap.
char* buf = NULL;
The Buffer Overrun
Heap Overruns
The following application shows how a heap overrun can be exploited:
char* buf2;
buf2 = (char*)malloc(16) ;
g_plnput = new BadStri ngBuf ;
buf = (char*)malloc(16);
//Bad programmer - no error checking on allocations
g_plnput->lnit(buf2) ;
//The worst that can happen is we'll crash, right???
strcpy(buf, inputl);
g_pInput->SetString( input2);
printf(”input 1 = %s\ninput2 = %s\n". buf, g_pInput->GetStri ng( ) );
if(buf != NULL)free(buf );
}
The Buffer Overrun
Heap Overruns
int main(int argc, char* argv[])
{
char argl[128];
//This is the address of the bar function.
//It looks backwards because Intel processors are little endian.
char arg2[4] = {0x0f, 0x10, 0x40, 0};
int offset = 0x40;
/*Using 0xfd is an evil trick to overcome heap corruption checking The
0xfd value at the end of the buffer checks for corruption. No error checking
here - it is just an example of how to construct an overflow string.*/
memset(argl, 0xfd, offset);
argl[offset] = (char)0x94;
argl[offset+l] = (char)0xfe
argl[offset+2] = (char)0xl2
argl[offset+3] = 0; argl[offset+4] = 0;
printf ("Address of bar is %p\n", bar);
BadFunc(argl , arg2);
if(g_plnput != NULL delete g_plnput;
return 0; }
The Buffer Overrun
Array Indexing Errors
• Array indexing errors are much less commonly exploited than buffer overruns
but it amounts to the same thing—a string is just an array of characters, and
it stands to reason that arrays of other types could also be used to write to
arbitrary memory locations.
• If you don't look deeply at the problem, you might think that an array
indexing error would allow you to write to memory locations only higher than
the base of the array, but this isn't true.
• Let's look at sample code that demonstrates how an array indexing error can
be used to write memory in arbitrary locations:
// ArraylndexError .cpp
#include <stdio.h>
#include <stdlib.h>
int* IntVector;
void bar(void)
{
printf ("Augh! I've been hacked! \n");
}
The Buffer Overrun
Array Indexing Errors
void Insertlnt(unsigned long index, unsigned long value)
{
//We're so sure that no one would ever pass in
//a value more than 64 KB that we're not even going to
//declare the function as taking unsigned shorts
//or check for an index out of bounds - don!
printf("Writing memory at %p\n", &( IntVector[index] ) );
IntVector[index] = value;
}
bool InitVector(int size)
{
IntVector = ( int* )mal1oc(sizeof(int)*size);
printf ("Address of IntVector is %p\n", IntVector);
if(intVector == NULL)return false;
else return true;
}
The Buffer Overrun
Array Indexing Errors
int main(int argc, char* argv[])
{
unsigned long index, value;
if (argc != 3)
{
printf ("Usage is %s [index] [value]\n");
return -1;
}
printf("Address of bar is %p\n". bar);
//Let's initialize our vector - 64 KB ought to be enough for anyone <g>.
if( !InitVector(0xffff))
{
printf("Cannot initialize vector!\n");
return -1;
}
index = atol(argv[l]);
value = atol(argv[2]);
Insertlnt(index, value);
return 0;}
The Buffer Overrun
Array Indexing Errors
• Now let's look at the math.
• The array in our example starts at 0x00510048, and the value we'd like to
write is—guess what?—the return value on the stack, which is located at
0x0012FF84.
• The following equation describes how the address of a single array element is
determined by the base of the array, the index, and the size of the array
elements:
• Address of array element = base of array + index * sizeof(element)
• Substituting the example's values into the equation, we get
• 0x10012FF84 = 0x00510048 + index * 4
• Note that Oxl0012FF84 is used in our equation instead of 0x0012FF84.
• A little quick work with Calc.exe shows that index is 0x3FF07FCF, or
1072725967, and that the address of bar(0x00401000) is 4198400 in decimal.
Here are the program results:
• [d:\3ArrayIndexError.exe 1072725967 4198400
• Address of bar is 00401000
• Address of IntVector is 00510048
• Writing memory at 0012FF84
• Augh! I've been hacked!
Format String Bugs
The Buffer Overrun
• Format string bugs aren't exactly a buffer overflow, but because they lead to
the same problems.
• Unless you follow security vulnerability mailing lists closely, you might not
be familiar with this problem.
• You can find two excellent postings on the problem in BugTraq: one is by Tim
Newsham and is available at www.securityfocus. com/archive/'1/81 565, and the
other is by Lamagra Argamal and is available at
www.securityfocus.com/archive/1/66842.
• The basic problem stems from the fact that there isn't any realistic way for
a function that takes a variable number of arguments to determine how many
arguments were passed in.
• What makes this problem interesting is that the %n format specifier writes
the number of bytes that would have been written by the format string
• into the pointer supplied for that argument With a bit of tinkering, we find
that somewhat random bits of our process's memory space are now overwritten
with the bytes of the attacker's choice.
• A large number of format string bugs have been found in unix and unix-Iike
applications over the last year.
Format String Bugs
The Buffer Overrun
• Exploiting such bugs is a little difficult on Windows systems only because
many of the chunks of memory we'd like to write are located at OxOOffffff or
below—for example, the stack will normally be found in the range of
approximately 0x00120000.
• The fix to the problem is relatively simple: always pass in a format string
to the print/ family of functions For example, printf(input); is exploitable,
and printf( "%s", input) is not exploitable.
• Despite the fact that I didn't include a demo application, always remember
that if you allow an attacker to start writing memory anywhere in your
application, it's just a matter of time before he figures out how to turn it
into a crash or execution of arbitrary code.
• This bug is fairly simple to avoid.
• Take special care if you have custom format strings stored to help with
versions of your application in different languages.
• If you do, make sure that the strings can't be written by unprivileged users.
The Buffer Overrun
Unicode and ANSI Buffer Size Mismatches
• The buffer overrun caused by Unicode and ANSI buffer size mismatches is
somewhat common on Windows platforms.
• It occurs if you mix up the number of elements with the size in bytes of a
Unicode buffer.
• There are two reasons it's rather widespread: Windows NT and later support
ANSI and Unicode strings, and most Unicode functions deal with buffer sizes
in wide characters,not byte sizes.
• The most commonly used function that is vulnerable to this kind of bug is
MultiBYtetoWideChar Take a look at the following code:
BOOL GetName(char *szName)
{
WCHAR wszUserName[256];
// Convert ANSI name to Unicode.
MultiByteToWideChar(CP_ACP, 0,szName,-1,wszUserName,sizeof(wszUserName));
// Snip
}
• Can you see the vulnerability? OK, time is up.
• The problem is the last argument of MultiByteToWideChar.
The Buffer Overrun
Unicode and ANSI Buffer Size Mismatches
• The documentation for this argument states: "Specifies the size, in wide
characters, of the buffer pointed to by the IpWideCharStr parameter." The
value passed into this call is sizeof(uszUserName), which is 256, right?
• No, it's not. wszUserName is a Unicode string; it's 256 wide characters.
• A wide character is two bytes, so sizeof(wszUserName) is actually 512 bytes.
• Hence, the function thinks the buffer is 512 wide characters in size.
• Because wszUserName is on the stack, we have a potential exploitable buffer
overrun.
• Here's the correct way to write this function:
• MultiByteToWideChar(CP_ACP, 0,szName,-1,wszUserName,sizeof (wszUserName)
/sizeof (wszUserName[0] ) )
The Buffer Overrun
Preventing Buffer Overruns
• The first line of defense is simply to write solid code! Although some
aspects of writing secure code are a little arcane, preventing buffer
overruns is mostly a matter of writing a robust application. Writing Solid
Code.
• Always validate all your inputs—the world outside your function should be
treated as hostile and bent upon your destruction.
• Likewise, nothing about the function's internal implementation, nothing other
than the function’s expected inputs and output, should be accessible outside
the function.
• I recently exchanged mail with a programmer who had written a function that
looked like this:
void PrintLine(const char* msg)
{
char buf[255];
sprintf(buf. "Prefix %s suffix\n". msg);
}
The Buffer Overrun
Preventing Buffer Overruns
• When 1 asked him why he wasn't validating his inputs, he replied that he
controlled all the code that called the function, he knew how long the buffer
was, and he wasn't going to overflow it.
• Then I asked him what he thought might happen if someone else who wasn't that
careful needed to maintain his code. "Oh." he said.
• This type of construct is just asking for trouble—functions should always
fail gracefully, even if unexpected input is passed into the function.
Determining Good Access Control
• Microsoft Windows offers many means to limit who has access to what.
• The most common, and to some extent one of the least understood, means is the
access control list (ACL). The ACL is a fundamental part of Microsoft Windows
NT, Windows 2000, and Windows XP.
• In this Unit, I'll discuss some of the best practices when determining
appropriate access control mechanisms for protecting resources.
• The topics covered include why ACLs are important, what makes up an ACL, how
to choose good ACLs, the creation of ACLs, NULL DACLs and other dangerous ACE
types, and other access control mechanisms.
Determining Good Access Control
Why ACLs Are Important
• ACLs are quite literally your application's last backstop against an attack,
with the possible exception of good encryption and key management.
• If an attacker can access a resource, his job is done.
• Imagine you have some data held in the registry and the ACL on the registry
key is Everyone (Full Control), which means anyone can do anything to the
data, including read, write, or change the data or deny others access to the
• data.
• Look at the following code example, which reads the data from the registry
key with the dangerous ACL:
Determining Good Access Control
Why ACLs Are Important
#define MAX_BUFF (64)
#define MY_VALUE "SomeData"
BYTE bBuff[MAX_BUFF];
ZeroMemory(bBuff, MAX_BUFF);
// Open the registry.
HKEY hKey = NULL;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE," Software\\ North wind traders"
,0,KEY_READ, &hKey) == ERROR_SUCCESS){
// Determine how much data to read.
DWORD cbBuff = 0;
if ( RegQueryValueEx(hKey,MY_VALUE,NULL,NULL,NULL,&cbBuff) = ERROR_SUCCESS) {
// Now read all the data.
if ( RegQueryValueEx(hKey,MY_VALUE,NULL,NULL,bBuff,&cbBuff) = ERROR_SUCCESS) {
// Cool !
// We have read the data from the registry.
}
}
}
if (hKey) RegCloseKey(hKey) ;
Determining Good Access Control
Why ACLs Are Important
• This code might look reasonable, but it's horribly flawed.
• The code incorrectly assumes that the data held in the registry is no bigger
than 64 bytes in size.
• The first call to RegQueryValueEx reads the data size from the registry, and
the second call to RegQueryValueEx reads into the local buffer as many bytes
of data as were determined by the first call to RegQueryValueEx.
• A potential buffer overrun exists if this value is greater than 64 bytes.
Determining Good Access Control
What Makes Up an ACL?
• An ACL is an access control method employed by many operating systems,
including Windows NT, Windows 2000, and Windows XP, to determine to what
degree an account is allowed to access a resource.
• Windows 95, Windows98, Windows Me, and Windows CE do not support ACLs.
Determining Good Access Control
What Makes Up an ACL?
• Windows NT and later contains two types of ACLs: discretionary access control
lists (DACLs) and system access control list (SACLs).
• A DACL determines access rights to secured resources.
• A SACL determines audit policy for secured resources.
• Examples of resource that can be secured using DACLs and audited using SACLs
include the following:
• Files and directories
• File shares
• Registry keys
• Shared memory
• Job objects
• Mutexes
• Named pipes
• Printers
• Semaphores
• Active directory objects
Determining Good Access Control
What Makes Up an ACL?
• Each DACL includes zero or more access control entries (ACEs).
• A NULL DACL—that is, a current DACL that is set to NULL—means no access
control mechanism exists on the resource.
• NULL DACLs are had and should never be used because an attacker can set any
access policy On the object.
• An ACE includes two major components: an account represented by the account's
Security ID (SID) and a description of what that SID can do to the resource
in question.
• As you might know, a SID represents a user, group, or computer.
• The most famous—some would say infamous—ACE is Everyone(Full Control)
Everyone is the account; the SID for Everyone, also called World,is S-l-1-0.
• Full Control is the degree to which the account can access the resource in
question—in this case, the account can do anything to the resource.
• Believe me, Full Control really does mean anything! Note that an ACE can also
be a deny ACE, an ACE that disallows certain access.
• For example, Everyone (Deny Full Control) means that every account—including
you!—will be denied access to the resource. If an attacker can set this ACE
on a resource, serious denial of service (DoS) threats exist because no one
can access the resource.
Determining Good Access Control
A Method of Choosing Good ACLs
• Over the past few months I've come to live by the following security maxim
when performing security reviews: "You must account for every ACE in an ACL.“
• In fact, if you can't determine why an ACE exists in an ACL, you should
remove the ACE from the ACL.
• As with all engineering processes, you should design your system using a
high-level analysis technique to model the business requirements before
creating the solution, and the same philosophy applies to creating ACLs.
• The process of defining an appropriate ACL for your resources is simple:
1. Determine the resources you use.
2. Determine the business-defined access requirements.
3. Determine the appropriate access control technology.
4. Convert the access requirements to access control technology.
Determining Good Access Control
Creating ACLs
• I am covering the creation of ACLs because one of the arguments I hear from
developers against adding ACLs to their applications is that they have no
idea which APIs to use. In this portion of the chapter, I'll delve into
creating ACLs in Windows 2000.
Creating ACLs in Windows 2000
• Recognizing that many people did not understand the ACL and security
descriptor functions in the Windows 2000 security engineering team added a
textual ACL and security descriptor representation called the Security
Descriptor Definition Language (SDDL).
• Essentially, SIDs and ACEs are represented in SDDL through the use of well-
defined letters.
• The following example code creates a directory named c:\MyDir and sets the
following ACE:
Determining Good Access Control
Determining Good Access Control
Determining Good Access Control
NULL DACLs and Other Dangerous ACE Types
• A NULL DACL is a way of granting all access to an object to all users,
including attackers.
• I sometimes quip that NULL DACL == No Defense. And it is absolutely true.
• If you don't care that anyone can do anything to your object—including read
from it. write to it. delete existing data, modify existing data, and deny
others access to the object—a NULL DACL is fine.
• However. I have yet to see a product for which such a requirement is of
benefit, which, of course,completely rules out the use of NULL DACLs in your
products’ If you see code like the following, file a bug.
• It should be fixed because the object is not protected.
• if (SetSecurityDescriptorDacl(&sd.
• TRUE, // DACL Present
• NULL, // NULL DACL
• FALSE)) {
• // Use security descriptor and NULL DACL.
• }
Determining Good Access Control
NULL DACLs and Other Dangerous ACE Types
• Another variation of this is to populate a SECURITYDESCRIPTOR structure
manually.
• The following code will also create a NULL DACL:
• SECURITY.DESCRIPTOR sd = {
• SECURITY_DESCRIPTOR_REVISION,0x0,SE_DACL_PRESENT,0x0,0x0,0x0,
• 0x0); // Dacl is 0 or NULL.
Determining Good Access Control
NULL DACLs and Other Dangerous ACE Types
Dangerous ACE Types
• You should be wary of three other dangerous ACE types: Everyone (WRITE_DAC).
Evenone (WRITE_OWNER) and directory ACLs.
• which allow anyone to add new executables
Everyone (WRITE_DAC)
• WRITE_DAC is the right to modify the DACL in the object's security
descriptor. If an untrusted user can change the Acl, the user can give
himself whatever access to the object he wants and can deny others access to
the object.
Everyone (WRITE_0WNER)
• WRITE_OWNER is the right to change the owner in the object's security
descriptor. By definition, the owner of an object can do anything to the
object. If an untrusted user can change the object owner, all access is
possible for that user as is denying others access to the object.
Determining Good Access Control
NULL DACLs and Other Dangerous ACE Types
Everyone (FILE_ADD_FILE)
• The Everyone (FILE_ADD_FILE) ACE is particularly dangerous because it allow s
untrusted users to add new executables to the file system. The danger is that
an attacker can write a malicious executable file to a file system and wait
for an administrator to run the application. Then the malevolent application,
a Trojan, performs nefarious acts. In short, never allow untrusted users to
write files to shared application directories.
Everyone (DELETE)
• The Everyone (DELETE) ACE allows anyone to delete the object, and you should
never allow untrusted users to delete objects created by your application.
Determining Good Access Control
Other Access Control Mechanisms
• Using ACLs is a useful method to protect resources, but there are other ways
too.
• Three of the most common are IP restrictions,COM+ roles, and SQL triggers and
permissions.
• What makes these a little different from ACLs is that they are built into
specific applications and ACLs are a critical core component of the operating
system.
IP Restrictions
• IP restrictions are a component of most Web servers, including IIS.
• Using IP restrictions, a developer or administrator can restrict access to
parts of a Web site to specific IP addresses (for example, 192.168.19.23),
subnets (192.168.19.0/24), DNS names (.www.microsofi.cotn), and domain names
(*.microsoft com) If you're building Web-based applications, don't rule out
using IP restrictions.
• For example, you might include some form of administration functionality.
• One way of restricting who can use the administration tools is to place an IP
restriction limiting the usage to the IP addresses of certain administration
machines.
Determining Good Access Control
Other Access Control Mechanisms
• If you find your analysis of your business requirements and access rights
includes wording Like accessible only at the local machine" or "deny access
to all users and computers in the accounting northwindtraders.com domain,"
you might need to consider using IP restrictions.
• IP restrictions can also be useful if you include functionality that you want
enabled by default but don't want attackers using.
• You can achieve this by setting an IP restriction on the virtual directory
you create to allow your code to execute only at the local machine
(127.0.0.1).
Determining Good Access Control
C0M+ Roles
• COM+ roles are somewhat similar to Windows groups, but rather than being
defined and populated by a network administrator, they are defined by the
application designer at development time and populated by an application
administrator at deployment time.
• This allows for great flexibility because the network group membership and
the application role membership are related yet independent, which allows for
application design flexibility.
• Roles are enforced by COM+ at the application level by using the Component
Services management tool, or they can be enforced programmatically using the
IsCallerlnRole method.
• The following Visual Basic code shows how the method is used:
'Get the security call context.
Dim fAllowed As Boolean
Dim objCallCtx As SecurityCal1 Context
Set objCallCtx = GetSecurityCallContext( )
'Perform the role check.
fAllowed = objCallCtx. IsCal1erlnRole('Doctor")
If (fAllowed) Then ' Act according to the result.
End If
Determining Good Access Control
SQL Server Triggers and Permissions
• SQL Server triggers allow the developer to place arbitrarily complex access
rules on SQL tables.
• A trigger is called automatically by the SQL engine when data in the table is
either added, deleted, or modified.
• Note that triggers are not used when data is read This can be problematic, as
you might create an application with some access control logic using one or
more triggers to access control logic in other pails of the database, such as
permissions.
• The triggers will not be executed if a read operation is attempted.
• Permissions are to SQL Server what ACLs are to Windows and are in the simple
form “subject doing something to object." Examples include "Blake can read
from the Accounts table" and “Auditors can Read. Write, and Delete from the
AuditLog table."
• All objects can be secured in SQL Server by using permissions.

You might also like