如果巅峰留不住,那就重走来时路
免责声明
该文章内容仅用于学习交流自查使用,请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息、技术或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关,公众号儒道易行及作者不为此承担任何责任,一旦造成后果请自行承担。
1.签到
打开签到题页面,拖动滑杆,如果将滑杆滑动到最左边,提交 0,那么我们会得到成功的返回,但是没有 flag
尝试手动提交一些非整数的值,发现得到返回信息:
我可以给你 1 个 flag、2 个 flag、3 个 flag…… 但我没法给你 0.34101个 flag。
返回信息提示我们要提交正整数的值,比如 1,而不是一个小数的值。
第一种方法
通过分析发现,这个滑杆的数值其实是通过浏览器地址栏中的一个参数来控制的,所以直接修改地址栏中的参数 number 的值为 1 即可,修改后回车即可得到 flag。
第二种方法
有的同学一定要把滑杆拖动到 1 才肯罢休,但即使是用键盘方向键操纵,最后数值也不会停留在 1。
分析前端页面,我们可以看到这么一段 JavaScript 代码:
varprevVal=0;$(document).ready(function() {$("#show").text($('#number')[0].value);$('#number').on('input', function() {if ($('#number')[0].value.toString() ==="1") {console.log('没想到吧!');$('#number')[0].value=1.00001;if (prevVal==1.00001) $('#number')[0].value=0.99999;if (prevVal==0.99999) $('#number')[0].value=1.00001; }$("#show").text($('#number')[0].value.toString());prevVal=$('#number')[0].value; });});
其中 console.log('没想到吧!'); 所在的代码块就是判断在滑杆数值变动时是否为 1,如果为 1 就跳过的代码,所以我们无法手动拖动或键盘控制滑杆的值到 1。
但是我们可以直接参考这段代码,直接把滑杆的值设置为 1,具体来说,打开 Chrome 的开发者工具(F12),在 Console 标签下输入以下代码执行,即可将滑杆的值设置为 1,然后点击提交就可以得到 flag:
$('#number')[0].value = 1;
点击提取
第三种方法
直接修改value的值为1
可以看到滑杆已停在1的位置,点击提取
第四种方法
将step设置为1
向右拖动滑杆即可到1的位置
2.2048
第一种方法
查看网页源代码,发现提示:
<!-- changelog: - 2020/10/31 getflxg @ static/js/html_actuator.js -->
进而打开 static/js/html_actuator.js 这个文件,找到和游戏胜利有关的逻辑:
var url; if (won) { url = "/getflxg?my_favorite_fruit=" + ('b'+'a'+ +'a'+'a').toLowerCase(); } else { url = "/getflxg?my_favorite_fruit="; } let request = new XMLHttpRequest(); request.open('GET', url);
如果访问 /getflxg?my_favorite_fruit= 可以得到返回信息:
还没有大成功,不能给你 flxg。
这正是游戏失败时的提示信息。
我们打开 Chrome 浏览器的开发者工具,切换到 Console 标签页,执行一下 ('b'+'a'+ +'a'+'a').toLowerCase(),得到正确的应该填入的值为 banana
访问 /getflxg?my_favorite_fruit=banana,则可以得到正确的 flag。
有的同学可能会好奇为什么 ('b'+'a'+ +'a'+'a').toLowerCase() 的计算结果是 banana,这个问题可以参考:https://stackoverflow.com/questions/57456188/why-is-the-result-of-ba-a-a-tolowercase-banana 。
3.一闪而过的flag
首先下载题目中所给出的exe文件
打开cmd命令行窗口
将下载下来的exe文件拖到命令行窗口,点击回车运行即可得到flag
也可以在文件下载后的位置打开命令行窗口,直接运行exe文件
4.从零开始的记账工具人
这道题考察选手基本的编程处理数据的能力,常见的编程语言都可以编写出解题代码。
解法 1
手工计算
解法 2
使用任意文本编辑器(或者 Excel 本身)做字符串替换,替换规则如下:
'零' -> '''壹' -> '1''贰' -> '2''叁' -> '3''肆' -> '4''伍' -> '5''陆' -> '6''柒' -> '7''捌' -> '8''玖' -> '9''拾' -> '*10+''佰' -> '*100+''仟' -> '*1000+''元' -> '+''角' -> '/10+''分' -> '/100''++' -> '+''整' -> ''
然后如果开头有乘号或者结尾有加号,去掉即可,这样的数学表达式求值即可得到正确的结果。
解法 3
编程求解,这里使用 Python 语言。
我们首先使用 Excel(或者其他商业的、开源的、在线的电子表格工具)将下载的文件转换为 .csv 格式,即逗号分隔的文本。(当然,你也可以使用解析 Excel 文件格式的库来处理)
然后在 Python 中安装 cn2an 这个中文数字转换的库:
python3 -m pip install cn2an
然后使用 Python 程序处理这个文件:
importcn2anlines = open('bills.csv').readlines()[1:]s = 0forlineinlines:a, b = line.strip().split(',')n = 0if'元'ina:y, a = a.split('元')n += cn2an.cn2an(y, "smart")if'角'ina:y, a = a.split('角')n += cn2an.cn2an(y, "smart") /10if'分'ina:y, a = a.split('分')n += cn2an.cn2an(y, "smart") /100s += n*int(b)print(s)
5.超简单的世界模拟器
这道题手工构造与写代码暴力搜索都可以解决。
使用搜索引擎搜索“生命游戏”或“Game of Life”都可以找到很多相关的资料,其中会提到生命游戏的演化规则和一些有趣的构造。
手工构造解法
为了消除右上角的方块,我们只要放置一个水平移动的“太空船”即可:
000000000000000001111000000000010001000000000000001000000000010010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
这样可以得到第一个 flag。
消除第二个方块有点困难,因为(比较小的)飞行器只能沿着对角线方向和水平竖直方向飞行,我们的可控制区域比较小,无法让飞行器移动后与方块碰撞。
所以我们可以找一些会扩散比较大的初始状态,例如这个链接里面讲的例子。
一个可行的例子:
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011000000000000001100000000000011000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000
暴力解法
直接随机生成 0/1 矩阵,大概几十次就可以找到一个,Python 代码见solve.py
importrandomMAP_SIZE = 50CONTROL_SIZE = 15STEP = 200FLAGS = [(5, 45), (25, 45)]defflag_range(flag):x, y = flagforiinrange(2):forjinrange(2):yieldx+i, y+jclassGame:def__init__(self, W, H):self.W = Wself.H = Hself.map = [[0for_inrange(W)] for_inrange(H)]forflaginFLAGS:forx, yinflag_range(flag):self.map[x][y] = 1defstep(self):new = [[0for_inrange(self.W)] for_inrange(self.H)]foriinrange(self.H):forjinrange(self.W):cnt = 0forioin-1, 0, 1:forjoin-1, 0, 1:if0<= i+io<self.H:if0<= j+jo<self.W:ifio!= 0orjo!= 0:ifself.map[i+io][j+jo]:cnt += 1ifcnt == 3:new[i][j] = 1elifcnt == 2:new[i][j] = self.map[i][j]else:new[i][j] = 0self.map = newrandom.seed(2020)whileTrue:game = Game(MAP_SIZE, MAP_SIZE)foriinrange(CONTROL_SIZE):forjinrange(CONTROL_SIZE):game.map[i][j] = random.randrange(2)s = ''forlineingame.map[:CONTROL_SIZE]:foriinline[:CONTROL_SIZE]:s += str(i)s += 'n'last = game.mapforiinrange(STEP):game.step()ifgame.map == last:breaklast = game.mapcnt = 0fori, flaginenumerate(FLAGS):ifall(notgame.map[x][y] forx, yinflag_range(flag)):cnt += 1print("flags =", cnt)ifcnt:print(s)
6.从零开始的火星文生活
首先下载题目中所给出的文件
例如用 VSCode 的“Select Encoding”功能。
步骤(开始时 UTF-8 打开题目附件):
Save with Encoding -> GBK
Reopen with Encoding -> UTF-8
Save with Encoding -> ISO8859-1
Reopen with Encoding -> GBK
7.自复读的复读机
解题思路
使用搜索引擎搜索“输出自己的程序”或者类似的词,可以查到这类程序叫做 Quine。可以很容易在网上查到很多 Python 3 的 Quine,例如:
exec(s:='print("exec(s:=%r)"%s)')
还有
s='s=%r;print(s%%s)';print(s%s)
等等。
这道题要求输出代码的逆序以及代码的哈希,我们可以修改上面的 Quine:
输出自己逆序的程序:exec(s:='print(("exec(s:=%r)"%s)[::-1])')(把 print 的内容用括号括起来然后逆序即可)
但这样提交之后有一个问题,就是输出比代码多了一个 n,这是由于输入的代码结尾没有换行符而 print 输出的内容结尾会自带换行符,我们只需要让 print 不输出换行符,加一个 ,end="" 即可。
对于第二问,我们把 print 的内容用 Python 自带的计算 sha256 的函数包起来即可。
答案
第一问(每行都是一个可能的构造):
exec(s:='print(("exec(s:=%r)"%s)[::-1],end="")')
s='s=%r;print((s%%s)[::-1],end="")';print((s%s)[::-1],end="")
第二问(每行都是一个可能的构造):
exec(s:='print(__import__("hashlib").sha256(("exec(s:=%r)"%s).encode()).hexdigest(),end="")')exec(s:='import hashlib;print(hashlib.sha256(("exec(s:=%r)"%s).encode()).hexdigest(),end="")')import hashlib;s='import hashlib;s=%r;print(hashlib.sha256((s%%s).encode()).hexdigest(),end="")';print(hashlib.sha256((s%s).encode()).hexdigest(),end="")
其他
要注意的是,这道题的程序是使用标准输入读入代码然后用 exec() 执行的,所以并不能使用 print(open(file).read()) 之类输出自己源代码文件的方案。
你可以使用 import os; os.system('ls') 之类的代码来在服务器上任意执行命令,但是进程是以低权限运行的,这种方法不能读到 flag。
8.233 同学的字符串工具
「字符串大写工具」题解
代码的意思是:如果我们输入一个字面上不是 "flag" 但转换为大写后会变成 "FLAG" 的字符串,就可以得到 flag。
我们可以以 "unicode uppercase collision" 为关键字搜索,不难找到一个连字(ligature)
fl (0xFB02)
这个“字符”将在转换为大写时变成 FL 两个字符!因此,只需输入 flag 即可得到 flag。
flag{badunic0debadbad}
「UTF-7 转换工具」题解
代码的意思是:如果我们输入一个字面上不是 "flag" 但从 UTF-7 转换为 UTF-8 后会变成 "flag" 的字符串,就可以得到 flag。
不妨查阅 UTF-7 相关资料。可以得知:一个 Unicode 字符串,在 UTF-7 编码下,可能有多种编码,甚至纯粹的 ASCII 字符串也可以有多种编码!
那么事情就简单了。我们依照 Wikipedia 等参考资料给出的 UTF-7 编码算法,可以构造出 "flag" 的另一种“写法”。比如,选择 f 下手。
f 的 Unicode 码位是 0x66
将 0x66 写成 16 位二进制数:0000 0000 0110 0110
重新分组:000000 000110 011000
使用 base64 的编码表,将每组变成一个字符:AGY
那么最终 "flag" 的另一种 UTF-7 替代写法就是 +AGY-lag,输入即可得到 flag。
flag{please_visit_www.utf8everywhere.org}
攻防交流圈
1、本圈主要分享:攻防及SRC实战经验分享、代码审计漏洞详情及代码、最新漏洞详情及原创漏洞利用工具、免杀手法及工具代码、问题解答等。2、圈主出身于深信服深蓝攻防实验室、新华三攻防实验室,连续5年多次获得国家级、省级、地市级、行业级护网攻击队前三名。3、漏洞盒子总榜前五十名、补天总榜前五十名、去哪网SRC总榜前五十名。4、获得50+CVE通用漏洞编号、100+CNVD通用漏洞证书。5、CSDN、公众号、博客、先知社区、SecIN、FreeBuf粉丝量10000+。6、前1-50名: 25¥,50-100名: 50¥,100-150名: 75¥,依次类推.....!
原文始发于微信公众号(儒道易行):【CTF】Hackergame黑客游戏
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论