order by 子查询_SQLMAP检测逻辑分析-联合查询注入

前言

联合查询注入两个前提

  1. 存在数据显示位
  2. union左右列数相同

联合查询注入分三步

  1. order by/union select 猜解列数
  2. union select 寻找显示位
  3. 注入数据库查询攻击

联合查询注入

order by猜解列数

sqlmap采用二分法猜解列数.

  1. 10为区间进行判断.设置highCols = 10
  2. 构造ORDER BY highCols,若与正常页面"不相似",进行以下操作,反之继续判断直到判断出不相似状态,若一直找不到(highCols>ORDER_BY_MAX),终止判断.
  3. 在该区间内取中间值mid = highCols - (highCols - lowCols) // 2 (//为整数除法,舍去小数)
  4. 构造ORDER BY mid,发送请求,若与正常页面相似,则说明返回的页面是正常的,即列数是>=mid,这时令lowCols = mid,否则令highCols = mid
  5. 进行以上循环,直到(highCols - lowCols) < 2,则确定lowCols为为列数。否则继续判断增加区间判断.

5e6550cf32cd5f39456030b0d8268a64.png

贴上源码便于理解.

6abaca2bccc08c51bc6d6fc1fdd44f32.png

上面还有一个问题就是相似的页面,sqlmap从以下几个维度来进行判断的.

  1. 正则搜索(warning|error):, order (by|clause), unknown column, failed 在植入payload的请求中,不在正常请求中并且非heavilyDynamic(后续介绍)和相似度一致(后续介绍),满足以上条件返回true.
  2. 正则搜索data types cannot be compared or sorted不在 植入payload的请求中,返回true.

同样贴出源码

return not any(re.search(_, page or "", re.I) and not re.search(_, kb.pageTemplate or "", re.I) for _ in ("(warning|error):", "order (by|clause)", "unknown column", "failed")) and not kb.heavilyDynamic and comparison(page, headers, code) or re.search(r"data types cannot be compared or sorted", page or "", re.I) is not None

Union猜解列数

总结来说,构造union all select NULL, 每次增加NULL,判断返回页面,来确定列数.SQLmap会发送多个这种请求,记录该页面与原始页面的相似度,存入items的集合中.并寻找最大的相似度和最小的相似度.

接下来sqlmap通过两种方式对以上数据进行分析.从源码一步一步了解具体实现方式:

  if not retVal:
  #取出minItem,maxItem
      for item in items:
          if item[1] == min_:
              minItem = item
          elif item[1] == max_:
              maxItem = item
  #从`radios`去除最小值。
      if min_ in ratios:
          ratios.pop(ratios.index(min_))
  #从`radios`去除最大值。
      if max_ in ratios:
          ratios.pop(ratios.index(max_))
      # ratios所有元素都等于min_,且都不等于max_,判定列数为maxItem中count
      if all(_ == min_ and _ != max_ for _ in ratios):
          retVal = maxItem[0]
#ratios所有元素都等于max_,且都不等于min_,判定列数为minItem中count
      elif all(_ != min_ and _ == max_ for _ in ratios):
          retVal = minItem[0]
  1. 去除最大的radio和最小的radio
  2. 如果剩余的页面都完全相同,且与最小或最大的radio其中一个相同,不与另一个相同.all(x):如果all(x)参数x对象的所有元素不为0、’’、False或者x为空对象,则返回True,否则返回False).

若上述未检测处理,则使用第二种方式(因为上述if处理方式一样,故归为一类)

elif abs(max_ - min_) >= MIN_STATISTICAL_RANGE:
# 通过stdev计算标准差
    deviation = stdev(ratios)

    if deviation is not None:
# 计算标准差区间[平均值-7*标准差,平均值+7*标准差]
        lower, upper = average(ratios) - UNION_STDEV_COEFF * deviation, average(ratios) + UNION_STDEV_COEFF * deviation

        if min_ < lower:
            retVal = minItem[0]

        if max_ > upper:
            if retVal is None or abs(max_ - upper) > abs(min_ - lower):
                retVal = maxItem[0]

首先了解下标准差的概念.

简单来说,标准差是一组数值自平均值分散开来的程度的一种测量观念。一个较大的标准差,代表大部分的数值和其平均值之间差异较大;一个较小的标准差,代表这些数值较接近平均值。例如,两组数的集合{0, 5, 9, 14}和{5, 6, 8, 9}其平均值都是7,但第二个集合具有较小的标准差。述“相差k个标准差”,即在 X̄ ± kS 的样本(Sample)范围内考量。标准差可以当作不确定性的一种测量。例如在物理科学中,做重复性测量时,测量数值集合的标准差代表这些测量的精确度。当要决定测量值是否符合预测值,测量值的标准差占有决定性重要角色:如果测量平均值与预测值相差太远(同时与标准差数值做比较),则认为测量值与预测值互相矛盾。这很容易理解,因为如果测量值都落在一定数值范围之外,可以合理推论预测值是否正确。

以下是一个正态分布图,上述计算的正常页面的相似度看作一个正太分布.

af888ee0af5731085ac5f2af750e68dc.png

可以看到大部分的随机数据集中在中间。x轴为标准差.可以计算出来约有99.99%的数值落在7个标准差之间.换句话说,sqlmap保证正常的请求99.99%的概率落在这上面.超出该区间的99.99%不是正常请求.依此判断列数.

寻找输入点

为了方便分析,假定确认的列数为3.大概的思路是构造payloadUNION SELECT NULL, NULL, NULL,依此将其中 NULL替换为随机字符串,从结果寻找随机字符串.

我在测试的时候也发现了一个坑,漏洞代码如下:

sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";
	$result=mysql_query($sql);
	$row = mysql_fetch_array($result);
	if($row)
	{
	  	echo "<font size='5' color= '#99FF00'>";	
	  	echo 'Your Login name:'. $row['username'];
	  	echo "<br>";
	  	echo 'Your Password:' .$row['password'];
	  	echo "</font>";
  	}

返回数据限制成一行,如果按照上述思路,就会产生问题,不会回显第二个查询的数据.sqlmap针对这种将第一个查询设置为false,来保证第二个查询可以查询到数据.

85d479dbf7e86379ff16c09578e4d5dc.png

总结

以上是关于自动化union检测的思路,能力有限可能存在错误.仅供参考.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值