brunch

You can make anything
by writing

C.S.Lewis

by Younggi Seo Apr 26. 2018

Section1: malicious RCE attack

레지스터로 이루어진 CPU의 세계

https://www.youtube-nocookie.com/embed/341VqGbPFk8?rel=0&controls=0


CTF(Capture The Flag)라는 해킹 대회가 있다. 먼저 해킹에 성공해서 문제 해결 종료를 의미하는 깃발을 쟁취하는 취지의 대회 명칭으로 반드시 출제되는 문제가 '버퍼 오버플로우'이다. 버퍼(Buffer)는 말 그대로 해석하면 '완충제'이고 오버플로우(overflow)는 '흘러넘치다'라는 뜻이다. 합치면 "완충제가 제구실을 못하다." 정도 되겠다.



해킹 공격 기법을 접근하기 전에 대다수의 해킹 입문자들은 공격의 유형과 어떻게 이루어지는지의 과정부터 살피는 경우가 많을 거다. 나 또한 시스템 공격 중 상위 레벨의 버그에 해당하는 버퍼오버플로우를 처음 접했을 때 무작정 공격의 행태부터 구글링 했었다.



하지만 꼭 해커가 아니고 개발자라도 어렴풋이 알고만 있는 컴퓨터의 기본 개념을 상기시켜서 이 공격의 의도를 캐는 것은 어렵지 않다(물론 이 공격을 처음 발상해낸 것은 기본 원리만 순순히 암기하고 응용하는 인재풀에서는 해내기 어려울뿐더러 이러한 능력이 단순히 주입식 사고 성적의 내림차순인 학벌을 뛰어넘는 실력이다. 그래서 정형화된 틀에서 벗어나는 것에 끈질기게 매달리는 유형의 사람이 해커다). 공격의 의도를 먼저 캐내고 그다음은 어떻게 실제로 해커가 의도한 원리를 적용하는지 살펴보는 게 특정 시험을 위한 암기를 지양하는 '이해의 절차'가 순리대로 이루어지리라 본다. 근간에 해당하는 큰 그림(시스템 사고)으로 어떻게 돌아가는지 살피고 해당 취지의 프레임(비정형적인 결과 도출을 위한 시각)으로 바꿔서 보면 개념을 수월하게 접근할 수 있다.



먼저 지정된 메모리의 양(버퍼량)을 넘어서 프로그램을 오작동시키게 만드는 공격은 프로그래밍 언어 중 'C'나 오래된 버전의 리눅스 단에서나 가능하다. 자바나 최근에 업데이트를 시킨 윈도에서 만약 이 공격을 성공시킨다면 그 당사자는 메모리의 오버플로우(공격의 메커니즘)될 수 있는 취약점을 방지한 코드나 소프트웨어 애플리케이션을 해킹할 수 있다는 거다. 머리단의 동영상 강좌에서는 프래그래밍에서 호출이 어떻게 이루어지는지 '스택 프레임'을 그리면서 강의하는 UNSW의 교수가 나온다. 함수에서 값을 호출하는 과정을 통해 CPU(Central Processing Unit, 중앙처리장치)의 레지스터에서 프로그램을 어떤 순서로 제어하는지 즉 시스템의 Procedure(절차)가 어떻게 흐르는지의 순서를 알 수 있다.


https://www.youtube.com/watch?v=Q2sFmqvpBe0



위의 동영상은 '스택 호출'의 내용인데 프로그래밍 구동 절차를 메모리의 한 종류인 스택을 그림(Diagram)으로 표현해서 설명해준다(UNSW 교수가 그리면서 말하는 '스택 프레임'과 같다). 그럼, 프로그래밍에서 개발자가 작성한 코드를 해석하고 실행시켜주는 것은 메모리일까, CPU일까? 아무래도 실행을 하기 위해 메모리에 값을 옮기고 하는 과정을 보니 '메모리'라고 할 수도 있겠다. 아니다. 실제로 그 메모리는 CPU 내부(혹은 바깥)의 '레지스터(Register, 단어 뉘앙스가 '기록 장소'라는 느낌이 안 드나?)'라는 저장소이다. 흔히들 메모리라고 불리는 보통 DRAM(Dynamic Random Access Memory, RAM의 한 종류)은 CPU와 떨어져 있고 '메인 메모리(주기억 장치)'를 지칭한다.



메인 메모리(CPU의 레지스터와 별개인)는 앞서 얘기했던 실제로 프로그램의 데이터를 처리(제어 및 연산)하는 레지스터와 연결되어 있으며, 명령어와 데이터를 보관하는 역할을 한다. 그래서 위의 동영상 커버를 장식하고 있는 그림에서 왼쪽은 프로그램 함수(Function,  객체지향 언어에서 처리의 기본 단위)를 각각 나타내는 '프로시저(Procedure, 절차 : 다음 편들에 나오겠지만 어셈블리어의 실행 단위를 프로시저라고 함.)'가 레지스터(오른쪽의 스택 프레임)에 의해 하나씩 메인 메모리 영역에 해당하는 공간에 호출하는 과정이 곧 'Stack Call(스택 호출)'이다. 그리고 메인 메모리는 한 칸에 1바이트씩 구분하고 이렇게 구분하는 메모리의 단위에는 '주소(Address, 번지)'라고 부르는 번호가 붙어 있다. CPU는 이 어드레스를 이용해서 메인 메모리에 보관된 명령어나 데이터를 읽거나 데이터를 기록하기도 한다. 단 보통 시스템의 전원이 갑자기 나가면, 메인 메모리에 기록된 내용은 모두 휘발된(사라진)다.



바탕화면의 프로그램의 아이콘(. exe 확장자를 가진 파일의 바로가기 아이콘)을 더블클릭하면 프로그램이 작동하는데 이때 메인 메모리에 실린(loading, 컴파일한 후의 내용을 적재한) 기계어(Binary Code, 컴퓨터는 0과 1 이진수의 전기적 신호만을 해석할 수 있으므로) 프로그램을 CPU(컴퓨터)가 해석 및 실행해서 컴퓨터 전체를 제어하고, 데이터를 연산한다. 본인이 만든 소스코드를 실행시키면 이 코드가 컴파일(소스 코드를 판독한 후 기계어(Native code)로 번역)이 되어(컴퓨터가 읽을 수 있도록) 기계어인 EXE 파일로 변환(Link라는 절차로 실행 가능한 파일로 생성)하면 프로그램이 실행될 때 이 파일이 하드디스크로부터 메인 메모리에 복사된다. 이때 CPU가 이 프로그램의 내용을 해석하고 실행하는 세부적인 흐름(CPU에 의해 스택이라는 메모리의 한 종류가 자동으로 해석 및 처리하는 과정)이 앞서 동영상들의 과정(함수 호출 시 메모리의 이용 순서)과 같다.

Section 2에 이어서 계속.



참조

Hisao Yazawa. 예승철 역. (2002). 성공과 실패를 결정하는 1%의 프로그래밍 원리: How program works, 서울: 성안당. com.









 


 






매거진의 이전글 함수와 라이브러리 in PYTHON
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari