## Matryoshka (Crackme, 50+100+300+500)
This task was a crackme, which given correct password, spits out the next stage (base64-encoded).Let's start with the first one.
## Stage 1
Running the binary normally, we get the usage information:```$ ./stage1.binUsage: ./stage1.bin <pass>$ ./stage1.bin testTry again...```Hmm, let's trace the binary to see which libraries it calls:```$ ltrace ./stage1.bin testPass__libc_start_main(0x40064d, 2, 0x7ffc81da72a8, 0x4007a0 <unfinished ...>strcmp("testPass", "Much_secure__So_safe__Wow")  = 39fwrite("Try again...\n", 1, 13, 0x7fd915fba740Try again...)  = 13+++ exited (status 1) +++```We see it compares our input against constant. Running `./stage1.bin Much_secure__So_safe__Wow` gives us the nextstage.
## Stage 2
This time we are out of luck: tracing the binary doesn't help. We need to disassemble the binary.Looking at the code, we see it consists of about 15 comparisons, such as:```0x004007b0      mov rax, qword [rbp - local_30h]0x004007b4      add rax, 80x004007b8      mov rax, qword [rax] ; rax=pass0x004007bb      movzx eax, byte [rax] ; rax=pass[0]0x004007be      movsx eax, al0x004007c1      lea edx, [rax + 0x10] ; edx=pass[0]+0x100x004007c4      mov rax, qword [rbp - local_30h]0x004007c8      add rax, 80x004007cc      mov rax, qword [rax] ; rax=pass0x004007cf      add rax, 60x004007d3      movzx eax, byte [rax] ; rax=pass[6]0x004007d6      movsx eax, al0x004007d9      sub eax, 0x10 ; rax-=0x100x004007dc      cmp edx, eax0x004007de      je 0x4007e7  ;[2]0x004007e0      mov dword [rbp - local_14h], 00x004007e7      mov rax, qword [rbp - local_30h]```This particular comparison can be stated as `pass[0]+0x10=pass[6]-0x10`. I stepped through the whole binary andkeeped track of all the equations:```b[0]='P'2*b[3]=200 <=> b[3]=100 <=> b[3]='d'b[0]+0x10=b[6]-0x10 <=> b[6]='p'b[5]=0x5f <=> b[5]='_'b[1]=b[7] b[1]=b[10]b[1]-0x11=b[0] <=> b[1]='a', b[7]='a', b[10]='a'b[3]=b[9] <=> b[9]='d'b[4]='i'b[2]-b[1]=0xd <=> b[2]='n'b[8]-b[7]=0xd <=> b[8]='n'
b="Pandi_panda"```We can construct a full password using those equations: `Pandi_panda`. Again, passing this phrase to the executablegives us another stage.
## Stage 3
This binary was much funnier. Instead of using normal calls and jumps, it relied on Unix signals for flow control.The original code could look something like this:```cint main(int argc, char** argv){	// Stuff, checking for length and so on skipped.	int pid=getpid();	signal(SIGINT, fn1);	for(int i=0;i<1024;i++){		kill(pid, SIGINT);	}}
void fn1(int sig){	if(first_pass_character_is_ok){		signal(SIGINT, fn2);	}}
void fn2(int sig){	if(second_pass_character_is_ok){		signal(SIGINT, fn3);	}}
// And so on. The last function printed congratulations and next stage.```Each function sets SIGINT's handler to the next one if it's password character was correct. These functions werequite boring to reverse (but if needed, I could do this). Instead, I relied on `LD_PRELOAD`.
Since each character was checked on its own, isolated from the others, I could brute force each characterindividually. It turned out to be quite problematic - as these functions were returning `void`, I couldn't knowif the character is good. I decided to replace `signal` function as well - this way, if it was called, I knew thatpassword was OK.
This is the code I wrote:```c#include <stdio.h>#include <stdlib.h>
unsigned int tab[]= { 0x4007fd,0x40085c,0x4008c7,0x400926,0x40098a,	0x4009e8,0x400a4c,0x400ab0,0x400b14,0x400b73,0x400bd7,0x400c36,	0x400c95,0x400d0c,0x400d6b,0x400dcf,0x400e2e,0x400e8d,0x400eec,	0x400f4b,0x400faa,0x40100e };char* pass=(char*)0x6040c0;void testx(int a){}
char password[50];int i;unsigned char cc;
typedef void (*sighandler_t)(int);sighandler_t signal(int signum, sighandler_t handler){	password[i]=cc;	printf("%s\n", password);	return testx;}
__attribute__((constructor)) void init(){	for(i=0;i