본문 바로가기

CTF

[AceBear Security Contest] secure login

AceBear Security Contest secure login Reversing 711pt


실행해보면 현재 시간을 알려주면서 NAME 과 password를 입력받는다.

IDA로 열어보았다.


sub_8048AA3 함수를 먼저 호출 한 뒤에 name 값과 password 값을 입력 받은 후 sub_8048950함수에서 password를 암호화 시킨다.

후에 암호화 시킨 password와 s2(F05664E983F54E5FA6D5D4FFC5BF930743F60D8FC2C78AFBB0AF7C82664F2043) 

값이 같다면 해당 서버에서 플래그를 추출한다.


먼저 sub_8048AA3 함수를 보면 알람 함수가 보이고 key data를 불러오는 함수가 보인다. (key 제일 중요)

그 다음 현재 시간을 기준으로 time(0) 함수로 seed값을 옮겨 srand(seed) 해준다. 

후에 ctime(&seed)를 사용해 시간을 출력한다. 


그 다음 strlen(passwd) == 64와 같이 sub_80488ED함수로 pw를 체크하는데 0~9, a~f, A~F 인지 확인한다. 

왜 이렇게 입력을 받는지는 pw 암호화 함수를 보면 알 수 있다.


여기서 보면 nptr, v9 포인터를 각 0x10씩 할당 해준뒤에 input 과 key를 4byte씩 해당 포인터에 옮긴다.

그 다음 strtoul 함수를 통해 해당 문자열을 16진수 값으로 바꿔주는데 이 부분으로 인해 sub_80488ED 함수의 의문점이 풀린다.

맨 위 함수 sub_8048AA3 에서 srand(seed) 시켜줬기 때문에 rand() 값은 시간에 따라 유동적이다.

암호화 부분을 정리해보면 이렇게 나온다.

key(4byte) * ((v6 ^ input(4byte) ^ rand) + 1) + (v6 ^ input(4byte) ^ rand) 가 된다.

후에 0x40 byte를 할당한 s 배열에 하위 4byte 값을 "%04X" 형태로 넣는다.

즉  (key(4byte) * ((v6 ^ input(4byte) ^ rand) + 1) + (v6 ^ input(4byte) ^ rand)) & 0xffff 가 s에 들어간다.


문제를 본격적으로 풀기전 해야할일은 UTC + 9 (Korea Seoul) 로 되어있는 시간을 UTC+000 으로 바꿔줘야 한다. (rand 값 때문)

터미널 창에 sudo ln -sf /usr/share/zoneinfo/UTC /etc/localtime 입력해주면 정상적으로 시간이 바뀐다.

이제 약간 꼼수를 부려보자면 input 으로 넣은 password는 해쉬 문자열인지와 동시에 64글자 인지 비교해준다.

후에 strtoul 함수로 16진수 값으로 바뀌게 되는데 만약 이 값을 0이 되게 한다면?

key 값을 구할 수 있게된다.


[rand]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
 
int main()
{
   time_t seed = time(0);
   printf("%s\n", ctime(&seed));
   srand(seed);
   for(int i=0; i<16; i++)
   {
      printf("%#x\n", rand());
   }
   return 0;
}
cs

rand 값은 이런식으로 구할 수 있으며 해당 rand 프로그램을 실행시킨 동시에

해당 문제 서버에 접속해 '0' * 64 값을 password에 넣어주고 암호화된 password를 추출해 준다.

이제 brute force를 통해 key를 구할 수 있다.


[Find_key]

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
154
155
156
def brute_force(r, s):
    key = [[24286]]
    for i in range(1len(s)):
        arr = []
        tmp = s[i - 1]
        for j in range(0x10000xffff + 1):
            if (j * ((r[i] ^ tmp) + 1+ (r[i] ^ tmp)) & 0xffff == s[i]:
                arr.append(j)
                # print "%d %d" % (i, j)
        key.append(arr)
    return key
 
 
def change_int(n):
    num = []
    n = n.split('\n')
    for i in range(len(n)):
        num.append(int(n[i], 16))
    return num
 
 
def slide_4char(s):
    str = []
    for i in range(0len(s) + 1):
        if i != and i % == 0:
            str.append(int(s[i - 4: i], 16))
    return str
 
 
if __name__ == "__main__":
    # Fri Feb  2 07:32:19 2018
    r1 = '''0x7041553f
0x7e3b232c
0x15c7f551
0x7cc57f64
0x2184777c
0x137bfa51
0x3f1512b7
0x7c8def4c
0x43b8fd77
0x727ba646
0x708855b6
0x67682eef
0x7c1c7a20
0x12b25cf7
0x7eaf5588
0x6805c94a'''
    s1 = 'C2BF88F3233939770D873B1F911FF61F4F88DD4769E7CC3DF6256D44CF40795B'
 
    # Fri Feb  2 07:32:31 2018
    r2 = '''0x17159667
0x78f3ea8f
0x2710173f
0x68e5c96b
0x7c789d53
0x672618e7
0x2a262650
0x420ebef2
0x1983c445
0x3532fcff
0x3f7fd348
0x20bad53f
0x25548ee4
0x22bfff30
0x728b03d6
0x6b02017a'''
    s2 = '3497EE50551F7DD392757B9F79FF23AFBA4AA7CF969F968D7C41611DA0FB8127'
 
    # Fri Feb  2 07:32:40 2018
    r3 = '''0x7406968a
0x151f07e5
0x43edd2dd
0x59c28bb5
0x30d2b744
0x65d1256f
0xa280872
0x56537d6a
0x79cd34ae
0x56dfd1d2
0x4adcc758
0x1bb288a9
0x33cde739
0x5eea08b4
0x6974b223
0x3cb833ab'''
    s3 = '2D149561A20542C364AF01DF7DBF84EFF6813A5F009FB941F654B0A6AE1D94CB'
 
    # Fri Feb  2 08:21:48 2018
    r4 = '''0x74e2d0d0
0x750ed0b9
0x5ea320f5
0x3127d0c0
0x335c10b6
0x650e4344
0x6fd50e63
0x34774d72
0x7730d37
0x66f7531e
0xb45807
0x3614a82
0x3f38cf5a
0x33095611
0x511cdd14
0x43a65ba'''
    s4 = 'A40E46F72279A2E78FCB0DFFFF9F56AF75B8EC8731934E7B9419DABE9116B103'
 
'''
    # Fri Feb  2 08:26:15 2018
    r5 = 0xc2de2d9
0x19b09e9b
0x55d579a
0x6c5b77de
0x23f1a477
0x5f49176d
0x21206f94
0x1643caea
0xf4a3ce8
0x33ad9bed
0x32d05f2
0x5fcda9ec
0x11527adb
0x1b504c68
0x71ad17c6
0x1fba01a0
    s5 = 'A7E5C4865B45C26FCE850CDF397FE2EF97076B67E8B78C07D42892467BC43763'
'''
 
r1 = change_int(r1)
r2 = change_int(r2)
r3 = change_int(r3)
r4 = change_int(r4)
# r5 = change_int(r5)
 
s1 = slide_4char(s1)
s2 = slide_4char(s2)
s3 = slide_4char(s3)
s4 = slide_4char(s4)
# s5 = slide_4char(s5)
 
bf1 = brute_force(r1, s1)
bf2 = brute_force(r2, s2)
bf3 = brute_force(r3, s3)
bf4 = brute_force(r4, s4)
# bf5 = brute_force(r5, s5)
 
key = []
for i in range(16):
    for a1 in bf1[i]:
        for a2 in bf2[i]:
            for a3 in bf3[i]:
                for a4 in bf4[i]:
                    if a1 == a2 and a2 == a3 and a3 == a4:
                        key.append(a1)
 
print key

cs

하나의 rand 값과 암호화된 pw가지고는 중복되는 key값이 매우 많다.

그러므로 다른 시간마다 rand값과 암호화된 pw값을 4번 정도 추출한 다음 brute force 해주었다.

key = [24286, 10488, 20349, 23555, 38773, 47583, 64543, 34151, 16160, 51255, 22419, 19405, 12220, 18566, 32836, 53651]

원래 key 값은 총 64byte 지만 어차피 암호화 할 때 4byte씩 뭉쳐 strtoul 해준 값으로 암호화 하기 때문에 미리 4byte 붙여서 정수형으로 변환 해준 후 리스트로 정리해줬다.

rand 값이 시간에 따라 유동적이기 때문에 입력할 password 는 시간에 따라 달라져야 한다.

시간에 맞춰 입력할 pw를 위와 같이 brute force를 통해 값을 구한 후 서버에 바로 값을 넣어 flag를 구하였다.


[Solve]

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
from pwn import *
from ctypes import *
import time
 
key = [24286104882034923555387734758364543341511616051255224191940512220185663283653651]
hash = [615262583333781200634270954527506233763917398347149863355794523131874261918259#F05664E983F54E5FA6D5D4FFC5BF930743F60D8FC2C78AFBB0AF7C82664F2043
 
libc = CDLL("libc.so.6")
 
p=remote('securelogin.acebear.site'5001)
seed = libc.time(0)
libc.srand(seed)
=   
pw = '' 
for i in range(16):
        r = libc.rand()
        for j in range(00xffff + 1):
                if (key[i] * ((h ^ r ^ j) + 1+ (h ^ r ^ j)) & 0xffff == hash[i]:
                        pw += "%04X" % j
                        h = hash[i] 
                        break   
 
#print time.asctime(time.localtime(time.time()))
print p.sendlineafter('name: ','gyeongje'),
print p.sendlineafter(': ', pw)
print p.recv(1024)
 
p.interactive()
cs




'CTF' 카테고리의 다른 글

[Codegate 2018] RedVelvet  (0) 2018.02.05
[Codegate 2018] Impel Down  (0) 2018.02.04
[Codegate 2017] EasyCrack 101  (1) 2018.01.30
[Codegate 2017] angrybird  (0) 2018.01.30
[SECCON 2017] JPEG file  (0) 2018.01.20