ctfshow刷題記錄-cry方向-1

天道酬勤(暑假游泳版)發表於2024-03-04

0x00

題目來源:ctfshow 菜狗杯 crypto方向 base47
題目描述:
神必字元: E9CVT+HT5#X36RF4@LAU703+F$E-0N$@68LMXCVDRJJD5@MP#7MUZDTE?WWLG1S#L@+66H@59KTWYK8TW0RV
神必字典:
0123456789ABCDEFGHJKLMNPQRSTUVWXYZ?!@#$%^&*-+

0x01

第一次做這種base換表的題目,在網上查了查相關wp,感覺自己對base家族還不太熟悉,於是自己先用py寫了個base64的加解密的指令碼,程式碼如下:

string1 = "E9CV^T+HT5#X36RF4@LAU703+F$E-0N$@68LMXCVDRJJD5@MP#7MUZDTE?WWLG1S#L@+^66H@59KTWYK8TW0RV"
test_string = "abc123"
dict1 = "0123456789ABCDEFGHJKLMNPQRSTUVWXYZ?!@#$%^&*-+"


def base64_encode(test_string):
    dict2 = ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")# base64表
    temp_string = str()
    for i in test_string:  # 字元->二進位制ascii碼, 放到temp_string裡
        temp_string += bin(ord(i))[2:].zfill(8)
    temp_list = list() 
    if len(test_string) % 3 == 1:
        temp_string += "0000"
    if len(test_string) % 3 == 2:
        temp_string += "00"
    while temp_string!='':
        temp_list.append(temp_string[0:6])
        temp_string=temp_string[6:]
    fina_list = list()  # 以這些6位的二進位制數值查詢base表,存到fina_list中
    for i in range(0, len(temp_list)):
        fina_list.append(dict2[int(temp_list[i], 2)])
    fina_string = str()
    for i in fina_list:  # 轉化成字串fina_string
        fina_string +=  i
    if len(test_string) % 3 == 1:
        fina_string += "=="
    if len(test_string) % 3 == 2:
        fina_string += "="
    return fina_string

'''print("asfaegqfa123:", base64_encode("asfaegqfa123"), "YXNmYWVncWZhMTIz"==base64_encode("asfaegqfa123"))
print("asfaegqfa12:", base64_encode("asfaegqfa12"), "YXNmYWVncWZhMTI="==base64_encode("asfaegqfa12"))
print("asfaegqfa1231:", base64_encode("asfaegqfa1231"), "YXNmYWVncWZhMTIzMQ=="==base64_encode("asfaegqfa1231"))'''


def base64_decode(string):
    #dict2 = "0123456789ABCDEFGHJKLMNPQRSTUVWXYZ?!@#$%^&*-+"
    dict2="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    list2 = list(dict2)
    temp_string=str()
    if string[-1] == "=" and string[-2] == "=":
        string = string[0 : len(string) - 2]
    if string[-1] == "=" and string[-2] != "=":
        string = string[0 : len(string) - 1]
    for i in string:  # 字元轉二進位制碼
        temp_string+=str(bin(list2.index(i))[2:].zfill(6))
    length=len(temp_string)
    if length%8==2:
        temp_string=temp_string[0:length-2]
    if length%8==4:
        temp_string=temp_string[0:length-4]
    fina_list=list()
    while temp_string!='':   #每八位分一組  放入fina_list中
        fina_list.append(temp_string[0:8])
        temp_string=temp_string[8:] 
    fina_string=str()
    for i in fina_list:
        fina_string+=chr(int(i,2))
    return fina_string

'''print("asfaegqfa123"==base64_decode("YXNmYWVncWZhMTIz"))
print("asfaegqfa12" == base64_decode("YXNmYWVncWZhMTI="))
print("asfaegqfa1231"==base64_decode(""))'''
`

後來問了問王師傅,基本理解了base的本質其實就是進位制轉換,每個字串都對應一串256進位制的數字(一個字元都是8bit,用ascii解碼方式) 回過頭來看題目,這個其實就是base45加密的字串,思路應該是密文中每個字元對應字典的下標這一串數字是len(字典)進位制的,先轉成10進位制,再轉ascii碼字串即可,指令碼程式碼如下:

import libnum
cipher = "E9CV^T+HT5#X36RF4@LAU703+F$E-0N$@68LMXCVDRJJD5@MP#7MUZDTE?WWLG1S#L@+^66H@59KTWYK8TW0RV" 
key = "0123456789ABCDEFGHJKLMNPQRSTUVWXYZ?!@#$%^&*-+"
sum=0
for i in range(len(cipher)):
    sum+=key.index(cipher[i])*pow(len(key),len(cipher)-1-i)
flag=libnum.n2s(sum)
print(flag)

0x02

由這道題引發的思考,可不可以做一個base任意數字的編碼,由上述原理寫出了一個basexx加解密的指令碼,程式碼如下:

import libnum
def base_xx_decode(cipher):
    # key為任意對映表 
    # key = "0123456789ABCDEFGHJKLMNPQRSTUVWXYZ?!@#$%^&*-+"  
    key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"  #base64表
    sum = 0
    for i in range(len(cipher)):
        sum += key.index(cipher[i]) * pow(len(key), len(cipher) - 1 - i)  #len(key)進位制轉10進位制
    flag = libnum.n2s(sum)    #ascii值轉字串
    return flag
print(base_xx_decode("YWJjMTIz"))       # just an example  =='abc123'

def base_xx_encode(plaintext):
    key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    beichushu = libnum.s2n(plaintext)
    cipher=str()
    chushu = len(key)   #給chushu yushu shang beichushu賦初值  然後輾轉相除法進行10進位制轉len(key)進位制,並直接對映到cipher裡
    yushu = beichushu % chushu
    shang = beichushu // chushu
    beichushu = shang
    cipher += key[yushu]
    while shang != 0:
        yushu = beichushu % chushu
        shang = beichushu // chushu
        beichushu = shang
        cipher += key[yushu]
    cipher=cipher[::-1]
    return cipher
print(base_xx_encode("abc123"))  # just an example   =='YWJjMTIz' 

這個指令碼只能加解密無填充規則且ascii編碼的那種,比如base64就是無“=”