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。
這就是我目前所認識的IO,IO涉及到很多攻擊手法,我應該會另寫一篇文章來進行記錄各種板子。
這篇文章中的圖片來源兩位師傅的部落格,但是我一下子找不到這兩位師傅的部落格地址了,故沒有在文章末尾新增參考文章,先冒昧的直接拿來了,望見諒。