Featured image of post Hackergame-2020 Write-up

Hackergame-2020 Write-up

这应该是我第一次参加 CTF,写下一些自己的做题思路吧

Preface

此前从来没参加过 CTF、信安赛之类的,真要说类似的就是解一些过年时我所关注的各位大佬发的红包谜题了。

反正就一直对 CTF 抱有很大的念想。虽说 USTC 这个只有个人赛,不过早就听说其难度老少皆宜了,大学后可支配时间也多了,作为我的第一次比赛正好。

大佬们就没必要看了(

Q List

  • 签到
  • 猫咪问答++
  • 2048
  • 一闪而过的 Flag
  • 从零开始的记账工具人
  • 超简单的世界模拟器(2)
  • 从零开始的火星文生活
  • 自复读的复读机(2)
  • 233 同学的字符串工具
  • 233 同学的 Docker
  • 从零开始的 HTTP 链接
  • 来自一教的图片
  • 超简陋的 OpenGL 小程序
  • 生活在博弈树上(2)
  • 来自未来的信笺
  • 狗狗银行
  • 超基础的数理计算器
  • 永不溢出的计算器
  • 普通的身份认证器
  • 超精巧的数字论证器
  • 超自动的开箱模拟器
  • 室友的加密硬盘
  • 超简易的网盘服务器
  • 超安全的代理服务器(2)
  • 证验码
  • 动态链接库检查器
  • 超精准的宇宙射线模拟器
  • 超迷你的挖矿模拟器
  • Flag 计算机
  • 中间人(2)
  • 不经意传输(2)

签到

选手要多少个 flag,我就给多少个 flag,绿色背景,红色加粗,显眼的位置,标准的格式,这都不叫送,那还有什么叫做送。

点击 「打开/下载题目」 按钮,打开 flag 提取器,获取第一个 flag 吧!

直接滑动是滑不到1

让我们打开控制台看看

定位到滑动块的元素,可以发现这个step属性值很奇怪,把它给改成10.50.1之类的值再滑动一下,就发现可以定位到 1 了,再点提取

第一个 Flag 就得到了

猫咪问答++

这题其实我是留到第二天才做的

点此查看题目截图

此题考察搜索引擎的使用能力。

先说说答案吧,从第一问到第五问分别是122569917098

我当时没能查到第一题和第二题,第四题一开始用错成了谷歌全景,后来被朋友指点才发现要用百度全景。

这是当时用 Python 写的遍历

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.common.exceptions import NoSuchElementException
import time
import requests

bs = webdriver.Firefox()
bs.get("http://202.38.93.111:10001/?token=1294%3AMEYCIQDGGgsw4ZIS8VYoonINuZNHwWagU8HonbAS8xibpRsb8QIhAMtC8zWSEbqwPOgmgaix0hzT%2Bho30JdIC8fp%2B1Uojwdg")

bs.find_element_by_xpath("/html/body/form/div/div[1]/div/div[2]/input").click()
bs.find_element_by_xpath("/html/body/form/div/div[1]/div/div[2]/input").send_keys(str(0))
time.sleep(0.2)
bs.find_element_by_xpath("/html/body/form/div/div[2]/div/div[2]/input").click()
bs.find_element_by_xpath("/html/body/form/div/div[2]/div/div[2]/input").send_keys(str(0))
time.sleep(0.2)
bs.find_element_by_xpath("/html/body/form/div/div[3]/div/div[2]/input").click()
bs.find_element_by_xpath("/html/body/form/div/div[3]/div/div[2]/input").send_keys(str(0))
time.sleep(0.2)
bs.find_element_by_xpath("/html/body/form/div/div[4]/div/div[2]/input").click()
bs.find_element_by_xpath("/html/body/form/div/div[4]/div/div[2]/input").send_keys(str(0))
time.sleep(0.2)
bs.find_element_by_xpath("/html/body/form/div/div[5]/div/div[2]/input").click()
bs.find_element_by_xpath("/html/body/form/div/div[5]/div/div[2]/input").send_keys(str(0))
time.sleep(0.2)
bs.find_element_by_xpath("/html/body/form/div/input").click()
time.sleep(1)

# 用眼睛看吧,不想写字符串识别了
for i in range(12, 23):
    bs.find_element_by_xpath("/html/body/form/div/div[2]/div/div[2]/input").click()
    bs.find_element_by_xpath("/html/body/form/div/div[2]/div/div[2]/input").send_keys(str(i))
    time.sleep(0.2)
    bs.find_element_by_xpath("/html/body/form/div/div[3]/div/div[2]/input").click()
    bs.find_element_by_xpath("/html/body/form/div/div[3]/div/div[2]/input").send_keys(str(256))
    time.sleep(0.2)
    bs.find_element_by_xpath("/html/body/form/div/div[4]/div/div[2]/input").click()
    bs.find_element_by_xpath("/html/body/form/div/div[4]/div/div[2]/input").send_keys(str(9))
    time.sleep(0.2)
    bs.find_element_by_xpath("/html/body/form/div/div[5]/div/div[2]/input").click()
    bs.find_element_by_xpath("/html/body/form/div/div[5]/div/div[2]/input").send_keys(str(9))
    time.sleep(0.2)
    bs.find_element_by_xpath("/html/body/form/div/div[6]/div/div[2]/input").click()
    bs.find_element_by_xpath("/html/body/form/div/div[6]/div/div[2]/input").send_keys(str(17098))
    time.sleep(0.2)
    print(i)
    bs.find_element_by_xpath("/html/body/form/div/input").click()
    time.sleep(1)
# keyboard interrupt 后第一问答案为 12

写的很丑,但既然用到了,那就写进 Write-up

最终得到第二题的 Flag

2048

要实现 FLXG,你需要过人的智慧,顽强的意志,和命运的眷属。只有在 2048 的世界里证明自己拥有这些宝贵的品质,实现「大成功」,你才有资格扛起 FLXG 的大旗。

一个并不寻常的 2048

我一开始真的就玩了起来…然后玩到炸毁金矿我心态就跟着炸了,这 TM 怎么还没结束啊(

我当时也挺呆的,就写了个脚本让它自己跑…emm

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.common.exceptions import NoSuchElementException
import time
import requests
# 打开firefox,并访问2048游戏界面
bs = webdriver.Firefox()
bs.get("http://202.38.93.111:10005/")
bs.find_element_by_name("token").click()
bs.find_element_by_name("token").send_keys("1294:MEYCIQDGGgsw4ZIS8VYoonINuZNHwWagU8HonbAS8xibpRsb8QIhAMtC8zWSEbqwPOgmgaix0hzT+ho30JdIC8fp+1Uojwdg")
bs.find_element_by_xpath("/html/body/form/input[2]").click()
html = bs.find_element_by_tag_name('html')

while True:
    # 每四个方向操作后判断游戏是否结束
    print('send up,right,down,left')
    html.send_keys(Keys.UP)
    time.sleep(0.2)
    html.send_keys(Keys.RIGHT)
    time.sleep(0.2)
    html.send_keys(Keys.DOWN)
    time.sleep(0.2)
    html.send_keys(Keys.LEFT)
    time.sleep(0.2)
    game_over = bs.find_element_by_xpath("/html/body/div/div[3]/div/p")
    if game_over.text == 'FLXG 永不放弃!':
        #score = bs.find_element_by_class_name('score-container')    #当前得分
        #print('game over, score is %s' % score.text)
        #print('wait 3 seconds, try again')
        #time.sleep(3)
        # 游戏结束后,等待3秒,自动点击try again重新开始
        print("重新开始")
        try_again = bs.find_element_by_class_name('retry-button')
        try_again.click()

然后丢到后台没理它,开始做下一题了

Two thousand years later…

当我翻到后台——

WTF?跑到了 5436 还没结果时我就知道我方法错了

View-source 走起

诶这不是赤裸裸的提示嘛

点进去看看

看到这里我就知道脚本永远跑不出来了

再往下翻翻

原来是 js 跳转,那我们直接把url拿出来就行了,可这个url有点奇怪,里面有个函数,拿到控制台跑一下试试

成功获取了真正的url!输入网址回车

得到第三题的 Flag

一闪而过的 Flag

flag 来了,可是我什么也看不见!

先下载文件

直接双击运行只会看到黑框出现一下就消失了

  • 第一种方法:直接快速截屏,肉眼识别

  • 第二种方法:在命令行运行文件

这里采用第二种

复制

得到第四题的 Flag

从零开始的记账工具人

这不是很简单吗?电子表格里面一拖动就算出来了

考察搜索引擎使用以及小脚本的编写

先把题目下载下来

先看看bills.xlsx,里面是 1000 行人民币大写金额,那么题目要求就是全部转换小写求和了

这题我一开始就想到了Python,又是我最熟悉的大数据分析,于是直接把bills.xlsx上传到了树莓派的内网notebook服务器上

首先需要找一个人民币大写转小写的函数做轮子,再用数量乘金额并求和

代码如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import numpy as np
import pandas as pd
import re
def aoligeiganle(amount):
    chinese_num = {'零': 0, '壹': 1, '贰': 2, '叁': 3, '肆': 4, '伍': 5, '陆': 6, '柒': 7, '捌': 8, '玖': 9}
    chinese_amount = {'分': 0.01, '角': 0.1, '元': 1, '拾': 10, '佰': 100, '仟': 1000, '圆': 1}
    amount_float = 0
    if '亿' in amount:
        yi = re.match(r'(.+)亿.*', amount).group(1)
        amount_yi = 0
        for i in chinese_amount:
            if i in yi:
                amount_yi += chinese_num[yi[yi.index(i) - 1]] * chinese_amount[i]
        if yi[-1] in chinese_num.keys():
            amount_yi += chinese_num[yi[-1]]
        amount_float += amount_yi * 100000000
        amount = re.sub(r'.+亿', '', amount, count=1)
    if '万' in amount:
        wan = re.match(r'(.+)万.*', amount).group(1)
        amount_wan = 0
        for i in chinese_amount:
            if i in wan:
                amount_wan += chinese_num[wan[wan.index(i) - 1]] * chinese_amount[i]
        if wan[-1] in chinese_num.keys():
            amount_wan += chinese_num[wan[-1]]
        amount_float += amount_wan * 10000
        amount = re.sub(r'.+万', '', amount, count=1)

    amount_yuan = 0
    for i in chinese_amount:
        if i in amount:
            if amount[amount.index(i) - 1] in chinese_num.keys():
                amount_yuan += chinese_num[amount[amount.index(i) - 1]] * chinese_amount[i]
    amount_float += amount_yuan

    return amount_float

df = pd.read_excel('./bills.xlsx', 'Sheet1')

raw_price_list = []
price_list = []
num_list = np.array(df['数量'])
for i in range(0,1000):
    raw_price_list.append(aoligeiganle(df['单价'][i]))
raw_price_list = np.array(raw_price_list)
sum(np.multiply(num_list, raw_price_list))

这里其实麻烦也挺多的,很后面才发现找来的这个函数不完整,没有对开头汉字金额的进行处理

于是在函数尾部加上以下代码

1
2
if '拾' in amount[0]:
        amount_float += 10

最终运算结果是这样的

答案12422.75,这就是第五题的 Flag 值了

得到第五题 Flag

自复读的复读机

能够复读其他程序输出的程序只是普通的复读机。

顶尖的复读机还应该能复读出自己的源代码。

什么是国际复读机啊(战术后仰)

这题应该是我耗时最长的题目了,不过题目本身还是非常有意思的

先来读题

你现在需要编写两个只有一行 Python 代码的顶尖复读机:

满足两个条件分别对应了两个 flag

  • 其中一个要输出代码本身的逆序(即所有字符从后向前依次输出)

  • 另一个是输出代码本身的 sha256 哈希值,十六进制小写

遇事不懂,首先谷歌

Quine 是什么?

A quine is a computer program which takes no input and produces a copy of its own source code as its only output. The standard terms for these programs in the computability theory and computer science literature are “self-replicating programs”, “self-reproducing programs”, and “self-copying programs”.

—-Wiki

简而言之就是打印出代码本身

看来 Quine 就是我们所需要的了

找到以下文章供参考

http://littledva.cn/article-24/

还是打开我最熟悉的notebook,一步步来解析题目吧!

1
a=chr(39);c="+a)*2+c)";print(('a=chr(39);c="+a)*2+c)";print(('+a)*2+c)

先把范例拿进去试试,的确输出了代码本身

然后解析一下这段代码的原理

  • 代码只有一个print函数

  • 代码可以拆成以下三部分

    1. a=chr(39);c="+a)*2+c)";print(('

    2. a=chr(39);c="+a)*2+c)";print(('

    3. +a)*2+c)

  • print的层级

    1. ‘a=chr(39);c="+a)*2+c)";print((’

    2. (‘1’+a)*2

    3. (‘1’+a)*2+c

仔细看看就可以明白代码自复读的原理了

以上不详细讲了,进入解题吧

第一题:输出代码本身的逆序(即所有字符从后向前依次输出)

我们知道Python字符串逆序有以下两种方法(其余不介绍):

  • str[::-1]

  • ‘’.join(reversed(str))

显然第一个看起来简单好写,从第一个入手

1
a=chr(39);c="+a)*2+c)";print(('a=chr(39);c="+a)*2+c)";print(('+a)*2+c)

我们要输出逆序,那就直接在print最后加个[::-1]试试呗

1
2
3
a=chr(39);c="+a)*2+c)";print((('a=chr(39);c="+a)*2+c)";print(('+a)*2+c)[::-1])
# 输出 )c+2*)a+'((tnirp;")c+2*)a+"=c;)93(rhc=a'((tnirp;")c+2*)a+"=c;)93(rhc=a
# 正序 a=chr(39);c="+a)*2+c)";print(('a=chr(39);c="+a)*2+c)";print(('+a)*2+c)

少了[::-1]和一对括号,那就加到c里面去

1
2
3
a=chr(39);c="+a)*2+c)[::-1])";print((('a=chr(39);c="+a)*2+c)[::-1])";print((('+a)*2+c)[::-1])
# 输出 )]1-::[)c+2*)a+'(((tnirp;")]1-::[)c+2*)a+"=c;)93(rhc=a'(((tnirp;")]1-::[)c+2*)a+"=c;)93(rhc=a
# 正序 a=chr(39);c="+a)*2+c)[::-1])";print((('a=chr(39);c="+a)*2+c)[::-1])";print((('+a)*2+c)[::-1])

完成!它输出了自身的倒序!

可这还不够,我们把它丢到web executor试试

1
2
3
4
5
Your code is:
'a=chr(39);c="+a)*2+c)[::-1])";print(((\'a=chr(39);c="+a)*2+c)[::-1])";print(((\'+a)*2+c)[::-1])'

Output of your code is:
')]1-::[)c+2*)a+\'(((tnirp;")]1-::[)c+2*)a+"=c;)93(rhc=a\'(((tnirp;")]1-::[)c+2*)a+"=c;)93(rhc=a\n'

它发生了什么?多了个\n

其实我看到这里犯了个迷糊,既然你输出\n那我也输出一个\n不就是了吗(大声)

然后有了以下代码

1
a=chr(39);b=chr(92)+"n";c="+a)*2+c)[::-1]+b)";print((('a=chr(39);b=chr(92)+"n";c="+a)*2+c)[::-1]+b)";print((('+a)*2+c)[::-1]+b)

然后…

1
2
3
4
5
Your code is:
'a=chr(39);b=chr(92)+"n";c="+a)*2+c)[::-1]+b)";print(((\'a=chr(39);b=chr(92)+"n";c="+a)*2+c)[::-1]+b)";print(((\'+a)*2+c)[::-1]+b)'

Output of your code is:
')b+]1-::[)c+2*)a+\'(((tnirp;")b+]1-::[)c+2*)a+"=c;"n"+)29(rhc=b;)93(rhc=a\'(((tnirp;")b+]1-::[)c+2*)a+"=c;"n"+)29(rhc=b;)93(rhc=a\\n\n'

我就忍不住笑了 hhh

后来我才想到是print自带的换行啊,那我加个end=''不就行了吗

于是正确代码如下——

1
a=chr(39);c="+a)*2+c)[::-1],end="+a*2+")";print((('a=chr(39);c="+a)*2+c)[::-1],end="+a*2+")";print((('+a)*2+c)[::-1],end='')

得到此题第一个 Flag

第二题:输出代码本身的 sha256 哈希值,十六进制小写

此题难度高一点

先贴出源代码

1
import hashlib;a=chr(39);c="+a)*2+c+a+";d=a+"+d).encode()).hexdigest(),end="+a*2+")";print(hashlib.sha256((('import hashlib;a=chr(39);c="+a)*2+c+a+";d=a+"+d).encode()).hexdigest(),end="+a*2+")";print(hashlib.sha256((('+a)*2+c+a+'.encode()).hexdigest())'+d).encode()).hexdigest(),end='')

就随便讲讲思路吧,前面其实挺好构造的,主要是后面那一块

这个构造就是靠眼力,哪里多了个单引号,哪里少了个括号,添添补补就完事了。

构造d的原理和构造c的原理是一样的

构造原型是这样的——

1
import hashlib;print(hashlib.sha256("codeself".encode()).hexdigest())

codeself就是输出这个代码本身了

在进行构造时,可以把codeself写成如下形式方便参考

1
2
3
4
a=chr(39)
c="+a)*2+c+a+"
d=a+"+d).encode()).hexdigest(),end="+a*2+")";
print(('import hashlib;a=chr(39);c="+a)*2+c+a+";d=a+"+d).encode()).hexdigest(),end="+a*2+")";print(hashlib.sha256((('+a)*2+c+a+'.encode()).hexdigest())'+d,end='')

一般来说,只要这里输出和你的源代码一样,那这个题目就完成了

然后放到web executor

得到此题第二个 Flag

小小的题外话

当时做这题时周末已经结束了,于是我用思修课加一节晚自习,靠手写把这两题硬生生写出来的,用了整整四张草稿纸。

233 同学的 Docker

既然已经删掉了,应该不会被人找出来吧?

我本人并未使用过Docker,因此解这题并没有用到什么特别高级的技巧或者命令

先把镜像拉下来

1
sudo docker pull 8b8d3c8324c7/stringtool

查看一下修改历史

1
sudo docker history 8b8d3c8324c7/stringtool

第二行这个flag.txt明显就是我们需要的了

进入docker主目录

1
cd /var/lib/docker

直接搜索flag.txt

1
sudo find . | grep flag.txt

出现了两个结果,分别cat一下看看

1
2
sudo cat ./overlay2/a81374850a078b714197906a329e0250980bb2d44506c274e367c1e65e0af83d/diff/code/flag.txt
sudo cat ./overlay2/1595e998716bd50a416f17e04ac40a819e138974da1463cab6428319794c42e8/diff/code/flag.txt

在第二个文件中发现了我们需要的 Flag

其它的

狗狗银行

你能在狗狗银行成功薅到羊毛吗?

先说明这题我并没能解出来,后来才听我朋友说要用burp

不对,没解出来能算进Write-up的一部分嘛,于是我就写了个其它的

进去网页看看

一开始会给你初始资产1000,把它薅到2000就是胜利了

  • 收入来源:储蓄卡利息

  • 支出方向:吃饭还款利息

研究一下利息可以发现,它在1000时每日利息为3,可在167时每日利息为1,那我分出把1000分成六张167的卡试试,结果发现利息涨为每日6了,于是我的基本思路就是借款吃饭,用储蓄卡利息叠钱叠利息

手动有点麻烦,写个selenium自动脚本试试

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.common.exceptions import NoSuchElementException, StaleElementReferenceException, ElementClickInterceptedException, UnexpectedAlertPresentException
import time
import requests
import json

# 打开狗狗银行
bs = webdriver.Firefox()
bs.get("http://202.38.93.111:10100/?token=1294%3AMEYCIQDGGgsw4ZIS8VYoonINuZNHwWagU8HonbAS8xibpRsb8QIhAMtC8zWSEbqwPOgmgaix0hzT%2Bho30JdIC8fp%2B1Uojwdg")
time.sleep(3)
html = bs.find_element_by_tag_name('html')

# 添加 600 个储蓄卡,33 为对应办新卡的数字+1
# bs.find_element_by_xpath("/html/body/div/section/main/section/aside/div/div[184]").click()
# time.sleep(1)
# for i in range(600):
#     bs.find_element_by_class_name("ant-card-extra").click()
#     time.sleep(0.8)

def transfer(hunter, target):
    bs.find_element_by_xpath("/html/body/div/section/main/section/main/div[1]/div/div/div[1]/div[2]/button").click() # 点击转账按钮
    time.sleep(0.2)
    bs.find_element_by_xpath("/html/body/div[2]/div/div[2]/div/div[2]/div[2]/form/div[1]/div[2]").click() # 点击第一个框
    # bs.find_element_by_xpath("/html/body/div[3]/div/div/div/div[2]/div/div/div[" + hunter + "]").click() # 选择 hunter,数字代表对应储蓄卡
    time.sleep(0.5)

    ele_first = bs.find_element_by_xpath("/html/body/div[3]/div/div/div/div[2]")
    if int(hunter) == 1:
        ele_first.send_keys(Keys.ENTER)
    else:
        for i in range(int(hunter) - 1):
            ele_first.send_keys(Keys.DOWN)
            time.sleep(0.2)
        time.sleep(0.4)
        ele_first.send_keys(Keys.ENTER)

    bs.find_element_by_xpath("/html/body/div[2]/div/div[2]/div/div[2]/div[2]/form/div[2]/div[2]").click() # 点击第二个框
    # bs.find_element_by_xpath("/html/body/div[4]/div/div/div/div[2]/div/div/div[" + target + "]").click() # 选择 target,数字代表对应储蓄卡
    time.sleep(0.5)

    ele_second = bs.find_element_by_xpath("/html/body/div[4]/div/div/div/div[2]")
    if int(target) == 1:
        ele_second.send_keys(Keys.ENTER)
    else:
        for i in range(int(target) - 1):
            ele_second.send_keys(Keys.DOWN)
            time.sleep(0.2)
        time.sleep(0.4)
        ele_second.send_keys(Keys.ENTER)

    bs.find_element_by_xpath("/html/body/div[2]/div/div[2]/div/div[2]/div[2]/form/div[3]/div[2]/div/div/div/div[2]/input").send_keys(5) # 输入金额,目前固定 5 元
    bs.find_element_by_xpath("/html/body/div[2]/div/div[2]/div/div[2]/div[3]/button[2]").click() # convert

# 基本设计方法,每次信用卡借款5次,从大于167余额的储蓄卡转相应数额到不足的卡

# 信用卡借款 5 次
def rent_money():
    bs.find_element_by_xpath("/html/body/div/section/main/section/aside/div/div[8]").click()
    time.sleep(1)
    for times in range(2):
        bs.find_element_by_xpath("/html/body/div/section/main/section/main/div[2]/div/form/button").click()
        time.sleep(1)

# 获取所有卡的余额,余额为 172 或者大于 172 的卡转给不足 167 的卡,根据差分倍数进行多次转账
while True:
    # 借款模块
    try:
        bs.find_element_by_xpath("/html/body/div/section/main/section/aside/div/div[8]").click()
        time.sleep(1)
        for times in range(5):
            print("借款 1 次")
            bs.find_element_by_xpath("/html/body/div/section/main/section/main/div[2]/div/form/button").click()
            time.sleep(1)
    except NoSuchElementException:
        print("无此元素报错,可能是页面未刷新完全,继续下一个动作")
        bs.refresh()
    
    # 转账模块
    try:
        banl_list = []
        for i in range(1, 200): # 减小内存占用,请在此设置操作的储蓄卡区间,需要大于下面设置的值
            banl = bs.find_element_by_xpath("/html/body/div/section/main/section/aside/div/div[" + str(i+1) + "]/div[2]/div/span[2]").text
            banl_list.append(str(banl))
        insuff = [j + 1 for j in range(len(banl_list)) if int(banl_list[j]) < 167][0:4]
        for b in range(100): # 减小内存占用,请在此设置操作的储蓄卡区间
            insuff_Card_list = []
            if b == 6:
                continue
            elif int(banl_list[b]) >= 172:
                try:
                    print("储蓄卡 " + str(b+1) + " 余额为 " + banl_list[b])
                    print("储蓄卡 " + str(b+1) + " 转给储蓄卡 " + str(insuff[0]))
                    transfer(str(b + 1), str(insuff[2]))
                    time.sleep(1)
                    if abs(167 - int(banl_list[b])) / 5 >= 2:
                        print("储蓄卡 " + str(b+1) + " 转给储蓄卡 " + str(insuff[1]) + " 第二次")
                        transfer(str(b + 1), str(insuff[0]))
                        time.sleep(1)
                        if abs(167 - int(banl_list[b])) / 5 >= 3:
                            print("储蓄卡 " + str(b+1) + " 转给储蓄卡 " + str(insuff[2]) + " 第三次")
                            transfer(str(b + 1), str(insuff[1]))
                            time.sleep(1)
                            if abs(167 - int(banl_list[b])) / 5 >= 4:
                                print("储蓄卡 " + str(b+1) + " 转给储蓄卡 " + str(insuff[2]) + " 第三次")
                                transfer(str(b + 1), str(insuff[0]))
                                time.sleep(1)
                except NoSuchElementException:
                    print("无此元素报错,可能是页面未刷新完全,继续下一个动作")
                    continue
                except StaleElementReferenceException:
                    print("选择元素报错,原因未知,刷新页面,继续下一个动作")
                    bs.refresh()
                    time.sleep(2)
                except ElementClickInterceptedException:
                    print("表单选择错误,可能是识别混乱,刷新页面,继续下一个动作")
                    bs.refresh()
                    time.sleep(2)
            elif int(banl_list[b]) < 172:
                if int(banl_list[b]) == 0:
                    insuff_Card_list.append(b + 1)
                else:
                    print(banl_list[b])
                    print("储蓄卡 " + str(b + 1) + " 不足172元,跳过")
                    continue
        if len(insuff_Card_list) > 4:
            print("储蓄卡 " + "".join(insuff_Card_list) + " 空空如也")
    except UnexpectedAlertPresentException:
        print("未知错误,刷新")
        bs.refresh()
        time.sleep(2)

首先设置了一个转账函数transfer(),把固定金额从一个卡转到另一个卡

其次是生成储蓄卡,用于自动生成600张储蓄卡

再是借款模块,在每次循环开始借款5

再写一个转账模块,包括识别和函数

再把报错处理一下,全部模块丢进while True

以上仅为测试用,所以并没有写的很深入,比如固定金额转账,还有一些报错处理没完善

当时我是比赛第一天熬夜写的脚本,花了4个钟

第二天就丢在后台运行了一个下午,后来就变成上面图片那样,负资产越来越多直到-5000

然后我就不想去碰这题了(题目真屑————啊不对,我真屑

至于用burp解题,我不会啊啊啊((

总结

当前分数:900, 总排名:379 / 2340

binary:0 , general:750 , math:0 , web:150 (非准确数值)

估计再过一天也做不出来什么题目

排行榜看看,发现苏卡卡已经3100分了

对比赛总结一下就是

  • web相关的难一点点的话一个解不出来,思路倒是有挺多,主要是工具不会用(

  • 能真正用到selenium的地方确实不多,以后还是不费这么大劲去写它了

  • 能做出来的题目做得还是非常愉快的,也确实老少皆宜

  • (果然我就是菜鸡)

明年预计是要继续打的

就算是提前放出Write-up,只要我的分数够低也是没有问题的(逃

注意:博文图片可能需要翻墙访问,虽说之前说过要翻新博客,可也一直咕着,虽有基本的框架,但并不想那么早放出来,以前就被人爆破过。

CC BY-NC-SA 4.0 License