Blog

  • Using gdb

    Using gdb

    I figured I’ll write a mini-tutorial on how to use gdb, because there’s not that many places where they teach you how to use gdb effectively.

    Let’s say you have a program and it crashes, what do you do?

    Example code:

    “`


    void func() { char *p = 0; *p = 0x69; }


    int main() { func(); }


    “`

    Next:

    “`


    gdb a.out

    “`

    Followed by the `run` command:

    “`


    (gdb) run

    Starting program: /home/d/a.out

    [Thread debugging using libthread_db enabled]

    Using host libthread_db library “/lib/x86_64-linux-gnu/libthread_db.so.1”.


    Program received signal SIGSEGV, Segmentation fault.

    0x000055555555513d in func () at test.c:1

    1 void func() { char *p = 0; *p = 0x69; }

    (gdb)

    “`

    You can see where it crashes, but you’d like a stacktrace…

    “`


    gdb) bt

    #0 0x000055555555513d in func () at test.c:1

    #1 0x0000555555555155 in main () at test.c:3

    (gdb)

    “`

    (NB: `bt` stands for backtrace)

    You can go up a frame and check local variables:

    “`


    (gdb) up

    #1 0x0000555555555155 in main () at test.c:3

    3 int main() { func(); }

    (gdb) info local

    No locals.

    “`

    Or down a frame and check local variables:

    “`


    (gdb) down

    #0 0x000055555555513d in func () at test.c:1

    1 void func() { char *p = 0; *p = 0x69; }

    (gdb) info local

    p = 0x0

    “`

    You can continue after the segfault:

    “`

    (gdb) cont

    Continuing.


    Program terminated with signal SIGSEGV, Segmentation fault.

    The program no longer exists.

    (gdb)

    “`

    Now we can re-run it, but before we do, we can set a breakpoint:

    “`

    (gdb) break func

    Breakpoint 1 at 0x555555555131: file test.c, line 1.

    (gdb)


    “`

    Now we run it again, it will stop at the breakpoint:

    “`


    (gdb) run

    Starting program: /home/d/a.out

    [Thread debugging using libthread_db enabled]

    Using host libthread_db library “/lib/x86_64-linux-gnu/libthread_db.so.1”.


    Breakpoint 1, func () at test.c:1

    1 void func() { char *p = 0; *p = 0x69; }

    (gdb)

    “`

    We can single step through it:

    “`


    (gdb) step


    Program received signal SIGSEGV, Segmentation fault.

    0x000055555555513d in func () at test.c:1

    1 void func() { char *p = 0; *p = 0x69; }

    (gdb)

    “`

    We can also try the command `next`, which is similar to `step` but skips over subroutines.

    We can get help from gdb at any time using `help`.

    Another useful `info` command is `info reg`, which shows CPU registers.

    Also useful is `disas` command, which disassembles the code.

     

  • Using RTL-SDR under Linux

    Using RTL-SDR under Linux

    First steps:

    “`

    sudo apt install rtl-sdr gnuradio-dev gqrx

    “`

    This will install GQRX, which is an excellent program to view and listen to the spectrum.

    When running GQRX, you need to specify the I/O device. Input should be your RTL-SDR and output should be your soundcard device.

    Next, specify an FM radio station and you should be able to tune to it quite easily, remembering to demodulate WFM (Wide FM) Stereo to hear it properly.

    Note the spectrum analysis is done by FFT (Fast Fourier Transform) on the signals received by the SDR. This is the brilliancy of using SDRs — they make cheap spectrum analyzers — spectrum analyzers used to cost $250k AUD back in the day!

    Next you might want to try dump1090, which gets you an airplane’s transponder information.

    “`

    sudo apt install dump1090 (or it’s dump1090-mutability)

    dump1090 –interactive –net

    “`

    Some other interesting things:

    NSW Police radio band (unfortunately they use encrypted radios, but it’s interesting if you’re studying P25 encrypted radio protocol):

    https://www.radioreference.com/db/aid/1026

    There’s something interesting about using encryption (AES-256) — it means they use a shared key, and for it to be a stream cipher (e.g. CBC or GCM modes), it means everyone has to lock onto some timing signal to synchronize the stream cipher, or else they use the insecure block modes to encrypt their data. Best case is they use a nonce in AES-256-GCM mode.

    I wonder if the radios they use are easily buffer overflow hackable… (e.g. imagine sending a dodgy encrypted packet on the air and hacking every police radio at the same time!)

    I wish I could get my hands on a police radio to reverse engineer. But I think since they use a standard protocol (P25), all I need is an encrypted P25 radio, e.g. from Motorola, etc.

    Something for the people at ASD (Australian Signals Directorate) to play with, I’m sure.

  • What is a buffer overflow, anyway? By j00n1x

    What is a buffer overflow, anyway? By j00n1x

    S0 my f3ll0w pupils, j00 w4nt t0 kn0w wh4t a buff3r 0verfl0w is, am i right? J00 w4nt t0 b3 1337?

    Let’s follow in the footsteps of someone before us: aleph1’s article in phr4ck.

    https://phrack.org/issues/49/14.html

    Okay? Have you read that? D0 j00 f33l l33t n0w?

  • Smallest hello world in linux assembly

    Smallest hello world in linux assembly

    From https://jameshfisher.com/2018/03/10/linux-assembly-hello-world/

    global _start

    section .text

    _start:
      mov rax, 1        ; write(
      mov rdi, 1        ;   STDOUT_FILENO,
      mov rsi, msg      ;   “Hello, world!n”,
      mov rdx, msglen   ;   sizeof(“Hello, world!n”)
      syscall           ; );

      mov rax, 60       ; exit(
      mov rdi, 0        ;   EXIT_SUCCESS
      syscall           ; );

    section .rodata
      msg: db “Hello, world!”, 10
      msglen: equ $ – msg

    However, when we assemble and link it, it will actually be quite large.

    $ nasm -f elf64 -o hello.o hello.s
    $ ld -o hello hello.o
    $ ./hello
    Hello, world!

    $ ls -al hello
    -rwxrwxr-x 1 d d 8872 Jun 12 08:22 hello

    That’s because it uses a section .rodata, which requires a read-only memory page, on top of a code page (read-executable). So that requires 8KB (if 4KB pages are used) in your binary.

    Still, it’s smaller than a “puts(“Hello world”)” C example program.


    #include <stdio.h>

    int main()
    {
        puts(“Hello, world!”);
        return 0;
    }

    Size of C program:


    $ gcc test.c
    $ ls -al a.out
    -rwxrwxr-x 1 d d 15960 Jun 12 08:24 a.out

    $ strip a.out
    $ ls -al a.out
    -rwxrwxr-x 1 d d 14472 Jun 12 08:25 a.out

    Going back to the assembly program, to shrink it down even more so, the modified source code is then:


    global _start

    section .text

    _start:
      mov rax, 1        ; write(
      mov rdi, 1        ;   STDOUT_FILENO,
      mov rsi, msg      ;   “Hello, world!n”,
      mov rdx, msglen   ;   sizeof(“Hello, world!n”)
      syscall           ; );

      mov rax, 60       ; exit(
      mov rdi, 0        ;   EXIT_SUCCESS
      syscall           ; );

      msg: db “Hello, world!”, 10
      msglen: equ $ – msg

    The same code, without the section .rodata. It just means the text string “Hello World” is actually in the code (.text section) page.

    Next step is to strip the binary — to make it even slightly more smaller.

    This is the best we can do, without hacking the binary any further.


    $ ls -al hello
    -rwxrwxr-x 1 d d 4360 Jun 12 08:19 hello

    So that’s 4KB, plus abit more, if you include the ELF headers.

    Creating our own ELF headers

    Taking from the following articles:

    https://www.muppetlabs.com/%7Ebreadbox/software/tiny/teensy.html

    https://stackoverflow.com/questions/53382589/smallest-executable-program-x86-64-linux

    We create our own ELF header and just build using `nasm -o test test.s`


    bits 64
                org 0x08048000

    ehdr:                                           ; Elf64_Ehdr
                db  0x7F, “ELF”, 2, 1, 1, 0         ;   e_ident
        times 8 db  0
                dw  2                               ;   e_type
                dw  62                              ;   e_machine
                dd  1                               ;   e_version
                dq  _start                          ;   e_entry
                dq  phdr – $$                       ;   e_phoff
                dq  0                               ;   e_shoff
                dd  0                               ;   e_flags
                dw  ehdrsize                        ;   e_ehsize
                dw  phdrsize                        ;   e_phentsize
                dw  1                               ;   e_phnum
                dw  0                               ;   e_shentsize
                dw  0                               ;   e_shnum
                dw  0                               ;   e_shstrndx

    ehdrsize    equ $ – ehdr

    phdr:                                           ; Elf64_Phdr
                dd  1                               ;   p_type
                dd  5                               ;   p_flags
                dq  0                               ;   p_offset
                dq  $$                              ;   p_vaddr
                dq  $$                              ;   p_paddr
                dq  filesize                        ;   p_filesz
                dq  filesize                        ;   p_memsz
                dq  0x1000                          ;   p_align

    phdrsize    equ     $ – phdr

    _start:
      mov rax, 1        ; write(
      mov rdi, 1        ;   STDOUT_FILENO,
      mov rsi, msg      ;   “Hello, world!n”,
      mov rdx, msglen   ;   sizeof(“Hello, world!n”)
      syscall           ; );

      mov rax, 60       ; exit(
      mov rdi, 0        ;   EXIT_SUCCESS
      syscall           ; );

      msg: db “Hello, world!”, 10
      msglen: equ $ – msg

    filesize      equ     $ – $$

    We build it with nasm:


    $ nasm -o test test.s

    $ ls -al test
    -rwxr-xr-x 1 d d 173 Jun 12 08:35 test

    The output is 173 bytes! That’s small. But it can be improved, based off those articles above.

  • Hacking 102 – Leaking the canary with strncpy

    Hacking 102 – Leaking the canary with strncpy

    A convoluted example of how you can leak GCC’s stack protector canary with a strncpy, thanks to strncpy not null terminating when the strlen is greater than or equal to the buffer size specified in the 3rd parameter.

    get_canary() just verifies it’s actually the same as GCC’s canary.


    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    unsigned long get_canary()
    {
        asm(“mov %fs:0x28, %rax”);
    }

    // prints out our string, which is a non-null terminated string, thanks to strncpy’s rule of not null terminating!

    void print_str(const char *str)
    {
        for (int i = 0; i < strlen(str); i++) {
            printf(“%x”, (unsigned char) str[i]);
        }

        printf(“n”);

        for (int i = 0; i < strlen(str) + 16; i+=8) {
            unsigned long *p = (unsigned long *) &str[i];
            printf(“%lx “, *p);
        }

        printf(“n”);

        unsigned long *canary = (unsigned long *) &str[256+8];

        printf(“Is this the canary getting leaked out? %lxn”, *canary);

        printf(“Hint: Ignore the last two hex digits, as that’s just ‘A’ character, overwriting the 0x00 nulln”);

    }

    void func(const char *input)
    {
        char buf[256];

        // NB: This is a convoluted strncpy, probably won’t find it in the wild, but you never know…

        strncpy(buf, input, sizeof(buf)+9); // non-null termination AND off-by-one! — overwrite with ‘A’ on the last number of the canary, as it’s zero (i.e. little endian 00 aa bb cc dd ee ff 11, so the 00 stops printing it out
                            // cause it’s null, but if we use strncpy with an off-by-one that hits the last digit (first digit little endian) then we can print it out

        // also, 8 bytes is just empty part of the stack, so that’s why it’s 9 bytes. 8 empty bytes, + 1 off-by-one.

        print_str(buf);
    }

    int main()
    {
        char input[1024];

        memset(input, ‘A’, sizeof(input));

        printf(“Canary: %lxn”, get_canary());

        func(input);
    }

    Output:

    $ gcc test.c

    $ ./a.out
    Canary: 6af07ba9ba12d800
    41414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141d812baa97bf06ad0ac548dff7f
    4141414141414141 4141414141414141 4141414141414141 4141414141414141 4141414141414141 4141414141414141 4141414141414141 4141414141414141 4141414141414141 4141414141414141 4141414141414141 4141414141414141 4141414141414141 4141414141414141 4141414141414141 4141414141414141 4141414141414141 4141414141414141 4141414141414141 4141414141414141 4141414141414141 4141414141414141 4141414141414141 4141414141414141 4141414141414141 4141414141414141 4141414141414141 4141414141414141 4141414141414141 4141414141414141 4141414141414141 4141414141414141 4141414141414141 6af07ba9ba12d841 7fff8d54acd0 55ce63ecb3f8 4141414141414141
    Is this the canary getting leaked out? 6af07ba9ba12d841
    Hint: Ignore the last two hex digits, as that’s just ‘A’ character, overwriting the 0x00 null
    *** stack smashing detected ***: terminated

    Notice the bold/underline is the canary in reverse, because it’s stored little endian on x86_64.

  • Hacking 101 – stack buffer overflows on x86_64

    Hacking 101 – stack buffer overflows on x86_64

    I won’t explain in too much detail, but the following code creates a buffer overflow that controls the return instruction pointer on the stack, changing the flow of the code into calling func2().

    /*

        compile: gcc test.c -fno-stack-protector
        run: ./a.out 4 (or ./a.out 2… greater than ./a.out 1)

    */

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    //#define USE_CANARY

    void func2()
    {
        printf(“I did it!n”);
    }

    void func(const char *input)
    {
    #ifdef USE_CANARY
        long int canary = 0xdeadbeefc001d00d;
    #endif
        char buf[256];

    //    strcpy(buf, input);
    // cause there’s a null in the address…

        memcpy(buf, input, 256+8*8);
        // buffer overfl0wwwwwwwwwww

        printf(“buf: %sn”, buf);
        fflush(stdout);

    #ifdef USE_CANARY
        if (canary != 0xdeadbeefc001d00d) {
            printf(“Buffer overflow detected! Aborting!n”);
            abort();
        }
    #endif
    }

    int main(int argc, char **argv)
    {
        
        char input[1024];
        int loop;

        // fill up input with ‘A’ x 256 (leaving 1024-256 bytes left)
        memset(input, ‘A’, 256);

        printf(“size of func2’s pointer (in bytes): %ldn”, sizeof(&func2));
        printf(“func2’s address: %lxn”, (unsigned long) func2);

        if (argc < 2) {
            loop = 4;
        }

        else {
            loop = atoi(argv[1]);
        }

        // fill past the ‘A’s with a pointer to func2(), up to “loop”.
        for (int i = 0; i < loop; i++) {
            unsigned long *p = (unsigned long *) (input + 256 + i * sizeof(&func2));
            *p = (unsigned long) func2;
        }

        printf(“input: %sn”, input);

        // verify the func2’s addresses are actually inside the input buffer.

        for (int i = 0; i < loop; i++) {
            char *p = input + 256 + i * sizeof(&func2);
            unsigned long *q = (unsigned long *) p;
            printf(“address: %lxn”, *q);
        }

        // call func with input buffer.

        func(input);
    }

    Output:


    gcc test.c -fno-stack-protector

    $ ./a.out

    size of func2’s pointer (in bytes): 8
    func2’s address: 561e883a51e9
    input: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�Q:�V
    address: 561e883a51e9
    address: 561e883a51e9
    address: 561e883a51e9
    address: 561e883a51e9
    buf: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�Q:�V
    I did it!
    I did it!
    I did it!
    Segmentation fault (core dumped)

    Creating our own Canary

    Notice if you compiled with -DUSE_CANARY, it uses our artificial canary, and will abort before the overflow exploits the return instruction pointer.

    gcc test.c -fno-stack-protector -DUSE_CANARY
    $ ./a.out

    size of func2’s pointer (in bytes): 8
    func2’s address: 562a98ea0209
    input: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA    �*V
    address: 562a98ea0209
    address: 562a98ea0209
    address: 562a98ea0209
    address: 562a98ea0209
    buf: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA    �*V
    Buffer overflow detected! Aborting!
    Aborted (core dumped)

    Comparing with gcc’s canary

    Now if you look at a normal compilation, and check out the assembly using `objdump -D ./a.out`

    0000000000001223 <func>:
        1223:       f3 0f 1e fa             endbr64
        1227:       55                      push   %rbp
        1228:       48 89 e5                mov    %rsp,%rbp
        122b:       48 81 ec 20 01 00 00    sub    $0x120,%rsp
        1232:       48 89 bd e8 fe ff ff    mov    %rdi,-0x118(%rbp)
        1239:       64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
        1240:       00 00
        1242:       48 89 45 f8             mov    %rax,-0x8(%rbp)
        1246:       31 c0                   xor    %eax,%eax

            …. more opcodes ….

        … followed at the end by …

        12a4:       e8 17 fe ff ff          call   10c0 <__stack_chk_fail@plt>
        12a9:       c9                      leave  
        12aa:       c3                      ret    



    This is the setting of the canary and the checking of the canary at the end of the function, done by the compiler.

    The objdump without stack protector for func is:

    <func>:
        1203:       f3 0f 1e fa             endbr64
        1207:       55                      push   %rbp
        1208:       48 89 e5                mov    %rsp,%rbp
        120b:       48 81 ec 10 01 00 00    sub    $0x110,%rsp
        1212:       48 89 bd f8 fe ff ff    mov    %rdi,-0x108(%rbp)

    You can see the canary’s secret value is stored in %fs:0x28, and gets moved to register %rax, which then gets copied onto the frame pointer %rbp – 8 bytes, which is just before the saved frame pointer, and two pointers from the return instruction pointer on the stack.

    If you can leak the %fs:0x28 value, you can overwrite the canary with the same value during the overflow, and thus bypass the canary check.

    This is the reason why %rax is cleared (xor %rax, %rax), to avoid leaking the value in the %rax register.

    Getting the canary secret value from gcc via some means, and then using it

    Source code follows:

    /*

        compile: gcc test.c -fno-stack-protector
        run: ./a.out 4 (or ./a.out 2… greater than ./a.out 1)

    */

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    //#define USE_CANARY

    unsigned long get_canary()
    {
        asm(“mov %fs:0x28, %rax”);
    }

    void func2()
    {
        printf(“I did it!n”);
    }

    void func(const char *input)
    {
    #ifdef USE_CANARY
        long int canary = 0xdeadbeefc001d00d;
    #endif
        char buf[256];

    //    strcpy(buf, input);
    // cause there’s a null in the address…

        memcpy(buf, input, 256+8*8);
        // buffer overfl0wwwwwwwwwww

        printf(“buf: %sn”, buf);
        fflush(stdout);

    #ifdef USE_CANARY
        if (canary != 0xdeadbeefc001d00d) {
            printf(“Buffer overflow detected! Aborting!n”);
            abort();
        }
    #endif
    }

    int main(int argc, char **argv)
    {
        
        char input[1024];
        int loop;

        // fill up input with ‘A’ x 256 (leaving 1024-256 bytes left)
        memset(input, ‘A’, 256);

        printf(“size of func2’s pointer (in bytes): %ldn”, sizeof(&func2));
        printf(“func2’s address: %lxn”, (unsigned long) func2);

        if (argc < 2) {
            loop = 2; // loop = 2 is the optimal solution for this case.
        }

        else {
            loop = atoi(argv[1]);
        }

        unsigned long gcc_canary = get_canary(); // get gcc canary secret value.

        // After the ‘AAAA’ put a gcc_canary for us. The space gcc will provide will be 16 bytes, so we just fill
        // it up with 2x canary secret values. (assuming loop = 2)

        for (int i = 0; i < loop; i++) {
            unsigned long *p = (unsigned long *) (input + 256 + i * sizeof(&func2));
            *p = (unsigned long) gcc_canary;
        }

        // Now put a pointer to func2(), at least twice (assuming loop = 2).

        for (int i = loop; i < loop * 2; i++) {
            unsigned long *p = (unsigned long *) (input + 256 + i * sizeof(&func2));
            *p = (unsigned long) func2;
        }

        printf(“input: %sn”, input);

        // verify the func2’s addresses are actually inside the input buffer.

        for (int i = 0; i < loop * 2; i++) {
            char *p = input + 256 + i * sizeof(&func2);
            unsigned long *q = (unsigned long *) p;
            printf(“address or canary: %lxn”, *q);
        }

        // call func with input buffer.

        func(input);
    }

    Output:


    gcc test.c
    $ ./a.out

    size of func2’s pointer (in bytes): 8
    func2’s address: 55ad7774c21d
    input: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    address or canary: ac9d07067ff30500
    address or canary: ac9d07067ff30500
    address or canary: 55ad7774c21d
    address or canary: 55ad7774c21d
    buf: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    I did it!
    Segmentation fault (core dumped)