ImaginaryCTF 2024
Web
journal
题目给出了index.php的源码
1 | <?php |
assert可以执行代码。原本想着是吧strpos的括号闭合。然后进行代码执行。。。。
到后来才发现assert不能执行多条语句。
可以用or连接两个语句让assert执行

同时我也发现strpos的参数可以是一个函数

The Amazing Race
进入环境后会自动给我们分配一个uid来唯一的记录我们的游戏进度。游戏中@代表玩家所在的位置。.代表玩家可以走的位置。。。#表示墙玩家不能通过该位置。F表示游戏终点
在游戏右下角的F四周都被#包围。无法通过正常的方法到达

/source接口中有题目的源码

当我们首次访问/路由的时候会将我们重定向到/<mazeId>路由。然后我们没有<mazeId>会调用createMaze()函数创建一个maze同时生成一个mazeId并将该mazeId与生成的maze绑定
用solved变量来表示题目是否解出。当getLoc(mazeId) == (MAZE_SIZE-1, MAZE_SIZE-1)为true
即游戏角色到达maze右下角的时候


再来看看源码中给的其他函数方法
源码中initDb()创建了一个表。包含id,maze,row,col,up,down,left,right字段up,down,left,right字段的类型为bool类型

getLoc()函数充数据库中查询出我们当前的位置

getMaze()函数根据mazeId来查询出Maze

getCanMove()通过提供的mazeId来查询当前可以移动的方向

writeLoc将移动过后的位置写入数据库

writeCanMove将移动过位置后可以移动的方向写入数据库

在/move前半部分代码接收了GET传入的id与move并分别将他们的值赋给mazeId与moveStr
随后用getCanMove()函数取出当前位置可以移动的方向
然后定义一个移动列表validMoves并判断move的方向是否合法

之后会用getLoc()函数获取到玩家的位置。然后对玩家的位置进行更新。然后更新迷宫将玩家的老位置设置为
.新位置设置为@ 然后使用wirteCanMove更新玩家可以移动的方向

读到这里我仍不知道漏洞点在哪里。我读了siunam的博客之后才知道。可以利用条件竞争来进行欺骗数据库
举个例子
1 | 想象一下一个银行应用程序,其中两个联名账户的所有者拥有 100 元的余额,他们同时尝试提取 90 元。如果不妥善处理竞争条件,最好的情况是,一个请求更快并首先完成,然后第二个请求由于资金不足而失败,最坏的情况是,他们同时到达数据库,并且都成功地从余额为 100 元的账户中提取了 90 元(总共 180 元),这对银行来说是一种损失,也是应用程序中非常危险的漏洞。 |
考虑以下迷宫,其中我们只能移动left或right:
1 | ####### |
尽管有墙,是否可以强制玩家向一侧移动right
为此,我们可以:
玩家移动到left,因此限制方向将right改为left
1
2
3 #######
#@.#..#
#######
现在尝试同时发送 2 个right移动请求
玩家的位置将在中心墙上
1
2
3 #######
#..@..#
#######
为了尝试这一想法我用Golang编写了一个简易的并发程序来验证这一观点
现在我们将@移动到距离#只有一个.的位置上面

然后并发三个数据包成功的将@移动到原本无法到达的#上面(经历了好几次失败)

通过这个思路,我们可以通过并发来突破#的限制
下面是我写的一个脚本,一次只能发送像一个方向移动的包(是的,这个脚本非常垃圾,归根结底还是我太菜了(-̩̩̩-̩̩̩-̩̩̩-̩̩̩-̩̩̩___-̩̩̩-̩̩̩-̩̩̩-̩̩̩-̩̩̩))
大伙可以多发几次来做题
1 | package main |
不知道为什么在使用我这个脚本的时候会出现@分身的问题

官网给的这个题目的难度分级为3 (满分10)

Pwning en Logique
我见到的第一个prolog语言出的题目
附件给的源码看了不难理解(我没接触过这门语言仍能看懂) 只是大概理解 , 大概率有很大的偏差
















