버퍼 오버플로

위키百科, 우리 모두의 百科事典.

버퍼 오버플로 ( 英語 : buffer overflow ) 또는 버퍼 오버런 ( buffer overrun )은 메모리를 다루는 데에 誤謬가 發生하여 잘못된 動作을 하는 프로그램 脆弱點이다. 컴퓨터 保安 프로그래밍 에서는 프로세스 데이터 버퍼 에 貯藏할 때 프로그래머가 指定한 곳 바깥에 貯藏하는 것을 意味한다. 벗어난 데이터는 隣接 메모리를 덮어 쓰게 되며 이때 다른 데이터가 包含되어 있을 수도 있는데, 損傷을 받을 수 있는 데이터는 프로그램 變數와 프로그램 흐름 制御 데이터도 包含된다. 이로 인해 잘못된 프로그램 擧動이 나타날 수 있으며, 메모리 接近 誤謬, 잘못된 結果, 프로그램 終了, 또는 시스템 保安 漏泄이 發生할 수 있다.

버퍼 오버플로가 코드를 實行시키도록 設計되거나 프로그램 作動을 變更시키도록 設計된 入力에 依해 觸發될 수 있다. 따라서 이는 많은 소프트웨어 脆弱點 의 根幹이 되며 惡意的으로 利用 될 수 있다. 警戒 檢査 로 버퍼 오버플로를 防止할 수 있다.

버퍼 오버플로는 普通 데이터를 貯藏하는 過程에서 그 데이터를 貯藏할 메모리 位置가 有效한지를 檢査하지 않아 發生한다. 이러한 境遇 데이터가 담긴 位置 近處에 있는 값이 損傷되고 그 損傷이 프로그램 實行에 影響을 미칠 수도 있다. 特히, 惡意的인 攻擊으로 인해 프로그램에 脆弱點이 發生할 수도 있다.

흔히 버퍼 오버플로와 關聯되는 프로그래밍 言語는 C와 C++로, 어떤 領域의 메모리에서도 內藏된 데이터 接近 또는 덮어쓰기 保護 機能을 提供하지 않으며 어떤 配列에 記錄되는 데이터가 그 配列의 範圍 안에 包含되는지 自動으로 檢査하지 않는다.

技術的인 說明 [ 編輯 ]

버퍼 오버플로는 不充分한 警戒 檢査 에 依해 버퍼에 쓰인 데이터 가 버퍼에 이미 割當된 近接한 메모리 住所 에 있는 데이터 값을 오염시킬 때 發生한다. 大部分 이는 文字列 을 하나의 버퍼에서 다른 버퍼로 複寫할 때 發生한다.

基本 예제 [ 編輯 ]

아래의 예제에서, 프로그램은 메모리에서 隣接해 있는 두 아이템을 定義하였다: 8 바이트 길이 스트링 버퍼, A. 그리고 2 바이트 정수형, B. 于先, A는 8바이트 모두 數字 0값만 包含하고 B는 數字 3을 包含한다. 文字들은 1바이트 크기이다.

A B
0 0 0 0 0 0 0 0 0 3

이제, 프로그램은 文字列 "excessive"를 A 버퍼에 貯藏한다. 한 바이트짜리 0값이 스트링의 끝임을 알리기 위해 따라온다. 스트링의 길이를 確認하지 않음으로 B의 값을 덮어쓴다.

A B
'e' 'x' 'c' 'e' 's' 's' 'i' 'v' 'e' 0

비록 프로그래머가 B가 바뀌는 것을 全혀 意圖하지 않았다 하더라도, B의 값은 文字列의 한 部分을 構成하는 數字로 바뀌었다. 이 예제에서 ASCII 를 使用하는 빅 엔디言 시스템에서 "e" "0"는 數字 25856街 될 수 있다. B가 프로그램이 定義한 唯一한 다른 變數였다면, B의 끝을 지나가는 긴 스트링을 쓰는 것은 세그멘테이션 誤謬 , 프로세스 終了와 같은 誤謬를 發生시켰을 것이다.

利用 [ 編輯 ]

버퍼 오버플로 脆弱點을 利用하는 技術은 救助 , 運營 體制 , 메모리 領域에 따라 다르다. 例를 들어 (heap, 動的 메모리 割當에 使用됨) 을 利用하는 方法은 函數 呼出 스택 을 利用하는 方法과 매우 다르다.

스택 基盤 利用 [ 編輯 ]

技術的 性向을 가진 惡意的 使用者가 스택 基盤 버퍼 오버플로를 利用하여 프로그램을 아래와 같이 操作할 수 있다:

  • 스택에 가까운 地域 變數를 덮어씀으로써 프로그램의 擧動을 攻擊者에게 惠澤을 주는 方向으로 바꾼다.
  • 스택 프레임 안의 歸還 住所를 덮어쓴다. 函數가 歸還하면 實行이 攻擊者가 指定한 歸還 住所로부터 再開되는데 普通 使用者 入力으로 채워진 버퍼이다.
  • 函數 포인터 또는 例外 핸들러를 덮어씀으로써 以後에 實行되는 部分을 가로챈다.

트램폴라이닝(trampolining)이라 불리는 方法을 使用하면, 使用者가 指定한 데이터의 住所를 모르더라도, 레지스터에 그 住所가 貯藏되어 있다면, 實行 흐름을 使用者 提供 데이터로 跳躍하도록하는 어떤 實行코드의 住所로 歸還 住所를 덮어쓸 수 있다. 位置가 레지스터 R에 貯藏되어 있다면 jump R이나 call R과 같이 R에 貯藏되어 있는 住所로 건너뛰는 作動코드 opcode 로 使用者 提供 데이터가 實行되도록 할 수 있다. 適當한 作動코드 또는 바이트의 位置는 DLL 이나 實行 파일 自體 안에서 찾을 수 있다. 그러나 作動 코드의 住所는 典型的으로는 어떠한 無效 文字 도 包含할 수 없고, 이러한 作動 코드의 位置는 應用 프로그램마다, 運營 體制 버전에 따라 달라질 수 있다. 메타스플로잇 프로젝트 는 그러한 適當한 作動코드의 데이터베이스로 윈도우 運營 體制에 關한 것이 羅列되어 있다.

스택 基盤 利用 예 [ 編輯 ]

아래의 例에서 "X"는 프로그램이 實行될 때 스택 에 있게 되는 데이터이다. 프로그램은 그 다음 작은 量의 貯藏空間만 必要한 函數 "Y"를 呼出한다. 그리고 "Y"는 그 다음 많은 버퍼를 必要로 하는 "Z"를 呼出한다.

Z Y X
            : / / /

萬若 函數 Z가 오버플로를 發生시키면, 그것은 函數 Y나 週 프로그램에 包含된 데이터를 덮어 쓸 수도 있다:

Z Y X
. . . . . . . . / /

이것은 大部分의 시스템에서 現在의 프로세스가 呼出되기 前 實行되고 있던 프로그램 部分의 位置인 返還값을 스택이 갖고 있기 때문에 特히나 深刻하다. 函數가 끝날 때 臨時 貯藏所는 스택에서 除去되고 實行은 返還 住所로 되돌아간다. 그런데 返還 住所를 버퍼 오버플로가 덮어쓰면 어떤 다른 位置를 가리킬 것이다. 처음 예제에서와 같은 버퍼 오퍼플로가 偶然히 發生하는 境遇 거의 틀림없이 쓸모없는 位置일 것이다. 어떠한 프로그램 命令語 位置가 아닌 以上, 프로세스는 망가질 것이다. 그리고 惡意的인 攻擊者가 시스템 保安課 衝突할 수 있는 任意 位置로 返還 住所를 바꿀 수 있다.

힙 基盤 利用 [ 編輯 ]

힙 데이터 領域에서 일어나는 버퍼 오버플로를 힙 오버플로라 부르며 스택 基盤 오버플로와는 다른 方法으로 利用할 수 있다. 힙 上의 메모리는 動的으로 應用 프로그램에 依해 實行時間 中에 割當되고 普通 프로그램 데이터를 保管하고 있다. 利用하는 方法은 이 데이터를 특정한 方法으로 汚染시켜 應用 프로그램이 連結 리스트 포인터(linked list pointer)等과 같은 內部 資料 構造를 덮어쓰게 한다. 基本的인 힙 오버플로 技術은 動的 메모리 割當 連結( malloc 上位 水準 데이터)을 덮어씀으로써 프로그램 函數 포인터를 造作한다. 마이크로소프트 JPEG GDI+ 脆弱點은 힙 오버플로度 컴퓨터 使用者에 危險이 될 수 있다는 例이다.

이용당하는 것을 막는 障壁 [ 編輯 ]

읽히거나 實行되기 前에 버퍼를 操作하면 利用하려는 試圖를 막을 수도 있다. 이러한 造作은 이용당할 威脅을 緩和시켜줄 수는 있지만 不可能하게 만들지는 못한다. 造作에는 大文字로 또는 小文字로 變換, 制御 富豪 除去, 數字 英文字 除去 等이 包含된다. 이러한 防止 手段을 回避하는 技術도 存在한다: 數字 英文字 코드 , 多形性 코드 , 自體 修正 코드 , libc 歸還 攻擊 等. 같은 方法을 侵入 感知 시스템 에 依한 피探知를 回避하는 데도 使用할 수 있다. 어떤 境遇에는, 유니코드 變換의 境遇도 包含되지만, 서비스 拒否만 可能한 것으로 脆弱點의 威脅이 잘못 表現되었지만 事實은 任意 코드의 遠隔 實行이 可能할 수도 있다.

이용의 實際 [ 編輯 ]

實世界 利用에서는 다양한 이슈를 克服해야 攻擊을 信賴性 있게 遂行할 수 있다. 이러한 要素에는 住所에서의 無效값 바이트, 셸 코드 位置 可變性, 環境間 相異性, 그리고 다양한 對應手段이다.

NOP 슬라이드 技法 [ 編輯 ]

NOP 슬라이드 技法은 가장 오래되고 가장 널리 알려진 스택 버퍼 오버플로 攻擊 技法이다. 버퍼의 正確한 住所를 찾는 問題를 解決하는 것으로, 標的 領域의 크기를 效果的으로 增大시킨다. 이를 위하여 훨씬 큰 領域의 스택을 NOP 機械語 코드 (컴퓨터가 이 命令을 읽으면 그 클럭 싸이클에는 아무 일도 하지 않는다)로 오염시킨다. 攻擊者 提供 데이터 끝, 卽 NOP 命令語 以後에 버퍼의 最上位 位置, 셸 코드가 있는 곳으로 相對的 jump 命令語를 둔다. NOP 命令語의 母音이 "NOP 슬라이드"라고 불린다. 왜냐하면 歸還 住所를 덮어 쓸 때 NOP 領域 內의 住所값 어디를 써도 結局 NOP 命令語들을 따라 "미끄러져" 最後의 相對 jump로 實際 惡性 코드에 到達하기 때문이다. 이 技法은 攻擊者가 相對的으로 작은 크기의 셸 코드의 位置 代身 스택에서 NOP 슬라이드의 位置를 推定하면 된다.

이 技法이 人氣 있기 때문에 많은 侵入 防止 시스템 業體에서 이러한 NOP 機械語 命令語 패턴을 探索하여 使用中인 셸 코드를 檢出할 것이다. 重要한 것은 NOP 슬라이드는 반드시 傳統的인 NOP 機械語 코드만 담는 것은 아니며 어떤 命令이라도 셸 코드가 實行될 수 없을 만큼 機械 狀態를 해치지 않으면 하드웨어로 支援되는 NOP자리에 使用할 수 있다. 結果的으로, 攻擊者가 NOP 슬라이드를 셸코드 實行에 事實上 支障이 없는 任意로 選擇한 命令語로 채우는 慣行이 널리 퍼지게 되었다.

한便, 이 方法이 어떤 攻擊이 成功的일 確率을 크게 높이는 反面, 問題가 없는 것은 아니다.

  • 이 技法을 利用한 攻擊이라도 如前히 어느 程度 運에 依存, 스택 上의 거리 오프셋(offset)을 推定하여 NOP-슬라이드 領域에 들어가게 해야 한다. 不正確하게 推定하면 普通 標的 프로그램이 깨지고 시스템 管理者에게 攻擊者의 活動을 警報하게 된다.
  • 또 한가지 問題가 될 수 있는 境遇는 效果的인 NOP-슬라이드가 割當받을 수 있는 메모리에 비해 너무 큰 境遇이다. 이것이 問題가 될 수 있는 境遇는 割當된 버퍼 크기가 너무 작고 現在 스택의 깊이가 너무 얕을 때(卽, 現在 스택 프레임의 끝으로부터 始作點까지의 空間이 얼마 되지 않았을 때)이다. 그 問題點에도 不拘하고 NOP-슬라이드는 주어진 플랫폼, 環境, 狀況에 따라 唯一하게 作動하는 方法으로 아직도 重要한 技法이다.

레지스터에 貯藏된 住所로 건너뛰기 [ 編輯 ]

레지스터로 건너뛰기 jump to register 技法은 NOP-슬라이드와 같은 追加 空間이나 스택 位置 오프셋을 推定하지 않아도 잘 作動한다. 戰略은 復歸 포인터를 덮어써서 統制된 버퍼, 卽 셸코드를 담고 있는 레지스터의 位置로 프로그램이 건너뛰게 만드는 것이다. 例를 들어 레지스터 A가 어떤 버퍼의 始作點을 담고 있다면, 이 레지스터를 오퍼랜드(operand)로 삼은 어떠한 건너뛰기 또는 呼出로 實行 흐름의 制御權을 얻을 수 있다. 實戰에서는 어떤 프로그램이 意圖的으로는 어떤 特定 레지스터에 貯藏된 住所로 건너뛰는 命令을 包含하지 않을 수도 있다. 傳統的인 解法은 어떤 意圖되지 않은 適當한 作動코드 opcode 事例를 프로그램 메모리 어딘가 固定된 位置에서 찾는 것이다. 例를 들면, 뜻하지 않게 i386 JMP esp 命令이 包含된 境遇가 ntdll.dll 안의 DbgPrint()函數에 있었다. 이 命令의 作動 코드는 FF E4이다. 이 連續 두 바이트 패턴이 call DbgPrint 命令에서 1Byte 떨어진 곳 住所 0x7C941EED에 나타났다. 攻擊者가 프로그램의 歸還 住所를 이 住所로 덮어 쓰면, 프로그램이 처음에는 0x7C941EED로 건너뛰어 實行 코드 FF E4를 JMP esp 命令으로 認識하여 스택의 正常 位置로 jump, 攻擊者의 코드를 實行할 것이다. 이 技法이 可能하다면 脆弱性의 深刻性이 相當히 增加한다. 이는 왜냐하면 利用이 充分히 信賴性 있게 作動하여 攻擊을 自動化, 實行하면 假想敵으로 成功을 保證할 수 있게 되기 때문이다. 이러한 理由로, 이 技法이 인터넷 웜 에서 가장 흔히 버퍼 오버플로 脆弱點을 利用하기 위해 使用된다. 이 方法은 또한 셸코드의 位置를 윈도 플랫폼 床에서 덮어씌어진 歸還 住所 뒤에 位置하더라고 可能하다. 實行 코드는 住所 0x00400000에 基盤하고, x86은 리틀 엔디안 構造이므로 歸還 住所의 最後 바이트는 반드시 無效값이 되고, 이것이 버퍼 複寫를 마감하며 그 以後에는 아무것도 씌지 않는다. 이로 하여 셸코드의 크기는 버퍼의 크기로 制限되며, 지나친 規制가 될 수 있다. 動的 連結 라이브러리 DLL은 高位 메모리 (0x01000000 以上)에 貯藏되며 따라서 無效 바이트가 없는 住所를 가지므로, 이 方法은 無效 바이트 (또는 다른 許容 안되는 文字)를 덮어씌어진 復歸 住所에서 除去할 수 있다. 이런 式으로 使用되면, 이 方法은 때때로 DLL 프램폴라이닝이라고 불린다.

保護 對應 手段 [ 編輯 ]

다양한 技法이 버퍼 오버플로를 감지 또는 防止하기 위하여, 다양한 代價를 支拂하며 使用되어 왔다. 가장 信賴性 있는 버퍼 오버플로를 回避 또는 防止하기 위한 方法은 言語 水準에서 自動 保護를 使用하는 것이다. 그러나 이러한 種類의 保護는 旣存 코드 에 適用할 수 없고, 때때로 技術的, 商業的, 또는 文化的 制限으로 脆弱한 言語를 要求한다.

프로그래밍 言語 選擇 [ 編輯 ]

프로그래밍 言語 選擇은 버퍼 오버플로 發生에 깊이 있는 影響을 미칠 수 있다. 2008年 基準으로, C와 그로부터 發展된 C++는 가장 人氣 있는 言語들에 包含되며, 巨大한 量의 소프트웨어가 이러한 言語로 作成되었다. C와 C++는 메모리上 어떤 部分에서도 데이터 接近과 덮어쓰기에 對한 內臟 保護 機能이 없다. 더 具體的으로, 데이터가 어떤 配列 (버퍼의 具現)에 씌어지는 데이터가 그 配列의 範圍 안에 씌어지는지 檢査하지 않는다. 그러나 標準 C++ 라이브러리는 데이터를 안전히 貯藏하는 많은 方法을 提供하고, C言語에서 버퍼 오버플로를 回避하기 위한 技術도 存在한다. 長期間 作動시키며 安定性을 維持해야 하는 프로그램을 作成해야 한다면 보다 데이터 타입과 오버플로 檢事가 嚴格한 C#과 자바를 使用할 수 있다.

많은 다른 프로그래밍 言語는 實行時間 檢査를 提供하고, 어떤 境遇에는 甚至於 컴파일 詩 檢査하여 C 또는 C++가 데이터를 덮어쓰고 繼續하여 더 많은 命令을 實行하여 잘못된 結果가 프로그램을 깨뜨릴 수도 있는 境遇 警告 또는 例外 를 提起할 수도 있다. 그러한 言語의 例는 에이다 , 리스프 , 모듈라-2 , 스몰토크 , OCaml 그리고 C에서 發展된 사이클론 D 이다. 자바 닷넷 바이트코드 環境도 警戒 檢査를 모든 配列에 對하여 要求한다. 거의 모든 인터프리터 言語 는 잘 定義된 에러 條件에 信號를 보냄으로써 버퍼 오버플로에 對抗 保護할 것이다. 어떤 言語가 充分한 兄 情報(type information)를 提供하면 때때로 可能케 할것인지 不可能하게 할 것인지 定할 수 있게 해 준다. 政敵 코드 分析 은 多數의 動的 警戒 檢査를 除去할 수 있지만, 잘못 具現되거나 不適切한 케이스(case)는 深刻하게 性能을 저하시킬 수 있다. 소프트웨어 工學者는 반드시 操心스럽게 安全性과 性能 費用 사이의 調律을 考慮하여 言語와 컴파일러 設定을 決定하여야 한다.

安全한 라이브러리 使用 [ 編輯 ]

버퍼 오버플로의 問題는 C와 C++言語에서는 一般的이다. 왜냐하면 이들 言語가 데이터 兄을 保管 場所로서 버퍼의 低水準 表現上 詳細를 露出시키기 때문이다. 버퍼 오버플로는 반드시 따라서 버퍼 管理 코드안에서의 높은 水準의 正確性을 維持함으로써 回避되어야 한다. 오래前부터 標準 라이브러리 函數 中 境界를 檢査하지 않는 函數의 使用을 避할 것이 勸告되어 왔다: gets , scanf , strcpy 等. 모리스 웜 핑거 데몬 안에서 呼出되는 gets 函數를 利用하였다.

잘 씌어지고 檢査된 抽象 데이터型 라이브러리는 警戒 檢査를 包含한 버퍼 官吏를 中央集中化하고 自動的으로 實施하여 버퍼 오버플로 發生과 衝擊을 줄일 수 있다. 버퍼 오버플로가 日常的으로 일어나는 言語의 두가지 主要한 基本 데이터 兄은 文字列과 配列이다; 따라서 버퍼 오버플로를 이러한 데이터 刑에서 防止하는 라이브러리는 必要 領域 가운데 厖大한 大多數를 擔當해 줄 수 있다. 如前히 이러한 安全한 라이브러리를 使用하지 못한다면 버퍼 오버플로와 다른 脆弱點을 낳을 것이다; 自然스럽게 라이브러러 自體의 어떤 버그도 潛在的인 脆弱點이 된다. "安全한" 라이브러리 具現은 "改善된 文字列 라이브러리", Vstr, 語源을 包含한다. 오픈 BSD 運營體制 C 라이브러리 는 strlcpy와 strlcat 函數를 提供하지만 이들은 前 安全 라이브러리 具現보다 더 制限되어 있다.

2006年 9月 C 言語 標準 委員會 技術 報告書 24731이 公開되었다; 이는 標準 C 라이브러리의 文字列과 入出力 函數들에 基盤하였으나 버퍼 크기 媒介 變數를 追加로 가진 函數들을 明細하였다. 그러나 이런 函數들의 버퍼 오버플로 防止 效力은 論難의 餘地가 있다. 프로그래머가 일부러 函數 呼出 마다 介入하여야 하는데 이는 더 오래된 標準 라이브러리 函數의 버퍼 오버플로를 防止하게 만드는 것과 等價의 일이다.

可能한 더 安全한 機能을 提供하는 函數를 使用하는 것도 方法이다. 例를 들어 文字列의 길이를 求하는 C 函數 strlen , wcslen 函數는 NULL 文字를 만날 때까지 繼續 다음 메모리를 參照해 나가는 메커니즘으로 되어 있어서 元來의 文字列 끝에 NULL이 없으면 最惡의 境遇 메모리 領域 끝을 넘어서까지 메모리를 參照하려 試圖할 것이다. 이 때에는 좀 더 改善된 函數 strlen s wcslen s 를 使用하여 參照할 最大 메모리를 制限할 수 있다. 이 外에 旣存의 文字列 函數 뒤에 _s가 붙은 이름의 函數를 使用하면 버퍼 오버플로 問題를 改善할 수 있다. [1]

버퍼 오버플로 保護 [ 編輯 ]

버퍼 오버플로 保護는 가장 一般的인 버퍼 오버플로를 檢出하기 위해 使用되며 函數가 歸還할 때 스택이 變更되었는지 檢査한다. 變更되었다면 프로그램이 세그멘테이션 誤謬 를 發生 시키며 中斷된다. 그러한 시스템의 세가지 例가 gcc 패치人 립세이프 LibSafe, 스택 가드 , 프로폴리스 이다. 마이크로소프트의 데이터 實行 防止 모드는 明白히 SEH 例外 處理機를 가리키는 포인터를 덮어쓰기로부터 保護한다. 더 强力한 스택 保護는 스택을 두가지로 나눔으로써 可能하다: 하나는 데이터用이고 다른 하나를 函數 歸還에 使用하는 것이다. 이러한 區分은 포스 프로그래밍 言語 에 비록 安全을 위한 機能은 아니지만 採擇되어 있다. 어쨌든, 이는 버퍼 오버플로에 關한 完璧한 解決策은 아닌 것이, 歸還 住所가 아닌 敏感한 데이터는 如前히 덮어씌어질 可能性이 있다.

포인터 保護 [ 編輯 ]

버퍼 오버플로는 포인터를 造作함으로써 (貯藏되어 있는 住所를 包含하여) 作動한다. 포인트 가드는 컴파일러 擴張으로 提案되었는데, 攻擊者가 信賴性 있게 포인터와 住所를 造作하는 것을 防止한다. 接近 方法은 컴파일러가 追加 코드를 揷入하여 自動的으로 포인터를 使用 前後에 XOR-인코딩하도록 하는 것이다. 攻擊者가 (理論的으로는) 어떤 값이 포인터를 인코드/디코드할 때 使用할지 알지 못하기 때문에 어떤 값으로 덮어 써야 願하는 效果를 거둘 수 있을지 알기 힘들게 된다. 포인트가드가 配布된 적은 없지만 마이크로소프트에서 비슷한 接近 方法을 具現하여 윈도 XP SP2와 윈도 서버 2003 SP1 以後에 適用하였다. 포인터 保護를 自動 機能으로 具現하지는 않았고, API를 追加하여 프로그래머의 裁量에 따라 呼出하여 使用하도록 하였다. XOR이 線形이므로, 攻擊者가 暗號化된 포인터를 造作하여 어떤 住所의 下位 바이트만 덮어쓸 수 있다. 이렇게 하면 攻擊者가 여러番 試圖하거나 複數의 位置 (例를 들어 NOP 슬라이드 안의 어떤 位置)에 對해 試圖함으로써 攻擊이 成功할 수 있다. 마이크로소프트는 任意로 暗號化 方案을 變更함으로써 이 弱點을 補完, 部分的으로만 덮어쓰기가 可能하게 하였다.

實行 空間 保護 [ 編輯 ]

實行 空間 保護는 버퍼 오버플로를 防止하기 위한 接近 方法으로 스택이나 힙 相議 코드가 實行되는 것을 막는다. 攻擊者는 버퍼 오버플로를 利用하여 任意의 코드를 프로그램의 메모리에 揷入할 수 있지만, 實行 領域 保護가 있다면, 그 코드를 實行하고자 하는 어떠한 試圖도 例外를 發生시킬 것이다. 어떤 CPU는 NX (No eXecute) 또는 XD (eXecute Disabled)비트 라는 機能을 支援하는데 소프트웨어와 連繫하여 데이터의 페이지 (卽 스택이나 힙을 담고 있는)를 읽고 쓰기는 可能하나 實行 不可로 標示할 수 있다. 어떤 유닉스 運營 體制는 (例를 들어 오픈 BSD , OS X ) 은 實行可能한 空間 保護와 함께 出市되었다. (예: W^X ) 옵션 패키지에는 다음이 包含될 수 있다:

새로운 마이크로소프트 變種도 實行 空間 保護를 支援하며 데이터 實行 防止 라고 부른다. 常用 追加 機能은 다음과 같다:

實行 空間 保護로 libc로 歸還 攻擊 또는 攻擊者 코드 實行에 依支하지 않는 攻擊을 防止한다고 保證할 수는 없다.

住所 空間 配置 難手話 [ 編輯 ]

住所 空間 配置 難手話 (Address space layout randomization, ASLR)는 컴퓨터 保安 機能으로 重要 데이터 領域, 例를 들어 實行 코드의 基盤 住所, 라이브러리, 힙, 스택 住所 等을 任意로 프로세서의 住所 空間에 配置하는 것이다. 函數와 變數를 찾을 수 있는 假想 메모리 住所의 亂手話로 버퍼 오버플로 利用이 더 어려워지지만 不可能한 것은 아니다. 攻擊者가 利用 試圖를 各各의 시스템에 따라 다르게 하도록 强要하므로 인터넷 웜 防禦에 더 有用하다. 비슷하지만 덜 效果的인 方法은 프로세스와 라이브러리를 假想 住所 空間에 里베이스 하는 것이다.

深層 패킷 調査 [ 編輯 ]

深層 패킷 調査로 네트워크 境界에서 아주 簡單한 버퍼 오버플로 遠隔 試圖를 攻擊 固有 信號과 經驗的 方法으로 檢出할 수 있다. 알려진 攻擊 固有 信號 또는 긴 NOP 命令이 檢出되면 패킷을 막을 수 있으며, 攻擊 패킷 內容으 조금 달라도 使用할 수 있다. 패킷 스캐닝은 效果的이지 못한데, 그 까닭은 알려진 攻擊만 막을 수 있고 NOP 슬라이드는 다양한 方法으로 暗號化 할 수 있기 때문이다. 攻擊者들은 經驗論的 패킷 스캐너와 侵入 感知 시스템 의 探知를 回避하기 위하여 英數字 , 탈바꿈 , 自己 修正 셸코드 를 使用하기 始作하였다.

이용의 歷史 [ 編輯 ]

버퍼 오버플로는 1972年 컴퓨터 保安 技術 企劃 硏究에서 技法을 紹介하였을 때부터 理解되었던 槪念이다. "이 機能을 遂行하는 코드는 出處와 目的地 住所를 適切히 檢査하지 않으므로, 使用者가 모니터의 一部를 덮어쓰도록 許容한다. 이는 코드를 모니터에 揷入하여 制御權을 獲得하는 데 使用될 수 있다." 오늘날 모니터는 커널이라고 불릴 것이다.

1980年代 個人用 컴퓨터의 擴散으로 이 技法에 對해 아는 사람의 數가 增加하였다. 코모도어 PET 床에서 例를 들어 흔히 두 番째 테이프 버퍼를 使用하여 어셈블리 言語 루틴을 貯藏하였다. [ 模糊한 表現 ] 어떤 프로그래머들은 最大 32KB인 컴퓨터의 主記憶場所 空間에서 몇바이트를 節約하기 위해 베이직 言語의 번거로운 POKE 命令 使用 代身 프린트 버퍼의 始作點을 테이프 버퍼로 變更하여 6502 어셈블리 言語 코드(異常해 보이는 글字로 이루어진)를 直接 願하는 곳으로 出力하였다. 實際로는 프린터 버퍼가 테이프 버퍼 보다 길었기 때문에, 베이직 文字列이 쉽게 1024 바이트를 넘어갔고, PET像의 마이크로소프트 베이직 인터프리터와 干涉하였다. 初期 맥, 코모도어, 아타리等 初期 個人用 컴퓨터 부트 이미지 로더와 95, 98까지의 마이크로소프트 윈도우 運營 體制는 버퍼 保護에 不適切하였고 많은 프로그래머들이 버퍼 오버플로에 對해 알게 되었다. 最初로 文書에 남은 敵對的 버퍼 오버플로 利用은 1988年이었다. 모리스 웜 이 인터넷에서 自身을 퍼뜨리기 위해 使用했던 몇가지 攻擊 가운데 하나였다. 그 프로그램이 利用했던 것은 핑거 라는 유닉스 서비스 였다. 1995年 토마스 老婆틱은 獨立的으로 버퍼 오버플로를 再發見하였고 自身의 發見을 버그트랙 (Bugtraq) 保安 메일링 리스트 에 公開하였다. 1年 後 1996年 엘리아스 레비 (알레프 원으로 알려진)는 프랙 지에 "재미와 所得을 위해 스택 때리기"라는 題目의 記事에서 스택 基盤 버퍼 오버플로 脆弱點을 攻掠하는 段階別 紹介를 公開하였다.

그 以後에 最小限 두가지의 大規模 인터넷 웜이 버퍼 오버플로를 利用하여 많은 數의 시스템에 影響을 주었다. 2001年 코드 레드 웜 은 마이크로소프트의 인터넷 情報 서비스 5.0의 버퍼 오버플로를 利用했고, 2003年의 SQL 슬래머 웜은 마이크로소프트 SQL 서버 2000 을 實行시키는 컴퓨터에 影響을 주었다.

2003年 許可된 엑스박스 게임 안에 存在했던 버퍼 오버플로가 利用되어 自作 게임 을 包含한 許可 받지 않은 소프트웨어도 콘솔에서 모드칩 이라고 알려진 하드웨어 變更 없이 利用할 수 있게 되었다. PS2 獨立 攻擊 도 버퍼 오버플로를 使用하여 같은 作用을 플레이스테이션 2 에 일으켰다. 黃紅 攻擊 닌텐도 位 에서 같은 效果를 거두었는데, 젤多義 傳說 黃昏의 公州 의 버퍼 오버플로를 利用하였다.

예제 소스 코드 [ 編輯 ]

아래의 C 소스 코드는 一般的인 프로그래밍 失手를 보여준다. 一旦 컴파일 되면, 너무 긴 커맨드라인 人者 文字列을 가지고 實行하면 프로그램은 버퍼 오버플로 誤謬를 發生할 것이다. 왜냐하면 이 因子의 길이를 체크하지 않고 버퍼를 채우는 데 使用하기 때문이다. [2]

/* overflow.c - 버퍼 오버플로를 說明한다 */


#include
 <stdio.h>

#include
 <string.h>


int
 main
(
int
 argc
,
 char
 *
argv
[])

{

  char
 buffer
[
10
];

  if
 (
argc
 <
 2
)

  {

    fprintf
(
stderr
,
 "使用法: %s 文字列
\n
"
,
 argv
[
0
]);

    return
 1
;

  }

  strcpy
(
buffer
,
 argv
[
1
]);

  return
 0
;

}

9個 以下의 文字 스트링은 버퍼 오버플로를 일으키지 않는다. 10 以上의 文字들은 오버플로를 일으킨다. 이것은 언제나 不正確하지만 프로그램 誤謬나 세그먼트 폴트를 일으키지는 않는다. strncpy 는 버퍼에 쓰일 文字의 個數를 制限할 수 있다.

이 프로그램은 strncpy 를 利用해 아래와 같이 安全하게 다시 쓸 수 있다: [2]

/* better.c - 問題 解決 方法 하나를 說明한다 */


#include
 <stdio.h>

#include
 <string.h>


int
 main
(
int
 argc
,
 char
 *
argv
[])

{

  char
 buffer
[
10
];

  if
 (
argc
 <
 2
)

  {

    fprintf
(
stderr
,
 "使用法: %s 文字列
\n
"
,
 argv
[
0
]);

    return
 1
;

  }

  strncpy
(
buffer
,
 argv
[
1
],
 sizeof
(
buffer
));

  buffer
[
sizeof
(
buffer
)
 -
 1
]
 =
 '\0'
;
  /* 文字列의 끝을 分明히 맺는다 */

  return
 0
;

}

같이 보기 [ 編輯 ]

參照 [ 編輯 ]

  1. Routine Mappings(CRT)
  2. Safer C: Developing Software for High-integrity and Safety-critical Systems ( ISBN   0-07-707640-0 )

外部 링크 [ 編輯 ]