---
# System prepended metadata

title: 'Simple PWN 0x21(fopen, fread, fwrite, fclose)'
tags: [eductf, PWN, CTF]

---

# Simple PWN 0x21(fopen, fread, fwrite, fclose)
###### tags: `CTF` `PWN` `eductf`

Version: Ubuntu 20.04

## Original Code
:::spoiler fopen
```cpp=
#include <fcntl.h>
#include <stdio.h>

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

    return 0;
}
```
:::

:::spoiler fread
```cpp=
#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
```cpp=
#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
```cpp=

```
:::

## Analyze
### fopen
* Flow chart
    ![](https://i.imgur.com/CZgCWFL.png)
1. `fopen` - main()
    ```baah!
    ...
    <main+26>    call   fopen@plt    <fopen@plt>
    pwndbg> si
    ```
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`
    ```bash!
    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
      }
    }
    ```
    :::
3. Initialize - `iofopen.c`
    ```cpp!
    ...
    _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`
    ```bash!
    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()`](https://elixir.bootlin.com/glibc/glibc-2.31/source/libio/fileops.c)
4. `__GI__IO_file_fopen` - `iofopen.c`
    ```bash!
    ...
    <__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
    ```
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
    ```
6. `sys_open` - `open64.c`
    ```bash!
    <_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
    :::spoiler work flow
    ```bash!
    <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`
    ```bash!
    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
    ![](https://i.imgur.com/gESVUEE.png)

### fwrite
* Flow chart
    ![](https://i.imgur.com/IF94XNU.png)

### fclose
* Flow chart
    ![](https://i.imgur.com/nOpUw3e.png)
