漏洞成因
在crushftp.server.ServerSessionHTTP.handle_http_requests
方法中对用户名有特殊处理。
当用户名中不包含~
的时候 lookup_user_pass
的值为true
1 2 3 4 5 6
| boolean lookup_user_pass = true; if (s3_username.indexOf("~") >= 0) { user_pass = s3_username.substring(s3_username.indexOf("~") + 1); user_name = s3_username.substring(0, s3_username.indexOf("~")); lookup_user_pass = false; }
|
后面在调用 login_user_pass
方法的时候传入的第一个参数就是lookup_user_pass
1
| this.thisSession.login_user_pass(lookup_user_pass, false, user_name, user_pass))
|
login_user_pass
方法最终会调用到crushftp.handlers.UserTools.verify_user(crushftp.server.ServerStatus, java.lang.String, java.lang.String, java.lang.String, crushftp.handlers.SessionCrush, int, java.lang.String, int, java.util.Properties, java.util.Properties, boolean)
方法
当anyPass
为true
的时候只比较了用户名是否相等就直接返回了user
对象没有对密码进行验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public Properties verify_user(ServerStatus server_status_frame, String the_user, String the_password, String serverGroup, SessionCrush thisSession, int user_number, String user_ip, int user_port, Properties server_item, Properties loginReason, boolean anyPass) { if (the_user.indexOf("\\") >= 0) { the_user = the_user.substring(the_user.indexOf("\\") + 1); }
if (!the_password.startsWith("SHA:") && !the_password.startsWith("SHA512:") && !the_password.startsWith("SHA256:") && !the_password.startsWith("SHA3:") && !the_password.startsWith("MD5:") && !the_password.startsWith("MD5S2:") && !the_password.startsWith("CRYPT3:") && !the_password.startsWith("BCRYPT:") && !the_password.startsWith("MD5CRYPT:") && !the_password.startsWith("PBKDF2SHA256:") && !the_password.startsWith("SHA512CRYPT:") && !the_password.startsWith("ARGOND:")) { String the_password2 = Common.url_decode(the_password); if (!the_password2.startsWith("SHA:") && !the_password2.startsWith("SHA512:") && !the_password2.startsWith("SHA256:") && !the_password2.startsWith("SHA3:") && !the_password2.startsWith("MD5:") && !the_password2.startsWith("MD5S2:") && !the_password2.startsWith("CRYPT3:") && !the_password2.startsWith("BCRYPT:") && !the_password2.startsWith("MD5CRYPT:") && !the_password2.startsWith("PBKDF2SHA256:") && !the_password2.startsWith("SHA512CRYPT:") && !the_password2.startsWith("ARGOND:")) { Properties user = null; Log.log("USER_OBJ", 2, "Validating user " + the_user + " with password " + (the_password != null && !the_password.equals("")) + " "); if (!ServerStatus.BG("blank_passwords") && the_password.trim().equals("") && !anyPass && !the_user.equalsIgnoreCase("ANONYMOUS")) { return null; } else { try { user = ut.getUser(serverGroup, the_user, true); } catch (Exception var23) { Log.log("USER_OBJ", 2, var23); }
Log.log("USER_OBJ", 1, "Validating user " + the_user + " with local user file:" + (user != null ? String.valueOf(user.size()) : "no user.XML found!")); if (user != null) { loginReason.put("reason", "valid user"); ServerStatus var10000 = ServerStatus.thisObj; if (ServerStatus.BG("secondary_login_via_email") && the_user.indexOf("@") >= 0 && user.getProperty("username").indexOf("@") < 0) { the_user = user.getProperty("username"); }
if (anyPass && user.getProperty("username").equalsIgnoreCase(the_user)) { return user; }
|
修复方案
修改了this.thisSession.login_user_pass(false, false, user_name, user_pass))
的调用逻辑,传入的第一个参数被固定设置为false