Overview:
- Get the sqlite3 command & test the radius login locally to create the DB & OTP
- Insert a row into the “server” table with the @gmail.com login/pass of the sending email address
- Insert a row into the “login” table with the Wi-Fi login username, $salt$<wpa-pbkdf2(salt,password)>, & email/sms address
That’s it, now you have one time pads being sent to your phone for your home Wi-Fi enterprise login and you simply append those 6 digit numbers to the end of your password. Make sure to turn off your Wi-Fi password saving as well.
Source code can be found here: [GIT Repo]
vim /etc/freeradius/sites-{available,enabled}/{default,inner-tunnel}
... authorize { ... update control { Auth-Type := `/usr/bin/python /opt/freeradius/freeauth.py 86400 %{User-Name} %{User-Password}` } ... } ...
vim /opt/freeradius/freeauth.py – needs correct freeradius permissions
#!/usr/bin/python import crypt import hashlib import hmac import os import random import re import smtplib import sqlite3 import string import sys import time def sqloexec(sqloobjc, sqlocomd): try: sqloobjc.execute(sqlocomd) except: pass def cleanstr(inputstr): outpstri = "" charlist = (string.digits + string.uppercase + string.lowercase) for inputchr in inputstr: if (inputchr in charlist): outpstri += inputchr return outpstri def pbkdfsha(s, p): i = 1; l = ((256 / 8) * 2); d = "" while (len(d) < l): c = 0; rounds = 4096; f = "" lasthmac = (s + chr((i >> 24) & 0xff) + chr((i >> 16) & 0xff) + chr((i >> 8) & 0xff) + chr((i >> 0) & 0xff)) while (c < rounds): u = hmac.new(p, lasthmac, hashlib.sha1).digest() lasthmac = u t = "" for x in range(0, len(u)): if (x >= len(f)): f += chr(0) t += chr(ord(f[x]) ^ ord(u[x])) f = t c += 1 for j in f: q = "" if (ord(j) < 0x10): q = "0" if (len(d) < l): h = hex(ord(j)) d += (q + h[2:]) i += 1 return d denystri = "Reject" authstri = "Accept" mailuser = "" mailpass = "" expstime = int(sys.argv[1]) username = cleanstr(sys.argv[2]) userpass = sys.argv[3] usercode = "" regxobjc = re.match("^(.*[^0-9])([0-9]+)$", userpass) if (regxobjc): userpass = str(regxobjc.group(1)) usercode = str(regxobjc.group(2)) usermail = [""] mailcode = "" sqloconn = sqlite3.connect("/opt/freeradius/freeauth.db") sqlocurs = sqloconn.cursor() sqloexec(sqlocurs, "CREATE TABLE server (user TEXT, pass TEXT);") sqloexec(sqlocurs, "CREATE TABLE login (user TEXT, pass TEXT, mail TEXT);") sqloexec(sqlocurs, "CREATE TABLE token (loginuser TEXT, code TEXT, time INTEGER, exps INTEGER);") for sqlorowo in sqlocurs.execute("SELECT * FROM server;"): mailuser = str(sqlorowo[0]) mailpass = str(sqlorowo[1]) authflag = 0 for sqlorowo in sqlocurs.execute("SELECT * FROM login WHERE user = '" + username + "';"): sqlohash = str(sqlorowo[1]) sqlomail = str(sqlorowo[2]) sqloinfo = sqlohash.split("$") if (sqloinfo[2] == pbkdfsha(sqloinfo[1], userpass)): authflag = 1 usermail[0] = sqlomail if (authflag != 1): sqloconn.commit() sqloconn.close() sys.stdout.write(denystri);sys.exit(1) prestime = int(time.time()) sqlocurs.execute("DELETE FROM token WHERE loginuser = '" + username + "' AND (" + str(prestime) + " - time) >= exps;") authflag = 0 timelist = [] for sqlorowo in sqlocurs.execute("SELECT * FROM token WHERE loginuser = '" + username + "';"): sqlocode = str(sqlorowo[1]) sqlotime = int(sqlorowo[2]) if (sqlocode == usercode): authflag = 1 timelist.append(sqlotime) timelist.sort() if (authflag == 1): sqloconn.commit() sqloconn.close() sys.stdout.write(authstri);sys.exit(0) sendcode = 0 if (len(timelist) >= 1): if ((prestime - timelist[-1]) >= 60): sendcode = 1 else: sendcode = 1 if (sendcode == 1): for x in range(0, 6): mailcode += str(random.randint(0, 9)) sqlocurs.execute("INSERT INTO token VALUES ('" + username + "', '" + mailcode + "', " + str(prestime) + ", " + str(expstime) + ");") if ((mailuser != "") and (mailpass != "") and (usermail[0] != "") and (mailcode != "")): mailmesg = "\r\n".join([ "From: " + mailuser, "To: " + usermail[0], "Subject: Code = " + mailcode, "", "OTP Auth Delivery" ]) server = smtplib.SMTP("smtp.gmail.com:587") server.ehlo() server.starttls() server.login(mailuser, mailpass) server.sendmail(mailuser, usermail, mailmesg) server.quit() sqloconn.commit() sqloconn.close() sys.stdout.write(denystri);sys.exit(1)
…and!… a SSH PAM OTP too:
/* gcc -fPIC -DPIC -shared -rdynamic -o sshdauth.so sshdauth.c cp -fv sshdauth.so /lib/`uname -m`-linux-gnu/security/ vim /etc/pam.d/sshd auth required sshdauth.so vim /etc/ssh/sshd_config UsePAM yes UsePrivilegeSeparation no PasswordAuthentication yes ChallengeResponseAuthentication yes */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <strings.h> #include <unistd.h> #include <security/pam_appl.h> #include <security/pam_modules.h> int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char *argv[]) { return PAM_SUCCESS; } int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { int pame = 0; const char *umsg = "Username: ", *pmsg = "Password: ", *cmsg = "Passcode: "; const char *user = NULL, *pass = NULL, *code = NULL; struct pam_conv *conv; struct pam_message mesg; struct pam_response *resp; const struct pam_message *msgp; int link[2]; char data[96], auth[2048]; pid_t pidn; /* pam setup */ pame = pam_get_user(pamh, &user, NULL); if ((pame != PAM_SUCCESS) || (user == NULL)) { return PAM_AUTH_ERR; } pame = pam_get_authtok(pamh, PAM_AUTHTOK, (const char **)&pass, NULL); if (pame != PAM_SUCCESS) { return PAM_AUTH_ERR; } if (fork() == 0) { execl("/usr/bin/python", "python", "/opt/freeradius/freeauth.py", "120", user, pass, NULL); exit(0); } wait(NULL); pame = pam_get_item(pamh, PAM_CONV, (const void **)&conv); if (pame != PAM_SUCCESS) { return PAM_AUTH_ERR; } //mesg.msg_style = PAM_PROMPT_ECHO_OFF; mesg.msg_style = PAM_PROMPT_ECHO_ON; mesg.msg = cmsg; msgp = &mesg; resp = NULL; pame = (*conv->conv)(1, &msgp, &resp, conv->appdata_ptr); if ((pame != PAM_SUCCESS) || (resp == NULL)) { return PAM_AUTH_ERR; } code = resp->resp; /* auth check */ if (pipe(link) == -1) { return PAM_AUTH_ERR; } pidn = fork(); if (pidn == -1) { return PAM_AUTH_ERR; } if (pidn == 0) { dup2(link[1], STDOUT_FILENO); close(link[0]); bzero(auth, 2046 * sizeof(char)); strncpy(auth, pass, 256); strncpy(auth + strlen(auth), code, 256); execl("/usr/bin/python", "python", "/opt/freeradius/freeauth.py", "120", user, auth, NULL); exit(0); } close(link[1]); bzero(data, 94 * sizeof(char)); read(link[0], data, 92 * sizeof(char)); wait(NULL); if (strcmp(data, "Accept") == 0) { return PAM_SUCCESS; } return PAM_AUTH_ERR; }
[…] RADIUS/SSH OTP […]