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;
}
One thought on “FreeRadius + PyOTP = My Home Wi-Fi With WPA-EAP-TTLS User/Pass/OTP Auth”