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(1, len(s)): arr = [] tmp = s[i - 1] for j in range(0x1000, 0xffff + 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(0, len(s) + 1): if i != 0 and i % 4 == 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 = [24286, 10488, 20349, 23555, 38773, 47583, 64543, 34151, 16160, 51255, 22419, 19405, 12220, 18566, 32836, 53651] hash = [61526, 25833, 33781, 20063, 42709, 54527, 50623, 37639, 17398, 3471, 49863, 35579, 45231, 31874, 26191, 8259] #F05664E983F54E5FA6D5D4FFC5BF930743F60D8FC2C78AFBB0AF7C82664F2043 libc = CDLL("libc.so.6") p=remote('securelogin.acebear.site', 5001) seed = libc.time(0) libc.srand(seed) h = 0 pw = '' for i in range(16): r = libc.rand() for j in range(0, 0xffff + 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 |