Quick we need to get access to the bunker and we are running out of time! The door is using an advanced steam-powered door locking mechanism which we cannot breach. One of our scientists managed to make a tool that measures the mechanical stress of the pipes moving steam during the verification of the password and created a power consumption model but it looks like just random signals. Can you find anything useful in the data?
Category: hardware
Solver: rgw
Flag: HTB{c4n7_h1d3_f20m_71m3}
Writeup
In this challenge, we get a remote container as well as some python code that can be used to talk to it. When running the script, the server asks the client for a password. After guessing a password, the server sends some binary data that is interpreted as a 1000-element NumPy array of measurements that looks like this:
[-0.20979757 -0.16274394 -0.30431337 -0.48358536 -0.23253828 -0.199225
-0.35388743 -0.18253244 -0.120403 -0.30962142 -0.48970272 -0.43847888
-0.46813139 -0.15836405 -0.153939 -0.39243379 -0.15445498 -0.23950641
-0.43257999 -0.58911743 -0.08425488 -0.1941009 -0.05628938 -0.16563285
-0.28682638 -0.54433299 -0.26713258 -0.29094738 -0.2016906 -0.00103324
-0.28420763 -0.48121093 -0.48555699 -0.43820257 -0.48621702 -0.05918698
-0.16951941 -0.5318846 -0.59982784 -0.07673312 -0.15018049 -0.24099132
-0.13796123 -0.2872664 -0.1526497 -0.31796715 -0.19353571 -0.35775008
-0.31040582 -0.28919463 -0.4066198 -0.50202594 -0.19568491 -0.19411991
-0.30400802 -0.48653632 -0.1630739 -0.32888972 -0.1641641 -0.30862783
-0.19511367 -0.20058613 -0.49763135 -0.55450173 -0.48074822 -0.49928282
-0.52733085 -0.40796361 -0.16375752 -0.27194523 -0.17078945 -0.24661013
-0.19072903 -0.29251013 -0.12717011 -0.2739726 -0.26580045 -0.39421924
...
-0.12730652 -0.33734566 -0.54149761 -0.14008503 -0.21165112 -0.55421833
-0.2218916 -0.36660566 -0.55732013 -0.20110808 -0.34029531 -0.32260168
-0.12310121 -0.37722785 -0.49553628 -0.15342243 -0.26856934 -0.48974869
-0.25899613 -0.33214945 -0.46055076 -0.1032769 ]
We suspect that when guessing a password that is partially correct, the measurements might differ from the measurements taken when the password contains incorrect characters.
Therefore, we try to use statistics on the measurements: We average the measurement vectors over all letters and subtract the individual vectors from the average. At the end, we compute the absolute value of these differences. While guessing single-letter passwords, we notice that while most chars have an absolute deviation of about 30, one character, H
, has a deviation of 162:
a 39.949657649801225
b 40.714569725158626
c 39.61497940004325
d 39.474006697622215
e 40.29897016028263
f 41.89109899208532
g 40.241643524264596
h 39.309716549203934
i 39.826753110922525
j 39.777182594552954
k 39.984043260288885
l 40.47633608780173
m 40.24759348709958
n 38.12986267742626
o 39.86780215040693
p 38.877102226438495
q 40.05740659718354
r 39.21962494136937
s 38.49766987388506
t 40.75136015479862
u 37.47011649858465
v 39.562042262040976
w 39.760485470084944
x 41.521272764450664
y 40.38963761988974
z 39.494044855249996
A 39.76983364485786
B 38.95036756181348
C 39.870353888659444
D 40.0154409203386
E 38.282992764086416
F 40.88182735993278
G 40.06438310252747
H 162.12007396563763
I 38.40294490783265
J 38.353039747285145
K 39.8239059214363
L 42.0861582308512
M 40.778670231970096
N 41.28603219141854
O 40.181731007751935
P 39.84819858493701
Q 39.96896304132981
R 41.978422895479774
S 39.38199930291793
T 39.065399506199704
U 40.71543270098678
V 39.419632346973536
W 39.28195141479476
X 39.60843822728355
Y 40.985558841970594
Z 39.782674332876205
0 42.02124852746148
1 40.50830029920388
2 40.17730906035423
3 39.95775017387069
4 40.689673535418514
5 41.29425831812978
6 40.643575457603916
7 39.762556561411344
8 41.082097079921425
9 40.9476795039626
! 40.75906409666984
" 40.962444940909904
# 40.085388705516564
$ 41.12138177846864
% 38.85483813133038
& 40.05988767387291
' 38.90183514120064
( 38.476441274792656
) 39.070732636868215
* 38.67164570943267
+ 40.134294920793835
, 40.74501273938988
- 40.89069266048346
. 39.52948594200726
/ 40.037632622120825
: 40.362748698461616
; 42.56763182240383
< 41.25076473654308
= 42.18869178715396
> 40.731563821069386
? 42.52021658053573
@ 42.31315719820586
[ 37.59811557020994
\ 41.16434211160815
] 41.07575097475494
^ 41.06401710669304
_ 39.14158587863376
` 40.95357310946744
{ 38.97310258482758
| 39.63342981398347
} 40.5395185352735
~ 40.75728522823533
Therefore, by looking at the character with the maximum absolute difference, we can guess the correct password one letter at a time.
Our final script looks like this:
#!/usr/bin/env python
import time
import socket
import base64
import numpy as np
from string import ascii_lowercase, ascii_uppercase, digits, punctuation
HOST = '167.172.51.181'
PORT = 32164
def b64_decode_trace(leakage):
byte_data = base64.b64decode(leakage) # decode base64
return np.frombuffer(byte_data) # convert binary data into a NumPy array
def connect_to_socket(option, data):
data = data.encode()
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
resp_1 = s.recv(1024)
s.sendall(option)
resp_2 = s.recv(1024)
s.sendall(data)
resp_data = b''
tmp = s.recv(8096)
while tmp != b'':
resp_data += tmp
tmp = s.recv(8096)
s.close()
return resp_data
def get_power_trace(guess):
leakage = connect_to_socket(b'1', guess)
time.sleep(0.1)
return b64_decode_trace(leakage)
def get_next_char(initial_password):
charset = ascii_lowercase + ascii_uppercase + digits + punctuation
power_traces = {}
for letter in charset:
print(letter, end='', flush=True)
power_traces[letter] = get_power_trace(initial_password+letter)
print()
avg = np.sum(list(power_traces.values()), 0)/len(charset)
absolute_differences = {letter: np.sum(np.absolute(avg-power_traces[letter])) for letter in charset}
return max(absolute_differences, key=absolute_differences.get)
if __name__ == '__main__':
password = ''
while True:
char = get_next_char(password)
password += char
print(password)
if char == '}':
break
After taking some time to run, the final output looks like this:
We get the flag HTB{c4n7_h1d3_f20m_71m3}
.