20250321 ‐ Browser Forensics - rundas-r00t/blog GitHub Wiki
given a browser.sqlite file, answer the following questions:
- What did the user search for on craigslist?
- What was the current price of bitcoin when the user was browsing?
- What Bitcoin exchange did the user log in to?
- What is the email that was used to log into the exchange?
- What was the ID of the Bitcoin transaction that the user looked at?
- What was the total BTC of all the inputs of the Bitcoin transaction?
- Which bitcoin address received the majority of the Bitcoin in the transaction?
before getting too deep into sqlite3, lets see if we can strings | grep and answer some of these questions. First, let's try:
Click to reveal
strings browser.sqlite|grep 'craigslist'

with a keen eye, we see the &query=bitcoin part of the URL in the 2nd line and in the 6th from the bottom. to confirm, let's redo our grep statement:
strings browser.sqlite|grep 'craigslist|grep 'query'

looks good.
for the second question, let's continue our grepping skills, this time using a strings|grep|grep combo again.
Click to reveal
strings browser.sqlite|grep 'bitcoin'|grep '\$' --being sure to escape the $ with a \.

there we go!
For the 3rd question, let's just look at all the https entries and see what we can see:
Click to reveal
strings browser.sqlite|grep 'https'

Coinbase is a fairly large crypto-exchange, and we can tell by the .com/accounts/528cf016.... web address that the user logged in and viewed his/her wallet.
we're doing great so far, and haven't even needed sqlite3 just yet. amazing!
looking further through our current results, we see some hits for mail.google.com, so let's grep for gmail.com and see what we get:
Click to reveal
strings browser.sqlite|grep 'https'|grep 'gmail'

ok looks good.
keeping this trend going, let's answer the next question by grep 'transaction':
Click to reveal
strings browser.sqlite|grep 'transactions'

Nice.
for the next question, let's finally utilize sqlite3 and start poking around some tables.
Click to reveal
sqlite3 browser.sqlite
sqlite> .tables
sqlite> select * from moz_inputhistory;
sqlite> select * from moz_historyvisits;

not exactly sure what i'm looking at here... let's amke this a little more legible:
sqlite> .headers ON
sqlite> .mode column
sqlite> select * from moz_historyvisits;

that looks better. now we can see that the long string of numbers in indeed Epoch Time. we also see headings for place_id. With ChatGPT's help, let's try a JOIN and see if we can match the place_id with a URL, say craigslist.org:

sqlite> SELECT moz_places.url, datetime(moz_historyvisits.visit_date / 1000000, 'unixepoch') AS visit_time FROM moz_places JOIN moz_historyvisits ON moz_places.id = moz_historyvisits.place_id WHERE moz_places.url LIKE '%craigslist.org%' ORDER BY visit_time DESC LIMIT 10;
what exactly is this command doing? we are selecting columns moz_places.url and moz_hostiryvisits.visit_date, while also converting Epoch time to a typical date stamp and renaming the visit_date column to visit_time. then we're cross-referencing table moz_historyvisits with moz_places where the id matches, and where the URL is similar to craigslist.org, and let's order it newest first. results should look like:

sweet! we now know when the user visited some variation of craigslist.org. unfortunately, this doesn't really help us answer Question 6. but it is nice to see that we're able to navigate some tables and get the output we need. Since i'm not sure at all how to answer Question 6, i utilized ChatGPT with quite a few prompts to eventually produce a script that would dump all the information from all the tables to the screen.
sqlite3 browser.sqlite < megadump.sql

scrolling further down the results, we see our Epoch Time again:

in a real-life scenario, i would look for transaction URL's similar to this:
sqlite3 browser.sqlite < megadump.sql | grep '/tx/'

Unfortunately, the transaction doesn't actually exist:

Feeling pretty stuck on this, i had to turn to the guide, which references a really awesome website https://inloop.github.io/sqlite-viewer/ .

let's upload our database to it and see if we can finally answer Question 6.

checking each table in the dropdown menu produces familiar data:

again, i'm not seeing anything new, so back to the guide, which just so happens to reference the URL that we tried earlier which we thought was invalid. i guess i made a typo or didn't clean it up properly to trying it. but i tried all 3 URLs that show up using this command:
sqlite3 browser.sqlite < megadump.sql | grep '/tx/'

using notepad to clean them up b/c i'm slightly irked by this whole thing now lol:

and loading anyone of these into a web browser produces a page like this:
Click to reveal

so basically on this screen we see "2 inputs". scrolling down, we see that this matches to the "From" category:

adding these numbers up produces the correct answer.
phew! man Question 6 was a wild ride! but now that we got through it, Question 7 will be a breeze!
all we need to do is look at the "To:" column and copy/paste the correct address into the answer field.
Click to reveal

SQLite Forensics? Done!