-
-
[原创][writeup]CTFHUB-UnsortedBin Attack
-
发表于: 2023-3-13 17:01 16404
-
全局变量上方内存区,我们本次不利用此块内容
mallocHook上方内存区
FakeChunk选址
虽然这题叫UnsortedBin Attack,但是甚至可以用上一题的exp来打通,不是很理解为什么要在interface
函数中设置magic
这个后门,不过为了符合出题人的要求,所以还是单独用UnsortedBin Attack来做一次
假如不存在全局变量heapList;magic
,目前不知道需要申请FakeChunk
到哪个位置,所以需要使用Unsorted Bin
来泄露main_Arena
的地址
根据分析可知:
当FreeChunk
为unsorted bin
一链表中唯一元素时,该FreeChunk->fd FreeChunk->bk
均指向main_arena+offset
,经过调试得知该offset=88;__malloc_hook = main_arena-0x10
,经过上述分析已知__malloc_hook
上方可构造FakeChunk
以劫持__malloc_hook
本题的重点是通过Unsorted Bin来泄露main_arena
,具体泄露方式需要参照题目的show()
函数运作方式,例如本题是以字符串来输出heap
中内容,我们只需要把内存填充至fd\bk
指针即可
举个其它show()
函数形式的例子:write(0,heapList[index]+16,*heapList[index]+8)
该情况下泄露思路如下
可以注意到在完成泄露准备释放chunk#2 chunk#1
时对chunk#3->heapHeader
进行了一次还原,若不作此操作,将会触发报错
*** Error in `./pwn': free(): invalid next size (fast): 0x0000000001a530f0 ***
可以注意到是在free()函数时的错误,若进入glibc源码中搜索invalid next size (fast)
可以找到触发该报错的函数是_int_free
,以下是触发该报错的检查源码
该检查会判断下一块chunk的大小是否小于 MINSIZE || 大于 system_mem,若符合则会报错,所以需要将下一个chunk的size修改成符合条件的值避免报错
int
__cdecl __noreturn main(
int
argc, const char
*
*
argv, const char
*
*
envp)
{
init(argc, argv, envp);
interface();
}
void __noreturn interface()
{
int
choice;
/
/
[rsp
+
4h
] [rbp
-
Ch] BYREF
unsigned __int64 v1;
/
/
[rsp
+
8h
] [rbp
-
8h
]
v1
=
__readfsqword(
0x28u
);
while
(
1
)
{
while
(
1
)
{
menu();
__isoc99_scanf(
"%d"
, &choice);
if
( choice !
=
1
)
break
;
add();
}
switch ( choice )
{
case
2
:
delete();
break
;
case
3
:
show();
break
;
case
4
:
edit();
break
;
case
1024
:
if
( magic >
28800
)
system(
"/bin/sh"
);
break
;
default:
exit(
-
1
);
}
}
}
int
__cdecl __noreturn main(
int
argc, const char
*
*
argv, const char
*
*
envp)
{
init(argc, argv, envp);
interface();
}
void __noreturn interface()
{
int
choice;
/
/
[rsp
+
4h
] [rbp
-
Ch] BYREF
unsigned __int64 v1;
/
/
[rsp
+
8h
] [rbp
-
8h
]
v1
=
__readfsqword(
0x28u
);
while
(
1
)
{
while
(
1
)
{
menu();
__isoc99_scanf(
"%d"
, &choice);
if
( choice !
=
1
)
break
;
add();
}
switch ( choice )
{
case
2
:
delete();
break
;
case
3
:
show();
break
;
case
4
:
edit();
break
;
case
1024
:
if
( magic >
28800
)
system(
"/bin/sh"
);
break
;
default:
exit(
-
1
);
}
}
}
unsigned __int64 add()
{
unsigned
int
inputSize;
/
/
[rsp
+
4h
] [rbp
-
101Ch
] BYREF
unsigned
int
index;
/
/
[rsp
+
8h
] [rbp
-
1018h
]
unsigned
int
v3;
/
/
[rsp
+
Ch] [rbp
-
1014h
]
char v4[
4096
];
/
/
[rsp
+
10h
] [rbp
-
1010h
] BYREF
unsigned __int64 v5;
/
/
[rsp
+
1018h
] [rbp
-
8h
]
v5
=
__readfsqword(
0x28u
);
memset(v4,
0
, sizeof(v4));
for
( index
=
0
; index <
=
9
;
+
+
index )
{
if
( !
*
(&heapList
+
index) )
{
v3
=
index;
break
;
}
}
if
( index
=
=
11
)
{
puts(
"wrong"
);
exit(
0
);
}
puts(
"Size: "
);
__isoc99_scanf(
"%d"
, &inputSize);
if
( inputSize >
0x500
)
inputSize
=
1280
;
*
(&heapList
+
v3)
=
malloc(inputSize);
Size[v3]
=
inputSize;
puts(
"Content: "
);
read(
0
,
*
(&heapList
+
v3), inputSize);
return
__readfsqword(
0x28u
) ^ v5;
}
unsigned __int64 add()
{
unsigned
int
inputSize;
/
/
[rsp
+
4h
] [rbp
-
101Ch
] BYREF
unsigned
int
index;
/
/
[rsp
+
8h
] [rbp
-
1018h
]
unsigned
int
v3;
/
/
[rsp
+
Ch] [rbp
-
1014h
]
char v4[
4096
];
/
/
[rsp
+
10h
] [rbp
-
1010h
] BYREF
unsigned __int64 v5;
/
/
[rsp
+
1018h
] [rbp
-
8h
]
v5
=
__readfsqword(
0x28u
);
memset(v4,
0
, sizeof(v4));
for
( index
=
0
; index <
=
9
;
+
+
index )
{
if
( !
*
(&heapList
+
index) )
{
v3
=
index;
break
;
}
}
if
( index
=
=
11
)
{
puts(
"wrong"
);
exit(
0
);
}
puts(
"Size: "
);
__isoc99_scanf(
"%d"
, &inputSize);
if
( inputSize >
0x500
)
inputSize
=
1280
;
*
(&heapList
+
v3)
=
malloc(inputSize);
Size[v3]
=
inputSize;
puts(
"Content: "
);
read(
0
,
*
(&heapList
+
v3), inputSize);
return
__readfsqword(
0x28u
) ^ v5;
}
unsigned __int64 delete()
{
unsigned
int
index;
/
/
[rsp
+
4h
] [rbp
-
Ch] BYREF
unsigned __int64 v2;
/
/
[rsp
+
8h
] [rbp
-
8h
]
v2
=
__readfsqword(
0x28u
);
puts(
"Index:"
);
__isoc99_scanf(
"%d"
, &index);
if
( index >
0xB
)
{
puts(
"wrong"
);
exit(
0
);
}
free(
*
(&heapList
+
index));
*
(&heapList
+
index)
=
0LL
;
Size[index]
=
0
;
return
__readfsqword(
0x28u
) ^ v2;
}
unsigned __int64 delete()
{
unsigned
int
index;
/
/
[rsp
+
4h
] [rbp
-
Ch] BYREF
unsigned __int64 v2;
/
/
[rsp
+
8h
] [rbp
-
8h
]
v2
=
__readfsqword(
0x28u
);
puts(
"Index:"
);
__isoc99_scanf(
"%d"
, &index);
if
( index >
0xB
)
{
puts(
"wrong"
);
exit(
0
);
}
free(
*
(&heapList
+
index));
*
(&heapList
+
index)
=
0LL
;
Size[index]
=
0
;
return
__readfsqword(
0x28u
) ^ v2;
}
unsigned __int64 show()
{
unsigned
int
index;
/
/
[rsp
+
4h
] [rbp
-
Ch] BYREF
unsigned __int64 v2;
/
/
[rsp
+
8h
] [rbp
-
8h
]
v2
=
__readfsqword(
0x28u
);
puts(
"Index:"
);
__isoc99_scanf(
"%d"
, &index);
if
(
*
(&heapList
+
index) )
printf(
"Content: %s\n"
, (const char
*
)
*
(&heapList
+
index));
return
__readfsqword(
0x28u
) ^ v2;
}
unsigned __int64 show()
{
unsigned
int
index;
/
/
[rsp
+
4h
] [rbp
-
Ch] BYREF
unsigned __int64 v2;
/
/
[rsp
+
8h
] [rbp
-
8h
]
v2
=
__readfsqword(
0x28u
);
puts(
"Index:"
);
__isoc99_scanf(
"%d"
, &index);
if
(
*
(&heapList
+
index) )
printf(
"Content: %s\n"
, (const char
*
)
*
(&heapList
+
index));
return
__readfsqword(
0x28u
) ^ v2;
}
unsigned __int64 edit()
{
int
nbytes;
/
/
[rsp
+
0h
] [rbp
-
10h
] BYREF
unsigned
int
index;
/
/
[rsp
+
4h
] [rbp
-
Ch] BYREF
unsigned __int64 v3;
/
/
[rsp
+
8h
] [rbp
-
8h
]
v3
=
__readfsqword(
0x28u
);
puts(
"Index:"
);
__isoc99_scanf(
"%d"
, &index);
puts(
"Size:"
);
__isoc99_scanf(
"%d"
, &nbytes);
if
( Size[index] >
=
nbytes )
{
if
(
*
(&heapList
+
index) )
{
puts(
"Content:"
);
read(
0
,
*
(&heapList
+
index), (unsigned
int
)nbytes);
}
else
{
puts(
"wrong"
);
}
}
else
{
puts(
"wrong!"
);
}
return
__readfsqword(
0x28u
) ^ v3;
}
unsigned __int64 edit()
{
int
nbytes;
/
/
[rsp
+
0h
] [rbp
-
10h
] BYREF
unsigned
int
index;
/
/
[rsp
+
4h
] [rbp
-
Ch] BYREF
unsigned __int64 v3;
/
/
[rsp
+
8h
] [rbp
-
8h
]
v3
=
__readfsqword(
0x28u
);
puts(
"Index:"
);
__isoc99_scanf(
"%d"
, &index);
puts(
"Size:"
);
__isoc99_scanf(
"%d"
, &nbytes);
if
( Size[index] >
=
nbytes )
{
if
(
*
(&heapList
+
index) )
{
puts(
"Content:"
);
read(
0
,
*
(&heapList
+
index), (unsigned
int
)nbytes);
}
else
{
puts(
"wrong"
);
}
}
else
{
puts(
"wrong!"
);
}
return
__readfsqword(
0x28u
) ^ v3;
}
pwndbg> x
/
30gx
0x6020AC
-
0x1f
0x60208d
:
0xfff7bc38e0000000
0x000000000000007f
0x60209d
:
0xfff7bc4540000000
0x000000000000007f
0x6020ad
<magic
+
1
>:
0x0000000000000000
0x0000000000000000
0x6020bd
:
0x0000000000000000
0x0000000000000000
0x6020cd
<ptr
+
13
>:
0x0000000000000000
0x0000000000000000
0x6020dd
<ptr
+
29
>:
0x0000000000000000
0x0000000000000000
0x6020ed
<ptr
+
45
>:
0x0000000000000000
0x0000000000000000
0x6020fd
<ptr
+
61
>:
0x0000000000000000
0x0000000000000000
0x60210d
<ptr
+
77
>:
0x0000000000000000
0x0000000000000000
0x60211d
:
0x0000000000000000
0x0000000000000000
0x60212d
<Size
+
13
>:
0x0000000000000000
0x0000000000000000
0x60213d
<Size
+
29
>:
0x0000000000000000
0x0000000000000000
pwndbg> x
/
30gx
0x6020AC
-
0x1f
0x60208d
:
0xfff7bc38e0000000
0x000000000000007f
0x60209d
:
0xfff7bc4540000000
0x000000000000007f
0x6020ad
<magic
+
1
>:
0x0000000000000000
0x0000000000000000
0x6020bd
:
0x0000000000000000
0x0000000000000000
0x6020cd
<ptr
+
13
>:
0x0000000000000000
0x0000000000000000
0x6020dd
<ptr
+
29
>:
0x0000000000000000
0x0000000000000000
0x6020ed
<ptr
+
45
>:
0x0000000000000000
0x0000000000000000
0x6020fd
<ptr
+
61
>:
0x0000000000000000
0x0000000000000000
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课