RETURN-ORIENTED PROGRAMMING ON THE ARM CORTEX-

Daniel Dunn and Jason Macy February 23, 2014

1 Introduction

This document will outline the procedure used to exploit the stack on the Cortex-M4 as well as the theory and setup we used for this assignment. The techniques discussed in the document were used to exploit a downward grow- ing stack, however they can easily be modified for use with an upward growing stack.

2 Theory and Setup

This attack hinges on the idea that one has access to the source code of the program they are attacking. Often one has the executable on their computer and can use various utilities to dump the source code. In this case Fromelf was used to disassemble the .axf file into Assembly Language. We included the majority of the microlib functions in order to give us a larger sample space to select gadgets. There are many automated gadget finders and other resources that can be useful. We found it to be much efficient to use the find function included with many text editors because we had a good idea of what functions we needed for this task. There was also spent making sure the Keil IDE did not optimize needed features from the source code. The linker flag --no_remove was used to keep unused code in the final project. The compiler flag --no_protect_stack used to remove stack cookies as well. This ensured our gadgets would be preserved in the final executable and any modification of the return address would go unnoticed. In the end, two adjacent commands were found that would allow us to to memory from code space.

Figure 1: This is the first gadget used. The was originally used to restore state and return the end of a function but was repurposed to load R4 and R5 and branch to our next gadget

1 Figure 2: This is the second gadget used. This is a simple STR command that took advantage of previously loaded registers.

3 Implementation

This portion of the assignment required the most trial and error. The payload was designed to hold all vital information as well as have proper alignment to allow it to be interpreted as part of the stack. It’s important to remember when popping to the program counter that it has already been incremented once the command is executed. In our case instead of popping the address 0x810 into the PC we had to use 0x811, otherwise a hard fault would result.

3.1 Procedure After reading the datasheet for the microcontroller it was found that the value 0xA4420004 had to be written into the Flash Memory Control Register(0x400FD008). This proved to be a simple task using the above gadgets. The table below out- lines the content of the payload.

Gadgets Exploited Stack Overflown [16] AAAAAAAA Overflown passwd[16] AAAAAAAA Address of Gadget A Unexploited Stack 0x000000811 POP {r4-r6, PC} uname[16] Value to Pop into R4 0xA4420004 passwd[16] Value to Pop into R5 0x400FD008 Return Address[0x2A3] Filler to Pop into R6 AAAA Address of Gadget B to pop into PC 0x00000080F STR r4,[R5,#0X00]

Table 1: The table on the left demonstrates the unaltered stack. The table on the right shows the outline used when designing a payload.

Using the above outline and a hex editor we created a string of data that could be inserted in lieu of login credentials. When creating the payload it was important to remember the endianness of the board in order to orient the entries properly. The hex file was transmitted using a terminal application because many of the number combinations are not mapped to ascii characters.

2 3.2 Results Using the methods and gadgets outlined above we were able to successfully flash the memory of our microcontroller. It should be noted that the assignment statement required a reset of the board. This did not happen because once the memory was erased, the gadgets and code we used were no longer on the board. Also, once the memory was flashed it is essentially in the same state as initial startup. Below you’ll find the results of the code injection.

(a) (b)

Figure 3: Figure 3:a shows the stack before code injection. A3 02 is the orginial return address for Auth(). Figure 3:b shows the state of the stack after injection

(a) (b)

Figure 4: Figure 4:a shows the state of the memory before the code injection. Figure 4:b shows the final result after injecting payload.

4 Conclusion

This was a successful implementation of a code injection. Given more time and a larger code space, I don’t think it would be difficult to implement more com- plex attacks using the same methods. The limiting factor would be the size of the stack. This assignment has demonstrated the importance of code structure and how it interacts with the hardware its been implemented on. With this knowledge in mind I would structure the auth function differently for a downward growing stack than I would for an upward growing stack. I would also avoid using func- tions like gets() and opt for an implementation with bounds checking.

3 Payload.hex

6161 6161 6161 6161 6161 6161 6161 6161 1108 0000 0400 42a4 08d0 0f40 6161 6161 0f08 0000

Main.c

1 2 #include ”tm4c123gh6pm .h” 3 #include ” uart . h” 4 5 int main ( void ) 6 { 7 int a u t h o r i z e ; 8 9 i n i t ( ) ; 10 11 while ( 1 ) 12 { 13 a u t h o r i z e = auth ( ) ; 14 15 i f (authorize == 1) 16 myprintf(”Login/ incorrect! ”); 17 18 else i f (authorize == 0) 19 myprintf(”Welcome to the matrix! ”); 20 } 21 22 }

Uart.h

1 #ifndef UART H 2 #define UART H 3 4 #define UNAME ”jamacy” 5 #define PASSWD ”skittlebrau” 6 7 void transmit ( char ); 8 void i n i t ( void ); 9 int auth ( void ); 10 void myprintf ( char ∗); 11 void mygets ( char∗ ); 12 char g e tc h a r ( void ); 13 void delayms ( int ); 14 void s c o r c h e d e a r t h ( void ); 15 16 #endif

Uart.c

1 #include ”tm4c123gh6pm .h” 2 #include ” uart . h” 3 #include ” s t r i n g . h” 4 5 //Bloat header files 6 #include 7 #include 8 #include

4 9 #include 10 #include 11 #include 12 #include 13 #include 14 #include 15 #include 16 #include 17 #include 18 #include 19 #include 20 #include 21 #include 22 #include ∗/} 69 UART1 DR R = message[i];

5 70 71 } 72 } 73 74 void mygets ( char ∗ b u f f e r ) 75 { 76 char byte = 0 ; 77 int count = 0 ; 78 79 while ( 1 ) 80 { 81 while ( (UART1 FR R& 0x40) == 0 ) {/∗ If FIFO is empty, wait ∗/ } ; 82 byte = UART1 DR R; 83 i f (byte == 0x0D) 84 { 85 break ; 86 } 87 buffer[count] = byte; 88 count++; 89 } 90 91 b u f f e r [ count ] = ’ \0 ’ ; 92 93 } 94 95 //Unused code sections 96 void transmit ( char data ) 97 { 98 UART1 DR R = data ; 99 } 100 101 char g e tc h a r ( void ) 102 { 103 char data ; 104 data=UART1 DR R; 105 return data ; 106 } 107 108 void delayms ( int mult ) 109 { 110 111 NVIC ST CTRL R=0x04 ; 112 NVIC ST RELOAD R = 0xF40∗mult ; 113 NVIC ST CURRENT R= 0 ; 114 NVIC ST CTRL R|=0x5 ; 115 116 while (NVIC ST CURRENT R); 117 118 } 119 //End of unused code sections 120 121 122 //Bloat code 123 void b l o a t ( ) 124 { 125 char a[20] =”this”; 126 int t=rand ( ) ; 127 char ∗ pItem ; 128 char key[20] = ”example”; 129 int n=abs ( 2 3 ) ; 130 f l o a t b=a t o f ( a ) ; 131 int c=a t o l ( a ) ;

6 132 long long int d=atoll(a); 133 long int e=a t o l ( a ) ; 134 char strvalues[][20] = {”some”,”example”,””,”here” } ; 135 int f o o [ 5 ] = { 1 , 2 , 3 , 4 , 5 } ; 136 int bar [ 5 ] = { 3 , 1 , 4 , 5 , 2 } ; 137 d i v t divresult; 138 139 n=l a b s (65537L) ; 140 isalnum ( n ) ; 141 i s a l p h a ( n ) ; 142 i s b l a n k ( n ) ; 143 i s c n t r l ( n ) ; 144 i s d i g i t ( n ) ; 145 i s g r a p h ( n ) ; 146 i s l o w e r ( n ) ; 147 i s p u n c t ( n ) ; 148 i s s p a c e ( n ) ; 149 i s p r i n t ( n ) ; 150 i s u p p e r ( n ) ; 151 i s x d i g i t ( n ) ; 152 n=cos ( 3 . 1 4 ) ; 153 n=s i n ( 3 . 1 4 ) ; 154 n=tan ( 3 . 1 4 ) ; 155 n=acos ( 3 . 1 4 ) ; 156 n=a s i n ( 3 . 1 4 ) ; 157 n=atan ( 3 . 1 4 ) ; 158 n=cosh ( 3 . 1 4 ) ; 159 n=s i n h ( 3 . 1 4 ) ; 160 n=tanh ( 3 . 1 4 ) ; 161 n=exp ( 5 ) ; 162 n=l o g ( 2 ) ; 163 n=pow ( 2 , 2 ) ; 164 n=s q r t ( 7 1 ) ; 165 n=c b r t ( 8 0 ) ; 166 i s g r e a t e r (n , 1 0 ) ; 167 i s l e s s (n , 4 ) ; 168 memcmp( key , s t r v a l u e s [ 1 ] , 4 ) ; 169 strcmp ( key , s t r v a l u e s [ 1 ] ) ; 170 memset ( key , ’ 0 ’ , 5 ) ; 171 172 d i v r e s u l t = div ( 3 8 , 5 ) ; 173 174 175 q s o r t ( s t r v a l u e s , 4 , 20 , ( int ( ∗ )( const void ∗ , const void ∗) ) strcmp ); 176 pItem = ( char ∗) bsearch (key, strvalues, 4, 20, ( int ( ∗ )( const void ∗ , const void ∗) ) strcmp ) ; 177 178 } 179 //End of bloat code

7