DGZ's Blog.

angstormctf WP (未完)

Word count: 1.7kReading time: 8 min
2020/04/02 Share

MISC

ws1

跟踪http流就可以看到flag

ws2

做法有两个吧,还有我选了最弱智的不行的第三种方法

第一种

找到POST包,看到有jpeg

右键JPEG File Interchange Format,显示分组字节,或者导出分组字节流文件,令后缀为jpg

第二种

HTTP对象中有一个multipart,导出,再用foremost可以直接分离出该jpg图片

我错就错在了只会foremost这个流量包文件

ws3

做法有两个

第一种

http对象导出18kb的文件,命名为test

用binwalk一看只有Zlib文件,我觉得这就是为什么不能用foremost分离的原因,只能用binwalk分离,可以看到文件夹中已经提取了jpg出来了

第二种

比较复杂,参考:https://github.com/joshdabosh/writeups/blob/master/AngstromCTF2020/misc/ws3.md

clam clam clam

参考:https://qiita.com/takdcloose/items/cbaed47c43d16edce402#clam-clam-clam-70pt
https://github.com/zhassan6992/angstromCTF2020-writeup/tree/master/misc/clam%20clam%20clam

1
2
3
4
5
from pwn import *

p = remote("misc.2020.chall.actf.co",20204)
mes = p.recvuntil(b"\x0d")
print(mes)

可以看到除了clam 还有一条消息,这是因为回车(\r)是一个控制字符。当您将其打印到终端时,终端将执行一些特殊的效果,而不是显示字形。对于回车,特殊的效果是将光标移动到当前行的开头。因此,如果打印中间包含回车的行,那么结果是下半部分被写在了上半部分之上,大概就是被覆盖的意思

nc misc.2020.chall.actf.co 20204 > output.txt
可能更为直接,然后将文本中的clam等重复字符串替换,最后只剩那句话type “clamclam” for salvation

1
2
3
4
5
6
from pwn import *

p = remote("misc.2020.chall.actf.co",20204)
mes = p.recvuntil(b"\x0d")
p.sendline(b"clamclam")
p.interactive()

得到actf{cl4m_is_my_f4v0rite_ctfer_in_th3_w0rld}

也可以命令行敲入

echo clamclam | nc misc.2020.chall.actf.co 20204

PSK

题目中的关键词就是PSK 和 31bits
wiki这时候的突出就表现出来了,大概是因为是外国人出的题目
PSK31或“相移键控,31波特”,也叫BPSK31和QPSK31,是一种流行的计算机声卡生成的无线电传打字模式,主要用于业余无线电操作员进行实时键盘到键盘的聊天,最常使用高频业余无线电波段(近短波)的频率。是一种数字调制。
wav文件听起来就是段噪音,可以通过Fldigi 4.1.09解密,但似乎我不太能用,
下载地址:http://www.w1hkj.com/files/fldigi/
还有:https://github.com/r00tstici/writeups/blob/master/angstromCTF_2020/psk/README.md 可以参考,使用的是RX-PSK31软件

除了psk31 还有psk63

shifer

8L95d0.png
后面才看懂了题,就是n是一个序数,对应的斐波拉契数列的第n个数,也就是当n为37时,明文偏移第37个斐波拉契数,然后要在60s内算完50个问题,又是只能写脚本。

1
2


CRYPTO

Keysar

带有key的凯撒加密

Hey! My friend sent me a message… He said encrypted it with the key ANGSTROMCTF.
He mumbled what cipher he used, but I think I have a clue.
Gotta go though, I have history homework!!
agqr{yue_stdcgciup_padas}
Author: joshdabosh

在线解密:http://rumkin.com/tools/cipher/caesar-keyed.php
又偏移又替换

Wacko Images

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from numpy import *
from PIL import Image

flag = Image.open(r"flag.png")
img = array(flag)

key = [41, 37, 23]

a, b, c = img.shape

for x in range (0, a):
for y in range (0, b):
pixel = img[x, y]
for i in range(0,3):
pixel[i] = pixel[i] * key[i] % 251
img[x][y] = pixel

enc = Image.fromarray(img)
enc.save('enc.png')

还是关键的模运算,pixel[i] = pixel[i] * key[i] % 251
不吐槽了…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from numpy import *
from PIL import Image
from gmpy2 import *

flag = Image.open(r"enc.png")
img = array(flag)

key = [41, 37, 23]
invkey=[invert(k,251) for k in key]

a, b, c = img.shape

for x in range (0, a):
for y in range (0, b):
pixel = img[x, y]
for i in range(0,3):
pixel[i] = pixel[i] * invkey[i] % 251
img[x][y] = pixel

dec = Image.fromarray(img)
dec.save('flag.png')

Confused Streaming

知识盲区知识盲区,有缘再解决

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
from __future__ import print_function
import random,os,sys,binascii
from decimal import *
try:
input = raw_input
except:
pass
getcontext().prec = 1000
def keystream(key):
random.seed(int(os.environ["seed"]))
e = random.randint(100,1000)
while 1:
d = random.randint(1,100)
ret = Decimal('0.'+str(key ** e).split('.')[-1])
for i in range(d):
ret*=2
yield int((ret//1)%2)
e+=1
try:
a = int(input("a: "))
b = int(input("b: "))
c = int(input("c: "))
# remove those pesky imaginary numbers, rationals, zeroes, integers, big numbers, etc
if b*b < 4*a*c or a==0 or b==0 or c==0 or Decimal(b*b-4*a*c).sqrt().to_integral_value()**2==b*b-4*a*c or abs(a)>1000 or abs(b)>1000 or abs(c)>1000:
raise Exception()
key = (Decimal(b*b-4*a*c).sqrt() - Decimal(b))/Decimal(a*2)
except:
print("bad key")
else:
flag = binascii.hexlify(os.environ["flag"].encode())
flag = bin(int(flag,16))[2:].zfill(len(flag)*4)
ret = ""
k = keystream(key)
for i in flag:
ret += str(next(k)^int(i))
print(ret)

wp讲的都是输入a、b、c不满足
1
if b*b < 4*a*c or a==0 or b==0 or c==0 or Decimal(b*b-4*a*c).sqrt().to_integral_value()**2==b*b-4*a*c or abs(a)>1000 or abs(b)>1000 or abs(c)>1000:

就输出flag,然后a、b、c要不满足条件,就是二元一次方程组解出无理数解的情况,随便丢一组abc进去就得到flag的二进制串,在转换一下就完成了。
所以我不知道中间的
1
2
3
4
5
6
7
flag = binascii.hexlify(os.environ["flag"].encode())
flag = bin(int(flag,16))[2:].zfill(len(flag)*4)
ret = ""
k = keystream(key)
for i in flag:
ret += str(next(k)^int(i))
print(ret)

在玩什么蛇皮,目前的认知是ret不会是flag的二进制形式(菜)

one time bad

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
#server.py
import random, time
import string
import base64
import os

def otp(a, b):
r = ""
for i, j in zip(a, b):
r += chr(ord(i) ^ ord(j))
return r


def genSample():
p = ''.join([string.ascii_letters[random.randint(0, len(string.ascii_letters)-1)] for _ in range(random.randint(1, 30))])
k = ''.join([string.ascii_letters[random.randint(0, len(string.ascii_letters)-1)] for _ in range(len(p))])

x = otp(p, k)

return x, p, k

random.seed(int(time.time()))

print("Welcome to my one time pad service!\nIt's so unbreakable that *if* you do manage to decrypt my text, I'll give you a flag!")
print("You will be given the ciphertext and key for samples, and the ciphertext for when you try to decrypt. All will be given in base 64, but when you enter your answer, give it in ASCII.")
print("Enter:")
print("\t1) Request sample")
print("\t2) Try your luck at decrypting something!")

while True:
choice = int(input("> "))
if choice == 1:
x, p, k = genSample()
print(base64.b64encode(x.encode()).decode(), "with key", base64.b64encode(k.encode()).decode())

elif choice == 2:
x, p, k = genSample()
print(base64.b64encode(x.encode()).decode())
a = input("Your answer: ").strip()
if a == p:
print(os.environ.get("FLAG"))
break

else:
print("Wrong! The correct answer was", p, "with key", k)

正常步骤是输入1,得到x和k,再根据otp函数逆出p,输入2再输入p得到flag
但是这里有个trick,如果我们一直都以A(一个ascii字符)去当作p,经过一段时间后没准能匹配到,所以我们就一直循环吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *
host="misc.2020.chall.actf.co"
port=20301

s=remote(host,port)
print(s.recv())
while 1:
s.sendline("2")
print(s.recv())
s.sendline("A")
ans=s.recv()
print(ans)
if b'actf'in ans:
exit()
s.close()

CATALOG
  1. 1. MISC
    1. 1.1. ws1
    2. 1.2. ws2
      1. 1.2.1. 第一种
      2. 1.2.2. 第二种
    3. 1.3. ws3
      1. 1.3.1. 第一种
      2. 1.3.2. 第二种
    4. 1.4. clam clam clam
    5. 1.5. PSK
    6. 1.6. shifer
  2. 2. CRYPTO
    1. 2.1. Keysar
    2. 2.2. Wacko Images
    3. 2.3. Confused Streaming
    4. 2.4. one time bad