I’m a bit stuck. Got a C code and a precompiled (target) binary.
//gcc malloc.c -o malloc -m32
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
int main()
{
unsigned int *tab, n, k, v, PoC = 0;
printf("PoC at %pn",&PoC);
printf("n: ");
scanf("%u",&n);
tab = malloc(n*sizeof(int));
if(tab == 0)
return 1;
printf("Success! (%p)n",tab);
printf("tab[k]=v; k,v: ");
scanf("%u%u",&k,&v);
if(k<n)
tab[k] = v;
else
puts("k>=n - FAIL");
if(PoC == 1337)
puts("Victory!");
}
So (if I got it right) to overwrite PoC (to make it 1337) while I control input to heap.
Compiled the binary and used gdb(gef) on it, n=4, breakpoint on 18:
gef➤ print &PoC
$1 = (unsigned int *) 0xffffcfac
gef➤ print tab
$2 = (unsigned int *) 0x5655a9c0
gef➤ print (0xffffcfac - 0x5655a9c0) /4
$3 = 0x2a6a897b
gef➤ p/d (0x2a6a897b)
$4 = 711625083
my guess it’s way too far for just overflowing with input from scanf(“%u%u”,&k,&v);
only v could be used, as k is checked against size of n.
gef➤ info proc map
Mapped address spaces:
Start Addr End Addr Size Offset Perms objfile
0x56555000 0x56556000 0x1000 0x0 r--p /home/kali/Desktop/malloc
0x56556000 0x56557000 0x1000 0x1000 r-xp /home/kali/Desktop/malloc
0x56557000 0x56558000 0x1000 0x2000 r--p /home/kali/Desktop/malloc
0x56558000 0x56559000 0x1000 0x2000 r--p /home/kali/Desktop/malloc
0x56559000 0x5655a000 0x1000 0x3000 rw-p /home/kali/Desktop/malloc
0x5655a000 0x5657c000 0x22000 0x0 rw-p [heap]
0xf7c00000 0xf7c22000 0x22000 0x0 r--p /usr/lib32/libc.so.6
0xf7c22000 0xf7d9b000 0x179000 0x22000 r-xp /usr/lib32/libc.so.6
0xf7d9b000 0xf7e1c000 0x81000 0x19b000 r--p /usr/lib32/libc.so.6
0xf7e1c000 0xf7e1e000 0x2000 0x21b000 r--p /usr/lib32/libc.so.6
0xf7e1e000 0xf7e1f000 0x1000 0x21d000 rw-p /usr/lib32/libc.so.6
0xf7e1f000 0xf7e29000 0xa000 0x0 rw-p
0xf7fc2000 0xf7fc4000 0x2000 0x0 rw-p
0xf7fc4000 0xf7fc8000 0x4000 0x0 r--p [vvar]
0xf7fc8000 0xf7fca000 0x2000 0x0 r-xp [vdso]
0xf7fca000 0xf7fcb000 0x1000 0x0 r--p /usr/lib32/ld-linux.so.2
0xf7fcb000 0xf7fed000 0x22000 0x1000 r-xp /usr/lib32/ld-linux.so.2
0xf7fed000 0xf7ffb000 0xe000 0x23000 r--p /usr/lib32/ld-linux.so.2
0xf7ffb000 0xf7ffd000 0x2000 0x30000 r--p /usr/lib32/ld-linux.so.2
0xf7ffd000 0xf7ffe000 0x1000 0x32000 rw-p /usr/lib32/ld-linux.so.2
0xfffdd000 0xffffe000 0x21000 0x0 rw-p [stack]
target (precompiled) binary is also secured?
└─$ pwn checksec ./malloc
Arch: i386-32-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
Decomplied in ghidra (cleaned few variable names):
/* WARNING: Function: __x86.get_pc_thunk.bx replaced with injection: get_pc_thunk_bx */
undefined4 main(void)
{
undefined4 uVar1;
int in_GS_OFFSET;
uint n;
uint k;
undefined4 v;
int local_1c;
void *tab;
int local_14;
undefined *local_10;
local_10 = &stack0x00000004;
local_14 = *(int *)(in_GS_OFFSET + 0x14);
local_1c = 0;
printf("PoC at %pn",&local_1c);
printf("n: ");
__isoc99_scanf(&DAT_0001081f,&n);
tab = malloc(n << 2);
if (tab == (void *)0x0) {
uVar1 = 1;
}
else {
printf("Success! (%p)n",tab);
printf("tab[k]=v; k,v: ");
__isoc99_scanf(&DAT_00010841,&k,&v);
if (k < n) {
*(undefined4 *)(k * 4 + (int)tab) = v;
}
else {
puts("k>=n - FAIL");
}
if (local_1c == 0x539) {
puts("Victory!");
}
uVar1 = 0;
}
if (local_14 != *(int *)(in_GS_OFFSET + 0x14)) {
uVar1 = __stack_chk_fail_local();
}
return uVar1;
}
Really need a hint, I’m new to binary exploitation.
Heapster is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.