최근 참 많은 일이 있었다. 퇴사 → 신사업 준비 → 취업 준비 .. 다사다난했지만 잠깐 쉬어가는 타이밍이라 생각하니 마음이 편안하다. 오히려 좋아!
딱히 조급한 마음도 없고, 내 자신에 대한 확신도 있고, 기쁜 일들도 많고, 그래서 요즘이 가장 행복한 시기인 것 같다. 그리고 좋은 사람들 덕분에 이런 저런 제안들도 많이 들어오고 있다. 감사한 일이다. 면접만 잘 본다면 올 하반기에 취업할 수 있을 것 같은데, 내가 하기 나름이니까 열심히 해봐야지.
주로 노션을 쓰다보니 Velog 관리를 소홀히 하게 된다. oopy로 노션 자체를 호스팅 해야 하나 싶기도 하고 .. 매번 포스팅을 옮기는 과정이 생각보다 귀찮아서 고민을 좀 해봐야겠다.
보안 업무를 하다 보면, 가끔 바이너리 보호 기법을 리스팅해야 하는 일이 생기기도 한다. 그럴 때 주로 사용하는 도구가 checksec
이며, PIE, RELRO, Canaries, ASLR, Fortify Source의 활성화 여부를 확인해주는 bash 스크립트이다. 나는 CTF 플레이어가 아니지만, CTF 할 때 가장 많이 사용하는 듯하다.
아무쪼록 다음과 같은 checksec
수행 결과를 엑셀 테이블로 변환하여 저장하는 코드를 작성해 보자.
$ pip install openpyxl # python
$ pip3 install openpyxl # python3
openpyxl 패키지는 엑셀 작업을 수행할 수 있도록 도와주는 파이썬 패키지이다.
Canary
와 PIE
가 없는 것만을 파싱하여 기재하고, 나머지는 -로 표기할 것이다. 해당 코드를 실행하기 전에 checksec
수행 결과를 log.txt
라는 파일로 저장해 놓아야 한다.
import openpyxl
import re
class Excel:
def __init__(self):
self.workbook = openpyxl.Workbook()
self.sheet = self.workbook.active
self.initialize()
def initialize(self):
self.row = 2
title_list = ['No.', 'FILENAME', 'RELRO', 'STACK CANARY', 'NX', 'PIE', 'RPATH', 'RUNPATH']
ascii_list = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
index = 1
for title in title_list:
self.sheet.cell(row = 1, column = index).value = title
index = index + 1
for ascii in ascii_list:
if ascii == 'B':
width = 40
elif ascii == 'A':
width = 5
else:
width = 20
self.sheet.column_dimensions[ascii].width = width
def parse(self):
f = open('log.txt', 'r')
data = f.read()
data_split = data.split('\n')[1::2]
return data_split
def write(self, filename, flag):
if flag['Canary'] and flag['PIE']:
return
self.sheet.cell(row = self.row, column = 2).value = filename
if not flag['Canary']:
self.sheet.cell(row = self.row, column = 4).value = 'No canary found'
else:
self.sheet.cell(row = self.row, column = 4).value = '-'
if not flag['PIE']:
self.sheet.cell(row = self.row, column = 6).value = 'No PIE'
else:
self.sheet.cell(row = self.row, column = 6).value = '-'
if not flag['RELRO']:
self.sheet.cell(row = self.row, column = 3).value = 'No RELRO'
else:
self.sheet.cell(row = self.row, column = 3).value = '-'
if not flag['NX']:
self.sheet.cell(row = self.row, column = 5).value = 'NX disabled'
else:
self.sheet.cell(row = self.row, column = 5).value = '-'
if not flag['RPATH']:
self.sheet.cell(row = self.row, column = 7).value = 'No RPATH'
else:
self.sheet.cell(row = self.row, column = 7).value = '-'
if not flag['RUNPATH']:
self.sheet.cell(row = self.row, column = 8).value = 'No RUNPATH'
else:
self.sheet.cell(row = self.row, column = 8).value = '-'
self.sheet.cell(row=self.row, column = 1).value = self.row - 1
# self.sheet.cell(row=self.row, column = 3).value = '-'
# self.sheet.cell(row=self.row, column = 5).value = '-'
# self.sheet.cell(row=self.row, column = 7).value = '-'
# self.sheet.cell(row=self.row, column = 8).value = '-'
self.row = self.row + 1
print(f'[*] {filename} : row {self.row} added')
def set_flag(self, line):
flag = {
'RELRO' : True,
'Canary' : True,
'NX' : True,
'PIE' : True,
'RPATH' : True,
'RUNPATH' : True
}
if 'No canary found' in line:
flag['Canary'] = False
if 'No PIE' in line:
flag['PIE'] = False
if 'No RELRO' in line:
flag['RELRO'] = False
if 'NX disabled' in line:
flag['NX'] = False
if 'No RPATH' in line:
flag['RPATH'] = False
if 'No RUNPATH' in line:
flag['RUNPATH'] = False
return flag
def check(self, line):
filename = re.split(r' {2,}', line)[-1].split('\t')[-1].split('/')[-1]
flag = self.set_flag(line)
self.write(filename, flag)
def run(self):
data_split = self.parse()
for line in data_split:
self.check(line)
self.save()
def save(self):
self.workbook.save('result.xlsx')
if __name__ == "__main__":
excel = Excel()
excel.run()
실행 흐름을 따라가며 각 함수의 기능에 대해 알아보도록 하자.
def run(self):
data_split = self.parse()
for line in data_split:
self.check(line)
self.save()
Excel
클래스 생성 후 가장 먼저 호출하는 함수. 모듈화 해 놓은 각 기능들을 한 번에 호출하는 용도로 만들어 두었다. parse, check, save 순으로 실행됨.
def parse(self):
f = open('log.txt', 'r')
data = f.read()
data_split = data.split('\n')[1::2]
return data_split
log.txt 파일을 열어서 개행문자 \n
를 기준으로 데이터를 쪼갠다. 참고로 아래 사진을 보면 두 줄 간격으로 의미 있는 데이터가 존재한다. 따라서 [1::2]
과 같이 간격을 두고 split
하여 저장하였다.
def check(self, line):
filename = re.split(r' {2,}', line)[-1].split('\t')[-1].split('/')[-1]
flag = self.set_flag(line)
self.write(filename, flag)
정규표현식으로 파일 이름을 가져온 뒤, set_flag
함수를 호출하여 보호 기법 활성화 여부를 체크한다. 그리고 write
함수에서 self.sheet.cell(row = self.row, column = N).value
의 값을 지정해준다. (각 셀에 데이터를 채우는 과정임)
def save(self):
self.workbook.save('result.xlsx')
self.workbook
은 openpyxl
패키지에서 제공되는 객체이다. workbook: 엑셀 파일, worksheet: 엑셀 시트 cell: 엑셀 한 칸 이라고 생각하면 될 것 같다. 아무튼 result.xlsx
라는 파일로 저장하면 모든 과정은 끝난다.
파일명은 가렸고, 다음과 같이 Canary
와 PIE
가 비활성화 된 바이너리 리스트만 출력할 수 있었다. 이렇게 필터링 해서 뽑아놓고 세부적으로 점검하면 되겠지. python
으로 툴링하는 게 왜 이렇게 재미있는지 모르겠다. 마법같은 언어야.