Sandiman v1
Diberikan dua buah file output
dan encrypt.py
.
Challenge
$ cat output
53 14 14 53 14 22 53 22 14 14 51 14 22 14 21 51 14 22 22 21 14 53 53 22 14 53 53 53 21 14 22 11 14 14 53 51 14 14 53 51 14 53 14 14 53 51 53 51 21 14 53 14 14 22 11 53
import string
import itertools
def adfgvx(val):
val = val.lower()
encode = ""
num = ""
table = ["8","p","3","d","1","n",
"l","t","4","o","a","h",
"7","k","b","c","5","z",
"j","u","6","w","g","m",
"x","s","v","i","r","2",
"9","e","y","0","f","q"]
jumble = "adfgvx"
for char in val:
row = table.index(char) // 6
col = table.index(char) %6
num += str(row) + str(col)
for i in range(len(num)):
tmp = int(num[i])
encode += jumble[tmp]
return encode
def column(key,userval):
try:
assert key.isalpha()
key = key.lower()
userval = userval.lower()
col=len(key)
userval=userval.replace(' ','')
if((len(userval)%col)!=0):
userval+="x"*(len(userval)%col)
o=[]
for i in key:
o.append(i)
h=[]
for i in range(col):
h.append(userval[i:len(userval):col])
dic=dict(zip(o,h))
so=sorted(dic.keys())
yoay = ''.join(dic[i]for i in so)
return yoay
except:
print("Whoops, Wrong maneh. repeat char a?")
def check(key):
key = key.lower()
char = "abcdefghijlkmnopqrstuvwxyz"
for i in char:
count = key.count(i)
if count > 1:
return false
def encryptA(key,userval,counter=2):
key = key.lower()
userval = userval.lower()
col=len(key)
userval=userval.replace(' ','')
if((len(userval)%col)!=0):
userval+="x"*(len(userval)%col)
o=[]
for i in key:
o.append(i)
h=[]
for i in range(col):
h.append(userval[i:len(userval):col])
dic=dict(zip(o,h))
so=sorted(dic.keys())
yeay = ''.join(dic[i]for i in so)
return yeay
def chunker(seq, size):
it = iter(seq)
while True:
chunk = tuple(itertools.islice(it, size))
if not chunk:
return
yield chunk
def prepare_input(dirty):
dirty = ''.join([c.upper() for c in dirty if c in string.ascii_letters])
clean = ""
if len(dirty) < 2:
return dirty
for i in range(len(dirty)-1):
clean += dirty[i]
if dirty[i] == dirty[i+1]:
clean += 'X'
clean += dirty[-1]
if len(clean) & 1:
clean += 'X'
return clean
def generate_table(key):
alphabet = "ABCDEFGHIKLMNOPQRSTUVWXYZ"
table = []
for char in key.upper():
if char not in table and char in alphabet:
table.append(char)
for char in alphabet:
if char not in table:
table.append(char)
return table
def encryptC(plaintext, key):
table = generate_table(key)
plaintext = prepare_input(plaintext)
ciphertext = ""
for char1, char2 in chunker(plaintext, 2):
row1, col1 = divmod(table.index(char1), 5)
row2, col2 = divmod(table.index(char2), 5)
if row1 == row2:
ciphertext += table[row1*5+(col1+1)%5]
ciphertext += table[row2*5+(col2+1)%5]
elif col1 == col2:
ciphertext += table[((row1+1)%5)*5+col1]
ciphertext += table[((row2+1)%5)*5+col2]
else:
ciphertext += table[row1*5+col2]
ciphertext += table[row2*5+col1]
return ciphertext
def encryptB(plain):
try:
assert plain.isalpha()
plain = plain.lower()
for char in plain:
row = int((ord(char) - ord('a')) / 5) + 1
col = ((ord(char) - ord('a')) % 5) + 1
if char == 'k':
row = row - 1
col = 5 - col + 1
elif ord(char) >= ord('j'):
if col == 1 :
col = 6
row = row - 1
col = col - 1
print(row, col, end =' ', sep ='')
print("")
except:
print("Opps, Somethin Went Wrong")
if __name__ == "__main__":
plain = input("plain: ")
key = "Hology"
keyC = "momogi"
shift = 16
A = encryptA(key,plain)
C = encryptC(A,keyC)
D = ""
plain = plain.upper()
print(plain)
for i in range(len(plain)):
tmp = ord(plain[i]) + (shift%26)
if(tmp > 90):
D += chr((tmp + 65) % 91)
else:
D += chr(tmp)
keyE = "arek"
E = adfgvx(D)
E = column(keyE,E)
encryptB(E)
Solution
Terdapat banyak fungsi pada kode program. Jujur saja, saya sempat melakukan trace dengan perlahan untuk memahami alur enkripsi. Namun karena banyaknya fungsi enkripsi (meskipun key
diketahui), alhasil saya menyelesaikan challenge ini secara black-box.
Implementation
import string
import itertools
def adfgvx(val):
val = val.lower()
encode = ""
num = ""
table = ["8","p","3","d","1","n",
"l","t","4","o","a","h",
"7","k","b","c","5","z",
"j","u","6","w","g","m",
"x","s","v","i","r","2",
"9","e","y","0","f","q"]
jumble = "adfgvx"
for char in val:
row = table.index(char) // 6
col = table.index(char) %6
num += str(row) + str(col)
for i in range(len(num)):
tmp = int(num[i])
encode += jumble[tmp]
return encode
def column(key,userval):
try:
assert key.isalpha()
key = key.lower()
userval = userval.lower()
col=len(key)
userval=userval.replace(' ','')
if((len(userval)%col)!=0):
userval+="x"*(len(userval)%col)
o=[]
for i in key:
o.append(i)
h=[]
for i in range(col):
h.append(userval[i:len(userval):col])
dic=dict(zip(o,h))
so=sorted(dic.keys())
yoay = ''.join(dic[i]for i in so)
return yoay
except:
print("Whoops, Wrong maneh. repeat char a?")
def check(key):
key = key.lower()
char = "abcdefghijlkmnopqrstuvwxyz"
for i in char:
count = key.count(i)
if count > 1:
return false
def encryptA(key,userval,counter=2):
key = key.lower()
userval = userval.lower()
col=len(key)
userval=userval.replace(' ','')
if((len(userval)%col)!=0):
userval+="x"*(len(userval)%col)
o=[]
for i in key:
o.append(i)
h=[]
for i in range(col):
h.append(userval[i:len(userval):col])
dic=dict(zip(o,h))
so=sorted(dic.keys())
yeay = ''.join(dic[i]for i in so)
return yeay
def chunker(seq, size):
it = iter(seq)
while True:
chunk = tuple(itertools.islice(it, size))
if not chunk:
return
yield chunk
def prepare_input(dirty):
dirty = ''.join([c.upper() for c in dirty if c in string.ascii_letters])
clean = ""
if len(dirty) < 2:
return dirty
for i in range(len(dirty)-1):
clean += dirty[i]
if dirty[i] == dirty[i+1]:
clean += 'X'
clean += dirty[-1]
if len(clean) & 1:
clean += 'X'
return clean
def generate_table(key):
alphabet = "ABCDEFGHIKLMNOPQRSTUVWXYZ"
table = []
for char in key.upper():
if char not in table and char in alphabet:
table.append(char)
for char in alphabet:
if char not in table:
table.append(char)
return table
def encryptC(plaintext, key):
table = generate_table(key)
plaintext = prepare_input(plaintext)
ciphertext = ""
for char1, char2 in chunker(plaintext, 2):
row1, col1 = divmod(table.index(char1), 5)
row2, col2 = divmod(table.index(char2), 5)
if row1 == row2:
ciphertext += table[row1*5+(col1+1)%5]
ciphertext += table[row2*5+(col2+1)%5]
elif col1 == col2:
ciphertext += table[((row1+1)%5)*5+col1]
ciphertext += table[((row2+1)%5)*5+col2]
else:
ciphertext += table[row1*5+col2]
ciphertext += table[row2*5+col1]
return ciphertext
def encryptB(plain):
result = ''
try:
assert plain.isalpha()
plain = plain.lower()
for char in plain:
row = int((ord(char) - ord('a')) / 5) + 1
col = ((ord(char) - ord('a')) % 5) + 1
if char == 'k':
row = row - 1
col = 5 - col + 1
elif ord(char) >= ord('j'):
if col == 1 :
col = 6
row = row - 1
col = col - 1
result += "{}{} ".format(row, col)
return result.strip()
except:
print("Opps, Somethin Went Wrong")
def cek_similar(a, b):
a = a.split()
b = b.split()
score = 0
for i,j in zip(a,b):
if i==j:
score+=1
return score
if __name__ == "__main__":
ct = open('sandiman1.enc').read()
print(ct)
flag = ''
while True:
maxscore = 0
benar = 'z'
for ch in 'ABCDEFGHIKLMNOPQRSTUVWXYZ'.lower():
pload = 'a'*(27 - len(flag)) + ch + flag
plain = pload
key = "Hology"
keyC = "momogi"
shift = 16
A = encryptA(key,plain)
C = encryptC(A,keyC)
D = ""
plain = plain.upper()
for i in range(len(plain)):
tmp = ord(plain[i]) + (shift%26)
if(tmp > 90):
D += chr((tmp + 65) % 91)
else:
D += chr(tmp)
keyE = "arek"
E = adfgvx(D)
E = column(keyE,E)
z = encryptB(E)
score = cek_similar(ct, z)
if score > maxscore:
maxscore = score
benar = ch
if len(z) > len(ct):
break
flag += benar
print(flag[::-1])
$ python solve-sandiman-v1.py
53 14 14 53 14 22 53 22 14 14 51 14 22 14 21 51 14 22 22 21 14 53 53 22 14 53 53 53 21 14 22 11 14 14 53 51 14 14 53 51 14 53 14 14 53 51 53 51 21 14 53 14 14 22 11 53
a
ra
ora
tora
ptora
yptora
ryptora
cryptora
ecryptora
decryptora
odecryptora
rodecryptora
prodecryptora
eprodecryptora
reprodecryptora
ireprodecryptora
uireprodecryptora
quireprodecryptora
equireprodecryptora
requireprodecryptora
trequireprodecryptora
ptrequireprodecryptora
yptrequireprodecryptora
ryptrequireprodecryptora
cryptrequireprodecryptora
dcryptrequireprodecryptora
ldcryptrequireprodecryptora
oldcryptrequireprodecryptora
Submit dan muncul alert flag salah. Hapus karakter terakhir, submit, dan flag benar.
Flag
oldcryptrequireprodecryptor
Sandiman v2
Challenge ini merupakan lanjutan dari seri Sandiman v1.
Challenge
Diberikan dua buah file output
dan encrypt.py
.
$ cat output
I think this is safe enough: sapmbe.ahlesulue.n..
secured flag: 4e8ac1f39c798068cd0190dab44146a2
from Crypto.Cipher import AES
import sys
import binascii
import random
IV = "4n0t3rkeybr0sist"
def encrypt(msg,phrase):
aes = AES.new(phrase, AES.MODE_CBC,IV)
return aes.encrypt(msg)
W = 5
perm = range(W)
random.shuffle(perm)
msg = open("rawkey.txt").read().strip()
raw = open("rawkey.txt").read().strip()
while len(msg) % (2*W):
msg += "."
for i in xrange(100):
msg = msg[1:] + msg[:1]
msg = msg[0::2] + msg[1::2]
msg = msg[1:] + msg[:1]
res = ""
for j in xrange(0, len(msg), W):
for k in xrange(W):
res += msg[j:j+W][perm[k]]
msg = res
print "I think this is safe enough: " + msg
key = raw
data = binascii.hexlify(encrypt(sys.argv[1],key))
print "secured flag: " + data
Solution
Intinya, program tersebut memiliki alur enkripsi sebagai berikut:
- Membuka file
rawkey.txt
. File ini menjadi key di fungsi encrypt. - Padding
rawkey
dengan karakter titik hingga panjangrawkey
menjadi kelipatan 10. Dilihat dari output yang dihasilkan program, panjangrawkey
adalah 20 karakter (16 karakterrawkey
+ 4 karakter hasil padding), lalu disimpan dalam variabelmsg
. - Isi dari variabel
msg
‘dihancurkan’ dengan loop sebanyak 100x. Encrypted msg
ditampilkan di output.
How to solve?
- Generate dummy plaintext sebanyak 16 karakter + 4 karakter padding, simpan ke sebuah variabel, misal variabel
pp
. - Generate seluruh kemungkinan
perm
, gunakan modulepermutations
pada packageitertools
agar mempermudah pengerjaan. - Untuk semua kemungkinan
perm
, ‘hancurkan’ variabelpp
dengan loop 100x, lalu bandingkan posisi karakter paddingnya. Jika sesuai, maka didapat perm yang benar. - Jika sudah ditemukan, recover isi dari
rawkey
dengan membandingkannya dengan stringsapmbe.ahlesulue.n..
. - Dekripsi ciphertext yang diberikan dengan key yang didapat dan IV yang diberikan.
- Enjoy.
Implementation
from Crypto.Cipher import AES
import itertools, string
IV = "4n0t3rkeybr0sist"
def ubah(a,b,c):
res = ''
for i in a:
res += c[b.index(i)]
return res
def decrypt(msg,phrase):
aes = AES.new(phrase, AES.MODE_CBC,IV)
return aes.decrypt(msg)
W = 5
pp = string.lowercase[:16] + '.'*4
c = 'sapmbe.ahlesulue.n..'
perms = list(itertools.permutations(range(W), W))
for perm in perms:
msg = pp
for i in xrange(100):
msg = msg[1:] + msg[:1]
msg = msg[0::2] + msg[1::2]
msg = msg[1:] + msg[:1]
res = ""
for j in xrange(0, len(msg), W):
for k in xrange(W):
res += msg[j:j+W][perm[k]]
msg = res
if msg[6] == '.' and msg[16] == '.' and msg.endswith('..'):
print 'perm = {}'.format(perm)
print 'message = {}'.format(msg)
key = ubah(pp, msg, c).strip('.')
pt = decrypt('4e8ac1f39c798068cd0190dab44146a2'.decode('hex'), key)
print 'plaintext = {}'.format(pt)
$ python solve-sandiman2.py
perm = (3, 2, 4, 1, 0)
message = jhldef.cpnkimgoa.b..
plaintext = 3asyKn0wnIVKeyzz
Flag
3asyKn0wnIVKeyzz