Skip to content

Commit e31d35d

Browse files
committed
Updated algorithm for blank password detection
1 parent a5f20c2 commit e31d35d

File tree

5 files changed

+74
-30
lines changed

5 files changed

+74
-30
lines changed

config/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
)
1010

1111
const (
12-
ReleemAgentVersion = "1.21.1"
12+
ReleemAgentVersion = "1.21.2"
1313
)
1414

1515
type Config struct {

current_version_agent

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.21.1
1+
1.21.2

install.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env bash
2-
# install.sh - Version 1.21.1
2+
# install.sh - Version 1.21.2
33
# (C) Releem, Inc 2022
44
# All rights reserved
55

@@ -9,7 +9,7 @@ export PATH=$PATH:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/
99
# using the package manager.
1010

1111
set -e -E
12-
install_script_version=1.21.1
12+
install_script_version=1.21.2
1313
logfile="/var/log/releem-install.log"
1414

1515
WORKDIR="/opt/releem"

metrics/dbInfo.go

Lines changed: 68 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package metrics
22

33
import (
4+
"strings"
5+
46
"github.com/Releem/mysqlconfigurer/config"
57
"github.com/Releem/mysqlconfigurer/models"
68
"github.com/Releem/mysqlconfigurer/utils"
@@ -51,59 +53,101 @@ func security_recommendations(DbInfo *DbInfoGatherer) []models.MetricGroupValue
5153
var output_users []models.MetricGroupValue
5254

5355
var password_column_exists, authstring_column_exists int
54-
err := models.DB.QueryRow("SELECT 1 FROM information_schema.columns WHERE TABLE_SCHEMA = 'mysql' AND TABLE_NAME = 'user' AND COLUMN_NAME = 'password'").Scan(&password_column_exists)
55-
if err != nil {
56-
DbInfo.logger.Error(err)
57-
}
58-
err = models.DB.QueryRow("SELECT 1 FROM information_schema.columns WHERE TABLE_SCHEMA = 'mysql' AND TABLE_NAME = 'user' AND COLUMN_NAME = 'authentication_string'").Scan(&authstring_column_exists)
59-
if err != nil {
60-
DbInfo.logger.Error(err)
61-
}
62-
// DbInfo.logger.Info(password_column_exists, authstring_column_exists)
56+
57+
// New table schema available since mysql-5.7 and mariadb-10.2
58+
// But need to be checked
59+
models.DB.QueryRow("SELECT 1 FROM information_schema.columns WHERE TABLE_SCHEMA = 'mysql' AND TABLE_NAME = 'user' AND COLUMN_NAME = 'password'").Scan(&password_column_exists)
60+
models.DB.QueryRow("SELECT 1 FROM information_schema.columns WHERE TABLE_SCHEMA = 'mysql' AND TABLE_NAME = 'user' AND COLUMN_NAME = 'authentication_string'").Scan(&authstring_column_exists)
6361
PASS_COLUMN_NAME := "password"
6462
if password_column_exists == 1 && authstring_column_exists == 1 {
6563
PASS_COLUMN_NAME = "IF(plugin='mysql_native_password', authentication_string, password)"
6664
} else if authstring_column_exists == 1 {
6765
PASS_COLUMN_NAME = "authentication_string"
6866
} else if password_column_exists != 1 {
67+
DbInfo.logger.Info("Skipped due to none of known auth columns exists")
6968
return output_users
7069
}
71-
DbInfo.logger.Info(PASS_COLUMN_NAME)
70+
DbInfo.logger.Info("Password column = ", PASS_COLUMN_NAME)
7271

73-
var Username, User, Host, Blank_Password, Password_As_User string
74-
rows_users, err := models.DB.Query("SELECT CONCAT(QUOTE(user), '\\@', QUOTE(host)), user, host, (" + PASS_COLUMN_NAME + " = '' OR " + PASS_COLUMN_NAME + " IS NULL) as Blank_Password, (CAST(" + PASS_COLUMN_NAME + " as Binary) = PASSWORD(user) OR CAST(" + PASS_COLUMN_NAME + " as Binary) = PASSWORD(UPPER(user)) ) as Password_As_User FROM mysql.user")
75-
if err != nil || rows_users.Next() == false {
76-
DbInfo.logger.Error(err)
77-
rows_users, err = models.DB.Query("SELECT CONCAT(QUOTE(user), '\\@', QUOTE(host)), user, host, (" + PASS_COLUMN_NAME + " = '' OR " + PASS_COLUMN_NAME + " IS NULL) as Blank_Password, (CAST(" + PASS_COLUMN_NAME + " as Binary) = CONCAT('*',UPPER(SHA1(UNHEX(SHA1(user))))) OR CAST(" + PASS_COLUMN_NAME + " as Binary) = CONCAT('*',UPPER(SHA1(UNHEX(SHA1(UPPER(user)))))) ) as Password_As_User FROM mysql.user")
72+
var Username, User, Host, Password_As_User string
73+
rows_users, err := models.DB.Query("SELECT CONCAT(QUOTE(user), '@', QUOTE(host)), user, host, (CAST(" + PASS_COLUMN_NAME + " as Binary) = PASSWORD(user) OR CAST(" + PASS_COLUMN_NAME + " as Binary) = PASSWORD(UPPER(user)) ) as Password_As_User FROM mysql.user")
74+
if err != nil || !rows_users.Next() {
75+
if strings.Contains(err.Error(), "Error 1064 (42000): You have an error in your SQL syntax") {
76+
DbInfo.logger.Info("PASSWORD() function is not supported. Try another query...")
77+
} else {
78+
DbInfo.logger.Error(err)
79+
}
80+
rows_users, err = models.DB.Query("SELECT CONCAT(QUOTE(user), '@', QUOTE(host)), user, host, (CAST(" + PASS_COLUMN_NAME + " as Binary) = CONCAT('*',UPPER(SHA1(UNHEX(SHA1(user))))) OR CAST(" + PASS_COLUMN_NAME + " as Binary) = CONCAT('*',UPPER(SHA1(UNHEX(SHA1(UPPER(user)))))) ) as Password_As_User FROM mysql.user")
7881
if err != nil {
7982
DbInfo.logger.Error(err)
80-
return output_users
8183
}
8284
defer rows_users.Close()
8385
for rows_users.Next() {
84-
err := rows_users.Scan(&Username, &User, &Host, &Blank_Password, &Password_As_User)
86+
err := rows_users.Scan(&Username, &User, &Host, &Password_As_User)
8587
if err != nil {
8688
DbInfo.logger.Error(err)
87-
continue
89+
} else {
90+
output_users = append(output_users, models.MetricGroupValue{"Username": Username, "User": User, "Host": Host, "Password_As_User": Password_As_User})
8891
}
89-
output_users = append(output_users, models.MetricGroupValue{"Username": Username, "User": User, "Host": Host, "Blank_Password": Blank_Password, "Password_As_User": Password_As_User})
9092
}
9193
} else {
9294
defer rows_users.Close()
93-
err := rows_users.Scan(&Username, &User, &Host, &Blank_Password, &Password_As_User)
95+
err := rows_users.Scan(&Username, &User, &Host, &Password_As_User)
9496
if err != nil {
9597
DbInfo.logger.Error(err)
9698
} else {
97-
output_users = append(output_users, models.MetricGroupValue{"Username": Username, "User": User, "Host": Host, "Blank_Password": Blank_Password, "Password_As_User": Password_As_User})
99+
output_users = append(output_users, models.MetricGroupValue{"Username": Username, "User": User, "Host": Host, "Password_As_User": Password_As_User})
98100
}
99101
for rows_users.Next() {
100-
err := rows_users.Scan(&Username, &User, &Host, &Blank_Password, &Password_As_User)
102+
err := rows_users.Scan(&Username, &User, &Host, &Password_As_User)
101103
if err != nil {
102104
DbInfo.logger.Error(err)
103-
continue
105+
} else {
106+
output_users = append(output_users, models.MetricGroupValue{"Username": Username, "User": User, "Host": Host, "Password_As_User": Password_As_User})
104107
}
105-
output_users = append(output_users, models.MetricGroupValue{"Username": Username, "User": User, "Host": Host, "Blank_Password": Blank_Password, "Password_As_User": Password_As_User})
106108
}
107109
}
110+
111+
output_user_blank_password := make(models.MetricGroupValue)
112+
rows_users, err = models.DB.Query("SELECT CONCAT(QUOTE(user), '@', QUOTE(host)) FROM mysql.global_priv WHERE ( user != '' AND JSON_CONTAINS(Priv, '\"mysql_native_password\"', '$.plugin') AND JSON_CONTAINS(Priv, '\"\"', '$.authentication_string') AND NOT JSON_CONTAINS(Priv, 'true', '$.account_locked'))")
113+
if err != nil {
114+
if strings.Contains(err.Error(), "Error 1146 (42S02): Table 'mysql.global_priv' doesn't exist") {
115+
DbInfo.logger.Info("Not MariaDB, try another query...")
116+
} else {
117+
DbInfo.logger.Error(err)
118+
}
119+
rows_users, err = models.DB.Query("SELECT CONCAT(QUOTE(user), '@', QUOTE(host)) FROM mysql.user WHERE (" + PASS_COLUMN_NAME + " = '' OR " + PASS_COLUMN_NAME + " IS NULL) AND user != '' /*!50501 AND plugin NOT IN ('auth_socket', 'unix_socket', 'win_socket', 'auth_pam_compat') */ /*!80000 AND account_locked = 'N' AND password_expired = 'N' */")
120+
if err != nil {
121+
DbInfo.logger.Error(err)
122+
}
123+
defer rows_users.Close()
124+
for rows_users.Next() {
125+
err := rows_users.Scan(&Username)
126+
if err != nil {
127+
DbInfo.logger.Error(err)
128+
} else {
129+
output_user_blank_password[Username] = 1
130+
}
131+
}
132+
} else {
133+
defer rows_users.Close()
134+
for rows_users.Next() {
135+
err := rows_users.Scan(&Username)
136+
if err != nil {
137+
DbInfo.logger.Error(err)
138+
} else {
139+
output_user_blank_password[Username] = 1
140+
}
141+
}
142+
}
143+
144+
for i, user := range output_users {
145+
if _, ok := output_user_blank_password[user["Username"].(string)]; ok {
146+
output_users[i]["Blank_Password"] = 1
147+
} else {
148+
output_users[i]["Blank_Password"] = 0
149+
}
150+
}
151+
108152
return output_users
109153
}

mysqlconfigurer.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env bash
2-
# mysqlconfigurer.sh - Version 1.21.1
2+
# mysqlconfigurer.sh - Version 1.21.2
33
# (C) Releem, Inc 2022
44
# All rights reserved
55

@@ -15,7 +15,7 @@ MYSQLTUNER_REPORT=$MYSQLCONFIGURER_PATH"mysqltunerreport.json"
1515
RELEEM_MYSQL_VERSION=$MYSQLCONFIGURER_PATH"mysql_version"
1616
MYSQLCONFIGURER_CONFIGFILE="${MYSQLCONFIGURER_PATH}${MYSQLCONFIGURER_FILE_NAME}"
1717
MYSQL_MEMORY_LIMIT=0
18-
VERSION="1.21.1"
18+
VERSION="1.21.2"
1919
RELEEM_INSTALL_PATH=$MYSQLCONFIGURER_PATH"install.sh"
2020
logfile="/var/log/releem-mysqlconfigurer.log"
2121

0 commit comments

Comments
 (0)