DASCTF Sept X 浙江工业大学秋季挑战赛

本文最后更新于:6 小时前

CRYPTO

签到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from Crypto.Util.number import *
import random
flag=b'flag{******************}'
n = 2 ** 256
# n = 115792089237316195423570985008687907853269984665640564039457584007913129639936
print(n)
flaglong=bytes_to_long(flag)
m = random.randint(2, n-1) | 1
c = pow(m, flaglong, n)
print('m = ' + str(m))
print('c = ' + str(c))

# m = 73964803637492582853353338913523546944627084372081477892312545091623069227301
# c = 21572244511100216966799370397791432119463715616349800194229377843045443048821

题目意思很简单,就是求满足 mbytes_to_long(flag) %n=c 的flag值。

相关知识点

离散对数问题:离散对数(英语:Discrete logarithm)是一种基于同余运算和原根的一种对数运算。而在实数中对数的定义 logba是指对于给定的a和b,有一个数x,使得bx=a。相同地在任何群G中可为所有整数k定义一个幂数为bK,而离散对数logba是指使得bK=a的整数k

1
2
3
4
5
6
7
8
9
10
11
12
from sympy.ntheory import discrete_log
import binascii

n = 2 ** 256
m = 73964803637492582853353338913523546944627084372081477892312545091623069227301
c = 21572244511100216966799370397791432119463715616349800194229377843045443048821
flag = discrete_log(n, c, m) # 求解以c为底,n的对数;m为c的阶
print(hex(flag))
# 0x666c61677b4441534354465f7a6a75747d
flag = "666c61677b4441534354465f7a6a75747d"
flag = binascii.unhexlify(flag) # 16进制转字符串
print(str(flag, 'utf-8')) # bytes转字符串

MISC

Girlfriend’s account

题目说明:jackie的女朋友又偷偷用他的信用卡买东西了,你能算算一共花了多少钱吗?

————考excel函数的与ctf毫无关系的sb题目

解题步骤

xlsx内容

金额转小写=SUM(ISNUMBER(SEARCH(TEXT({1,2,3,4,5,6,7,8,9},"[dbnum2]"&{"0亿";"0仟!*万";"0佰!*万";"0拾!*万";"0万";"万!*0仟";"万!*0佰";"万!*0拾";"0元";"0角";"0分"}),IF(ISERR(FIND("万",E2)),"万",)&E2))*{1,2,3,4,5,6,7,8,9}*10^{8;7;6;5;4;3;2;1;0;-1;-2})

件数转小写=MATCH(G2,TEXT(ROW($1:$5000),"[dbnum2]"),0)=IF(B3=”壹”,1,IF(B3=”贰”,2,IF(B3=”叁”,3,IF(B3=”肆”,4,IF(B3=”伍”,5,IF(B3=”陆”,6,IF(B3=”柒”,7,IF(B3=”捌”,8,IF(B3=”玖”,9)))))))))=MATCH(G2,TEXT(ROW($1:$100),"[dbnum2]"),0)

总价=F2*H2

Ctrl+shift+enter计算结果,下拉5000行填充即可(应该有简便方法。。。)

求和=SUM(I2:I5001)

得到flag:flag{12305926.36}

双目失明,身残志坚

附件为无后缀zip文件,拖入winhex查看文件头不大对劲,尝试拖入foremost分离出压缩包,解压得到两个图片,分别是blind.png和original.png,两图片内容已知,其中blind.png文件更大,结合题目名和图片名猜想为盲水印

相关知识点

数字水印

数字水印(digital watermark)技术,是指在数字化的数据内容中嵌入不明显的记号。
特征是,被嵌入的记号通常是不可见或不可察的,但是可以通过计算操作检测或者提取。

盲水印与傅里叶变换

这里介绍的盲水印是以知乎某答主的频域添加盲水印的文章为基础,在2016HCTF的也出了一个隐写题目,也是以频域为背景的。

盲水印,是指人感知不到的水印,包括看不到或听不见(没错,数字盲水印也能够用于音频)。其主要应用于音像作品、数字图书等,目的是在不破坏原始作品的情况下,实现版权的防护与追踪。

对图像进行傅里叶变换,起始是一个二维离散傅里叶变换,图像的频率是指图像灰度变换的强烈程度,将二维图像由空间域变为频域后,图像上的每个点的值都变成了复数,也就是所谓的复频域,通过复数的实部和虚部,可以计算出幅值和相位,计算幅值即对复数取模值,将取模值后的矩阵显示出来,即为其频谱图。但是问题来了,复数取模后,数字有可能变的很大,远大于255,如果数据超过255,则在显示图像的时候会都当做255来处理,图像就成了全白色。因此,一般会对模值再取对数,在在0~255的范围内进行归一化,这样才能够准确的反映到图像上,发现数据之间的差别,区分高频和低频分量,这也是进行傅里叶变换的意义。

盲水印提取项目:BlindWaterMark

环境配置

python2.3皆可,且加解密结果不同(python2和python3 random的算法不同)

若同时存在python2、python3,注意环境变量、pip、依赖库冲突

依赖库安装

pip install -r requirements.txt 经尝试不可行

需安装opencv-python、matplotlib(涉及numpy、pillow)

命令提取盲水印

1
2
3
4
python bwm.py encode original.png flag.png blind.png  # 合成盲水印
python2 bwm.py decode original.png blind.png flag.png
python bwmforpy3.py decode original.png blind.png flag.png --oldseed # 效果等同python2
python bwmforpy3.py decode original.png blind.png flag.png

有软件WaterMake可实现盲水印

解题步骤

将图片依次拷贝至python2(3)\Lib\site-packages\BlindWaterMark-master目录下尝试,分别执行命令python2 bwm.py decode original.png blind.png decode1.pngpython bwmforpy3.py decode original.png blind.png decode1.png

python3成功提取到png

decode1.png

考虑摩斯密码因无法分段放弃,猜测为盲文

——望国家加大对残障人士的关注。。。。百度到的盲文对照表乱的一塌糊涂

下载app文星盲文学习助手,依次对照声母韵母,注意以下特殊对照

点位(1234)、(13)、(125)与i、ü开头的韵母相拼时读作j、q、x;与其他韵母相拼时读作g、k、h

点位(256)自成音节时读ueng,与韵母相拼时读作ong

点位(26)有o、e两读音

对照结果为zhejianggongiedaxüe,修正为zhejianggongyedaxue

提交flag:flag{zhejianggongyedaxue}

——很遗憾结束后半小时才出

复现

CRYPTO

签到

[网鼎杯 2020 青龙组]you_raise_me_up原题

MISC

Girlfriend’s account

python脚本读取xls文件,字典替换中文数字,相乘并加和

双目失明,身残志坚

盲文介绍

​ 盲文又称点字,国际通用的点字由6个凸起的圆点为基本结构组成,是专供盲人摸读、书写的文字符号。1829年,法国盲人路易•布莱尔(Louls Braille,1809-1852)受夜文的启发,创造出了以简单的凸点代替拉丁字母的盲文体系,国际上用他的名字来命名盲文(Braille)。

布莱尔创造的由6个点为基础结构的盲字,在纸面上有的凸起,有的不凸起,形成64种变化,即64种符形,在每个符号(单位称“方”)左右两列,每列各三个点,从左边自上而下叫做1、2、3点,从右边自上而下叫做4、5、6点。

数字

解读:每个数字的盲文前面都有个“3456”点符形,是数号,表示后面的读作阿拉伯数字。

字母

解读:英语盲文a-j都只是用了1245点位即上半截,和数字的一样;k-t是a-j下面加上了3号点位。

声母 声母续

注意:声母g/k/h在韵母i/u/ü时变读为j/q/x。z/c/s/zh/ch/sh/r后面的i省略

韵母 声调

ZipBomb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import os.path
import zipfile
import re

dir_path = 'zipBomb'
files = os.listdir(dir_path) # 返回指定的文件夹包含的文件或文件夹的名字的列表
print(files)
setee = []
for file in files: # 遍历文件夹
position = dir_path + '\\' + file # 构造绝对路径,"\\",其中一个'\'为转义符
print(position)
z = zipfile.ZipFile(position, 'r') # 创建(w)或读取(r)zip文件
for filename in z.namelist(): # 返回压缩包内所有文件名的列表
bytes = z.read(filename) # 从压缩包里解压缩出一个文件
# 以二进制方式打开读每一个文件 flag的16进制值为666C6167
if b'flag' in bytes: # wp给出的脚本为Zmxh,跑不出来
print(filename)

找到zipBomb\OJ.ZIP中名为FLAG的文件含错误flag:flag{F4KE_flag!}

猜测扫描每个文件内容识别flag的十六进制值找到正确flag

REVERSE

ea5ycpp

程序逻辑不懂,大概是在执行brainfuck代码吧?

brainfuck代码详解:百度百科

赋值部分汇编代码(避免大小端模式影响)

image-20211012183623736

1
2
3
4
5
6
7
8
9
10
# 例text24 = '>+++++++++++++++++++++++++[<+>-]'
# text24:在【1】中放入25,把它移动到【0】中即相加,并将【1】置零
v14 = [0x68, 0x6F, 0x65, 0x6C, 0x81, 0x69, 0x7A, 0x3D, 0x3B, 0x79, 0x6B, 0x73, 0x38, 0x39, 0x7B, 0x70, 0x7B, 0x48, 0x73, 0x7C, 0x85, 0x47, 0x7C, 0x96]
flag = ''
j = 2
for i in range(24):
flag += chr(v14[i]-j) # (v14[i] - (2+i))
j += 1
print(flag)
# flag{br41n_f**k_i5_go0d}

easy_math

根据字符串找到main函数

main函数

由于小端模式,v7的值实为’aSci!}’

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
from z3 import *

v23 = 'flagU' # 应经过类似处理未发现
v22 = Int('v22')
v24 = Int('v24')
v25 = Int('v25')
v26 = Int('v26')
# 解方程
s = Solver()
s.add(v26 - v22 == 0x61536369217D)
s.add(v25 - v22 == 0x586531316F)
s.add(v24 - v22 == 0x5F3631626F4E)
s.add(v22 + v24 + v25 + v26 == 0xC121F9FCC23A)
if s.check() == sat:
answer = s.model()
# print(answer)
# 将结果转为16进制后转换为字符输出
v22 = str(hex(answer[v22].as_long()))
v24 = str(hex(answer[v24].as_long()))
v25 = str(hex(answer[v25].as_long()))
v26 = str(hex(answer[v26].as_long()))
print(v22)
print(v24)
print(v25)
print(v26)
flag = ''
flag += '000000' # 补全8位分段(可有可无)
flag += v22[2::]
flag += '0000'
flag += v24[2::]
flag += '000000'
flag += v25[2::]
flag += '0000'
flag += v26[2::]
print(flag)
print(len(flag))
flag1 = [0] * 64
for i in range(0, 64, 2):
flag1[i] = flag[i:i + 2]
print(chr(int(flag1[i], 16)), end='')
# _F1boN he11o acci!}

奇奇怪怪的碰运气出flag。。。。。一堆函数不知道干啥的。。。。

pig_brain_king

运行exe

题目运行需要msvcp140d.dll(放到同目录下或C:\Windows\SysWOW64中即可),题中所有文字提示的输出都是通过从字典中取值并逐一输出的

字典

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
d = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/{}?!_'
print(d[22]+d[33]+d[40]+' '+d[34]+d[44]+' '+d[45]+d[33]+d[30]+' '+d[44]+d[45]+d[43]+d[40]+d[39]+d[32]+d[30]+d[44]+d[45]+' '+d[41]+d[34]+d[32]+' '+d[27]+d[43]+d[26]+d[34]+d[39]+' '+d[36]+d[34]+d[39]+d[32]+d[66]+d[67])
print(d[2]+d[26]+d[39]+' '+d[50]+d[40]+d[46]+' '+d[26]+d[39]+d[44]+d[48]+d[30]+d[43]+' '+d[53]+d[52]+d[52]+d[52]+' '+d[42]+d[46]+d[30]+d[44]+d[45]+d[34]+d[40]+d[39]+d[44]+' '+d[28]+d[40]+d[43]+d[43]+d[30]+d[28]+d[45]+d[37]+d[50]+d[66])
print(d[13]+d[40]+d[48]+' '+d[44]+d[45]+d[26]+d[43]+d[45]+' '+d[29]+d[40]+d[34]+d[39]+d[32]+' '+d[45]+d[33]+d[30]+' '+ d[42]+d[46]+d[30]+d[44]+d[45]+d[34]+d[40]+d[39]+d[44]+d[67])
print(d[15]+d[37]+d[30]+d[26]+d[44]+d[30]+' '+d[30]+d[39]+d[45]+d[30]+d[43])
print(d[39]+d[40]+d[39]+d[40]+d[39]+d[40])
print(d[27]+d[34]+d[39]+d[32]+d[40]+d[67])
print(d[19]+d[33]+d[30]+' '+d[26]+d[39]+d[44]+d[48]+d[30]+d[43]+' '+d[34]+d[44])
# 即
# Who is the strongest pig brain king?!
# Can you answer 1000 questions correctly?
# Now start doing the questions!
# Please enter
# nonono
# bingo!
# The answer is

**法一:**在判断正误的语句中有错误跳转,将其nop掉或改成jnz即可

回答问题正误

sub_4114BF输出answer即flag,大体思路是依次正确回答1000个问题(即输入屏幕短暂显示的字符串)后显示flag并清屏

第1001次判断未发现,flag的计算思路不明

flag输出

依次改掉休眠(将push改为0即可),错误跳转,输入1000个任意字符,即显示flag

sleep函数修改

jz改为jnz

1
2
3
4
5
# 生成1000行任意字符
file_handle = open('writein.txt', mode='w')
for i in range(1001):
file_handle.write('a\n')
file_handle.close()

第1001次显示flag

**法二:**利用pwntools自动化解nc -l -p 8081 -e ./re-pig_brain_king.exe,无需修改错误跳转,直接获取屏幕输出并输入

pwntools工具未使用过

1
2
3
4
5
6
7
8
9
10
11
12
13
# exp
from pwn import *
import time
context.log_level = 'debug'
r = remote('172.17.208.1',8081)

for i in range(1001):
r.recvuntil("Now start doing the questions!\r\n")
time.sleep(0.1)
ans=r.recvline()[:-2]
print("ans:",ans)
r.sendlineafter("Please enter:", ans)
r.interactive()

**flag:**flag{YOU_ar3_The_k1ng_Of_pig_bra1n!}