nasm x86:将要发送的有效负载解释为NULL的发送系统调用

nasm x86:将要发送的有效负载解释为NULL的发送系统调用,x86,nasm,system-calls,send,X86,Nasm,System Calls,Send,我正在尝试编写一些shell代码,它将连接到localhost上端口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).

我正在尝试编写一些shell代码,它将连接到localhost上端口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
看来我的euid没有被用作参数。但是,当我在二进制文件上运行gdb时,程序似乎正确设置了send调用的参数:


我是nasm的新手,如果这是一个愚蠢的语法问题,我道歉。谢谢你的帮助

TL;DR:您在STRACE中看到的
send
的值NULL是因为您以
root
用户身份运行STRACE,并且Linux发行版上
root
的UID通常为0。在调试器中可以看到0x3e8,因为您以UID=1000(即0x3e8)的非特权用户身份运行调试器

sys\u send
需要指向要发送的数据的指针,而不是数据。值0x0000和0x03e8被视为内存地址,即使它们不是内存地址。这两个地址都是我们没有读取权限的内存,因此结果是
strace
输出中
send


您正在将UID值传递给
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
位32
第二节数据
第2节bss
第节.案文
全球启动:
_开始:
; s=插座(2,1,0)
推送字节0x66;socketcall是syscall#102(0x66)。
波普eax
干熄焦;将edx调零,以便稍后用作空DWORD。
异或ebx,ebx;ebx是socketcall的类型。
公司ebx;1=系统插座=插座()
推动edx;生成arg数组:{protocol=0,
推送字节0x1;(相反)SOCK_STREAM=1,
推送字节0x2;AF_INET=2}
mov-ecx,esp;ecx=ptr到参数数组
int 0x80;在syscall之后,eax具有套接字文件描述符。
xchg-esi,eax;将插座FD保存在esi中以备将来使用。
; 连接(s,[231337,]16)
推送字节0x66;socketcall(系统调用#102)
波普eax
公司ebx;ebx=2(AF_INET需要)
推送DWORD 0x0100007f;生成sockaddr结构:IP地址=127.0.0.1
推送字0x697a;(按相反顺序)端口=31337
推字bx;AF_INET=2
mov-ecx,esp;ecx=服务器结构指针
推送字节16;argv:{sizeof(服务器结构)=16,
推送ecx;服务器结构指针,
推送esi;套接字文件描述符}
mov-ecx,esp;ecx=参数数组
公司ebx;ebx=3=SYS\u CONNECT=CONNECT()
int 0x80
; geteuid(无效)
推送字节0x31;调用geteuid(syscall#49)
波普eax
int 0x80;eax=有效用户id
推动eax;将EAX放在堆栈上
电子数据交换;获取UID的地址(在堆栈上)
; 发送(3,euid,8,0)
推送字节0x66;socketcall(系统调用#102)
波普eax
xor-edx,edx;为标志创建零
推式edx
推送字节4;要传输的数据的大小
推行电子数据交换;有效用户标识号
推动esi;文件描述符
mov-ebx,9;ebx=9=SYS\u SEND=SEND()
mov-ecx,esp;参数数组
int 0x80
; 出口(1)
推送字节1;呼救
波普eax
异或ebx,ebx
int 0x80
我发送4个字节的数据(32位整数),而不是8个字节。接收器应该正好接收4个字节,其中包含UID的二进制值


如果要将UID作为可打印字符串发送,则必须将UID转换为字符串,并将字符串地址传递给
send

我的观察力很好,犯了愚蠢的错误!我以根的形式运行strace,得到空值。当一个低权限用户清除了空值并且我的0x3e8出现时,重新运行strace,但它没有解决地址错误的问题。@Hosty:当然没有,正如Michael所说,
socketcall
在内存中获取其参数,第二个参数是指向缓冲区的指针,而不是缓冲区本身。(奇怪的是,
send(2)
手册页没有提到内核接口是一个通用的
socketcall
系统调用;大多数系统调用都提到库/内核的差异。我之前的评论(查看ECX的指针)是基于那种误解,即
send
是一个简单的系统调用,带有ebx=fd、ecx=buf等。明白了,谢谢!
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