[ISITDTU 2018] XOR Write-up

2018. 7. 30. 23:07


XOR문제입니다.

많은 사람들이 풀었기때문에 100점까지 낮아졌습니다 ㅠ;;


아니... 어떻게 이걸 더 많이 푼거지 ;;

다른 암호들이 훨씬 빨리 풀리는데 ...


아무튼!


문제는 아래와 같습니다.


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
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from flag import flag,key
 
assert len(key) == 10
 
#padding
if len(flag) % len(key) != 0:
    n = len(key) - len(flag) % len(key)
    for i in range(n):
        flag += " "
 
= []Q
for a in range(len(key)):
    i = a
    for b in range(len(flag)/len(key)):
        if b % 2 != 0:
            m.append(ord(flag[i]) ^ ord(key[a]))
        else:
            m.append(ord(flag[i+len(key)-(a+1+a)])^ ord(key[a]))
        i += len(key)
enc_flag = ""
for j in range(len(m)):
    enc_flag += "%02x" % m[j]
 
print enc_flag
 
#enc_flag = 1d14273b1c27274b1f10273b05380c295f5f0b03015e301b1b5a293d063c62333e383a20213439162e0037243a72731c22311c2d261727172d5c050b131c433113706b6047556b6b6b6b5f72045c371727173c2b1602503c3c0d3702241f6a78247b253d7a393f143e3224321b1d14090c03185e437a7a607b52566c6c5b6c034047
 
cs


키 값도 주고, 문제도 단순합니다. 홀수번째 블록암호가 거꾸로 XOR되기때문에 이를 유의해서 풀면 보통 XOR암호문제와 다를게 없습니다.


그래서 조금 어려운 문제가 아닌가싶었는데;;

대부분이 Bruteforcing으로 잘풀었습니다.(flag형식이 지정되어있기때문에...)

하지만 저는 hamming_distance와  Alphabet score를 이용해서 풀어보았습니다.


먼저 hamming_distance 측정을 통해 평문이 알파벳과 숫자로 구성된 문자열이란 것을 알 수 있습니다.

그래서 Alphabet score를 매기는 방식으로 코드를 짜서 풀었습니다. CTF에 나오는 플래그 형식이 완전히 알파벳이 아니라서 조금 변형시키긴했지만~

그래도 잘 돌아갑니당..ㅎㅎ


관련개념은 추후에 블로그에 올리겠습니다.

그럼 이 글도 조금은 수정되겠져


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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
#Letter Distribution - Exterior Memory  http://www.macfreek.nl/memory/Letter_Distribution
freq = {
' ' : 18.28846265,
'E' : 10.26665037,
'T' : 7.51699827,
'A' : 6.53216702,
'O' : 6.15957725,
'N' : 5.71201113,
'I' : 5.66844326,
'S' : 5.31700534,
'R' : 4.98790855,
'H' : 4.97856396,
'L' : 3.31754796,
'D' : 3.28292310,
'U' : 2.27579536,
'C' : 2.23367596,
'M' : 2.02656783,
'F' : 1.98306716,
'W' : 1.70389377,
'G' : 1.62490441,
'P' : 1.50432428,
'Y' : 1.42766662,
'B' : 1.25888074,
'V' : 0.79611644,
'K' : 0.56096272,
'X' : 0.14092016,
'J' : 0.09752181,
'Q' : 0.08367550,
'Z' : 0.05128469,
 
'1' : 5.66844326#I
'4' : 6.53216702#A
'5' : 5.31700534#S
'3' : 10.26665037,#E
'0' : 6.15957725#O
'_' : 18.28846265,#_
 
'{' : 3.0,
'}' : 3.0,
}
def alphabet_score(stringA):
    score = 0.0
    for c in stringA:
        c=c.upper()
        if c in freq:
            score+=freq[c]
    return score
 
def XOR_singleByte(str1, sbyte):
    result = ""
    for i in range(0,len(str1),2):
        h1 = int(str1[i:i+2],16)
        h2 = sbyte
        result+= '{:02x}'.format(h1^h2)
    return result
 
def XOR_with_Key(str1, Key):
    result = ""
    keylen=len(Key)
    for i in range(0,len(str1),2):
        h1 = int(str1[i:i+2],16)
        h2 = ord(Key[(i/2)%keylen])
        result+= '{:02x}'.format(h1^h2)
    return result
 
def Hamming_distance(str1, str2):
    d = 0
    for i in range(0len(str1)):
        hd = ord(str1[i]) ^ ord(str2[i])
        while hd > 0:
            d += (hd & 0x1)
            hd = hd>>1
    return d
    
enc_flag = "1d14273b1c27274b1f10273b05380c295f5f0b03015e301b1b5a293d063c62333e383a20213439162e0037243a72731c22311c2d261727172d5c050b131c433113706b6047556b6b6b6b5f72045c371727173c2b1602503c3c0d3702241f6a78247b253d7a393f143e3224321b1d14090c03185e437a7a607b52566c6c5b6c034047"
cipher = enc_flag.decode("hex")
 
KEY_LEN = 10
BLOCK_LEN = len(cipher)/KEY_LEN
 
blocks = [""]*BLOCK_LEN
for i in range(len(cipher)):
    blocks[i%BLOCK_LEN]+=cipher[i]
 
ciphers = ["",""]
 
for i, b in enumerate(blocks):
    if i % 2 != 0:
        ciphers[0+= b
    else:
        ciphers[1= b + ciphers[1]
 
        
distance = 0.0
= (len(ciphers[0])/(KEY_LEN))-1
for bsize in range(0,len(ciphers[0])-2*KEY_LEN,KEY_LEN):
    b1=ciphers[0][bsize:bsize+KEY_LEN]
    b2=ciphers[0][bsize+KEY_LEN:bsize+KEY_LEN*2]
    distance += Hamming_distance(b1, b2)
 
d=(distance/(n*KEY_LEN))
 
print("hamming_distance1 : %f" % d)
        
distance = 0.0
= (len(ciphers[1])/(KEY_LEN))-1
for bsize in range(0,len(ciphers[1])-2*KEY_LEN,KEY_LEN):
    b1=ciphers[1][bsize:bsize+KEY_LEN]
    b2=ciphers[1][bsize+KEY_LEN:bsize+KEY_LEN*2]
    distance += Hamming_distance(b1, b2)
 
d=(distance/(n*KEY_LEN))
 
print("hamming_distance2 : %f" % d)    
    
keyString = ""
cipher = ciphers[0]+ciphers[1]
 
for i in range(0, KEY_LEN):
    Max_score = 0.0
    score = 0.0
    key = 0
    for sbyte in range(0,255):
        nCaesar = ""
        for j in range(i, len(cipher), KEY_LEN):
            nCaesar += cipher[j]
        nCaesar = nCaesar.encode("hex")
        nResult = XOR_singleByte(nCaesar, sbyte)
        nomal_string = nResult.decode("hex")
        
        score = alphabet_score(nomal_string)
    
        if score > Max_score:
            Max_score = score
            key = sbyte
    keyString += chr(key)
 
print("KeyString :"),
print(keyString)
 
print("\nPlaintext : ")
plain1 = XOR_with_Key(ciphers[0].encode("hex") ,keyString).decode("hex")
plain2 = XOR_with_Key(ciphers[1].encode("hex") ,keyString).decode("hex")
plain2 = plain2[::-1]
 
plain = ""
for i in range(BLOCK_LEN/2+1):
    plain += plain2[i*KEY_LEN:(i+1)*KEY_LEN] + plain1[i*KEY_LEN:(i+1)*KEY_LEN]
 
print(plain)
cs



'Write-up > Crypto' 카테고리의 다른 글

[CSAW Quals 2017] BabyCrypt Writeup  (0) 2018.09.14
[hackcon18] Ron, Adi and Leonard (Wiener Attack)  (0) 2018.08.18
[ISITDTU 2018] Simple RSA Write-up  (0) 2018.07.30
[ISITDTU 2018] Baby Write-up  (0) 2018.07.30
[MeePwnCTF 2018] bazik  (0) 2018.07.25

+ Recent posts