Forensics
listening?
- Challenge description
Got a pcpa file (challenge.pcap)
By Wireshark, I opened the pcap file and found it was about 9 seconds record of the packets
I mainly focused on HTTP Stream, so I filtered “http” in Wireshark and found something interesting.
Because of the form items I observed (shown as the image below), It made a
POST
request tooauth2.googleapis.com/token
. I guessed it made a API call before, so I recreated the payload from the pcap, and tried to make the same API call again.
Made a google API call
Payload
1
curl -X POST https://oauth2.googleapis.com/token -d "client_secret=AER8VvrXuFfYfqjhidcekAM0&grant_type=refresh_token&refresh_token=1//044y6gZR87Kl0CgYIARAAGAQSNwF-L9IrkAFpIJPMhiGY0OPJpo5RiA5_7R-mHH-kuHwCMUeFL2JqxevGr23oBJmaxdnrD52t3X4&client_id=1097638694557-3v745luessc34bkoiqkf8tndqgvbqjpm.apps.googleusercontent.com"
Got an access token json. Besides, I found this access token was for reading gmail’s messages only.
1
2
3
4
5
6{
"access_token": "ya29.a0ARrdaM9yn8BOV1WE517K_qMViaktMBVtkz3y19-hdqllimqBrXhgXmyhpPDFzAq8N42YBLjuwCLebbj78RWZCL02Pve_gfEabr_e5FFDo1BoXrNWgHj5dVIAn-lglixXue6XFc9nWsO4zRcJTTKxm39SkxxVFw",
"expires_in": 3599,
"scope": "https://www.googleapis.com/auth/gmail.readonly",
"token_type": "Bearer"
}Created token.json to store credentials
1
2
3
4
5
6
7
8
9
10{
"client_secret": "AER8VvrXuFfYfqjhidcekAM0",
"grant_type": "refresh_token",
"refresh_token": "1//044y6gZR87Kl0CgYIARAAGAQSNwF-L9IrkAFpIJPMhiGY0OPJpo5RiA5_7R-mHH-kuHwCMUeFL2JqxevGr23oBJmaxdnrD52t3X4",
"client_id": "1097638694557-3v745luessc34bkoiqkf8tndqgvbqjpm.apps.googleusercontent.com",
"access_token": "ya29.a0ARrdaM9yn8BOV1WE517K_qMViaktMBVtkz3y19-hdqllimqBrXhgXmyhpPDFzAq8N42YBLjuwCLebbj78RWZCL02Pve_gfEabr_e5FFDo1BoXrNWgHj5dVIAn-lglixXue6XFc9nWsO4zRcJTTKxm39SkxxVFw",
"expires_in": 3599,
"scope": "https://www.googleapis.com/auth/gmail.readonly",
"token_type": "Bearer"
}Interactive with Google gmail API
I run the Python script on colab, the script is shown as following block.
It simply provided the credentials to google authentication api’s to get the privilege to read someone’s gmail messages.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87from __future__ import print_function
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
import os.path
import base64
import email
from bs4 import BeautifulSoup
# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/gmail.readonly']
def main():
"""Shows basic usage of the Gmail API.
Lists the user's Gmail labels.
"""
creds = None
# The file token.json stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
if os.path.exists('token.json'):
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'credentials.json', SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open('token.json', 'w') as token:
token.write(creds.to_json())
service = build('gmail', 'v1', credentials=creds)
# Call the Gmail API
result = service.users().messages().list(userId='me').execute()
# We can also pass maxResults to get any number of emails. Like this:
# result = service.users().messages().list(maxResults=200, userId='me').execute()
messages = result.get('messages')
# messages is a list of dictionaries where each dictionary contains a message id.
# iterate through all the messages
for msg in messages:
# Get the message from its id
txt = service.users().messages().get(userId='me', id=msg['id']).execute()
# Use try-except to avoid any Errors
try:
# Get value of 'payload' from dictionary 'txt'
payload = txt['payload']
headers = payload['headers']
# Look for Subject and Sender Email in the headers
for d in headers:
if d['name'] == 'Subject':
subject = d['value']
if d['name'] == 'From':
sender = d['value']
# The Body of the message is in Encrypted format. So, we have to decode it.
# Get the data and decode it with base 64 decoder.
parts = payload.get('parts')[0]
data = parts['body']['data']
data = data.replace("-","+").replace("_","/")
decoded_data = base64.b64decode(data)
# Now, the data obtained is in lxml. So, we will parse
# it with BeautifulSoup library
soup = BeautifulSoup(decoded_data , "lxml")
body = soup.body()
# Printing the subject, sender's email and message
print("Subject: ", subject)
print("From: ", sender)
print("Message: ", body)
print('\n')
except:
pass
if __name__ == '__main__':
main()Results
Dump all the mail message (There are about 4000 lines of messages, so I filtered some of them, shown as section below)
From the message below, we can obtain the flag:FwordCTF{email_forensics_is_interesting_73489nn7n4891}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32Subject: fwordplayground@gmail.com
From: Anonymousemail <noreply@anonymousemail.me>
Message: [<p>fwordplayground@gmail.com fwordplayground@gmail.com fwordplayground@gmail.com fwordplayground@gmail.com fwordplayground@gmail.com
</p>]
Subject: fwordplayground@gmail.com
From: Anonymousemail <noreply@anonymousemail.me>
Message: [<p>Hello everyone
</p>]
Subject: 1
From: Anonymousemail <noreply@anonymousemail.me>
Message: [<p>Hello everyone, Thank you for playing Fword CTF
</p>]
Subject: Flag
From: Fword Team <fword.team@gmail.com>
Message: [<p>FwordCTF{email_forensics_is_interesting_73489nn7n4891}
</p>]
Subject: Finish setting up your new Google Account
From: Google Community Team <googlecommunityteam-noreply@google.com>
Message: [<p>Let's get started,
Welcome to Google. Your new account comes with access to Google products,
apps, and services.
Here are a few tips to get you started.
CTF results
Place and points
- We registerd as the ToInfinityAndBeYANd, and got 1356 points resulted in 98 th in the ctf.
Categories
- We solved four challenges: one Welcome, one Cryptography, one bash, and one Forensics challenge.
Members - I am @x0mg
- I solved the Froensics challenge, although I put a lot of time in osint and reverse engineering but had no good outcome.
Score over time