跳转至

Session Management Challenge Two(会话管理 2)

题介绍

需要输入管理员的账号和密码才能获得通关密钥

功能实现

输入系统默认的账号和密码(admin/password)发现无法登陆 ,请求数据包

POST /challenges/d779e34a54172cbc245300d3bc22937090ebd3769466a501a5e7ac605b9f34b7 HTTP/1.1


subName=admin&subPassword=password 
查看后台代码 在 src/main/java/servlets/module/challenge/SessionManagement2.java 中
详细代码如下:
Object nameObj = request.getParameter("subName");
Object passObj = request.getParameter("subPassword");
String subName = new String();
String subPass = new String();
String userAddress = new String();
if(nameObj != null)
    subName = (String) nameObj;
if(passObj != null)
    subPass = (String) passObj;
log.debug("subName = " + subName);
log.debug("subPass = " + subPass);

log.debug("Getting ApplicationRoot");
String ApplicationRoot = getServletContext().getRealPath("");
log.debug("Servlet root = " + ApplicationRoot );

Connection conn = Database.getChallengeConnection(ApplicationRoot, "BrokenAuthAndSessMangChalTwo");
log.debug("Checking credentials");
PreparedStatement callstmt;

log.debug("Committing changes made to database");
callstmt = conn.prepareStatement("COMMIT");
callstmt.execute();
log.debug("Changes committed.");

callstmt = conn.prepareStatement("SELECT userName, userAddress FROM users WHERE userName = ? AND userPassword = SHA(?)");
callstmt.setString(1, subName);
callstmt.setString(2, subPass);
log.debug("Executing authUser");
发现进行了预编译SQL查询,杜绝了SQL注入问题 ,同时连接的BrokenAuthAndSessMangChalTwo数据库,所以这个点没有账号和密码无法验证通过

继续查看代码

ResultSet resultSet = callstmt.executeQuery();
if(resultSet.next())
{
    log.debug("Successful Login");
    // Get key and add it to the output
    String userKey = Hash.generateUserSolution(Getter.getModuleResultFromHash(ApplicationRoot, levelHash), (String)ses.getAttribute("userName"));
    htmlOutput = "<h2 class='title'>" + bundle.getString("response.welcome") + " " + Encode.forHtml(resultSet.getString(1)) + "</h2>" +
            "<p>" +
            bundle.getString("response.resultKey") + " <a>" + userKey + "</a>" +
            "</p>";
}
else
{   //查询失败后,通过用户名查询用户的邮箱地址 
    log.debug("Incorrect credentials, checking if user name correct");
    callstmt = conn.prepareStatement("SELECT userAddress FROM users WHERE userName = ?");
    callstmt.setString(1, subName);
    log.debug("Executing getAddress");
    resultSet = callstmt.executeQuery();
    if(resultSet.next())  //找到邮箱 则返回到前端 
    {
        log.debug("User Found");
        userAddress = bundle.getString("response.badPass") + " <a>" + Encode.forHtml(resultSet.getString(1)) + "</a><br/>";
    }
    else
    {
        userAddress = bundle.getString("response.badUser") + "<br/>";
    }
    htmlOutput = makeTable(userAddress, bundle);
}
Database.closeConnection(conn);

如果用户名存在,则会返回对应邮箱地址到前端展示

同时前端还有个功能,可以通过邮箱找回用户的密码

请求地址

POST /challenges/f5ddc0ed2d30e597ebacf5fdd117083674b19bb92ffc3499121b9e6a12c92959 HTTP/1.1

subEmail=zoidberg22%40shepherd.com
对应功能 功能在 src/main/java/servlets/module/challenge/SessionManagement2ChangePassword.java 中

Object emailObj = request.getParameter("subEmail");
String subEmail = new String();
if(emailObj != null)
    subEmail = (String) emailObj;
log.debug("subEmail = " + subEmail);

log.debug("Getting ApplicationRoot");
String ApplicationRoot = getServletContext().getRealPath("");

String newPassword = Hash.randomString(); //随机生成新密码
try
{
    Connection conn = Database.getChallengeConnection(ApplicationRoot, "BrokenAuthAndSessMangChalTwo");
    log.debug("Checking credentials");
    PreparedStatement callstmt = conn.prepareStatement("UPDATE users SET userPassword = SHA(?) WHERE userAddress = ?"); //根据邮箱重置密码 
    callstmt.setString(1, newPassword);
    callstmt.setString(2, subEmail);
    log.debug("Executing resetPassword");
    callstmt.execute();
    log.debug("Statement executed");

    log.debug("Committing changes made to database");
    callstmt = conn.prepareStatement("COMMIT");
    callstmt.execute();
    log.debug("Changes committed.");

    htmlOutput = Encode.forHtml(newPassword); //编码新密码
    Database.closeConnection(conn);
}
catch(SQLException e)
{
    log.error(levelName + " SQL Error: " + e.toString());
}
log.debug("Outputting HTML");
out.write(bundle.getString("response.changedTo") + " " + htmlOutput); //输出密码到客户端 
使用预编译根据邮箱地址重置用户密码,并且将新生成的密码返回到客户端进行展示

解题步骤

  • 输入错误的密码,可以获得用户的注册邮箱
  • 通过使用邮箱找回密码功能,获得最新生成的新密码
  • 使用新密码登录,即可获得通关密钥

总结

返回到客户端的内容一定要严格进行校验,防止将敏感信息返回到客户端

Back to top