DGZ's Blog.

深信服培训记录-Crypto

Word count: 2.4kReading time: 12 min
2020/04/21 Share

Crypto

xbase64

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
# /usr/bin/python
# encoding: utf-8
base64_table = ['=','A', 'B', 'C', 'D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
'a', 'b', 'c', 'd','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
'0', '1', '2', '3','4','5','6','7','8','9',
'+', '/'][::-1]

def encode_b64(s):
l = len(s)
i = 0
result = ''
while i < l:
# 将字符转换为二进制编码,然后对齐
s1 = s[i]
b1 = bin(ord(s1))[2:]
cb1 = b1.rjust(8, '0')

i += 1
if i >= l:
cb2 = '00000000'
else:
s2 = s[i]
b2 = bin(ord(s2))[2:]
cb2 = b2.rjust(8, '0')

i += 1
if i >= l:
cb3 = '00000000'
else:
s3 = s[i]
b3 = bin(ord(s3))[2:]
cb3 = b3.rjust(8, '0')

# 将三字节转换为四字节
cb = cb1 + cb2 + cb3

rb1 = cb[:6]
rb2 = cb[6:12]
rb3 = cb[12:18]
rb4 = cb[18:]

# 转换后的编码转为十进制备用
ri1 = int(rb1, 2)
ri2 = int(rb2, 2)
ri3 = int(rb3, 2)
ri4 = int(rb4, 2)

# 处理末尾为0的情况,以'='填充
if i - 1 >= l and ri3 == 0:
ri3 = -1

if i >= l and ri4 == 0:
ri4 = -1

result += base64_table[ri1] + base64_table[ri2] + base64_table[ri3] + base64_table[ri4]

i += 1

return result

print encode_b64(open("flag","r").read())
base64_table = ['=','A', 'B', 'C', 'D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
'a', 'b', 'c', 'd','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
'0', '1', '2', '3','4','5','6','7','8','9',
'+', '/'][::-1]
#output: mZOemISXmpOTkKCHkp6Rgv==

可以看到新表是=的位置被移到了开头,而且结尾有个[::-1]
一个方法是直接根据base64编码原理写解密脚本,另外一个方法是直接贴旧表,利用index对应上旧表的字符,脚本如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import base64
new_base64_table = ['=','A', 'B', 'C', 'D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
'a', 'b', 'c', 'd','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
'0', '1', '2', '3','4','5','6','7','8','9',
'+', '/'][::-1]
old_base64_table = ['A', 'B', 'C', 'D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
'a', 'b', 'c', 'd','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
'0', '1', '2', '3','4','5','6','7','8','9',
'+', '/','=']

target="mZOemISXmpOTkKCHkp6Rgv=="
s=''
for i in target:
s+=old_base64_table[new_base64_table.index(i)]
print (base64.b64decode(s))

关键的地方在于
result += base64_table[ri1] + base64_table[ri2] + base64_table[ri3] + base64_table[ri4]
对于flag,我们无论是用新表还是旧表,加密过程是一样的,生成的二进制数是一样的,只是最后因为表不同所以生成的密文不同。

shellocode

到github下载shellcodeexec

维吉尼亚密码 卡西斯基试验

相关资料也参考了:https://www.jianshu.com/p/3d2c73464a51

卡西斯基试验是基于类似the这样的常用单词有可能被同样的密钥字母进行加密,从而在密文中重复出现。例如,明文中不同的CRYPTO可能被密钥ABCDEF加密成不同的密文:

    密钥:ABCDEF AB CDEFA BCD EFABCDEFABCD

    明文:CRYPTO IS SHORT FOR CRYPTOGRAPHY

    密文:CSASXT IT UKSWT GQU GWYQVRKWAQJB

此时明文中重复的元素在密文中并不重复。然而,如果密钥相同的话,结果可能便为(使用密钥ABCD):

    密钥:ABCDAB CD ABCDA BCD ABCDABCDABCD

    明文:CRYPTO IS SHORT FOR CRYPTOGRAPHY

    密文:CSASTP KV SIQUT GQU CSASTPIUAQJB

此时卡西斯基试验就能产生效果。对于更长的段落此方法更为有效,因为通常密文中重复的片段会更多。如通过下面的密文就能破译出密钥的长度:

    密文:DYDUXRMHTVDVNQDQNWDYDUXRMHARTJGWNQD

其中,两个DYDUXRMH的出现相隔了18个字母。因此,可以假定密钥的长度是18的约数,即长度为18、9、6、3或2。而两个NQD则相距20个字母,意味着密钥长度应为20、10、5、4或2。取两者的交集,则可以基本确定密钥长度为2。 (可以取18和20的最大公约数)

培训中的脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
i=0
slist=[]
snum=[]
sjg=[]
while i<len(a)-4:
s=a[i]+a[i+1]+a[i+2]
if s not in slist:
slist.append(s)
snum.append(1)
sjg.append(i)
else:
snum[slist.index(s)]+=1
sig[slist.index(s)]=i-sjg[slist.index(s)]
i+=1

for i in range(len(snum)):
if snum[i]>=2:
print(slist[i],sig[i])

*2图
如图,得到公约数为12,所以key=12位
但具体key是什么还要进一步爆破

真的用py2的讲师,我自己用py3就很蛋疼
关于py3的16进制解码:https://www.cnblogs.com/zhaijiahui/p/9597935.html

原py2脚本:

1
2
3
4
5
6
7
8
9
10
11
import os
def xor(a,b):
assert len(a)==len(b)
c=""
for i in range(len(a)):
c+=chr(ord(a[i])^ord(b[i]))
return c
m="50543fc0bca1bb4f21300f0074990f846a8009febded0b2198324c1b31d2e2563c908dcabbc461f194e70527e03a807e9a478f9a56f7".decode("hex")
c1="66bbd551d9847c1a10755987b43f8b214ee9c6ec2949eef01321b0bc42cffce6bdbd604924e5cbd99b7c56cf461561186921087fa1e9".decode("hex")
c2="44fc6f82bdd0dff9aca3e0e82cbb9d6683516524c245494b89c272a83d2b88452ec0bfa0a73ffb42e304fe3748896111b9bdf4171903".decode("hex")
print (xor(xor(c1[0:27],c2[0:27]),m[27:54]))

其中会报错:
1
2
3
4
Traceback (most recent call last):
File "...fezexp.py", line 9, in <module>
m="50543fc0bca1bb4f21300f0074990f846a8009febded0b2198324c1b31d2e2563c908dcabbc461f194e70527e03a807e9a478f9a56f7".decode("hex")
AttributeError: 'str' object has no attribute 'decode'

参考链接修改成bytes.fromhex
会报错
1
2
3
4
5
6
Traceback (most recent call last):
File "D:\...\fezexp.py", line 12, in <module>
print (xor(xor(c1[0:27],c2[0:27]),m[27:54]))
File "D:\...\fezexp.py", line 6, in xor
c+=chr(ord(a[i])^ord(b[i]))
TypeError: ord() expected string of length 1, but int found

ord()去掉之后
会报错
1
2
3
4
5
6
7
Traceback (most recent call last):
File "...fezexp.py",line 17, in <module>
print (xor(xor(c1[0:27],c2[0:27]),m[27:54]))
File ""...fezexp.py",line 10, in xor
c+=chr(a[i]^b[i])
TypeError: unsupported operand type(s) for ^: 'str' and 'int'
[Finished in 0.1s]

一开始我纠结了半天,为什么会是’str’ and ‘int’异或,c1[0:27],c2[0:27]),m[27:54]不都是bytes型的吗
小茗大佬叫我去debug,emmmm但是我一次都没debug过,有机会练练…
后来小肥羊看出来,是我第一次异或是正常的,但是函数中return了一个str,bytes传到for循环中是int,所以才会报这个错。
经过小肥羊帮忙,函数内加了个判断,这段代码在sublime运行会报错,而在idle不会报错
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# import os
def xor(a,b):
assert len(a)==len(b)
c=""
print("a:",a,"b:",b)
if type(a) == str:
for i in range(len(a)):
c+=chr(ord(a[i])^b[i])
elif type(a) == bytes:
for i in range(len(a)):
c+=chr(a[i]^b[i])
return c


m=bytes.fromhex("50543fc0bca1bb4f21300f0074990f846a8009febded0b2198324c1b31d2e2563c908dcabbc461f194e70527e03a807e9a478f9a56f7")
c1=bytes.fromhex("66bbd551d9847c1a10755987b43f8b214ee9c6ec2949eef01321b0bc42cffce6bdbd604924e5cbd99b7c56cf461561186921087fa1e9")
c2=bytes.fromhex("44fc6f82bdd0dff9aca3e0e82cbb9d6683516524c245494b89c272a83d2b88452ec0bfa0a73ffb42e304fe3748896111b9bdf4171903")
print(xor(xor(c1[0:27],c2[0:27]), m[27:54]))

所以真的麻烦= =

CBC翻转攻击

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from zio import *
def cbc_bit_attack_mul(c,m,position,target):
l=len(position)
r=c
for i in range(l):
change=position[i]-16
tmp=chr(ord(m[position[i]])^ord(target[i])^ord(c[change]))
r=r[0:change]+tmp+r[change+1:]
return r

target=("106.14.204.93",5009)
io=zio(target)
io.read_until("session=")
session=io.read(16)
io.read_until("checksum=")
c=io.readline().strip()
t1="session="+session+";admin=0"
newchecksum=cbc_bit_attack_mul(c.decode("hex"),t1,[16+16-1],['1'])
io.writeline("session="+session+";admin=1;checksum="+newchecksum.encode("hex"))
io.interact()

CBC选择密文攻击

J3Mi7Q.png

rpd-level0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from zip import *
import time
import random
target=("106.14.204.93",5000)
io=zio(target)

def getstream(times):
for i in range(times-1):
random.randint(0,2**64)
return random.randint(0,2**64)

times=0
now=int(time.time())+10
while 1:
now-=1
times+=1
seed=random.seed(now)
print 1
io.writeline(str(getstream(times)))
if "atum" not in io.readline():
break

rdp-level1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from zio import *
import time
import random
target=("106.14.204.93",5001)

io=zio(target)

v1=int(io.readline().strip())
v2=int(io.readline().strip())
def liner(seed):
return ((seed*25214903917+11) & 0xffffffffffff)

for i in range(0xffff+1):
seed=v1*65536+i
if liner(seed)>>16 == v2:
print seed
print liner(liner(seed))>>16
io.writeline(str(liner(liner(seed))>>16))
print io.readline()

rdp-level2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from zio import *
import time
import random


target=("106.14.204.93",5002)
io=zio(target)

getlist=[]
for i in range(624):
print (i)
io.read_until("#")
io.writeline("1")
getlist.append(int(io.readline().strip()))

import libprngcrack
r=libprngcrack.crack_prng(getlist)
io.read_until("#")
io.writeline(str(r.getrandbits(32)))
io.interact()

需要libprngcrack.py以及java文件

CATALOG
  1. 1. Crypto
    1. 1.1. xbase64
    2. 1.2. shellocode
    3. 1.3. 维吉尼亚密码 卡西斯基试验
    4. 1.4. CBC翻转攻击
    5. 1.5. rpd-level0
    6. 1.6. rdp-level1
    7. 1.7. rdp-level2