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

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

tags: CTF PWN eductf

Version: Ubuntu 20.04

Original Code

  • fopen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include <fcntl.h>
    #include <stdio.h>
    
    int main()
    {
        FILE *fp;
        fp = fopen("./test", "r");
        fclose(fp);
    
        return 0;
    }
    
  • fread
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #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;
    }
    
  • fwrite
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #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;
    }
    

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
      ...
    
    • new_f
      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
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
        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
        1
        2
        3
        4
        5
          ...
          _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);
          ...
        
    • _IO_file_jumps
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
        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>
        }
      
    • parse mode in fileops.c - _IO_new_file_fopen()
  1. __GI__IO_file_fopen - iofopen.c
    1
    2
    3
    4
    5
    6
     ...
     <__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
    
  2. _IO_file_open - fileops.c
    1
    2
    3
    4
    5
     <__GI__IO_file_fopen+188>    call   _IO_file_open	<_IO_file_open>
         rdi: 0x5555555592a0 ◂— 0xfbad248c
         rsi: 0x555555556006 ◂— 0x747365742f2e /* './test' */
         rdx: 0x0
         rcx: 0x1b6
    
  3. sys_open - open64.c
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     <_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
    
  • Whole work flow
    • work flow
      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
        <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
      
      
      
    • *fp
      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
        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