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
语言出的题目
附件给的源码看了不难理解(我没接触过这门语言仍能看懂) 只是大概理解 , 大概率有很大的偏差