# IRIS CTF 2024 Write up - OSINT - All Challenges
Hi, I am vow. I participated IRIS CTF 2024 and played with Black Bauhinia.
I tried to make this write up as beginner friendly as possible so that everybody can follow and learn something.
Special thanks to harrier, hollow, TheHakkaman and th1k4n for solving the challenges with me.
---
## Part 1: What is, and how to OSINT?
OSINT is a new category added to IRIS CTF this year. So, what is OSINT?
:::info
### OSINT - Definition
Open-Source Intelligence (OSINT) is publicly available information appearing
in print or electronic form. This includes radio, television, newspapers, journals, the Internet, commercial databases, videos, graphics, and drawings.
:::
To simply put, most of the time, OSINT CTF challenges require you to search and gather information from publicly available sources in order complete the challenge.
Some common OSINT challenges include:
- Using a search engine to find information
- Gather information in images
- Geolocation
- And more...
So, how does one get better at OSINT?
### Google Harder.
![1](https://hackmd.io/_uploads/BJwBqCytT.jpg)
Now, let's dive into the challenges.
---
## Part 2: Czech Where? (401 Solves)
:::warning
Iris visited this cool shop a while back, but forgot where it was! What street is it on?
Hint! FYI: The flag is all lowercase and _ for spaces. Please remove all accent marks if there are any. Wrap your answer in `irisctf{}`.
:::
We are given an image, and are tasked to find the street name of where this image was captured.
This is a Geolocation OSINT challenge, and from the hint we can guess that the street name is likely to contain spaces and accent marks.
![2](https://hackmd.io/_uploads/BkBU50kYa.png)
If we read the title carefully, **Czech Where?** is obviously a hint for where the image was taken, **Czech Republic**. However, there are lots of streets in Czech Republic so we need to narrow down our scope.
The image itself doesn't really provide us with any clues except for the **N:20 address** top of the door.
Fortunately, Google offers a very useful feature called **"Search by Image"** that can help us. Basically, you could upload an image, and Google will show webpages that have similar images (Remember to change the scale to the whole image!).
![3](https://hackmd.io/_uploads/BJaLqC1Ya.jpg)
Looking at the results, the first returned image looks **very similar to our image**:
![4](https://hackmd.io/_uploads/ByGvq0yK6.jpg)
Visiting the webpage, we can see it is a travel blog of a **Japanese** person.
![5](https://hackmd.io/_uploads/By4wqCkFp.png)
If we scroll down the blog, we would see our image, but let's focus on the **text first**. Perhaps it may give us some clues as to where the image was taken at?
If we copy and paste some text into **[DeepL Translator](https://www.deepl.com/translator#ja/en/%E5%A4%8F%E6%97%85%E2%98%86%E3%83%81%E3%82%A7%E3%82%B3%E3%80%80%E9%BB%84%E9%87%91%E5%B0%8F%E8%B7%AF%EF%BC%A0%E3%83%97%E3%83%A9%E3%83%8F%E5%9F%8E%E2%91%A0%0A%E6%AC%A1%E3%81%AB%E3%82%84%E3%81%A3%E3%81%A6%E3%81%8D%E3%81%9F%E3%81%AE%E3%81%AF%E9%BB%84%E9%87%91%E5%B0%8F%E8%B7%AF%E3%80%82%0A%E3%83%97%E3%83%A9%E3%83%8F%E5%9F%8E%E5%86%85%E3%81%AB%E3%81%82%E3%82%8B%E7%B4%B0%E3%81%84%E5%B0%8F%E9%81%93%E3%81%AB%E6%98%94%E3%81%AA%E3%81%8C%E3%82%89%E3%81%AE%E5%AE%B6%E3%81%8C%E4%B8%A6%E3%82%93%E3%81%A7%E3%81%84%E3%82%8B%E3%80%82%0A%E3%81%A0%E3%81%84%E3%81%9F%E3%81%84%E3%81%9D%E3%81%93%E3%81%AF%E3%81%8A%E5%9C%9F%E7%94%A3%E5%B1%8B%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%A6%E3%81%84%E3%82%8B%E3%81%AE%E3%81%A7%E3%81%99%E3%81%8C%E3%80%81%E3%82%B3%E3%82%B3%E3%82%82%E3%83%81%E3%82%B1%E3%83%83%E3%83%88%E3%81%AB%E5%90%AB%E3%81%BE%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8B%E3%81%A8%E3%81%AF%E3%81%84%E3%81%88%E3%80%81%E3%81%8A%E9%87%91%E3%82%92%E6%89%95%E3%82%8F%E3%81%AA%E3%81%91%E3%82%8C%E3%81%B0%E5%85%A5%E3%82%8C%E3%81%AA%E3%81%84%E3%82%93%E3%81%A7%E3%81%99%E3%81%AD%EF%BD%9E%E3%80%82%0A%E6%98%94%E3%81%AE%E5%AE%B6%E3%80%85%E3%82%92%E8%A6%8B%E3%82%8B%E3%81%93%E3%81%A8%E3%81%8C%E3%81%A7%E3%81%8D%E3%82%8B%E3%81%A8%E3%81%84%E3%81%86%E6%84%8F%E5%91%B3%E3%81%A7%E3%81%AF%E3%80%81%E3%82%BF%E3%83%80%E3%81%A7%E3%81%AF%E5%85%A5%E3%82%89%E3%81%9B%E3%81%AA%E3%81%84%E3%81%A3%E3%81%A6%E3%81%93%E3%81%A8%E3%81%AA%E3%81%AE%E3%81%8B%E3%81%97%E3%82%89%E3%80%82)**, we get the following translation:
:::info
### Japanese
夏旅☆チェコ 黄金小路@プラハ城①
次にやってきたのは黄金小路。
プラハ城内にある細い小道に昔ながらの家が並んでいる。
だいたいそこはお土産屋になっているのですが、ココもチケットに含まれているとはいえ、お金を払わなければ入れないんですね~。
昔の家々を見ることができるという意味では、タダでは入らせないってことなのかしら。
============================================================
### English (US)
Summer Trip☆**Czech Republic Golden Alley at Prague Castle** (1)
Next came Golden Alley.
This is a narrow alley inside Prague Castle lined with old-fashioned houses.
That's usually where the souvenir shops are, but even though this place is included in the ticket, you have to pay to get in!
I wonder if they don't let you enter for free in the sense that you can see the old houses.
:::
Seems like it is mentioning a place called **"Golden Alley"**, that is located in **Czech Republic near Prague Castle**. If we Google these keywords, we get this:
![6](https://hackmd.io/_uploads/BkedcCyK6.png)
:::success
We now know that this image is likely to be taken in Czech Republic near Prague Castle, at a place called "**The Golden Lane**".
:::
Now, we can proceed to search for this place using **Google Maps Street View**.
:::info
For those who don't know, Google Maps has something called "Street View" which provides interactive panoramas from positions along many streets in the world, which gives you the experience of "walking in a street" within your computer.
:::
Typing "The Golden Lane" leads us to here:
![7](https://hackmd.io/_uploads/H1tuqRyFa.png)
Let's take a look using "Street View" (Just drag the "Orange Person" at the bottom right, and place it on the blue lines that appear!)
Looking around the streets, we see this building:
![8](https://hackmd.io/_uploads/Hki_qA1K6.jpg)
If we compare the 2 images, we can see that there are many similarites:
![9](https://hackmd.io/_uploads/SJpOcCyY6.jpg)
:::info
### Similarites
- Both buildings' address are "**N:20**".
- Both buildings have 2 windows, 1 big 1 small, and both have a whitish frame.
- Both buildings have a cobble bottom.
:::
At this point, we are quite confident that this is the building we are looking for.
Now, we just have to check the street name, modify it so it matches our flag format, and we would have our first flag!
![10](https://hackmd.io/_uploads/BkiF5A1ta.png)
:::spoiler Flag
`irisctf{zlata_ulicka_u_daliborky}`
:::
:::success
### Summary
**Google Image Search** is very useful for finding similar images on the web. Other good options include:
- **[SauceNAO](https://saucenao.com/)** (Good at finding art/drawing)
- **[ascii2d](https://ascii2d.net/)** (Good at Twitter image reverse)
- **[Yandex](https://yandex.com/images/)**
- **[IQDB](http://iqdb.org/)**
For geolocation challenges, **Google Street** View is often the go-to solution.
Language Barrier? **DeepL and Google Translate** are here to help.
:::
---
## Part 3: Away on Vacation (255 Solves)
:::warning
Iris and her assistant are away on vacation. She left an audio message explaining how to get in touch with her assistant. See what you can learn about the assistant.
Transcript: Hello, you’ve reached Iris Stein, head of the HR department! I’m currently away on vacation, please contact my assistant Michel. You can reach out to him at **michelangelocorning0490@gmail.com**. Have a good day and take care.
:::
This time, our goal is to learn more about the assistant of Iris Stein. Reading the transcript, we can learn a few facts:
:::info
- Michel has a gmail account.
- Michel's full name is likely "Michelangelo Corning" based on the gmail naming.
- Iris Stein is a head of a HR department.
:::
Given that we have an email address, why not try sending a message to it?
:::danger
Note: It is highly recommended to use a non-personal email address, for safety and privacy reasons.
:::
After sending an email to Michel, we received this reply:
![11](https://hackmd.io/_uploads/SkpAcRJt6.png)
:::info
Dear,
Thank you for the email, I'm currently away on vacation to celebrate New Years! If you would like a quicker response, feel free to reach out to **my social media**. I **mostly talk about birds** on it.
Have a great start to the year, and take care!
:::
From this reply, we learn something new, which is that **Michel has his own social media account and mostly talk about birds on it.** Let's try searching for it.
![12](https://hackmd.io/_uploads/S1VJiRJKp.png)
Hmm, it seems like searching for "**Michelangelo Corning**" or "**Michelangelo Corning Social Media**" or "**Michelangelo Corning [Insert Popular Social Media Platform Name Here]**" did not provide any relevant information.
Maybe trying a **different search engine** might yield better results?
There are many search engines in the world besides Google, here are a few other examples:
:::info
### Search Engines
- **[Bing](https://www.bing.com/)** (Search engine by Microsoft)
- **[DuckDuckGo](https://duckduckgo.com/)** (A search engine that focuses on Internet privacy)
- **[Baidu](https://www.baidu.com/)** (A popular Chinese search engine)
- **[Yahoo!](https://yahoo.com/)**
:::
Let's try using **DuckDuckGo**, repeating the same keywords and we get this:
![13](https://hackmd.io/_uploads/rycJoAkYp.png)
Let's check out this **[Instagram account](https://www.instagram.com/michelangelo_corning/)**:
![14](https://hackmd.io/_uploads/ry0JiRJYa.png)
Several important details stand out here:
:::info
- This account has a low amount of posts and followers, which is to be expected for an account that is made solely for the purpose for a CTF challenge.
- The posts of this account are made a few days prior to this event.
- The posts mainly talk about birds, just as Michel's email mentioned.
- The profile image of this account looks uncanny. (More on that in "Summary")
:::
This is probably the social media we are searching for, let's take a look at the posts! But, Instagram requires you to have an account in order to access the platform.
Nowadays, many websites require you to register an account to access their tools or platform, but sometimes we prefer not to sign up with our personal email accounts, either to avoid spam or for privacy reasons.
A solution to this problem would be to use a **"Disposable Email"**.
:::info
### Disposable Emails
Disposable emails are temporary email addresses which are deleted after a certain time period, and most can only receive emails. They take very little time to create and are easily disposable, which is good if you want to access online materials without releasing your contact information. A good recommendation would be **[TempMail](https://temp-mail.org/en/)**.
:::
For some larger platforms, they may have checks that prevent email addresses with unusual email domains from signing up. In that case, your only option would be to use your personal email, or to create a new email address with a commonly known email doamin like Gmail.
After creating an account, we can take a look at Michel's posts. If we take a closer look at the **images, descriptions and comments**, we would find something interesting:
![15](https://hackmd.io/_uploads/HkUxi0kta.jpg)
The flag is located in the description of this post!
:::spoiler Flag
`irisctf{pub1ic_4cc0unt5_4r3_51tt1ng_duck5}`
:::
:::success
### Summary
When searching for information, don't just read the **descriptions**, sometimes go through the **comments**! They might provide additional information.
People tend to use their **real names** for their **personal email address**, as it is easier for others to identify them and feels more professional.
There are many **search engines** in the world, each might yield different search results.
**Disposable emails** are handy, use them if you don't want to give out your personal information.
============================================================
### Additional Information - Uncanny Images
Usually when creating social media accounts for OSINT challenges, challenge authors most of the time won't use real people's faces. Therefore, these profile images are mostly like AI generated.
There is a website called **[**ThisPersonDoesNotExist**](https://thispersondoesnotexist.com/)**, which generates random human faces using AI. Since AI is not perfect, this explains why the profile pictures sometimes look a bit uncanny. (Their stares sometimes haunt me lol)
:::
---
## Part 4: Personal Breach (173 Solves)
:::warning
Security questions can be solved by reconnaissance. The weakest link in security could be the people around you.
Website: https://personal-breach-web.chal.irisc.tf/
:::
For this challenge, we are given a link to a website where we have to fill in some personal information related to Iris Stein. Here are the questions:
![16](https://hackmd.io/_uploads/rJ2ujR1ta.png)
:::info
- How old is Iris?
- What hospital was Iris born in?
- What company does Iris work for?
:::
Reading the description, the second sentences hints that for this challenge, we are going to have to look at other people's social media accounts or websites in order to gain more information about Iris Stein.
Since we already have Michel's Instagram account, let's take a look at who Michel is following:
![17](https://hackmd.io/_uploads/HymFjAyFT.png)
We see that Michel is following Iris Stein, how about let's take a look at [Iris Stein's Instagram account](https://www.instagram.com/irisstein_station/)?
![18](https://hackmd.io/_uploads/SyHtj0yYp.jpg)
Taking look at Iris Stein's followers, it seems she is mainly following other companies' social media accounts (with the exception of Michel), so it is unlikely we can find any more useful information here.
Again, let's go through Iris' posts and see what we can find!
:::info
### Exercise: Go through Iris Stein's posts and see what you can discover.
:::spoiler **Solution**
Reading the posts, we can learn a few facts:
- Iris loves to travel.
- Iris also likes Mimosas and Tiramisu.
But the more useful information for this task would be:
- Her mother is named **"Elaina Stein"**, and is born in April.
- Her mother **does not have an Instagram account**.
![19](https://hackmd.io/_uploads/ByfcjAyYT.jpg)
Remember the description? **"The weakest link in security could be the people around you."** Maybe we can find more information in her mother's social media account.
:::
After completing the exercise (or checking the answers), you should know what to look for. Using different search engines, an interesting result popped up when I searched the key words using **DuckDuckGo**, and upon clicking **[the result](https://www.facebook.com/people/Elaina-Stein/61555040318052/)**, we arrive here:
![20](https://hackmd.io/_uploads/H1AioCyYT.png)
:::info
Let's do a check:
- [x] Low amount of posts.
- [x] Most posts made recently.
- [x] Uncanny profile image.
:::
This does seem like the account we should be looking for.
Taking a deeper look, we see that there is a section called "Life Events":
![21](https://hackmd.io/_uploads/S1E2i01FT.png)
And it seems like it has Elaina and Iris' birthdays! Let's take a look at Iris' birthday:
![22](https://hackmd.io/_uploads/r1d2iC1Ka.png)
At this point, we know **Iris' birth date**, which allows us to determine Iris' age. We also got an **image** and a **hint** to where Iris was born.
:::info
### Exercise: Determine where Iris was born.
:::spoiler **Solution**
**Google Image Search** is here to save the day!
Using the image of the hospital room for a reverse search gives us the following queries:
![23](https://hackmd.io/_uploads/H1C3s0kY6.jpg)
It is easy to see that the first query is exactly the same as our image. Therefore, we can conclude that Iris was born in **Lenox Hill Hospital**.
:::
We now have two pieces of information to fill in the form, but we are still missing the last piece of the puzzle - **"What company does Iris work for?"**
Not much more information can be found within the social media accounts and posts, so let's go back to the drawing board. Since it is asking something related to work, we can try searching in one of the biggest business networking platforms - **[LinkedIn](https://www.linkedin.com/)**.
After signing up an account for LinkedIn and searching for "Iris Stein", we are met with an overwhelming amount of results:
![24](https://hackmd.io/_uploads/BJS6sRJYa.png)
How can we find the correct account? We have some clues in hand:
:::info
- Iris Stein is a **head of a HR department**. (Away on Vacation)
- We have some **images** of how Iris Stein looks like. (Instagram Account)
![25](https://hackmd.io/_uploads/ByhTiAkt6.jpg)
:::
Looking back at LinkedIn, **[there does exist an account](https://www.linkedin.com/in/iris-stein-57894b2a7/)** that looks very similar to the images above:
![26](https://hackmd.io/_uploads/HJ7AsA1Yp.png)
In fact, this account has the exact image as the first image above, just with different color grading and without the heart emojis. We can also see that this Iris Stein in LinkedIn is also a HR of a company.
At this point we can pretty much confirm that this LinkedIn account belongs to the same Iris Stein we are searching for, and we can conclude that Iris Stein works for **Mountain Peak Hiring Agency**.
:::info
### Answers for the website
:::spoiler
- How old is Iris? ---> $2024-1996-1 = 27$
- What hospital was Iris born in? ---> **Lenox Hill Hospital**
- What company does Iris work for? ---> **Mountain Peak Hiring Agency**
:::
Now, we just have to submit the answers and get our flag!
:::spoiler Flag
`irisctf{s0c1al_m3d1a_1s_an_1nf3cti0n}`
:::
:::success
### Summary
Some people may have **more than one social media** account, keep searching at different platforms.
Don't just focus on the person you are searching, pay some attention to the **people close them**.
:::
---
## Part 5: A Harsh Reality of Passwords (28 Solves)
:::warning
Recently, Iris's company had a breach. Her password's hash has been exposed. This challenge is focused on understanding Iris as a person.
Hash: `$2b$04$DkQOnBXHNLw2cnsmSEdM0uyN3NHLUb9I5IIUF3akpLwoy7dlhgyEC`
The flag format is `irisctf{plaintextPassword}`
Hints:
- Focus on Iris and what she finds important!
- There are three words (not letters, but words), and a certain amount of numbers following it.
- There's no leet words, proper capitalization nothing like (ExAmPLE), no special characters as well like -,! etc.
- Please, don't spend time looking for database breaches.
============================================================
### IMPORTANT
The write up author used Python, a programming language, to solve this challenge. This write up will assume that the reader has basic knowledge in using Python.
If you want to learn Python from scratch, I would recommend these 2 sites:
- [Python Tutorial](https://www.pythontutorial.net/)
- [W3Schools](https://www.w3schools.com/python/)
But most importantly, try coding something yourself. Experience is the best teacher. 😀
:::
Before attempting this challenge, we need to understand what is a "Hash".
:::info
### Hash Function - Definition
A hash function is any function that can be used to map data of arbitrary size to fixed-size values. The values returned by a hash function are called hashes. Hashing is mainly used for data validation purposes.
Hash functions are commonly used as an effective cryptographic tool because of the following properties:
- It has a **fixed length output**. (All hashes are equally long in characters.)
- It is very **efficient**.
- It is computationally **hard to reverse** a hash function. (You can't get the password easily by just having the hash.)
- It is very hard to find two different inputs of any length that result in the same hash. (**Collision-resistant**.)
In short, hashing is a secure data validation method. It is not meant to be decrypted (most of the time).
:::
That is the very basic idea of hashing. So our goal is to find a password that matches the hash, which would then be our flag. But first, we need to know what type of hash function is used for this hash, as there are many types of hash functions.
Throwing the hash into **[Hash Analyzer](https://www.tunnelsup.com/hash-analyzer/)**, we learn that the hash is made with a hash function called **bcrypt**.
So the main question remains: **How do we find the password?**
Based on the hints, we can have a rough idea of how the password looks like:
:::info
- It consists of 3 words and some numbers behind it.
- The words and numbers should be important to Iris.
- No leet words or special characters.
:::
Since this is an **OSINT** challenge (not a cypto challenge), we can guess that the password should be composed of words and numbers that were mentioned, or related to the theme of the posts.
Let's start off with numbers. It is very common to add numbers to password as it would make the password more secure, however most people would use **numbers that have special meaning** to them, perhaps **the date of an anniversary, a birthday**, etc.
If we recall the post where we found Iris' mother's name, there is something **important** written there:
![27](https://hackmd.io/_uploads/Byfgn0yY6.jpg)
It seems that Iris mother's birthday is important to Iris, and it is common knowledge that dates are represented using numbers. Checking back the Facebook page:
![28](https://hackmd.io/_uploads/HJ4g30JtT.png)
:::warning
We see that Elaina Stein was born in **[9th April, 1965](https://www.facebook.com/profile.php?id=61555040318052)**, however when we click into the life event, we can see that Elaina was in fact born in **[8th April, 1965](https://www.facebook.com/permalink.php?story_fbid=pfbid0331vL6wHVsnTuofLDzbBWzMaMXCxdbwNuSSSjMuBjWgdtQfuLXGdgoLH3aMd38Cq5l&id=61555040318052)**.
The correct date should be **8th April, 1965**.
We will remember this for now.
:::
Now, here comes the big question: **What should the 3 words in the password be?**
Unfortunately, there is no method to directly determine the words, therefore our only way is to **brute force** the password using a custom password list, which will be generated using Python.
---
The first step would be to get a list of potential keywords that might be in the password. Usually the keywords would be **something of importance** like locations, food, items, etc, and usually not words like pronouns, adjectives, etc.
:::info
### Wordlist
Here is **[my wordlist](https://pastebin.com/DGVD5w2A)** consisting of words that I think are important to Iris.
Below is a slight explaination for why I chose each word:
[**Elaina**](https://www.instagram.com/p/C1qwh0Cuj5P/) - Her mother's name, said her birthday was important
[**Stein**](https://www.instagram.com/p/C1qwh0Cuj5P/) - Same as above
[**Mom**](https://www.instagram.com/p/C1qwh0Cuj5P/) - Same as above
[**Michel**](https://www.instagram.com/michelangelo_corning/) - Iris' assistant (Away on Vacation)
[**Czech**](https://www.instagram.com/p/C1l124HAH2i/) - Where she got the lamp (Czech Where?)
[**Prague**](https://www.instagram.com/p/C1l124HAH2i/) - Same as above
[**Amsterdam**](https://www.instagram.com/p/C1rBMQFu-VC/) - Mentioned in post
[**Swarovski**](https://www.instagram.com/p/C1rAzn2OZUL/?img_index=1) - Said she love Swarovski sculptures
[**Sculptures**](https://www.instagram.com/p/C1rAzn2OZUL/?img_index=1) - Same as above
[**Swans/Swan**](https://www.instagram.com/p/C1rAZJvO4p-/?img_index=1) - Said that they were adorable
[**Portofino**](https://www.instagram.com/p/C1qxxSwu7qD/) - Said it is a destination that she will always remember
[**Italy**](https://www.instagram.com/p/C1UZCAnrEc8/?img_index=1) - Portofino is in Italy, also appeared in hashtag
[**Netherland**](https://www.instagram.com/p/C1UZCAnrEc8/?img_index=1) - Appeared in hashtag
[**Berlin**](https://www.instagram.com/p/C1UZCAnrEc8/?img_index=1) - Appeared in hashtag
[**Mimosas**](https://www.instagram.com/p/C1qwh0Cuj5P/) - Said it was one of her favourite drinks
[**Tiramisu**](https://www.instagram.com/p/C1WM6L2uuom/?img_index=1) - Had a whole post talking about Tiramisu
[**Milan**](https://www.instagram.com/p/C1WM6L2uuom/?img_index=1) - A place she tried Tiramisu
[**Conte**](https://www.instagram.com/p/C1WM6L2uuom/?img_index=1) - Same as above
[**Ugolino**](https://www.instagram.com/p/C1WM6L2uuom/?img_index=1) - Same as above
[**Starbucks**](https://www.instagram.com/p/C1WM6L2uuom/?img_index=1) - Same as above
[**Lenox**](https://www.facebook.com/permalink.php?story_fbid=pfbid02poh2shGe3UT5qnN3d3NMUC4pTh1JngrFvqXqaXkCtZHH284KjZKZJ5iZDVVkmqgCl&id=61555040318052) - Iris' birth place (Personal Breach)
[**Hill**](https://www.facebook.com/permalink.php?story_fbid=pfbid02poh2shGe3UT5qnN3d3NMUC4pTh1JngrFvqXqaXkCtZHH284KjZKZJ5iZDVVkmqgCl&id=61555040318052) - Same as above
[**Food**](https://www.instagram.com/p/C1WM6L2uuom/?img_index=1) - Iris seems to like food and beverages?
[**Travel**](https://www.instagram.com/p/C1WLNZeuA4p/) - Profile description, said she likes to travel
[**Traveling**](https://www.instagram.com/p/C1WLNZeuA4p/) - Same as above
[**Europe**](https://www.instagram.com/p/C1WLNZeuA4p/) - Posts are mainly about places in Europe
:::
:::danger
### Warning
Note that my code and wordlist **may not be very optimized**, therefore the run time of my Python code **may be slightly long**.
Please also note that since my wordlist may be different from yours, my code **may or may not work for your wordlist**.
It is **highly not recommended** to use every word from all the Instagram post.
Still, here is a **[wordlist](https://pastebin.com/sjKUhsqW)** that contains **all words from Iris' Instagram** (contains duplicates).
:::
Now that we have our wordlist, let's do some data processing. The first goal would be to split every word into it's own unique string, remove all unnesscary newline or space characters, and put all the words into a list:
```python=
# Explaination:
# We first open the wordlist.txt file, and give it a name "file".
#
# Then for every line in the file, we split it into strings
# based on where a space exists. ("Hello World" --> ["Hello", "World"])
# Next, for every word in "line_with_many_words" (split() returns a list),
# we remove any newline characters or spaces using rstrip()
# and proceed to add the word into "word_list"
word_list = []
with open('COMPUTER_PATH_TO_YOUR_WORDLIST_TXT_FILE', "r") as file:
for line in file:
line_with_many_words = line.split(" ")
for word in line_with_many_words:
word_list.append(word.rstrip())
```
We now have a list of words, but we want a list with all words starting with capital letters only (All words have **proper capitalization**). Again, we can accomplish this with a little bit of Python:
```python=
# Explaination:
# Similar to above, we use a for-loop to get each word,
# then convert the first character into uppercase,
# then add the word to "processed_word_list" respectively.
processed_word_list = []
for word in word_list:
processed_word_list.append(word.title()) #Makes first character uppercase
```
:::info
### Tips - How to handle duplicates quickly (If there are any)
One neat trick to remove the repeated strings is to first convert the list into a set, then convert it back to a list. (This works because Python sets do not allow duplicates, so it removes them.)
```python=
# Remove duplicates using the "list-set" trick.
processed_word_list = list(set(processed_word_list ))
```
:::
Now here comes the fun part, we are going to use a built-in Python module called **"itertools"** to help us generate different password combinations. Itertools is very useful when you need to generate permutations and combinations with elements, it is also much faster and memory efficient when compared to using loops.
Our goal would be to select 3 words in order to form a password, and the 3 words can be in any order without repeats.
:::info
### Exercise: How many permutations can we form with the letters A, B, C?
:::spoiler **Solution**
{A,B,C}, {B,A,C}, {C,A,B}, {A,C,B}, {B,C,A}, {C,B,A}
:::
Now, let's implement this idea in Python, and using our wordlist as our set of elements:
```python=
# Explaination:
# We create permutations using the words we pre-processed,
# and put them in a list.
# The list should look something like this:
# [('Milan', 'Tiramisu', 'Stein'), ('Tiramisu', 'Swarovski', 'Amsterdam')...]
# Note that we only have a list of tuples for now, therefore we need to combine
# the strings in the tuples together.
# Using a for-loop, we go through each tuple, join the elements together,
# and put them in a new list called "password_strings".
from itertools import permutations
password_strings = []
for group in list(permutations(processed_word_list , 3)):
password_strings.append(''.join(group))
```
Now, we have a list containing all permutations of our word list!
But wait, we remember that we still have **a number (date)** to consider.
:::info
### Exercise: Can you generate all permutations of the date?
:::spoiler **Solution**
Recall that Iris’ mother was born in **8th April, 1965**, so our date list should look something like this:
```python=
numbers = ["8", "08", "4", "04", "1965"]
date_strings = []
for group in list(permutations(numbers, 3)):
date_strings.append(''.join(group))
```
This leaves us with 60 different dates (**we will be using this**), which is good enough, however we know that there are some dates that won't be in the password (such as "8084", "04808").
If you would like to further reduce the number of possible dates, we can modify our code into this:
```python=
# Explaination:
# We create 4 tuples:
# ('8', '4', '1985') ('8', '04', '1985')
# ('08', '4', '1985') ('08', '04', '1985')
# Then we create permutations using each of these 4 tuples,
# join the strings with "+", and append it to "date_strings".
from itertools import permutations, product
day = ["8", "08"]
month = ["4", "04"]
year = ["1985"]
date_strings = []
for pair in product(day,month,year):
for a,b,c in permutations(pair,3):
date_strings.append((day+month+year))
```
Which leaves us with just 24 possible combinations.
:::
Now, we have a list of words and a list of dates, we just need to join them together, save it to a text file, and we would have our password list!
```python=
# Explaination:
# We open up your password.txt file first
# (if the file does not exist, Python will automatically create one for you),
# Then for every word, we add all the possible dates behind it,
# along with a newline character (this is the same as pressing enter)
# and append it to the text file.
with open('COMPUTER_PATH_TO_YOUR_PASSWORD_TXT_FILE', "a") as file:
for date in date_strings:
for word in password_strings:
file.write((word+date) + "\n")
```
Now that we have our password list, it's time for the last step: Finding which password is the correct one.
There are two ways to do this, one is to use a password cracking tool called "**[Hashcat](https://hashcat.net/hashcat/)**" (probably the fastest method), the other is to use the **"bcrypt"** module in Python. Note that you have to install the module using **pip**.
### Hashcat Method (Highly recommended):
Prepare two textfiles, one would be your password list, and the other would be your hash list.
In this case the hash.txt should only contain:
**`$2b$04$DkQOnBXHNLw2cnsmSEdM0uyN3NHLUb9I5IIUF3akpLwoy7dlhgyEC`**
Now, once you have installed hashcat, you can execute the following command (**Linux**):
`$ hashcat -m 3200 -a 0 password.txt hash.txt`
The arguments `-m` and `-a` means the hashing function and attack method respectively.
[**`-m 3200`**](https://hashcat.net/wiki/doku.php?id=example_hashes) is bcrypt hash function, and [**`-a 0`**](https://hashcat.net/wiki/#core_attack_modes) is called "Dictionary attack" (basically means going through all the passwords in a text file to see which passwords match).
Once hashcat finds the password, the output would look like this:
**`$2b$04$DkQOnBXHNLw2cnsmSEdM0uyN3NHLUb9I5IIUF3akpLwoy7dlhgyEC:REDACTED_FOR_NOW`**
### Python Method:
The "bcrypt" module has a function called `checkpw()`, which checks whether a password is equal to a hash and returns a boolean value.
We can then brute force the password with the following code:
```python=
# Explaination:
# We open up your password list, remove the newline characters with rstrip(),
# convert the passwords into bytes (utf-8),
# and then compare the passwords with the hash.
# If it returns "True", that means we found the
# correct password, print it out, then stop.
# If it returns "False", that means we need to keep trying.
from bcrypt import checkpw
hash_goal = b"$2b$04$DkQOnBXHNLw2cnsmSEdM0uyN3NHLUb9I5IIUF3akpLwoy7dlhgyEC"
with open('COMPUTER_PATH_TO_YOUR_PASSWORD_TXT_FILE', "r", encoding='utf8') as file:
for password in file:
if (checkpw(bytes(password.rstrip(), "utf-8"), hash_goal) == True):
print("The password is: " + password)
break
else:
continue
```
Before showing the flag, let's see some statistics for password generation and hash cracking time:
:::info
### Statistics - Why data preprocessing is important
Using my wordlist (27 words, all starting with capital letters and 60 possible date combinations), we get **1053000** different password combinations.
(**Roughly 1.0 million combinations**)
It took:
- Hashcat: **454** seconds
- Python: **885** seconds
If the wordlist can have words that are completely lowercase (56 words, 60 possible date combinations), we would get **8929440** combinations.
(**Roughly 8.9 million combinations!**)
If we include **every single unique word** from Iris' Instagram posts, all starting with capital letters, the same 60 date combinations, we would get **749216160** combinations.
(**Roughly 749.2 million combinations!!**)
Now add lowercase words to the mix, and we have a grand total of **6032649600** combinations.
(**Roughly 6.0 billion combinations!!!**)
============================================================
As we can see, if we did not choose our wordlist for our password generation wisely, we would have waited for quite a long time (It would take about a month for the last case 💀).
:::
Now, here is the final code and the flag!
:::spoiler **Flag and Code**
```python=
from itertools import permutations
from bcrypt import checkpw
# Permutations of words.
word_list = []
processed_word_list = []
password_strings = []
with open('COMPUTER_PATH_TO_YOUR_WORDLIST_TXT_FILE', "r") as f:
for line in f:
line_with_many_words = line.rstrip().split(" ")
for word in line_with_many_words:
word_list.append(word.rstrip())
for word in word_list:
processed_word_list.append(word.title())
processed_word_list = list(set(processed_word_list))
for group in list(permutations(processed_word_list , 3)):
password_strings.append(''.join(group))
# ============================================================
# Permutations of date.
numbers = ["8", "08", "4", "04", "1965"]
date_strings = []
for group in list(permutations(numbers, 3)):
date_strings.append(''.join(group))
# ============================================================
# Generating password list by listing all combinations
# of password_strings and date, then exporting it to a file.
with open('COMPUTER_PATH_TO_YOUR_PASSWORD_TXT_FILE', "a") as file:
for date in date_strings:
for word in password_strings:
file.write((word+date) + "\n")
# ============================================================
# Hash brute forcing. (Slow)
flag = 0
hash_goal = b"$2b$04$DkQOnBXHNLw2cnsmSEdM0uyN3NHLUb9I5IIUF3akpLwoy7dlhgyEC"
print("Brute forcing hash...")
with open('COMPUTER_PATH_TO_YOUR_PASSWORD_TXT_FILE', "r") as file:
for password in file:
if (checkpw(bytes(password.rstrip(), "utf-8"), hash_goal) == True):
print("Found!")
print(password)
flag = 1
break
else:
continue
if (flag == 0):
print("Not found :(")
```
`irisctf{PortofinoItalyTiramisu0481965}`
:::
:::success
### Summary
People tend to use **words that are important to them** for their passwords, as it is much easier to memorize.
**Data preprocessing** is very important.
============================================================
:::
And that's it! I hope you learned something from this write up!