-
-
[原创]WarGame-heap0 解题思路
-
发表于:
2019-10-29 19:44
8615
-
Heap0伪代码如下:
如题所示,只要运行win函数就可获得shell,而这题要学一种新的漏洞:堆溢出,因为这题所用到的堆不需要很大很多,所以都由tcache分配,故不考虑其他情况;堆溢出因为只能造成任意地址写,并不能控制EIP,所以我此次要攻击的是GOT表的内容,通过修改GOT表指向的函数地址,然后由程序调用指定函数,从而达到间接控制EIP的目的,查看GOT表和函数地址如下:
表中有一个exit函数,从伪代码中可以得到,只要将exit函数地址修改为win函数地址,然后在菜单中选择退出,就可以执行win函数从而得到shell,攻击脚本如下(注意看脚本中的注释):
这里提一下堆内存分配时的规则,每个堆分配的时候都是一个0xf(16),当我们申请了10字节(0xa)事实上是0xa+0x8个字节(fd指针的4个,还有四个的值一直都是0,有没有大佬出来解释下),因为大于0x10所以系统分配了0x20字节的内存(现在看懂了cyclic(0x18)的原因了吧),因为堆利用的时候不好理解,所以我还找了个图(非常感谢semchapeu的耐心帮助O(∩_∩)O):
int win()
{
return system("/bin/sh");
}
int menu()
{
puts("1) Create chunk");
puts("2) Free chunk");
puts("3) Show chunk");
return puts("4) Exit");
}
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
__int64 v3; // rsi@1
const char *v4; // rdi@1
void *v5; // ST08_8@9
signed int v6; // eax@9
int v7; // [sp+4h] [bp-1Ch]@11
int v8; // [sp+14h] [bp-Ch]@6
int v9; // [sp+18h] [bp-8h]@2
signed int v10; // [sp+1Ch] [bp-4h]@1
v3 = 0LL;
v4 = (const char *)stdout;
setvbuf(stdout, 0LL, 2, 0LL);
v10 = 0;
while ( 1 )
{
while ( 1 )
{
menu(v4, v3);
v9 = ((int (*)(void))get_int)();
if ( v9 != 1 )
break;
if ( v10 > 99 )
{
puts("Too many chunks created");
exit(1);
}
puts("Size of the chunk:");
v8 = get_int("Size of the chunk:");
if ( v8 > 0 && v8 <= 4096 )
{
v5 = malloc(v8);
printf("Content: ");
gets(v5);
v3 = (unsigned int)v10;
v4 = "Chunk ID: %d\n";
printf("Chunk ID: %d\n", (unsigned int)v10);
v6 = v10++;
chunks[v6] = v5;
}
else
{
v4 = "Invalid size";
puts("Invalid size");
}
}
if ( v9 == 2 )
{
puts("Chunk id:");
v7 = get_int("Chunk id:");
if ( v7 >= 0 && v7 < v10 && chunks[v7] )
{
v4 = (const char *)chunks[v7];
free((void *)v4);
chunks[v7] = 0LL;
}
else
{
v4 = "No chunk with that id";
puts("No chunk with that id");
}
}
else if ( v9 == 3 )
{
v4 = "Not implemented";
puts("Not implemented");
}
else
{
if ( v9 == 4 )
{
puts("Bye");
exit(0);
}
v4 = "Invalid choice";
puts("Invalid choice");
}
}
}
int win()
{
return system("/bin/sh");
}
int menu()
{
puts("1) Create chunk");
puts("2) Free chunk");
puts("3) Show chunk");
return puts("4) Exit");
}
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
__int64 v3; // rsi@1
const char *v4; // rdi@1
void *v5; // ST08_8@9
signed int v6; // eax@9
int v7; // [sp+4h] [bp-1Ch]@11
int v8; // [sp+14h] [bp-Ch]@6
int v9; // [sp+18h] [bp-8h]@2
signed int v10; // [sp+1Ch] [bp-4h]@1
v3 = 0LL;
v4 = (const char *)stdout;
setvbuf(stdout, 0LL, 2, 0LL);
v10 = 0;
while ( 1 )
{
while ( 1 )
{
menu(v4, v3);
v9 = ((int (*)(void))get_int)();
if ( v9 != 1 )
break;
if ( v10 > 99 )
{
puts("Too many chunks created");
exit(1);
}
puts("Size of the chunk:");
v8 = get_int("Size of the chunk:");
if ( v8 > 0 && v8 <= 4096 )
{
v5 = malloc(v8);
printf("Content: ");
gets(v5);
v3 = (unsigned int)v10;
v4 = "Chunk ID: %d\n";
printf("Chunk ID: %d\n", (unsigned int)v10);
v6 = v10++;
chunks[v6] = v5;
}
else
{
v4 = "Invalid size";
puts("Invalid size");
}
}
if ( v9 == 2 )
{
puts("Chunk id:");
v7 = get_int("Chunk id:");
if ( v7 >= 0 && v7 < v10 && chunks[v7] )
{
v4 = (const char *)chunks[v7];
free((void *)v4);
chunks[v7] = 0LL;
}
else
{
v4 = "No chunk with that id";
puts("No chunk with that id");
}
}
else if ( v9 == 3 )
{
v4 = "Not implemented";
puts("Not implemented");
}
else
{
if ( v9 == 4 )
{
puts("Bye");
exit(0);
}
v4 = "Invalid choice";
puts("Invalid choice");
}
}
}
如题所示,只要运行win函数就可获得shell,而这题要学一种新的漏洞:堆溢出,因为这题所用到的堆不需要很大很多,所以都由tcache分配,故不考虑其他情况;堆溢出因为只能造成任意地址写,并不能控制EIP,所以我此次要攻击的是GOT表的内容,通过修改GOT表指向的函数地址,然后由程序调用指定函数,从而达到间接控制EIP的目的,查看GOT表和函数地址如下:
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
0x400000 0x401000 r--p 1000 0 /home/gavin/warGame/heap/heap0
0x401000 0x402000 r-xp 1000 1000 /home/gavin/warGame/heap/heap0
0x402000 0x403000 r--p 1000 2000 /home/gavin/warGame/heap/heap0
0x403000 0x404000 r--p 1000 2000 /home/gavin/warGame/heap/heap0
0x404000 0x405000 rw-p 1000 3000 /home/gavin/warGame/heap/heap0
0x7ffff79e4000 0x7ffff7bcb000 r-xp 1e7000 0 /lib/x86_64-linux-gnu/libc-2.27.so
0x7ffff7bcb000 0x7ffff7dcb000 ---p 200000 1e7000 /lib/x86_64-linux-gnu/libc-2.27.so
0x7ffff7dcb000 0x7ffff7dcf000 r--p 4000 1e7000 /lib/x86_64-linux-gnu/libc-2.27.so
0x7ffff7dcf000 0x7ffff7dd1000 rw-p 2000 1eb000 /lib/x86_64-linux-gnu/libc-2.27.so
0x7ffff7dd1000 0x7ffff7dd5000 rw-p 4000 0
0x7ffff7dd5000 0x7ffff7dfc000 r-xp 27000 0 /lib/x86_64-linux-gnu/ld-2.27.so
0x7ffff7fdb000 0x7ffff7fdd000 rw-p 2000 0
0x7ffff7ff7000 0x7ffff7ffa000 r--p 3000 0 [vvar]
0x7ffff7ffa000 0x7ffff7ffc000 r-xp 2000 0 [vdso]
0x7ffff7ffc000 0x7ffff7ffd000 r--p 1000 27000 /lib/x86_64-linux-gnu/ld-2.27.so
0x7ffff7ffd000 0x7ffff7ffe000 rw-p 1000 28000 /lib/x86_64-linux-gnu/ld-2.27.so
0x7ffff7ffe000 0x7ffff7fff000 rw-p 1000 0
0x7ffffffde000 0x7ffffffff000 rw-p 21000 0 [stack]
0xffffffffff600000 0xffffffffff601000 r-xp 1000 0 [vsyscall]
pwndbg> telescope 0x404000 0x405000
00:0000│ 0x404000 (_GLOBAL_OFFSET_TABLE_) —▸ 0x403e20 (_DYNAMIC) ◂— 0x1
01:0008│ 0x404008 (_GLOBAL_OFFSET_TABLE_+8) —▸ 0x7ffff7ffe170 ◂— 0x0
02:0010│ 0x404010 (_GLOBAL_OFFSET_TABLE_+16) —▸ 0x7ffff7dec680 (_dl_runtime_resolve_xsave) ◂— push rbx
03:0018│ 0x404018 (_GLOBAL_OFFSET_TABLE_+24) —▸ 0x401036 (free@plt+6) ◂— push 0 /* 'h' */
04:0020│ 0x404020 (_GLOBAL_OFFSET_TABLE_+32) —▸ 0x401046 (puts@plt+6) ◂— push 1
05:0028│ 0x404028 (_GLOBAL_OFFSET_TABLE_+40) —▸ 0x401056 (system@plt+6) ◂— push 2
06:0030│ 0x404030 (_GLOBAL_OFFSET_TABLE_+48) —▸ 0x401066 (printf@plt+6) ◂— push 3
07:0038│ 0x404038 (_GLOBAL_OFFSET_TABLE_+56) —▸ 0x401076 (getchar@plt+6) ◂— push 4
08:0040│ 0x404040 (_GLOBAL_OFFSET_TABLE_+64) —▸ 0x401086 (gets@plt+6) ◂— push 5
09:0048│ 0x404048 (_GLOBAL_OFFSET_TABLE_+72) —▸ 0x401096 (malloc@plt+6) ◂— push 6
0a:0050│ 0x404050 (_GLOBAL_OFFSET_TABLE_+80) —▸ 0x4010a6 (setvbuf@plt+6) ◂— push 7
0b:0058│ 0x404058 (_GLOBAL_OFFSET_TABLE_+88) —▸ 0x4010b6 (__isoc99_scanf@plt+6) ◂— push 8
0c:0060│ 0x404060 (_GLOBAL_OFFSET_TABLE_+96) —▸ 0x4010c6 (exit@plt+6) ◂— push 9 /* 'h\t' */
0d:0068│ 0x404068 (data_start) ◂— 0x0
... ↓
10:0080│ 0x404080 (stdout@@GLIBC_2.2.5) —▸ 0x7ffff7dd0760 (_IO_2_1_stdout_) ◂— 0xfbad2084
11:0088│ 0x404088 (completed) ◂— 0x0
... ↓
pwndbg> info functions
All defined functions:
Non-debugging symbols:
0x0000000000401000 _init
0x0000000000401030 free@plt
0x0000000000401040 puts@plt
0x0000000000401050 system@plt
0x0000000000401060 printf@plt
0x0000000000401070 getchar@plt
0x0000000000401080 gets@plt
0x0000000000401090 malloc@plt
0x00000000004010a0 setvbuf@plt
0x00000000004010b0 __isoc99_scanf@plt
0x00000000004010c0 exit@plt
0x00000000004010d0 _start
0x0000000000401100 _dl_relocate_static_pie
0x0000000000401110 deregister_tm_clones
0x0000000000401140 register_tm_clones
0x0000000000401180 __do_global_dtors_aux
0x00000000004011b0 frame_dummy
0x00000000004011b2 win
0x00000000004011c5 menu
0x00000000004011fc get_int
0x0000000000401237 main
0x0000000000401430 __libc_csu_init
0x0000000000401490 __libc_csu_fini
0x0000000000401494 _fini
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
0x400000 0x401000 r--p 1000 0 /home/gavin/warGame/heap/heap0
0x401000 0x402000 r-xp 1000 1000 /home/gavin/warGame/heap/heap0
0x402000 0x403000 r--p 1000 2000 /home/gavin/warGame/heap/heap0
0x403000 0x404000 r--p 1000 2000 /home/gavin/warGame/heap/heap0
0x404000 0x405000 rw-p 1000 3000 /home/gavin/warGame/heap/heap0
0x7ffff79e4000 0x7ffff7bcb000 r-xp 1e7000 0 /lib/x86_64-linux-gnu/libc-2.27.so
0x7ffff7bcb000 0x7ffff7dcb000 ---p 200000 1e7000 /lib/x86_64-linux-gnu/libc-2.27.so
0x7ffff7dcb000 0x7ffff7dcf000 r--p 4000 1e7000 /lib/x86_64-linux-gnu/libc-2.27.so
0x7ffff7dcf000 0x7ffff7dd1000 rw-p 2000 1eb000 /lib/x86_64-linux-gnu/libc-2.27.so
0x7ffff7dd1000 0x7ffff7dd5000 rw-p 4000 0
0x7ffff7dd5000 0x7ffff7dfc000 r-xp 27000 0 /lib/x86_64-linux-gnu/ld-2.27.so
0x7ffff7fdb000 0x7ffff7fdd000 rw-p 2000 0
0x7ffff7ff7000 0x7ffff7ffa000 r--p 3000 0 [vvar]
0x7ffff7ffa000 0x7ffff7ffc000 r-xp 2000 0 [vdso]
0x7ffff7ffc000 0x7ffff7ffd000 r--p 1000 27000 /lib/x86_64-linux-gnu/ld-2.27.so
0x7ffff7ffd000 0x7ffff7ffe000 rw-p 1000 28000 /lib/x86_64-linux-gnu/ld-2.27.so
0x7ffff7ffe000 0x7ffff7fff000 rw-p 1000 0
0x7ffffffde000 0x7ffffffff000 rw-p 21000 0 [stack]
0xffffffffff600000 0xffffffffff601000 r-xp 1000 0 [vsyscall]
pwndbg> telescope 0x404000 0x405000
00:0000│ 0x404000 (_GLOBAL_OFFSET_TABLE_) —▸ 0x403e20 (_DYNAMIC) ◂— 0x1
01:0008│ 0x404008 (_GLOBAL_OFFSET_TABLE_+8) —▸ 0x7ffff7ffe170 ◂— 0x0
02:0010│ 0x404010 (_GLOBAL_OFFSET_TABLE_+16) —▸ 0x7ffff7dec680 (_dl_runtime_resolve_xsave) ◂— push rbx
03:0018│ 0x404018 (_GLOBAL_OFFSET_TABLE_+24) —▸ 0x401036 (free@plt+6) ◂— push 0 /* 'h' */
04:0020│ 0x404020 (_GLOBAL_OFFSET_TABLE_+32) —▸ 0x401046 (puts@plt+6) ◂— push 1
05:0028│ 0x404028 (_GLOBAL_OFFSET_TABLE_+40) —▸ 0x401056 (system@plt+6) ◂— push 2
06:0030│ 0x404030 (_GLOBAL_OFFSET_TABLE_+48) —▸ 0x401066 (printf@plt+6) ◂— push 3
07:0038│ 0x404038 (_GLOBAL_OFFSET_TABLE_+56) —▸ 0x401076 (getchar@plt+6) ◂— push 4
08:0040│ 0x404040 (_GLOBAL_OFFSET_TABLE_+64) —▸ 0x401086 (gets@plt+6) ◂— push 5
09:0048│ 0x404048 (_GLOBAL_OFFSET_TABLE_+72) —▸ 0x401096 (malloc@plt+6) ◂— push 6
0a:0050│ 0x404050 (_GLOBAL_OFFSET_TABLE_+80) —▸ 0x4010a6 (setvbuf@plt+6) ◂— push 7
0b:0058│ 0x404058 (_GLOBAL_OFFSET_TABLE_+88) —▸ 0x4010b6 (__isoc99_scanf@plt+6) ◂— push 8
0c:0060│ 0x404060 (_GLOBAL_OFFSET_TABLE_+96) —▸ 0x4010c6 (exit@plt+6) ◂— push 9 /* 'h\t' */
0d:0068│ 0x404068 (data_start) ◂— 0x0
... ↓
10:0080│ 0x404080 (stdout@@GLIBC_2.2.5) —▸ 0x7ffff7dd0760 (_IO_2_1_stdout_) ◂— 0xfbad2084
11:0088│ 0x404088 (completed) ◂— 0x0
... ↓
pwndbg> info functions
All defined functions:
Non-debugging symbols:
0x0000000000401000 _init
0x0000000000401030 free@plt
0x0000000000401040 puts@plt
0x0000000000401050 system@plt
0x0000000000401060 printf@plt
0x0000000000401070 getchar@plt
0x0000000000401080 gets@plt
0x0000000000401090 malloc@plt
0x00000000004010a0 setvbuf@plt
0x00000000004010b0 __isoc99_scanf@plt
0x00000000004010c0 exit@plt
0x00000000004010d0 _start
0x0000000000401100 _dl_relocate_static_pie
0x0000000000401110 deregister_tm_clones
0x0000000000401140 register_tm_clones
0x0000000000401180 __do_global_dtors_aux
0x00000000004011b0 frame_dummy
0x00000000004011b2 win
0x00000000004011c5 menu
0x00000000004011fc get_int
0x0000000000401237 main
0x0000000000401430 __libc_csu_init
0x0000000000401490 __libc_csu_fini
0x0000000000401494 _fini
表中有一个exit函数,从伪代码中可以得到,只要将exit函数地址修改为win函数地址,然后在菜单中选择退出,就可以执行win函数从而得到shell,攻击脚本如下(注意看脚本中的注释):
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!