This site is the archived OWASP Foundation Wiki and is no longer accepting Account Requests.
To view the new OWASP Foundation website, please visit https://owasp.org

OWASP ModSecurity Securing WebGoat Section4 Sublesson 08.2 08.4 08.5 08.7

From OWASP
Revision as of 15:32, 24 July 2008 by Stephen Evans (talk | contribs) (Implementation)

Jump to: navigation, search

8. Cross-Site Scripting (XSS)

8.1 Phishing with XSS

8.2 LAB: Cross Site Scripting

  • Stage 1: Stored XSS
  • Stage 3: Stored XSS Revisited
  • Stage 5: Reflected XSS

8.4 Reflected XSS Attacks

8.5 Cross Site Request Forgery (CSRF)

8.7 Cross Site Tracing (XST) Attacks

Stages 2, 4, and 6 of the lab uses the developer version of WebGoat so that the source code can be modified to prevent the attacks in Stages 1, 3, and 5 respectively, but that's what we're doing here so these stages do not pertain to us.

Lesson overviews

See [relative paths].

Lesson solutions

See [relative paths].

Strategy

Probably due to the constraints of WebGoat, it is not feasible to fully illustrate sophisticated CSRF and XST attacks so they can be mitigated with the core ruleset rules from 'modsecurity_crs_40_generic_attacks.conf' for generic XSS attacks.

However, Stage 3 of the Lab proved challenging. The employee Bruce has malicious XSS code stored in his profile and it is triggered when David views it. The malicious code is contained in an address field that is displayed in the HTML body:

8899 FreeBSD Drive<script>alert(document.cookie)</script>


The strategy to mitigate this vulnerability is to use ModSecurity as an egress filter on the response body. It is observed that WebGoat only uses javascript in the Head section of HTML files and that Javascript is used only from *.js files such as:

<script language="JavaScript1.2" src="javascript/javascript.js" \ 
  type="text/javascript"></script>


Because we know this, we can consider any other javascript code as malicious and, for example, require any javascript to start with:

<script language="JavaScript1.2" src="javascript/

Implementation

The generic XSS attacks are mitigated from rules in the file 'rulefile_08_xss.conf':

  # False positives removed from following list: 'application'
  SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES|REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer \ 
    "@pm jscript onsubmit copyparentfolder javascript meta onmove onkeydown onchange \ 
    onkeyup activexobject expression onmouseup ecmascript onmouseover vbscript: \ 
    <![cdata[ http: settimeout onabort shell: .innerhtml onmousedown onkeypress \ 
    asfunction: onclick .fromcharcode background-image: .cookie ondragdrop onblur \ 
    x-javascript mocha: onfocus javascript: getparentfolder lowsrc onresize @import \ 
    alert onselect script onmouseout onmousemove background .execscript livescript: \ 
    getspecialfolder vbscript iframe .addimport onunload createtextrange onload <input" \
    "t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,deny,log,auditlog, \ 
    msg:'Cross-site Scripting (XSS) Attack - whole word matches',tag:'WEB_ATTACK/XSS', \ 
    logdata:'%{TX.0}',redirect:/_error_pages_/lesson08a.html,severity:'3'"

  # Enable the next line if want to change to 'pass' for detect-only mode
  # SecAction pass,nolog,skipAfter:959004

  SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES \ 
    "(?:\b(?:(?:type\b\W*?\b(?:text\b\W*?\b(?:j(?:ava)?|ecma|vb)| \ 
    application\b\W*?\bx-(?:java|vb))script|c(?:opyparentfolder|reatetextrange) \ 
    |get(?:special|parent)folder|iframe\b.{0,100}?\bsrc)\b| \ 
    on(?:(?:mo(?:use(?:o(?:ver|ut)|down|move|up)|ve)|key(?:press|down|up)| \ 
    c(?:hange|lick)|s(?:elec|ubmi)t|(?:un)?load|dragdrop|resize|focus|blur)\b\W* \ 
    ?=|abort\b)|(?:l(?:owsrc\b\W*?\b(?:(?:java|vb)script|shell|http)|ivescript)| \ 
    (?:href|url)\b\W*?\b(?:(?:java|vb)script|shell)|background-image|mocha) \ 
    :|s(?:(?:tyle\b\W*=.*\bexpression\b\W*|ettimeout\b\W*?)\(|rc\b\W*?\b \ 
    (?:(?:java|vb)script|shell|http):)|a(?:ctivexobject\b|lert\b\W*?\(|sfunction:))| \ 
    <(?:(?:body\b.*?\b(?:backgroun|onloa)d|input\b.*?\btype\b\W*?\bimage)\b| \ 
    ?(?:(?:script|meta)\b|iframe)|!\[cdata\[)|(?:\.(?:(?:execscrip|addimpor)t| \ 
    (?:fromcharcod|cooki)e|innerhtml)|\@import)\b)" \
    "capture,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,log,auditlog,deny, \ 
    msg:'Cross-site Scripting (XSS) Attack - script tags',tag:'WEB_ATTACK/XSS', \ 
    logdata:'%{TX.0}',redirect:/_error_pages_/lesson08b.html,severity:'3'"

  SecRule REQUEST_HEADERS|XML:/*|!REQUEST_HEADERS:Referer \ 
     "(?:\b(?:(?:type\b\W*?\b(?:text\b\W*?\b(?:j(?:ava)?|ecma|vb)| \ 
    application\b\W*?\bx-(?:java|vb))script|c(?:opyparentfolder|reatetextrange) \ 
    |get(?:special|parent)folder|iframe\b.{0,100}?\bsrc)\b| \ 
    on(?:(?:mo(?:use(?:o(?:ver|ut)|down|move|up)|ve)|key(?:press|down|up)| \ 
    c(?:hange|lick)|s(?:elec|ubmi)t|(?:un)?load|dragdrop|resize|focus|blur)\ 
    b\W*?=|abort\b)|(?:l(?:owsrc\b\W*?\b(?:(?:java|vb)script|shell|http)|ivescript)| \ 
    (?:href|url)\b\W*?\b(?:(?:java|vb)script|shell)|background-image|mocha):| \ 
    s(?:(?:tyle\b\W*=.*\bexpression\b\W*|ettimeout\b\W*?)\(|rc\b\W*?\b \ 
    (?:(?:java|vb)script|shell|http):)|a(?:ctivexobject\b|lert\b\W*?\(|sfunction:))| \ 
    <(?:(?:body\b.*?\b(?:backgroun|onloa)d|input\b.*?\btype\b\W*?\bimage)\b| \  
    ?(?:(?:script|meta)\b|iframe)|!\[cdata\[)|(?:\.(?:(?:execscrip|addimpor)t| \ 
    (?:fromcharcod|cooki)e|innerhtml)|\@import)\b)" \
    "capture,t:urlDecodeUni,t:htmlEntityDecode,t:compressWhiteSpace,t:lowercase,log, \ 
    auditlog,deny,msg:'Cross-site Scripting (XSS) Attack - in request headers or XML', \ 
    id:'959004',tag:'WEB_ATTACK/XSS',logdata:'%{TX.0}', \ 
    redirect:/_error_pages_/lesson08c.html,severity:'3'"


For stopping the malicious stored XSS script, this rule is used:

  SecRule TX:MENU "!@eq 900" "phase:4,t:none,pass,skip:1"

  # parse response body and write hidden values to file
  SecRuleScript "/etc/modsecurity/data/jscript_08.lua" "phase:4,t:none,log, \ 
    auditlog,deny,msg:'Lesson 8 XSS Lab Stage 3, found nonconformant javascript \ 
    tags using luascript',redirect:/_error_pages_/lesson08-3.html"


Since we are whitelisting the pattern that is accepting for using javascript, a Lua script is used. The source code is shown here in its entirety, replete with debug code for Level 9 debugging:

function main()  
  m.log(9, "Starting luascript file jscript_08.lua")
  print ("Executing luascript jscript_08.lua")

  local tbuff = m.getvar("RESPONSE_BODY", "none") 
  local str1
  
  for a in string.gmatch(tbuff, "<script.->") do
    str1 = string.format("\nLuascript: Trying to match: %s: ", a)
    m.log(9, str1)
  	
    if string.match(a, \ 
      "^<script%s+language=\"JavaScript1.2\"%s+src=\"javascript/") == nil then
      str1 = string.format("Luascript: from RESPONSE_BODY - \ 
        string not matching: %s; exiting", a)
      m.log(9, str1)
      return str1
    end
  end

  m.log(9, "Exiting luascript file jscript_08.lua")
  return nil
end


Note that Lua is implemented in ModSecurity so that returning a value of 'nil' means there is no match in the SecRuleScript; you can think of 'nil' as a "good" return code meaning that nothing bad has happened. Anything else returned will cause a match and invoke the actions in the SecRuleScript.