Wednesday, April 17, 2013

Log2Timeline - mft.pm

When I analyze a case, I always think that i want to see filename times.

So I modified mft.pm in log2timeline lib.

This is MFT.pm including filename times.

If you use log2timeline, It will support you when you analyze malware that times were changed.


Link : https://dorumugs-tools.googlecode.com/files/mft.pm


Monday, April 15, 2013

Carving - PCAP in Memory (NAFT)

I searched a tool to carve pcap in memory.

This tool is NAFT(The Network Appliance Forensic Toolkit). Download link is below.

Link : http://blog.didierstevens.com/programs/network-appliance-forensic-toolkit/


I introduce the way to carve pcap in memory.

(1) PCAP Structure





(2) Global Header & Packet Header








[RED]
Type           Description Value
DWORD MagicNumber 0xD4C3B2A1                                                      
WORD Major Version Number 0x0200
WORD Minor Version Number 0x0400
DWORD GMT to Local Correction 0x00000000
DWORD Accuracy of Timestamps 0x00000000
DWORD Max Length of Captured Packets 0xFFFF0000
DWORD Data Link Type 0x01000000

[Blue]
Type        Description          Value
DWORD MagicNumber                     1355707892 == 50CE75F4 == 0xF475CE50
DWORD Major Version Number 616446 == 967FE == 0xFE670900
DWORD Minor Version Number capture Length 92 => 0x5C
DWORD GMT to Local Correction Frame Length 92 => 0x5C

Just a trick. Time is made from file offset.

Example : Offset 7398799
          7 is timestamp seconds.
          398799 is timestamp microseconds.


(3) Searching ARP

Searching magic like "0x08 0x06 0x00 0x01 0x08 0x00 0x06 0x04"
(The offset of magic) - 12 == The Start of APR
(The offset of magic) + 30 == The end of APR
The total length of ARP == 42(0x2A)

From : The start of ARP to end of the ARP
ARP Offset : (The offset of baseAddress) + (The offset of magic) - 2*6
ARP DATA Offset : (The offset of magic) - 2*6 ~ (The offset of magic) + 30


(4) Searching IP
Search for bytes between 0x45 and 0x4F(depending flag options)
And than check if they are the start of a IPv4 header by calculating.
The value after calculating is compared with the checksum.
      potentialIPHeader : 69 ~ 69 + 4 * (69-64) => 69 ~ 89

If checksum is verified, Calculate Packet length.










#################################################################################
baseAddress                   :   0
offset(==index)               :   77008910
potential IP Header         :   4500004e0a85000080119bc8c0a88901c0a889ff
potentialIPHeader[2]      :   00
potentialIPHeader[3]      :   4e

ord(potentialIPHeader[2]) * 0x100 + ord(potentialIPHeader[3])
     0 * 0x100 + 78
packetLength                  :   78

Second                            :   0x4d
Microecond                     :   0x22ce
Packet saved in file        :   0x5c
Actual length of packet  :   0x5c

DATA                           : 
(77008896, '\xff\xff\xff\xff\xff\xff\x00PV\xc0\x00\x08\x08\x00E\x00\x00N\n\x85\x00\x00\x80\x11\x9b\xc8\xc0\xa8\x89\x01\xc0\xa8\x89\xff\x00\x89\x00\x89\x00:5\x81\xed!\x01\x10\x00\x01\x00\x00\x00\x00\x00\x00 EJFDEBFEEBFACACACACACACACACACAAA\x00\x00 \x00\x01')

Formula                           :
oFrames.AddFrame(baseAddress + index - 2*6 - 2, data[index - 2*6 - 2:index + packetLength], duplicates)
##################################################################################


Sunday, April 7, 2013

Carveing - PE files

If examiners couldn't search anything, he/she starts process to carve something like PE, registry, event log, jpeg and etc....

this page is project for carving something.

The first, i start PE carving.

Let's Start!


PE consist of PE Header and PE Body.

PE Header is comprised of DOS Header + DOS Stub + NT Header(File Header + Optional Header) + Section Headers.

PE Body is sections.

We must know PE structure for carving it. But i don't introduce it. Because its structure is introduced through web a lot.


- PE Carving -
Before Caving PE, examiner must know cluster/block size.

(1) Searching for PE Magic Value at the first offset of every cluster.
       PE magic value is 0x45 0x5A. its Ascii is MZ.

(2) If You find PE magic value at The first offset of a cluster, search for the magic value of NT header in the cluster. this is 0x50 0x45 0x00 0x00 and this value's ascii is PE.

(3) The size of NT Header is 0xF8.

(4) File header in NT header has the number of section. Number of sections must bigger than Zero.

(5) The magic of optional header in NT header is 0x0B 0x01, if this PE runs on 32bit. when it runs on 64bit, this value is 0x0B 0x02.

(6) The size of PE Header is found at offset 0x3C from the start of optional header.

(7) Section Headers have file alignment and section alignment. file alignment has the start offset of each section on file. section alignment has the start offset of each section on memory.

(8) The size of each section table is 0x28.

(9) Pointer to raw data in section table expresses the start offset of its section.

(10) Size of raw data in section table expresses The size of its section.



I made a tool. Click below link

https://dorumugs-tools.googlecode.com/files/PE_Carver.py

Monday, March 11, 2013

EnScript - ExportClass

I can search for something through
File Name,
Size,
Hash,
Full Path
.....

and then export CSV or something

##################################### CODE #####################################
class ExportDialogClass: DialogClass {
  PathEditClass SaveHere;

  ExportDialogClass(DialogClass parent, String &savePath) :
    DialogClass(parent, "ExportClass Example"),
    SaveHere  (this, "Location To save the CSV File", START, START, 200, DEFAULT, 0, savePath,  PathEditClass::REQUIRED | PathEditClass::FILECREATE)
  {
  }
}

class MainClass {
  ExportClass Export;


  MainClass() :
    Export(null, "File Name,MD5 Hash,Created Time,Written Time,Accessed Time,Entry Modified Time,Full Path,", 0)
  {
  }

  void Main(CaseClass c) {
    DateClass date();
    SystemClass::ClearConsole();
    SearchClass search();

    String savePath = "C:\\Exported_Report.CSV";

    date.Now();
    String Start = date.GetString();

    ExportDialogClass dialog(null, savePath);

    if (dialog.Execute() == SystemClass::OK) {
      LocalFileClass exportedReport();
      exportedReport.Open(savePath, FileClass::WRITE);
      Export.Open(exportedReport, ExportClass::TEXT);

      ItemIteratorClass it(c, 0, ItemIteratorClass::CURRENTVIEW_SELECTED);

      while( EntryClass entry = it.GetNextEntry()) {
       if (entry.Name() == "cmd.exe") {
        DateClass date();
        DateClass C = entry.Created();
        String created = C.Year() + "/" + C.Month() + "/" + C.Day() + " " + C.Hour() + ":" + C.Minute() + ":" + C.Second();
        DateClass W = entry.Written();
        String written = W.Year() + "/" + W.Month() + "/" + W.Day() + " " + W.Hour() + ":" + W.Minute() + ":" + W.Second();
        DateClass A = entry.Accessed();
        String accessed = A.Year() + "/" + A.Month() + "/" + A.Day() + " " + A.Hour() + ":" + A.Minute() + ":" + A.Second();
        DateClass M = entry.Modified();
        String modified = M.Year() + "/" + M.Month() + "/" + M.Day() + " " + M.Hour() + ":" + M.Minute() + ":" + M.Second();

        HashClass hash = search.ComputeHash(entry);
        Export.Write(entry.Name() + "," + hash + "," + created + " ," + written + " ," + accessed + " ," + modified + " ," + entry.ItemPath() + ",\n");
        }
      }
     Export.Close();

     date.Now();
     String Ended = date.GetString();
     Console.WriteLine("Exported report created at " + savePath + "\n\n" +
    "Start Time : " + Start + "\n" +
    "End   Time : " + Ended);
    }
  }
}




#################################### CONSOLE ####################################


Exported report created at C:\Exported_Report.CSV

Start Time : 03/11/13 09:54:00오전
End   Time : 03/11/13 09:55:07오전



##################################### DIAL LOG ####################################






###################################### Result #####################################











Friday, February 22, 2013

File System Geography - EXT2

- Create a EXT2 file.
Prior to Test, I made a EXT2 file named EXT2.dd.
Procedures are as below.

(1) Create a File filled with zeros.
dd if=/dev/zero of=EXT2.dd bs=1024000 count=10 

10+0 records in
10+0 records out
10240000 bytes (10 MB) copied, 0.487653 s, 21.0 MB/s

(2) format EXT2.dd as EXT2 filesystem.
mkfs -T ext2 EXT2.dd mke2fs 1.41.9 (22-Aug-2009)

EXT2.dd is not a block special device.
Proceed anyway? (y,n) y
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
640 inodes, 2500 blocks
125 blocks (5.00%) reserved for the super user
First data block=0
1 block group
32768 blocks per group, 32768 fragments per group
640 inodes per group

Writing inode tables: done                            

Writing superblocks and filesystem accounting information: done

(3) Identify EXT2.dd file.


# file EXT2.dd 
EXT2.dd: Linux rev 1.0 ext2 filesystem data, UUID=8f4aeba5-aa03-4000-be18-3cb597a585f1 (large files)


(4) Mount EXT2 to Local and Copy forensics.jpg for test.

# mount -o loop EXT2.dd ./RAW/

# df

Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/sda3             28755580   4839728  22455144  18% /
udev                    513268       232    513036   1% /dev
none                    513268       136    513132   1% /dev/shm
none                    513268       344    512924   1% /var/run
none                    513268         0    513268   0% /var/lock
none                    513268         0    513268   0% /lib/init/rw
none                  28755580   4839728  22455144  18% /var/lib/ureadahead/debugfs
/dev/sda1               233333     23889    197397  11% /boot
/dev/sdb1            206422036    191748 195744668   1% /cases
/dev/loop1                9824        24      9300   1% /test/EXT2/RAW

# cp ~/Desktop/forensics.jpg ./RAW/

# ls ./RAW/
forensics.jpg  lost+found

# umount /dev/loop1





- EXT2 Layout







- 6 Contents of Group
























Group has 6 contents as follows.

Super Block - Metadata of Group
Group Descriptor Table – Location information of Block Bitmap, Inode Bitmap, Inode Table
Block Bitmap – The information what blocks are allocated
Inode Bitmap – The information what inodes are allocated
Inode Table - The inode that Group use
Data Blocks - The data that Group use




- Super Block

From First Block + 0x400 : Super Block 

The Size of Inode : 128 bytes
The Total Count of Inode : 640(0x280)
The Total Size of Inode : 640 * 128 = 81920 bytes
The Size of Block : 2 => 4096 bytes





- Group Descriptor

Second Block : Group Descciptor

Blocks Bitmap Offset : 2 Block
Inodes Bitmap Offset : 3 Block
Inodes Table Offset : 4 Block


















- Identify Blocks / Inodes Bitmap and Table offset

Blocks Bitmap Offset : 2 Block * 0x1000 = 0x2000
Inodes Bitmap Offset : 3 Block * 0x1000 = 0x3000
Inodes Table Offset : 4 Block * 0x1000 = 0x4000

Data is placed after end of inode.
Total inodes occupy blocks in accordance with the total count of inode.

The size of a inode is 256 bytes.
The Total Size of Inode : 640 * 128 = 163840 bytes(Super Block has this information)

163840 / 4096(block size) = 40

and then

After first inode table offset + 40 block  = Beginning Data offset




























- Inode


The six of inode is reserved from 0 inode to 5 inode.

0 - Bad Blocks Inode
1 - Root Inode
2 - ACL Inode
3 - ACL Inode
4 - Boot Loader Inode
5 - Undelete Directory Inode


The size of inodes reserved is 0x600(1536 = 256 * 6)

Inode has many attributes. There is the offset of Directory Entry.
Directory Entry has location information about data.




















Root Inode has Direcotry Entries of Data(forensics.jpg).

Root Inode is second inode. so I moved from 0x4000 offset to 0x4100 offset.
(the size of inode is 0x100(256).

I checked Directory Entry offset at 0x4128. this value is 0x2C.

Directory Entry location of Root inode is at 0x2C000.



































- Directory Entry

The structure of each entry is as follow.










Forensics.jpg's structure is as follow.
its inode number is 0x0C.











The formula of forensics.jpg's Inode 

How : (First Inode Offset + file's Inode Number * Inode Entry Size) – Inode Entry Size
Real Data : (0x4000 + 0xC * 0x100) – 0x100 = 0x4B00
=> The number of First Inode count  is 0. So 0x100 must be subtracted.




- The inode of forensics.jpg

forensics.jpg is placed from 32 block to 36 block.

















I identified JPEG signature at Offset 0x32000.




















- Idendify a JPEG(forensics.jpg)

For identification of forensics.jpg, I used dd tool.
if => input
of => output
bs => block size (=block is cluster in unix)
skip => skip as much as block size.

bash-3.2# dd if=EXT2.dd of=forensics.jpg bs=4096 count=5 skip=204800
5+0 records in
5+0 records out
20480 bytes transferred in 0.000217 secs (94394886 bytes/sec)

File : forensics.jpg
URL : http://pchs.peachschools.org/sites/pchs.peachschools.org/files/computer-forensics.jpeg





Tuesday, February 19, 2013

Tips - Disk Signature

Examiner makes sets of Images for analyzing.

Because a case is analyzed by examiners.

This time, we use single capture function  to distribute images.

and then..


A person has images in 1 disk.
B person has images in 2 disk.


But those disks have same disk signature.

So if 1 disk is attached, 2 disk is not attached.

OK!

Let's see the condition through diskmgmt.msc.

2 disk is OFFLINE.


































- MBRWiz.exe

This time examiner can use a tool like MBRWiz.exe. CLI is free.




- Identify Disks

Command : MBRWiz.exe /list









































- Change Disk Signature of 2 disk

Command : MBRWiz.exe /disk=2 /signature=generate









- Disk Signature in Boot Sector

You can see the disk signature changed (offset 440 / DWORD)

































- Disk State

We can see the 1,2 disk mounted.








































How abut MBRWIz.exe? The Result is perfect!!!!!!!








































Now we can mount All of disks.  ;-)



Friday, February 8, 2013

Tools - Time Maker

This tool decodes and encodes digital times.

Download : http://dorumugs-tools.googlecode.com/files/time_maker.py

Link : http://forensicinsight.org/wp-content/uploads/2012/10/INSIGHT-Digital-Times.pdf



# python time_maker.py --help
Usage: python time_maker.py -e YYYY-MM-DD,##:##:##,GMT
       python time_maker.py -e 1980-10-10,10:10:10,9

       python time_maker.py -d list
       python time_maker.py -d Time_Format -i Input_time
       python time_maker.py -d w64 -i 129943698100000000

-- Time Format List --
        w64 - Windows 64bit Big Time                (EX:129943698100000000)
        w64_big_h - (Hex) Windows 64bit Big Time    (EX:01cda71ade0d1500)
        w64_lit_h - (Hex) Windows 64bit Little Time (EX:00150dde1aa7cd01)
        wfiletime - (Hex) Windows FILETIME Time     (EX:de0d1500:01cda71a)
        wcookie -  Windows Cookie Date Time         (EX:3725399296,30254874)
        unum - Unix Numeric Time                    (EX:1349896210)
        umilli - Unix Millisecond Time              (EX:1349896210000)
        umicro - Unix Microsecond Time              (EX:1349896210000)
        unum_big_h - (Hex) Unix Numeric Little Time (EX:5075c812)
        unum_lit_h - (Hex) Unix Numeric Big Time    (EX:12c87550)
        chrome - Google Chrome Time                 (EX:12994369810317375)
        mac_ab - Mac Absolute Time                  (EX:371589010)
        mac_ab_h - (Hex) Mac Absolute Time          (EX:1625ff92)
        ms32_big_h - (Hex) MS-DOS 32bit Big Time    (EX:414a994a)
        ms32_lit_h - (Hex) MS-DOS 32bit Little Time (EX:4a994a41)
        hfs32_big_h - (hex) HFS 32bit Big Time      (EX:cc9b7892)
        hfs32_lit_h - (hex) HFS 32bit Little Time   (EX:92789bcc)

Options:
  -h, --help            show this help message and exit
  -e ENCODER, --encoder=ENCODER
                        python time_maker.py -e YYYY-MM-DD,##:##:##,GMT
                        python time_maker.py -e 1980-10-10,10:10:10,9
  -d DECODER, --decoder=DECODER
                        python time_maker.py -d list
  -i INPUT, --Input_Time=INPUT
                        python time_maker.py -d Time_Format -i Input_Time
                        python time_maker.py -d w64 -i 129943698100000000                                                                                                                                 



Encoding Sample
# python time_maker.py -e 1980-10-10,10:10:10,9

-----------------------------------------------------------------
  1 o' clock is 3600 seconds
  1 day is 86400 seconds
  1 year is 8760 hours
  1 year is 31536000 seconds
  1 second is 1000000000 nano seconds
  1 second is 1000000 micro seconds
  1 second is 1000 milli seconds
-----------------------------------------------------------------
                User Input Time -  1980-10-10 10:10:10
          User Input Time + GMT -  1980-10-10 19:10:10
-----------------------------------------------------------------
             Windows 64bit Time -  119845266100000000
   (Hex) Windows 64bit Big Time -  1a9c6a271e71500
(Hex) Windows 64bit Little Time -  0015e771a2c6a901
    (Hex) Windows FILETIME Time -  71e71500:01a9c6a2
       Windows Cookie Date Time -  1910969600,27903650
              Unix Numeric Time -  340053010
          Unix Millisecond Time -  340053010000
          Unix Microsecond Time -  340053010000000
    (Hex) Unix Numeric Big Time -  1444cc12
 (Hex) Unix Numeric Little Time -  12cc4414
             Google Chrome Time -  11984526610317375
              Mac Absolute Time -  -638254190
        (Hex) Mac Absolute Time -  x260afc6
    (Hex) MS-DOS 32bit Big Time -  014a9945
 (Hex) MS-DOS 32bit Little Time -  45994a01
       (hex) HFS 32bit Big Time -  906a7c92
    (hex) HFS 32bit Little Time -  927c6a90                                                                                                                              



Decoding Sample
# python time_maker.py -d w64 -i 129943698100000000

-----------------------------------------------------------------
  1 o' clock is 3600 seconds
  1 day is 86400 seconds
  1 year is 8760 hours
  1 year is 31536000 seconds
  1 second is 1000000000 nano seconds
  1 second is 1000000 micro seconds
  1 second is 1000 milli seconds
-----------------------------------------------------------------
                User Input Time -  129943698100000000
         User Input Time Format -  w64
            Decode Inputed Time -  2012-10-10 19:10:10
-----------------------------------------------------------------                                                                                                                         






Thursday, February 7, 2013

Tools - GPS Tracker

If I have a GPS information, I will search these through APP like Google earth.

However if I get  a lot of GPS information............

So I made a tool by python.


Download : http://dorumugs-tools.googlecode.com/files/GPS_Tracker.py

# GPS_Tracker.py --help
Usage: Python GPS_Tracker.py -l LINE.TXT -t TACK.TXT                                                                          

Options:
  -h, --help            show this help message and exit
  -l LINE, --line=LINE  Make a line from Start to End
  -t TACK, --tack=TACK  Tack a GPS on the map


Line.txt

37.3998107,127.1111664

37.3998107,127.1111664
37.3997000,127.1112142
37.3995925,127.1113009
37.3995006,127.1113432
37.3994119,127.1113712

......

37.4674538,127.0361924
37.4681327,127.0355551
.......

37.5343720,126.9972295
37.5342722,126.9969639
37.5342995,126.9966298
37.5342557,126.9965094
37.5344452,126.9964499
                                                                                                                                                                                                

























Tack.txt

37.4555342,127.0475550
37.5367527,127.0005321
                                                                                                                                              







EnScript - EntryClass (2)


I can search for something through
File Name,
Size,
Hash,
Full Path
.....

and

identify files inside zip.


Name Return Type Declaration
MountVolume VolumeClass const MountVolume (uint Options, const String &Password="")
MountVolume VolumeClass const MountVolume (uint Options, CredentialClass credentials)

- MountVolme -
Mounts a compound file and returns the mounted volume
Arguments:
Options - PERSIST | CALCUNALLOC | SCANDELETED | MOUNTNOPOPUP | RESOLVEPATHS | FORCEKNOWN | SCANJETDIRTY | CREDSCANONLY | SCANRMS
Password - Holds a variable length array of characters

Mounts a compound file and returns the mounted volume
Arguments:
Options - PERSIST | CALCUNALLOC | SCANDELETED | MOUNTNOPOPUP | RESOLVEPATHS | FORCEKNOWN | SCANJETDIRTY | CREDSCANONLY | SCANRMS
credentials - Decryption credentials




I brought it from EnCase Help page.
###########################  Code and Result  ###########################

Black : Code

Red : Result

######################################################################
//Recurse all entries in the case and perform a 'View File Structure' on files that have an extension of ZIP.
//Print out the paths of the files inside the ZIPs

class MainClass;

class MainClass {
  bool good;
  void Main(CaseClass c) {
    int notWorks;
    uint opts; //can be any of EntryClass::MountOptions
    for(ItemIteratorClass i(c); EntryClass e = i.GetNextEntry();) {
      if (e.Extension().Compare("zip") == 0) {
        Console.WriteLine("Mounting " + e.FullPath());

Mounting 

        Console.WriteLine(e.TruePath());

dorumugs\C\Program Files (x86)\Autopsy\java\docs\beansbinding-1.2.1-doc.zip

        VolumeClass vol = e.MountVolume(opts, ""); //no password.  If a zip is password protected, vol will be null
        if (vol) {
          forall (EntryClass mountedEntry in vol) {
            /*
            notice that the 'FullPath' property is not the same as what the Table View shows.
            This is because the entries do not become part of the Case's Entry List until
            AFTER the script ends.  The only way to have the entries become part fo the case's
            entry list immediately is to add the device or evidence file to a case that is not
            part of the GlobalDataClass::CaseRoot().
            */
            Console.WriteLine("Entry Name=" + mountedEntry.TruePath());
            Console.WriteLine("Entry FullPath=" + mountedEntry.FullPath());


Entry Name=dorumugs\index-files
Entry FullPath=index-files
Entry Name=dorumugs\index-files\index-1.html
Entry FullPath=index-files\index-1.html
Entry Name=dorumugs\index-files\index-10.html
Entry FullPath=index-files\index-10.html
Entry Name=dorumugs\index-files\index-11.html
Entry FullPath=index-files\index-11.html
                        .
                        .
                        .
                        .
                        .


          }
        }
        else {
          Console.WriteLine("Could Not Mount " + e.FullPath());
          notWorks++;
        }
      }
    }
    if (notWorks == 0)
      Console.WriteLine("Worked");

Worked

    else
      Console.WriteLine("Does not work");

Does not work

  }
}