【ハッキングの気持ち】パスワード"AAAAAAAAAAAAAAAAAAAAAAAAAAAAA"でログインする
こんにちは!まさです
今回はプログラムのIF文を不正にパスするハッキングの方法を紹介したいと思います。
この方法を使ってIF文をパスできてしまうと、不正な文字列でのログインや、Linuxなどの場合、管理者権限を奪われてしまうという恐ろしい危険性が
あります。
そんな攻撃の中でも最も簡単な方法を紹介したいと思います。
今回攻撃するのは"auth_overflow"というプログラムです。
(下にC言語のコードを載せています)
このプログラムは、ユーザが入力した文字列が、あらかじめ決まったパスワードと一致しているか判定し、その結果を出力するというものです。
今回は"brillig"または"outgrabe"という文字列が入力されるとパスするようにしています。
★ auth_overflowの挙動
1. gccを使ってauth_overflow.cをコンパイルし、実行ファイル(a.out)を作ります。
今回はオプションで"-fno-stack-protector"を付け加えます。
このオプションは、"メモリへの不正な上書きを許す"という意味だと思ってください。
gcc auth_overflow.c -fno-stack-protector
2. パスワード以外の文字列を入力するとアクセス拒否します。
3. パスワード文字列を入力するとアクセス許可されます。
このプログラムの動きはこれだけです。
以下は"auth_overflow.c"のソースコードです。
#include <stdio.h> #include <stdlib.h> #include <string.h> int check_authentication(char *password) { char password_buffer[16]; int auth_flag = 0; strcpy(password_buffer, password); if(strcmp(password_buffer, "brillig") == 0) auth_flag = 1; if(strcmp(password_buffer, "outgrabe") == 0) auth_flag = 1; return auth_flag; } int main(int argc, char *argv[]) { if(argc < 2) { printf("使用方法: %s <パスワード>\n", argv[0]); exit(0); } if(check_authentication(argv[1])) { printf("\n-=-=-=-=-=-=-=-=-=-=-=-=-=-\n"); printf(" アクセスを許可します。\n"); printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-\n"); } else { printf("\nアクセスを拒否しました。\n"); } }
さて、ここでパスワードとは全く異なる文字列"AAAAAAAAAAAAAAAAAAAAAAAAAAAAA"(A×29回)を入力したらどうなるでしょうか?
その結果は...
”アクセスを許可してしまいました!”
プログラムのソースコードにはもちろんこのような文字列での分岐は想定されていません。
ではなぜこの文字列でパスしてしまうのでしょうか。
その秘密はバッファーオーバーフロー攻撃という、有名な攻撃手法にあります。
このプログラムで起きたことを説明します。
このプログラムでは"password_buffer[16]"という配列にユーザーからの入力文字列を格納します。
しかし、ここに29文字のAを格納しようとすると、溢れてしまった13文字はpassword_bufferのすぐ隣のメモリ領域に"無理矢理"格納されてしまいます。
これがバッファーオーバーフローです。
その結果、運の悪いことに、その隣にあった変数"auth_flag"のメモリ領域が、"A"という文字(16進数で41)で上書きされてしまったというわけです。
c言語では0以外の数はTrueとみなされるので、その結果アクセスを許可してしまったというわけです。
41という文字がAを意味しています。
ここでは長くなるので触れませんが、実際にデバッグツールgdbを使うとpassword_bufferからバッファーオーバーフローが起きている様子を確認することができます。
下の写真では、auth_flagのアドレス”0x7fffffffdbec”を見事なまでに"A"が侵食していることがわかります。
いかがでしたでしょうか。
気づいた方もいるかもしれませんが、この攻撃はpassword_bufferのメモリアドレスの”後ろ”にauth_flagのメモリアドレスがあったからこそ成功していました。
では逆の位置関係の場合どうなるでしょうか。
ソースコードでこの2つの変数宣言の順番を変えれば、メモリアドレスの位置関係を逆にすることができます。
この場合同様の攻撃は通用しません。
しかし、攻撃の仕方を変えると、実は不正な文字列でパスすることが可能です!
この場合は少し話が複雑になります。
アセンブリやスタックセグメント、インストラクションポインタの仕組みを理解すると、攻撃可能になります。
具体的には、auth_flagを汚染するのではなく、スタックフレームの戻りアドレスを汚染することで可能となります。
また機会があれば書きたいと思います。