跳转至

Session Management Challenge Three(会话管理 3)

题介绍

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

功能实现

输入任意账号和密码,点击提交

POST /challenges/t193c6634f049bcf65cdcac72269eeac25dbb2a6887bdb38873e57d0ef447bc3 HTTP/1.1


subUserName=admin&subUserPassword=password
对应实现代码 /src/main/java/servlets/module/challenge/SessionManagement3.java

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, "BrokenAuthAndSessMangChalThree");  //连接  BrokenAuthAndSessMangChalThree 数据库
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, userRole FROM users WHERE userName = ?"); //查询用户名 判断用户角色是否是 admin 
callstmt.setString(1, subName);
log.debug("Executing findUser");
ResultSet resultSet = callstmt.executeQuery();
if(resultSet.next())
{
    log.debug("User found");
    if(resultSet.getString(3).equalsIgnoreCase("admin"))
    {
        log.debug("Admin Detected");
        callstmt = conn.prepareStatement("SELECT userName, userAddress, userRole FROM users WHERE userName = ? AND userPassword = SHA(?)");  //进而判断用户名和密码是否正确 
        callstmt.setString(1, subName);
        callstmt.setString(2, subPass);
        log.debug("Executing authUser");
        ResultSet resultSet2 = callstmt.executeQuery();
        if(resultSet2.next())
        {
            log.debug("Successful Admin Login");
            // Get key and add it to the output
从实现上来看,没有发现明显漏洞,数据库查询是预编译的

界面上还有个功能,是修改密码,猜测可能是这个地方有问题

POST /challenges/b467dbe3cd61babc0ec599fd0c67e359e6fe04e8cdc618d537808cbb693fee8a HTTP/1.1

Cookie: current=WjNWbGMzUXhNZz09; JSESSIONID=A2479A1D9F44509E20B35106989DFFAF; token=22792033228396859635296159069930202705

newPassword=test1%40qq.com
对应实现代码 src/main/java/servlets/module/challenge/SessionManagement3ChangePassword.java

Cookie userCookies[] = request.getCookies();
int i = 0;
Cookie theCookie = null;
for(i = 0; i < userCookies.length; i++)
{
    if(userCookies[i].getName().compareTo("current") == 0)  //获得cookie中的current字段值 
    {
        theCookie = userCookies[i];
        break; //End Loop, because we found the token
    }
}
Object passNewObj = request.getParameter("newPassword");
String subName = new String();
String subNewPass = new String();
if(theCookie != null)
    subName = theCookie.getValue();
if(passNewObj != null)
    subNewPass = (String) passNewObj;
log.debug("subName = " + subName);
//Base 64 Decode
try
{
    byte[] decodedName = Base64.decodeBase64(subName);  // current进行两次base64解码 
    subName = new String(decodedName, "UTF-8");
    decodedName = Base64.decodeBase64(subName);
    subName = new String(decodedName, "UTF-8");
}

if(subNewPass.length() >= 6)  //新密码长度 要大于等于6位
{
    log.debug("Getting ApplicationRoot");
    String ApplicationRoot = getServletContext().getRealPath("");

    Connection conn = Database.getChallengeConnection(ApplicationRoot, "BrokenAuthAndSessMangChalThree");
    log.debug("Changing password for user: " + subName);
    log.debug("Changing password to: " + subNewPass);
    PreparedStatement callstmt;

    callstmt = conn.prepareStatement("UPDATE users SET userPassword = SHA(?) WHERE userName = ?"); //更新用户名(来源cookie)和密码 
    callstmt.setString(1, subNewPass);
    callstmt.setString(2, subName);
    log.debug("Executing changePassword");
    callstmt.execute();

解题步骤

通过修改密码功能,修改cookie中的current值为admin

总结

永远不能信任客户端传递的数据,使用强加密替代base64编码等

Back to top