Simple PWN 0x21(fopen, fread, fwrite, fclose)

Simple PWN 0x21(fopen, fread, fwrite, fclose)

tags: CTF PWN eductf

Version: Ubuntu 20.04

Original Code

:::spoiler fopen

#include <fcntl.h>
#include <stdio.h>

int main()
{
    FILE *fp;
    fp = fopen("./test", "r");
    fclose(fp);

    return 0;
}

:::

:::spoiler fread

#include <fcntl.h>
#include <stdio.h>

int main()
{
    FILE *fp;
    char buf[0x10];

    fp = fopen("./test", "r");
    fread(buf, 0x1, 0x10, fp);
    fclose(fp);

    return 0;
}

:::

:::spoiler fwrite

#include <fcntl.h>
#include <stdio.h>

int main()
{
    FILE *fp;
    char buf[0x10] = "TEST!!";

    fp = fopen("./test_write", "r");
    fread(buf, 0x1, 0x10, fp);
    fclose(fp);

    return 0;
}

:::

:::spoiler fclose


:::

Analyze

fopen

  • Flow chart
    1. fopen - main() ```baah! …

    <main+26> call fopen@plt fopen@plt pwndbg> si

    1
    2
    3
    4
    5
    6
    7
    8
    9
    2. `malloc` - `iofopen.c`
      ```bash!
      <__fopen_internal+26>    call   malloc@plt	<malloc@plt> # Size: 0x1d8
      pwndbg> heap
      ...
      Allocated chunk | PREV_INUSE
      Addr: 0x555555559290
      Size: 0x1e1
      ...
    

    :::spoiler new_f

      pwndbg> p *new_f
      $2 = {
        fp = {
          file = {
            _flags = 0,
            _IO_read_ptr = 0x0,
            _IO_read_end = 0x0,
            _IO_read_base = 0x0,
            _IO_write_base = 0x0,
            _IO_write_ptr = 0x0,
            _IO_write_end = 0x0,
            _IO_buf_base = 0x0,
            _IO_buf_end = 0x0,
            _IO_save_base = 0x0,
            _IO_backup_base = 0x0,
            _IO_save_end = 0x0,
            _markers = 0x0,
            _chain = 0x0,
            _fileno = 0,
            _flags2 = 0,
            _old_offset = 0,
            _cur_column = 0,
            _vtable_offset = 0 '\000',
            _shortbuf = "",
            _lock = 0x0,
            _offset = 0,
            _codecvt = 0x0,
            _wide_data = 0x0,
            _freeres_list = 0x0,
            _freeres_buf = 0x0,
            __pad5 = 0,
            _mode = 0,
            _unused2 = '\000' <repeats 19 times>
          },
          vtable = 0x0
        },
        lock = {
          lock = 0,
          cnt = 0,
          owner = 0x0
        },
        wd = {
          _IO_read_ptr = 0x0,
          _IO_read_end = 0x0,
          _IO_read_base = 0x0,
          _IO_write_base = 0x0,
          _IO_write_ptr = 0x0,
          _IO_write_end = 0x0,
          _IO_buf_base = 0x0,
          _IO_buf_end = 0x0,
          _IO_save_base = 0x0,
          _IO_backup_base = 0x0,
          _IO_save_end = 0x0,
          _IO_state = {
            __count = 0,
            __value = {
              __wch = 0,
              __wchb = "\000\000\000"
            }
          },
          _IO_last_state = {
            __count = 0,
            __value = {
              __wch = 0,
              __wchb = "\000\000\000"
            }
          },
          _codecvt = {
            __cd_in = {
              step = 0x0,
              step_data = {
                __outbuf = 0x0,
                __outbufend = 0x0,
                __flags = 0,
                __invocation_counter = 0,
                __internal_use = 0,
                __statep = 0x0,
                __state = {
                  __count = 0,
                  __value = {
                    __wch = 0,
                    __wchb = "\000\000\000"
                  }
                }
              }
            },
            __cd_out = {
              step = 0x0,
              step_data = {
                __outbuf = 0x0,
                __outbufend = 0x0,
                __flags = 0,
                __invocation_counter = 0,
                __internal_use = 0,
                __statep = 0x0,
                __state = {
                  __count = 0,
                  __value = {
                    __wch = 0,
                    __wchb = "\000\000\000"
                  }
                }
              }
            }
          },
          _shortbuf = L"",
          _wide_vtable = 0x0
        }
      }
    

    :::

    1. Initialize - iofopen.c
        ...
        _IO_no_init (&new_f->fp.file, 0, 0, &new_f->wd, &_IO_wfile_jumps);
        _IO_JUMPS (&new_f->fp) = &_IO_file_jumps;
        _IO_new_file_init_internal (&new_f->fp);
        ...
      

      :::spoiler _IO_file_jumps

        pwndbg> p _IO_file_jumps
        $3 = {
       __dummy = 0,
       __dummy2 = 0,
       __finish = 0x7ffff7e87ff0 <_IO_new_file_finish>,
       __overflow = 0x7ffff7e88a00 <_IO_new_file_overflow>,
       __underflow = 0x7ffff7e886b0 <_IO_new_file_underflow>,
       __uflow = 0x7ffff7e899c0 <__GI__IO_default_uflow>,
       __pbackfail = 0x7ffff7e8ad40 <__GI__IO_default_pbackfail>,
       __xsputn = 0x7ffff7e87be0 <_IO_new_file_xsputn>,
       __xsgetn = 0x7ffff7e877a0 <__GI__IO_file_xsgetn>,
       __seekoff = 0x7ffff7e87010 <_IO_new_file_seekoff>,
       __seekpos = 0x7ffff7e89d60 <_IO_default_seekpos>,
       __setbuf = 0x7ffff7e868f0 <_IO_new_file_setbuf>,
       __sync = 0x7ffff7e86780 <_IO_new_file_sync>,
       __doallocate = 0x7ffff7e7b3b0 <__GI__IO_file_doallocate>,
       __read = 0x7ffff7e87bb0 <__GI__IO_file_read>,
       __write = 0x7ffff7e875f0 <_IO_new_file_write>,
       __seek = 0x7ffff7e86d70 <__GI__IO_file_seek>,
       __close = 0x7ffff7e868e0 <__GI__IO_file_close>,
       __stat = 0x7ffff7e875d0 <__GI__IO_file_stat>,
       __showmanyc = 0x7ffff7e8aed0 <_IO_default_showmanyc>,
       __imbue = 0x7ffff7e8aee0 <_IO_default_imbue>
        }
      

      :::

    <__fopen_internal+120> call __GI__IO_file_fopen <__GI__IO_file_fopen> rdi: 0x5555555592a0 ◂— 0xfbad248c rsi: 0x555555556006 ◂— 0x747365742f2e /* './test' */ rdx: 0x555555556004 ◂— 0x747365742f2e0072 /* 'r' */ rcx: 0x1

    1
    2
    3
    4
    5
    6
    7
          5. `_IO_file_open` - `fileops.c`
      ```bash!
      <__GI__IO_file_fopen+188>    call   _IO_file_open	<_IO_file_open>
          rdi: 0x5555555592a0 ◂— 0xfbad248c
          rsi: 0x555555556006 ◂— 0x747365742f2e /* './test' */
          rdx: 0x0
          rcx: 0x1b6
    
    1
      6. `sys_open` - `open64.c`   ```bash!
    

    <_IO_file_open+33> call open64 # It'll return file number(fd) file: 0x555555556006 ◂— 0x747365742f2e /* './test' */ oflag: 0x0 # read only mode vararg: 0x1b6 ... <open64+73> syscall fd: 0xffffff9c file: 0x555555556006 ◂— 0x747365742f2e /* './test' */ oflag: 0x0 vararg: 0x0 ```

  • Whole work flow :::spoiler work flow
      <main+26>    call   fopen@plt	<fopen@plt>
          ...
          <__fopen_internal+26>    call   malloc@plt	<malloc@plt>
              size: 0x1d8
          ...
          <__fopen_internal+81>    call   _IO_no_init	<_IO_no_init>
          ...
          <__fopen_internal+103>    call   _IO_new_file_init_internal	<_IO_new_file_init_internal>
              rdi: 0x5555555592a0 ◂— 0xfbad0000
              ...
              <_IO_new_file_init_internal+25>    call   _IO_link_in	<_IO_link_in>
                  rdi: 0x5555555592a0 ◂— 0xfbad240c
                  rsi: 0xfbad0000
                  rdx: 0x0
                  rcx: 0x555555559390 ◂— 0x0
              ...
          <__fopen_internal+120>             call   __GI__IO_file_fopen	<__GI__IO_file_fopen>
              rdi: 0x5555555592a0 ◂— 0xfbad248c
              rsi: 0x555555556006 ◂— 0x747365742f2e /* './test' */
              rdx: 0x555555556004 ◂— 0x747365742f2e0072 /* 'r' */
              rcx: 0x1
              ...
          <__GI__IO_file_fopen+188>    call   _IO_file_open	<_IO_file_open>
              rdi: 0x5555555592a0 ◂— 0xfbad248c
              rsi: 0x555555556006 ◂— 0x747365742f2e /* './test' */
              rdx: 0x0
              rcx: 0x1b6
                  ...
                  <_IO_file_open+33>    call   open64	<open64>	# It'll return file number(fd)
                      file: 0x555555556006 ◂— 0x747365742f2e /* './test' */
                      oflag: 0x0 	# read only mode
                      vararg: 0x1b6
                      ...
                      <open64+73>    syscall  <SYS_openat>
                          fd: 0xffffff9c
                          file: 0x555555556006 ◂— 0x747365742f2e /* './test' */
                          oflag: 0x0
                          vararg: 0x0
    
    
    

    ::: :::spoiler *fp

      pwndbg> p *fp
      $4 = {
        _flags = -72539000,
        _IO_read_ptr = 0x0,
        _IO_read_end = 0x0,
        _IO_read_base = 0x0,
        _IO_write_base = 0x0,
        _IO_write_ptr = 0x0,
        _IO_write_end = 0x0,
        _IO_buf_base = 0x0,
        _IO_buf_end = 0x0,
        _IO_save_base = 0x0,
        _IO_backup_base = 0x0,
        _IO_save_end = 0x0,
        _markers = 0x0,
        _chain = 0x7ffff7fc45c0 <_IO_2_1_stderr_>,
        _fileno = 3,
        _flags2 = 0,
        _old_offset = 0,
        _cur_column = 0,
        _vtable_offset = 0 '\000',
        _shortbuf = "",
        _lock = 0x555555559380,
        _offset = -1,
        _codecvt = 0x0,
        _wide_data = 0x555555559390,
        _freeres_list = 0x0,
        _freeres_buf = 0x0,
        __pad5 = 0,
        _mode = 0,
        _unused2 = '\000' <repeats 19 times>
      }
    

    :::

fread

  • Flow chart

fwrite

  • Flow chart

fclose

  • Flow chart