PWN系列-初探IO

山西小嫦娥發表於2024-05-23

PWN系列-初探IO

記錄一下自己理解的IO,文章的程式碼均是glibc-2.23版本下的程式碼。

由於筆者才疏學淺,學識有限,文章中難免會有疏漏和錯誤之處,懇請各位師傅批評指正,多多包涵。

什麼是IO

IO中的I其實就是in,O其實就是out,一個輸入,一個輸出。

IO長什麼樣子

_IO_FILE_plus

首先先來認識一下_IO_FILE_plus結構體

struct _IO_FILE_plus
{
  _IO_FILE file;  /* 基礎的檔案結構體 */
  const struct _IO_jump_t *vtable;  /* 虛表指標 */
};

總結起來,_IO_FILE_plus 結構體透過包含 _IO_FILE 結構體和一個虛表指標。

_IO_FILE

_IO_FILE結構體定義:

struct _IO_FILE {
  int _flags;           /* 檔案狀態標誌 */
  char* _IO_read_ptr;   /* 讀取緩衝區的當前位置 */
  char* _IO_read_end;   /* 讀取緩衝區的結束位置 */
  char* _IO_read_base;  /* 讀取緩衝區的起始位置 */
  char* _IO_write_base; /* 寫入緩衝區的起始位置 */
  char* _IO_write_ptr;  /* 寫入緩衝區的當前位置 */
  char* _IO_write_end;  /* 寫入緩衝區的結束位置 */
  char* _IO_buf_base;   /* 緩衝區的起始位置 */
  char* _IO_buf_end;    /* 緩衝區的結束位置 */
  char *_IO_save_base;  /* 儲存位置指標 */
  char *_IO_backup_base;/* 備份緩衝區指標 */
  char *_IO_save_end;   /* 儲存結束指標 */
  struct _IO_marker *_markers; /* 標記 */
  struct _IO_FILE *_chain;     /* 檔案連結串列 */
  int _fileno;                 /* 檔案描述符 */
#if 0
  int _blksize;                /* 塊大小 */
#else
  int _flags2;                 /* 額外標誌 */
#endif
  _IO_off_t _old_offset;       /* 舊的偏移量 */
#if defined _G_IO_IO_FILE_VERSION && _G_IO_IO_FILE_VERSION == 0x20001
  unsigned short _cur_column;  /* 當前列號 */
  signed char _vtable_offset;  /* 虛表偏移量 */
  char _shortbuf[1];           /* 短緩衝區 */
#endif
  _IO_lock_t *_lock;           /* 鎖 */
#if defined _LIBC_REENTRANT
  _IO_lock_t *_lock_owner;     /* 鎖的擁有者 */
  unsigned int _lock_count;    /* 鎖計數 */
#endif
  _IO_off64_t _offset;         /* 偏移量 */
  void *__pad1;                /* 填充1 */
  void *__pad2;                /* 填充2 */
  void *__pad3;                /* 填充3 */
  void *__pad4;                /* 填充4 */
  size_t __pad5;               /* 填充5 */
  int _mode;                   /* 模式 */
  char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];
                               /* 未使用的填充空間 */
};

此結構體定義了標準C庫中用於檔案操作的內部資料結構。以下是每個成員變數的簡要說明:

  • _flags: 檔案狀態標誌,表示檔案的各種狀態和屬性。
  • _IO_read_ptr, _IO_read_end, _IO_read_base: 分別指向讀取緩衝區的當前位置、結束位置和起始位置。
  • _IO_write_base, _IO_write_ptr, _IO_write_end: 分別指向寫入緩衝區的起始位置、當前位置和結束位置。
  • _IO_buf_base, _IO_buf_end: 分別指向緩衝區的起始位置和結束位置。
  • _IO_save_base, _IO_backup_base, _IO_save_end: 分別用於儲存和備份緩衝區的位置指標。
  • _markers: 指向檔案流標記的指標。
  • _chain: 指向連結串列中下一個檔案流的指標。
  • _fileno: 檔案描述符。
  • _flags2: 額外的檔案狀態標誌。
  • _old_offset: 舊的偏移量。
  • _cur_column, _vtable_offset, _shortbuf: 用於輸入輸出流的輔助變數。
  • _lock: 指向檔案流鎖的指標,用於執行緒安全。
  • _offset: 當前的檔案偏移量。
  • __pad1, __pad2, __pad3, __pad4: 用於填充的指標,確保結構體對齊。
  • __pad5: 用於填充的大小。
  • _mode: 檔案模式。
  • _unused2: 未使用的填充空間,用於確保結構體的大小和對齊。

_IO_jump_t

struct _IO_jump_t 定義如下:

struct _IO_jump_t
{
  size_t __dummy; 
  size_t __dummy2;
  _IO_finish_t __finish;
  _IO_overflow_t __overflow;
  _IO_underflow_t __underflow;
  _IO_underflow_t __uflow;
  _IO_pbackfail_t __pbackfail;
  _IO_xsputn_t __xsputn;
  _IO_xsgetn_t __xsgetn;
  _IO_seekoff_t __seekoff;
  _IO_seekpos_t __seekpos;
  _IO_setbuf_t __setbuf;
  _IO_sync_t __sync;
  _IO_doallocate_t __doallocate;
  _IO_read_t __read;
  _IO_write_t __write;
  _IO_seek_t __seek;
  _IO_close_t __close;
  _IO_stat_t __stat;
  _IO_showmanyc_t __showmanyc;
  _IO_imbue_t __imbue;
};

這些欄位是指向不同函式型別的指標,用於實現多型性和靈活的檔案操作。以下是這些函式指標的大致功能說明:

  • __finish: 完成流的操作。
  • __overflow: 處理輸出緩衝區溢位的操作。
  • __underflow: 處理輸入緩衝區空的操作。
  • __uflow: 處理輸入緩衝區下溢的操作。
  • __pbackfail: 處理向輸入緩衝區放回字元失敗的操作。
  • __xsputn: 寫入多個字元的操作。
  • __xsgetn: 讀取多個字元的操作。
  • __seekoff: 相對偏移位置的檔案定位操作。
  • __seekpos: 絕對位置的檔案定位操作。
  • __setbuf: 設定緩衝區的操作。
  • __sync: 同步檔案緩衝區的操作。
  • __doallocate: 分配緩衝區的操作。
  • __read: 讀取資料的操作。
  • __write: 寫入資料的操作。
  • __seek: 檔案定位的操作。
  • __close: 關閉檔案的操作。
  • __stat: 獲取檔案狀態的操作。
  • __showmanyc: 顯示字元數的操作。
  • __imbue: 設定區域設定資訊的操作。

_IO_list_all

_IO_list_all 是一個全域性變數,在 GNU C 庫(glibc)中用於管理所有開啟的檔案流。它是一個指向 _IO_FILE 結構體連結串列的指標。透過這個連結串列,glibc 可以跟蹤和操作所有當前開啟的檔案流。

連結串列結構

_IO_list_all 是一個指向 _IO_FILE 結構體的指標,而 _IO_FILE 結構體本身包含一個 _chain 指標,指向下一個檔案流。因此,所有開啟的檔案流形成了一個連結串列。這個連結串列的頭部是 _IO_list_all

作用

  • 管理檔案流: 透過維護這個連結串列,glibc 能夠方便地管理所有開啟的檔案流。每當有新的檔案流建立時,會將其新增到連結串列中;當檔案流關閉時,會將其從連結串列中移除。
  • 檔案操作: 許多內部檔案操作函式,例如重新整理所有檔案流、關閉所有檔案流等,都需要遍歷這個連結串列,以對每個檔案流執行相應的操作。

IO的利用思路

IO利用的大致思路都是構造fake_io結構體,佈置一些資料和函式,透過程式正常的執行流程走到IO操作來劫持程式流來getshell。

image-20240523122431321

這就是我目前所認識的IO,IO涉及到很多攻擊手法,我應該會另寫一篇文章來進行記錄各種板子。

這篇文章中的圖片來源兩位師傅的部落格,但是我一下子找不到這兩位師傅的部落格地址了,故沒有在文章末尾新增參考文章,先冒昧的直接拿來了,望見諒。

相關文章