# 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

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

### fwrite
* Flow chart

### fclose
* Flow chart
