├── bipolar.py ├── gatoescoces.jpg ├── payload.js ├── readme.md ├── screenshot.jpg ├── script_example.sh ├── script_example1.sh └── shellPHP_example.php /bipolar.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | import numpy 3 | 4 | def copyArray(src,dst,start,end,prefix_src,prefix_dst): 5 | for i in range(start,end): 6 | #print("start:",start," end:",end," pSrc:",prefix_src," pDst:",prefix_dst," lenSrc:",len(src)," lenDst:",len(dst)) 7 | #print("dst:",(prefix_dst+i)," src:",(prefix_src+i)) 8 | dst[prefix_dst+i] = src[prefix_src+i] 9 | 10 | def jsHideIntoJpegMini(imgSrc,scriptToHide,imgDst): 11 | 12 | with open(imgSrc,'rb') as f1: bytesImgSrc = f1.read(10000000); 13 | # Si /* o */ fichero no valido 14 | # FF D8 FF E0 00 10 bla bla --> posicion 4 y 5 tam de cabecera 15 | tamCabeceraActual = bytesImgSrc[4]*256+bytesImgSrc[5] 16 | leidos = len(bytesImgSrc) 17 | 18 | jpgFinal = bytearray(leidos-tamCabeceraActual+2362+4) #2362=0x093A - Todo tal cual le quito la cabecera, le pongo el tamao nuevo de cabecera y los 4 bytes de cierre 2A 2F 2F 2F FF D9 19 | 20 | # Copiar bloques de bytes 21 | copyArray(bytesImgSrc,jpgFinal,0,4,0,0) #copio los primeros 4 bytes --> tipicamente FFD8 FFE0, la cabecera 22 | jpgFinal[4] = 0x09; jpgFinal[5] = 0x3A; #copio nuevo tamano 23 | copyArray(bytesImgSrc,jpgFinal,6,10,0,0) #copio los primeros 4 bytes de la cabecera sin contar el tam. Tipicametne JFIF 24 | jpgFinal[10] = 0x2F; jpgFinal[11] = 0x2A; 25 | copyArray(bytesImgSrc,jpgFinal,0,tamCabeceraActual-6,10,12) #copio lo que queda de tamCabeceraActual 26 | with open(scriptToHide,'rb') as f3: linesScriptToHide = f3.read(10000000); # payload js 27 | for i in range(0,2362-tamCabeceraActual-2-len(linesScriptToHide)): jpgFinal[(12+tamCabeceraActual-6)+i] = 0x00; 28 | payloadLen = len(linesScriptToHide) 29 | copyArray(linesScriptToHide,jpgFinal,0,len(linesScriptToHide),0,2362-payloadLen+4) #le meto el payload 30 | copyArray(bytesImgSrc,jpgFinal,0,(leidos-(tamCabeceraActual+4))-2,tamCabeceraActual+4,2362+4) # No copio FF D9 #copio lo que queda de tamCabeceraActual | # COPIO EL RESTO DEL FICHERO MENOS LOS DOS ULTIMOS BYTES 31 | 32 | jpgFinal[len(jpgFinal)-7] = 0x2A; jpgFinal[len(jpgFinal)-6] = 0x2F; jpgFinal[len(jpgFinal)-5] = 0x2F; # A final de fichero copio el cierre 33 | jpgFinal[len(jpgFinal)-4] = 0x2F; jpgFinal[len(jpgFinal)-3] = 0xFF; jpgFinal[len(jpgFinal)-2] = 0xD9; 34 | 35 | with open(imgDst,'wb') as f2: f2.write(jpgFinal) 36 | 37 | def jsHideIntoJpegBig(imgSrc,scriptToHide,imgDst): 38 | 39 | with open(imgSrc,'rb') as f1: bytesImgSrc = f1.read(10000000); 40 | #Falta considerar /* */ el fichero no es valido para stego 41 | 42 | # FF D8 FF E0 00 10 bla bla --> posicion 4 y 5 tam de cabecera 43 | tamCabeceraActual = bytesImgSrc[4]*256+bytesImgSrc[5] 44 | leidos = len(bytesImgSrc) 45 | #2F 2A -> 12074 -2 = 12072 46 | tamCabeceraDestino = 12074-tamCabeceraActual 47 | 48 | # Anado los 00 que hacen falta a la cabecera para tamano 2F2A 49 | # El payload js necesita antes 4 bytes -> FF FE 00 1C (00 1C -> el tam del payload+2) 50 | # Machacar [4] y [5] con el tam nuevo de cabecera 51 | 52 | with open(scriptToHide,'rb') as f3: linesScriptToHide = f3.read(10000000); # payload js 53 | payloadLen = len(linesScriptToHide) 54 | 55 | jpgFinal = bytearray(leidos+tamCabeceraDestino+payloadLen+4+1+2) 56 | 57 | copyArray(bytesImgSrc,jpgFinal,0,4,0,0) #copio los primeros 4 bytes --> tipicamente FFD8 FFE0, la cabecera 58 | jpgFinal[4] = 0x2F; jpgFinal[5] = 0x2A; #copio nuevo tamano 59 | 60 | for i in range(0,tamCabeceraDestino): 61 | jpgFinal[i+tamCabeceraActual+4] = 0x00; 62 | 63 | jpgFinal[tamCabeceraActual+4+tamCabeceraDestino] = 0xFF 64 | jpgFinal[tamCabeceraActual+4+tamCabeceraDestino+1] = 0xFE 65 | 66 | # Anadir el tamano del javascript con dos bytes por ejemplo 00 C1 67 | jpgFinal[tamCabeceraActual+4+tamCabeceraDestino+2] = 0x00; #CALCULARLO BIEN 68 | jpgFinal[tamCabeceraActual+4+tamCabeceraDestino+3]= payloadLen+2 #CALCULARLO BIEN 69 | 70 | copyArray(linesScriptToHide,jpgFinal,0,payloadLen,0,tamCabeceraActual+4+tamCabeceraDestino+4) 71 | 72 | copyArray(bytesImgSrc,jpgFinal,0,leidos-tamCabeceraActual-4+1, 73 | tamCabeceraActual+4-1,tamCabeceraActual+4+tamCabeceraDestino+4+payloadLen) 74 | 75 | jpgFinal[len(jpgFinal)-5] = 0x2A; 76 | jpgFinal[len(jpgFinal)-4] = 0x2F; 77 | jpgFinal[len(jpgFinal)-3] = 0xFF; 78 | jpgFinal[len(jpgFinal)-2] = 0xD9; 79 | 80 | with open(imgDst,'wb') as f2: f2.write(jpgFinal) 81 | 82 | def shHideIntoJpeg(imgSrc,scriptToHide,imgDst): 83 | 84 | with open(imgSrc,'rb') as f1: bytesImgSrc = f1.read(10000000); 85 | with open(scriptToHide,'rb') as f3: linesScriptToHide = f3.read(10000000); # payload js 86 | payloadLen = len(linesScriptToHide) 87 | 88 | leidos = len(bytesImgSrc) 89 | #en el fichero no puede haber 0x27 90 | # Si no tiene 0x27 entonces al final del script pongo : ' y al final de fichero ' 91 | # // FF D8 FF E0 00 10 bla bla --> posicion 4 y 5 tam de cabecera 92 | tamCabeceraActual = bytesImgSrc[4]*256+bytesImgSrc[5] 93 | 94 | jpgFinal = bytearray(leidos+tamCabeceraActual+291) 95 | # 291=0x0123 - Todo tal cual le quito la cabecera, le pongo el tamano nuevo de cabecera 96 | copyArray(bytesImgSrc,jpgFinal,0,4,0,0) #copio los primeros 4 bytes --> tipicamente FFD8 FFE0, la cabecera 97 | jpgFinal[4] = 0x01; jpgFinal[5] = 0x23; #copio nuevo tamano 98 | 99 | copyArray(bytesImgSrc,jpgFinal,6,10,0,0) 100 | 101 | for i in range(0,tamCabeceraActual-6): 102 | if bytesImgSrc[10+i] == 0x00: 103 | #if ByteToHex(bytesImgSrc[10+i]) == "00": 104 | jpgFinal[10+i] = 0x01 105 | else: 106 | jpgFinal[10+i] = bytesImgSrc[10+i] 107 | 108 | for i in range(0,291-tamCabeceraActual): 109 | jpgFinal[(10+tamCabeceraActual-6)+i] = 0x01; # es 0x01 pq el 0x00 da error en script bash 110 | 111 | jpgFinal[tamCabeceraActual+4] = 0x0D; 112 | jpgFinal[tamCabeceraActual+4+1] = 0x0A; 113 | 114 | copyArray(linesScriptToHide,jpgFinal,0,payloadLen,0,tamCabeceraActual+4+2) 115 | 116 | copyArray(bytesImgSrc,jpgFinal,0,leidos-tamCabeceraActual-4,tamCabeceraActual+4,291+4) 117 | 118 | 119 | with open(imgDst,'wb') as f2: f2.write(jpgFinal) 120 | 121 | def name(): 122 | 123 | print("") 124 | print(" ___ ___ ___ ___ ") 125 | print(" _____ ___ / /\ / /\ / /\ / /\ ") 126 | print(" / /::\ / /\ / /::\ / /::\ / /::\ / /::\ ") 127 | print(" / /:/\:\ / /:/ / /:/\:\ / /:/\:\ ___ ___ / /:/\:\ / /:/\:\ ") 128 | print(" / /:/~/::\ /__/::\ / /:/~/:/ / /:/ \:\ /__/\ / /\ / /:/~/::\ / /:/~/:/ ") 129 | print("/__/:/ /:/\:| \__\/\:\__ /__/:/ /:/ /__/:/ \__\:\ \ \:\ / /:/ /__/:/ /:/\:\ /__/:/ /:/___") 130 | print("\ \:\/:/~/:/ \ \:\/\ \ \:\/:/ \ \:\ / /:/ \ \:\ /:/ \ \:\/:/__\/ \ \:\/:::::/") 131 | print(" \ \::/ /:/ \__\::/ \ \::/ \ \:\ /:/ \ \:\/:/ \ \::/ \ \::/~~~~ ") 132 | print(" \ \:\/:/ /__/:/ \ \:\ \ \:\/:/ \ \::/ \ \:\ \ \:\ ") 133 | print(" \ \::/ \__\/ \ \:\ \ \::/ \__\/ \ \:\ \ \:\ ") 134 | print(" \__\/ \__\/ \__\/ \__\/ \__\/ ") 135 | print("") 136 | print(" -- --=[ bipolar 0.1 experimental (March 2020)]") 137 | print(" -- --=[ Author: Dr. Alfonso Munoz @mindcrypt]") 138 | print("") 139 | 140 | def menu(): 141 | name() 142 | 143 | def main(paramIn): 144 | 145 | if len(sys.argv)<5: 146 | menu() 147 | print(" -- --=[ #bipolar