Base64的隐写 0x01 隐写原理 填充两个’=’隐写四位信息,填充一个’=’隐写两位信息,将编码按照base64对照表还原,然后每8位转成字符即可.
0x02 隐写脚本 通过读取源文件source.txt文件把需要隐写的内容隐写进去并保存到stego.txt中。 相应加密脚本enStego.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import base64import sysdef enStego (sourceFile,setgoFile,message ): b64table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" with open (sourceFile,'r' ) as sourceText, open (setgoFile,'w' ) as setgoText: print (message) message = "" .join([bin (ord (i))[2 :].zfill(8 ) for i in message]) for line in sourceText: text = base64.b64encode(line[:-1 ].encode("utf-8" )).decode("utf-8" ) l = text.count('=' ) if 0 < 2 *l <= len (message): text = text[:-l-1 ] + b64table[b64table.index(text[-l-1 ])+int (message[:2 *l],2 )] + text[-l:] message = message[2 *l:] setgoText.write(text+'\n' ) if not len (message): break return len (message) if __name__ == "__main__" : if len (sys.argv) == 4 : print ("Remaining" ,enStego(sys.argv[1 ],sys.argv[2 ],sys.argv[3 ]),"bits!" ) else : print ("Remaining" ,enStego("source.txt" ,"stego.txt" ,"SimpleMessage\n" ),"bits!" )
使用方法:
1 ❯ python3 enStego.py source.txt stego.txt 「隐写信息」
source.txt文件内容(任意内容,这里只是放了一段C++代码):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 #include "linearList.h" #include <iostream> template <class T> struct chainNode { T element; chainNode<T> *next; chainNode(){} chainNode(const T& element){ this->element = element; } chainNode(const T& element, chainNode<T>* next){ this->element = element; this->next = next; } }; template <class T> class chain :public linearList<T> { public: chain(int initialCapacity = 10); chain(const chain<T>&); ~chain(); bool empty() const{ return listSize == 0; } int size() const{ return listSize; } T& get(int theIndex) const; int indexOf(const T& theElement) const; void erase(int theIndex); void insert(int theIndex, const T& theElement); void output(std::ostream& out) const; protected: void checkIndex(int theIndex) const; chainNode<T>* firstNode; int listSize; }; template <typename T> chain<T>::chain(int initialCapacity){ if(initialCapacity < 1){ std::ostringstream s; s << "initial capacity = "<< initialCapacity << " Must be > 0"; throw illegalParameterValue(s.str()); } firstNode = NULL; listSize = 0; } template <typename T> chain<T>::chain(const chain<T>& theList){ listSize = theList.listSize; if (listSize == 0) { firstNode = NULL; return; } chainNode<T>* sourceNode = theList.firstNode; firstNode = new chainNode<T>(sourceNode->element); sourceNode = sourceNode->next; chainNode<T>* targetNode = firstNode; while(sourceNode != NULL){ targetNode->next = new chainNode<T>(sourceNode->element); targetNode = targetNode->next; sourceNode = sourceNode->next; } targetNode->next = NULL; } template <typename T> chain<T>::~chain(){ while(firstNode != NULL){ chainNode<T>* nextNode = firstNode->next; delete firstNode; firstNode = nextNode; } } template <typename T> T& chain<T>::get(int theIndex) const{ checkIndex(theIndex); chainNode<T>* currentNode = firstNode; for(int i = 0; i < theIndex; ++i){ currentNode = currentNode->next; } return currentNode->element; } template <typename T> int chain<T>::indexOf(const T& theElement) const{ chainNode<T>* currentNode = firstNode; int index = 0; while(currentNode != NULL && currentNode->element != theElement){ currentNode = currentNode->next; ++index; } if(currentNode == NULL){ return -1; }else{ return index; } } template <typename T> void chain<T>::erase(int theIndex){ checkIndex(theIndex); chainNode<T>* deleteNode; if(theIndex == 0){ deleteNode = firstNode; firstNode = firstNode->next; }else{ chainNode<T>* p = firstNode; for(int i = 0;i < theIndex - 1;++i){ p = p->next; } deleteNode = p->next; p->next = p->next->next; } --listSize; delete deleteNode; } template <typename T> void chain<T>::insert(int theIndex, const T& theElement){ if(theIndex < 0 || theIndex > listSize){ std::ostringstream s; s << "index = " << theIndex << " size = " << listSize; throw illegalIndex(s.str()); } if(theIndex == 0){ firstNode = new chainNode<T>(theElement,firstNode); }else{ chainNode<T>* p = firstNode; for(int i = 0;i < theIndex - 1;++i){ p = p->next; } p->next = new chainNode<T>(theElement,p->next); } ++listSize; } template <typename T> void chain<T>::output(std::ostringstream& out) const{ for(chainNode<T>* currentNode = firstNode; currentNode != NULL; chainNode = chainNode->next){ out << currentNode->element << " "; } } template <typename T> std::ostream& operator<<(std::ostream& out, const chain<T>& x){ x.output(out); return out; } int main(int argc, char const *argv[]) { return 0; }
得到stego.txt文件内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 I2luY2x1ZGUgImxpbmVhckxpc3QuaCJ= I2luY2x1ZGUgPGlvc3RyZWFtPp== dGVtcGxhdGUgPGNsYXNzIFQ+ c3RydWN0IGNoYWluTm9kZZ== e7== CVQgZWxlbWVudDs= CWNoYWluTm9kZTxUPiAqbmV4dDt= CWNoYWluTm9kZSgpe32= CWNoYWluTm9kZShjb25zdCBUJiBlbGVtZW50KXs= CQl0aGlzLT5lbGVtZW50ID0gZWxlbWVudDt= CX1= CWNoYWluTm9kZShjb25zdCBUJiBlbGVtZW50LCBjaGFpbk5vZGU8VD4qIG5leHQpe5== CQl0aGlzLT5lbGVtZW50ID0gZWxlbWVudDv= CQl0aGlzLT5uZXh0ID0gbmV4dDt= CX3= fTu= dGVtcGxhdGUgPGNsYXNzIFQ+ Y2xhc3MgY2hhaW4gOnB1YmxpYyBsaW5lYXJMaXN0PFQ+ e9== cHVibGljOo== CWNoYWluKGludCBpbml0aWFsQ2FwYWNpdHkgPSAxMCk7 CWNoYWluKGNvbnN0IGNoYWluPFQ+Jik7 CX5jaGFpbigpO5== CWJvb2wgZW1wdHkoKSBjb25zdHu= CQlyZXR1cm4gbGlzdFNpemUgPT0gMDs= CX1= CWludCBzaXplKCkgY29uc3R7 CQlyZXR1cm4gbGlzdFNpemU7 CX1= CVQmIGdldChpbnQgdGhlSW5kZXgpIGNvbnN0O8== CWludCBpbmRleE9mKGNvbnN0IFQmIHRoZUVsZW1lbnQpIGNvbnN0O9== CXZvaWQgZXJhc2UoaW50IHRoZUluZGV4KTu= CXZvaWQgaW5zZXJ0KGludCB0aGVJbmRleCwgY29uc3QgVCYgdGhlRWxlbWVudCk7 CXZvaWQgb3V0cHV0KHN0ZDo6b3N0cmVhbSYgb3V0KSBjb25zdDt= CU== cHJvdGVjdGVkOt== CXZvaWQgY2hlY2tJbmRleChpbnQgdGhlSW5kZXgpIGNvbnN0O4== CWNoYWluTm9kZTxUPiogZmlyc3ROb2RlO9== CWludCBsaXN0U2l6ZTs= fTt= dGVtcGxhdGUgPHR5cGVuYW1lIFQ+ Y2hhaW48VD46OmNoYWluKGludCBpbml0aWFsQ2FwYWNpdHkpe3== CWlmKGluaXRpYWxDYXBhY2l0eSA8IDEpe8== CQlzdGQ6Om9zdHJpbmdzdHJlYW0gczv= CQlzIDw8ICJpbml0aWFsIGNhcGFjaXR5ID0gIjw8IGluaXRpYWxDYXBhY2l0eSA8PCAiIE11c3QgYmUgPiAwIjs= CQl0aHJvdyBpbGxlZ2FsUGFyYW1ldGVyVmFsdWUocy5zdHIoKSk7 CX1= CWZpcnN0Tm9kZSA9IE5VTEw7 CWxpc3RTaXplID0gMDt= fc== dGVtcGxhdGUgPHR5cGVuYW1lIFQ+ Y2hhaW48VD46OmNoYWluKGNvbnN0IGNoYWluPFQ+JiB0aGVMaXN0KXv= CWxpc3RTaXplID0gdGhlTGlzdC5saXN0U2l6ZTt= CWlmIChsaXN0U2l6ZSA9PSAwKX== CXv= CQlmaXJzdE5vZGUgPSBOVUxMO0== CQlyZXR1cm47 CX0= CWNoYWluTm9kZTxUPiogc291cmNlTm9kZSA9IHRoZUxpc3QuZmlyc3ROb2RlO1== CWZpcnN0Tm9kZSA9IG5ldyBjaGFpbk5vZGU8VD4oc291cmNlTm9kZS0+ZWxlbWVudCk7 CXNvdXJjZU5vZGUgPSBzb3VyY2VOb2RlLT5uZXh0O7== CWNoYWluTm9kZTxUPiogdGFyZ2V0Tm9kZSA9IGZpcnN0Tm9kZTt= CXdoaWxlKHNvdXJjZU5vZGUgIT0gTlVMTCl7 CQl0YXJnZXROb2RlLT5uZXh0ID0gbmV3IGNoYWluTm9kZTxUPihzb3VyY2VOb2RlLT5lbGVtZW50KTt= CQl0YXJnZXROb2RlID0gdGFyZ2V0Tm9kZS0+bmV4dDu= CQlzb3VyY2VOb2RlID0gc291cmNlTm9kZS0+bmV4dDs= CX1= CXRhcmdldE5vZGUtPm5leHQgPSBOVUxMOz== fS== dGVtcGxhdGUgPHR5cGVuYW1lIFQ+ Y2hhaW48VD46On5jaGFpbigpe2== CXdoaWxlKGZpcnN0Tm9kZSAhPSBOVUxMKXu= CQljaGFpbk5vZGU8VD4qIG5leHROb2RlID0gZmlyc3ROb2RlLT5uZXh0O1== CQlkZWxldGUgZmlyc3ROb2RlO7== CQlmaXJzdE5vZGUgPSBuZXh0Tm9kZTu= CX1= fZ== dGVtcGxhdGUgPHR5cGVuYW1lIFQ+ VCYgY2hhaW48VD46OmdldChpbnQgdGhlSW5kZXgpIGNvbnN0e9== CWNoZWNrSW5kZXgodGhlSW5kZXgpO/== CWNoYWluTm9kZTxUPiogY3VycmVudE5vZGUgPSBmaXJzdE5vZGU7 CWZvcihpbnQgaSA9IDA7IGkgPCB0aGVJbmRleDsgKytpKXt=
0x03 解密脚本 根据Base64的填充规则,向填充位读出隐藏信息。
相应脚本deStego.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import base64import sysdef deStego (stegoFile ): b64table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" with open (stegoFile,'r' ) as stegoText: message = "" for line in stegoText: try : text = line[line.index("=" ) - 1 :-1 ] message += "" .join([ bin ( 0 if i == '=' else b64table.find(i))[2 :].zfill(6 ) for i in text])[2 if text.count('=' ) ==2 else 4 :6 ] except : pass return "" .join([chr (int (message[i:i+8 ],2 )) for i in range (0 ,len (message),8 )]) if __name__ == "__main__" : if len (sys.argv) == 2 : print (deStego(sys.argv[1 ])) else : print (deStego("stego.txt" ))
使用方法:
1 2 ❯ python3 deStego.py stego.txt flag{base64_1s_Ama2ing}
得到flag