2.Python实现Base64

搜索Base64算法资料,详细解释该算法。用Python实现它,把自己的学号(字母大写)用Base64编码输出。并且把上面的源代码文件编译成pyc文件。(不要抄袭)

代码:

#Base64的索引与对应字符的关系
Base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
#待编码字符
STR="E41614018"
#转化成list方便处理缺失字节情况
Str=list(STR)
print("明文:  "+STR)
print("Base64:", end='')
#每组三个字符即3*8=24bit,转换为
for i in range(0,len(Str),3):
    a=ord(Str[i])
    #若缺2字节
    if len(Str)-1==i:
        b=0;
    else:
        b=ord(Str[i+1])
    #若缺1or2字节
    if (len(Str)-1==i)|(len(Str)-2==i):
        c=0;
    else:
        c=ord(Str[i+2])

    #拆成4个6bit,计算各自的索引号
    A=  a>>2
    B=((a&0b00000011)<<4)+((b&0b11110000)>>4)
    C=((b&0b00001111)<<2)+((c&0b11000000)>>6)
    D=  c&0b00111111

    #根据索引在Base64寻找,并输出对应字符
    #若缺2字节
    if len(Str)-1==i:
        print(Base64[A]+Base64[B]+'==', end='')
    else:
        #若缺1字节
        if (len(Str)-2==i):
            print(Base64[A]+Base64[B]+Base64[C]+'=', end='')
        else:
            #若不缺字节
            print(Base64[A]+Base64[B]+Base64[C]+Base64[D], end='')
print("\n")

运行结果:

逆hash python代码_Python

输出内容:

明文:  E41614018

Base64:RTQxNjE0MDE4

小结与讨论:

Base64编码算法能够将任意的字节数组数据,通过算法参照“Base64编码索引表”生成只有“大小写英文字母、数字、+、/”(共64个字符)内容表示的字符串数据,即将任意的内容转换为可见的字符串形式。

Base64算法在编码时将数据按照3个字节一组的形式进行处理,每3个字节在编码之后被转换为4个字节。而当数据的长度无法满足3的倍数的情况下,最后的数据需要进行填充操作,即补“=” (这里“=”是填充字符表示没有数据,而不是上述64个字符中包含的字符)。

这里需要注意的是:Base64是编码算法而不是加密算法,只是用来编码字节数组形成字符串的。Base64算法提供了解码功能,并且任何人都可以将Base64的编码结果解码成唯一的原文。

 

3.反编译

找班上学号和你相邻的一位同学要一下上面的pyc文件(不是源代码文件),然后搜索相关反编译工具把pyc反编译成Python源代码,最好能多找几种工具或者途径达到反编译的目的。

①在线反编译平台:https://tool.lu/pyc/:

逆hash python代码_Python_02

②Python反编译工具---Easy Python Decompiler:

逆hash python代码_Python_03

 

反编译失败,系统提示:Magic value mismatch魔法值不匹配。这是因为它只支持python2.7与python3.4以下的版本。

③在线反编译平台http://tools.bugscaner.com/decompyle/

逆hash python代码_Python_04

 

4.Cracking SHA1-Hashed Passwords

去https://www.mysterytwisterc3.org/用组长的学号注册一个账号(字母大写),

完成关卡Cracking SHA1-Hashed Passwords

https://www.mysterytwisterc3.org/en/challenges/level-ii/cracking-sha1-hashed-passwords

代码:

import hashlib
import copy

#递归求解1-8的全排列
def permutation(lst,k):
    result = []
    length = len(lst)
    tmp = [0]*k
    def next_num(a,ni=0):
        if ni == k:
            result.append(copy.copy(tmp))
            return
        for lj in a:
            tmp[ni] = lj
            b = a[:]
            b.pop(a.index(lj))
            next_num(b,ni+1)
    c = lst[:]
    next_num(c,0)
    return result

P=permutation([1,2,3,4,5,6,7,8],8)

SS = [[0 for i in range(4)] for i in range(9)]
S = [[0 for i in range(4)] for i in range(9)]
#放入所有可能选择
SS[1][1]="Q"
SS[1][2]="q"
SS[2][1]="W"
SS[2][2]="w"
SS[3][1]="I"
SS[3][2]="i"
SS[4][1]="N"
SS[4][2]="n"

SS[5][1]="%"
SS[5][2]="5"
SS[6][1]="("
SS[6][2]="8"
SS[6][3]="["
SS[7][1]="="
SS[7][2]="0"
SS[7][3]="}"
SS[8][1]="*"
SS[8][2]="+"
SS[8][3]="~"
flag=0;
#print(len(P),len(P[1]))

#遍历每一种排列情况
for i in range(len(P)):
    if flag==1:
        break;
    #根据排列组成S
    for j in range(len(P[1])):
        if flag==1:
            break;
        S[j+1]=SS[P[i][j]]
    sha1=""
    #print(S)
    #对于每种排列,每个键又有2、3种选择
    #遍历所有选择
    for a in range(1,4):
        #已经找到则退出
        if flag==1:
            break;
        #遇到为0的选项则跳过该可能
        if S[1][a]==0:
            continue
        for b in range(1,4):
            if flag==1:
                break;
            if S[2][b]==0:
                continue
            for c in range(1,4):
                if flag==1:
                    break;
                if S[3][c]==0:
                    continue
                for d in range(1,4):
                    if flag==1:
                        break;
                    if S[4][d]==0:
                        continue
                    for e in range(1,4):
                        if flag==1:
                            break;
                        if S[5][e]==0:
                            continue
                        for f in range(1,4):
                            if flag==1:
                                break;
                            if S[6][f]==0:
                                continue
                            for g in range(1,4):
                                if flag==1:
                                    break;
                                if S[7][g]==0:
                                    continue
                                for h in range(1,4):
                                    if flag==1:
                                        break;
                                    if S[8][h]==0:
                                        continue
                                    string=S[1][a]+S[2][b]+S[3][c]+S[4][d]+S[5][e]+S[6][f]+S[7][g]+S[8][h]        
                                    #计算sha1值
                                    sha1=hashlib.sha1(string.encode('utf-8'))
                                    #print(sha1.hexdigest())
                                    #若相同则输出对应密码
                                    if sha1.hexdigest()=='67ae1a64661ac8b4494666f58c4822408dd0a3e4':
                                        print('We found it : '+S[1][a]+S[2][b]+S[3][c]+S[4][d]+S[5][e]+S[6][f]+S[7][g]+S[8][h])
                                        print(sha1.hexdigest())
                                        flag=1

运行结果:

逆hash python代码_Python_05

结果验证:

密码:(Q=win*5

将密码提交到网站上,提示已经成功解题:

逆hash python代码_反编译_06

小结与讨论:

本题我们求解的基本思路还是暴力破解。仔细观察题目所给输入密码的键盘图:

逆hash python代码_全排列_07

考虑到题目应是短时间内可解的,所以我们做出如下的假设来减少计算量(后来得出的密码也证明假设是合理的)

(1)真正作为密码输入的应该只有Q、W、5、8、0、I、N、+这8个键(当然每个键会有不同的输入),shift键、方向键和右侧数字键都只做到控制作用,并没有实际的字符输入;

(2)不考虑重复按键的情况,否则该问题将无法求解。

于是,我们可以得到如下思路:

①由于我们未知这8个键的敲击顺序,我们要找出其全排列,易知为8的阶乘种;

②其次对于每一种排列情况又会有不同的字符组合,同一个键,如+键,可以输入“+”、“-”、“*”这3种字符。即使对Q之类的字母键也会有“Q”与“q”的区别,所以我们要对这些不同的字符组合进行遍历;

③对于每一种字符组合我们利用hashlib库来计算其sha1值与我们的目的sha1值进行比较,若相同则说明密码已经找到,即破解成功。

 

hint:密码长度为5

代码:

import hashlib
import copy

#递归求解0-4的全排列
def permutation(lst,k):
    result = []
    length = len(lst)
    tmp = [0]*k
    def next_num(a,ni=0):
        if ni == k:
            result.append(copy.copy(tmp))
            return
        for lj in a:
            tmp[ni] = lj
            b = a[:]
            b.pop(a.index(lj))
            next_num(b,ni+1)
    c = lst[:]
    next_num(c,0)
    return result
flag=0;
P=permutation([0,1,2,3,4],5)
#print(P)
#所有字符
SS=['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']

#通过五次循环从字符池中挑选出5个字符(因为题目给出密码为5位)
for a in range(len(SS)-4):
    if flag==1:
        break
    for b in range(1,len(SS)-3):
        if flag==1:
            break
        for c in range(2,len(SS)-2):
            if flag==1:
                break
            for d in range(3,len(SS)-1):
                if flag==1:
                    break
                for e in range(4,len(SS)):
                    if flag==1:
                        break
                    S=SS[a]+SS[b]+SS[c]+SS[d]+SS[e]
                    #对于挑选出的5个字符,进行全排列
                    for i in range(len(P)):
                        s=S[P[i][0]]+S[P[i][1]]+S[P[i][2]]+S[P[i][3]]+S[P[i][4]]
                        sha1=hashlib.sha1(s.encode('utf-8'))
                        #print(sha1.hexdigest())
                        #若相同则输出对应密码
                        if sha1.hexdigest()=='4b58475789e60dbf1a28d638b556a938134644c8':
                            print('We found it : '+s)
                            print(sha1.hexdigest())
                            flag=1
                            break

运行结果:

逆hash python代码_反编译_08