Posts Bruteforcing forks to leak stack canary [Pwn]
Post
Cancel

Bruteforcing forks to leak stack canary [Pwn]

In 2022 I learned a new technique to leak the stack canary with an interesting challenge developed by Animanegra. The challenge is called pwn7, and Animanegra was very insistent that I tried to solve it. Recently, I found time to solve it (one year later :D) and I decided to publish this write-up to explain this new concept. Thanks Animanegra for this original and fun challenge.

pwn7

The program has two parts: the first part, executed by a child created by a fork, asks the user for a number and always prints Noooope. The second part, executed by the parent, asks the user if they want to terminate the execution or if they want to enter another number (which creates another fork).

In addition, it has a function called win that prints the flag and the objective of the challenge is to call this function.

The most interesting part of source code is the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
void bad(){

	char lalala[16]="y";
	int pid;
	char leeme;
	int i;
	int myrand;

	while(strcmp(lalala,"y") == 0){

		myrand=rand();

		pid = fork();

		if(pid == 0){

			printf("In what number I am thinking?(0-1000):\n");
			fflush(stdout);
			i=0;
			leeme=(char)getchar();
			while(leeme != '\n'){
				lalala[i]=leeme;
				leeme=(char)getchar();
				i=i+1;
			}

			printf("Noooope\n");

			return;

		}else{

			lalala[0]='n';

			usleep(100000);

			printf("Do you want to continue (y/n)?\n");
			fflush(stdout);

			gets(lalala);
	
		}

	}

	printf("Program finished\n");

}

In this challenge, the vulnerabilities are very obvious. Both the parent’s and the child’s code have stack buffer overflow vulnerabilities when handling user input. In the parent’s part, we have a vulnerable call to gets that saves a non-fixed-length string into a buffer that is only 16 bytes long. In the child’s part, on the other hand, we have a loop that copies the user’s input into a one-byte-sized variable.

The difficulty of this challenge is that it’s built with a stack canary, and if we try to exploit these vulnerabilities directly with ROP the attack will be mitigated.

Bruteforcing forks to leak stack canary

First of all, it’s important to explain at a high level how the fork function works. When we call the fork function on Linux, a new process will be executed (with a different PID), and it will continue the execution in the same code instruction and with the same memory as its parent. The only difference between both is the value returned by fork - fork returns the PID of the child when executed on the parent, while when executed on the child it returns a value of zero. To branch to a different code the program uses this difference.

Since the process memory will be cloned each time a new child is spawned, the child and parent will have the same canary stack. We can use child processes to brute force this value, because triggering SIGABORT in a child won’t affect the parent.

Once we leak the canary, we can patch it and ROP into the win function.

The full exploit code is here.

Note that the exploit code is slightly different when used locally or remotely. Locally, we receive the error message of the stack canary validation through stderr, whereas remotely, we receive the Noooope string or not, depending on the stack canary’s validation result.

This post is licensed under CC BY 4.0 by the author.
Contents