パスワード解読について(CGIスクリプト)

このQ&Aのポイント
  • パスワード解読について(CGIスクリプト)の続きとなります。文字数が800文字を超えたため、分割しています。
  • $salt = $logpassword =~ /^$1(.*)$/ && $1 || substr($logpassword, 0, 2);の処理について質問しています。パターン結合演算子などの意味が分かりません。
  • これらの動作の目的と動作原理について教えていただきたいとのことです。
回答を見る
  • ベストアンサー

パスワード解読について(CGIスクリプト)

 「パスワード暗号化について(CGIスクリプト)」の続きとなっています。文字数が800文字を超えてしまったため、分割させていただきました。  続いて解読処理です。こっちは更に謎です。 $salt = $logpassword =~ /^\$1\$(.*)\$/ && $1 || substr($logpassword, 0, 2);  最初は//内の処理です。$1$だけは読めますが、「^」も「(.*)」も最後の$も不明です。「^」はEXORではありませんよね・・・?  次に&&とやはり||です。この辺は「え?ギャグ?」って感じです(まったく分かってません)。  最後にパターン結合演算子ですが・・・。「スカラー式をm//、s///、tr///と結びつける」と言われても何のことやら。大体上の表記ではmもsもtrも使ってないんで・・・。マッチmの略形でしょうか?  ということで長くなってしまいましたが、これらの動作の目的、そして動作原理を教えていただきたく質問させていただきました。  どうかよろしくお願いします。

  • Perl
  • 回答数3
  • ありがとう数2

質問者が選んだベストアンサー

  • ベストアンサー
回答No.2

こちらこそよろしくお願いします。 正規表現に付いては、それこそ一冊の本にもなっているくらいなので、あとで じっくりラクダ本やその「詳説 正規表現」(http://www.oreilly.co.jp/BOOK/regex/) をご覧いただくといいと思いますが、とりあえず簡単に補足しておきます。 まず「^」ですが、これは「頭から評価していく」という意味ではありません。 「n文字目から…」の方が正解です。 $a = 'Perl is not a Pearl'; $b = 'What is Perl?'; のとき、 $a = /^Perl/; は先頭がPerlで始まるので真 $b = /^Perl/; は先頭がWhatで始まるので偽 $a = /Perl/; はPerlを含むので真 $b = /Perl/; もPerlを含むので真 となります。 「.*」は0回でも一致します。/Pe.*rl/ はPerlにもPearlにもマッチします。 1回以上必ずなにかないといけない場合は/Pe.+rl/と「+」を使います。 上の例で言うとこの正規表現は$aでは真、$bでは偽になります。 さて、「()」は実際のカッコを指しているのではないことにご注意ください。 'This is (not) Perl' =~ /(.*)/ も真ですし、'This is not Perl' =~ /(.*)/ も真です。本来の「()」にマッチさせたければ\を使って /\(.*\)/とします。 ただの「()」は「カッコの中のマッチした文字列をこっそり$1に突っ込んでお いてください」という意味です。$1の1は、カッコの登場順の番号を表します。 例えば $date = '2001/5/11 21:25:30'; $date =~ m/^(\d+)\/(\d+)\/(\d+) (\d+):(\d+):(\d+)/; とすると、$1に「2001」が、$2に「5」が、$3に「11」が…$6に「30」が入り ます。 なお、「\d」は数字を表す記号です。また「/」はそのまま書くと m//のスラッシュと区別がつかなくなるので「\/」としてあります。これを 避けるためm//を「/」ではない任意の文字で囲む方法もあります。 $date =~ m@^(\d+)/(\d+)/(\d+) (\d+):(\d+):(\d+)@; これだと@が区切りになるので「/」はそのままでよくなります。このときは 「m」は省略できません(なんか余計な説明加えちゃってかえって混乱させ ちゃったかな…)。 > (@log = <IN>;とかforeach(0 .. $#data){}とか) foreachのかわりにmap {} @data; を使うことを覚えたりするとさらにクセに なりますよ。

Yuya_Tachibana
質問者

お礼

 再度お付き合いいただきありがとう御座います。考察2です(笑)。  なんかやたらと手強い正規表現ですが(最初の頃は謎の羅列でしたが)、片鱗をちょっと垣間見させていただいました。 $logpassword =~ /^\$1\$(.*)\$/ 仰る通りに上記を解読してみると・・・。  まず、基本的に「$1$何か$」という文字列を評価し、「何か」の部分以外がマッチすれば、「.*」であるために「何かの部分が空文字列」でもひとまず真ということですね。  それで、「/^$1$/」の形であるために「最初が$1$のもの」を評価することになると。  その後、()があるので()内でマッチするものがあれば$1に代入しろ、と。ここでは()内が「.*」つまり「なんでもいい」ということなんで、結局「$1$」と「$」に挟まれた部分の文字列を$1に代入せよ、と言うことなんですね。なんで$1かっていうのは、()が1つ目だからであると。  ちょっと意訳しすぎてるところもありますが、おおざっぱに言うとこの正規表現の形はこんな感じでOKですかね?  ただ、またちょっと疑問というか確認したいことは、「^」はつまり「文字列の0文字目から」という意味になるのでしょうか?だとすると、n文字目の場合はどうなるんでしょうか?リファレンスにも書いてないようなんで・・・。まぁ、これは後学だから別の本を参照すべきですね。  ¥のエスケープについてはちょっとかじってるのでなんとか理解できました。取得したIPを分けるときなんかにsplit(/\./,$ENV{'りもーとあど'})とするのと一緒ですね。  dは・・・。フォーマットの時のsprintf("%.3d",$data)みたいなものでしょうか?C言語では、まぁdは整数fは小数点とかありましたけど、あれと一緒ですかね?表記方法も一緒っぽいし。  んで合ってたら結論ですが、結局この質問って「正規表現なんたら」の問題だったわけですね・・・。CGIとか暗号解読とか、全然関係ないし・・・。正規表現恐るべし、祖国統一万歳ですね。  それじゃ、これで(この質問は)最後かと思いたいんですが、確認をよろしくお願いします(メールじゃないんでもちろんどなたでも。是非お願いします)。

その他の回答 (2)

回答No.3

そういう解釈でよろしいと思います。 「n文字目」についてですが、/^.{n}\$1\$/ ですね。{}で繰り返す数を 指定します。でもあまり使うことはないですね。固定で先頭から何文字か わかってる場合はsubstrで切り出したりできますしね。 substr($xxx, n) =~ /^\$1\$/ ともできます。…でも書いてないのは リファレンスとしていかがなものか。 dはdecimal, 10進数の略です。sprintfのものも同じ語源だと思います。 Perlの正規表現はさらにものすごく多機能です。ゆっくり覚えていくことを お薦めします。

Yuya_Tachibana
質問者

お礼

 どうもありがとう御座いました。複数回に渡って丁寧に説明して下さり、とてもわかりやすく勉強になりました。  教えて下さったことをしっかり頭にたたき込んで、これからも勉強していきたいと思います。  今回は本当に助かりました。心より御礼申し上げます。 悠夜

回答No.1

おっしゃるとおり//はm//の省略形です。ですから「^」は、正規表現の 「文字列先頭」をあらわす記号です。よってこの部分は 「$logpasswordが '$1$' で始まり0以上の何文字かが続き$が来るような文字 列か?」 といったことを調査しています。 &&や||は、論理演算子ですね。A && Bで 「Aを評価(実行するってことです)して、真なら続けてBを評価してその結果を 返す。Aが偽ならBには一切感知せず偽を返す」 ということになり、A || Bで 「Aを評価して、真ならBには一切感知せずその結果を返す。Aが偽なら引き続 きBを評価してその結果を返す。」 ということになります。 上記の意味は総じて以下のようなことなんじゃないでしょうか。 「$logpasswordがこれこれのような文字列で、しかも途中の(.*)部分が 真(つまり空文字列じゃない)だったときはその(.*)部分を、 そうじゃないときは$logpasswordの先頭から2文字を取り出して、 saltに入れてください」 if文で書きなおすと上記の式は以下のようなことに なると思います。 if ($logpassword =~ m/^\$1\$(.*)\$/) { if (defined($1) && $1 ne '') { $salt = $1; } else { $salt = substr($logpassword, 0, 2); } } else { $salt = substr($logpassword, 0, 2); } まあたしかに初めてご覧になった方にはわかりやすいものではないでしょうが …あんまりPerlをいじめないであげてください。&&や||をこのように使うのは Cでもshellでもいろんな言語にもありまして、UNIX関係者には馴染みがある用法です。 lispなどではむしろifよりもこちらのほうが標準的です。 馴れると最初のような式の方が上記ifを使ったものより読みやすくなったりし ます。 もちろん、「おれはifで書いた方がいいぜ!」とお思いになるのでしたら 誰にかまうことなくそうお書きになればよろしいでしょう。 どう書いてもいいのがPerlです。

Yuya_Tachibana
質問者

補足

 早速のご回答ありがとう御座います。とてもわかりやすい説明で助かりました。でももうちょっと分からないところがあるので、迷惑ついでにお願いいたします。  さて、まず残った疑問点なんですが、やはり、 「$logpassword =~ m/^\$1\$(.*)\$/」 の式ですね。  ひとまずm//がマッチ演算子だということが理解できました。そして「^」ですが、これは要するに文字列の先頭から評価していくんだ、ということで、いいんですかね?初心者の目で見ると、変数の中身の評価なんていつでも最初から始まるじゃないかと思うんですが・・・。これはそういうことではなく、「n文字目から評価する場合もあるので、それじゃないということを明示している」ということなのでしょうか?  1,次に(.*)ですが、これは「パターンの中の()で囲んだ部分」ですよね。「.*」は要するに「任意の1文字の0回以上の繰り返し(0回以上ってことは、全く何もない時でも一応評価する、ということでしょうか、それとも0は真でも空文字は偽、を示すのでしょうか)」を示していて、結局は「マッチ成功時に、最初の1文字($1)を引っこ抜いて$saltに代入する」と読んで正解なのでしょうか?  ・・・なんか何言ってるのか分からないですね(汗)。  2,そういうことじゃなく、「$_の最初が$1$で始まって途中がどーでもよくて、最後に$が来るっていう文字列だった場合にはその途中の部分を抜き出して$1に代入するんだ」ってことなんですかね。  ・・・意見が上の2つに分かれています。僕の中で(汗)。  できれば2番が正解であって欲しいんですが・・・(1番は謎に包まれています)。  2番が正解なら、「if (defined($1) && $1 ne '') 」の部分も「$1がひとまずなんらかの文字なら」の一言で決着が付くんですよね。  という感じで考察してみました。いかがなものでしょうか?  ちなみに、個人的にPerlは好きです。Cをちょっとかじっていたので、Perlの謎の破壊力にちょっと驚いているところです(@log = <IN>;とかforeach(0 .. $#data){}とか)。  今回、「if($data){}ってなんなんだ!?」ってことを理解した(真と偽について初めて知った)ときのような感じを論理演算子でまた味わいました。慣れるとついつい使ってしまうような表現ですね。面白いです。  というわけで、また何かしら多分きっとお世話になると思うので今後ともよろしくお願いします。

関連するQ&A

  • パスワード暗号化について(CGIスクリプト)

     現在記事削除処理の、キー暗号化と解読について勉強しているんですが、他の方が書いたソースを読んでもさっぱり意味不明です。技術評論社さんのリファレンスを参考にしてるんですが、どうも載っていないワザが使われているらしく・・・。  まずは暗号化処理です(とある有名ソースから抜粋)。 @SALT = ('a'..'z', 'A'..'Z', '0'..'9', '.', '/'); srand; $salt = $SALT[int(rand(@SALT))] . $SALT[int(rand(@SALT))]; $encrypt = crypt($password, $salt) || crypt ($password, '$1$' . $salt); 問題は$encryptなんですが、||演算子は、要するに左オペランドの保険みたいなものなんでしょうか?まず、左オペランドが偽になる、ということ自体が分かりません。結果が偽になる、というのは0を返すということでしょうか?  crypt関数が処理を失敗する(?)、ということでも偽になるかもしれないんですが、暗号化処理を失敗などということがあるのでしょうか?  次に、ひとまず左オペランドが偽だった場合ですが、右オペランドに関して、暗号化キーが「$1$xx」の5文字ですよね。暗号化キーは2文字までしか評価されないから、結局これは「$1」と変わらない気がします。というより、まずなぜ「$1$」なんでしょうか?そして、合計5文字の意味は・・・?謎は深まるばかりです。  質問の長さが800文字を超えてしまうので、前半はここで切らせていただきます。  後半は「パスワード解読について(CGIスクリプト)」にて質問させていただいています。  どうかよろしくお願いします。

    • ベストアンサー
    • Perl
  • 暗号解読してください!

    友達からこんな暗号をもらいました 3312 だそうです。 母音があは、1 いは、2 うは、3 えは、4 おは、5 がヒントです。 最後の文字は い です。 解読お願いします!

  • トリッププログラム!?

    7桁の数字が,A~Z・a~z・0~9で構成された9桁の文字列になるとき,3103364はどうなるでしょうか。 3181008は0c8DgWWOz,3854944は0eJ9w3vyzになります。 お願いします! 【参考】(トリッププログラム) $tripkey = "#istrip"; #文字列 $tripkey = substr($tripkey,1); $salt = substr($tripkey.'H.',1,2); $salt =~ s/^.-z/./go; $salt =~ tr/:;<=>?@\^_`/ABCDEFGabcdef/; $trip = crypt($tripkey,$salt); $trip = substr($trip,-9); $trip = '◆'.$trip; print "$trip";

    • ベストアンサー
    • Perl
  • PerlでLinuxのユーザー認証・管理プログラム

    ブラウザでLinuxのユーザー名とパスワードと入力して、 ユーザー認証してログイン後、Linuxユーザーの パスワードを自分で変更できるプログラムが作りたいのです。 /etc/passwdにパスワードが直接記録されていれば簡単なのでしょうが、 シャドウパスワードなので苦労しています。LinuxはFedora Core3です。 まず、/etc/shadowに記録されているような、 $1$ではじまる暗号化されたシャドウパスワードをPerlで作るには どのようにしたらいいのでしょうか。 pwconvのソースをみたらどんなアルゴリズムかわかると思い、 shadow-utilのSRPMをインストールしてみたりしましたがわかりませんでした。PHPのメーリングリストに $salt = substr(md5(microtime()), 0, 9); return crypt($password, "$1$" . $salt); このようなコードがあったのですが、これでは$saltが毎回 代わってしまい、よくある $salt=substr(暗号化されたパスワード,0,2); if(crypt($pass,$salt) ne 暗号化されたパスワード){ &err("パスワードが違います"); } のような認証ができないのではないかと思いました。 Linuxではどのようなアルゴリズムでシャドウバスワード を作り、パスワードの認証をしているのでしょうか。 つまり、簡単にいうとPerlでシャドウパスワードを使った Linuxユーザーのパスワード認証と パスワード変更ができないか、ということなのです。 また、Perlでシャドウパスワードなど作らなくても system()などを使ってLinuxのコマンドを使えば 各ユーザーの認証やパスワードの変更がブラウザでできるという場合は、 教えていただけないでしょうか。 どうかご教示ください。よろしくお願いします。

  • 文字化けしたメールの解読

    受信したメールが文字化けしてしまい読めません・・・ 分かる方、解読お願いします! :!"M%$7$/$J$l$P6/$/$J$k$N$HF1$8$@$H9M$($k$h$&$K!#$9$G$K:L;R$OM%$7$/$J$C$F$$$k$3$H$H;d$O;W$C$F$$$^$9!#4hD%$l:L;R!#%P%$%P%$

  • CGIのスクリプトの解釈で分からないところがあります

    どうも、こんにちは(@^^@)。 CGIのPerlスクリプトを勉強しています。いろいろ手持ちの本を探してみたのですが、下記のスクリプトの一部の解釈の仕方が分からないので教えてください。HTMLフォームからパスワードを受け取って、照会するスクリプトの一部です。他の行は、大体分かるのですが8行目のみが分かりません。 まず、sと対応するgeの意味。また、hex関数の$1の意味。解説書には、$1は特殊な変数と書いてありましたが、それ以上詳しい解説は、ありませんでした。hex$は、単に16進数を10進数に変換するんですよね。そして、%(..)、pack("c",hex($1))も元の意味が分からないので解釈に困っています。 「パスワードを照会するスクリプトの一部です。」 1: homonsya = $ENV{'QUERY_STRING'}; 2: 3: @group = split(/&/, $homonsya); 4: foreach $ans (@group) 5: {($name, $value) = split(/=/, $ans); 6: 7: $value =~ tr/+/ /; 8: $value =~ s/%(..)/pack("c", hex($1))/ge; #.....???←「16真数を『読める文字』変換」とある。 9: $ok_homonsya{$name} = $value;} 10: 11:$pass = $ok_homonsya{'myName'}; また、ネットで調べようと思い、いろいろ検索してみると下記のような行をよく見かけました。 ☆ $key =~ s/%([A-Fa-f0-9][A-Fa-f0-9])/pack("c", hex($1))/ge; こちらもとても疑問の行と似ていますし、今後もよく使いそうな感じなので、気になっています。私は、パスワードを受け取って、管理者フォームに移動するようなスクリプトを作りたいと思っています。どうぞ、よろしくお願いいたしますm(__)m。

    • ベストアンサー
    • Perl
  • cgiとhtml

    #!/urs/bin/local/perl use CGI qw(:standard); use Date::Calc qw(:all); $year = param('year'); $mon = param('mon'); if ($year or $mon){ #年、月がないとエラー if (!$year){ &error(100,'年、月を入力して下さい。'); }elsif(!$mon){ &error(110,'年、月を入力して下さい。'); } #年は1以上、月は、1~12の範囲 #紀元前は計算しない if($year < 1){ &error(120,'年に誤りがあります。'); } if($mon < 1 or $mon > 12){ &error(130,'月に誤りがあります。'); } #カレンダーの計算 $cline = Calendar($year,$mon); #先頭行と最終行をとる $cline =~ s/^\n//; $cline =~ s/\n$//; #改行区切りで分割 @Cal = split(/\n/,$cline); #まず、年、月をテーブルに入れる $CAL.=<<"EOL"; <table border="1"> <tr> <td colspan="7" align="center">$year年$mon月</td> </tr> EOL #曜日をテーブルに入れる $CAL.=<<"EOL"; <tr> <td>日</td> <td>月</td> <td>火</td> <td>水</td> <td>木</td> <td>金</td> <td>土</td> </tr> EOL #日付をテーブルに入れる for($i=2; $i<=$#Cal; $i++){ $CAL.= <<"EOL"; <tr> EOL $shift=3; #1日に3文字文使う $s = 0; for ($j=0; $j<7; $j++){ $day = substr($Cal[$i], $s, $shift); if($day !~ /\d/){ $day = '&nbsp;'; #数字がなければスペース }else{ $day =~ s/ //g; #余分なスペースをとる } $CAL.=<<"EOL"; <td align="right">$day</td> EOL $s += $shift #3文字を右へ $s += 1; #2回目からは、区切り文字も計算 } $CAL.=<<"EOL"; </tr> EOL } $CAL.=<<"EOL"; </table> EOL } print <<"EOL"; Content-type: txet/html というプログラムを作ってカレンダーを表示させたいのですが、 HTMLで打つときに <html> <head> <title>カレンダー</title> </head> <body> <from action="report.cgi"> 年:<input type="text" size="4" name="year"> 月:<input type="text" size="2" name="mon"> <br> <input type="submit" value="表示"> </from> <br><br> $CAL(と入れたのですが、画面に%CALと出るだけでカレンダーが表示されません) </body> </html> 何を入れると画面ににきれいにカレンダーが表示されるのでしょうか?

    • ベストアンサー
    • CGI
  • 多次元配列?配列のキー?変数の型?

    PHP勉強中のものです。 予定通りの動作にならんく四苦八苦しています。 どのように修正すれば予定通りになるのか考え方のアドバイスなどお願いします。 処理したいこと 変数$xxxの先頭の文字と最後の文字をsubstr()で取り出し$aaaと$bbbに別けそれぞれ代入しキーとして多次元配列に代入した配列要素を指定してechoで出力したい 試してみたこと $aaa1と$bbb1に直接整数を代入してみたところ、echoで出力された キーになる変数を整数型として変数に代入してみたが希望通りの動作にならなかった。 なにかアドバイス頂けると助かります。 $array = array( "0" =>array("あいうえお","かきくけこ"), "1" =>array("さしすせそ") ); $xxx = "0-1"; $aaa = substr($xxx,0,1); $bbb = substr($xxx,2); $aaa = (int)$aaa; $bbb = (int)$bbb; echo $array[$aaa][$bbb]; //出力されない $aaa1 = 0; $bbb1 = 1; echo $array[$aaa1][$bbb1]; //出力された $aaa = (int)$aaa; $bbb = (int)$bbb; echo $array[$aaa][$bbb]; //出力されない

    • ベストアンサー
    • PHP
  • こんなメールが来たんですが、解読お願いします。

    知らないアドレスからYahoo!メールに来ました。解読お願いします。 o$C$?$h(B?? $B?2$k;~4V$b$_$8$1!<$7$h(B $B:#Ho32FO$1$N$?$a$K@:?@2JDL$C$F%+%&%s%;%j%s%0$_$?$$$N$@$1$d$C$?$j$H$+K\Ev6b$+$1$5$;$k$h$J(B?? $BK\Ev:#$@$1$@$+$i$=$s$J$s$G$$$i$l$s$N$b(B $B$3$l0J9_0l@Z%a!<%k$bJV?.$7$J$$$7EEOC$b$G$J$$$+$i(B $B$b$&IU$-$^$H$o$J$$$G0l@Z$&$A$K4X$o$i$J$$$G$&$A$o$b$&0l@Z9%$-$8$c$J$$$70l@Z4X$o$j$?$/$J$$(B $B$3$l$,K\Ev$K$&$A$+$i$N:G8e$N%a!<%k$H:G8e$NCi9p(B $B$O$C$-$j:#8@$C$?$+$i$M$&$A$N5$;}$A$r(B $B$=$l$G$b$3$N%a!<%k$K4X$7$FJV?.$7$F$-$ ?$j$7$?;~E@$G$&$A$^$B$G0lJ?7/$N$3$H$H$+B>$K$b?'!92fK}$7$F$-$?$3$H$"$k$1$I$J$K$7$G$+$9$+J,$+$s$M$'$+$i(B $B$I$C$A$_$A$b$&Ho32FO$1=P$9=`Hw$o$7$F$k$7$b$&O"Mm$7$J$$$+$i$H$+DLMQ$7$J$$$+$i(B $B$I$C$A$,>!$D$+3Z$7$_$@$M!)(B $B$H$K$+$/$b$&$&$A$K4X$o$i$J$$$G(B $B$"$H(Bmixi$B$N$o>C$5$J$$(B$BA0$K>C$7$?$N$o$b$&O"Mm$7$F$3$J$$$C$F<+J,$+$i8@$C$?$+$i$=$l$J$i$C$F;W$C$?$1$I2?2s$bLsB+GK$C$F$k$+$i:#2s$o>C$7$^$;$s(B $B$"$J$?$,:#8e$&$A$KO"Mm$7$F$/$k$+$7$F$3$J$$$+$H$+?'!9BP1~8+$F$+$i7h$a$k$

  • 文字化けを直すには

    現在、文字列で名前を検索してデータファイルを 開いてその名前のデータを表示するというのを作っているのですが、 名前が文字化けしてしまい困っています。 名前はスカラー変数に入ってて、    print "<tr><td>$name</td></tr>"; こんな感じで表示しているんですけど、 $nameに特定の文字がはいっていると    特性の文字・td></tr> このように文字化けみたいなことがおきてしまいます。 どうすれば回避できるのでしょうか? よろしくお願いします。

    • ベストアンサー
    • Perl

専門家に質問してみよう