※ 질문/내용오류/공유할 내용이 있다면 jinkilee73@gmail.com으로 메일 주세요 :-)


Procedure Call 관련해서 잘못된 내용을 공부하다가 우연히 발견했다. assembly language에서 call 명령어에 대한 설명이 잘못 되어있었다.


http://operatingsystems.tistory.com/entry/SP-Procedure-Call


위의 링크이고 해당 내용은 수정해놓았다.

'Correction' 카테고리의 다른 글

[Correction] Ensemble : Bagging, Random Forest and Boosting  (0) 2016.09.11
[Correction] Symbol and Symbol Tables  (0) 2014.04.02
[Correction] Procedure Call  (0) 2013.11.10
[Correction] NW-TCP-and-UDP  (0) 2013.09.17
[Correction] NW-IP-header  (0) 2013.08.21
시작하며  (0) 2013.08.21
Posted by 빛나유

댓글을 달아 주세요

※ 질문/내용오류/공유할 내용이 있다면 jinkilee73@gmail.com으로 메일 주세요 :-)


아 요즘 참 공부 복잡하다. 슬럼프인가..? 무슨 공부를 해야하는지 너무 고민되고 하다가 Exploit을 공부하기로 했다. 얼마전에 Exploit 공부하면서 너무 재밌어서 Maybe에서 하자고 했다. 기존에 공부하던 커널은 어쩌고? 우선 잠시 미루자. 제 커널 포스팅을 기다리고 계셨던 독자님들 죄송합니다ㅠㅠ 그래도 공부하면서 조금씩 커널에 관한 이야기는 올라올 겁니다. 사실 올릴 이야기도 많이 있고요.


그래도 Maybe에서 Exploit을 공부하기로 했으니 Assembly를 다시 복습할 수 밖에 없었다. 기본적인 것은 이해하고 있으나 조금 더 구체적으로 공부를 다시 해보고 싶었다. 그래서 Procedure Call을 다시 복습했고 그 외의 명령어들에 대한 복습도 조금씩 했다.


Procedure Call에 대해서는 아래의 링크에서 아주 자세하게 설명해놨다.

http://operatingsystems.tistory.com/entry/SP-Procedure-Call


위의 내용과 관련하여 추가적으로 정리하고 싶은 것은 전체적인 스택의 구조이다. 위의 링크에서는 각각의 메모리가 어떤식으로 값이 저장되는지 어떤식으로 다시 이전의 프레임으로 돌아오는지에 대한 이야기는 구체적으로 잘 적혀있지만 전체적인 그림은 없다. 그 전체적인 그림이 아래의 그림과 같다.



친절하게 같은 그림을 두 개 그려서 실제로 어떤 식으로 값이 들어가 있는지 오른쪽 그림에서 볼 수 있다. sum함수의 stack frame과 main 함수의 stack frame 그 경계에 어떤 값이 있으며 그 양쪽으로 어떤 값이 늘어서는지 잘 보고 그 구조를 이해한 후 외워야 한다.


위의 그림을 보면 두 함수의 경계에서 caller함수인 main함수 쪽에는 eip값이 들어가 있고 callee함수인 sum함수 쪽에는 main함수 stack frame의 가장 bottom address인 main의 %ebp가 들어있다. 그리고 eip값 이전에는 sum함수를 호출하기 위해 쓰일 argument들이 쌓여있다. 마지막으로 main의 %ebp 다음에는 sum함수에서 쓰일 변수들이 쌓여있다.


저 구조를 머리 속에 외워두면 실제 어셈블리 코드를 작성할 수도 있다. 정말이냐고? 정말이다. 그래서 간단한 프로그램을 직접 어셈블리 언어로 작성해봤다. 간단하게 hello world를 10번 출력하는 프로그램이다.



첫번째 이렇게 코딩을 해서 실행을 시켜보니까 아래와 같은 에러가 발생했다.


위의 에러가 발새하는 이유를 읽어보면 main에 대한 reference가 정의되지 않았다고 하는데...

나는 사실 여기서 생각했다. 조금더 알기 위해서는 elf 파일 포멧에 대해서 공부를 해야되겠다고. 이것을 보자마자 예전에 시스템 프로그래밍 공부했을 때 봤던 책을 펴서 elf 파일 포멧에 대해서 공부했다.


여기서는 ELF 포멧이 어떤 것이며 어떠한 정보를 포함하고 있는지만 간략적으로 언급하고 넘어가겠다. (ELF 포멧에 대한 자세한 포스팅은 조만간 올라올 예정이다. 그러니까 조금만 기다려주라.)


컴퓨터를 전공하는 사람이라면 PE 파일 포멧이라는 말을 들어봤을 것이다. 이는 windows의 실행파일 포멧을 의미한다. windows의 실행파일 포멧 대표적으로 exe가 있고 dll이 있다. 그 외의 windows의 실행파일 포멧은 .cpl .ocx .sys .scr .drv .efi 등등이 있다. 이 파일들이 실제 reverse engineering 이나 다른 부분에서 얼마나 자주 쓰이는 지는 잘 모르겠다. 아무튼 PE파일 포멧은 이러한 확장자를 가진 파일에 대한 파일 구조이다.


windows에서 PE파일 포멧을 사용한다면 linux에서는 어떤 파일 포멧을 사용할까? 그것이 ELF파일 포멧이다. ELF파일은 Executable and Linking Format의 약자로, wikipedia에서 아래와 같이 설명되어있다.

In computing, the Executable and Linkable Format (ELF, formerly called Extensible Linking Format) is a common standard file format for executablesobject codeshared libraries, and core dumps. First published in the System V Application Binary Interfacespecification,[1] and later in the Tool Interface Standard,[2] it was quickly accepted among different vendors of Unix systems. In 1999 it was chosen as the standard binary file format for Unix and Unix-like systems on x86 by the 86open project.

ELF is flexible and extensible by design, and it is not bound to any particular processor or architecture. This has allowed it to be adopted by many different operating systems on many different platforms.

Filename extensionnone, .o.so.elf.prx,.puff.bin
Magic number0x7F 'E' 'L' 'F'
Developed byUnix System Laboratories
Type of formatBinaryexecutableobject,shared librariescore dump
Container forMany executable binary formats

출처 : http://en.wikipedia.org/wiki/Executable_and_Linkable_Format


위의 표에서 보이다 시피 ELF 포멧은 .none .o .so .elf .prx .puff .bin 파일에 대한 포멧이다. 여기서 잠깐 자꾸 포멧 포멧 하는데 도데체 포멧이 무엇이냐 라고 질문하는 사람이 있을 것이다. 여기서 말하는 포멧이란 파일의 구조를 말하는 것이다. 가령 100byte짜리 프로그램이 있다면 처음 7byte까지는 header가 있고 그 다음부터 20byte까지는 section table이 있고 등등 이런 식이다.(단순 예를 들기 위한 예시일 뿐이다. 실제로는 header 다음에 section table이 오지 않는다.)


위의 그림을 다시 한번 보자.

여기에는 오로지 코드밖에 없다. assembly language는 코드만 가지고는 동작하지 않는다. 반드시 아래와 같이 추가적인 정보가 head와 tail에 붙여져야 한다.



사실 .c파일을 컴파일러로 컴파일을 하면 나오는 .s파일은 위의 정보보다 더욱 많은 정보를 포함하고 있다. 실제로 컴파일을 해보면 .cfi_startproc .cfi_endproc 등등과 같은 여러 가지 내용이 각 함수의 procedure마다 추가되어있다. 그 내용들에 대해서는 다음 포스팅에서 설명할 생각이다. 위의 그림에서 head에 나온 내용을 설명해보면 다음과 같다.



위의 정보들을 보면 대충 무엇에 대한 정보가 들어있는지 추측할 수 있다. Hello World\nHello World처럼 main 함수에서 print할 문자열도 있다. main이 global 하다는 것도 알려주며 그것이 함수라는 것도 알려준다. 대략 이런 정보들이 있다.


도대체 이게 뭘까 아직도 궁금한 사람이 있다면 다음 포스팅을 기다려라. 다음 포스팅을 보기 전에 아래의 그림을 봐주길 바란다. 봐도 뭔지 모르겠지만 그냥 봐서 익숙해지자. section은 뭐고 symbol은 뭐고 section table은 무엇이며 아놔 모르겠다. 라고 말하셔도 된다. 그럴 수 밖에 없다. 그렇지만 다음에 배울 내용에 대한 예습 맛보기 라고 생각하고 보자. 아래의 그림은 readelf 라는 명령어로 elf 파일 포멧을 읽은 것이다.


============================================================================

root@xxxxx-MS-7592:/# readelf -a func

ELF Header:

  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 

  Class:                             ELF32

  Data:                              2's complement, little endian

  Version:                           1 (current)

  OS/ABI:                            UNIX - System V

  ABI Version:                       0

  Type:                              EXEC (Executable file)

  Machine:                           Intel 80386

  Version:                           0x1

  Entry point address:               0x80482f0

  Start of program headers:          52 (bytes into file)

  Start of section headers:          5284 (bytes into file)

  Flags:                             0x0

  Size of this header:               52 (bytes)

  Size of program headers:           32 (bytes)

  Number of program headers:         9

  Size of section headers:           40 (bytes)

  Number of section headers:         36

  Section header string table index: 33


Section Headers:

  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al

  [ 0]                   NULL            00000000 000000 000000 00      0   0  0

  [ 1] .interp           PROGBITS        08048154 000154 000013 00   A  0   0  1

  [ 2] .note.ABI-tag     NOTE            08048168 000168 000020 00   A  0   0  4

  [ 3] .note.gnu.build-i NOTE            08048188 000188 000024 00   A  0   0  4

  [ 4] .gnu.hash         GNU_HASH        080481ac 0001ac 000020 04   A  5   0  4

  [ 5] .dynsym           DYNSYM          080481cc 0001cc 000040 10   A  6   1  4

  [ 6] .dynstr           STRTAB          0804820c 00020c 000045 00   A  0   0  1

  [ 7] .gnu.version      VERSYM          08048252 000252 000008 02   A  5   0  2

  [ 8] .gnu.version_r    VERNEED         0804825c 00025c 000020 00   A  6   1  4

  [ 9] .rel.dyn          REL             0804827c 00027c 000008 08   A  5   0  4

  [10] .rel.plt          REL             08048284 000284 000010 08   A  5  12  4

  [11] .init             PROGBITS        08048294 000294 000023 00  AX  0   0  4

  [12] .plt              PROGBITS        080482c0 0002c0 000030 04  AX  0   0 16

  [13] .text             PROGBITS        080482f0 0002f0 0001c4 00  AX  0   0 16

  [14] .fini             PROGBITS        080484b4 0004b4 000014 00  AX  0   0  4

  [15] .rodata           PROGBITS        080484c8 0004c8 000008 00   A  0   0  4

  [16] .eh_frame_hdr     PROGBITS        080484d0 0004d0 000034 00   A  0   0  4

  [17] .eh_frame         PROGBITS        08048504 000504 0000d0 00   A  0   0  4

  [18] .init_array       INIT_ARRAY      08049f08 000f08 000004 00  WA  0   0  4

  [19] .fini_array       FINI_ARRAY      08049f0c 000f0c 000004 00  WA  0   0  4

  [20] .jcr              PROGBITS        08049f10 000f10 000004 00  WA  0   0  4

  [21] .dynamic          DYNAMIC         08049f14 000f14 0000e8 08  WA  6   0  4

  [22] .got              PROGBITS        08049ffc 000ffc 000004 04  WA  0   0  4

  [23] .got.plt          PROGBITS        0804a000 001000 000014 04  WA  0   0  4

  [24] .data             PROGBITS        0804a014 001014 000008 00  WA  0   0  4

  [25] .bss              NOBITS          0804a01c 00101c 000008 00  WA  0   0  4

  [26] .comment          PROGBITS        00000000 00101c 00002a 01  MS  0   0  1

  [27] .debug_aranges    PROGBITS        00000000 001046 000020 00      0   0  1

  [28] .debug_info       PROGBITS        00000000 001066 0000fb 00      0   0  1

  [29] .debug_abbrev     PROGBITS        00000000 001161 00009e 00      0   0  1

  [30] .debug_line       PROGBITS        00000000 0011ff 00004e 00      0   0  1

  [31] .debug_str        PROGBITS        00000000 00124d 000096 01  MS  0   0  1

  [32] .debug_loc        PROGBITS        00000000 0012e3 000070 00      0   0  1

  [33] .shstrtab         STRTAB          00000000 001353 000151 00      0   0  1

  [34] .symtab           SYMTAB          00000000 001a44 0004a0 10     35  51  4

  [35] .strtab           STRTAB          00000000 001ee4 000249 00      0   0  1

Key to Flags:

  W (write), A (alloc), X (execute), M (merge), S (strings)

  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)

  O (extra OS processing required) o (OS specific), p (processor specific)


There are no section groups in this file.


Program Headers:

  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align

  PHDR           0x000034 0x08048034 0x08048034 0x00120 0x00120 R E 0x4

  INTERP         0x000154 0x08048154 0x08048154 0x00013 0x00013 R   0x1

      [Requesting program interpreter: /lib/ld-linux.so.2]

  LOAD           0x000000 0x08048000 0x08048000 0x005d4 0x005d4 R E 0x1000

  LOAD           0x000f08 0x08049f08 0x08049f08 0x00114 0x0011c RW  0x1000

  DYNAMIC        0x000f14 0x08049f14 0x08049f14 0x000e8 0x000e8 RW  0x4

  NOTE           0x000168 0x08048168 0x08048168 0x00044 0x00044 R   0x4

  GNU_EH_FRAME   0x0004d0 0x080484d0 0x080484d0 0x00034 0x00034 R   0x4

  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x4

  GNU_RELRO      0x000f08 0x08049f08 0x08049f08 0x000f8 0x000f8 R   0x1


 Section to Segment mapping:

  Segment Sections...

   00     

   01     .interp 

   02     .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame 

   03     .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss 

   04     .dynamic 

   05     .note.ABI-tag .note.gnu.build-id 

   06     .eh_frame_hdr 

   07     

   08     .init_array .fini_array .jcr .dynamic .got 


Dynamic section at offset 0xf14 contains 24 entries:

  Tag        Type                         Name/Value

 0x00000001 (NEEDED)                     Shared library: [libc.so.6]

 0x0000000c (INIT)                       0x8048294

 0x0000000d (FINI)                       0x80484b4

 0x00000019 (INIT_ARRAY)                 0x8049f08

 0x0000001b (INIT_ARRAYSZ)               4 (bytes)

 0x0000001a (FINI_ARRAY)                 0x8049f0c

 0x0000001c (FINI_ARRAYSZ)               4 (bytes)

 0x6ffffef5 (GNU_HASH)                   0x80481ac

 0x00000005 (STRTAB)                     0x804820c

 0x00000006 (SYMTAB)                     0x80481cc

 0x0000000a (STRSZ)                      69 (bytes)

 0x0000000b (SYMENT)                     16 (bytes)

 0x00000015 (DEBUG)                      0x0

 0x00000003 (PLTGOT)                     0x804a000

 0x00000002 (PLTRELSZ)                   16 (bytes)

 0x00000014 (PLTREL)                     REL

 0x00000017 (JMPREL)                     0x8048284

 0x00000011 (REL)                        0x804827c

 0x00000012 (RELSZ)                      8 (bytes)

 0x00000013 (RELENT)                     8 (bytes)

 0x6ffffffe (VERNEED)                    0x804825c

 0x6fffffff (VERNEEDNUM)                 1

 0x6ffffff0 (VERSYM)                     0x8048252

 0x00000000 (NULL)                       0x0


Relocation section '.rel.dyn' at offset 0x27c contains 1 entries:

 Offset     Info    Type            Sym.Value  Sym. Name

08049ffc  00000106 R_386_GLOB_DAT    00000000   __gmon_start__


Relocation section '.rel.plt' at offset 0x284 contains 2 entries:

 Offset     Info    Type            Sym.Value  Sym. Name

0804a00c  00000107 R_386_JUMP_SLOT   00000000   __gmon_start__

0804a010  00000207 R_386_JUMP_SLOT   00000000   __libc_start_main


The decoding of unwind sections for machine type Intel 80386 is not currently supported.


Symbol table '.dynsym' contains 4 entries:

   Num:    Value  Size Type    Bind   Vis      Ndx Name

     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 

     1: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__

     2: 00000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.0 (2)

     3: 080484cc     4 OBJECT  GLOBAL DEFAULT   15 _IO_stdin_used


Symbol table '.symtab' contains 74 entries:

   Num:    Value  Size Type    Bind   Vis      Ndx Name

     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 

     1: 08048154     0 SECTION LOCAL  DEFAULT    1 

     2: 08048168     0 SECTION LOCAL  DEFAULT    2 

     3: 08048188     0 SECTION LOCAL  DEFAULT    3 

     4: 080481ac     0 SECTION LOCAL  DEFAULT    4 

     5: 080481cc     0 SECTION LOCAL  DEFAULT    5 

     6: 0804820c     0 SECTION LOCAL  DEFAULT    6 

     7: 08048252     0 SECTION LOCAL  DEFAULT    7 

     8: 0804825c     0 SECTION LOCAL  DEFAULT    8 

     9: 0804827c     0 SECTION LOCAL  DEFAULT    9 

    10: 08048284     0 SECTION LOCAL  DEFAULT   10 

    11: 08048294     0 SECTION LOCAL  DEFAULT   11 

    12: 080482c0     0 SECTION LOCAL  DEFAULT   12 

    13: 080482f0     0 SECTION LOCAL  DEFAULT   13 

    14: 080484b4     0 SECTION LOCAL  DEFAULT   14 

    15: 080484c8     0 SECTION LOCAL  DEFAULT   15 

    16: 080484d0     0 SECTION LOCAL  DEFAULT   16 

    17: 08048504     0 SECTION LOCAL  DEFAULT   17 

    18: 08049f08     0 SECTION LOCAL  DEFAULT   18 

    19: 08049f0c     0 SECTION LOCAL  DEFAULT   19 

    20: 08049f10     0 SECTION LOCAL  DEFAULT   20 

    21: 08049f14     0 SECTION LOCAL  DEFAULT   21 

    22: 08049ffc     0 SECTION LOCAL  DEFAULT   22 

    23: 0804a000     0 SECTION LOCAL  DEFAULT   23 

    24: 0804a014     0 SECTION LOCAL  DEFAULT   24 

    25: 0804a01c     0 SECTION LOCAL  DEFAULT   25 

    26: 00000000     0 SECTION LOCAL  DEFAULT   26 

    27: 00000000     0 SECTION LOCAL  DEFAULT   27 

    28: 00000000     0 SECTION LOCAL  DEFAULT   28 

    29: 00000000     0 SECTION LOCAL  DEFAULT   29 

    30: 00000000     0 SECTION LOCAL  DEFAULT   30 

    31: 00000000     0 SECTION LOCAL  DEFAULT   31 

    32: 00000000     0 SECTION LOCAL  DEFAULT   32 


    34: 08049f10     0 OBJECT  LOCAL  DEFAULT   20 __JCR_LIST__

    38: 0804a01c     1 OBJECT  LOCAL  DEFAULT   25 completed.6339

    39: 08049f0c     0 OBJECT  LOCAL  DEFAULT   19 __do_global_dtors_aux_fin

    41: 08049f08     0 OBJECT  LOCAL  DEFAULT   18 __frame_dummy_init_array_

    44: 080485d0     0 OBJECT  LOCAL  DEFAULT   17 __FRAME_END__

    45: 08049f10     0 OBJECT  LOCAL  DEFAULT   20 __JCR_END__

    48: 08049f14     0 OBJECT  LOCAL  DEFAULT   21 _DYNAMIC

    50: 0804a000     0 OBJECT  LOCAL  DEFAULT   23 _GLOBAL_OFFSET_TABLE_

    59: 0804a018     0 OBJECT  GLOBAL HIDDEN    24 __dso_handle

    60: 080484cc     4 OBJECT  GLOBAL DEFAULT   15 _IO_stdin_used

    66: 080484c8     4 OBJECT  GLOBAL DEFAULT   15 _fp_hw

    70: 0804a020     4 OBJECT  GLOBAL DEFAULT   25 glov

    71: 0804a01c     0 OBJECT  GLOBAL HIDDEN    24 __TMC_END__


## no procedure has lower address than _start besides _init

    61: 00000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@@GLIBC_

    73: 08048294     0 FUNC    GLOBAL DEFAULT   11 _init

    65: 080482f0     0 FUNC    GLOBAL DEFAULT   13 _start

    53: 08048320     4 FUNC    GLOBAL HIDDEN    13 __x86.get_pc_thunk.bx

    35: 08048330     0 FUNC    LOCAL  DEFAULT   13 deregister_tm_clones

    36: 08048360     0 FUNC    LOCAL  DEFAULT   13 register_tm_clones

    37: 080483a0     0 FUNC    LOCAL  DEFAULT   13 __do_global_dtors_aux

    40: 080483c0     0 FUNC    LOCAL  DEFAULT   13 frame_dummy

    62: 080483ec    49 FUNC    GLOBAL DEFAULT   13 func

    68: 0804841d    35 FUNC    GLOBAL DEFAULT   13 main

    63: 08048440    97 FUNC    GLOBAL DEFAULT   13 __libc_csu_init

    51: 080484b0     2 FUNC    GLOBAL DEFAULT   13 __libc_csu_fini

    56: 080484b4     0 FUNC    GLOBAL DEFAULT   14 _fini


## ABS is the file that should not be relocated

    33: 00000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c

    42: 00000000     0 FILE    LOCAL  DEFAULT  ABS test.c

    43: 00000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c

    46: 00000000     0 FILE    LOCAL  DEFAULT  ABS 


    47: 08049f0c     0 NOTYPE  LOCAL  DEFAULT   18 __init_array_end

    49: 08049f08     0 NOTYPE  LOCAL  DEFAULT   18 __init_array_start

    52: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTab

    54: 0804a014     0 NOTYPE  WEAK   DEFAULT   24 data_start

    55: 0804a01c     0 NOTYPE  GLOBAL DEFAULT   24 _edata

    57: 0804a014     0 NOTYPE  GLOBAL DEFAULT   24 __data_start

    58: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__

    64: 0804a024     0 NOTYPE  GLOBAL DEFAULT   25 _end

    67: 0804a01c     0 NOTYPE  GLOBAL DEFAULT   25 __bss_start

    69: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses

    72: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable


Histogram for `.gnu.hash' bucket list length (total of 2 buckets):

 Length  Number     % of total  Coverage

      0  1          ( 50.0%)

      1  1          ( 50.0%)    100.0%


Version symbols section '.gnu.version' contains 4 entries:

 Addr: 0000000008048252  Offset: 0x000252  Link: 5 (.dynsym)

  000:   0 (*local*)       0 (*local*)       2 (GLIBC_2.0)     1 (*global*)   


Version needs section '.gnu.version_r' contains 1 entries:

 Addr: 0x000000000804825c  Offset: 0x00025c  Link: 6 (.dynstr)

  000000: Version: 1  File: libc.so.6  Cnt: 1

  0x0010:   Name: GLIBC_2.0  Flags: none  Version: 2


Notes at offset 0x00000168 with length 0x00000020:

  Owner                 Data size Description

  GNU                  0x00000010 NT_GNU_ABI_TAG (ABI version tag)

    OS: Linux, ABI: 2.6.24


Notes at offset 0x00000188 with length 0x00000024:

  Owner                 Data size Description

  GNU                  0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring)

    Build ID: 15ba02e08f2be0aa3352d7cca6e07c77773b2c2f

============================================================================


위의 내용에 대해서 차근 차근 설명할 것이니 조금만 기다려라. section이 뭔지 symbol은 또 뭔지 전부 다 설명할거다. 나도 공부를 해야 블로깅을 할 수 있다.ㅠㅠ

Posted by 빛나유

댓글을 달아 주세요

※ 질문/내용오류/공유할 내용이 있다면 jinkilee73@gmail.com으로 메일 주세요 :-)


회사에서 업무하다가 갑자기 Slowloris DoS 공격 툴 이야기가 나왔다. perl 스크립트로 짜여져있다고 하는데 전체적으로 코드 생김새를 보니까 조금만 하면 분석할 수 있을 것 같다는 생각이 들어서 한번 분석해봤다. perl 스크립트를 시작하는 좋은 연습이 되겠다!!


우선 Slowloris에 대한 wikipedia 검색 결과를 보자.

Slowloris is a piece of software written by Robert "RSnake" Hansen which allows a single machine to take down another machine's web server with minimal bandwidth and side effects on unrelated services and ports.[1]

Slowloris tries to keep many connections to the target web server open and hold them open as long as possible. It accomplishes this by opening connections to the target web server and sending a partial request. Periodically, it will send subsequent HTTP headers, adding to—but never completing—the request. Affected servers will keep these connections open, filling their maximum concurrent connection pool, eventually denying additional connection attempts from clients.

출처 : http://en.wikipedia.org/wiki/Slowloris


위에서 언급했듯이 Slowloris perl 스크립트로 작성된 HTTP/HTTPS DoS 공격 툴이다. 다른 DoS 툴과 두드러진Slowloris만의 특징은 최소한의 자원으로 DoS를 수행한다는 점이다. , 해당 툴을 사용했을 경우 일반 DoS 증상처럼 다수의 트래픽이 탐지되거나 혹은 트래픽 양이 순간적으로 급증하지는 않는다. 그렇지만 각각의 Connection을 오래 유지하고 있으므로써 최종적으로 웹서버가 다룰 수 있는 최대한의 Connection 개수를 초과하여 DoS 공격을 성공시킨다.

 

Slowloris의 여러가지 옵션을 통해 다양하게 사용할 수 있다. Slowloris에서 사용할 수 있는 옵션은 아래와 같다.


Slowloris은 아래와 같은 방법으로 사용할 수 있다.


예시./slowloris.pl -dns www.example.com -port 443 -timeout 30 -num 500 –https


위의 공격은 www.example.com이라는 443포트를 사용하는 서버의 timeout 30초로 변경하여 매 30초마다 500개의 패킷을 보낸다는 뜻이다.


우선 전체적인 프로그램의 구조를 살펴본 후 조금 더 상세하게 분석해볼 생각이다. 사용하는 변수와 전체적인 스크립트의 흐름은 아래와 같다.

 

## 프로그램에서 사용될 변수 선언


위의 그림을 보면 스크립트 수행 시 사용될 옵션명과 그 옵션을 스크립트 내에서 접근할 변수명이 GetOptions{};에 모두 정의되어있다. 그 밑에 있는 unless문은 사용자가 스크립트를 수행할 때 옵션을 명시하지 않을 경우 해당 옵션들이 설정되는 기본값이다. 실제 수행되는 스크립트는 아래의 구조로 되어있다.

 

## 스크립트 수행 부분

위의 구문 중 if($test)부분은 실제로 test 용이다. Slowloris 스크립트 수행 시 test를 수행하고 싶을 때 test옵션을 넣을 수 있는데 그 때 if($test)부분으로 들어간다. else문은 multithread 가능여부에 따라 가능하면 domultithreading 함수 콜을 하고 그렇지 않으면 doconnections 수행한다.

 

살짝 집고 넘어가자 test 옵션이 있을 경우와 그렇지 않을 경우의 가장 큰 차이는 생성되는 소켓의 개수이다. Test 옵션이 있을 경우는 한 개만 생성해서 말 그대로 test 용도로 패킷을 만들어 보내는 것이고 test 옵션이 없을 경우는 실제로 다량의 소켓을 생성해서 다량의 패킷을 보내서 DoS 공격을 수행하게 된다.

 

전체적으로 구조를 보았으니 else문에서 수행되는 doconnections domultithreading 함수를 자세하게 분석해보면 아래와 같다.

 

## doconnections


위의 코드에서 두 개의 foreach문을 볼 수 있다. 두번째 foreach문에서 하는 역할은 정확히 말하면 아래와 같다.

두번째 foreach문에서는 print $handle “X-a; b\r\n” 함수를 if문 안에서 수행한다. 그렇다면 첫번째 foreach문에서 만든 패킷을 알아보자. 아래와 같다.

my $primarypaload = … 에서 볼 수 있지만, Content-Length: 42\r\n후에 \r\n가 한 개 더 있어야 하는데 없다. 게다가 두 번째 foreach문에 의해 헤더 요청이 엉뚱하게 X-a: b \r\n과 같이 들어오게 된다. 이 부분은 Slowloris 공격툴의 많은 특성을 보여주는데 이 내용은 조금 후에 다룰 예정이다.

 

## domultithreading

$num보다 작을 때까지 지속적으로 Thread를 생성하는 간단한 코드이다. 전체적으로 동작방식은 doconnections함수와 비슷하다. 실제로 threads->create로 생성하는 thead 역시 doconnections이다.


위에서 언급했듯이, Slowloris는 최소한의 트래픽으로 DoS 공격을 수행한다. 또한 단 한대의 PC만 있으면 언제든지 공격이 가능하다.


위에서 분석한 Slowloris 소스 코드의 특징을 한 마디로 정리하면, 사용자가 원하는 개수의 connection을 최대한 오래 지속시키거나 한계치를 초과시켜서 서버를 다운시키는 공격이 된다. 아래의 코드에서 확인할 수 있다.

위 그림에서 아래부분을 보면 my $primarypayload에서 전송할 패킷을 소켓에 write하는 과정에서 찾아볼 수 있다. 위와 같이 전송되면 생성된 소켓마다 아래와 같은 payload가 생성될 것이다.


GET / HTTP/1.1\r\n

Host: $sendhost\r\n

User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.503l3; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; MSOffice 12)\r\n

Content-Length: 42\r\n


\r\n CRLF에서 LF Line Feed이다. 이는 헤더의 line terminator이다.  HTTP 헤더 같은 경우 헤더를 끝낼 때 LF 두 개가 연속으로 나오는 \r\n\r\n과 같은 문자열이 있어야 헤더를 끝낼 수 있다위의 예시를 보면 Slowloris가 작성하고 있는 헤더는 LF가 하나 부족한 것을 알 수 있다. 절대 두 개 연속의 LF를 생성하여 헤더 작성을 끝내지 않는다.


위와 같이 패킷을 작성한 후 open되어있는 각각의 소켓에 X-a: b\r\n와 같은 비정상적인 헤더를 write하게 된다. 이 때 역시 LF는 하나만 작성하여 connection을 지속적으로 열어놓는다.이제 다시 doconenction 함수의 전체적인 구조를 보자.

소켓을 생성하고 전송하는 두 개의 foreach문이 while(1)이라는 무한 루프 안에 있는 것을 확인할 수 있다. , 사용자가 강제로 종료하기 전까지는 멈추지 않고 소켓을 생성하여 불완전한 헤더를 요청하고 서버로 하여금 connection open하게 만든다. 이와 같은 방법으로 공격을 하면 유입되는 이벤트의 양은 그다지 많지 않을 수 있다. 왜냐하면 foreach문의 내용을 보면 소켓이 생성되어 있지 않는 경우에만 소켓을 생성하는 특정 작업이 수행되기 때문에 이미 생성되어 있는 소켓에 대한 추가적인 작업은 없다.

 

Slowloris의 또 하나의 특징은 공격이 실패하기 전까지는 웹서버가 로그를 남기지 못 한다는 것이다. Connection이 지속적으로 열려있게 되기 때문에 서버입장에서는 로그를 남기고 싶어도 남길 수가 없다.


이러한 공격은 어떻게 탐지할 수 있을까? 


일반적으로 X-a: b \r\n 문자열을 탐지하여 Slowloris 공격툴 사용 여부를 탐지하곤 한다. 하지만 개인적으로 잘못된 방법이라고 생각한다. Slowloris는 개인 PC에서도 얼마든지 간단하게 돌아가는 스크립트 툴이기 때문에 X-a: b \r\n은 얼마든지 바꿔서 공격을 시도할 수 있다. 게다가 Slowloris 공격은 웹서버의 자원을 많이 사용하여 다운시키는 유형이 아니기 때문에 트래픽으로 탐지하는 것도 바람직한 방법은 아니다.

 

해당 스크립트는 Layer7을 기반으로 동작하는 스크립트 툴이기 때문에 Layer7과 그 이하의 어느정도 방어가 가능하다. 가장 대표적으로 할 수 있는 것은 웹서버의 설정 값 중에서 Timeout 값을 적절하게 설정하는 것이다. 또한 iptable에서 하나의 출발지 IP connection 개수를 제한하는 방법도 가능하다. (L3 단에서의 방어)


진짜 오랜만에 포스팅을 했다. 내가 게을러서라기보다는 올릴만한 성과물이 없었다. 사실 위에 분석해놓은 Slowloris는 진작에 해놨던 것인데 이제서야 써서 올리는 것이다. 그렇게 따지면 포스팅이 오랜만에 올라온 것이 나의 게으름일 수도 있겠다. 사실 근 1달간 커널과 exploitation 공부로 싸우고 있었다. 아직 해결하지 못 한 구석구석이 많다. exploit 진짜 재밌더라. 그래서 내가 Maybe 인원들에게 제안을 했지... exploit 공부해보자고. 모두들 쿨하게 OK 해서 공부를 하려고 하는데 아직 적당한 방법이 떠오르지 않는다. 내일쯤 관련해서 확실하게 연락해보고 의견받아보고 해야겠다.


기존의 블로그를 보면 어딘가에 앞으로 커널에 관한 포스팅이 많이 올라올 것이라는 이야기가 있을 것이다. 반만 듣고 반은 흘려보내주셔라. exploit 공부하고 포스팅할지도 모를 것 같다. 아무튼 다음 포스팅까지 안녕히...

'Vulnerability' 카테고리의 다른 글

[Vul] CVE-2012-1823 Vulnerability  (1) 2014.01.21
[Vul] Shellcode Execution  (4) 2013.12.30
[Vul] Format String Vulnerability  (0) 2013.11.23
[Vul] Slowloris DoS Tool  (0) 2013.10.28
[Vul] DEDECMS SQL Injection  (1) 2013.08.12
시작하며...  (0) 2013.08.12
Posted by 빛나유

댓글을 달아 주세요