目錄
  1. 1. Oldman Reverse
  2. 2. Honey, Help!
  3. 3. Zakukozh
  4. 4. ProCTF
  5. 5. QShell
  6. 6. Warmup
cybrics CTF 2019 writeup

前几天打了一下cybrics CTF,主要都是杂项,学到了不少东西,因此记录一下。

Oldman Reverse

1
2
desc:I've found this file in my grandfather garage. Help me understand what it does
file:oldman.asm

oldman.asm内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.MCALL  .TTYOUT,.EXIT
START:
mov #MSG r1
mov #0d r2
mov #32d r3
loop:
mov #MSG r1
add r2 r1
movb (r1) r0
.TTYOUT
sub #1d r3
cmp #0 r3
beq DONE
add #33d r2
swab r2 ;将目标位置的字数据的高位字节与低位字节互换
clrb r2 ;将目标位置的低字节数据清零
swab r2 ;将目标位置的字数据的高位字节与低位字节互换
br loop
DONE:
.EXIT

MSG:
.ascii "cp33AI9~p78f8h1UcspOtKMQbxSKdq~^0yANxbnN)d}k&6eUNr66UK7Hsk_uFSb5#9b&PjV5_8phe7C#CLc#<QSr0sb6{%NC8G|ra!YJyaG_~RfV3sw_&SW~}((_1>rh0dMzi><i6)wPgxiCzJJVd8CsGkT^p>_KXGxv1cIs1q(QwpnONOU9PtP35JJ5<hlsThB{uCs4knEJxGgzpI&u)1d{4<098KpXrLko{Tn{gY<|EjH_ez{z)j)_3t(|13Y}"
.end START

看懂汇编代码就可以了,字符串长度刚好为256,注释的三行代码相当于模256,脚本如下:

1
2
3
4
5
6
7
8
s = "cp33AI9~p78f8h1UcspOtKMQbxSKdq~^0yANxbnN)d}k&6eUNr66UK7Hsk_uFSb5#9b&PjV5_8phe7C#CLc#<QSr0sb6{%NC8G|ra!YJyaG_~RfV3sw_&SW~}((_1>rh0dMzi><i6)wPgxiCzJJVd8CsGkT^p>_KXGxv1cIs1q(QwpnONOU9PtP35JJ5<hlsThB{uCs4knEJxGgzpI&u)1d{4<098KpXrLko{Tn{gY<|EjH_ez{z)j)_3t(|13Y}"
print len(s)
a = 0
flag = ""
for i in range(32):
flag += s[a]
a = (a + 33) % 256
print flag

flag:cybrics{pdp_gpg_crc_dtd_bkb_php}

Honey, Help!

1
2
desc:I was working in my Kali MATE, pressed something, AND EVERYTHING DISAPPEARED!
file:honey_hlep.txt

echo $'\e(0)'命令将终端的assic转化成一种加密的字符z,输入abcdefghijklmnopqrstuvwxy{}

看题目给的图片,容易发现倒数第二行就是加密的flag。当时我是一个个手工替换,后来参考了一下ctftime上的脚本(注意:只能python3)

1
2
3
4
5
6
7
8
9
10
11
#! /usr/bin/python3
#coding:utf-8

ciphertext = '▒␉␌␍␊°±
␋┘┐┌└┼⎺⎻─⎼⎽├┤┴┬│≤≥π£'
plaintext = 'abcdefghijklmnopqrstuvwxyz{}'
mapping = {i:j for i, j in zip(ciphertext, plaintext)}

print(mapping)
with open('honey_help.txt') as f:
print(''.join([mapping.get(i, i) for i in f.read()]))

flag:cybrics{h0ly_cr4p_1s_this_al13ni$h_0r_w4t?}

Zakukozh

1
2
desc:This image containing flag is encrypted with affine cipher. Scrape it
file:zakukozh.bin

根据描述,zakukozh.bin是仿射密码加密的密文,仿射密码加密解密规则如下:

1
2
3
4
5
6
7
8
加密:c = ((a * x) + b) mod m
解密:x = (a^-1 * (x - b)) mod m
x:明文
c:密文
a,b:密钥
m:密文空间
a^-1:a关于m的乘法逆元
其中:a与m互素

这里数据以字节为单位,因此m=256,a为3到256的奇数,b为0到255。密文空间为127*256,可以爆破。

1
2
3
4
5
6
7
8
9
10
def affine_d(a,b,c):
return chr((a*(ord(c) - b))%256)
with open("zakukozh.bin",'rb') as f:
data = f.read()

for i in range(3,256,2):
for j in range(256):
file = ''.join([affine_d(i,j,c) for c in data])
with open("output/file_{}_{}".format(i,j),'wb') as f:
f.write(file)

然后

查看file_239_89,发现flag

除此之外,还有一种简易的方法

查看加密文件头60 09 EB 82 1C EF DF EF

  • JPEG: ff d8 ff e0 xx xx 4a 46 49 46
  • GIF: 47 49 46 38 39 61
  • PNG: 89 50 4e 47 0d 0a 1a 0a

因为仿射密码是简单的代换密码,因此猜测是png加密,于是可以直接根据文件头爆破a,b

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
png      = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]
zakukozh = [0x60, 0x09, 0xeb, 0x82, 0x1c, 0xef, 0xdf, 0xef]
x = []
def brute_a_b():
for a in range(3,256,2):
for b in range(256):
x = zakukozh[:]
for i in range(8):
x[i] = (a*(zakukozh[i] - b))%256
if x==png:
return a,b

a,b = brute_a_b()
print a,b

with open("zakukozh.bin",'rb') as f:
data = f.read()

png = ""
for i in data:
png += chr((a * (ord(i) - b))%256)
with open("flag.png",'wb') as f:
f.write(png)

flag:cybrics{W311_C0M3_2_CY13R1C5}

ProCTF

1
2
3
4
desc:We Provide you a Login for your scientific researches. Don't try to find the flag.

ssh pro@95.179.148.72
Password: iamthepr0

这里考察prolog语言如何调用shell,参考链接

http://www.ruanyifeng.com/blog/2019/01/prolog.html(Prolog 语言入门教程)

https://www.swi-prolog.org/pldoc/doc_for?object=shell%3Ashell/0(Prolog调用shell)

flag:cybrics{feeling_like_a_PRO?_that_sounds_LOGical_to_me!____g3t_it?_G37_1T?!?!_ok_N3v3Rm1nd…}

QShell

1
2
3
4
QShell is running on
nc spbctf.ppctf.net 37338

Grab the flag

连上之后,发现接收到一张二维码,解码结果为sh-5.0$。猜测应该是把交互信息通过二维码传输。于是只需两个转换脚本即可解决。首先,将接收的数据转为二维码图片

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
data = p.recvuntil("\n.").rstrip('.').rstrip()
p.recvline()

data += '#'
qr = [[]]
i = 0

while i < len(data):
if data[i] == '\xe2': #白色部分'\xe2\x96\x88'
qr[-1].append(255) #RGB(255,255,255)为白色
i += 3
elif data[i] == '\x20': #黑色部分为空格
qr[-1].append(0) #RGB(0,0,0)为黑色
i += 1
elif data[i] == '\x0a': #换行
qr.append([])
i += 1
else:
break
image = Image.new('RGB',(len(qr),len(qr[0])),(255,255,255))

for x in range(len(qr)):
for y in range(len(qr[0])):
rgb = qr[y][x]
image.putpixel((x,y),(rgb,rgb,rgb))

size = len(qr)
image = image.resize((size * 3, size * 3)) #3层通道
image.save("qr.png")

result = decode(image)
print result[0][0]

将二维码转化为传送数据

1
2
3
4
5
6
7
8
9
10
11
img = qrcode.make('cat flag.txt')   #生成二维码图片
data = b''
for y in range(img.size[1]):
for x in range(img.size[0]):
r = img.getpixel((x, y))
if r == 255:
data += b'\xe2\x96\x88'
else:
data += b' '
data += b'\n'
data += b'\n.'

完整脚本

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
from pwn import *
from PIL import Image
from pyzbar.pyzbar import decode
import qrcode


#context.log_level = 'debug'
p = remote("spbctf.ppctf.net", "37338")

def recv():
data = p.recvuntil("\n.").rstrip('.').rstrip()
p.recvline()

data += '#'
qr = [[]]
i = 0

while i < len(data):
if data[i] == '\xe2':
qr[-1].append(255)
i += 3
elif data[i] == '\x20':
qr[-1].append(0)
i += 1
elif data[i] == '\x0a':
qr.append([])
i += 1
else:
break

image = Image.new('RGB',(len(qr),len(qr[0])),(255,255,255))

for x in range(len(qr)):
for y in range(len(qr[0])):
rgb = qr[y][x]
image.putpixel((x,y),(rgb,rgb,rgb))

size = len(qr)
image = image.resize((size * 3, size * 3))
#image.save("flag.png")

result = decode(image)
print result[0][0]

def send(cmd):
img = qrcode.make(cmd)
data = b''
for y in range(img.size[1]):
for x in range(img.size[0]):
r = img.getpixel((x, y))
if r == 255:
data += b'\xe2\x96\x88'
else:
data += ' '
data += '\n'
data += b'\n.'
p.sendline(data)

recv()
while True:
cmd = raw_input("sh-5.0$ ")
send(cmd)
recv()
p.interactive()

运行结果

Warmup

1
2
3
desc:E_TOO_EASY

Just get the flag

网页有跳转,查看源网页

文章作者: kangel
文章鏈接: https://j-kangel.github.io/2019/07/25/cybrics/
版權聲明: 本博客所有文章除特別聲明外,均採用 CC BY-NC-SA 4.0 許可協議。轉載請註明來自 KANGEL