<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Sw33tBit on Medium]]></title>
        <description><![CDATA[Stories by Sw33tBit on Medium]]></description>
        <link>https://medium.com/@bitr13x?source=rss-6c5b2c01614b------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*KleSr2aPq6nfvojQuTLWGw.png</url>
            <title>Stories by Sw33tBit on Medium</title>
            <link>https://medium.com/@bitr13x?source=rss-6c5b2c01614b------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Thu, 28 May 2026 17:08:29 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@bitr13x/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Everything worth knowing about identity providers: OAuth and OpenID Connect]]></title>
            <link>https://medium.com/@bitr13x/everything-worth-knowing-about-identity-providers-oauth-and-openid-connect-7a720bae73b1?source=rss-6c5b2c01614b------2</link>
            <guid isPermaLink="false">https://medium.com/p/7a720bae73b1</guid>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[information-security]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <dc:creator><![CDATA[Sw33tBit]]></dc:creator>
            <pubDate>Thu, 01 Jan 2026 00:44:12 GMT</pubDate>
            <atom:updated>2026-01-01T14:42:15.187Z</atom:updated>
            <content:encoded><![CDATA[<p>This article defines identity providers (IdPs) and demonstrates how they function by constructing an OpenID connect (OIDC) from scratch. In addition, identify common potential weaknesses that might happen.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/900/0*Hf-wkrfJB2Wh8Gbz.png" /></figure><p>To avoid confusion, it is best to mention a little something about terminology:</p><p>Authentication: when user sign in without any privileges<br>Authorization: we assign the user privileges (write/read)<br>Client: usually is referred to an API or website that is trying to use the IDP</p><p>Keep in mind that my code does not have to be the best of the best, and you may be able to do better. I demonstrated how to easily integrate this technology into your tech stack.</p><p>if you are just looking for the full code:<br><a href="https://github.com/BitR13x/idp_provider">https://github.com/BitR13x/idp_provider</a></p><h3><strong>So what is that?</strong></h3><p>Have you ever heard of Single Sign-On (SSO), which uses Google, GitHub, and other services? That is essentially what OAuth and OpenID Connect are.</p><p>OAuth is an industry standard for authorizing a user to access third-party software. In other words, the user does not have to sign in several times with the same password to utilize each service.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*BOw7rMADsc79KCM2Tsy4xw.png" /><figcaption>Simplified flow of authentication/authorization</figcaption></figure><p>This diagram depicts how the login is done in a basic manner; we are attempting to redirect authentication to (identity) provider.</p><h4>Difference between OAuth vs OIDC</h4><p>OAuth 2.0 (Authorization): Handles “What can you do?”</p><ul><li>You do not care about the user it self, you only care about what they can do.</li></ul><p>OIDC (Authentication): Handles “Who are you?”</p><ul><li>OIDC is extended OAuth, you care about the user, who is it?</li><li>Authentication + Authorization</li></ul><h3>How it really works?</h3><p>We will start from the login button:</p><p>1) Redirect</p><ul><li>The process begins when a user clicks “Login.”</li><li>Your application (client) doesn’t ask for a password. Instead, it redirects the user’s browser away from site to the OpenID Connect Provider (IdP).</li><li>User will login as usual</li></ul><p>2) Callback</p><ul><li>Once the user successfully logs in and approves the request</li><li>The IdP redirects the browser to a specific URL on your server — usually defined as /callback.</li><li>Attached to this URL is a short-lived (This code is not a key)</li></ul><p>3) Code for Token</p><ul><li>The application (client) sends code to the IdP and IdP sends back access token.</li></ul><p>4) Access Token</p><ul><li>With this token you can access the API’s</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*PWLNCLPGCHzTADOvLE7m8g.png" /><figcaption>Diagram showing described flow</figcaption></figure><p>Perhaps you are wondering why we do not return the access token right away?</p><p>The difficulty is that you need to notify the program (client) that you have completed login, which is why the callback is required.</p><p>Why not append the access token directly to the URL? It is possible, but it is considered a security risk because it can be spoof, which is why an AuthCode is issued that is only valid for a certain time.</p><h3>Options for implementation</h3><h4>A few words on current options:</h4><ul><li>SaaS (Auth0, Okta, AWS Cognito)</li><li>Open Source (Keycloak, Ory Hydra)</li></ul><h4>Access tokens:</h4><p>Opaque Tokens — “Reference Tokens”</p><ul><li>The string is simply a pointer to a record in the database.</li></ul><p>Most providers give <strong>JWTs</strong> (JSON Web Tokens), which is why we will concentrate on them.</p><p>Here is an example of the token_id sent to the client:</p><pre>{<br>  &quot;iss&quot;: &quot;https://idp.example.com&quot;,<br>  &quot;sub&quot;: &quot;user_id&quot;,<br>  &quot;aud&quot;: &quot;client&quot;,<br>  &quot;exp&quot;: 1735689600,<br>  &quot;iat&quot;: 1735686000,<br>  &quot;nbf&quot;: 1735686000,<br>  &quot;jti/nonce&quot;: &quot;e9c1a2f4&quot;<br>}</pre><p>Jti, or nonce, protects against replay attacks (re-use of the same token); nonce is used to identify each token and is commonly used as a “kill switch”.</p><ul><li><strong>exp</strong> (expiration)</li><li><strong>iat</strong> (issued at)</li><li><strong>nbf</strong> (not valid before)</li></ul><h4>Login Page</h4><p>One option for smaller infrastructures is to build a login directly on the client and use the IdP as a “Auth provider.” This is less scalable than the standard approach of building a single login page for the IdP and redirecting the client to it.</p><h3>Implementation of IdP in elysia</h3><p>We will be focusing mostly on IdP endpoints because there are numerous methods for implementing database systems or deployments, among other things.</p><p>To begin, it is good practice to make explanation route:</p><pre>    .get(&#39;/.well-known/openid-configuration&#39;, () =&gt; {<br>        const issuer = config.oidc.issuer;<br>        return {<br>            issuer: issuer,<br>            authorization_endpoint: `${issuer}/authorize`,<br>            token_endpoint: `${issuer}/token`,<br>            userinfo_endpoint: `${issuer}/userinfo`,<br>            jwks_uri: `${issuer}/.well-known/jwks.json`,<br>            id_token_signing_alg_values_supported: [&#39;RS256&#39;],<br>            scopes_supported: [&#39;openid&#39;, &#39;default&#39;]<br>        };<br>    })</pre><p>This will introduce our routes, letting the client know where to authorize and obtain tokens.</p><p>Our goal will be implement these routes.</p><p>We’ll need to begin with:</p><h4>Token implementation</h4><p>JWT tokens use a variety of transportation algorithms, most notably HS256 and RS256.</p><p><strong>HS256</strong> is symmetrical and uses a simple <strong>secret</strong> to verify and decode, making it perfect for application authentication (which we will use later).</p><p><strong>RS256</strong>, on the other hand, uses <strong>public/private</strong> keys, which are required for cross-application verification; we simply generate these keys and disclose the public key.</p><pre># generating private/public key<br>openssl genpkey -algorithm RSA -out private.pem -pkeyopt rsa_keygen_bits:2048<br>openssl rsa -pubout -in private.pem -out public.pem</pre><pre>import * as jose from &#39;jose&#39;;<br>import { readFileSync } from &#39;fs&#39;;<br>import { join } from &#39;path&#39;;<br>import { config } from &#39;../config&#39;;<br><br>let privateKey: jose.KeyObject;<br>let publicKey: jose.KeyObject;<br>let jwks: { keys: jose.JWK[] };<br><br>export async const initializeKeys = () =&gt; {<br>    const privateKeyPath = join(import.meta.dir, &#39;../config/private.pem&#39;);<br>    const publicKeyPath = join(import.meta.dir, &#39;../config/public.pem&#39;);<br><br>    const privateKeyPEM = readFileSync(privateKeyPath, &#39;utf8&#39;);<br>    const publicKeyPEM = readFileSync(publicKeyPath, &#39;utf8&#39;);<br><br>    privateKey = await jose.importPKCS8(privateKeyPEM, &#39;RS256&#39;);<br>    publicKey = await jose.importSPKI(publicKeyPEM, &#39;RS256&#39;);<br><br>    const jwk = await jose.exportJWK(publicKey);<br>    jwk.kid = config.oidc.jwt.kid;<br>    jwk.use = &#39;sig&#39;;<br>    jwk.alg = &#39;RS256&#39;;<br><br>    jwks = {<br>        keys: [jwk]<br>    };<br>};<br><br>export const getPrivateKey = () =&gt; {<br>    return privateKey;<br>};<br><br>export const getJWKS = () =&gt; {<br>    return jwks;<br>};</pre><pre>    .get(&#39;/.well-known/jwks.json&#39;, () =&gt; {<br>        return getJWKS();<br>    })</pre><p>With that done we need to implement the authorize route:</p><h4>Authorize</h4><p>Here we need to define our database tables:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/333/1*zSK_RTmuAj0cBbZ2zxH-_Q.png" /><figcaption>Database tables</figcaption></figure><p>There isn’t much to surprise here. All we need to do for the client is declare the redirect URLs; otherwise, another vulnerability known as open redirect would occur.</p><p>This route must generate the AuthCode and return it to the callback, but we must ensure that everything we receive is correct.</p><p>Client:</p><pre>        const client = await clientRepo.findOneBy({ id: client_id });<br><br>        if (!client) {<br>            return status(400, &quot;Invalid client_id&quot;);<br>        }<br>        if (!client.redirect_uris.includes(redirect_uri)) {<br>            return status(400, &quot;Invalid redirect_uri&quot;);<br>        }</pre><p>User and scope</p><pre>        const requestedScopes = (scope || &#39;&#39;).split(&#39; &#39;);<br>        const allowed = requestedScopes.every(s =&gt; client.allowed_scopes.includes(s));<br>        if (!allowed) return status(400, &quot;Invalid scope&quot;);<br><br>        if (!user) {<br>            const currentUrl = request.url;<br>            return redirect(`/login?return_to=${encodeURIComponent(currentUrl)}`);<br>        };</pre><p>And define model:</p><pre>    .get(&#39;/authorize&#39;, async ({ query: { client_id, redirect_uri, scope, state, nonce }, redirect, status, user, request }) =&gt; {<br>        const clientRepo = AppDataSource.getRepository(Client);<br>        ...<br><br>        const code = uuidv4();<br>        await AuthCode.create({...}).save();<br>        ...<br><br>        // constructing url<br>        const redirectUrl = new URL(redirect_uri);<br>        redirectUrl.searchParams.set(&#39;code&#39;, code);<br>        if (state) redirectUrl.searchParams.set(&#39;state&#39;, state);<br><br>        return redirect(redirectUrl.toString());<br>    }, {<br>        query: t.Object({<br>            client_id: t.String(),<br>            redirect_uri: t.String(),<br>            scope: t.Optional(t.String()),<br>            state: t.Optional(t.String()),<br>            nonce: t.Optional(t.String())<br>        })<br>    })</pre><p>Models in Elysia are checkers (specify what we require for that specific route) and can be simply connected to Swagger or Openapi (api documentation).</p><p>The state guards against Cross-Site Request Forgery (CSRF) attacks.</p><p>The client will transmit it to the IdP and then verify that it is correct.<br>And now that we have virtually everything, all we need to do is generate tokens.</p><h4>Token generation</h4><p>This route will also need to check for the proper client (client id, secret) and code that we received (if it exists, expiration date, and if matching client id).</p><pre>        // ID Token (OIDC)<br>        const idToken = await new jose.SignJWT({<br>            sub: authCode.user.id,<br>            name: authCode.user.username,<br>            email: authCode.user.email,<br>            nonce: authCode.nonce,<br>            aud: client_id,<br>            iss: issuer,<br>        })<br>            .setProtectedHeader({ alg: &#39;RS256&#39;, kid: config.oidc.jwt.kid })<br>            .setIssuedAt()<br>            .setExpirationTime(config.oidc.jwt.idTokenExpiration)<br>            .sign(privateKey);<br><br>        // Access Token (OAuth2)<br>        const accessToken = await new jose.SignJWT({<br>            sub: authCode.user.id,<br>            scope: authCode.scope,<br>            aud: api_aud,<br>            iss: issuer<br>        })<br>            .setProtectedHeader({ alg: &#39;RS256&#39;, kid: config.oidc.jwt.kid })<br>            .setIssuedAt()<br>            .setExpirationTime(config.oidc.jwt.accessTokenExpiration)<br>            .sign(privateKey);</pre><p>This code is the main element of the route. It generates the tokens that the API will check using our public key, therefore we must sign it with our private key and set the appropriate parameters.</p><p>The ID token is intended for the front-end, whereas the access token grants us access to APIs.</p><p>However, you may have noticed that we only received a single aud for the access token, and we would need to repeat the authentication process, you are right.</p><p>We have several approaches that we can take:</p><ul><li>Super Token (listed as aud)</li><li>Separate Tokens (using the refresh token)</li></ul><p>The verification methodology for a refresh token is the same as for code; the refresh token is generated during the phase in which you get correct code.</p><pre>if (code) {<br>   ... // handle code<br>   remove code<br>} else if (refresh_token) {<br>   ... // handle refresh_token<br>   remove refresh_token<br>} else {<br>   return status(400, { error: &quot;unsupported_grant_type&quot; });<br>};<br><br>// generate access_token + token_id + refresh_token</pre><p>For sake of simplicity we will not focus on the this problem.</p><p>And instead use this version:</p><pre>    .post(&#39;/token&#39;, async ({ body: { client_id, client_secret, code }, error, request }) =&gt; {<br>        // Validate Client<br>        ...<br><br>        // Validate Code<br>        const authCode = await AuthCode.findOne({ <br>            where: { code },<br>            relations: [&quot;user&quot;, &quot;client&quot;]<br>        });<br>        ...<br><br>        // Generate Tokens<br>        ...<br>        await codeRepo.remove(authCode);<br><br>        return {<br>            access_token: accessToken,<br>            id_token: idToken,<br>            token_type: &#39;Bearer&#39;,<br>            expires_in: 7200<br>        };<br>    }, {<br>        body: t.Object({<br>            client_id: t.String(),<br>            client_secret: t.String(),<br>            code: t.String(),<br>            api_aud: t.String()<br>        })<br>    })</pre><p>We have now received a token on our client and may interact with the API.</p><p>The following path ‘/userinfo’, however it simply provides information about the logged user from the access_token, as the name implies.</p><p>There is still so-called “database garbage”. This is addressed via Expiration Management.</p><pre>DELETE FROM auth_code WHERE expiresAt &lt; NOW</pre><h3>API side of IdP</h3><p>We do not need to handle login/registration anymore; we can just focus on the tokens. We need to verify that the token is coming from the right source and that the signature is correct:</p><pre>import { createRemoteJWKSet, jwtVerify } from &#39;jose&#39;<br><br>export async function verifyAccessToken(token: string) {<br>  const JWKS = createRemoteJWKSet(<br>    new URL(`${ISSUER}/.well-known/jwks.json`)<br>  );<br><br>  const { payload } = await jwtVerify(token, JWKS, {<br>    issuer: ISSUER,<br>    audience: &#39;API-A&#39;<br>  })<br><br>  return payload<br>};</pre><p>We have now available this token:</p><pre>{<br>  sub: user.id,<br>  scope: scopes,<br>  aud: api_aud,<br>  iss: issuer<br>}</pre><p>Where issuer and audience is validated from “jose” library.</p><p>If you do not have access to these libraries, you must check the issuer and audience, and remember to get the public-key for signature verification from:</p><pre>const iss_url = `${ISSUER}/.well-known/jwks.json`</pre><p>We also set the protected-header during the token creation. This header contains:</p><ul><li><strong>alg</strong>: check protects against “alg: None” algorithm confusion attacks.</li><li><strong>kid</strong>: Token is using an anticipated key.</li><li><strong>type</strong>: token is the expected format.</li></ul><p>We now have the user’s ID, which we may manage as we see fit, as well as scope, which allows us to control what the user can do.</p><h3>Front-end side of IdP (React example)</h3><p>You must implement the ‘/callback’ that will receive the code and then send it to IdP via the ‘/token’ route.</p><p>With that, the login is completed.</p><p>It is quite basic. The only difficulty is that react uses DOM rendering, thus you need to use:</p><pre>window.location.pathname === &#39;/callback&#39;</pre><p>To decide if the current page is callback.<br>Redirect function that will be assigned on SSO button:</p><pre>export const loginWithRedirect = () =&gt; {<br>    const redirectUri = window.location.origin + &#39;/callback&#39;;<br>    const clientId = client_id;<br>    const audience = &#39;test_audience&#39;; // needs to match with API<br>    const scope = &#39;default&#39;;<br>    const responseType = &#39;code&#39;;<br><br>    const authUrl = `${IDP_VHOST}/authorize?` + <br>      `client_id=${encodeURIComponent(clientId)}&amp;` +<br>      `redirect_uri=${encodeURIComponent(redirectUri)}&amp;` +<br>      `response_type=${encodeURIComponent(responseType)}&amp;` +<br>      `scope=${encodeURIComponent(scope)}&amp;` +<br>      `audience=${encodeURIComponent(audience)}`;<br><br>    window.location.href = authUrl;<br>  }</pre><p>Main logic in the callback page will be just:</p><pre>const code = urlParams.get(&#39;code&#39;);<br>const response = await axios.post(`${IDP_VHOST}/token`, {<br>  client_id: client_id,<br>  client_secret: client_secret,<br>  code,<br>  api_aud: &#39;test_audience&#39;<br>});<br>const { access_token, id_token, refresh_token } = response.data;</pre><h3>Benefits</h3><ul><li>Scalable infrastructure (you can make several APIs operate together in harmony, leveraging the capabilities of frameworks)</li><li>Single Sign-On (SSO)</li></ul><h3>Disadvantages</h3><ul><li>Permissions require additional maintenance</li><li>Incorrect implementation may lead to vulnerabilities.</li></ul><h3>Attack surface in OAuth/OIDC</h3><p>Just a quick word on the topic of attack surface.</p><p>This topic is huge at it’s own we gone through a few of options already.</p><p>Identifying the attack surface is critical for assessing risk and determining where to hunt for vulnerabilities.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cgWtvJxFabM6l0-ZCwNqPg.png" /><figcaption>Diagram that shows part of attack surface</figcaption></figure><p>IdP can create a complex system where can be made a mistake pretty easily and it is good to know where to look for them.</p><h3>Conclusion</h3><p>Identity Providers built on OpenID standards play a huge role in modern digital ecosystems by delivering secure, interoperable, and user-centric authentication. By decoupling identity from individual applications.</p><p>OpenID-based IdPs reduce security risks in larger infrastucture, simplify access management, and enable seamless single sign-on across platforms. As organizations continue to adopt cloud services, APIs, and distributed architectures.</p><p>With everything said, you should be able to create your own IdP that can be used to integrate several applications and query them with a single login.</p><p>On top of that you know the most common vulnerabilies and why they can occure.</p><p>If you enjoyed this article, clap and follow me! Thanks for reading, and I wish you the best luck on your journey👋</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7a720bae73b1" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Google search engine: PageRank, webcrawling and own search engine for directories]]></title>
            <link>https://medium.com/@bitr13x/google-search-engine-pagerank-and-webcrawling-and-creating-own-search-engine-for-directories-052517cb2a3b?source=rss-6c5b2c01614b------2</link>
            <guid isPermaLink="false">https://medium.com/p/052517cb2a3b</guid>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[rankbrain]]></category>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[google]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Sw33tBit]]></dc:creator>
            <pubDate>Mon, 11 Aug 2025 10:35:03 GMT</pubDate>
            <atom:updated>2025-08-11T19:55:11.255Z</atom:updated>
            <content:encoded><![CDATA[<p>One of these days, I began to wonder how Google was able to establish itself as the most popular search engine, what is behind Google, and how he obtained such a large number of URLs.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/973/1*hf7j5I7jsVw5w1hkOQXhNA.png" /></figure><p>Behind google is complex system and there is lot of caching:</p><ul><li>Crawl + Index High-PageRank URLs</li><li>Preprocessing via LLMs (e.g., BERT, MUM)</li><li>Candidate Document Retrieval</li><li>Neural Matching &amp; RankBrain Filtering</li><li>Ranking Function (Weighted Scoring)</li></ul><p>And I’d like to start at the top and work my way down.</p><h3>One step at a time</h3><p>The first question I asked myself was how Google truly acquires the URLs, because crawling requires at least one URL and does not guarantee that you will get all URLs, and what if the missing URL has the solution you were searching for?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/566/0*S6bBXbIs4DrLAk9l" /></figure><p>Google uses a variety of sources, including seed URLs (gov, edu, and media), recursive crawling (link discovery — google bot), user contribution via API, and direct ingest from partner APIs or curated sources.</p><p>If we have pages we can search for information. Keyword matching was previously employed in a variety of ways, but Google now uses AI to determine what you’re looking for, such as <a href="https://backlinko.com/google-rankbrain-seo">RankBrain</a>, Neural Matching, and LLMs.</p><h3>Crawling</h3><p>Building your own bot to tour the internet is not a tough effort if you know how to use Python; all you have to do is request a URL and check for an element with a link, then do it recursively. It’s another story if you want it to be efficient and multi-threaded.</p><p>A good example of crawler is <a href="https://github.com/jaeles-project/gospider">gospider</a></p><h3>PageRank</h3><p>Google’s success can be attributed to the Markov chain, which is formed into PageRank.</p><p>By “formed,” I mean that it derives from a Markov chain and the key idea behind <strong>PageRank</strong> is to measure the importance of a webpage in simple words.</p><p>The difference between them is that transition probability is calculated from links and teleportation step (don’t worry, it’s math, but not that difficult).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/902/1*oxAbAjEHlRZdYjH0ScmFFg.png" /><figcaption>Graph of websites (A-F)</figcaption></figure><p><strong>Transition probability</strong> is declared by outgoing links.<br>When we look at page “A”, we can see that page has 2 outgoing links so the transition probability row is:</p><p>** A - B - C - D - E - F<br>A: [0, .5, 0.5, 0, 0, 0]</p><p>For example: P(B|A) = 1/N = 1/2 = 0.5</p><p>why 0s, because the probability of getting for example to the page A is 0.</p><p>Full transition probability matrix would look like this:</p><pre>     A    B    C     D    E    F<br>A [  0,  0.5, 0.5,   0,   0,   0 ]<br>B [  0,    0, 0.5, 0.5,   0,   0 ]<br>C [  1,    0,   0,   0,   0,   0 ]<br>D [  0,    0, 0.5,   0, 0.5,   0 ]<br>E [  0,    0, 0.5,   0,   0, 0.5 ]<br>F [  0,    0, 1.0,   0,   0,   0 ]</pre><p><strong>Page rank vector</strong> (π) is declared by random state, because after while it converges(reach) to a number, size of page rank vector is number of pages.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/294/1*6mb4V0pEzSsnM0BvKimG_w.png" /><figcaption>Formula for PageRank</figcaption></figure><p>Where next iteration of rank vector is dot product (previous state and transition probability).</p><p>This is calculated until change is lower then tolerable threshold.</p><h4>Teleportation</h4><p>With that explained, there is one more tiny thing to perform to solve problems such as a person becoming stranded on the internet or sporadically switching pages.</p><p>During the calculating procedure, there is a random state known as the dumping factor.</p><p>P’ = αP + (1 — α)E<br>where:<br>- E = matrix where elements “1/N” (size of P)<br>- α = dumping factor usually “0.85”<br>- P = transition probability</p><p>If you are interested in seeing more or just formal explanation about PageRank I recommend <a href="https://www.youtube.com/watch?v=JGQe4kiPnrU">this video</a>.</p><p>Note a little bit out of context: do not get stuck at the idea of just the webpage, <a href="https://www.youtube.com/watch?v=KZeIEiBrT_w">Markov chain</a> is powerful thing and is also used in AI for predicting next word. If you understand PageRank then you understand Markov chain.</p><h3>RankBrain</h3><p>RankBrain is one of Google’s top 3 ranking factors (along with backlinks[PageRank] &amp; content relevance,).</p><p>In high point of view you can see search like this:</p><blockquote>Query → Query Interpretation (vectorization, context) → Search Similar → Rank → Return</blockquote><p><strong>RankBrain</strong> cooperates with <strong>LLM</strong> (BART or similar), RankBrain will <strong>calculate similarity</strong> to reduce number of results and forward it into the LLM to find perfect match.</p><p>To understand more and apply this knowledge, I chose to create a custom file search that uses RankBrain and LLM to match correct files or directories.</p><p>As our small RankBrain I will be using <a href="https://github.com/facebookresearch">FAISS</a> (<strong>Facebook AI Similarity Search</strong>), it is a library for fast nearest-neighbor search in large vector collections.</p><p>This library include two approaches on searching the large vector collection:</p><ul><li>IndexFlatIP: Exact search using <strong>dot product</strong> similarity.</li><li>IndexHNSWFlat: Approximate search using <strong>Hierarchical Navigable Small World (HNSW)</strong> graphs with flat storage.</li></ul><p>The main idea behind is that FlatIP is focused on accuracy and HNSWFlat is focused on speed.</p><p>next on the list is LLM, this LLM needs to be focused on ranking (giving score for a match) for this I choose CrossEncoder specially model ms-marco-MiniLM-L-6-v2 .</p><h3>Applying this knowledge to create custom file search</h3><p>Whole project can be found on github <a href="https://github.com/BitR13x/MiniRankBrain">here</a>.</p><p>I started with classic file retrieval and used docs to create script that look like this:</p><pre>from sentence_transformers import SentenceTransformer, CrossEncoder<br>import faiss<br>import numpy as np<br><br><br># Load sample documents<br>def read_files_from_dir(dir_path: str):<br>    for root, _, files in os.walk(dir_path):<br>        for file in files:<br>            yield root + &quot;/&quot; + file<br><br><br>dir_path = os.environ[&#39;HOME&#39;]<br>documents = [file for file in read_files_from_dir(dir_path)]<br><br># Encode documents<br>encoder = SentenceTransformer(&#39;all-MiniLM-L6-v2&#39;)<br>doc_vectors = encoder.encode(documents, normalize_embeddings=True)<br><br># Create FAISS index<br>dimension = doc_vectors.shape[1]<br>index = faiss.IndexFlatIP(dimension)<br>index.add(doc_vectors)<br>doc_map = {i: doc for i, doc in enumerate(documents)}<br><br><br>def search_docs(request):<br>    query_vector = encoder.encode([request.query], normalize_embeddings=True)<br>    D, I = index.search(np.array(query_vector), request.top_k)<br><br>    candidates = [doc_map[i] for i in I[0]]<br>    pairs = [(request.query, doc) for doc in candidates]<br>    scores = cross_encoder.predict(pairs)<br><br>    reranked_docs = [doc for _, doc in sorted(zip(scores, candidates), reverse=True)]<br><br>    return QueryResponse(query=request.query, results=reranked_docs)<br><br>print(search_docs({query: &quot;idek attachments&quot;}))</pre><h4>Reading files and directories</h4><p>Quickly I realized kind of hard or impossible problem to solve “performance”, because looping home directory isn’t that good idea as I thought.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*npjOxoJbJXjp0SM4lbDLgA.png" /><figcaption>Number of files in my home directory</figcaption></figure><p>We will be looping around millions of files and we are still in python even in C/++, rust and in other high performance language it still takes around 25 seconds to loop the files and we do not only want to loop it but also encode it into vectors. Well it’s a great start I guess.</p><p>So clearly we need to be more smarter then looping though home directory we need relevance, multiprocessing and caching.</p><p>So I started with the <em>read_directories </em>function that will loop directories when I look back I should just recreate it in C and import it into python, but end up with a much more faster version (compared to single threaded in python) that is using multiprocessing:</p><pre>def read_dirs_from_dir(dir_path: str, max_workers=8):<br>    &quot;&quot;&quot;Yield directories under dir_path as soon as they are found.&quot;&quot;&quot;<br>    base_path = Path(dir_path)<br>    with ThreadPoolExecutor(max_workers=max_workers) as executor:<br>        futures = {executor.submit(scan_dirs, base_path): base_path}<br><br>        while futures:<br>            for future in as_completed(futures.keys()):<br>                futures.pop(future)<br>                try:<br>                    subdirs = future.result()<br>                except OSError:<br>                    # future does not exist<br>                    continue<br><br>                for subdir in subdirs:<br>                    yield str(subdir)<br>                    futures[executor.submit(scan_dirs, subdir)] = subdir</pre><p>Then implemented with similar logic <em>read_files</em> function, but I wanted to add some context to them, so I read 200 bytes from the file, and if it’s a programming language file, I get a function list using regex:</p><pre>def read_n_bytes_from_file(file_path: Path, n: int) -&gt; bytes:<br>    try:<br>        with file_path.open(&quot;rb&quot;) as f:<br>            return f&quot;{str(file_path)}: {f.read(n).decode(&#39;utf-8&#39;, errors=&#39;ignore&#39;)}&quot;<br>    except OSError:<br>        # binary file (cannot decode bytes)<br>        return f&quot;{str(file_path)}: &#39;&#39;&quot;<br><br><br>def process_file(file_path: Path) -&gt; tuple[str, str]:<br>    &quot;&quot;&quot;Return (file_path, text).&quot;&quot;&quot;<br>    ext = file_path.suffix.lstrip(&quot;.&quot;).lower()<br>    regex = COMPILED_PATTERNS.get(ext)<br>    if regex:<br>        return str(file_path), extract_functions_from_file(file_path, regex, ext)<br>    else:<br>        return read_n_bytes_from_file(file_path, 200)</pre><h4>Caching, batching and indexing</h4><p>Okay from this point we got some solid functions for reading files, but we will have memory issues when it comes to large lists of files. So next is caching, I end up creating sqlite3 database.</p><pre>def create_connection(database_path: str = &quot;documents.db&quot;, first_time: bool = False):<br>    cx = sqlite3.connect(database_path)<br>    cu = cx.cursor()<br>    cu.execute(&quot;ATTACH DATABASE &#39;cache.db&#39; AS cache&quot;)<br>    if first_time:<br>        clear_cache(cu, clear_all=True)<br>        create_cache(cu)<br>    return cx, cu<br></pre><p>definitely I didn’t planning to open connecting for every file/directory found So the next step is to break the files/directories into batches and then enter them into the database using pickle and base64; during this process, I also began indexing them in the FAISS index.</p><pre># init cache<br>cx, cu = create_connection(first_time=True)<br>cx.close()<br><br>def index_strings(encoder, dir_path: str, table: str, read_func, index, batch_size=3000, max_workers=8):<br>    &quot;&quot;&quot;indexing in parallel with FAISS&quot;&quot;&quot;<br>    def save_and_clear():<br>        vectors = encoder.encode(batch_buffer, normalize_embeddings=True)<br>        index.add(np.array(vectors, dtype=np.float32))<br><br>        # cache - 3000<br>        cx, cu = create_connection()<br>        <br>        # just database query insert to table<br>        insert_cache(cx, cu, b64e(pickle.dumps(batch_buffer)), table)<br>        cx.close()<br><br>        batch_buffer.clear()<br><br>        # run garbage collection after batch<br>        gc.collect()<br><br>    batch_buffer = []<br><br>    for string in read_func(dir_path, max_workers=max_workers):<br>        batch_buffer.append(string)<br><br>        if len(batch_buffer) &gt;= batch_size:<br>            save_and_clear()<br><br>    if batch_buffer:<br>        save_and_clear()</pre><p>The reason for exiting the database at the start is that we are going to run a multiprocessing function, and if we get a connection in a different thread, we will run into a lot of problems, so we need to create a new connection for each thread.</p><p>I also made this function into general purpose in order to swap type of index at the fly.</p><h4>Only batching</h4><p>Now we could have used the rest of the code from the beginning, but hold on, we must figure out the batching from database.</p><p>It’s small normalization, but painful to be honest:</p><pre>def batch_normalization(candidates, I):<br>    indices = []<br>    for i in I[0]:<br>        tmp = int((i // BATCH_SIZE) + 1)<br>        if not tmp in indices:<br>            indices.append(tmp)<br><br>    candidates = get_docs_by_ids(cu, indices, &quot;cache.directories&quot;)<br>    valid_candidates = []<br>    for c, index in zip(candidates, indices):<br>        for i in I[0]:<br>            if int((i // BATCH_SIZE) + 1) == index:<br>                candidate = pickle.loads(b64d(c.encode(&quot;utf-8&quot;)))[i % BATCH_SIZE]<br>                valid_candidates.append(candidate)<br><br>    return valid_candidates</pre><p>The problem here is that database starts from index 1 instead of 0 and we need to find the correct batch using:</p><pre># F_index from FAISS starts from 0<br>F_index // BATCH_SIZE + 1<br><br>BATCH_SIZE # just our batch size<br><br># this will get from the n file/directory<br>i % BATCH_SIZE<br># i = index of the array saved that&#39;s why not again +1<br><br># F_index = 4532, BATCH_SIZE = 2000<br># to query: 4532 // 2000 (+1) = 2 (+ 1) we get correct batch<br># then correct position [532] = [4532 % 2000]</pre><p>At the end I’ve wrapped it into web interface:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DolLK023FpPZhz_kSsBYQQ.png" /><figcaption>Results of search</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*v1KAN-9k7NELdg-E2icG3Q.png" /><figcaption>Indices and unsorted results</figcaption></figure><h3>Conclusion and final words</h3><p>Still it’s far from good optimization, because even 2411 directories took 13 seconds, but it was interesting experience.</p><p>Some potential upgrades include rewriting into rust or just a few functions into C, and to not loop without relevance for example each folder is known for some purpose (.git, node_moduls, vendor) and git repositories have usually README.md, the name can tell you whether it is worth continuing or not.</p><p>I was planning to also use summaries from models to add more context, but even looping directories took a lot of time so it’s just left it there and not used.</p><p>If you enjoyed this article, clap and follow me! Thanks for reading, and I wish you the best luck on your journey👋.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=052517cb2a3b" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Building your own network protection with Hybrid WAF and iptables]]></title>
            <link>https://systemweakness.com/writing-your-own-network-protection-for-server-waf-and-iptables-3e9d21b35c7a?source=rss-6c5b2c01614b------2</link>
            <guid isPermaLink="false">https://medium.com/p/3e9d21b35c7a</guid>
            <category><![CDATA[network-security]]></category>
            <category><![CDATA[web-security]]></category>
            <category><![CDATA[firewall]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <dc:creator><![CDATA[Sw33tBit]]></dc:creator>
            <pubDate>Wed, 23 Apr 2025 07:05:21 GMT</pubDate>
            <atom:updated>2025-05-16T18:03:44.898Z</atom:updated>
            <content:encoded><![CDATA[<p>In this article I’ll introduce types of firewalls, more specifically IPS/IDS, WAF and iptables. And how to implement your own WAF and iptables rules with python.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WqQYvRdvibHXsNTplyHPfw.png" /><figcaption>Animated representation of firewall (taken from: exa.net.uk)</figcaption></figure><p>Code in this article is publicly available right here:</p><p><a href="https://github.com/BitR13x/AI-WAF">GitHub - BitR13x/AI-WAF: Web Firewall that is powered by AI and signatures</a></p><h3>So theory comes first, what is firewall?</h3><p>It is usually a hardware or software-based system which monitors all incoming and outgoing traffic and, based on a defined set of security rules, it accepts, rejects, or drops that specific traffic. Web application firewall (WAF) is simply a firewall for web application.</p><p>In order to secure the internal network from unauthorized traffic, we need a <a href="https://www.geeksforgeeks.org/introduction-of-firewall-in-computer-network/">Firewall</a>.</p><h4>How about the IPS/IDS?</h4><p><strong>Intrusion Detection System (IDS): </strong>Looking for the signature of known attack types or detecting activity that deviates from a prescribed normal and then report it.</p><p>I<strong>ntrusion Prevention System (IPS): </strong>Basically the same, but it can block the packet/request.</p><p>Example of an open-source IPS/IDS: <strong>Suricata</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/225/0*8aqm07E_PiaZUuxk" /><figcaption>Suricata icon</figcaption></figure><p>Interesting sources related to IPS/IDS:<br><a href="https://cheatography.com/g33k247/cheat-sheets/suricata-nsm-more-than-an-ids/">Suricata cheetsheet</a><br><a href="https://github.com/ntop/nDPI">nDIP</a> — Deep Packet Inspection<br><a href="https://github.com/noushinpervez/Intrusion-Detection-CICIDS2017">Intrusion-Detection-CICIDS2017</a> — in-depth analysis of the CICIDS2017 dataset</p><h4>Comparison IPS/IDS and firewall:</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/894/1*PCg59K37m1HcbnRTRwbyrA.png" /><figcaption>Table from chatgpt</figcaption></figure><p>The differences are on thin ice, so I will not go deeper, because you could argue that the WAF or iptables can detect attacks and block them, meaning it would be something more complex than just a firewall.</p><h3><strong>Let’s move on, implementation of iptables?</strong></h3><p>By combining iptables and Python, you can create a custom intrusion detection and prevention system (IDS/IPS) that can intercept network packets before they reach the target service.</p><p>For example, using libraries such as NFQueue or Scapy in Python, you can:</p><ul><li>Analyze packets in real time</li><li>Detect suspicious patterns</li><li>Perform an automated action (e.g. dropping a packet or blocking an IP address).</li></ul><p>For example, here is a python script that blocks all IP addresses that are not in <em>whitelist.txt</em>:</p><pre>def process_packet(packet):<br>    scapy_packet = IP(packet.get_payload())<br>    features = extract_features(scapy_packet, packet)<br>    with open(&quot;./whitelist.txt&quot;) as file:<br>        for line in file:<br>            if line[0] == &quot;&quot; or line[0] == &quot;\n&quot;:<br>                continue<br><br>            if scapy_packet.src == line.strip().replace(&quot;\n&quot;, &quot;&quot;):<br>                print(f&quot;❌ Dropping Packet: {scapy_packet.summary()}&quot;)<br>                packet.drop()<br>        <br>    packet.accept()<br><br><br># Start Netfilter Queue<br>nfqueue = NetfilterQueue()<br>nfqueue.bind(1, process_packet)<br><br>print(&quot;Monitoring Traffic in Real-Time&quot;)<br>try:<br>    nfqueue.run()<br>except KeyboardInterrupt:<br>    print(&quot;\nStopping Firewall...&quot;)<br>    nfqueue.unbind()</pre><p>It works by using <em>NFQUEUE</em>, which is queueing packets to userspace. In simple terms, you get access to the packet using python. But you need to specify a queue number:</p><pre>sudo iptables -D INPUT -p tcp --dport 80 -j NFQUEUE --queue-num 1</pre><p>And you can do pretty neat stuff with this.</p><h3>Implementation of WAF</h3><p>We need to intercept HTTP(S) requests before they are delivered to the target server. This gives us the ability to analyze the content of the request and decide if it contains potentially malicious code.</p><p>We implement this step using a reverse-proxy component that I have programmed in Python using the library HTTPServer (a possible different approach is with the mitmproxy library).</p><p>The reverse-proxy acts as an intermediary between the user and the server. All traffic goes through this proxy first, which then decides whether to forward the request.</p><p>(The whole code is in the repository mentioned in the introduction)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*RhBwYy7FD4myEppWoUgJcA.png" /><figcaption>Implemented WAF architecture</figcaption></figure><p>This is how we forward the request:</p><pre>def do_GET(self, body=True):<br>  url = protocol+f&#39;{hostname}{self.path}&#39;<br>  resp = requests.get(url, headers=self.headers, verify=False)<br>  self.wfile.write(resp.text.encode(encoding=&#39;UTF-8&#39;,errors=&#39;strict&#39;))</pre><p>If we want to check the URL, we simply do something like this:</p><pre>def do_GET(self, body=True):<br>  url = protocol+f&#39;{hostname}{self.path}&#39;<br>  if verify_url(self.path): # we know that hostname is safe (from init)<br>    resp = requests.get(url, headers=self.headers, verify=False)<br>    self.wfile.write(resp.text.encode(encoding=&#39;UTF-8&#39;,errors=&#39;strict&#39;))<br>  else:<br>    self.send_error(403, &quot;Not allowed&quot;)</pre><h4>Signature-based</h4><p>A signature-based WAF is a security mechanism designed to detect known patterns or signatures of malicious activity.</p><p>I’ve collected rules from <a href="https://github.com/coreruleset/coreruleset">coreruleset</a>, <a href="https://user-agents.net/">user-agents</a> and <a href="https://rules.emergingthreats.net/">suricata</a>.</p><p>Then made a regex search to match if any string is in the request or response.</p><pre>    def __get_files_in_dir(self, dir_path: str) -&gt; list:<br>        if os.path.isdir(dir_path):<br>            return os.listdir(dir_path)<br>        else:<br>            return []<br><br>    def __search_string_in_file(self, file_path: str, string: str) -&gt; bool:        <br>        with open(file_path, &quot;r&quot;) as f:<br>            for line in f:<br>                # empty line or comment<br>                if line[0] == &quot;#&quot; or line[0] == &quot;\n&quot;:<br>                    continue<br>                <br>                # remove newline<br>                if line[-1]:<br>                    line = line[:-1]<br><br>                if re.search(re.escape(line), string):<br>                    return True # packet dangerous<br><br>        return False<br><br>    def __verify_signature(self, string: str, var: str) -&gt; bool:<br>        files = self.__get_files_in_dir(self.signatures_paths[var])<br>        if len(files) &gt; 0:<br>            for file in files:<br>                file_path = os.path.join(relative_path(self.signatures_paths[var]), file)<br>                if self.__search_string_in_file(file_path, string):<br>                    return False<br>        <br>        # returning True if path does not exist!<br>        return True</pre><h4>AI-based</h4><p>AI-powered Web Application Firewall uses artificial intelligence and machine learning to detect and block web attacks in real time.</p><p>I used <a href="https://www.kaggle.com/datasets/evg3n1j/fwaf-dataset">fwaf-dataset</a> and <a href="https://github.com/swisskyrepo/PayloadsAllTheThings">PayloadAllThethings</a> to train two models using PyTorch.</p><p>I didn’t create new model, but fine-tuned <em>distilbert-base-uncased </em>(you can use<em> </em>llama or any different model for classification).</p><pre>    def verify_url(self, url: str) -&gt; bool:<br>        inputs = self.tokenizer(url,<br>            truncation=True,<br>            padding=True,<br>            return_tensors=&quot;pt&quot;,<br>            max_length=500<br>        ).to(self.device)<br><br>        with torch.no_grad():<br>            outputs = self.url_model(**inputs)<br><br>        probabilities = torch.nn.functional.softmax(outputs.logits, dim=-1)<br>        predicted_class_index = torch.argmax(probabilities, dim=-1).item()<br><br>        predicted_class_name = self.url_labels[predicted_class_index]<br>        logging.info(f&quot;Probabilities for each class: {probabilities.numpy()}: {predicted_class_name}&quot;)<br><br>        if max(probabilities[0]) &lt; self.probability_catch:<br>            # We are not that certain<br>            return True<br><br>        if predicted_class_name == &quot;goodqueries&quot;:<br>            return True<br>        else:<br>            return False</pre><h3>Main disadvantages</h3><p><strong>Complexity: </strong>Setting up and keeping up a firewall can be time-consuming and difficult<strong><br>Limited Flexibility for developers<br>Limited adaptability: </strong>frequently rule-based for signatures and AI can’t be that much trusted</p><h4>Possible upgrade to this project</h4><p>One option is anomaly-based detection.<br>Once we gather enough data to define normal network flow, we can take action on anomalies.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/550/0*peHxraS7p5QI45_B.png" /><figcaption>Abstract example of statistically represented network flow in graph</figcaption></figure><h3>Conclusion</h3><p>Creating a comprehensive security system for a server environment is not only possible, but also highly effective when using a combination of multiple layers of protection, including WAF and iptables.</p><p>A good security architecture can significantly reduce the risk of successful cyber-attacks such as XSS, XXE, CSRF, DDoS or SQL injection.</p><p>If you enjoyed this article, clap and follow me! Thanks for reading, and I wish you the best luck on your journey👋.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3e9d21b35c7a" width="1" height="1" alt=""><hr><p><a href="https://systemweakness.com/writing-your-own-network-protection-for-server-waf-and-iptables-3e9d21b35c7a">Building your own network protection with Hybrid WAF and iptables</a> was originally published in <a href="https://systemweakness.com">System Weakness</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[HackTheBox Cyber Apocalypse CTF 2025 writeup: Reverse Engineering (endlesscycle, impossimaze)]]></title>
            <link>https://medium.com/@bitr13x/hackthebox-cyber-apocalypse-ctf-2025-writeup-reverse-engineering-endlesscycle-impossimaze-254b349ba227?source=rss-6c5b2c01614b------2</link>
            <guid isPermaLink="false">https://medium.com/p/254b349ba227</guid>
            <category><![CDATA[cybersecurity]]></category>
            <category><![CDATA[hackthebox]]></category>
            <category><![CDATA[reverse-engineering]]></category>
            <category><![CDATA[ctf-writeup]]></category>
            <dc:creator><![CDATA[Sw33tBit]]></dc:creator>
            <pubDate>Mon, 31 Mar 2025 07:28:15 GMT</pubDate>
            <atom:updated>2025-04-04T14:23:25.972Z</atom:updated>
            <content:encoded><![CDATA[<p>Two easy rated challenges from the HackTheBox CTF event. In this article we look into the Step-by-step breakdown of how to approach and solve these challenges.</p><p>The original binaries are saved <a href="https://github.com/BitR13x/CTF-Collection/tree/main/Cyber%20Apocalypse%202025">here</a>.</p><h3>Endlesscycle</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/986/1*RldR_Q_SXRC1TYF7fmVpVA.png" /></figure><p>After de-compilation and renaming I end-up with this code:</p><pre>int main(int argc,char **argv) {<br>  int iVar1;<br>  char *pcVar2;<br>  int i;<br>  int i2;<br>  <br>  pcVar2 = (char *)mmap((void *)0,158,7,33,-1,0);<br>                    /* 3486694491 */<br>  srand(UINT_001042b8);<br>  for (_i = 0; _i &lt; 158; _i = _i + 1) {<br>    for (_i2 = 0; _i2 &lt; (ulong)(long)INT_ARRAY_00104040[_i]; _i2 = _i2 + 1) {<br>      rand();<br>    }<br>    iVar1 = rand();<br>    pcVar2[_i] = (char)iVar1;<br>  }<br>                    /* construct function using rand */<br>  iVar1 = (*(code *)pcVar2)();<br>  if (iVar1 == 1) {<br>    puts(&quot;You catch a brief glimpse of the Dragon\&#39;s Heart - the truth has been revealed to you&quot;);<br>  }<br>  else {<br>    puts(&quot;The mysteries of the universe remain closed to you...&quot;);<br>  }<br>  return 0;<br>}</pre><p>This binary is initialized with srand and creates a function based on the rand function and it should be possible to recreate this function by setting the srand (for example in python), but I choose the easiest way by examining it in GDB.</p><pre>=&gt; 0x7ffff7fbf000: push   rbp // init<br>   0x7ffff7fbf001: mov    rbp,rsp<br>   0x7ffff7fbf004: push   0x101213e<br>   0x7ffff7fbf009: xor    DWORD PTR [rsp],0x1010101 <br>                           // 0x101213e ^ 0x101213e <br>   0x7ffff7fbf010: movabs rax,0x67616c6620656874<br>   0x7ffff7fbf01a: push   rax<br>   0x7ffff7fbf01b: movabs rax,0x2073692074616857<br>   0x7ffff7fbf025: push   rax<br>   0x7ffff7fbf026: push   0x1<br>   0x7ffff7fbf028: pop    rax<br>   0x7ffff7fbf029: push   0x1<br>   0x7ffff7fbf02b: pop    rdi<br>   0x7ffff7fbf02c: push   0x12<br>   0x7ffff7fbf02e: pop    rdx<br>   0x7ffff7fbf02f: mov    rsi,rsp<br>   0x7ffff7fbf032: syscall // write 18 bytes from stack f01b, f010<br>                              // What is the flag?<br>   0x7ffff7fbf034: sub    rsp,0x100 // 256 bytes reserved for buffer<br>   0x7ffff7fbf03b: mov    r12,rsp<br>   0x7ffff7fbf03e: xor    eax,eax <br>   0x7ffff7fbf040: xor    edi,edi<br>   0x7ffff7fbf042: xor    edx,edx // cleaning<br>   0x7ffff7fbf044: mov    dh,0x1<br>   0x7ffff7fbf046: mov    rsi,r12<br>   0x7ffff7fbf049: syscall         // read into r12<br>   0x7ffff7fbf04b: test   rax,rax // if read is not empty<br>   0x7ffff7fbf04e: jle    0x7ffff7fbf082<br><br><br>   // for loop sliding 4 bytes with xor<br>   0x7ffff7fbf050: push   0x1a // 26<br>   0x7ffff7fbf052: pop    rax<br>   0x7ffff7fbf053: mov    rcx,r12 // rcx = r12<br>   0x7ffff7fbf056: add    rax,rcx // rax += rcx + 26<br>   0x7ffff7fbf059: xor    DWORD PTR [rcx],0xbeefcafe<br>   0x7ffff7fbf05f: add    rcx,0x4 // rcx += 4<br>   0x7ffff7fbf063: cmp    rcx,rax // if rcx &lt; rax<br>   0x7ffff7fbf066: jb     0x7ffff7fbf059<br><br><br>   0x7ffff7fbf068: mov    rdi,r12<br>   0x7ffff7fbf06b: lea    rsi,[rip+0x12]        # 0x7ffff7fbf084<br>   0x7ffff7fbf072: mov    rcx,0x1a<br>   0x7ffff7fbf079: cld<br><br>   // comparing rdi (r12, input) with rsi (0x1a bytes = 26 bytes)<br>   0x7ffff7fbf07a: repz cmps BYTE PTR ds:[rsi],BYTE PTR es:[rdi]<br>   0x7ffff7fbf07c: sete   al<br>   0x7ffff7fbf07f: movzx  eax,al<br>   0x7ffff7fbf082: leave<br>   0x7ffff7fbf083: ret</pre><p>You can notice on the end there is a comparison RDI with RSI, where RDI is input. I dumped the memory:</p><pre>// 0x7ffff7fbf084: memory dump<br>0x7ffff7fbf084:   0xb6  0x9e  0xad  0xc5  0x92  0xfa  0xdf  0xd5<br>0x7ffff7fbf08c:   0xa1  0xa8  0xdc  0xc7  0xce  0xa4  0x8b  0xe1<br>0x7ffff7fbf094:   0x8a  0xa2  0xdc  0xe1  0x89  0xfa  0x9d  0xd2<br>0x7ffff7fbf09c:   0x9a  0xb7</pre><p>When reconstructing the behavior in C it should look something like this:</p><pre>int main() {<br>    char buffer[256];<br>    char message[] = &quot;What is flag?&quot;;<br>    char expected[] = &quot;...&quot;; // 0x7ffff7fbf084<br>    ssize_t bytes_read;<br>    <br>    // Print message<br>    write(STDOUT_FILENO, message, sizeof(message) - 1);<br>    <br>    // Read user input<br>    bytes_read = read(STDIN_FILENO, buffer, 256);<br>    if (bytes_read &lt;= 0) {<br>        return 0;<br>    }<br>    <br>    // XOR first few bytes with 0xBEEFCAFE<br>    for (int i = 0; i &lt; bytes_read - 4; i += 4) {<br>        *(int *)(buffer + i) ^= 0xBEEFCAFE;<br>    }<br>    <br>    // Compare with expected string<br>    if (memcmp(buffer, expected, 26) == 0) {<br>        puts(&quot;You got the flag!&quot;);<br>        return 1;<br>    }<br>    <br>    puts(&quot;Try again...&quot;);<br>    return 0;<br>}</pre><p>So now we can get the hands on python and reverse it:</p><pre>import struct<br><br># copied from memory dump<br>encrypted_data = [<br>    0xb6, 0x9e, 0xad, 0xc5, 0x92, 0xfa, 0xdf, 0xd5,<br>    0xa1, 0xa8, 0xdc, 0xc7, 0xce, 0xa4, 0x8b, 0xe1,<br>    0x8a, 0xa2, 0xdc, 0xe1, 0x89, 0xfa, 0x9d, 0xd2,<br>    0x9a, 0xb7<br>]<br><br># the key that is used<br>xor_key = 0xBEEFCAFE<br><br>original_bytes = bytearray()<br>for i in range(0, len(encrypted_data), 4):<br>    # XOR is applied to 4-byte chunks<br>    chunk = encrypted_data[i:i+4]<br>    while len(chunk) &lt; 4:<br>        chunk.append(0)<br>    <br>    # unpack it into int and back<br>    # (reverse of XOR is another XOR with same value)<br>    encrypted_int = struct.unpack(&quot;&lt;I&quot;, bytes(chunk))[0]<br>    decrypted_int = encrypted_int ^ xor_key<br>    original_bytes.extend(struct.pack(&quot;&lt;I&quot;, decrypted_int))<br><br>original_input = original_bytes.decode(errors=&quot;ignore&quot;)<br><br>print(&quot;Original input:&quot;, original_input)</pre><p>Next on the list is:</p><h3><strong>Impossimaze</strong></h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/540/1*ufh8Zh8Lo5Ndy-tK1aQZmw.png" /></figure><p>When trying to make sense in the binary I’ve ended up with this code:</p><pre>int main(int argc,char **argv) {<br>  int iVar1;<br>  uint uVar2;<br>  uint max_y_2;<br>  uint max_x_2;<br>  ulong max_x;<br>  char char_to_write;<br>  int x;<br>  int y;<br>  int *char_index;<br>  undefined4 in_register_0000003c;<br>  long in_FS_OFFSET;<br>  int half_x;<br>  int max_y;<br>  char position_x_y [24];<br>  long canary;<br>  <br>  canary = *(long *)(in_FS_OFFSET + 40);<br>                    /* newterm(getenv(&quot;TERM&quot;), stdout, stdin); */<br>  initscr(CONCAT44(in_register_0000003c,argc));<br>  cbreak();<br>  noecho();<br>  curs_set(0);<br>  keypad(window,1);<br>  max_y = getmaxy(window);<br>  max_x = getmaxx(window);<br>                    /* ensures half */<br>  half_x = (int)(((uint)(max_x &gt;&gt; 31) &amp; 1) + (int)max_x) &gt;&gt; 1;<br>  max_y = max_y / 2;<br>  x = 0;<br>  do {<br>    max_y_2 = getmaxy(window);<br>    max_x_2 = getmaxx(window);<br>    if (x == 260) {<br>      half_x = half_x - (uint)(1 &lt; half_x);<br>    }<br>    else if (x &lt; 261) {<br>      if (x == 258) {<br>        max_y = max_y + 1;<br>      }<br>      else if (x == 259) {<br>        max_y = max_y - (uint)(1 &lt; max_y);<br>      }<br>    }<br>    else {<br>      half_x = half_x + (uint)(x == 261);<br>    }<br>    werase(window);<br>    wattr_on(window,1048576,0);<br>    wborder(window,0,0,0,0,0,0,0,0);<br>    if (2 &lt; (int)max_x_2) {<br>      x = 1;<br>      do {<br>        y = 1;<br>        if (2 &lt; (int)max_y_2) {<br>          do {<br>            uVar2 = get_char(x,y);<br>            if ((int)uVar2 &lt; 61) {<br>              char_to_write = &#39;A&#39;;<br>              if ((int)uVar2 &lt; 31) {<br>                char_to_write = (-(uVar2 &lt; 31) &amp; 133U) + 86;<br>              }<br>            }<br>            else {<br>              char_to_write = (-(uVar2 - 61 &lt; 120) &amp; 202U) + 86;<br>            }<br>            iVar1 = wmove(window,y,x);<br>            if (iVar1 != -1) {<br>              waddch(window,(int)char_to_write);<br>            }<br>            y = y + 1;<br>          } while (y != max_y_2 - 1);<br>        }<br>        x = x + 1;<br>      } while (max_x_2 - 1 != x);<br>    }<br>    wattr_off(window,1048576,0);<br>    wattr_on(window,2097152,0);<br>    x = wmove(window,max_y,half_x);<br>    if (x != -1) {<br>      waddch(window,88);<br>    }<br>    wattr_off(window,2097152,0);<br>    snprintf(position_x_y,16,&quot;%d:%d&quot;,(ulong)max_y_2,(ulong)max_x_2);<br>    x = wmove(window,0,0);<br>    if (x != -1) {<br>      waddnstr(window,position_x_y,4294967295);<br>    }<br>    if ((max_y_2 == 13) &amp;&amp; (max_x_2 == 37)) {<br>      wattr_on(window,524288,0);<br>      wattr_on(window,2097152,0);<br>      char_index = &amp;INT_001040c0;<br>      x = 6;<br>      do {<br>        y = x + 1;<br>        x = wmove(window,6,x);<br>        if (x != -1) {<br>                    /* add a character (with attributes) to a curses window and advance cursor  */<br>          waddch(window,(&amp;DAT_00104120)[*char_index]);<br>        }<br>        char_index = char_index + 1;<br>        x = y;<br>      } while (y != 30);<br>      wattr_off(window,2097152,0);<br>      wattr_off(window,524288,0);<br>    }<br>    x = wgetch(window);<br>  } while (x != 113);<br>  endwin();<br>  if (canary != *(long *)(in_FS_OFFSET + 40)) {<br>                    /* WARNING: Subroutine does not return */<br>    __stack_chk_fail();<br>  }<br>  return 0;<br>}</pre><p>This binary is keeping track of window size, position x-y and moving cursor using <em>wmove </em>and <em>waddch</em>.</p><p>My approach was to search for printing any method, that may print out our flag. There were a few functions that caught my eye:</p><pre>uVar2 = get_char(x,y);<br>if ((int)uVar2 &lt; 61) {<br>    char_to_write = &#39;A&#39;;<br>    if ((int)uVar2 &lt; 31) {<br>      char_to_write = (-(uVar2 &lt; 31) &amp; 133U) + 86;<br>    }<br>}<br>else {<br>  char_to_write = (-(uVar2 - 61 &lt; 120) &amp; 202U) + 86;<br>}<br><br>waddch(window,(int)char_to_write);<br><br>// Write formatted output to sized buffer<br>snprintf(position_x_y,16,&quot;%d:%d&quot;,(ulong)max_y_2,(ulong)max_x_2);<br>waddnstr(window,position_x_y,4294967295);<br><br>char_index = &amp;INT_001040c0;<br>waddch(window,(&amp;DAT_00104120)[*char_index]);</pre><p><em>waddch</em> is used add a character to a curses window and advance cursor.</p><p>So we got few options, we will try to eliminate it one by one by thinking what it does, the first is kind of complex shifting of the char depending on <em>get_char</em> function:</p><pre>int get_char(int x,int y) {<br>  return *(int *)(&amp;DAT_00102020 +<br>                 (long)((x + *(int *)(&amp;DAT_00102020 + (long)((y + 1337) % 256) * 4)) % 256) * 4);<br>}</pre><p>But I stepped out and was thinking about the “<strong><em>char_to_write = ‘A’;”</em></strong>, it seemed weird to me, so I moved on.</p><p>Next we just printing position x-y, that’s clearly not what we are searching for.</p><p>Moving on we end-up here:</p><pre>char_index = &amp;INT_001040c0;<br>waddch(window,(&amp;DAT_00104120)[*char_index]);</pre><p>I noticed that the <em>char_index</em> variable is actually an array of <em>ints</em> and if some conditions are met then the char is printed.</p><p>So I tried to extract some of the non-null ints from the memory and added it to the<em> DAT_00104120 </em>and what we got here: “<em>HTB{“</em>, beginning of the flag and I knew that I was on the right path.</p><pre>00104205 H<br>0010413c T<br>001041d8 B<br>001041d2 {<br>00104160 T<br>00104188 H<br>001041f2 3<br>001041aa _<br>00104170 c<br>001041a6 u<br>0010421c r<br>00104193 s<br>001041f2 3<br>001041aa _<br>0010420d i<br>00104193 s<br>001041aa _<br>00104165 b<br>0010421c r<br>00104176 o<br>001041eb k<br>001041f2 3<br>0010420f n<br>001041e0 }<br><br># HTB{th3_curs3_is_brok3n}</pre><h3>Final words</h3><p>Thanks for reading, if someone is interested in collaboration write me on discord (bitr13x) or email me (<a href="mailto:sw33tbit@protonmail.com">sw33tbit@protonmail.com</a>).</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=254b349ba227" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[TryHackMe CTF HackfinityBattle Writeup: Reverse Engineering (computemagic, oldauth)]]></title>
            <link>https://medium.com/@bitr13x/tryhackme-ctf-hackfinitybattle-writeup-reverse-engineering-computemagic-oldauth-ae99c70409c5?source=rss-6c5b2c01614b------2</link>
            <guid isPermaLink="false">https://medium.com/p/ae99c70409c5</guid>
            <category><![CDATA[tryhackme]]></category>
            <category><![CDATA[reverse-engineering]]></category>
            <category><![CDATA[ctf]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <dc:creator><![CDATA[Sw33tBit]]></dc:creator>
            <pubDate>Thu, 27 Mar 2025 13:08:28 GMT</pubDate>
            <atom:updated>2025-03-28T23:21:32.791Z</atom:updated>
            <content:encoded><![CDATA[<p>In this article, we will look into the process of solving two reverse engineering challenges from the TryHackMe CTF event. Step-by-step breakdown of how to approach and solve these puzzles.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*wA6dJ8KKstpQZZcr.png" /></figure><p>The original binaries are saved <a href="https://github.com/BitR13x/CTF-Collection/tree/main/Hackinfinity/reverse_engineering">here</a>.</p><h3>Recommended knowledge</h3><p>First get familiar with C (often you will end-up in de-compiler), it is very useful to learn little bit of assembly, registers and calling conventions if you need to use GDB.</p><p>Most important is to learn how to google build-in functions and more.</p><h3>Few tips how to approach these types challenges</h3><p>Find your de-compiler (Ghidra, IDA, Binary ninja, cutter, radare2 and more), there are lot’s of options just find what you are comfortable.</p><p>I stick with Ghidra and cutter (switching to the cutter if Ghidra does not decompile built-in functions or cannot find the main, just to check).</p><p>Get the bigger picture do not look into one part of the code too long if you look at a function from a different part, you can spot what is it for and decide if you need to understand it.</p><p>When looking for the main function, look for common patterns (the main function is usually loaded in the same manner from the entry point of the binary).</p><p>Plot graph of the execution flow for bigger binaries, it can help with clarity.</p><p>Make comments (the same reason).</p><h3>Computemagic</h3><p>When opening a binary usually you would see weird names and types.</p><p>After some renaming and figuring out what does what. I end up with this code:</p><pre> <br>int main(int argc,char **argv) {<br>  int error_res;<br>  ssize_t read_return;<br>  long in_FS_OFFSET;<br>  undefined4 option_value;<br>  socklen_t address_len;<br>  int socket;<br>  int socket_filedesc;<br>  int check;<br>  size_t length;<br>  sockaddr socketAddr;<br>  char buffer [24];<br>  undefined8 local_10;<br>  <br>  local_10 = *(undefined8 *)(in_FS_OFFSET + 40);<br>  option_value = 1;<br>  address_len = 16;<br>  while( true ) {<br>                    /* int socket(int domain, int type, int protocol); */<br>    socket = ::socket(2,1,0);<br>    if (socket == 0) {<br>      perror(&quot;socket failed&quot;);<br>                    /* WARNING: Subroutine does not return */<br>      exit(1);<br>    }<br>    error_res = setsockopt(socket,1,15,&amp;option_value,4);<br>    if (error_res != 0) {<br>      perror(&quot;setsockopt failed&quot;);<br>                    /* WARNING: Subroutine does not return */<br>      exit(1);<br>    }<br>    socketAddr.sa_family = 2;<br>    socketAddr.sa_data[2] = &#39;\0&#39;;<br>    socketAddr.sa_data[3] = &#39;\0&#39;;<br>    socketAddr.sa_data[4] = &#39;\0&#39;;<br>    socketAddr.sa_data[5] = &#39;\0&#39;;<br>    socketAddr.sa_data._0_2_ = htons(9003);<br>    error_res = bind(socket,&amp;socketAddr,16);<br>    if (error_res &lt; 0) {<br>      perror(&quot;bind failed&quot;);<br>                    /* WARNING: Subroutine does not return */<br>      exit(1);<br>    }<br>    error_res = listen(socket,3);<br>    if (error_res &lt; 0) break;<br>    socket_filedesc = accept(socket,&amp;socketAddr,&amp;address_len);<br>    if (socket_filedesc &lt; 0) {<br>      perror(&quot;accept failed&quot;);<br>                    /* WARNING: Subroutine does not return */<br>      exit(1);<br>    }<br>    sendBanner(socket_filedesc);<br>    read_return = read(socket_filedesc,buffer,16);<br>    if (read_return &lt; 0) {<br>      perror(&quot;read failed&quot;);<br>                    /* WARNING: Subroutine does not return */<br>      exit(1);<br>    }<br>    length = strlen(buffer);<br>    if ((length != 0) &amp;&amp; (socketAddr.sa_data[length + 13] == &#39;\n&#39;)) {<br>      socketAddr.sa_data[length + 13] = &#39;\0&#39;;<br>    }<br>    check = checkSpell(buffer,socket_filedesc);<br>    if (check == 1) {<br>      puts(&quot;\nSpell check successful.&quot;);<br>    }<br>    else {<br>      puts(&quot;\nSpell check failed.&quot;);<br>    }<br>    close(socket_filedesc);<br>    close(socket);<br>  }<br>  perror(&quot;listen failed&quot;);<br>                    /* WARNING: Subroutine does not return */<br>  exit(1);<br>}</pre><p>The binary starting a socket and waiting for connection.</p><p>Here is the most interesting parts of the code:</p><pre>socket_filedesc = accept(socket,&amp;socketAddr,&amp;address_len);<br>read_return = read(socket_filedesc,buffer,16);<br>length = strlen(buffer);<br>if ((length != 0) &amp;&amp; (socketAddr.sa_data[length + 13] == &#39;\n&#39;)) {<br>  socketAddr.sa_data[length + 13] = &#39;\0&#39;;<br>}<br>check = checkSpell(buffer,socket_filedesc);<br>if (check == 1) {<br>  puts(&quot;\nSpell check successful.&quot;);<br>}<br>else {<br>  puts(&quot;\nSpell check failed.&quot;);<br>}</pre><p>Now we know how large the input string must be and we know what function is used to validate if the input is correct.</p><pre>int checkSpell(char *buffer,int filedesc) {<br>  int return_val;<br>  size_t length;<br>  <br>  length = strlen(buffer);<br>  if ((int)length &lt; 1) {<br>    puts(&quot;Empty string.&quot;);<br>    return_val = 0;<br>  }<br>  else {<br>    switch(*buffer) {<br>    case &#39;A&#39;:<br>      func_1(buffer,filedesc);<br>      break;<br>    ...<br>    ...<br>    case &#39;Z&#39;:<br>      func_26(buffer,filedesc);<br>    }<br>    return_val = 1;<br>  }<br>  return return_val;<br>}</pre><p>Switch case, that is calling different functions depending on the first letter.</p><p>It can look complex, but I realized it has to take parameters in order to check the actual string and I end up look into each function that has parameters and found:</p><pre>void func_13(char *buf,int filedsc) {<br>  int result;<br>  <br>  result = check_other(buf);<br>  if (result != 0) {<br>    read_flag(filedsc);<br>  }<br>  return;<br>}</pre><p>Where the real validation happens:</p><pre><br>bool check_other(char *buf) {<br>  int res_strcmp;<br>  long in_FS_OFFSET;<br>  int i;<br>  char hardcoded [16];<br>  long canary;<br>  <br>  canary = *(long *)(in_FS_OFFSET + 40);<br>  // all what we need to reverse:<br>  for (i = 0; i &lt; 16; i = i + 1) {<br>    hardcoded[i] = buf[i] + 0x4U ^ 13;<br>  }<br><br>  res_strcmp = strcmp(hardcoded,&quot;AhhF1ag1571GHFDS&quot;);<br>  if (res_strcmp != 0) {<br>    printf(&quot;Incorrect: %s\n&quot;,buf);<br>  }<br>  else {<br>    printf(&quot;Correct: %s\n&quot;,buf);<br>  }<br>  if (canary != *(long *)(in_FS_OFFSET + 40)) {<br>                    /* WARNING: Subroutine does not return */<br>    __stack_chk_fail();<br>  }<br>  return res_strcmp == 0;<br>}</pre><p>Which I reverse by using python (the 0x4U means unsigned 4):</p><pre>a = &quot;AhhF1ag1571GHFDS&quot;<br>buf = [&quot;&quot;] * len(a)<br><br>for i in range(len(buf)):<br>    buf[i] = chr(ord(a[i]) + 4 ^ 13)<br><br>print(&quot;&quot;.join(buf)) # HaaG8hf8468FAGEZ</pre><h3>Oldauth</h3><p>Here is the same process rename everything and type it:</p><pre><br>int main(int argc,char **argv,char **envp) {<br>  bool bVar1;<br>  int iVar2;<br>  char *fgets_check;<br>  size_t newline_index;<br>  undefined7 extraout_var;<br>  undefined7 extraout_var_00;<br>  undefined7 extraout_var_01;<br>  undefined7 extraout_var_02;<br>  undefined4 in_register_0000003c;<br>  long in_FS_OFFSET;<br>  char username [112];<br>  char key [1000];<br>  long canary_bit;<br>  <br>  canary_bit = *(long *)(in_FS_OFFSET + 40);<br>  setup(CONCAT44(in_register_0000003c,argc));<br>  printf(&quot;Enter the key: &quot;);<br>  fgets_check = fgets(key,1000,stdin);<br>  if (fgets_check == (char *)0) {<br>    puts(&quot;Error!&quot;);<br>    iVar2 = -1;<br>  }<br>  else {<br>    newline_index = strcspn(key,&quot;\n&quot;);<br>    key[newline_index] = &#39;\0&#39;;<br>                    /* xor by 82 every char<br>                        */<br>    change(key,newline_index,82);<br>    if (newline_index != 16) {<br>                    /* <br>                        */<br>      fail();<br>    }<br>    if (key[2] != &#39;Q&#39;) {<br>      fail();<br>    }<br>    if (key[13] != &#39;4&#39;) {<br>      fail();<br>    }<br>                    /* suma of chars and modulo (4: how many chars, 3: modulo) */<br>    bVar1 = check(key,4,3);<br>    if ((int)CONCAT71(extraout_var,bVar1) == 0) {<br>      fail();<br>    }<br>    bVar1 = check(key + 4,5,8);<br>    if ((int)CONCAT71(extraout_var_00,bVar1) == 0) {<br>      fail();<br>    }<br>    bVar1 = check(key + 8,4,5);<br>    if ((int)CONCAT71(extraout_var_01,bVar1) == 0) {<br>      fail();<br>    }<br>    bVar1 = check(key + 12,4,3);<br>    if ((int)CONCAT71(extraout_var_02,bVar1) == 0) {<br>      fail();<br>    }<br>    printf(&quot;Enter the username: &quot;);<br>    fgets_check = fgets(username,100,stdin);<br>    if (fgets_check == (char *)0) {<br>      puts(&quot;Error!&quot;);<br>      iVar2 = -1;<br>    }<br>    else {<br>      newline_index = strcspn(username,&quot;\n&quot;);<br>      iVar2 = compare_with_target(username,newline_index);<br>      if (iVar2 == 0) {<br>        fail();<br>      }<br>      succeed();<br>      iVar2 = 0;<br>    }<br>  }<br>  if (canary_bit != *(long *)(in_FS_OFFSET + 40)) {<br>                    /* WARNING: Subroutine does not return */<br>    __stack_chk_fail();<br>  }<br>  return iVar2;<br>}</pre><p>Find interesting parts of code:</p><p>(I’ve named the first input as key)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/557/1*HXLml5CZaEt0EmEN9mAUnA.png" /><figcaption>This tells us the size and few letters</figcaption></figure><p>Next there is called four times on an input check function.</p><pre>    bVar1 = check(key,4,3);<br>    if ((int)CONCAT71(extraout_var,bVar1) == 0) {<br>      fail();<br>    }<br>    bVar1 = check(key + 4,5,8);<br>    if ((int)CONCAT71(extraout_var_00,bVar1) == 0) {<br>      fail();<br>    }<br>    bVar1 = check(key + 8,4,5);<br>    if ((int)CONCAT71(extraout_var_01,bVar1) == 0) {<br>      fail();<br>    }<br>    bVar1 = check(key + 12,4,3);<br>    if ((int)CONCAT71(extraout_var_02,bVar1) == 0) {<br>      fail();<br>    }</pre><p>After some adjustments for the function:</p><pre>bool check(char *key,int for_end,int modulo) {<br>  int suma;<br>  int i;<br>  <br>  suma = 0;<br>  for (i = 0; i &lt; for_end; i = i + 1) {<br>    suma = suma + key[i];<br>  }<br>  return suma % modulo == 0;<br>}</pre><p>I also noticed a second <em>fgets</em> meaning there are two parts (password and username). I started with reversing the check function using python:</p><pre>key = [&quot;&quot;, &quot;&quot;, &quot;Q&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, &quot;&quot;, &quot;4&quot;, &quot;&quot;, &quot;&quot;]<br>def rev_check(start, end, modulo):<br>    suma = 0<br>    def_letter = &quot;d&quot;<br>    for i in range(start, start+end):<br>        if not key[i]:<br>            key[i] = def_letter<br>        <br>        suma += ord(key[i])<br><br>    if suma % modulo != 0:<br>        tmp = suma % modulo<br>        key[i] = chr(ord(def_letter) - tmp)<br><br># from the binary<br>rev_check(0, 4, 3)<br>rev_check(4, 5, 8)<br>rev_check(8, 4, 5)<br>rev_check(12, 4, 3)<br><br>print(&quot;REV Check:&quot;, key)<br>for c in range(len(key)):<br>    key[c] = chr(ord(key[c]) ^ 82)<br><br>print(&quot;XOR:&quot;, key)<br><br>with open(&quot;rev_out&quot;, &quot;w&quot;) as f:<br>    f.write(&quot;&quot;.join(key))<br><br>print(&quot;password:&quot;, &quot;&quot;.join(key).encode())</pre><p>Not the prettiest code, but hey it works.</p><p>2nd part is username:</p><pre>    printf(&quot;Enter the username: &quot;);<br>    fgets_check = fgets(username,100,stdin);<br>    if (fgets_check == (char *)0) {<br>      puts(&quot;Error!&quot;);<br>      iVar2 = -1;<br>    }<br>    else {<br>      newline_index = strcspn(username,&quot;\n&quot;);<br>      iVar2 = compare_with_target(username,newline_index);<br>      if (iVar2 == 0) {<br>        fail();<br>      }<br>      succeed();<br>      iVar2 = 0;<br>    }</pre><p>Noticed that there is called the <em>compare_with_target</em> function, to check if the username is correct.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/467/1*5qg_WrTfl5JoqVEGBGmPLw.png" /></figure><p>Don’t get confused with the return “!=” it has to return the “<em>1”.</em></p><p>This function is a straight forward checking hard-coded variable with a small ASCII shift (+2).</p><p>The reverse of this function in python would look like this:</p><pre># username<br>username = &quot;&quot;<br>for c in &quot;elb4rt0pwn&quot;:<br>    username += chr(ord(c) - 2)<br><br>print(&quot;username:&quot;, username)</pre><p>After sending it all together into the binary you would get a flag.</p><h3>Final words</h3><p>Thanks for reading, if someone is interested in collaboration write me on discord (bitr13x) or email me (<a href="mailto:sw33tbit@protonmail.com">sw33tbit@protonmail.com</a>).</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ae99c70409c5" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Solve equations and mathematical games with Z3 solver]]></title>
            <link>https://medium.com/@bitr13x/black-boxing-the-z3-solver-solve-equations-and-more-using-z3-595d4de2719c?source=rss-6c5b2c01614b------2</link>
            <guid isPermaLink="false">https://medium.com/p/595d4de2719c</guid>
            <category><![CDATA[hacking]]></category>
            <category><![CDATA[reverse-engineering]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <dc:creator><![CDATA[Sw33tBit]]></dc:creator>
            <pubDate>Fri, 14 Mar 2025 08:46:52 GMT</pubDate>
            <atom:updated>2025-03-16T00:37:59.626Z</atom:updated>
            <content:encoded><![CDATA[<p>How to efficiently solve problems ranging from simple mathematical equations to advanced logical satisfiability.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/540/1*2y4S8pFSL0YjvGiLuqOvaQ.png" /></figure><h3>What is Boolean Satisfiability (SAT) and Satisfiability Modulo Theories (SMT)</h3><p><strong>Boolean Satisfiability </strong>abbreviated<strong> SAT.</strong> Boolean stands for True or False and satisfiability is when it is true under some assignment of values to its variables. Meaning <strong>SAT</strong> solvers trying to find if the variables can be replaced by the values TRUE or FALSE in such a way that the formula evaluates to TRUE. The standard definition is:</p><blockquote>SAT solvers determine the ‘satisfiability’ of boolean set of equations for a set of inputs.</blockquote><p>In other hand the SMT practically doing the same thing, but it combines the power of SAT solvers and other types of solvers to solve more complicated formulas for example handling inequalities, uninterpreted functions. SMT can handle formulas that involve multiple theories such as <strong>linear arithmetic</strong>, <strong>bit-vectors</strong>, and <strong>arrays</strong>.</p><h3><strong>Intro into Z3 Solver</strong></h3><p>Why we were talking about <strong>SMT</strong> and <strong>SAT</strong>, because the <strong>Z3</strong> is <a href="https://smt-lib.org/solvers.shtml">one of the <strong>SMTs</strong></a><strong>. </strong>It can be used for a variety of purposes such as formal verification, model checking, static program analysis and lot more.</p><p>Often when navigating through this field you will come across the terms like:</p><p><strong>Symbols</strong> (= variables), <br><strong>Unsat/sat</strong> (= unsatisfiable/satisfiable), (= unsolvable/solvable)<br><strong>Concrete values</strong> (= strings, decimals and integers)<br><strong>Literals</strong> (= SAT variable in short)<br><strong>Clauses</strong> (= combination of literals)</p><h4>Bonus</h4><p><strong>P </strong>problem (Polynomial problem): Refers to problems that can be solved efficiently (in polynomial time [n² + n, n]) by a deterministic algorithm. Example: Sorting a list.</p><p><strong>NP </strong>problem<strong> </strong>(Nondeterministic Polynomial problem): Refers to problems for which a solution can be quickly verified (in polynomial time). Example: Verifying a solution to a Sudoku puzzle.</p><h3>How the Z3 actually works? Well here you go:</h3><p>The fastest way how to demonstrate it, is how to solve Facebook quiz:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/227/0*tllS_2trEwIevGkp" /></figure><p>We can rewrite it into Z3 form, where flowers will be the symbols (variables):</p><pre>from z3 import *<br><br># flowers =&gt; Symbolic [Int] type<br>rflower = Int(&quot;rflower&quot;)<br>bflower = Int(&quot;bflower&quot;)<br>yflower = Int(&quot;yflower&quot;)<br># rflower, bflower, yflower = Ints(&#39;rflower bflower yflower&#39;)<br><br>solver = Solver()<br><br># (Constraints) Equations<br>solver.add(rflower + rflower + rflower == 60)<br>solver.add(rflower + bflower + bflower == 30)<br>solver.add(bflower - yflower == 3)<br># note: if we know the result is positive, we can add constraint: flower &gt; 0<br><br># Solver.check =&gt; CheckSatResult[sat, unsat, unknown]<br>if solver.check() == sat:<br>    model = solver.model()<br>    print(&quot;Sat solution:&quot;)<br>    print(<br>        f&quot;Answer is: {model[yflower]} + {model[rflower]} + {model[bflower]} =&quot;, <br>        f&quot;{model[yflower].as_long() + model[rflower].as_long() + model[bflower].as_long()}&quot;<br>    )<br>else:<br>    print(&quot;unsat: No solution found.&quot;)</pre><p>I think everything is straight forward except one thing why “<em>.as_long()”</em>? That’s because <em>model[variable]</em> is not <em>Int</em>,<em> </em>but<em> </em>class <em>z3.z3.IntNumRef.</em></p><p>When we dive a little bit deeper and look how Z3 is actually solving these problems:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/752/1*4TO5cqFKNLvonWTaIp4Z3Q.png" /><figcaption>abstract path of Z3 solving equation</figcaption></figure><h3>Solving reverse engineering challenge:</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/755/1*qD43cdqRfw1f1Wn-JKUKwg.png" /><figcaption>Decompiled binary using Ghidra</figcaption></figure><p>What do we even see? It’s binary that checks whatever license format is right or not, the license is hardcoded under some if statement, which has to be true in order to crack the binary.</p><p>The argc arguments is the number of arguments supplied we know we need to run the binary with at least one argument and the length is 32 bytes.</p><p>There are two approaches about this problem using Z3, we use it to solve as equation or with angr that will control flow of the program and try to brute force it until everything is met.</p><p>We will apply Z3 by rewriting the if statement into equation (you don’t need to do it manually, help yourself, for example you can use global replace)</p><p>There is a small catch with the conversion, the chars are from -128 to 127 and when they overflow it will move back and forth.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/564/1*LxhfxKE7gq7nQ1qQGdTJqg.png" /><figcaption>Small C example of the char conversion</figcaption></figure><p>In order to solve this weird unusual acting we will use <em>BitVecs</em>, I thought of using a function to handle the logic, but I end up using <em>BitVecs</em> for the simplicity.</p><pre>from z3 import *<br><br><br>def check_license_with_z3():<br>    solver = Solver()<br>    # Create array of bitvecs with size of 32<br>    string = [BitVec(f&quot;string_{i}&quot;, 8) for i in range(32)]<br><br>    solver.add(<br>        string[29] == string[5] - string[3] + ord(&quot;F&quot;),<br>        string[2] + string[22] == string[13] + ord(&quot;{&quot;),<br>        string[12] + string[4] == string[5] + 0x1c,<br>        string[25] * string[23] == string[0] + string[17] + 0x17,<br>        string[27] * string[1] == string[5] + string[22] + -21,<br>        string[9] * string[13] == string[28] * string[3] + -9,<br>        string[9] == ord(&quot;p&quot;),<br>        string[19] + string[21] == string[6] + -128,<br>        string[16] == string[15] - string[11] + ord(&quot;0&quot;),<br>        string[7] * string[27] == string[1] * string[13] + ord(&quot;-&quot;),<br>        string[13] == string[18] + string[13] + -101,<br>        string[20] - string[8] == string[9] + ord(&quot;|&quot;),<br>        string[31] == string[8] - string[31] + -121,<br>        string[20] * string[31] == string[20] + 4,<br>        string[24] - string[17] == string[21] + string[8] + -23,<br>        string[7] + string[5] == string[5] + string[29] + ord(&quot;,&quot;),<br>        string[12] * string[10] == string[1] - string[11] + -36,<br>        string[31] * string[0] == string[26] + -27,<br>        string[1] + string[20] == string[10] + -125,<br>        string[18] == string[27] + string[14] + 2,<br>        string[30] * string[11] == string[21] + ord(&quot;D&quot;),<br>        string[5] * string[19] == string[1] + -44,<br>        string[13] - string[26] == string[21] + -127,<br>        string[23] == string[29] - string[0] + ord(&quot;X&quot;),<br>        string[19] == string[8] * string[13] + -23,<br>        string[6] + string[22] == string[3] + ord(&quot;S&quot;),<br>        string[12] == string[26] + string[7] + -114,<br>        string[16] == string[18] - string[5] + ord(&quot;3&quot;),<br>        string[30] - string[8] == string[29] + -77,<br>        string[20] - string[11] == string[3] + -76,<br>        string[16] - string[7] == string[17] + ord(&quot;f&quot;),<br>        string[1] + string[21] == string[11] + string[18] + ord(&quot;+&quot;),<br>    )<br><br>    if solver.check() == sat:<br>        model = solver.model()<br>        print(<br>            &quot;&quot;.join([<br>                chr(c.as_long())<br>                for c in [model.eval(string[i]) for i in range(len(string))]<br>            ])<br>        )<br>        print(&quot;License Correct&quot;)<br>        return True<br>    else:<br>        print(&quot;License Invalid&quot;)<br>        return False</pre><p>(Bonus if we want to just get the string “License Correct”, it’s done by overwriting the if instruction.)</p><h3><strong>Conclusion</strong></h3><p>We’ve learnt about Z3, the most fundamental terminology in Z3, and how to solve basic problems with Z3.</p><p>With a little knowledge about Z3, you will be able to solve complex problems like rubic cube, sudoku, magic square and <a href="https://ericpony.github.io/z3py-tutorial/guide-examples.htm">lot more</a>.</p><p>If you enjoyed this article, clap👋 and follow me! Thanks for reading! Looking forward to seeing you in the future.</p><h4>More Resources</h4><p>Exemplar challenges: <a href="https://github.com/PwnFunction/learn-z3">https://github.com/PwnFunction/learn-z3</a><br>Docs: <a href="https://github.com/Z3Prover/z3/wiki#background">https://github.com/Z3Prover/z3/wiki#background</a><br>YouTube explanation: <a href="https://www.youtube.com/watch?v=EacYNe7moSs">https://www.youtube.com/watch?v=EacYNe7moSs</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=595d4de2719c" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Cross-site scripting (XSS): Comprehensive guide on how to attack and defend]]></title>
            <link>https://medium.com/@bitr13x/cross-site-scripting-xss-comprehensive-guide-on-how-to-attack-and-defend-5a5bfb2dbce2?source=rss-6c5b2c01614b------2</link>
            <guid isPermaLink="false">https://medium.com/p/5a5bfb2dbce2</guid>
            <category><![CDATA[web-security]]></category>
            <category><![CDATA[infosec]]></category>
            <category><![CDATA[cross-site-scripting]]></category>
            <category><![CDATA[owasp]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <dc:creator><![CDATA[Sw33tBit]]></dc:creator>
            <pubDate>Mon, 26 Aug 2024 19:31:29 GMT</pubDate>
            <atom:updated>2024-08-26T19:31:29.230Z</atom:updated>
            <content:encoded><![CDATA[<p>This is a summary of XSS and everything needed to be able to find this vulnerability and protect yourself and others.</p><p>When starting out learning about XSS there is a lot of stuff, but most of it is just repeating, and you can’t find anything new. This guide should also cover the special cases that are hard to find on the web.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*e3krx4Mi1ka6IKXa4IQILg.png" /></figure><h3>Why my JavaScript is not executing?</h3><ul><li><em>Browser protection against JavaScript execution</em></li></ul><h4>1) SOP (<a href="https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy">Same-Origin Policy</a>)</h4><p>It is a security rule that keeps data safe by making sure that web pages from one website (origin) can’t access data from another website (origin) without permission.</p><p>Anytime when we want to read the response from an API or different website (origin), the website has to answer with a CORS header to allow reading, otherwise we will get a SOP error:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*3h4HqCb9UVGAhhEncDix0A.png" /><figcaption>Fetch request from different origin</figcaption></figure><h4>2) CSP (<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP">Content Security Policy</a>)</h4><p>A security feature that allows website owners to control what content (like scripts, images, or styles) can be loaded onto their web pages.</p><p>You can set your <a href="https://content-security-policy.com/">CSP</a> in html using meta tag (or using header Content-Security-Policy):</p><pre>&lt;meta<br>  http-equiv=&quot;Content-Security-Policy&quot;<br>  content=&quot;default-src &#39;self&#39;; img-src https://*; child-src &#39;none&#39;;&quot; /&gt;</pre><h4>3) CORS (<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS">Cross-Origin Resource Sharing</a>)</h4><p>Way for a website to request resources (like data) from another website even if they have different origins (domains).</p><p>It’s known under these headers:</p><pre>Access-Control-Allow-Origin: https://foo.example<br>Access-Control-Allow-Methods: POST, GET, OPTIONS<br>Access-Control-Allow-Headers: X-PINGOTHER, Content-Type<br>Access-Control-Max-Age: 86400</pre><p>It’s used to enable sharing of resources between different websites, but in a controlled way.</p><h4>4) Sanitized characters</h4><p>If a site properly sanitizes characters, the characters are rendered as HTML entities and the JavaScript or HTML tags are not executed.</p><ul><li>A double quote (“) as &amp;quot; or &amp;#34;</li><li>A single quote (‘) as &amp;apos; or &amp;#39;</li><li>An opening angle bracket (&lt;) as &amp;lt; or &amp;#60;</li><li>A closing angle bracket (&gt;) as &amp;gt; or &amp;#62;</li></ul><h3>Weird JavaScript</h3><ul><li><em>Encoding, function execution and much more is acting very weird when it comes to javascript</em></li></ul><h4>Encoding</h4><p>JavaScript supports various types of encoding, like Hex, Decimal, Unicode, named and HTML5 entities.</p><p>The weird thing about this, is that we can turn these encoding directly into chars or numbers without using a decoding function.</p><p>Also, it’s useful to know that a single character escape sequence exists:</p><pre>&#39;\b&#39; // backspace<br>&#39;\f&#39; // form feed<br>&#39;\n&#39; // new line<br>&#39;\r&#39; // carriage return<br>&#39;\t&#39; // tab<br>&#39;\v&#39; // vertical tab<br>&#39;\0&#39; // null<br>&#39;\&#39;&#39; // single quote<br>&#39;\&quot;&#39; // double quote<br>&#39;\\&#39; // backslash</pre><p>We can break down a word or sentence using this knowledge:</p><pre>&quot;A\W\E\S\O\M\E&quot; // &quot;AWESOME&quot;<br><br>&#39;Multiple \<br>lines&#39; // &quot;Multiple lines&quot;</pre><p><strong>Hex:</strong></p><p>We can encode using hex, but here is the problem that we can’t declare variables or call functions, because without a double quote it will cause an error.</p><pre>const a = () =&gt; 1;<br><br>&quot;\x61&quot; // returns &quot;a&quot;<br>\x61 // Invalid escape sequence</pre><p><strong>Unicode:</strong></p><p>We can declare functions and variables, we can also half encode word so that it won’t get filtred out.</p><pre>// unicode character &quot;63&quot; is allowed as a variable<br>const \u0061 = () =&gt; 1;<br>\u{63} = 1 <br><br>\u{61}() //correctly calls the function<br><br>&quot;H\u0065LLO&quot; // HELLO</pre><h4>Function Execution</h4><p>Functions may be quite fascinating in JavaScript, we can invoke them without parentheses:</p><pre>function printout(n1) {<br>  return n1;<br>};<br><br>printout(&quot;Hello World!&quot;); // output: &quot;Hello World&quot;<br>printout`Hello World!`; //  output: [&quot;Hello World&quot;]</pre><p>If we want to execute a function with more parameters, we can utilize <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals">template literals</a>. however, the indexing starts at 1 rather than 0.</p><pre>function sum(n1, n2) {<br>  console.log(n1, n2); // [&quot;n1&quot;, &quot;&quot;, &quot;&quot;], n2<br>  return Number(n1[0]) + n2;<br>}; <br><br>sum`5${4}`; // output: 9<br><br>// Easier way through arguments<br>function x() {<br>  console.log(arguments);<br>};<br><br>x`${1}${2}${3}`; // output [[&quot;&quot;, &quot;&quot;, &quot;&quot;], 1, 2, 3]</pre><p>There are more ways to execute a function. For example:</p><p>Interesting ways of executing alert found in book from <em>Gareth Heyes</em>:</p><pre>window.valueOf=alert;window+1<br>setTimeout`alert\x281337\x29`<br>&#39;1337,&#39;.replace`1337${alert}`<br>Reflect.apply.call`${alert}${window}${[1337]}`/</pre><p>And more from PayloadsAllTheThings:</p><pre>window[&#39;alert&#39;](0)<br>parent[&#39;alert&#39;](1)<br>self[&#39;alert&#39;](2)<br>top[&#39;alert&#39;](3)<br>this[&#39;alert&#39;](4)<br>frames[&#39;alert&#39;](5)<br><br>[7].map(alert);<br>[8].find(alert);<br>[9].every(alert);<br>[10].filter(alert);<br>[11].findIndex(alert);<br>[12].forEach(alert);</pre><h4><a href="https://book.hacktricks.xyz/pentesting-web/xss-cross-site-scripting/iframes-in-xss-and-csp">Iframe</a> and <a href="https://www.geeksforgeeks.org/window-object-in-javascript/">Window</a></h4><p>We can dereference window.alert and it will also dereference alert, because the origin of alert function lies on window.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/722/1*K9rUAMqiDLuQp4g__-_0zA.png" /><figcaption>Dereferencing alert object from window</figcaption></figure><p>Iframes can be used for JavaScript sandbox execution, suppose we got this code, and we want to execute a XSS to get the secret.</p><pre>var secret = &quot;MY-SECRET&quot;;<br>function createSandboxedEnvironment(code) {<br>    const iframe = document.createElement(&#39;iframe&#39;);<br>    iframe.style.display = &#39;none&#39;;<br>    document.body.appendChild(iframe);<br><br>    const sandboxWindow = iframe.contentWindow;<br>    const sandboxDocument = iframe.contentDocument;<br><br>    try {<br>        sandboxWindow.eval(code);<br>    } catch (error) {<br>        console.error(&#39;Error in sandboxed code:&#39;, error);<br>    } finally {<br>        document.body.removeChild(iframe);<br>    };<br>};<br><br>createSandboxedEnvironment(`console.log(&#39;Sandboxed:&#39;, secret);`); // undefined</pre><p>If we execute an XSS in the current scope, we will not receive any secrets or cookies. This means that it must be executed in the main window rather than the iframe window.</p><pre>createSandboxedEnvironment(<br>  `console.log(&#39;Sandboxed:&#39;, parent.secret);`<br>); // MY-SECRET<br><br>createSandboxedEnvironment(<br>  `console.log(&#39;Sandboxed:&#39;, window.top.secret);`<br>); // MY-SECRET<br><br>createSandboxedEnvironment(<br>  `console.log(&#39;Sandboxed:&#39;, window.parent.secret);`<br>); // MY-SECRET</pre><p>Another interesting aspect of the window object is that it allows you to launch a new tab and read from it if you are on the same origin. Assume we discovered XSS in a page and there is a /notes endpoint on the same origin. If we wish to read the /notes of another user, we may simply open a new window and read them.</p><pre>&lt;script&gt;<br>    window.open(&quot;http://localhost/notes.html&quot;, &quot;pwn&quot;);<br>    setTimeout(`console.log(window.open(&quot;&quot;, &quot;pwn&quot;).document.body.textContent)`, 1000);<br>&lt;/script&gt;</pre><p>But there is a catch that browsers usually block new windows. Still, we can get it through iframe .</p><pre>&lt;script&gt;<br>    const iframe = document.createElement(&#39;iframe&#39;);<br>    iframe.src = &quot;http://localhost/notes.html&quot;;<br>    iframe.style.display = &quot;none&quot;;<br>    document.body.appendChild(iframe);<br>    setTimeout(&quot;console.log(iframe.contentDocument.body.textContent)&quot;, 1000)<br>&lt;/script&gt;</pre><p>When we can’t access a window, the document.defaultView property is simply a way of obtaining the window object. For example, we can usually use a workaround that will allow us to access the “defaultView” property.</p><pre>let node = document.createElement(&#39;div&#39;);<br>node.ownerDocument.defaultView.alert(1337);</pre><h4>Payloads</h4><p>There are plenty of them, and I mean it. When it comes to XSS, we may get fairly creative, combining every mentioned aspect to overcome filters. The reason XSS is so dangerous is that it includes keyloggers, not to mention general user data and session hijacking.</p><p><strong><em>Most popular sources of XSS payloads:</em></strong></p><ul><li><a href="https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XSS%20Injection">PayloadsAllTheThings</a></li><li><a href="https://portswigger.net/web-security/cross-site-scripting/cheat-sheet">Portswigger.net</a></li><li><a href="https://github.com/payloadbox/xss-payload-list/blob/master/Intruder/xss-payload-list.txt">Payloadbox</a></li></ul><h3>Weird browser</h3><h4>Document.getelementById()</h4><p>Did you know that you could get the element by id simply with a variable:</p><pre>&lt;a href=&quot;clobbered:1337&quot; id=x&gt;&lt;/a&gt;<br>&lt;script&gt;<br>  alert(x);//clobbered:1337<br>  alert(typeof x);//object<br>&lt;/script&gt;</pre><h4><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs">Data URLs</a></h4><p>data:,Hello%2C%20World%21</p><p>Data URLs are URLs that can render a webpage with scripts and tags in a browser; for example, we can use them to render a webpage directly in a <a href="https://ctftime.org/writeup/27125">redirect</a>.</p><h4><a href="https://www.jitbit.com/alexblog/256-targetblank---the-most-underestimated-vulnerability-ever/">Target property</a></h4><p>There was a time when element a with parameter _blank could access the original page, but this is no longer the case. However, if the parameter rel is set to opener, there may still be an issue.</p><pre>&lt;a href=&quot;http://localhost&quot; target=&quot;_blank&quot; rel=&quot;opener&quot;&gt;EXAMPLE&lt;/a&gt;</pre><p>The attacker can redirect the original webpage to his own destination or can just execute on the window JavaScript:</p><pre>if (window.opener) {<br>  window.opener.location = &#39;https://you-re-hacked.com&#39;;<br>};<br><br>if (window.opener) {<br>  window.opener.alert(&quot;YOUR COOKIES ARE MINE&quot;);<br>};</pre><h3>Defending</h3><h4>Snyk</h4><p>Automated security tool for scanning and monitoring your software development. It’s incredibly simple to set up and utilize. Sometimes snyk produces false positives, but it is still worthwhile to verify.</p><h4>Keep your libraries up-to-date</h4><p>Most vulnerabilities are not detected immediately, and people strive to address them as soon as possible when strange things occur. Keeping your libraries up-to-date is also important and sometimes painful.</p><h4>Javascript/Markdown sanitilization</h4><p>Sanitization is a good security practice to use when including or reflecting client-side HTML on your website. There are several open-source libraries. One example is: <a href="https://www.npmjs.com/package/sanitize-html">sanitize-html</a></p><h4>CSP (<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP">Content Security Policy</a>)</h4><p>As mentioned, CSP can enhance your security by preventing cross-domain scripts from being loaded. However, it is not sufficient to include only CSP.</p><h3>Conclusion</h3><p>XSS is one of the most pervasive and dangerous vulnerabilities in web security, capable of compromising user data, hijacking sessions, and executing malicious code.</p><p>Theoretically, any user input might be utilized as an attack vector, potentially resulting in a vulnerability. You should pay special attention to these areas to ensure that they do not cause any strange behavior.</p><p>If you enjoyed this article, clap and follow me! Thanks for reading, and I wish you the best luck on your journey👋.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5a5bfb2dbce2" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Neural Networks: A Beginner’s Guide to Understanding the Magic Behind AI]]></title>
            <link>https://medium.com/@bitr13x/neural-networks-a-beginners-guide-to-understanding-the-magic-behind-ai-153bae652a2d?source=rss-6c5b2c01614b------2</link>
            <guid isPermaLink="false">https://medium.com/p/153bae652a2d</guid>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[neural-networks]]></category>
            <category><![CDATA[computer-science]]></category>
            <dc:creator><![CDATA[Sw33tBit]]></dc:creator>
            <pubDate>Sun, 17 Sep 2023 18:58:57 GMT</pubDate>
            <atom:updated>2023-09-17T19:03:19.596Z</atom:updated>
            <content:encoded><![CDATA[<p>Welcome traveler, in the growing world of intelligence there is a term that always stands out as incredibly influential, “neural networks.” These computerized structures, which draw inspiration from the mechanisms of the brain serve as the foundation, for state of the art technologies that drive various applications, like autonomous vehicles and voice recognition systems.</p><p>After a short break, I’m back with another interesting article, where we look deep into how neural networks work. I will try to explain it in a simple way and hopefully, you will find out that in the end it’s not that hard.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KEJjZa_Z27qWZVhr6S-Jyw.jpeg" /></figure><p>I’m not a professional and I could be wrong if you spot any mistakes, head into comments 🙂.</p><p>With that said let’s jump into the darkness…</p><h3>You will learn</h3><h4><strong>Fundamentals of Neural Networks</strong></h4><ul><li>What Are Neural Networks?</li><li>Neurons</li></ul><h4><strong>Neural Network Layers</strong></h4><ul><li>Input Layer</li><li>Hidden Layers</li><li>Output Layer</li></ul><h4><strong>Common Implementations</strong></h4><ul><li>Feedforward Neural Networks (FNN)</li><li>Convolutional Neural Networks (CNN)</li><li>Recurrent Neural Networks (RNN)</li><li>Long Short-Term Memory Networks (LSTM)</li></ul><h3>What Are Neural Networks?</h3><p>You could think of them like equivalent of the human brain’s information processing system. They are designed to mimic the brain’s ability to learn, adapt, and process data. These networks consist of artificial neurons, or nodes, interconnected by weighted connections, the whole calls it self: Artificial Neural Network (ANN).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*da54QdIzKOetYf98" /><figcaption>Visual representation of “neural network”.</figcaption></figure><p>Neural networks are inspired by the workings of the brain. In our brains neurons communicate by transmitting signals through synapses. Artificial neural networks replicate this process using models.</p><p>These networks are exceptional, at recognizing patterns making predictions and handling volumes of data, which is crucial for tasks such, as image recognition, language comprehension and recommendation systems.</p><h3>Neurons</h3><blockquote>Building Blocks of Neural Networks</blockquote><p>In a neural network, each neuron acts as a processing unit.</p><p>Artificial neurons take input data, perform calculations on it, and produce an output.</p><p>These outputs are then used as inputs for subsequent layers or are the final predictions of the network.</p><h4><strong>Weights and Biases</strong></h4><p>Two essential components are weights and biases. These elements determine how strongly an input signal influences the neuron’s output.</p><ul><li><strong>Weights</strong>💪<strong>:</strong> Weights is the strength of connections between neurons. Each connection between neurons has an associated weight. Larger weights amplify the input’s impact on the neuron’s output, while smaller weights diminish it.</li><li><strong>Biases</strong>👤<strong>:</strong> Biases are like an offset or threshold for the neuron. They are shifting the activation function left or right. If you want to read more about biases you can click <a href="https://www.turing.com/kb/necessity-of-bias-in-neural-networks">here</a>.</li></ul><p>Weights and biases enable neurons to learn and adjust their behavior during training. The process of determining the appropriate weights and biases, often known as model training or optimization.</p><p>They are capable of learning complicated patterns and correlations among data, making them useful for tasks like as image recognition, natural language interpretation, and many others.</p><h4>Example of neural prediction</h4><p>Imagine you are training a neural network to predict whether a student will pass a test based on the number of hours they study. Your input data consists of the number of hours a student studied, and the output is representing whether they passed (1) or failed (0).</p><p>To make this prediction, the neuron performs the following operation:</p><blockquote>Output = Activation Function(Weight × Number of Hours Studied + Bias)</blockquote><ul><li><strong>Activation function</strong>⚡️: It determines whether a neuron should “fire” (output a signal) or not based on the input it receives. The most frequent functions are <strong>Sigmoid</strong>, <strong>ReLU </strong>(Rectified Linear Unit), <strong>Tanh</strong> (hyperbolic tangent)<strong>.</strong></li></ul><p>Here the bias can represent how hard is the test, Let’s say the weight is 0.1, and the bias is -5 and you studied for 40hours.</p><blockquote>Output = Activation Function(0.1 x 40 x -5) = -1</blockquote><p>Since it’s -1 meaning you wouldn’t pass. Of course predicting the test like this is nonce, but you got the point.</p><h3><strong>Neural Network Layers</strong></h3><p>Neural networks are made up of layers, each having its own function and characteristics.</p><p>Understanding these levels is critical for understanding how information moves through a network and how the decisions are made.</p><p>We’ll look at the three main types of layers in a neural network architecture: the Input Layer, Hidden Layers, and Output Layer.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/538/1*REzVHUebWj8lFpsqWSnpdw.png" /><figcaption>Network Layers</figcaption></figure><h4><strong>Input Layer</strong></h4><blockquote>The Entry Point of Data</blockquote><p>The first layer of a neural network is the Input Layer. Its major duty is to receive data and forward it to the following layers for processing.</p><p>Each neuron in the input layer corresponds to a feature or input variable, it serves as an important link between the external data and the neural network.</p><ul><li><strong>No Computation</strong>🚧<strong>:</strong> Neurons in the input layer don’t perform any computation. They simply transmit the input data to the hidden layers.</li><li><strong>Size Determination</strong>🔍<strong>:</strong> The number of neurons in the input layer is determined by the dimensionality of the input data. For instance, in an image classification task, each pixel might correspond to a neuron in the input layer.</li></ul><p>You may encounter situations where input values are constrained to a specific range [0, 1] that’s called standardization and normalization. It can help the neural network converge faster during training and make it more robust to different input scales. However, these techniques are not always necessary and depend on the type of data.</p><h4><strong>Hidden Layers</strong></h4><blockquote>The Workhorses of the Network</blockquote><p>In a neural network, the true computing takes place in the Hidden Layers. These layers are in charge of extracting characteristics from input data as well as learning complex patterns and representations.</p><p>While a network can have numerous hidden layers, the number and size of hidden layers are determined by the network’s architecture and the task’s complexity.</p><ul><li><strong>Weighted Sum</strong>➕: The values provided are multiplied by their weights. These weighted sums are computed by taking the dot product, between the input values and the corresponding neuron weights. The outcome is a collection of sums.</li><li><strong>Bias Addition</strong>➕: After calculating the weighted sums, each neuron adds a bias term.</li><li><strong>Activation Function</strong>⚡️: The result of the weighted sum plus the bias for each neuron is then passed through an activation function.</li><li><strong>Hierarchical Learning</strong>🧠<strong>:</strong> Hidden layers progressively learn more abstract and high-level features as information flows through the network’s layers.</li></ul><p>The hidden layers of a neural network act as feature extractors.</p><h4><strong>Output Layer</strong></h4><blockquote>Making Predictions</blockquote><p>Final layer of the neural network. It produces the network’s predictions or outputs based on the processed information from the hidden layers. The structure and number of neurons in the output layer depend on the nature of the task.</p><ul><li><strong>Loss Calculation</strong>📉: Once the network produces its output, the loss or error between the predicted values and the actual target values (ground truth) is calculated. This loss is a measure of how well the network is performing.</li><li><strong>Backpropagation and Training</strong>🔄: The computed loss is used to update the network’s weights and biases through a process called backpropagation and optimization algorithms like gradient descent. The network learns to adjust its parameters to minimize the loss, making its predictions more accurate over time.</li><li><strong>Interpretation</strong>📖<strong>:</strong> The values produced by the neurons in the output layer are often interpreted as probabilities or class scores, depending on the problem. The highest-scoring class or classes are the network’s final predictions.</li></ul><p>The final predictions or values are created in the output layer based on the network’s learnt weights and biases. Network’s performance is enhanced by training, in which it learns to make better predictions by altering its parameters.</p><h3><strong>Common Implementations</strong></h3><p>Neural networks come in a variety of shapes and sizes, each one customized to specific types of data and activities. I’ll introduce you to four common neural network implementations and share insights on where they thrive.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vTsDqjgjM1ROqYW9ITIgDw.jpeg" /></figure><h4><strong>Feedforward Neural Networks (FNN)</strong></h4><blockquote>The Foundation of Neural Networks</blockquote><p>Feedforward Neural Networks, often referred to as multilayer perceptrons (MLPs), serve as the foundational architecture for neural networks. They are versatile and can be used for a wide range of tasks, including classification and regression.</p><ul><li><strong>Architecture</strong>🏰<strong>:</strong> FNNs consist of an input layer, one or more hidden layers, and an output layer. Information flows in one direction, from input to output, without loops or cycles.</li><li><strong>Applications</strong>📋<strong>:</strong> FNNs find applications in image classification, sentiment analysis, and other structured data tasks. Their simplicity and effectiveness make them a valuable choice for many problems.</li></ul><h4><strong>Convolutional Neural Networks (CNN)</strong></h4><blockquote>Unraveling Image and Spatial Data</blockquote><p>Convolutional Neural Networks are specifically designed for tasks involving grid-like data, such as images and spatial data. They excel at capturing spatial hierarchies and patterns.</p><ul><li><strong>Architecture</strong>🏰<strong>:</strong> CNNs incorporate convolutional layers for feature extraction and pooling layers for dimensionality reduction. These layers allow the network to understand spatial relationships in the data.</li><li><strong>Applications</strong>📋<strong>:</strong> CNNs are the go-to choice for image classification, object detection, facial recognition, and tasks involving grid-like data.</li></ul><h4><strong>Recurrent Neural Networks (RNN)</strong></h4><blockquote>Mastering Sequential Data</blockquote><p>Recurrent Neural Networks are designed for tasks that involve sequential data, where the order of elements matters. They have memory cells that enable them to retain information from previous time steps.</p><ul><li><strong>Architecture</strong>🏰<strong>:</strong> RNNs have recurrent connections that loop back on themselves, allowing them to maintain a form of memory. This makes them suitable for tasks like natural language processing, time series prediction, and speech recognition.</li><li><strong>Applications</strong>📋<strong>:</strong> RNNs are used in machine translation, text generation, speech synthesis, and any task involving sequences.</li></ul><h4><strong>Long Short-Term Memory Networks (LSTM)</strong></h4><blockquote>Overcoming the Shortcomings of RNNs</blockquote><p>While RNNs are powerful for sequential data, they suffer from vanishing gradient problems. Long Short-Term Memory Networks (LSTMs) were developed to address these issues by introducing specialized memory cells.</p><ul><li><strong>Architecture</strong>🏰<strong>:</strong> LSTMs include memory cells with gating mechanisms that control the flow of information, allowing them to capture long-range dependencies in sequential data.</li><li><strong>Applications</strong>📋<strong>:</strong> LSTMs are widely used in tasks requiring long-term dependencies, such as speech recognition, language modeling, and sentiment analysis.</li></ul><p>These are just a few of the common neural network architectures, each tailored to different data types and tasks. As we explore these implementations further, you’ll gain a deeper understanding of how to choose the right architecture for your specific AI and machine learning projects.</p><h3>Conclusion</h3><p>They can be used almost everywhere and they are ground breaking because they can remove the repetitive tasks from daily life, but at their core they cannot replace humans.. So, no worries 😊.</p><p>Anyway, If you enjoyed this article, clap👋 and follow me📑! Thanks for reading! Looking forward to seeing you in the future.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=153bae652a2d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Quick introduction in Godot 4 Multiplayer]]></title>
            <link>https://medium.com/@bitr13x/quick-introduction-in-godot-4-multiplayer-ed7e35cbfec5?source=rss-6c5b2c01614b------2</link>
            <guid isPermaLink="false">https://medium.com/p/ed7e35cbfec5</guid>
            <category><![CDATA[game-development]]></category>
            <category><![CDATA[godot-4]]></category>
            <category><![CDATA[godot-engine]]></category>
            <category><![CDATA[godot]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Sw33tBit]]></dc:creator>
            <pubDate>Wed, 17 May 2023 14:03:11 GMT</pubDate>
            <atom:updated>2023-05-17T14:03:11.128Z</atom:updated>
            <content:encoded><![CDATA[<p>Greetings to everyone! Today I bring you a quick introduction to Godot version 4 multiplayer.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*p4vBXVLhwr_A3n9A.png" /></figure><p>If you want a better understanding, I recommend you read the <a href="https://godotengine.org/article/multiplayer-in-godot-4-0-scene-replication/">documentation</a> or at least know the differences between server-side and client-side. With that said, let’s go straight into it.</p><h3>Setup the Network</h3><p>This is similar to Godot 3.5, but the syntax is a little bit different:</p><p>For example, now everything about multiplayer is actually under a global class named “multiplayer” (MultiplayerAPI), meaning when we connect signals, it’s under the multiplayer class.</p><pre># GODOT 3.5<br>get_tree().connect(&quot;connected_to_server&quot;, self, &quot;_connected_to_server&quot;)<br># GODOT 4<br>multiplayer.connected_to_server.connect(self._connected_to_server)</pre><p>For quick setup, you can use this code:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5f6bde75c622a4a6510fb1500ba0d209/href">https://medium.com/media/5f6bde75c622a4a6510fb1500ba0d209/href</a></iframe><p>This code you will add as auto-load and then a create node with lobby and connect the signals, then button to switch scenes. To better understand the code, you can check my <a href="https://medium.com/@bitr13x/how-to-make-a-simple-2d-multiplayer-game-in-godot-6247b68d0af0">previous guide</a> to multiplayer 3.5.</p><h3>Multiplayer Synchronizer</h3><p>In this version of Godot, they added the multiplayer synchronizer, which simplifies the programming of multiplayer. Now you need to add it to the player tree, and then just set the properties that you want to synchronize.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DxqiAwZZx7rZoGDVM0SF2A.png" /></figure><p>This is so helpful and can save you a lot of time.</p><h3>Multiplayer Spawner</h3><p>Another new feature that also simplifies the process of spawning and managing networked objects in multiplayer games</p><p>But when I was using it, I fell into lots of errors, and then I just implemented my own spawner. If you want to play with it on your own, I recommend you look up the <a href="https://docs.godotengine.org/en/stable/classes/class_multiplayerspawner.html">documentation</a>.</p><h3>RPC Calls</h3><p>RPCs are essential for implementing networked gameplay and interactions, and that’s why it’s useful to know how to use them properly.</p><p>RPC changed syntax to a much simpler version.</p><p>For example, now you don’t have any master, puppet, remote, etc., but you have much simpler syntax.</p><h4>Syntax of RPC Calls in Godot 4:</h4><p>You will start with “@”, and then you will specify RPC’s mode, sync, transfer_mode.</p><pre># mode, sync, transfer_mode (order doesn&#39;t matter)<br># reliable -&gt; tcp, unreliable -&gt; udp (spamming), unreliable_ordered<br>@rpc(&quot;any_peer&quot;, &quot;call_local&quot;, &quot;reliable&quot;)<br>func totaly_sync():<br>  print(&quot;Running locally and any_connected_client running this function&quot;)<br><br>@rpc(&quot;call_local&quot;)<br>func local_call():<br>  print(&quot;calling just local function&quot;)<br><br># You also can use different channels used mostly for optimizations <br>@rpc(any_peer, 1)<br>func my_chat_func(message):<br> print(&quot;RPC received on channel 1, message: &quot; + str(message))<br><br># Calling rpc function:<br># rpc() == self.rpc<br>rpc(&quot;totaly_sync&quot;)<br># with arguments:<br>rpc(&quot;my_chat_func&quot;, &quot;Hello&quot;)</pre><p>But be careful, you can’t send any node because that could lead to an RCE vulnerability, so you need to work around it. Usually, I declare a list of items that I want to sync and then just send the index through the network.</p><pre>@onready var items = [<br> preload(&quot;res://path/to/scene.tscn&quot;),<br> preload(&quot;res://path/to/scene.tscn&quot;),<br>]<br><br>@rpc(&quot;any_peer&quot;, &quot;call_local&quot;, &quot;reliable&quot;)<br>func sync_items(index: int) -&gt; void:<br> spawn_item(items[index])</pre><h3>Controlling the execution flow</h3><p>The last thing on our list is how to actually control the execution flow. The main way to control the flow is by:</p><pre># check whoever executing the code if its the owner of current node<br>mutiplayer.is_mutliplayer_authority()<br># check if its the server<br>multiplayer.is_server()<br># set the ownership of the node<br>NODE.set_multiplayer_authority()<br></pre><p>When you instancing the player, you need to set him as the multiplayer_authority of its node. This will make your life much simpler.</p><p>And keep in mind that when using the “_ready()” function, the execution of this function usually happens before the multiplayer_authority is set.</p><h3>Conclusion</h3><p>With this article, you should be able to program multiplayer into your game. Sometimes multiplayer can be a pain because something is not syncing properly, and debugging the error is a little bit difficult, but with a cool head, you eventually find the error and gain a little bit more knowledge.</p><p>If you enjoyed this article, clap and follow me! Thanks for reading, and I wish you the best luck on your journey.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ed7e35cbfec5" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Exploring Blockchain Security Risks]]></title>
            <link>https://medium.com/@bitr13x/exploring-blockchain-security-risks-81193465ff37?source=rss-6c5b2c01614b------2</link>
            <guid isPermaLink="false">https://medium.com/p/81193465ff37</guid>
            <category><![CDATA[blockchain-security]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <category><![CDATA[infosec]]></category>
            <category><![CDATA[blockchain]]></category>
            <dc:creator><![CDATA[Sw33tBit]]></dc:creator>
            <pubDate>Sat, 25 Feb 2023 13:36:02 GMT</pubDate>
            <atom:updated>2023-02-25T13:36:02.166Z</atom:updated>
            <content:encoded><![CDATA[<p>Welcome traveler, today we will discuss blockchain technology, it’s the potential to revolutionize the way we store and transfer data, providing a secure and transparent way to conduct transactions without the need for intermediaries. However, like any technology, blockchain is not without its security risks. In this article, we’ll explore some of the most common blockchain security threats and the best practices for protecting your data in a decentralized world. Let’s dive in!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/901/1*UleklZBKJ6xK3d_L46xZ_A.png" /></figure><h3>Common Blockchain Security Threats</h3><p>Blockchain technology has a lot of potential benefits, but it’s not without its risks. Here are some common blockchain security threats you should be aware of:</p><h4>51% Attacks</h4><p>This is when a single entity controls the majority of the network’s computing power. In such a scenario, the attacker can rewrite transaction histories, effectively controlling the network.</p><h4>Smart Contract Vulnerabilities</h4><p>Smart contracts are self-executing contracts with the terms of the agreement between buyer and seller being directly written into code. This code can have vulnerabilities that attackers can exploit, which can lead to theft or misuse of assets.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/410/1*j-09bFHOvtbi_gpJ0MRDdw.png" /></figure><h4>Private Key Theft</h4><p>Private keys are used to access blockchain wallets and are the gateway to the funds in those wallets. If an attacker can obtain a private key, they can gain access to the wallet and the funds it holds.</p><h3>Best Practices for Blockchain Security</h3><p>To mitigate the risks associated with blockchain security threats, there are several best practices you can follow:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/364/1*WDxfzD5vmT9I7WrGtx-gyw.png" /></figure><h4>Encryption</h4><p>Use strong encryption to protect your data in transit and at rest.</p><h4>Multi-factor authentication (MFA)</h4><p>It’s easy for a password to be stolen, guessed, or hacked, especially if it’s weak or reused across multiple accounts.</p><h4>Regular Security Audits</h4><p>Important component of any effective cybersecurity strategy. These audits involve systematically reviewing your organization’s security controls, policies, and procedures to identify vulnerabilities and risks that could lead to security breaches.</p><p>Regularly audit your blockchain systems to identify and fix vulnerabilities.</p><h4>Keep Software and Hardware Up-to-date</h4><p>It provides security patches to protect against vulnerabilities, improves performance and compatibility, adds new features</p><p>Ensure that you are using the latest software and hardware to prevent vulnerabilities.</p><h3>Emerging Trends in Blockchain Security</h3><p>The blockchain industry is constantly evolving, and so are the security measures being implemented. Here are some emerging trends in blockchain security:</p><h4>Decentralized Identity Solutions</h4><p>Using blockchain technology to create decentralized identity solutions that allow individuals to control their own digital identities.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/309/1*hZ9yTWFU3mPhbVLKGvW2JA.png" /></figure><h4>Blockchain-based Security Tokens</h4><p>Security tokens are a new type of digital asset that represent ownership in traditional financial assets, such as stocks and bonds. Using blockchain technology, these assets can be made more secure and transparent.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/442/1*KsLXRRRKGH_aZhmTsH5n-g.png" /></figure><h3>Conclusion</h3><p>Blockchain technology has the potential to revolutionize the way we store and transfer data, but it’s not without its risks. Understanding the common blockchain security threats and implementing best practices and emerging trends can help protect your data. By following the best practices and keeping up with emerging trends, we can work towards a more secure blockchain ecosystem.</p><p>Thank you for taking the time to read this! If you liked this article, please clap and follow me! I hope to see you again in the future.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=81193465ff37" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>