Perl CGI被黑客入侵?但我正在做一切正确

前端之家收集整理的这篇文章主要介绍了Perl CGI被黑客入侵?但我正在做一切正确前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我刚刚注意到我的一个网页目录中有一些奇怪的PHP文件。他们原来是垃圾邮件发送者的漏洞利用文件

自2006年以来,他们一直在那里,在我使用我的CGI脚本进行高调的捐赠活动的时候。而这些文件被放置在脚本的可写目录中,所以我怀疑我的脚本可能被以某种方式被利用了。

但是我使用Perl“污点检查”,严格等等,我从来没有将查询数据传递给shell(它从不调用shell!)或使用查询数据生成OPEN的文件路径…我只OPEN文件,我直接在脚本中指定。我将查询数据INTO写入文件作为文件内容,但据我所知,这并不危险。

我盯着这些脚本,看不到任何东西,我研究了所有的Perl CGI标准孔。当然,他们可能会以某种方式获得我的主机帐户的密码,但是这些脚本被放置在我的CGI脚本的数据目录中的事实使我怀疑脚本。 (另外,他们得到我的密码“不知何故”是一个非常可怕的解释。)另外,在那段时间,我的日志显示了很多“警告,从非PayPal地址收到的IPN”消息,这些IP来自俄罗斯。所以似乎有人至少TRYING来破解这些脚本。

涉及两个脚本,我将它们粘贴到下面。任何人都可以看到任何可能被利用来写入意外的文件

这是第一个脚本(用于接收PayPal IPN并跟踪捐款,并跟踪哪个站点产生最多捐款):

  1. #!/usr/bin/perl -wT
  2.  
  3.  
  4. # Created by Jason Rohrer,December 2005
  5. # Copied basic structure and PayPal protocol code from DonationTracker v0.1
  6.  
  7.  
  8. # Script settings
  9.  
  10.  
  11.  
  12. # Basic settings
  13.  
  14. # email address this script is tracking payments for
  15. my $receiverEmail = "receiver\@yahoo.com";
  16.  
  17. # This script must have write permissions to BOTH of its DataDirectories.
  18. # It must be able to create files in these directories.
  19. # On most web servers,this means the directory must be world-writable.
  20. # ( chmod a+w donationData )
  21. # These paths are relative to the location of the script.
  22. my $pubDataDirectory = "../goliath";
  23. my $privDataDirectory = "../../cgi-data/donationNet";
  24.  
  25. # If this $privDataDirectory setting is changed,you must also change it below
  26. # where the error LOG is opened
  27.  
  28. # end of Basic settings
  29.  
  30.  
  31.  
  32.  
  33.  
  34. # Advanced settings
  35. # Ignore these unless you know what you are doing.
  36.  
  37.  
  38.  
  39. # where the log of incoming donations is stored
  40. my $donationLogFile = "$privDataDirectory/donationLog.txt";
  41.  
  42.  
  43. # location of public data generated by this script
  44. my $overallSumFile = "$pubDataDirectory/overallSum.html";
  45. my $overallCountFile = "$pubDataDirectory/donationCount.html";
  46. my $topSiteListFile = "$pubDataDirectory/topSiteList.html";
  47.  
  48. # private data tracking which donation total coming from each site
  49. my $siteTrackingFile = "$privDataDirectory/siteTracking.txt";
  50.  
  51. # Where non-fatal errors and other information is logged
  52. my $logFile = "$privDataDirectory/log.txt";
  53.  
  54.  
  55.  
  56. # IP of notify.paypal.com
  57. # used as cheap security to make sure IPN is only coming from PayPal
  58. my $paypalNotifyIP = "216.113.188.202";
  59.  
  60.  
  61.  
  62. # setup a local error log
  63. use CGI::Carp qw( carpout );
  64. BEGIN {
  65.  
  66. # location of the error log
  67. my $errorLogLocation = "../../cgi-data/donationNet/errors.log";
  68.  
  69. use CGI::Carp qw( carpout );
  70. open( LOG,">>$errorLogLocation" ) or
  71. die( "Unable to open $errorLogLocation: $!\n" );
  72. carpout( LOG );
  73. }
  74.  
  75. # end of Advanced settings
  76.  
  77.  
  78. # end of script settings
  79.  
  80.  
  81.  
  82.  
  83.  
  84.  
  85.  
  86.  
  87. use strict;
  88. use CGI; # Object-Oriented CGI library
  89.  
  90.  
  91.  
  92. # setup stuff,make sure our needed files are initialized
  93. if( not doesFileExist( $overallSumFile ) ) {
  94. writeFile( $overallSumFile,"0" );
  95. }
  96. if( not doesFileExist( $overallCountFile ) ) {
  97. writeFile( $overallCountFile,"0" );
  98. }
  99. if( not doesFileExist( $topSiteListFile ) ) {
  100. writeFile( $topSiteListFile,"" );
  101. }
  102. if( not doesFileExist( $siteTrackingFile ) ) {
  103. writeFile( $siteTrackingFile,"" );
  104. }
  105.  
  106.  
  107. # allow group to write to our data files
  108. umask( oct( "02" ) );
  109.  
  110.  
  111.  
  112. # create object to extract the CGI query elements
  113.  
  114. my $cgiQuery = CGI->new();
  115.  
  116.  
  117.  
  118.  
  119. # always at least send an HTTP OK header
  120. print $cgiQuery->header( -type=>'text/html',-expires=>'now',-Cache_control=>'no-cache' );
  121.  
  122. my $remoteAddress = $cgiQuery->remote_host();
  123.  
  124.  
  125.  
  126. my $action = $cgiQuery->param( "action" ) || '';
  127.  
  128. # first,check if our count/sum is being queried by another script
  129. if( $action eq "checkResults" ) {
  130. my $sum = readTrimmedFileValue( $overallSumFile );
  131. my $count = readTrimmedFileValue( $overallCountFile );
  132.  
  133. print "$count \$$sum";
  134. }
  135. elsif( $remoteAddress eq $paypalNotifyIP ) {
  136.  
  137. my $donorName;
  138.  
  139.  
  140. # $customField contains URL of site that received donation
  141. my $customField = $cgiQuery->param( "custom" ) || '';
  142.  
  143. # untaint and find whitespace-free string (assume it's a URL)
  144. ( my $siteURL ) = ( $customField =~ /(\S+)/ );
  145.  
  146. my $amount = $cgiQuery->param( "mc_gross" ) || '';
  147.  
  148. my $currency = $cgiQuery->param( "mc_currency" ) || '';
  149.  
  150. my $fee = $cgiQuery->param( "mc_fee" ) || '0';
  151.  
  152. my $date = $cgiQuery->param( "payment_date" ) || '';
  153.  
  154. my $transactionID = $cgiQuery->param( "txn_id" ) || '';
  155.  
  156.  
  157. # these are for our private log only,for tech support,etc.
  158. # this information should not be stored in a web-accessible
  159. # directory
  160. my $payerFirstName = $cgiQuery->param( "first_name" ) || '';
  161. my $payerLastName = $cgiQuery->param( "last_name" ) || '';
  162. my $payerEmail = $cgiQuery->param( "payer_email" ) || '';
  163.  
  164.  
  165. # only track US Dollars
  166. # (can't add apples to oranges to get a final sum)
  167. if( $currency eq "USD" ) {
  168.  
  169. my $status = $cgiQuery->param( "payment_status" ) || '';
  170.  
  171. my $completed = $status eq "Completed";
  172. my $pending = $status eq "Pending";
  173. my $refunded = $status eq "Refunded";
  174.  
  175. if( $completed or $pending or $refunded ) {
  176.  
  177. # write all relevant payment info into our private log
  178. addToFile( $donationLogFile,"$transactionID $date\n" .
  179. "From: $payerFirstName $payerLastName " .
  180. "($payerEmail)\n" .
  181. "Amount: \$$amount\n" .
  182. "Fee: \$$fee\n" .
  183. "Status: $status\n\n" );
  184.  
  185. my $netDonation;
  186.  
  187. if( $refunded ) {
  188. # subtract from total sum
  189.  
  190. my $oldSum =
  191. readTrimmedFileValue( $overallSumFile );
  192.  
  193. # both the refund amount and the
  194. # fee on the refund are now reported as negative
  195. # this changed as of February 13,2004
  196. $netDonation = $amount - $fee;
  197. my $newSum = $oldSum + $netDonation;
  198.  
  199. # format to show 2 decimal places
  200. my $newSumString = sprintf( "%.2f",$newSum );
  201.  
  202. writeFile( $overallSumFile,$newSumString );
  203.  
  204.  
  205. my $oldCount = readTrimmedFileValue( $overallCountFile );
  206. my $newCount = $oldCount - 1;
  207. writeFile( $overallCountFile,$newCount );
  208.  
  209. }
  210.  
  211. # This check no longer needed as of February 13,2004
  212. # since now only one IPN is sent for a refund.
  213. #
  214. # ignore negative completed transactions,since
  215. # they are reported for each refund (in addition to
  216. # the payment with Status: Refunded)
  217. if( $completed and $amount > 0 ) {
  218. # fee has not been subtracted yet
  219. # (fee is not reported for Pending transactions)
  220.  
  221. my $oldSum =
  222. readTrimmedFileValue( $overallSumFile );
  223. $netDonation = $amount - $fee;
  224. my $newSum = $oldSum + $netDonation;
  225.  
  226. # format to show 2 decimal places
  227. my $newSumString = sprintf( "%.2f",$newSumString );
  228.  
  229. my $oldCount = readTrimmedFileValue(
  230. $overallCountFile );
  231. my $newCount = $oldCount + 1;
  232. writeFile( $overallCountFile,$newCount );
  233. }
  234.  
  235. if( $siteURL =~ /http:\/\/\S+/ ) {
  236. # a valid URL
  237.  
  238. # track the total donations of this site
  239. my $siteTrackingText = readFileValue( $siteTrackingFile );
  240. my @siteDataList = split( /\n/,$siteTrackingText );
  241. my $newSiteData = "";
  242. my $exists = 0;
  243. foreach my $siteData ( @siteDataList ) {
  244. ( my $url,my $siteSum ) = split( /\s+/,$siteData );
  245. if( $url eq $siteURL ) {
  246. $exists = 1;
  247. $siteSum += $netDonation;
  248. }
  249. $newSiteData = $newSiteData . "$url $siteSum\n";
  250. }
  251.  
  252. if( not $exists ) {
  253. $newSiteData = $newSiteData . "$siteURL $netDonation";
  254. }
  255.  
  256. trimWhitespace( $newSiteData );
  257.  
  258. writeFile( $siteTrackingFile,$newSiteData );
  259.  
  260. # now generate the top site list
  261.  
  262. # our comparison routine,descending order
  263. sub highestTotal {
  264. ( my $url_a,my $total_a ) = split( /\s+/,$a );
  265. ( my $url_b,my $total_b ) = split( /\s+/,$b );
  266. return $total_b <=> $total_a;
  267. }
  268.  
  269. my @newSiteDataList = split( /\n/,$newSiteData );
  270.  
  271. my @sortedList = sort highestTotal @newSiteDataList;
  272.  
  273. my $listHTML = "<TABLE BORDER=0>\n";
  274. foreach my $siteData ( @sortedList ) {
  275. ( my $url,$siteData );
  276.  
  277. # format to show 2 decimal places
  278. my $siteSumString = sprintf( "%.2f",$siteSum );
  279.  
  280. $listHTML = $listHTML .
  281. "<TR><TD><A HREF=\"$url\">$url</A></TD>".
  282. "<TD ALIGN=RIGHT>\$$siteSumString</TD></TR>\n";
  283. }
  284.  
  285. $listHTML = $listHTML . "</TABLE>";
  286.  
  287. writeFile( $topSiteListFile,$listHTML );
  288.  
  289. }
  290.  
  291.  
  292. }
  293. else {
  294. addToFile( $logFile,"Payment status unexpected\n" );
  295. addToFile( $logFile,"status = $status\n" );
  296. }
  297. }
  298. else {
  299. addToFile( $logFile,"Currency not USD\n" );
  300. addToFile( $logFile,"currency = $currency\n" );
  301. }
  302. }
  303. else {
  304. # else not from paypal,so it might be a user accessing the script
  305. # URL directly for some reason
  306.  
  307.  
  308. my $customField = $cgiQuery->param( "custom" ) || '';
  309. my $date = $cgiQuery->param( "payment_date" ) || '';
  310. my $transactionID = $cgiQuery->param( "txn_id" ) || '';
  311. my $amount = $cgiQuery->param( "mc_gross" ) || '';
  312.  
  313. my $payerFirstName = $cgiQuery->param( "first_name" ) || '';
  314. my $payerLastName = $cgiQuery->param( "last_name" ) || '';
  315. my $payerEmail = $cgiQuery->param( "payer_email" ) || '';
  316.  
  317.  
  318. my $fee = $cgiQuery->param( "mc_fee" ) || '0';
  319. my $status = $cgiQuery->param( "payment_status" ) || '';
  320.  
  321. # log it
  322. addToFile( $donationLogFile,"WARNING: got IPN from unexpected IP address\n" .
  323. "IP address: $remoteAddress\n" .
  324. "$transactionID $date\n" .
  325. "From: $payerFirstName $payerLastName " .
  326. "($payerEmail)\n" .
  327. "Amount: \$$amount\n" .
  328. "Fee: \$$fee\n" .
  329. "Status: $status\n\n" );
  330.  
  331. # print an error page
  332. print "Request blocked.";
  333. }
  334.  
  335.  
  336.  
  337. ##
  338. # Reads file as a string.
  339. #
  340. # @param0 the name of the file.
  341. #
  342. # @return the file contents as a string.
  343. #
  344. # Example:
  345. # my $value = readFileValue( "myFile.txt" );
  346. ##
  347. sub readFileValue {
  348. my $fileName = $_[0];
  349. open( FILE,"$fileName" )
  350. or die( "Failed to open file $fileName: $!\n" );
  351. flock( FILE,1 )
  352. or die( "Failed to lock file $fileName: $!\n" );
  353.  
  354. my @lineList = <FILE>;
  355.  
  356. my $value = join( "",@lineList );
  357.  
  358. close FILE;
  359.  
  360. return $value;
  361. }
  362.  
  363.  
  364.  
  365. ##
  366. # Reads file as a string,trimming leading and trailing whitespace off.
  367. #
  368. # @param0 the name of the file.
  369. #
  370. # @return the trimmed file contents as a string.
  371. #
  372. # Example:
  373. # my $value = readFileValue( "myFile.txt" );
  374. ##
  375. sub readTrimmedFileValue {
  376. my $returnString = readFileValue( $_[0] );
  377. trimWhitespace( $returnString );
  378.  
  379. return $returnString;
  380. }
  381.  
  382.  
  383.  
  384. ##
  385. # Writes a string to a file.
  386. #
  387. # @param0 the name of the file.
  388. # @param1 the string to print.
  389. #
  390. # Example:
  391. # writeFile( "myFile.txt","the new contents of this file" );
  392. ##
  393. sub writeFile {
  394. my $fileName = $_[0];
  395. my $stringToPrint = $_[1];
  396.  
  397. open( FILE,">$fileName" )
  398. or die( "Failed to open file $fileName: $!\n" );
  399. flock( FILE,2 )
  400. or die( "Failed to lock file $fileName: $!\n" );
  401.  
  402. print FILE $stringToPrint;
  403.  
  404. close FILE;
  405. }
  406.  
  407.  
  408.  
  409. ##
  410. # Checks if a file exists in the filesystem.
  411. #
  412. # @param0 the name of the file.
  413. #
  414. # @return 1 if it exists,and 0 otherwise.
  415. #
  416. # Example:
  417. # $exists = doesFileExist( "myFile.txt" );
  418. ##
  419. sub doesFileExist {
  420. my $fileName = $_[0];
  421. if( -e $fileName ) {
  422. return 1;
  423. }
  424. else {
  425. return 0;
  426. }
  427. }
  428.  
  429.  
  430.  
  431. ##
  432. # Trims any whitespace from the beginning and end of a string.
  433. #
  434. # @param0 the string to trim.
  435. ##
  436. sub trimWhitespace {
  437.  
  438. # trim from front of string
  439. $_[0] =~ s/^\s+//;
  440.  
  441. # trim from end of string
  442. $_[0] =~ s/\s+$//;
  443. }
  444.  
  445.  
  446.  
  447. ##
  448. # Appends a string to a file.
  449. #
  450. # @param0 the name of the file.
  451. # @param1 the string to append.
  452. #
  453. # Example:
  454. # addToFile( "myFile.txt","the new contents of this file" );
  455. ##
  456. sub addToFile {
  457. my $fileName = $_[0];
  458. my $stringToPrint = $_[1];
  459.  
  460. open( FILE,">>$fileName" )
  461. or die( "Failed to open file $fileName: $!\n" );
  462. flock( FILE,2 )
  463. or die( "Failed to lock file $fileName: $!\n" );
  464.  
  465. print FILE $stringToPrint;
  466.  
  467. close FILE;
  468. }
  469.  
  470.  
  471.  
  472. ##
  473. # Makes a directory file.
  474. #
  475. # @param0 the name of the directory.
  476. # @param1 the octal permission mask.
  477. #
  478. # Example:
  479. # makeDirectory( "myDir",oct( "0777" ) );
  480. ##
  481. sub makeDirectory {
  482. my $fileName = $_[0];
  483. my $permissionMask = $_[1];
  484.  
  485. mkdir( $fileName,$permissionMask );
  486. }

而且,这里有一些冗余(对于…完整性呢?),但这是第二个脚本(用于生成网站HTML按钮,人们可以添加到自己的网站):

  1. #!/usr/bin/perl -wT
  2.  
  3.  
  4. # Created by Jason Rohrer,December 2005
  5.  
  6.  
  7. # Script settings
  8.  
  9.  
  10.  
  11. # Basic settings
  12.  
  13. my $templateFile = "buttonTemplate.html";
  14.  
  15. # end of Basic settings
  16.  
  17.  
  18.  
  19.  
  20.  
  21. # Advanced settings
  22. # Ignore these unless you know what you are doing.
  23.  
  24. # setup a local error log
  25. use CGI::Carp qw( carpout );
  26. BEGIN {
  27.  
  28. # location of the error log
  29. my $errorLogLocation = "../../cgi-data/donationNet/errors.log";
  30.  
  31. use CGI::Carp qw( carpout );
  32. open( LOG,">>$errorLogLocation" ) or
  33. die( "Unable to open $errorLogLocation: $!\n" );
  34. carpout( LOG );
  35. }
  36.  
  37. # end of Advanced settings
  38.  
  39.  
  40. # end of script settings
  41.  
  42.  
  43.  
  44.  
  45.  
  46.  
  47.  
  48.  
  49. use strict;
  50. use CGI; # Object-Oriented CGI library
  51.  
  52.  
  53. # create object to extract the CGI query elements
  54.  
  55. my $cgiQuery = CGI->new();
  56.  
  57.  
  58.  
  59.  
  60. # always at least send an HTTP OK header
  61. print $cgiQuery->header( -type=>'text/html',-Cache_control=>'no-cache' );
  62.  
  63.  
  64. my $siteURL = $cgiQuery->param( "site_url" ) || '';
  65.  
  66. print "Paste this HTML into your website:<BR>\n";
  67.  
  68. print "<FORM><TEXTAREA COLS=40 ROWS=10>\n";
  69.  
  70. my $buttonTemplate = readFileValue( $templateFile );
  71.  
  72. $buttonTemplate =~ s/SITE_URL/$siteURL/g;
  73.  
  74. # escape all tags
  75. $buttonTemplate =~ s/&/&amp;/g;
  76. $buttonTemplate =~ s/</&lt;/g;
  77. $buttonTemplate =~ s/>/&gt;/g;
  78.  
  79.  
  80. print $buttonTemplate;
  81.  
  82. print "\n</TEXTAREA></FORM>";
  83.  
  84.  
  85.  
  86.  
  87. ##
  88. # Reads file as a string.
  89. #
  90. # @param0 the name of the file.
  91. #
  92. # @return the file contents as a string.
  93. #
  94. # Example:
  95. # my $value = readFileValue( "myFile.txt" );
  96. ##
  97. sub readFileValue {
  98. my $fileName = $_[0];
  99. open( FILE,$permissionMask );
  100. }

解决方法

我以前看过类似的东西。在我们的例子中,我很确定黑客在库中使用了一个尚未更新的缓冲区溢出。他们然后可以使用PHP shell来写入服务器文件

很可能问题不在你的代码中。更经常地更新您的软件会使攻击不太可能,但不幸的是,无法完全防范黑客攻击。有可能他们正在扫描旧版软件中的常见漏洞。

猜你在找的Perl相关文章