{"id":182,"date":"2020-03-26T12:13:00","date_gmt":"2020-03-26T12:13:00","guid":{"rendered":"https:\/\/certitude.consulting\/blog\/?p=182"},"modified":"2021-01-26T12:15:25","modified_gmt":"2021-01-26T12:15:25","slug":"analysis-of-crypto-used-by-appveyor-secure-variables","status":"publish","type":"post","link":"https:\/\/certitude.consulting\/blog\/en\/analysis-of-crypto-used-by-appveyor-secure-variables\/","title":{"rendered":"Analysis of Crypto used by AppVeyor Secure Variables"},"content":{"rendered":"\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"500\" height=\"384\" src=\"https:\/\/certitude.consulting\/blog\/wp-content\/uploads\/2021\/01\/cbc.png\" alt=\"\" class=\"wp-image-243\" srcset=\"https:\/\/certitude.consulting\/blog\/wp-content\/uploads\/2021\/01\/cbc.png 500w, https:\/\/certitude.consulting\/blog\/wp-content\/uploads\/2021\/01\/cbc-300x230.png 300w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/figure><\/div>\n\n\n\n<p>We recently investigated AppVeyor\u2019s \u201csecure variables\u201d (aka \u201cEncrypt YAML\u201d) feature. We wanted to understand the crypto and algorithms it uses (which is not documented at the time of this writing) and discovered a few interesting things, which we describe in this blog post.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">AppVeyor Secure Variables<\/h2>\n\n\n\n<p>AppVeyor is a build software that is available on-premise or in the cloud. AppVeyor can be connected to a (public) source code repository, such as your GitHub repository, and be configured to automatically build a new version of the software whenever code in the repository is changed. The AppVeyor build configuration file (appveyor.yml) can also be checked in to a source code repository to make use of its collaboration and versioning features.<\/p>\n\n\n\n<p>However, certain information in this appveyor.yml file might be sensitive (e.g. access credentials to other systems or services required during the build) and should not be visible to all developers (or to everyone in case of open source projects). The AppVeyor secure variables feature allows you to encrypt sensitive data before putting it into the appveyor.yml file. So only AppVeyor can decrypt this data to obtain the original value and use it during the build process. These encrypted values can e.g. be used in the appveyor.yml in configurations for environment variables or within webhooks.<\/p>\n\n\n\n<p>The first thing to be aware of is that secure variables are only protected from users without write access to the appveyor.yml. <strong>Users with write access to this file can obtain the decrypted value. <\/strong>This can be done by e.g. just printing the secure variable to the build log (the secure variable is automatically decrypted by AppVeyor).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Secure Variable Encryption<\/h2>\n\n\n\n<p>We analyzed properties of the encryption of secure variables.<\/p>\n\n\n\n<p>We found out that the used cipher is a <strong>block cipher and has 128 bit (16 bytes) block size<\/strong>. This can be discovered by increasing the length of the plaintext. If the ciphertext length increases equally to the plaintext length, the used cipher is a stream cipher. If the ciphertext length increases in blocks, then it is a block cipher. In the case of a block cipher, one can easily find out the block length by observing the increase in length of the ciphertext.<\/p>\n\n\n\n<p>We did some further tests to find out more.<\/p>\n\n\n\n<p>Our test used the following secure variable (unencrypted):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Bearer SecretToken123456789012345678901234567890<\/code><\/pre>\n\n\n\n<p>The hexadecimal representation of this string is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>42 65 61 72 65 72 20 53 65 63 72 65 74 54 6F 6B\n65 6E 31 32 33 34 35 36 37 38 39 30 31 32 33 34\n35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30<\/code><\/pre>\n\n\n\n<p>When using the Encrypt YAML feature for this variable, AppVeyor returns the following Base64-encoded encrypted string:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>FVwaQuowgIbDmPo987vdYrmGEHeelN7l6ni8MTzouU3jtrE8\/9w6tYSuq84DHJbXhMQKpxqfZOTRIH0g\/flKjg==<\/code><\/pre>\n\n\n\n<p>After Base64 decoding, the hex representation is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>15 5C 1A 42 EA 30 80 86 C3 98 FA 3D F3 BB DD 62\nB9 86 10 77 9E 94 DE E5 EA 78 BC 31 3C E8 B9 4D\nE3 B6 B1 3C FF DC 3A B5 84 AE AB CE 03 1C 96 D7\n84 C4 0A A7 1A 9F 64 E4 D1 20 7D 20 FD F9 4A 8E<\/code><\/pre>\n\n\n\n<p>Here we can already see that our encrypted ciphertext has 16 bytes more than the plaintext. This is probably due to padding and allows us to infer that the <strong>block size of the ciphertext is 16 bytes<\/strong>.<\/p>\n\n\n\n<p>To find out more about block size and the mode of operation, we modified the following bytes of the ciphertext:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>15 5C 1A 42 EA 30 80 86 C3 98 FA 3D F3 BB DD 62\nB9 86 11 77 9E 94 DE E5 EA 78 BC 31 3C E8 B9 4D\nE3 B6 B1 3C FF DC 3A B5 84 AE AB CE 03 1C 96 D7\n84 C4 0A A7 1A 9F 64 E4 D1 20 7D 20 FD F9 4A 8E<\/code><\/pre>\n\n\n\n<p>This ciphertext decrypted to the following value:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Bearer SecretTokL        Q4\u2592u5i?y\u2592\u2592'15668901234567890<\/code><\/pre>\n\n\n\n<p>The hexadecimal representation of this string is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>42 65 61 72 65 72 20 53 65 63 72 65 74 54 6F 6B\n4C 09 51 34 FD 75 35 16 69 3F 79 FD FD 27 31 1C\n35 36 36 38 39 30 31 32 33 34 35 36 37 38 39 30<\/code><\/pre>\n\n\n\n<p>We can see that a change of the third byte in the second ciphertext block changed the whole second plaintext block and the third byte of the next plaintext block. This perfectly matches the behavior of the <strong>cipher mode CBC<\/strong> as displayed in the following figure:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/images.squarespace-cdn.com\/content\/v1\/5d70aab8475df200010ac3bf\/1576321070727-Q616DLBHYU6SFQGNXNLQ\/ke17ZwdGBToddI8pDm48kPR0b9BLtkzwpbuy20bzW8lZw-zPPgdn4jUwVcJE1ZvWQUxwkmyExglNqGp0IvTJZUJFbgE-7XRK3dMEBRBhUpygMJ9xJk-4gpWoxodmZvkWgPeTNNleT6HXxWfAEer8vZHeq1fXGA5OgrxdJKUea_M\/cbc_dec_small.PNG?format=1000w\" alt=\"cbc_dec_small.PNG\"\/><\/figure>\n\n\n\n<p>Generally, in CBC a change in a byte of a ciphertext block at index X directly affects all bytes of the same ciphertext block and the byte at index X of the next ciphertext block. The observed behavior further confirms that the encryption algorithm is a block cipher with 16 bytes length.<\/p>\n\n\n\n<p>Our test didn&#8217;t lead to an error but decrypted normally. From that we can infer that the<strong> ciphertext is not integrity protected<\/strong>.<\/p>\n\n\n\n<p>In many cases missing integrity protection has security implications. In combination with the CBC cipher mode, this can result in so called \u201cPadding Oracle\u201d attacks. These attacks exploit the lack of integrity protection and some properties of CBC mode and PKCS#7 padding and allow attackers to fully or partially decrypt ciphertext!<\/p>\n\n\n\n<p>This means, AppVeyor might be vulnerable to Padding Oracle attacks. Notably, as laid out at the beginning of the post, anyone with write access to the appveyor.yml can decrypt values by design. <strong>Thus, a Padding Oracle would have no security implications in AppVeyor<\/strong>. Nevertheless, for more curious readers, we briefly describe our analysis of a potential Padding Oracle in AppVeyor.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Padding Oracle in AppVeyor<\/h2>\n\n\n\n<p>To be able to exploit a Padding Oracle, one must obtain a valid ciphertext and be able to provide arbitrary ciphertext to the decryption system. Furthermore, it must be possible to distinguish the following cases (e.g. by different error message, by timing, or other means) when decrypting ciphertext:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>A given ciphertext decrypts to a valid plaintext<\/li><li>A given ciphertext decrypts to a malformed plaintext (e.g. with non-ASCII characters) and has valid padding<\/li><li>A given ciphertext has invalid padding<\/li><\/ol>\n\n\n\n<p>This information, combined with the knowledge of how CBC and PKCS#7 work and some basic logic, is enough for an attacker to decrypt most of a given ciphertext. To confirm the existence or non-existence of a potential Padding Oracle in AppVeyor, we performed the following tests.<\/p>\n\n\n\n<p>We used a secure variable (the Bearer-token from above) to let AppVeyor authenticate against our web server. On the web server we received:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>POST \/ HTTP\/1.1\nAuthorization: Bearer SecretToken123456789012345678901234567890\nContent-Type: application\/json; charset=utf-8\nHost: 54.69.243.156:8000\nContent-Length: 8858\nConnection: Keep-Alive<\/code><\/pre>\n\n\n\n<p>This matches the behavior of case 1.<\/p>\n\n\n\n<p>We then modified the third byte of the second block and again let AppVeyor authenticate against our web server. This time we received:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>POST \/ HTTP\/1.1\nAuthorization: Bearer SecretTokL        Q4\u2592u5i?y\u2592\u2592'15668901234567890\nContent-Type: application\/json; charset=utf-8\nHost: 54.69.243.156:8000\nContent-Length: 8860\nConnection: Keep-Alive<\/code><\/pre>\n\n\n\n<p>This matches the behavior of case 2.<\/p>\n\n\n\n<p>Lastly, we crafted a ciphertext that causes bad padding. For that we changed the last byte of the third block. Due to CBC mode, this change should not only scramble the third block, but also change the last byte of the fourth block, which is our padding. Since padding needs to have a specific structure in PKCS#7, this change should cause incorrect padding. We used the following ciphertext:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>15 5C 1A 42 EA 30 80 86 C3 98 FA 3D F3 BB DD 62\nB9 86 10 77 9E 94 DE E5 EA 78 BC 31 3C E8 B9 4D\nE3 B6 B1 3C FF DC 3A B5 84 AE AB CE 03 1C 96 00\n84 C4 0A A7 1A 9F 64 E4 D1 20 7D 20 FD F9 4A 8E<\/code><\/pre>\n\n\n\n<p>With this ciphertext we let AppVeyor authenticate against our web server one last time. The result was:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>POST \/ HTTP\/1.1\nContent-Type: application\/json; charset=utf-8\nHost: 54.69.243.156:8000\nContent-Length: 8840\nConnection: Keep-Alive<\/code><\/pre>\n\n\n\n<p>This matches the behavior of case 3.<\/p>\n\n\n\n<p>Is this a problem? Yes, it is! Because this behavior exactly matches the definition of a Padding Oracle. An attacker could now continue this attack as described in <a href=\"https:\/\/robertheaton.com\/2013\/07\/29\/padding-oracle-attack\/\" target=\"_blank\" rel=\"noreferrer noopener\">this blog post<\/a> and could obtain most or all of the plaintext from the ciphertext. Particularly, if an attacker knows the initialization vector, he\/she can obtain all of the plaintext. If an attacker doesn&#8217;t know the initialization vector, he\/she could obtain the plaintext for the whole ciphertext except the first ciphertext block. However, in many cases the first ciphertext block can be guessed or obtained from the system.<\/p>\n\n\n\n<p>As mentioned before, due to the design of the secure variables feature altogether, there seem to be no security implications of this issue in AppVeyor.<\/p>\n\n\n\n<p>Conclusively, in this article we showed:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>How AppVeyor&#8217;s secure variables work.<\/li><li>The encryption used for secure variables.<\/li><li>How this encryption mode and lack of integrity protection can, in principle, lead to Padding Oracle attacks that allow the decryption of most or all of the ciphertext.<\/li><\/ul>\n\n\n\n<p>This analysis was performed in cooperation with Daniel Ostovary from <a href=\"https:\/\/www.signpath.io\/\" target=\"_blank\" rel=\"noreferrer noopener\">SignPath<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>We recently investigated AppVeyor\u2019s \u201csecure variables\u201d (aka \u201cEncrypt YAML\u201d) feature. We wanted to understand the crypto and algorithms it uses (which is not documented at the time of this writing) and discovered a few interesting things, which we describe in this blog post. AppVeyor Secure Variables AppVeyor is a build software that is available on-premise [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":243,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[60,103],"tags":[110,94,111,84],"class_list":["post-182","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-technical-analysis","category-vulnerability-research-en","tag-appveyor","tag-cryptography","tag-padding-oracle","tag-vulnerability"],"_links":{"self":[{"href":"https:\/\/certitude.consulting\/blog\/wp-json\/wp\/v2\/posts\/182","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/certitude.consulting\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/certitude.consulting\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/certitude.consulting\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/certitude.consulting\/blog\/wp-json\/wp\/v2\/comments?post=182"}],"version-history":[{"count":3,"href":"https:\/\/certitude.consulting\/blog\/wp-json\/wp\/v2\/posts\/182\/revisions"}],"predecessor-version":[{"id":245,"href":"https:\/\/certitude.consulting\/blog\/wp-json\/wp\/v2\/posts\/182\/revisions\/245"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/certitude.consulting\/blog\/wp-json\/wp\/v2\/media\/243"}],"wp:attachment":[{"href":"https:\/\/certitude.consulting\/blog\/wp-json\/wp\/v2\/media?parent=182"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/certitude.consulting\/blog\/wp-json\/wp\/v2\/categories?post=182"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/certitude.consulting\/blog\/wp-json\/wp\/v2\/tags?post=182"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}