Jump to content
XPEnology Community

neXus

Member
  • Posts

    54
  • Joined

  • Last visited

Posts posted by neXus

  1. As long we will have the hand on the kernel, we could fool the checks.

     

    My next challenge will be to simulate the ttyS1 serial device and the Uart device check by synobios to avoid any patching.

     

    It will be harder but that's a nice playground :smile:

     

    They don't seems to have hardware "protection" stuff as we can found on readynas for example (encryption key in OTP for example).

  2. Works fine here too with my module. I was digging on the disassembly code to check what was really checked.

     

    Vortex is faster than me :smile: I have some issue with my coredump as there is no symbols on it. I'm not a professional so I have to make it step by step.

  3. Ok, my hooking kernel module is almost ready, now we have to find the /proc/bus/pci/devices to feed it.

     

    I tried why an handcrafted one, no luck :smile:

     

    DiskStation> cat /proc/bus/pci/devices | openssl dgst -sha1
    (stdin)= 0420d5aff0e976362758ec21d0d7e6def6730921
    
    DiskStation> cat /root/devices | openssl dgst -sha1
    (stdin)= 5d901113beb9d0b2a0ca458693d20a5697951c4e
    
    DiskStation> insmod dsmcheck.ko 
    
    DiskStation> cat /proc/bus/pci/devices | openssl dgst -sha1
    (stdin)= 5d901113beb9d0b2a0ca458693d20a5697951c4e
    

  4. It's not working, I'm pretty sure the sanity check code is also in packed binaries (elf/cgi).

     

    I kill everything (httpd/scemd/findhostd).

     

    Changing as you said, fire a trace log on scemd launch, here is the result.

     

    DiskStation> cat trace.7414 |grep open | grep cgi
    [f71acd6b] open("/usr/syno/synoman/webman/modules/StorageManager/storagehandler.cgi", O_RDONLY) = 11
    [f71acd6b] open("/usr/syno/synoman/webman/modules/StorageManager/volumehandler.cgi", O_RDONLY) = 11
    [f71acd6b] open("/usr/syno/synoman/webman/modules/PkgManApp/PkgMan.cgi", O_RDONLY) = 11
    [f71acd6b] open("/usr/syno/synoman/webman/modules/PkgManApp/PkgSynoMan.cgi", O_RDONLY) = 11
    [f71acd6b] open("/usr/syno/synoman/webman/modules/DSMNotify/dsmnotify.cgi", O_RDONLY) = 11
    [f71acd6b] open("/lib/libsynocgi.so", O_RDONLY) = 11
    
    DiskStation> strings /lib/libdsm.so.4 |grep .cgi
    /LIB/libsynocgi.so
    /USR/syno/synoman/webman/modules/StorageManager/storagehandler.cgi
    /USR/syno/synoman/webman/modules/StorageManager/volumehandler.cgi
    /USR/syno/synoman/webman/modules/PkgManApp/PkgMan.cgi
    /USR/syno/synoman/webman/modules/PkgManApp/PkgSynoMan.cgi
    /USR/syno/synoman/webman/modules/DSMNotify/dsmnotify.cgi
    

  5. Hu, not sure how it will be fooled, as /usr and /USR are distincts on case sensitive file system.

     

    The only way to make it work could be to override /usr by /USR for the entire system (same for lib). As in binaries it looks for /usr /lib we can place orignal files in here. But it's really a dirty way !

     

    EDIT : It may work in fact... give a try on it :smile:

     

    But you can make a try and report :smile:

     

    I preferrer not altering anything on stock firmware and make the work kernel side only. (Included synobios.ko I have plan for this one too).

  6. This will not work as an integrity check is done BEFORE parsing the devices.

     

    Signature for elf/cgi are the same, same for the two so as well.

     

    So there is two kind of hashes, I don't really know what is hashed.

     

    There two hashes because elf/cgi are packed but not the so.

     

    I have to find the common parts on each which I believe include the strings statements.

     

    Another way will be modify the kernel sources to add the convenient devices but I don't know if there will be side effects.

     

    Edit : better create a module which will hook open syscall and return a fake device list if it match some criteria.

     

    Anyway a /proc/bus/pci/devices from a genuine 3612xs will be helpfull

     

    So, maybe we don't need to patch files, proper simulation may do the trick.

     

    Thanks

  7. So, I may have found how they protect it, no how to defeat it. Here is the deal.

     

    Those files :

     

    • /usr/syno/bin/findhostd
      /usr/syno/bin/scemd
      /lib/libdsm.so
      /lib/libsynocgi.so
      /usr/syno/synoman/webman/modules/StorageManager/storagehandler.cgi
      /usr/syno/synoman/webman/modules/StorageManager/volumehandler.cgi
      /usr/syno/synoman/webman/modules/PkgManApp/PkgMan.cgi
      /usr/syno/synoman/webman/modules/PkgManApp/PkgSynoMan.cgi
      /usr/syno/synoman/webman/modules/DSMNotify/dsmnotify.cgi

     

    are packed the same way (I don't know yet if it's a home made packing or "readytogo" one.

     

    Something is triggering sort of "sanity check" function.

     

    At the end of each file above you can found a 256o chain, which is, I believe a RSA signature. So all theses files are checked to see if their integrity has not been compromised (with the dnsdsm cert). Expect the one which is running this function (here we found our /proc/self/comm string).

     

    Once this santity check is done, another function open the synoinfo.conf to get the NAS unique model name, let's say synology_bromolow_3612xs.

     

    It next open /proc/bus/pci/devices and check all the devices in it for I think a match with devices defined on each protected files above :

     

    extract :

     

    --------------------- Strings
    808610d3    // 82574L Gigabit Network Connection                                                      
    e1000e                                                            
    0b00                                                              
    0c00                                                              
    0d00                                                              
    0100
    --------------------- Strings     
    

     

    We can read thoses string as : 808610d3 pci id for the hardware / e1000e module associated / 0b00..0100 is the BusDevFunc id.

     

    So I believe that somewhere, there is a link between the model and the following devices (ata/usb/ethernet).

     

    if there is a mistmatch with this mapping, the process unlink (remove) /dev/sd* or /dev/sas*.

     

    We can't alter the files without resign them with the private key associated with the dnsdsm cert and append the new signatures to the end of the file.

  8. 197  [f6ec11f8] stat64("/dev/sda", {st_dev=makedev(9, 0), st_ino=712, st_mode=S_IFBLK|0644, st_nlink=1, st_uid=0, st_gid=0, st_blksize=4096, st_blocks=0, st_rdev=makedev(8, 0), st_atime=2013/09/23-16:45:50, st_mtime=2013/09/23-16:45:50, st_ctime=2013/09/23-16:45:50}) = 0
    7197  [f6ec335d] unlink("/dev/sda")     = 0
    

     

    One step beyond :wink:

  9. Well, beta files are not packed but they don't seems to have any protection in it (no /dev/sd*).

     

    One more thing, attaching strace to all http process, the cgi don't remove the sda, I believe so there is also countermeasure against dynamic analysis. (PTRACE detection pretty simple to do in fact.. damn... same for gdb)

     

    20954 19:03:31 [f6bf4c08] ptrace(PTRACE_TRACEME, 0, 0, 0) = -1 EPERM (Operation not permitted)
    20989 19:03:38 [f6c06c08] ptrace(PTRACE_TRACEME, 0, 0, 0) = -1 EPERM (Operation not permitted)
    

     

    Hopefully it can be defeated :smile:

  10. Ok I can now start a dynamic analysis, first thing I found :

     

    I try to trace cgi execution, and create a mknod /dev/sda

     

    I have no traces of storagehandler.cgi, it presume the check is done in several modules could be rsrcmonitor or externaldevices.

     

    I'll keep trying, a little help could be fine :wink:

     

    Sda Still here : 1379691942
    16652 root     21600 S    /usr/syno/synoman/webman/modules/ResourceMonitor/rsrcmonitor2.cgi
    
    Sda Still here : 1379691942
    16652 root     21600 S    /usr/syno/synoman/webman/modules/ResourceMonitor/rsrcmonitor2.cgi
    
    Sda Still here : 1379691946
    23147 root     22748 S    /usr/syno/synoman/webman/modules/SystemInfoApp/SystemInfo.cgi
    23149 root     17724 S    /usr/syno/synoman/webman/modules/PollingTask/polling.cgi
    23236 root     23108 R    /usr/syno/synoman/webman/modules/ControlPanel/modules/externaldevices.cgi
    
    Sda Still here : 1379691947
    23219 root     18104 S    /usr/syno/synoman/webman/modules/SystemInfoApp/LogViewer.cgi
    24752 root     21600 S    /usr/syno/synoman/webman/modules/ResourceMonitor/rsrcmonitor2.cgi
    
    Sda Still here : 1379691950
    27243 root     17636 R    /usr/syno/synoman/webman/modules/DSMNotify/dsmnotify.cgi
    
    no more sda : 1379691950
    27243 root     17768 S    /usr/syno/synoman/webman/modules/DSMNotify/dsmnotify.cgi
    

  11. Giving up for now static analysis, I will make my custom kernel with debug enabled and start dynamic analysis.

     

    Obfuscation is pretty hard to read, that's the point of this :smile:

     

    Anyway, seems the cgi don't have any obfuscation, how did you manage to get the core ? (Not familliar with web stuff :smile:)

     

    Thanks

  12. As far as I know there are non senses obfuscation :

     

    loc_4ACF8:                              ; CODE XREF: LOAD:loc_4ACF8p
    
    LOAD:0004ACF8 E8 FC FF FF FF                                call    near ptr loc_4ACF8+1
    

     

    You can found the pattern "E8 FC FF FF FF" regulary on this bloc of code.

     

    I made a little script to undefine this as there is non sens for me.

     

     

    def fixTheJmpCalls():
       # Fix the jmp call in select code
       selection, startaddr, endaddr = idaapi.read_selection()
       idaapi.unmark_selection()
       if selection:    
           for opcode in range(startaddr,endaddr):
               if GetMnem(opcode) == "jmp" or GetMnem(opcode) == "call":
                   if GetDisasm(opcode)[-2:-1] == "+" and GetDisasm(opcode)[-1:].isdigit():
                       print "Broken Instruction: %X"%opcode, GetDisasm(opcode)
                       MakeUnkn(opcode,0)
                       MakeArray(opcode,5)
    

     

    it seems to fix the flow, but there are still some other obfuscation to reveal, example :

     

    loc_4AE00:                              ; CODE XREF: LOAD:0004ADF6j
    LOAD:0004AE00 8B 8D 9C F8 FF FF                             mov     ecx, [ebp-764h]
    LOAD:0004AE06 85 C9                                         test    ecx, ecx
    LOAD:0004AE08 74 0E                                         jz      short loc_4AE18
    LOAD:0004AE0A 8B 85 9C F8 FF FF                             mov     eax, [ebp-764h]
    LOAD:0004AE10 89 04 24                                      mov     [esp], eax
    LOAD:0004AE13
    LOAD:0004AE13                               loc_4AE13:                              ; CODE XREF: LOAD:loc_4AE13p
    LOAD:0004AE13 E8 FC FF FF FF                                call    near ptr loc_4AE13+1
    LOAD:0004AE18
    LOAD:0004AE18                               loc_4AE18:                              ; CODE XREF: LOAD:0004AE08j
    LOAD:0004AE18 85 DB                                         test    ebx, ebx
    

     

    The test eax,eax will always be true, so the jz will always jump and the code behind never used. It could be changes to :

     

    LOAD:0004AE00                               loc_4AE00:                              ; CODE XREF: LOAD:0004ADF6j
    LOAD:0004AE00 8B 8D 9C F8 FF FF                             mov     ecx, [ebp-764h]
    LOAD:0004AE06 85 C9                                         test    ecx, ecx
    LOAD:0004AE08 74 0E                                         jz      short loc_4AE18
    LOAD:0004AE08                               ; ---------------------------------------------------------------------------
    LOAD:0004AE0A 8B 85 9C F8 FF FF 89 04 24 E8+junk            db 'ïࣰ  ë',4,'$Þ³   '
    LOAD:0004AE18                               ; ---------------------------------------------------------------------------
    LOAD:0004AE18
    LOAD:0004AE18                               loc_4AE18:                              ; CODE XREF: LOAD:0004AE08j
    

     

     

    Not sure it will help but I don't found any other explanation.

     

    Assembly guys, please contribute :smile:

  13. I came accross this one too but it only traverse defined func. It seems there is a mix of several obfuscation in here. The good point I think, the harder they try to hide what is done, easier it will be to fool once we figure out what is really done :smile:

     

    I'm working on the libdsm.so as it has the same pattern as cgi regarding obfuscation. I will share any progress here, do the same :smile:

     

    I have change a bit the python code to work on selected area :

     

    def fixTheJmpCalls():
       # Fix the jmp call in select code
       selection, startaddr, endaddr = idaapi.read_selection() 
       if selection:    
           for opcode in range(startaddr,endaddr):
               if GetMnem(opcode) == "jmp" or GetMnem(opcode) == "call":
                   if GetDisasm(opcode)[-2:-1] == "+" and GetDisasm(opcode)[-1:].isdigit():
                       print "Broken Instruction: %X"%opcode, GetDisasm(opcode)
                       code_addr = GetOperandValue(opcode, 0) 
                       fix_addr = code_addr -1 
                       MakeUnkn(fix_addr,1)
                       MakeCode(code_addr)
    

     

    I'll give a try

  14. Disassembly code contains anti reverse technique (Jump Trick with short near ptr loc+1) in order to avoid linear disassembly :

     

     

    33 C0 XOR eax, eax

    74 01 jz short near ptr loc+1

    E9 58 C3 68 94 jmp near ptr 94A8D521h

     

    Should be disassembled as :

     

    33 C0 xor eax,eax

    74 01 jz short near ptr loc+1

    E9 junk

    58 Pop eax

    C3 retn

     

    It will be harder to find what is really done. It's the same countermeasure malware uses.

     

    More info here :

     

    http:http://books.google.fr/books?id=FQC8EPYy834C&lpg=PA329&ots=BsntpxIe6l&dq=Fool%20Linear%20Disassembly&hl=fr&pg=PA329#v=onepage&q=Fool%20Linear%20Disassembly&f=false

  15. Could be dumb question but :

     

    Someone with a silicon raid controller can give a try ? As it seems too be a common factor.

     

    What happens if we use only pata disks (/dev/hdX) ?

     

    The test seems in call near ptr dword_F6BB419C, we have to study it :smile:

  16. @Andy928,

     

    From where did you get the stage2 grub file, I guess stage1 & 1.5 are almost "regular" but there are a lot of feature in stage2 added by Syno.

     

    I was also wondering why we could not find sources for the modified grub (I'm not sure about the licencing model grub belong to).

     

    I also be very pleased to know which kind of patching do you set in the genuine Stage2 for the xpenology project.

     

    Thanks a lot

×
×
  • Create New...