-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbindhack.c
239 lines (172 loc) · 4.4 KB
/
bindhack.c
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
/*
A simple LD_PRELOAD hack to let you specify the source address
for all outbound connections or if you want to limit a process
to only listening on one IP
Copyright (C) 2005 Robert J. McKay <[email protected]>
License: You can do whatever you want with it.
Compile:
gcc -fPIC -static -shared -o bindhack.so bindhack.c -lc -ldl
You can add -DDEBUG to see debug output.
Usage:
LD_PRELOAD=/path/to/bindhack.so <command>
eg:
LD_PRELOAD=/home/rm/bindhack.so telnet example.com
you can also specify the address to use at runtime like so:
LD_PRELOAD=/home/rm/bindhack.so BIND_SRC=192.168.0.1 telnet example.com
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <dlfcn.h>
#include <arpa/inet.h>
/*
This is the address you want to force everything to use. It can be
overriden at runtime by specifying the BIND_SRC environment
variable.
*/
#define SRC_ADDR "192.168.0.1"
/*
LIBC_NAME should be the name of the library that contains the real
bind() and connect() library calls. On Linux this is libc, but on
other OS's such as Solaris this would be the socket library
*/
#define LIBC_NAME "libc.so.6"
#define YES 1
#define NO 0
int
bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen)
{
struct sockaddr_in src_addr;
void *libc;
int (*bind_ptr)(int, void *, int);
int ret;
int passthru;
char *bind_src;
#ifdef DEBUG
fprintf(stderr, "bind() override called for addr: %s\n", SRC_ADDR);
#endif
libc = dlopen(LIBC_NAME, RTLD_LAZY);
if (!libc)
{
fprintf(stderr, "Unable to open libc!\n");
exit(-1);
}
*(void **) (&bind_ptr) = dlsym(libc, "bind");
if (!bind_ptr)
{
fprintf(stderr, "Unable to locate bind function in lib\n");
exit(-1);
}
passthru = YES; /* By default, we just call regular bind() */
if (my_addr==NULL)
{
/* If we get a NULL it's because we're being called
from the connect() hack */
passthru = NO;
#ifdef DEBUG
fprintf(stderr, "bind() Received NULL address.\n");
#endif
}
else
{
if (my_addr->sa_family == AF_INET)
{
struct sockaddr_in myaddr_in;
/* If this is an INET socket, then we spring to
action! */
passthru = NO;
memcpy(&myaddr_in, my_addr, addrlen);
src_addr.sin_port = myaddr_in.sin_port;
}
else
{
passthru = YES;
}
}
if (!passthru)
{
#ifdef DEBUG
fprintf(stderr, "Proceeding with bind hack\n");
#endif
src_addr.sin_family = AF_INET;
bind_src=getenv("BIND_SRC");
/* If the environment variable BIND_SRC is set, then use
that as the source IP to bind instead of the hard-coded
SRC_ADDR one.
*/
if (bind_src)
{
ret = inet_pton(AF_INET, bind_src, &src_addr.sin_addr);
if (ret<=0)
{
/* If the above failed, then try the
built in address. */
inet_pton(AF_INET, SRC_ADDR,
&src_addr.sin_addr);
}
}
else
{
inet_pton(AF_INET, SRC_ADDR, &src_addr.sin_addr);
}
/* Call real bind function */
ret = (int)(*bind_ptr)(sockfd,
(void *)&src_addr,
sizeof(src_addr));
}
else
{
#ifdef DEBUG
fprintf(stderr, "Calling real bind unmolested\n");
#endif
/* Call real bind function */
ret = (int)(*bind_ptr)(sockfd,
(void *)my_addr,
addrlen);
}
#ifdef DEBUG
fprintf(stderr, "The real bind function returned: %d\n", ret);
#endif
/* Clean up */
dlclose(libc);
return ret;
}
/*
Sometimes (alot of times) programs don't bother to call bind()
if they're just making an outgoing connection. To take care of
these cases, we need to call bind when they call connect
instead. And of course, then call connect as well...
*/
int
connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen)
{
int (*connect_ptr)(int, void *, int);
void *libc;
int ret;
#ifdef DEBUG
fprintf(stderr, "connect() override called for addr: %s\n", SRC_ADDR);
#endif
/* Before we call connect, let's call bind() and make sure we're
using our preferred source address.
*/
ret = bind(sockfd, NULL, 0); /* Our fake bind doesn't really need
those params */
libc = dlopen(LIBC_NAME, RTLD_LAZY);
if (!libc)
{
fprintf(stderr, "Unable to open libc!\n");
exit(-1);
}
*(void **) (&connect_ptr) = dlsym(libc, "connect");
if (!connect_ptr)
{
fprintf(stderr, "Unable to locate connect function in lib\n");
exit(-1);
}
/* Call real connect function */
ret = (int)(*connect_ptr)(sockfd, (void *)serv_addr, addrlen);
/* Clean up */
dlclose(libc);
return ret;
}