Home Write ups

[MBE RPI SEC] Lab 8

04 Apr 2020

lab8C

lab8B

lab8A

1) lab8C

The program ask us to provide two file name or file descriptor and compares their differences. After spend some hours to search complicates things in the program, the function securityCheck get my attention:

char* securityCheck(char* arg, char* s)
{
	if(strstr(arg, ".pass"))
		return "<<<For security reasons, your filename has been blocked>>>";
	return s;
}

If a file name contains the string “.pass”, the string “«<For security reasons, your filename has been blocked»>” will be compared with the other but the file content will be loaded in the program.

To verify this, I created a file named “.pass” with a string inside. If I placed a breakpoint at 0xXXXXXedf and I run the program with these arguments: -fn=.pass -fd=20 (any number can be entered for the second argument it is not matter), you can see that the content of the file in the stack:

filecontent

But in the server, it is not possible to open the .pass file because gdb drop the setuid rights so we need to find another way.

The first number for the file descriptor corresponds to STDIN,STDOUT and STDERR. So the next new file opened get the file descriptor number 3. To obtain the content of .pass, these arguments need to be entered -fn=/home/lab8B/.pass -fd=3:

pass8c

2) lab8B

The program allows creating two vectors with some integer parameters in different data types (car, short int, unsigned long, etc). It is possible to sum the two vectors in a third vector and save this vector like favourites. I can save 10 favourites vectors.

After some tests, I saw some strange behaviour when I print the list of favourites. It seems the program is bugged here. After checking the code, I found the problem in the function fave when the memcpy function is called:

memcpy(faves[i], (int*)(&v3)+i, sizeof(struct vector));

The pointer of the destination is increased by one. It means that the next source does not point to the next vector structure but to the next parameter (the next “integer”).

Let’s check with gdb what happens. I placed a breakpoint to the memcpy call and we can see below the arguments for memcpy before the call:

fave1

The src argument points to the beginning of the vector structure and it is corresponding to the address of the printf function. It is the default value for all vectors like you can see below:

int main(int argc, char** argv)
{
	char sel;
	printMenu();
	v1.printFunc = printf;
	v2.printFunc = printf;
	v3.printFunc = printf;

Below, the values of the first saved vector:

print1

The function pointer point to the printf address. Let’s check if we save a second time the same vector.

fave2

The src argument points to the next “integer”. 0x40062 corresponds to the char value (b in ASCII) and 4 to the value of the short int 4. The size of a char is equals to one byte and an address is equals to 4 bytes. It is the reason why we see the value of the short int and the value of the char in the pointer function.

A function named thisIsASecret call the system function:

/*
 * Bonus points if you don't use this function.
 */
void thisIsASecret()
{
	system("/bin/sh");
}

So if I enter in the good integer the value of the thisIsASecret address in decimal format and save enough vectors, I will be able to overwrite the function pointer and jump to the function thisIsASecret. To do this, I will use a Python script that you can download here.

3) lab8A

The program allows you to read some “books” named A, B and C and that’s all. I check the security enable in the program:

checksec

The code contains two obtain obvious vulnerabilities:

    /* Our Apologies,the interface is currently under developement */
    char buf_secure[512];
    scanf("%s", buf_secure);
    printf(buf_secure); <= basic format string vulnerability
/* We specialize in words of wisdom */
    char buf[24];
    // to avoid the null
    global_addr = (&buf+0x1);
    // have to make sure no one is stealing the librarians cookies (they get angry)
    global_addr_check = global_addr-0x2;
    char lolz[4];

    printf("\n..I like to read ^_^ <==  ");
    read(STDIN, buf, 2048); // >> read a lot every day ! <= buffer overflow here

To overwrite the RET address we need to bypass this condition:

if(((*( global_addr))^(*(global_addr_check))) != ((*( global_addr))^(0xdeadbeef))){
        printf("\n\nWoah There\n");
        // why are you trying to break my program q-q
        exit(EXIT_FAILURE);
    }

    // protected by my CUSTOM cookie - so soooo safe now
    return;

Thanks to the buffer overflow, it is possible with the following code:

p.recvuntil("[+] Enter Your Favorite Author's Last Name:")
p.sendline("A")
p.recvuntil("..I like to read ^_^ <==  ")
p.sendline("A"*16+"\xEF\xBE\xAD\xDE"

If we try to overflow the RET address, we will see this error:

*** stack smashing detected ***: ./lab8A terminated

It is because of the canary is enabled. With Ghidra, we can see where the canary is checked:

canary

To bypass this protection, we can get the random value through the format string. If we check the content of the stack before calling the vulnerable printf, we can see where the canary is located:

bypass

It is easy to calculate the offset:

Now, we can place the value of canary and a classic ropchain in the right place in the buffer overflow in order to pop the shell.

You can download the solution here.