跳转至

Session Management Challenge Five(会话管理 5)

题介绍

需要输入账号和密码进行登录

功能实现

请求数据包

POST /challenges/7aed58f3a00087d56c844ed9474c671f8999680556c127a19ee79fa5d7a132e1 HTTP/1.1


subUserName=test&subUserPassword=password

对应代码实现

Object nameObj = request.getParameter("subUserName");
Object passObj = request.getParameter("subUserPassword");
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, "BrokenAuthAndSessMangChalFive");
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, userRole FROM users WHERE userName = ?");  //参数化查询 是否存在用户 
callstmt.setString(1, subName);
log.debug("Executing findUser");
ResultSet resultSet = callstmt.executeQuery();
//Is the username valid?
if(resultSet.next())
{
    log.debug("User found");
    //Is the user an Admin?
    if(resultSet.getString(2).equalsIgnoreCase("admin"))  //判断用户是否是管理员 
    {
        log.debug("Admin Detected");
        callstmt = conn.prepareStatement("SELECT userName, userRole FROM users WHERE userName = ? AND userPassword = SHA(?)"); //判断用户名和密码是否正确 
        callstmt.setString(1, subName);
        callstmt.setString(2, subPass);

发现没有SQL注入问题

找回密码功能代码

POST /challenges/7aed58f3a00087d56c844ed9474c671f8999680556c127a19ee79fa5d7a132e1SendToken HTTP/1.1


subUserName=admin
对应实现
Object nameObj = request.getParameter("subUserName");
String userName = new String();
if(nameObj != null)
    userName = (String) nameObj;
log.debug("subName = " + userName);

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

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

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

callstmt = conn.prepareStatement("SELECT userName FROM users WHERE userName = ?"); //参数化查询
callstmt.setString(1, userName);
log.debug("Executing findUser");
ResultSet resultSet = callstmt.executeQuery();
//Is the username valid?
if(resultSet.next())
{
    log.debug("User found");  //可以判断用户名是否存在 
    htmlOutput = bundle.getString("setToken.sentTo.1") + " '" + Encode.forHtml(userName) + "' " +  bundle.getString("setToken.sentTo.2");
}
else

只能判断用户名是否存在

从页面html中可以找到重置用户名和密码的链接

POST /challenges/7aed58f3a00087d56c844ed9474c671f8999680556c127a19ee79fa5d7a132e1ChangePass HTTP/1.1


userName=admin&newPassword=password&resetPasswordToken=U3RhIFNlcCAxOCAwODoyODoxMCBCU1QgMjAyMQ==

前两个参数比较好理解,最后一个参数,黑盒是非常难想到的

Object tokenObj = request.getParameter("resetPasswordToken");
String userName = new String();
String newPass = new String();
String token = new String();
if(passNewObj != null)
    newPass = (String) passNewObj;
if(userNewObj != null)
    userName = (String) userNewObj;
if(tokenObj != null)
    token = (String) tokenObj;
log.debug("userName = " + userName);
log.debug("newPass = " + newPass);
log.debug("token = " + token);
String tokenTime = new String();
try
{
    byte[] decodedToken = Base64.decodeBase64(token);
    tokenTime = new String(decodedToken, "UTF-8");
}
catch (UnsupportedEncodingException e)
{
    log.debug("Could not decode password token");
    errorMessage += "<p>" + bundle.getString("changePass.noDecode") + "</p>";
}
if(tokenTime.isEmpty())
{
    log.debug("Could not decode token. Ending Servlet.");
    out.write(errorMessage);
}
else
{
    log.debug("Decoded Token = " + tokenTime);

    //Get Time from Token and see if it is inside the last 10 minutes
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("EEE MMM d HH:mm:ss Z yyyy"); //时间格式 必须是这种 
    try 
    {
        Date tokenDateTime = simpleDateFormat.parse(tokenTime);
        Date currentDateTime = new Date();
        //Get difference in minutes
        tokenLife = (int)((currentDateTime.getTime()/60000) - (tokenDateTime.getTime()/60000));
        log.debug("Token life = " + tokenLife);
    } 
    catch (ParseException e) 

解题步骤

需要知道服务器当前的 EEE MMM d HH🇲🇲ss Z yyyy ,然后base64编码
服务器的时间可能不是当前时间,所以执行 date命令 进行查看

总结

有些问题不进行代码审计是很难发现的,所以保护好自己的源代码是非常有必要的

Back to top