[Crypto] ASIS CTF Finals 2016 - SRPP [Secure Remote Password Protocol]


Average: 2.83
Rating Count: 12
You Rated: Not rated
Points
231
Solves
35
Category
Crypto

Description

Try to crack our super safe cryptography system and find the flag.

nc srpp.asis-ctf.ir 22778

http://asis-ctf.ir/tasks/srpp.txz_baa9ec300fd3488a8417fc849a07c2aaf5a26224

Server.py (given by the challenge)

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

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import socket
import time
from hashlib import *
from thread import *
from Crypto.Util.number import *
from os import urandom
from random import *
from string import *
from secret import password, flag



_port = int(sys.argv[1])
_timeout = 3
_host = ''
_bufsize = 4096

_logfile = open(str(sys.argv[0]) + '.log', 'a')

_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
_socket.bind((_host, _port))
_socket.listen(_bufsize)
_taskname = 'SRPP'
_hash = 'sha512'


def Hash(*args):
a = ':'.join(str(a) for a in args)
return int(sha256(a).hexdigest(), 16)


def getParams(nbit):
N = getPrime(nbit)
g = 2
k = Hash(N, g)
return(N, g, k)


def clientThread(client):
client.send('Bot detection: Are you ready?' + '\n')
A = ''.join([choice(printable[:62]) for x in range(26)])
print A[:4]
msg = 'ASIS needs proof of work to start the ' + _taskname + ' challenge.\n' + _hash.upper() + '(X + "%s").hexdigest() = "%s...",\nX is an alphanumeric string and |X| = 4\nEnter X: ' % (A[4:], sha512(A).hexdigest()[:32])
client.send(msg)
X = client.recv(_bufsize).strip()
if sha256(X + A[4:]).hexdigest() == sha256(A).hexdigest():
client.settimeout(_timeout)
client.send('Good work, Let\'s Go!' + '\n')
nbit = 1024
params = getParams(nbit)
N, g, k = params
email = 'admin@asis-ctf.ir'
client.send('Please login as "admin@asis-ctf.ir" and get the flag:' + '\n')
client.send('Sever is generating the parameters ...' + '\n')
client.send('params = (N, g, k) = ' + str(params) + '\n')

salt = urandom(32)

N, g, _ = params
x = Hash(salt, email, password)
verifier = pow(g, x, N)

while True:
try:
client.send('Send the email address and the public random positive value A seperated by "," as "email, A": ' + '\n')
ans = client.recv(_bufsize).strip()
print ans
try:
email, A = ans.split(',')
A = int(A)
assert (A != 0 and A != N), client.send('Are you kidding me?! :P' + '\n')
assert email == 'admin@asis-ctf.ir', client.send('You should login as admin@asis-ctf.ir' + '\n')
b = getRandomRange(1, N)
B = (k * verifier + pow(g, b, N)) % N

client.send('(salt, public_ephemeral) = (%s, %d) \n' % (salt.encode('base64')[:-1], B))
print gmpy.invert(B)
u = Hash(A, B)

client.send('Send the session key: ' + '\n')
K_client = client.recv(_bufsize).strip()
assert K_client.isdigit(), client.send('Please send a valid positive integer as session key.' + '\n')
K_client = int(K_client)

S_s = pow(A * pow(verifier, u, N), b, N)
K_server = Hash(S_s)

client.send('Send a POC of session key: ' + '\n')
M_client = client.recv(_bufsize).strip()


assert M_client.isdigit(), client.send('Please send valid positive integer as POC.' + '\n')
M_client = int(M_client)

assert (K_server == K_client), client.send('The session key is not correct!' + '\n')
assert (M_client == Hash(Hash(N) ^ Hash(g), Hash(email), salt, A, B, K_client)), client.send('The POC is not correct!' + '\n')

M_server = Hash(A, M_client, K_server) # TODO: check server POC in clinet side

client.send('Great, you got the flag: ' + flag + '\n')
client.close()
break

except:
client.send('Provided input is not valid.' + '\n')
client.send('Quiting ...' + '\n')
client.close()
break

except socket.timeout:
client.send('Timeout! Plase send faster ... \n')
client.close()
break
else:
client.send('Sorry, Bad proof of work! \n')
client.close()


while True:
client, addr = _socket.accept()
start_new_thread(clientThread ,(client,))
s.close()

To solve this you needed to realise that A = 2N ≡ 0 (mod N). The web server was checking only for values like A = 0 or A = N. To beat the system you only need to set the A to A = 2N and set the session key to 0 and hash it:

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

import re
from pwn import *
from string import *
from hashlib import *
from os import urandom
from itertools import product
from Crypto.Util.number import *


def Hash(*args):
a = ':'.join(str(a) for a in args)
return int(sha256(a).hexdigest(), 16)


def is_solution(s, sol):
return sol == sha512(s).hexdigest()[:32]


def parse(s):
#m = re.search('\"[a-zA-Z0-9]*\"', s)
m = re.findall(r'\"[a-zA-Z0-9.]*\"', s)
salt = m[0][1:-1]
first16bytes = m[1][1:-4]
return salt, first16bytes


def regex_parse(regex, s):
m = re.findall(regex, s)
return m


def bot_system(junk):
salt, sol = parse(junk)
chars = digits + ascii_uppercase + ascii_lowercase
for n in range(4, 4 + 1):
for comb in product(chars, repeat=n):
x = ''.join(comb)
if is_solution(x.rstrip() + salt.rstrip(), sol):
r.sendline(x)
return r.recvuntil("Send the email address and the public random positive value A seperated by \",\" as \"email, A\":")
r.sendline("2ewq")
return r.recvline()

if __name__ == '__main__':
email = 'admin@asis-ctf.ir'
context(arch='i386', os='linux')
r = remote('srpp.asis-ctf.ir', 22778)
junk = r.recvuntil('Enter X:')
print junk
junk = bot_system(junk)
print junk
N, g, k = regex_parse(r"[0-9]+", junk)
A = 2 * long(N)
r.sendline('%s,%d' % (email, A))
junk = r.recvuntil("Send the session key:")
print junk
salt, B = regex_parse(
r'(?:[A-Za-z0-9+/]{4}){2,}(?:[A-Za-z0-9+/]{2}[AEIMQUYcgkosw048]=|[A-Za-z0-9+/][AQgw]==|[0-9]+)', junk)
x = Hash(salt.decode('base64'), email, 'x')
u = Hash(A, B)
K_client = str(Hash(0))
r.sendline(K_client)
junk = r.recvuntil("Send a POC of session key:")
print junk
M_client = Hash(Hash(long(N)) ^ Hash(long(g)), Hash(email),
salt.decode('base64'), long(A), long(B), K_client)
r.sendline(str(M_client))
junk = r.recvall(timeout=3)
print junk

# r.sendline(321)
# print r.recvall(timeout=2)

Requirements to run the code above:

capstone==3.0.4
cffi==1.8.2
cryptography==1.5
enum34==1.1.6
idna==2.1
ipaddress==1.0.17
Mako==1.0.4
MarkupSafe==0.23
paramiko==2.0.2
pluggy==0.3.1
psutil==4.3.1
pwn==1.0
pwntools==3.0.2
py==1.4.31
pyasn1==0.1.9
pycparser==2.14
pycrypto==2.6.1
pyelftools==0.24
Pygments==2.1.3
pyserial==3.1.1
PySocks==1.5.7
python-dateutil==2.5.3
requests==2.11.1
ROPGadget==5.4
six==1.10.0
tox==2.3.1
virtualenv==15.0.3

Running it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

(env)kinyabitch@Debian ~/h/c/a/c/SRPP> python srpp.py
[+] Opening connection to srpp.asis-ctf.ir on port 22778: Done
Bot detection: Are you ready?
ASIS needs proof of work to start the SRPP challenge.
SHA512(X + "Qdir2gMmUNfQTEWws7TiiC").hexdigest() = "6ab9e49f8f1666eedbfcd245641494b5...",
X is an alphanumeric string and |X| = 4
Enter X:
Good work, Let's Go!
Please login as "admin@asis-ctf.ir" and get the flag:
Sever is generating the parameters ...
params = (N, g, k) = (150264492626393812114930741471401106498656623083068639913262819178319899775751847281352721734537734815860211276875675213404746620022806433472801532459549667439961097968054640742518648454976403201201715934962422442028556067288440471827328146158430586959765296795581920036648128166307787893201848761850772213819L, 2, 24575437478632421856161724587288271515505936432761108412190739330057705715583L)
Send the email address and the public random positive value A seperated by "," as "email, A":

(salt, public_ephemeral) = (xqP2u8/GnuOlvvwzqQyDSCzKdub3VSlC7hqSVgViCn0=, 58941979940718432698750128575222177241044268927849539714742170613086773456642367825722147824342183209059606531876412131592206870210224884096962602048579555044090406168925997732687622279935969221985354817678067387309953487365627666658193178058756987452583249987259227031087509426824835666790488037514334092494)
Send the session key:

Send a POC of session key:
[+] Receiving all data: Done (66B)
[*] Closed connection to srpp.asis-ctf.ir port 22778

Great, you got the flag: ASIS{7bdb4b540699ef341f4a3b32469cd3f6}