{"id":46,"date":"2025-04-15T07:31:13","date_gmt":"2025-04-15T07:31:13","guid":{"rendered":"https:\/\/hackingwithj.com\/?p=46"},"modified":"2025-04-15T07:43:49","modified_gmt":"2025-04-15T07:43:49","slug":"unauthorized-access-to-high-resolution-photos-from-a-paid-photoshoot","status":"publish","type":"post","link":"https:\/\/hackingwithj.com\/?p=46","title":{"rendered":"Unauthorized Access to High-Resolution Photos From a Paid Photoshoot"},"content":{"rendered":"\n<p>In this post, I\u2019ll walk you through how I discovered a way to access original, high-resolution photos from a photoshoot\u2014photos you&#8217;re normally required to pay extra for. While this isn&#8217;t your typical \u201chack\u201d with terminal commands and fancy exploits, it does highlight a critical flaw in how some web apps handle access control.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>\u26a0\ufe0f Disclaimer: The image below (blurred for privacy) shows watermarked preview photos. I did not access or download photos belonging to others. My actions were limited to my own account<\/p>\n<\/blockquote>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"487\" src=\"https:\/\/hackingwithj.com\/wp-content\/uploads\/2025\/04\/Schermafbeelding-2025-04-08-153442-1024x487.png\" alt=\"\" class=\"wp-image-47\" style=\"width:892px;height:auto\" srcset=\"https:\/\/hackingwithj.com\/wp-content\/uploads\/2025\/04\/Schermafbeelding-2025-04-08-153442-1024x487.png 1024w, https:\/\/hackingwithj.com\/wp-content\/uploads\/2025\/04\/Schermafbeelding-2025-04-08-153442-300x143.png 300w, https:\/\/hackingwithj.com\/wp-content\/uploads\/2025\/04\/Schermafbeelding-2025-04-08-153442-768x366.png 768w, https:\/\/hackingwithj.com\/wp-content\/uploads\/2025\/04\/Schermafbeelding-2025-04-08-153442-1536x731.png 1536w, https:\/\/hackingwithj.com\/wp-content\/uploads\/2025\/04\/Schermafbeelding-2025-04-08-153442.png 1901w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\"><em>Figure 1<\/em><\/figcaption><\/figure>\n\n\n\n<p>The concept of the web app is simple: after a photo session, you&#8217;re given access to an online portfolio. From there, you can select a set number of photos to download\u2014based on your studio package\u2014or purchase additional digital copies or physical prints. But here\u2019s the catch: a single high-res digital copy costs \u20ac35. That\u2019s steep, especially when you consider you could print them yourself elsewhere for much cheaper\u2014<strong>if<\/strong> you had access to the original files. That\u2019s where I started digging.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Sniffing<\/h2>\n\n\n\n<p>Each user&#8217;s portfolio is accessed via a URL that includes a portfolio ID and a 4-digit token for \u201cprotection.\u201d Out of curiosity, I typed <code>..\/..\/<\/code> in the URL path\u2014and to my surprise, I could access a page listing other user portfolios, were you can enter a token. Yep. That easy. While I chose not to explore or open any of them (not my scope, not my interest), the fact that this was even possible is <em>a major red flag<\/em> in terms of access control and product design.<\/p>\n\n\n\n<p>Since I was only interested in my own files, I opened the browser developer tools to inspect the HTML and network activity. Within 5 minutes, I noticed something interesting:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"702\" height=\"250\" src=\"https:\/\/hackingwithj.com\/wp-content\/uploads\/2025\/04\/Schermafbeelding-2025-04-08-153640.png\" alt=\"\" class=\"wp-image-57\" srcset=\"https:\/\/hackingwithj.com\/wp-content\/uploads\/2025\/04\/Schermafbeelding-2025-04-08-153640.png 702w, https:\/\/hackingwithj.com\/wp-content\/uploads\/2025\/04\/Schermafbeelding-2025-04-08-153640-300x107.png 300w\" sizes=\"auto, (max-width: 702px) 100vw, 702px\" \/><figcaption class=\"wp-element-caption\"><em>Figure 2<\/em><\/figcaption><\/figure>\n\n\n\n<p>Each watermarked image had a special CSS class applied to it. By simply removing or modifying that class in the frontend, the watermark disappeared\u2014and the image became fullscreen width. This meant I could screenshot the photo in high quality, <em>but<\/em> I wanted to go further. If the frontend could render the image in high quality, it meant the full-resolution file was already being loaded in the background.<\/p>\n\n\n\n<p>I didn\u2019t even need to fire up tools like Burp Suite or OWASP ZAP. Just by watching the network tab in my browser&#8217;s dev tools while loading the portfolio, I found that each image was being loaded as a blob file\u2014uncompressed and in full resolution.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1021\" height=\"71\" src=\"https:\/\/hackingwithj.com\/wp-content\/uploads\/2025\/04\/Schermafbeelding-2025-04-08-153748-1.png\" alt=\"\" class=\"wp-image-56\" style=\"width:1021px;height:auto\" srcset=\"https:\/\/hackingwithj.com\/wp-content\/uploads\/2025\/04\/Schermafbeelding-2025-04-08-153748-1.png 1021w, https:\/\/hackingwithj.com\/wp-content\/uploads\/2025\/04\/Schermafbeelding-2025-04-08-153748-1-300x21.png 300w, https:\/\/hackingwithj.com\/wp-content\/uploads\/2025\/04\/Schermafbeelding-2025-04-08-153748-1-768x53.png 768w\" sizes=\"auto, (max-width: 1021px) 100vw, 1021px\" \/><figcaption class=\"wp-element-caption\"><em>Figure 3<\/em><\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"444\" src=\"https:\/\/hackingwithj.com\/wp-content\/uploads\/2025\/04\/Schermafbeelding-2025-04-08-153855-1024x444.png\" alt=\"\" class=\"wp-image-61\" srcset=\"https:\/\/hackingwithj.com\/wp-content\/uploads\/2025\/04\/Schermafbeelding-2025-04-08-153855-1024x444.png 1024w, https:\/\/hackingwithj.com\/wp-content\/uploads\/2025\/04\/Schermafbeelding-2025-04-08-153855-300x130.png 300w, https:\/\/hackingwithj.com\/wp-content\/uploads\/2025\/04\/Schermafbeelding-2025-04-08-153855-768x333.png 768w, https:\/\/hackingwithj.com\/wp-content\/uploads\/2025\/04\/Schermafbeelding-2025-04-08-153855-1536x667.png 1536w, https:\/\/hackingwithj.com\/wp-content\/uploads\/2025\/04\/Schermafbeelding-2025-04-08-153855.png 1615w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\"><em>Figure 4<\/em><\/figcaption><\/figure>\n\n\n\n<p>I downloaded several of them and checked the metadata. They were original quality. And yes, I compared them to legally downloaded versions\u2014no visible difference.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"336\" height=\"131\" src=\"https:\/\/hackingwithj.com\/wp-content\/uploads\/2025\/04\/Schermafbeelding-2025-04-13-152820.png\" alt=\"\" class=\"wp-image-64\" srcset=\"https:\/\/hackingwithj.com\/wp-content\/uploads\/2025\/04\/Schermafbeelding-2025-04-13-152820.png 336w, https:\/\/hackingwithj.com\/wp-content\/uploads\/2025\/04\/Schermafbeelding-2025-04-13-152820-300x117.png 300w\" sizes=\"auto, (max-width: 336px) 100vw, 336px\" \/><figcaption class=\"wp-element-caption\"><em>Figure 5<\/em><\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Is This Hacking?<\/h2>\n\n\n\n<p>Good question.<\/p>\n\n\n\n<p>I didn\u2019t brute-force any credentials, inject SQL, or exploit a server vulnerability. The files were already delivered to me, unprotected. The only thing \u201chidden\u201d was the watermark overlay in the frontend, and the lack of a proper download mechanism didn\u2019t stop the original images from being accessible. So in that sense, yes, this is a form of unauthorized access\u2014<strong>not through malicious action, but through poor design<\/strong>. To top it off, I also found hardcoded JavaScript functions that kept track of how many downloads a user had left\u2014on the frontend. That means this could easily be manipulated too.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The aftermath<\/h2>\n\n\n\n<p>After discovering this issue, I responsibly disclosed the vulnerability to the company and waited 30 days before writing this post. This isn&#8217;t meant to shame the developers\u2014it\u2019s a lesson on why frontend-only protection is never enough when dealing with paid digital content. Always assume the user can see, modify, or capture whatever is rendered in their browser.<\/p>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:100%\"><\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>In this post, I\u2019ll walk you through how I discovered a way to access original, high-resolution photos from a photoshoot\u2014photos you&#8217;re normally required to pay extra for. While this isn&#8217;t your typical \u201chack\u201d with terminal commands and fancy exploits, it does highlight a critical flaw in how some web apps handle access control. \u26a0\ufe0f Disclaimer: [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"site-container-style":"default","site-container-layout":"default","site-sidebar-layout":"default","disable-article-header":"default","disable-site-header":"default","disable-site-footer":"default","disable-content-area-spacing":"default","footnotes":""},"categories":[7],"tags":[],"class_list":["post-46","post","type-post","status-publish","format-standard","hentry","category-realworld"],"_links":{"self":[{"href":"https:\/\/hackingwithj.com\/index.php?rest_route=\/wp\/v2\/posts\/46","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/hackingwithj.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/hackingwithj.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/hackingwithj.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/hackingwithj.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=46"}],"version-history":[{"count":12,"href":"https:\/\/hackingwithj.com\/index.php?rest_route=\/wp\/v2\/posts\/46\/revisions"}],"predecessor-version":[{"id":72,"href":"https:\/\/hackingwithj.com\/index.php?rest_route=\/wp\/v2\/posts\/46\/revisions\/72"}],"wp:attachment":[{"href":"https:\/\/hackingwithj.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=46"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/hackingwithj.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=46"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/hackingwithj.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=46"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}